Skip to content

docs(evidence): state both Evidence source transports across the site - #799

Merged
jeremi merged 3 commits into
mainfrom
agent/evidence-transport-sweep
Aug 21, 2026
Merged

docs(evidence): state both Evidence source transports across the site#799
jeremi merged 3 commits into
mainfrom
agent/evidence-transport-sweep

Conversation

@jeremi

@jeremi jeremi commented Aug 21, 2026

Copy link
Copy Markdown
Member

Follow-up to #798, which fixed the architecture page's claim that an Evidence
Gateway source is always reached over HTTP. The same HTTP-only framing survived
on seven more pages and in registry-trust-boundaries.svg. This is the sweep,
in one PR.

What was wrong

A reader could conclude from these pages that Evidence Gateway must cross a
network boundary to reach a source, and that a source always resolves a
credential. Neither holds. Both source transports are frozen and coequal:

  • registry.evidence.fixed-http-json-source/v1
    (products/evidence/contracts/source-contract.yaml)
  • registry.evidence.fixed-sqlite-extract-source/v1
    (products/evidence/contracts/sqlite-extract-source-contract.yaml)

A statement source has no origin, scheme, host, port, method, path, media type,
redirect policy, or header; no connection string, secret reference, or
authentication kind; and no network path at all. Every rewritten claim is
anchored to those contracts, to bundle.schema.yaml, or to the runtime code
that enforces it.

Files

File Change
explanation/threat-model.mdx Figure alt text, the fixed-sources section, the product-separation section, and the SSRF, secret-material, and hostile-script bullets
explanation/integration-patterns.mdx Decision guide re-keyed to what the caller needs back; the Evidence source model and its credential bullet split per transport
explanation/trusted-context-constraints.mdx Acquisition kind restated transport-neutrally; HTTP properties attributed to the HTTP stage; freshness section corrected
explanation/records-stay-home.mdx Mermaid source node and the Evidence paragraph
start/evidence-quickstart.mdx Dropped "HTTP" from the product-separation paragraph
configure/evidence.mdx The sources row of the bundle key table
spec/rs-arc-g.mdx The Evidence Gateway component paragraph
public/images/registry-trust-boundaries.svg Source box subtitle, arrow label, right-column body, <desc>

Left alone deliberately

"HTTP source" is correct in these places and was not touched: consuming a
Relay-served API as a source, the DHIS2 and FHIR examples, source-batch
(HTTP-only, bundle.schema.yaml 896-900 and 1212), and the OpenAPI authoring
path in evidencectl.

Security review notes

Re-reading these pages against source turned up seven defects. Six are
security-sensitive, and two of them previously let a reader infer a stronger
guarantee than the code provides:

  1. Secret file mode. The secret-material bullet claimed mode exactly
    0600. validate_file_metadata() in
    crates/registry-platform-config/src/secrets.rs accepts 0o400 | 0o600. An
    operator reading the old text would expect a 0400 secret to be refused.
  2. V1-I30 overstated audit completeness. The page said "every native audit
    event records the closed response-protection mode". The matrix scopes that to
    authorized-material events; the minimal authorization-refusal event records
    neither field. Anyone relying on that field being universally present needed
    to know.
  3. V1-I21 signed-JWS availability is scoped to grants issuing under the
    audience-scoped subject binding, not to every authorized grant.
  4. A cited test did not exist. file_secret_uses_open_file_owner_and_exact_mode_checks
    is not in the tree. Replaced with the real
    file_secret_accepts_only_owner_read_and_optional_owner_write_modes. A
    citation pointing at nothing is how a security claim survives its proof being
    deleted.
  5. Freshness. The page said Version 1 has no source freshness family at all.
    A statement source must declare maximumExtractAgeSeconds, and
    validate_extract_age() compares it against the extract's publishedAt
    before any row is read, failing as ProblemCode::DependencyUnavailable. The
    heading now says "record freshness", which is the claim that still holds:
    that bound is on the extract file's age, not the record's.
  6. Diagram arrow label read "one fixed HTTP request per evaluation". The
    ceiling is one request per acquisition stage; search-then-fetch-set runs
    up to five stages, so the old label was wrong on both transports.
  7. Diagram: "only Evidence Gateway holds a source credential" now reads
    "ever holds", since a statement source holds none.

Claims that moved toward a stronger guarantee, and therefore need their
citations checked rather than their prose: the statement transport's
credential-free, network-free, origin-free character; scripts never receiving
statement text or the connection; index binding and named-only parameters. All
rest on sqlite-extract-source-contract.yaml, which is frozen. If that contract
is ever unfrozen or its transport_absences block edited, every one of those
sentences must be re-verified.

Citation drift

Twelve path:start-end citations no longer contained the symbol they named.
All were repointed to the symbol names themselves, which do not drift. No gate
catches this today; I'd like to propose a checker separately rather than widen
this PR.

Verification

From docs/site/:

npm run check   # exit 0; Vale 0 errors 0 warnings; astro check 0 errors 0 warnings
npm test        # 364 pass, 0 fail

The redrawn SVG was rendered with resvg against the installed Public Sans and
IBM Plex Mono, then measured: rightmost ink at x=677.5 in a 720-wide viewBox, no
collisions, every label inside its box.

No production code changes.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aca23bacab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/site/src/content/docs/explanation/threat-model.mdx Outdated
Comment thread docs/site/src/content/docs/configure/evidence.mdx
@jeremi

jeremi commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

@codex review

Re-review requested for 1b2ab21b1, which scopes the HTTP source credential claim per the P2 above. Please check the none authentication kind qualification against sources.*.authentication.kind in products/evidence/contracts/bundle.schema.yaml, and whether the SVG's "only Evidence Gateway ever holds a source credential" still needs qualification.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1b2ab21b16

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/site/public/images/registry-trust-boundaries.svg Outdated
@jeremi

jeremi commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

Accepted, fixed in 15a0309.

The clearer fix than qualifying each occurrence with "authenticated" is to name the property that is actually fixed. What trusted configuration pins is the authentication kind, and none is one of the kinds it can pin it to, so authentication is accurate for every HTTP source without a qualifier. The normative sentence in the same section already used that word:

...and on the HTTP transport also the origin, method, fixed or tagged selector or prior-fact-bound path, fixed headers, authentication, TLS, projection, redirect denial, and proxy denial

The three occurrences you named, plus a fourth in the SSRF bullet that had the same list, now match it:

  • registry-trust-boundaries.svg:93 (diagram body)
  • registry-trust-boundaries.svg:5 (<desc>)
  • threat-model.mdx:101 (figure alt text)
  • threat-model.mdx:447 (SSRF bullet, same list, not in your report)

The diagram line grew from 76 to 80 characters. Rendered at 1728px and measured the rightmost non-white pixel: the source block ends at svg x=677.9 of the 720 viewBox, so it is still not the widest line in that block and nothing overflows.

Agreed on "only Evidence Gateway ever holds a source credential" standing as written, and it is unchanged.

jeremi added 3 commits August 21, 2026 11:03
PR #798 corrected the architecture page's claim that an Evidence Gateway
source is always reached over HTTP. The same HTTP-only framing survived on
seven more pages and in the trust-boundaries diagram, so a reader could still
conclude that Evidence must cross a network boundary to reach a source, and
that a source always resolves a credential.

Both source transports are frozen and coequal:
registry.evidence.fixed-http-json-source/v1 and
registry.evidence.fixed-sqlite-extract-source/v1. A statement source has no
origin, scheme, host, port, method, path, media type, redirect policy, or
header; no connection string, secret reference, or authentication kind; and no
network path at all. Every rewritten claim is anchored to those contracts, to
bundle.schema.yaml, or to the runtime code that enforces it.

Left alone, because HTTP is genuinely correct there: consuming a Relay-served
API as a source, the DHIS2 and FHIR examples, source-batch, and the OpenAPI
authoring path in evidencectl.

Security-sensitive corrections found while re-reading the pages against source:

- threat-model: the secret-file bullet claimed mode exactly 0600. The code
  accepts 0400 or 0600 (validate_file_metadata in
  crates/registry-platform-config/src/secrets.rs). An operator reading the old
  text would expect a 0400 secret to be refused.
- threat-model: V1-I30 was stated as "every native audit event records the
  closed response-protection mode". The matrix scopes that to
  authorized-material events; the minimal authorization-refusal event records
  neither field. The old text overstated audit completeness.
- threat-model: V1-I21 signed-JWS availability is scoped to grants issuing
  under the audience-scoped subject binding, not to every authorized grant.
- threat-model: a cited test, file_secret_uses_open_file_owner_and_exact_mode
  _checks, does not exist. Replaced with the real
  file_secret_accepts_only_owner_read_and_optional_owner_write_modes.
- trusted-context-constraints: the page said Version 1 has no source freshness
  family at all. A statement source must declare maximumExtractAgeSeconds, and
  the runtime compares it against the extract's published-at instant before any
  row is read, failing as DependencyUnavailable. The section heading now says
  "record freshness", which is the claim that still holds.
- diagram: the arrow label read "one fixed HTTP request per evaluation". The
  ceiling is one request per acquisition stage; search-then-fetch-set runs up
  to five stages, so the old label was wrong on both transports.
- diagram: "only Evidence Gateway holds a source credential" now reads "ever
  holds", since a statement source holds none.

Twelve drifted path:line-range citations were repointed to the symbol names
they name, which do not drift. No production code changes.

Verified from docs/site: npm run check (exit 0, Vale 0 errors 0 warnings,
astro check 0 errors 0 warnings) and npm test (364 pass, 0 fail). The redrawn
SVG was rendered with resvg against the installed Public Sans and IBM Plex Mono
and measured: rightmost ink at x=677.5 in a 720-wide viewBox, no collisions.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Codex P2: an HTTP JSON source under `authentication.kind: none` resolves no
credential, so "an HTTP source is the case where a credential exists" was
absolute where the schema is not.

State the allowance and its bounds rather than hedge: only a `local` assurance
bundle may declare `none`, only at a canonical numeric-loopback origin, and
production and evidence-grade bundles reject that kind
(`sources.*.authentication.kind` in bundle.schema.yaml).

The SVG's "only Evidence Gateway ever holds a source credential" is a
capability comparison against Relay, which never holds one, so it stands.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
…erty lists

The trust-boundary diagram, its description, the figure alt text, and the
SSRF bullet each listed "credential" among the properties trusted
configuration fixes on an HTTP source. An HTTP source under the `none`
authentication kind resolves no credential, so the list reads as an
overclaim even though the fixed property is really the authentication
kind. The normative sentence in the same section already says
"authentication"; these four now match it.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
@jeremi
jeremi force-pushed the agent/evidence-transport-sweep branch from 15a0309 to 309f4ca Compare August 21, 2026 09:04
@jeremi
jeremi merged commit aae53d5 into main Aug 21, 2026
33 checks passed
@jeremi
jeremi deleted the agent/evidence-transport-sweep branch August 21, 2026 09:08
jeremi added a commit that referenced this pull request Aug 21, 2026
This reverts commit aae53d5.

The v0.24.0 release PR recorded immutable docs archive digests in
`docs/site/src/data/archive-lock.yaml`, and #799 merged after it. Its
content changes move the built v0.24.0 docset, so the candidate's
`archive:snapshot --verify-lock` step now fails with `archive bundle
v0.24.0 does not match its immutable lock entry`.

A locked entry cannot be re-recorded: `assertArchiveLockImmutable` rejects
any change to an existing entry, and `addArchiveLockEntry` refuses to
overwrite one. The release therefore requires `main` to carry the content
the lock was recorded against. This revert restores a tree byte-identical
to the preparation commit b227235.

Re-land #799 immediately after v0.24.0 publishes; the change is sound and
belongs in the next release.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
jeremi added a commit that referenced this pull request Aug 22, 2026
This restores aae53d5 (#799), reverted by d1a6c7b so that protected main
carried the docs content the v0.24.0 immutable archive lock was recorded
against.

v0.24.0 has published, and registry-docs-v0.24.0.tar.gz is now a release
asset whose sha256 equals the archive-lock bundle digest. assemble-archives
restores a published bundle in preference to rebuilding one, so the archived
v0.24.0 docset no longer draws its bytes from the checked-out tree and docs
content on main can move without disturbing it. Confirmed locally: npm run
check:archives reports 3 restored, 0 bootstrapped.

The docs/site tree is byte-identical to the original #799 merge.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
jeremi added a commit that referenced this pull request Aug 22, 2026
This restores aae53d5 (#799), reverted by d1a6c7b so that protected main
carried the docs content the v0.24.0 immutable archive lock was recorded
against.

v0.24.0 has published, and registry-docs-v0.24.0.tar.gz is now a release
asset whose sha256 equals the archive-lock bundle digest. assemble-archives
restores a published bundle in preference to rebuilding one, so the archived
v0.24.0 docset no longer draws its bytes from the checked-out tree and docs
content on main can move without disturbing it. Confirmed locally: npm run
check:archives reports 3 restored, 0 bootstrapped.

The docs/site tree is byte-identical to the original #799 merge.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
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.

1 participant