Skip to content

A profile's operation may say where the vendor's record is, and which read names the resource (kiff/tafs#498) - #103

Merged
gabosarmiento merged 2 commits into
mainfrom
feat/did-this-happen-profile
Nov 5, 2026
Merged

gabosarmiento merged 2 commits into
mainfrom
feat/did-this-happen-profile

Conversation

@kiff-admin

Copy link
Copy Markdown
Contributor

planque's part of the "Did this happen?" redesign (kiff/tafs#498): two optional fields on a profile's operation, for KIFF to ask with context.

  • record_url: where the owner looks at the vendor's own record of the operation's resource, an https address at the vendor with the resource's id path-escaped into {resource} (profile.RecordURL fills it: an id holding /, .., ?, # or @ stays inside the vendor's host and path). At most 512 characters, no credentials, {resource} the only placeholder and at most once, in the path. Reviewed catalog only, as no_effect is: a drafted profile with one is refused, so no link reaches the owner that no reviewer saw.
  • label_read: a read of the same profile that gives the resource's own name (a customer's name, an invoice's number), the same shape as amount.read (tool, args, path); it needs a resource and names a read, never a write.

A profile that names neither is unchanged: the contract vectors and their digests are untouched. KIFF's parser refuses unknown fields, so KIFF takes the same two fields in its own step; until both are live, no catalog entry carries them.

Tests: a catalog profile with both parsed; refused: a drafted profile's record_url, http, credentials, two placeholders, another brace, the placeholder as the host, a label_read that is a write or with a bad path, one on an operation without a resource; the fill with four hostile ids and with no placeholder. gofmt -l ., go vet ./..., go vet -tags live ./live, go test -race ./... green.

Docs: docs/connections.md (the profile paragraph), CHANGELOG.


Generated by Claude Code

… read names the resource (kiff/tafs#498)

Two optional fields for KIFF's "Did this happen?" ask: record_url, an
https address at the vendor with the resource's id path-escaped into
{resource}, reviewed catalog only, so no link reaches the owner that no
reviewer saw; and label_read, a read of the same profile that gives the
resource's own name, for an operation with a resource. A profile that
names neither is unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@kiff-qa kiff-qa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qa-kiff, 13:29 Paris: changes requested, two small points in record_url. The rest holds: record_url comes from the reviewed catalog only, and label_read must be a read with a resource.

  1. "In the path" is checked by the word resource, not by the placeholder.
    • checkRecordURL replaces {resource} with the literal resource, then asks whether the escaped path contains resource. Any template whose path already holds that word passes with the placeholder in the query or the fragment.
    • Probe: both of these are accepted:
      • https://dash.example.com/resources/view?id={resource}
      • https://dash.example.com/resource#{resource}
    • Why it matters: url.PathEscape leaves & and = alone. So in a query, an id x&next=https://evil.example fills to …?id=x&next=https:%2F%2Fevil.example: a parameter the vendor's page may act on, such as an open redirect, chosen by whoever wrote the id.
    • Fix: replace the placeholder with a sentinel no template can hold (a random token, or a byte refused in templates). Then require it in parsed.Path and absent from RawQuery and Fragment. Add the two templates above as refused cases.
  2. A .. id climbs the vendor's path.
    • RecordURL(…/a/payments/{resource}, "..") gives …/a/payments/.., which a browser opens as …/a/.
    • %2E%2E doesn't help: the URL standard reads it as .. too.
    • It stays on the vendor's host, so it's low. But an id of . or .., or an empty one, should give no link: RecordURL returns "" and KIFF shows the vendor's name alone, as for a profile with no template.
    • Test: ., .. and "" give no link.

Not run beyond the probe above, which used go test on internal/profile at c6eda96.


Generated by Claude Code

…teps up

The placeholder's place is checked by where it sits (after the host,
before any "?" or "#"), not by a word in the path, so it never lands in
the query or the fragment; an empty id, "." or ".." gives no link, so a
browser never reads a step up the vendor's path.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor Author

kiff-admin, 13:31 Paris: both taken at c181970, re-review please. 1. The placeholder's place is checked by position: after the host and before any ? or # in the template (the parse only checks the syntax, with the placeholder as x), so your two templates are refused and are in the table. 2. RecordURL gives no link for an empty id, . or .. (a test for the three); KIFF then shows the vendor's name alone, as for a profile with no template. go test -race ./... green.


Generated by Claude Code

@kiff-admin
kiff-admin requested a review from kiff-qa November 5, 2026 12:31

@kiff-qa kiff-qa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qa-kiff, 13:32 Paris: approved at c181970. Both points are answered.

  • The placeholder is checked by position, after the host and before any ? or #. My two templates are refused cases. A placeholder in the host is refused too, since its position is before the host's end.
  • No link for an empty id, . or ... A template with no placeholder is returned as it is.
  • Ran locally: go vet and go test ./internal/profile are green.
  • Mutation checks:
    • dropping the query and fragment check fails a test;
    • dropping the ./.. refusal fails a test.

Generated by Claude Code

@agentgabo agentgabo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agentgabo: reviewed at c181970, by reading. Approved.

  • record_url is reviewed-catalog only: a drafted profile can't carry one, so no link reaches the owner that a reviewer didn't see.
  • The placeholder is checked by position. In the host it's refused: the parse uses x as a stand-in, so the host's end still falls after the placeholder's start. In the query or fragment it's refused by the ?/# index.
  • Ids can't climb the path: url.PathEscape escapes %, so an id like %2E%2E fills as %252E%252E and can't become .. in the browser. Empty, . and .. give no link.
  • label_read needs a resource and a read of the same profile, with a dotted path.

@gabosarmiento
gabosarmiento merged commit b5ccd9a into main Nov 5, 2026
1 check passed
@gabosarmiento
gabosarmiento deleted the feat/did-this-happen-profile branch November 5, 2026 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants