Vote for your favorite SkillMD. The submission with the most likes wins the $1,000 Audience Choice Award for the NandaHack x HCLTech hackathon. Voting is open through September 25.Vote now →
mergedhumanPR #280Auth

fix: use credentials written into an endpoint URL, never record them

Follow-up to the review of merged 00a013b: URL confidentiality.

Author

JamesCarnley avatar

@JamesCarnley

github profile →
Status
Merged
Merged on
Sep 16
Branch
fix/url-credentials-never-recorded

Description

The pitch.

Follow-up to the review of merged `00a013b`: URL confidentiality.

### Problem

An endpoint behind basic authentication can be tested by writing its credentials
into the URL, and httpx sends them. Reproduced on `main`:

- `test-agent` printed the password and recorded it in the run, events, intents,
  report and rerun command.
- `receipt` signed it into a receipt while announcing that "nothing private
  leaves the bundle".
- `pulse` stored it, and after the target was re-pointed at a clean URL, still
  printed it as an "earlier endpoint", as did `--report` and `--records`.

### Decision

Codex's constraints were: preserve exact endpoint distinctions, don't silently
strip credentials, and don't rewrite signed evidence. Within those, the
maintainer chose to **keep credential URLs usable, and never print or record
the credentials Town recognises**, rather than refuse them. Stripping would test a different endpoint:
against a real basic-auth agent, the same URL without credentials gets 401.

### Change

- **Credentials are recognised where httpx finds them**, in the URL's
  authority, never by searching text for things that look like URLs. A password
  may hold quotes, brackets or spaces. A URL httpx cannot parse is not called,
  and everything before its last `@` is withheld.
- **The recorder replaces only the operator's own credentials.** Only the
  operator's locators are registered (the subject URL, and a resolved index
  entry), and only their exact credentials are replaced, in every spelling they
  take: as written, httpx-normalised, percent-decoded, and shell-quoted, always
  inside `://…@`. An agent's own text is recorded as it said it.
- **Evidence and Pulse history show `<credentials 1a2b3c4d>`**, an HMAC of the
  credentials httpx sends, keyed by a random secret in the Town home that is
  never recorded. Two credential sets for one host stay distinguishable, and a
  short password can't be guessed from the label. If the key can't be used,
  Town records `<credentials withheld>` instead and warns: it never crashes and
  never leaks.
- **Receipts show `<credentials withheld>`,** the same on every machine; the
  bundle fingerprint still pins the exact endpoint. The CLI no longer claims
  nothing private leaves the bundle.
- **The rerun asks for `<operator-supplied-url>`,** as a Track rerun already does
  for an unrecorded command. An index rerun stays exact.
- **Evidence recorded earlier is not rewritten.** Reports, `replay`,
  `visualize` and new receipts withhold its credentials, and receipts issued
  before this still verify.
- **Echoes are closed.** `a2a test` and the Track `--agent` errors no longer
  repeat credentials. A Pulse refusal of any `--target` holding an `@` repeats
  none of it, because a mistyped or mis-split target can put part of a
  password in its name.

### What Town does not recognise

The guarantee covers recognised credentials only. The guide
(`docs/testing-an-existing-agent.md`) now says exactly where it stops:

- **A token outside the user information,** such as in a query string or a
  header, is used, printed and recorded as written.
- **A password with an unencoded `/`, `?` or `#`** ends the host early. Two
  outcomes:
  - **The URL no longer parses,** as in `user:pass/word@host`, which is the
    usual case. Town does not call it, and withholds everything before its last
    `@`.
  - **It still reads as a host,** as in `user:1234/word@host`,
    `token/word@host` or `user:a@b/c@host`. The URL goes to that host, and the
    rest of the password is used, printed and recorded as written. Town can't
    tell this from an ordinary `@` in a path such as `/users/a@b`, so it
    neither refuses nor rewrites the URL. `test-agent --url`, `a2a test` and
    `pulse` print a note without the URL; a URL from an `--index` file gets
    none. Refusing such URLs would change what Town accepts, so that is left
    for a maintainer.

Also known:
- Labels belong to one Town home.
- A Town from before this chang

…

Try it

Open PR on GitHubView diff

Checkout locally

git fetch origin pull/280/head:pr-280
git checkout pr-280