Repository navigation
Commit 66f4f98
authored
chore: retire Registry Notary and make Evidence the documented product (#644)
* style(evidence): expand remaining inline YAML in the reference bundle
Finishes the reformatting the reference deployment bundle already started:
the last flow-style mappings become block mappings, so selector fields, fixed
headers, and selector alternatives are edited and diffed a line at a time.
Verified value-identical: the parsed document is unchanged.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* perf(evidence): commit audit appends in groups to sustain 1000 req/s
Measured audit throughput was about 270 appends/second and flat from 1 to 128
concurrent appenders: every append took one fsync under a held mutex, at
3.70 ms each. At two audit records per request that capped the service near
135 requests/second regardless of hardware or concurrency.
Security review note, required for a change to audit integrity.
What changed
Chain-head ownership moves from registry_platform_audit::ChainState into
Evidence's DurableJsonlSink. ChainState::append held its mutex across
sink.write(), which serialized every append whatever the sink did internally.
The on-disk chain is byte-identical: same keyed hasher, same envelope.
A two-lock split replaces the single mutex. A short state lock claims a chain
position and advances the head, performing no I/O; a separate flush lock is
held across the blocking fsync. Appends arriving during a write form the next
batch. Group commit is leader-follower with no timer and no configured window:
the first caller to arrive while no write is in flight writes everything queued
so far, and the others wait on the flush lock to find their records already
durable. Batch size is 1 at idle and grows by itself under load.
Segments rotate at auditStorage.maximumFileBytes with chain continuity across
the seam, and startup verification is now bounded to the active segment, so
restart time no longer grows with retained history.
Properties preserved
Chain positions are handed out in enqueue order under one lock, so concurrent
appends extend one chain rather than forking it. Nothing is reported durable
before its own bytes are synced. A failed durable write leaves the in-memory
head ahead of the disk, so the sink poisons itself and refuses every later
append for the life of the process rather than chaining onto a record the disk
never received; concurrent waiters on a poisoned batch each receive the
failure instead of hanging. A batch crossing a segment bound flushes the
buffered run into the outgoing segment before sealing. Pinned-writer identity
is still validated before the append and again after the sync, for both the
segment and the lock file.
Defect found and fixed during review
The first version of the split read the recorded fingerprint under the state
lock but compared it after releasing the lock, and acquired that lock with a
non-blocking try_lock. Both were wrong under load: the service's own appends
changed the file between snapshot and comparison, so readiness read its own
traffic as external mutation, and try_lock lost to writer contention, which is
busyness rather than ill health. Measured 195 of 200 probes unready while the
service wrote its own audit records, which would have taken a healthy service
out of a load balancer rotation under sustained load. The fingerprint is now
compared under the same lock the writer advances it under, and only while the
sink is quiescent. Tamper detection is unchanged.
Accepted risk
Startup verification is bounded to the active segment, so tampering inside an
already sealed segment is not caught at boot. The new `evidence verify-audit`
command is the out-of-band counterpart that does catch it. It reads the audit
path and hash secret from the deployment's own runtime document and takes no
path or secret flags, so it can neither be aimed at a foreign chain nor take a
secret on a command line. It reports a missing sealed segment as archived
history rather than as corruption, so deliberate archival stays
distinguishable from tampering.
Cross-crate change
AuditEnvelope::new_with_hasher in registry-platform-audit becomes public.
Visibility only, no behavior change. The alternative was a second
implementation of the chain hash inside Evidence, and two implementations of a
security-critical hash chain diverge eventually. Notary shares the crate and is
unaffected; its tests pass unchanged.
Result
Audit appends, same host, before and after: 270/s to 322/s at 1 concurrent
appender, ~270/s to 1,253/s at 8, to 4,245/s at 32, and to 12,864/s at 128.
End to end over real sockets through the whole request path, including token
verification, rate limiting, Rhai preparation, one source call, Rhai
extraction, evidence construction, Ed25519 signing, and both audit appends:
6,976 to 7,057 requests/second across two runs at 128 in flight, p50 17.8 ms,
zero non-2xx. The in-process source's own ceiling is measured in the same run
and the check reports the run inconclusive below a 5x margin; it measured 20.8x.
The request path also gains structured request logging, a correlation header,
and an opt-in metrics listener, and the audit and rate-limiter capacity gauges
that make the ceilings above observable. They land here rather than separately
because the gauges read storage state this change introduces.
The traceability checker now accepts #[tokio::test(flavor = "multi_thread")] as
a test item. A concurrency invariant cannot be proven by a single-threaded
test, so the stricter form meant leaving these invariants untraced.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* fix(evidence): validate deployment secret material in check
evidence check accepted a deployment whose mounted secrets the server
refuses at startup, so a signing key whose kid does not match the
bundle's signing.activeKeyId passed check and then failed every start.
Check now resolves and validates the audit, subject-binding, and
signing material exactly as startup does, without opening the audit
chain; source credentials stay unresolved because readiness owns them.
Security review notes: startup validation is extracted into
validate_secret_material, not altered; check gains read-only secret
resolution with the same fixed value-free operator messages; no secret
bytes reach output; startup error-class precedence now reports
subject-binding and signing faults before audit chain faults when both
are broken.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* feat(evidence): add a compose deployment for the adopter images
A static reference docker-compose for the evidence service and the
optional mint pairing: static private addresses on a user-defined
network because the listener refuses wildcard binds, the deployment
project mounted read-only with a container-shaped runtime file
overlaid on the project's host-shaped one, and the audit chain in a
named volume. The files are adopter-owned after copying; there is no
generation contract. Verified end to end against the locally built
images: check, both health endpoints, and audit persistence across a
restart.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): route compose traffic on readiness, not liveness
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* feat: add distroless adopter and development images for mint and evidence
One multi-stage Dockerfile built from the repository root, with a
cargo-chef recipe per binary so dependency compilation is a cacheable
layer and an unrelated workspace manifest change invalidates neither
image. Both images run as the distroless nonroot user with no shell.
These are not release evidence; released images keep following the
release/docker reproducible-build path.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* feat(evidence): declare source response shapes and add get_path
Every source now carries a required responseSchema: a closed JSON Schema for
the projected response, validated in Rust after projection and before the
response reaches an extraction script. A response outside the shape its adapter
was reviewed against is a source-protocol failure and no script runs, so
hand-written protocol checking is no longer the only thing between a malformed
response and fact construction.
The response role relaxes two rules the fact and adapter-parameter roles keep,
because the projected tree is not the wire response. It may require fewer
members than it declares properties, since projection drops a leaf the record
did not carry and an ambiguous page is decided before any record is read. A
node may also write its type as the pair [T, "null"], because a source that
reports an explicit null has that null carried through projection verbatim; it
reaches the script as the same unit marker is_missing already reads. That pair
is the only union the subset admits and only in this role.
get_path resolves one bounded RFC 6901 pointer and answers with the missing
marker, replacing chains of contains and type_of in the migrated adapters. A
pointer that is not resolvable syntax, exceeds 256 bytes, or exceeds 16
segments is a script fault and fails the invocation rather than answering
missing.
Security-sensitive: this narrows what reaches bounded script execution and adds
one enforcement point before extraction. It changes no authentication,
authorization, signing, audit, or disclosure behaviour, and every source
protocol failure stays publicly indistinguishable. Tracked as the
source_response_shape invariant with a bound negative test.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs: add Notary retirement and Evidence onboarding plan, DoD, and /goal
Track the approved consolidation plan as a repo-level artifact: retire
Notary, keep Relay, land Evidence onboarding with CI-verified tutorials,
and prove the Evidence-over-Relay composition. The /goal command drives
execution one DoD item at a time and keeps the plan's checklist and
status log current. Narrow the .claude/ ignore so only the shared
project commands directory is tracked.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* feat(evidence): add a curl | bash installer for the Evidence toolset
evidencectl gains an install.sh mirroring the registryctl installer
conventions: it installs evidence, evidencectl, and mint together or not
at all, verifies every release asset against SHA256SUMS before anything
reaches the install directory, refuses unpinned or non-canonical release
tags, and supports an offline EVIDENCECTL_ASSET_DIR mode for
higher-assurance installs after release/VERIFY.md. Eleven offline bash
tests drive the script through fake curl and uname binaries; shellcheck
and shfmt clean.
Ticks F1 in plans/notary-retirement-and-evidence-onboarding.md.
Review notes: distribution tooling that verifies release artifacts. It
performs integrity verification only (SHA256SUMS) and states so;
authenticity verification remains the documented release/VERIFY.md
path. Failed or interrupted installs roll back to the previous toolset.
No production code changes.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* feat(release): ship the Evidence toolset through the release channel
The reproducible builder now builds evidence, evidencectl, and mint and
checksums them into dist/bin like the existing binaries. The candidate
workflow stages evidencectl-<tag>-install.sh beside the registryctl
installer. The registry-release artifact inventory accepts the three
binaries and the installer as optional artifacts, with per-platform
optional backfill names and an installer filename guard; two unit tests
cover acceptance and continued rejection of unknown artifacts.
Ticks F2 in plans/notary-retirement-and-evidence-onboarding.md.
Review notes: release provenance change. The new artifacts are optional
in the inventory so every historical manifest still validates
(registry-stack-beta-26.yaml re-validated); they flip to required at a
minimum version only after the first release ships them end to end
(plan item F3), the way registryctl-installer did at v0.14.0. The
builder image, cargo flags, and checksum flow are unchanged; the new
binaries follow the exact existing pattern. Verified: full
test_registry_release run (only pre-existing rust-result shard failure,
flagged separately), test_release_candidate, test_release_workflow_
structure, test_release_workflow_guard, test_check_release_source_model,
manifest validation, source-model check, bash -n, shellcheck.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): document how adopters install the Evidence toolset
The product README explains the release-asset installer (pinned tag,
three binaries together or not at all, SHA256SUMS integrity check, the
release/VERIFY.md path plus EVIDENCECTL_ASSET_DIR for authenticity),
its environment variables, and the source build alternative.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs: record that root CI already drift-checks the Evidence OpenAPI
Ticks B2 in the plan: the evidence-contracts CI job regenerates every
Evidence contract, the OpenAPI document included, and byte-diffs the
committed products/evidence/generated/ artifacts, triggered for crate
and product-path changes alike. No new gate needed.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* fix(evidence): stop response schemas requiring leaves projection may drop
A response schema that required a projected leaf of every record turned an
ordinary ambiguous page into a source-protocol failure: the page is refused
from the pager before any record is read, so a record on it need not be
complete. Relax the record shapes to require nothing, move the presence
checks a single matched record must pass into the extract scripts, and add
fixture cases covering both sides.
Projection guarantees intermediate containers and only drops terminal
leaves, so requiring an intermediate is redundant and guarding one in script
is unreachable; state that rule in the source contract's response_shape.
Reported by the tutorial writer as finding 23.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* feat(release): build the Evidence toolset for the optional platforms
The candidate workflow's native build-platforms matrix (macos-arm64,
linux-arm64) now builds evidence, evidencectl, and mint beside
registryctl and stages them into the platform payload. The assemble
step and the artifact inventory accept the per-platform names
generically, so no other step changes.
Ticks F4 in plans/notary-retirement-and-evidence-onboarding.md:
linux-amd64 stays the required reproducible baseline; linux-arm64 and
macos-arm64 are optional, matching registryctl.
Review notes: release provenance change scoped to the existing native
matrix job; toolchain pin, targets, and upload flow unchanged. The
registryctl version-verification step stays registryctl-only.
Verified: test_release_candidate, test_release_workflow_structure,
test_release_workflow_guard (63 tests), YAML parse.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): record group commit as implemented in PERFORMANCE.md
The file still described group commit as deferred work and presented the
pre-batching 122-161 rps runs as the current baseline, while audit.rs
commits appends in groups and OPERATOR-CONTRACT.md records the sustained
7057 requests/second measurement. The baseline rows stay as the labeled
before-figure; the group-commit section now states the implemented
behavior and its preserved properties, and points at the
OPERATOR-CONTRACT measurement. The Linux re-measure caveat stays.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(site): add the Evidence onboarding content surface
New pages: the RS-PR-EVIDENCE protocol profile (56 requirements, each
citing its frozen contract file), the first-assertion tutorial (E1,
commands and outputs verified against the built binaries), Configure
Evidence, Evidence security model (every invariant-matrix id covered
and traced to named tests), Evaluate Evidence, the Evidence problems
reference (all nine public problem types), and Registry Mint configure
and reference pages. The when-to-use page gains the Evidence door and
the four adopter personas; the glossary disambiguates Evidence (the
product), Notary evidence credentials, the Evidence toolset, and
Registry Mint.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): quote the fixture placeholder in the operator contract
The docs site's shell-fence gate parses every sh fence with /bin/sh -n
once the operator contract is mirrored as a product page; the bare
<path> placeholder reads as a redirection there. Quoting it keeps the
placeholder convention and parses.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(site): wire the Registry Evidence product into the site plumbing
repo-docs.yaml mirrors seven Evidence product pages from
products/evidence at the current ref, the latest docset registers the
product, and the OpenAPI pipeline pulls the generated
registry-evidence.openapi.json (drift-checked in root CI) into a Redoc
operations section beside a new narrative API page. The sidebar gains
the Answer with Evidence flow, the Evidence security, problems, Mint,
evaluate, and RS-PR-EVIDENCE entries, and a Registry Evidence product
group.
Archived docsets predate Evidence, so sync and fetch now filter
docset-excluded docs before requiring a docset product pin, a repo
absent from an archived docset keeps its current ref and rides the
current shell (verified against v0.15.2: the Evidence throw is gone;
that docset's remaining sync failure is a pre-existing Notary allowlist
gap on main, flagged separately), and the Evidence product group splices
optionally while generate-sidebar.test.mjs pins its presence for the
current docset. Site suite: 267 tests, 0 failures; redocly lint clean
for the new spec.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs: tick B1, B3, B7, F6, F7 and record the docs-wave status
The plan's status log records the archived-docset design decision, the
partial B5/B8/F5 state, the pre-existing failures flagged out of scope,
and the next unblocked items (B4 gate, E6, E2-E5).
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): use straight quotes in the operator contract lead
The Vale gate on the mirrored product page rejects typographic quotes.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* fix(evidence): remove eight adopter frictions found writing the tutorial
A tutorial writer took the Mint and Evidence scaffold end to end and
recorded where the tooling misled or under-informed them. Each fix below
closes one of those:
- Bundle immutability errors name the failing path, not just the rule.
- `evidence serve` announces a start only once both listeners are held,
and a bind failure names the address and the cause.
- A rejected source response shape logs which member failed which schema
rule.
- The bounded-integer rejection states the whole rule it enforces.
- `evidencectl new --port` chooses the Evidence listener port, and
refuses the port a paired `--with-mint` deployment binds.
- `--with-mint` keeps the example caller's key at project root: the
caller is a different party from the issuer that registers it.
- `evidencectl fixtures run` reports the cases evaluated beside the
artifact counts, which are not a coverage figure.
- New `evidencectl keygen token` writes a printable, header-safe bearer
token. `keygen secret` makes HMAC key material whose raw bytes an HTTP
header rejects; its help and the scaffold's printed steps now say so.
Security review notes:
- `keygen token` writes 32 bytes of `getrandom` entropy as base64url
without padding, owner-only (0600), with no trailing newline because
the runtime reads the file whole. The value is never printed, and a
test asserts it reaches neither stream.
- The response-shape rejection log is built from the violation's
instance and schema pointers only. The library's own message embeds
the offending value and is deliberately unused; a test plants a secret
in a rejected response and asserts it never appears.
- The bind failure message carries the configured address and the
operating system's reason, both already operator-supplied or
operator-visible. No secret reaches it.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* feat(docs): add the Evidence tutorial gate
check-evidence-tutorials.sh extracts the first-assertion tutorial's
shell fences, drift-checks the fence count and required command and
output literals, then replays the on-machine journey (scaffold, key
generation, the immutability freeze, the fixtures run, cleanup) against
toolset binaries built from source or supplied via EVIDENCE_BIN and
EVIDENCECTL_BIN. The release-download fences wait for a release that
ships the toolset (plan item F3). The dry-run drift check joins npm run
check; three node tests cover the pass case and both drift failures.
Verified end to end locally: the tutorial executes verbatim and reports
2 passed, 0 failed.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* feat(ci): run the Evidence tutorials from a clean container
A path-gated evidence-tutorials job tests the gate helpers, checks
command drift, builds the toolset with the ci profile, and executes the
tutorial inside the repository's pinned builder-image digest with the
repo mounted read-only and the prebuilt binaries injected, so the run
sees only a clean Debian userland plus the toolset. The classifier
gains an evidence_tutorial output firing on the gate's inputs and on
registry-evidence and registry-evidencectl changes, with routing tests,
and the required-results job counts the new job. actionlint clean;
classifier suite 29 tests green.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(site): add the move-Evidence-to-production-signing tutorial
Tutorial E6: production key generation with the kid-must-match rule,
JWKS assembly with the retired-key retention window, offline validation
with evidence check and fixture evaluation, serve and readiness
confirmation, the startup-only rotation procedure, the limits of what a
signature proves, and troubleshooting. Every rule restates
products/evidence/OPERATOR-CONTRACT.md; commands verified against the
evidencectl CLI. Site suite 270 tests green; Vale clean.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs: tick B4 and B6 and record the tutorial-gate design
The status log records the gate's container caveat, the F3 dependency
for the release-download fences, and that extending the executable gate
to further tutorials belongs to B5.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs: record the A1 token-topology outcome
Relay embeds no token issuance and verifies inbound callers through
configured OIDC with EdDSA support; Mint issues EdDSA tokens and serves
a JWKS, so IdP-less Evidence-over-Relay is Relay verifier configuration
pointed at Mint's issuer, and the reserved Mint-for-Relay code branch
is not triggered. registry-platform-sts turns out to have zero
consumers and joins the C4 orphan candidates. The Mint claim-set
question moves to A2 and D.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* fix(evidencectl): keep zero bytes out of test-provisioned secrets
The scaffold test wrote 32 raw random bytes per secret file, and the
runtime rejects secret material containing a NUL byte, so each file
failed ~12% of the time and a full run roughly 40%. Regenerate until
no byte is zero, exactly as keygen secret does.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* feat(evidencectl): suggest source configuration from an OpenAPI document
evidencectl source suggest turns one OpenAPI operation into draft
Evidence source artifacts: the projection allowlist, a closed-subset
response schema, a get_path extract skeleton, a facts stub, and a
pasteable sources block. An interactive front-end (operation picker,
leaf multi-select, bound prompts with provenance-labelled defaults)
and the flag-driven front-end share one deterministic core, and every
run ends by printing the equivalent fully-flagged command.
The tool derives what the document can state, observes optional
bounds from a local sample response, and never invents a bound: an
unresolved decision is omitted plus a TODO comment, so evidence check
rejects the draft until the operator supplies it. The runtime stays
the only validator of the closed subset.
Security review notes: the drafted acquisition posture is the weakest
claim (record-transformed) with an explicit upgrade TODO, never
field-projected on the operator's behalf; sample files are read once,
size-capped, and only derived numeric bounds ever reach an artifact,
pinned by canary tests; no network access anywhere, external $refs
rejected; source ids are sanitized so generated file paths cannot
escape the project bundle directory; existing files are never
overwritten.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* test(evidence): prove a signed assertion over a Relay-shaped source
A wiremock mirrors the Relay OpenAPI's protected household-record read
by hand (path, bearer, Data-Purpose, entity response shape) so Evidence
proves the blessed Evidence-over-Relay composition without depending on
Relay code. The test drives OAuth client credentials through the frozen
runtime's public API to a signed flattened JWS, verifies it against the
deployment JWKS under the full relying policy, and pins minimum
disclosure with canaries: the record id, the untouched field, and the
raw region code never reach the assertion payload. Zero production-code
changes were needed; every composition component already exists in the
frozen V1 runtime.
Ticks A2 in plans/notary-retirement-and-evidence-onboarding.md.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* wip(evidence): commit in-flight work set aside for the worktree merge
Committed on request so the evidencectl/source-suggest worktree branch
can merge into a clean main. Contents are the main-worktree WIP that
the merge automation stashed as source-suggest-merge-setaside: the
evidencectl suggest module (OpenAPI ingestion, flattening, narrowing,
emit, interactive mode, with fixtures and five test files), evidence
crate follow-ups to the source response-schema work (bundle, runtime,
main, cli and source-contract tests), boundary-day fixture cases for
both reference deployment projects, scaffold template and test
updates, and wording refinements to the two Evidence tutorials.
Not reviewed or verified as a unit; committed as WIP for review and
squash. Restored verbatim from the setaside stash tree.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* Revert "wip(evidence): commit in-flight work set aside for the worktree merge"
This reverts commit 1f2390fb901b4593a9445951303cf3d63a0d8c11.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(site): state the exact immutability refusal wording in tutorials
The runtime prints the refused input after the error prefix, and the
secret provider root has its own ownership refusal; both tutorials now
quote the real messages. Tutorial gate dry-run still passes.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* fix(evidencectl): make the evidence binary resolver crate-visible
suggest::emit calls fixtures::resolve_evidence_binary, which was private to
its own module. The binary target does not declare mod suggest yet, so the
error only surfaced under --all-targets, where the suggest_emit test target
includes both modules and fails to compile.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* fix(evidencectl): dispatch the source suggest command from the binary
The suggest feature merged with its modules, fixtures and five test files
but without `mod suggest`, without the `Source` subcommand, and without the
`inquire` dependency its interactive front-end imports, so the crate did not
build and the command was unreachable.
Four of the five suggest test files pull modules in with `#[path =
"../src/suggest/X.rs"] mod X;` because the crate has only a `[[bin]]`
target. That compiles a module whether or not `main.rs` declares it, which
is how a fully tested command shipped unreachable. `tests/cli_surface.rs`
drives the real binary over the whole top-level subcommand set, asserting
each one is both listed and dispatchable, so the same omission fails next
time. Verified red at db20eab0: `--help` lists four commands, not five.
`inquire` joins the workspace dependency table with its default features,
matching every other dependency in the crate. Default features are kept
because dropping them swaps the fuzzy filter behind `Select`/`MultiSelect`
for substring matching, which is a behaviour change rather than a wiring fix.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* fix(evidencectl): correct the bounds and quoting the suggest draft emits
Review of the merged `source suggest` pipeline found seven defects that
each let a draft claim more than the evidence behind it supports.
Page-size detection matched any parameter name containing "page", "size"
or "limit", so a `page` index beside a `pageSize` ceiling, and unrelated
names like `fileSizeCeiling`, both fed the array bound. The comparison is
now against a closed list of whole normalized names. When several genuine
size parameters are advertised, the fallback takes the smallest rather
than the largest: only the smallest ceiling is one a response can
actually reach, and bounding above it points away from minimum
disclosure.
The emitted artifacts escaped too little. The reproduce line now
shell-quotes any path outside a safe character set, the extract script
emits a real Rhai string literal for the pointer, and drafted YAML quotes
on any control character rather than newline alone. A root-level array
carried no bound annotation at all, and TODO paths named the template
directory rather than the scaffolded project's, so neither told the
operator where to act.
`evidence check` classification keyed on a substring, so a bundle
rejection whose message merely mentioned a runtime stage was reported as
unprovisioned secrets. It now matches the runtime's fixed stage messages
at the start of stderr. An unnamed root pointer renders as
"(response root)", the wording narrow.rs already uses. The OpenAPI loader
gained the size ceiling the sampler already enforces.
Every fix carries a test proved failing first.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* feat(evidence): add a protected-read reference deployment project
The two existing reference projects both read a registry product's own
API and neither covers residence region. This one reads a protected,
scoped, read-only registry API of the shape Registry Relay presents,
and signs residence region as a coarse controlled code mapped from the
register's own code, so all four coequal acceptance definitions now
have a deployment-shaped worked example.
It earns its place on lookup shape rather than branding: the envelope
reports no total, only a page of records and a further-pages flag, so
uniqueness is decided from both signals together and a single record on
a page claiming further pages is ambiguous. The bundle names no
registry product and depends on none.
Eighteen fixture cases run through the production ABI offline. No
Evidence production code changes; the only Rust edits extend the three
existing #[cfg(test)] reference-project lists.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(site): correct the first-assertion tutorial against the shipped scaffold
The tutorial described a residence-region acceptance definition the
scaffold does not ship, listed a codelists directory it does not create,
and printed a fixtures-run output that predates the case counts
evidencectl now reports. A reader following it saw different output than
documented on their first command.
The gate did not catch the output drift because it substring-matched the
count-free prefix, so pin the full documented lines instead. The gate
also failed confusingly, mid-journey, when handed a relative binary
path; refuse that up front with a message that names the cause.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* fix(evidencectl): read real-world OpenAPI documents in source suggest
Trialling `source suggest` against two published descriptions, a DHIS2 2.42
document and the OpenCRVS Events 2.0.0 document, showed the tool refusing
schemas the closed subset already admits, and refusing whole operations over
constructs it could bound instead.
- A `$ref` cycle no longer fails the operation. The repeat is cut with a
marker that declares no type, so the flattener skips it and never offers it
as a leaf, and a whole-subtree selection over it is rejected by name. A
cycle is not missing information, it is an expansion with no end; cutting it
keeps the rest of the operation selectable.
- An `anyOf`/`oneOf` of exactly two members where one is `{"type": "null"}`
collapses into the kept member carrying `[T, "null"]`. This is how a
generated 3.1 document spells nullability, and the subset already admits the
result.
- A `["null", T]` pair is reordered to `[T, "null"]` at resolution time.
Flattening accepted either order and narrowing required one, so a document
writing the pair the other way passed one stage and failed the next.
- A node stating no `type` but stating `properties` or `items` is read as
`object` or `array`, with a note naming the reading.
- A bound clamped to the subset ceiling is now credited to the ceiling, not
to the document. A specification writing `maxItems: 2147483647` is declining
to bound the array; carrying its name onto the 256 the draft ends up with
would read as a promise the source never made.
- A run with no terminal now lists the operations, or the leaves of the chosen
operation, alongside the flags it needs, and a URL passed to `--openapi` is
refused with the command that fetches it.
Measured on the two documents: the DHIS2 sweep of 154 GET operations goes from
87 yielding nothing to 1, and that one describes a schema with no declared
properties. On the OpenCRVS document `GET /config` goes from failing outright
to 32 leaves, `POST /events/search` from 10 leaves to 31, and `GET /locations`
from 2 to 6.
No source-product name enters production code, dependencies, features,
configuration schemas, routes, or CLI options; the new fixtures are neutral.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(site): run the Evidence tutorial gate over a registry of tutorials
The gate replayed one hard-coded tutorial. The onboarding path is a series
of them, so the drift knobs move into a per-tutorial spec: the sh fence
count, the ordered reader journey, the literals the text must keep, and the
lines the transcript must contain. Each tutorial replays in a reader
directory of its own.
A journey step is either a range of sh fences to execute or a documented
before/after fence pair applied to a file the reader edits, which is what a
tutorial that modifies the scaffolded bundle needs. Files a reader creates
outright stay inside the sh fences that create them, so the text a reader
copies is the text CI runs.
Registering a tutorial is now a slug plus a spec branch.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* ci: keep Evidence tutorial routing in step with the gate's registry
The Evidence tutorial job watched one tutorial page by name. The onboarding
track is a series of them, so the next tutorial added would not have
triggered the job that replays it, and could have broken with no pull
request noticing.
The watched inputs become a named constant, and a test reads the gate's own
tutorial registry and asserts every registered slug is watched. Adding a
tutorial to the gate without wiring its page here now fails, naming the path
that is missing.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* feat(evidencectl): fetch the OpenAPI document for source suggest from a URL
Registry APIs publish their description at a well-known URL far more often
than they ship it as a file, so `--openapi` now takes either. Nothing about
the draft changes: it is still reviewed by a human and still carries a TODO
wherever a bound could not be derived.
Security review note. The description decides which leaves the operator is
offered, and the projection they pick from it is the data-minimization
boundary of the finished source, so a tampered document could quietly widen
what a deployment reads. The rule applied is the one the runtime already
enforces for the source URLs it will itself call (`validate_source_url`):
https anywhere, plain http only to a numeric loopback host, never a
credential in the authority. The credential refusal does not echo the URL
back, so a password cannot reach a terminal or a scrollback buffer. No
request carries authentication; a description behind a token is fetched by
the operator and passed as a file. Redirects are followed but bounded, and
the URL the response came from is re-checked under the same rule. The body
is capped while reading rather than from Content-Length. Fetched text
reaches only the draft the operator sees.
Transport is ureq, already a workspace dependency used by registryctl, so no
crate enters the graph and cargo-deny is unaffected. Tests are hermetic:
policy is a pure function, and transport runs against a throwaway server on
a loopback port, which is also the one case where plain http is permitted.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): note the URL form of source suggest --openapi
States the fetch rule where the flag is documented, so an operator reading
the README learns the constraint before hitting the refusal.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* fix(evidence): name why the audit boundary refused to start
Startup printed one line, "runtime audit initialization failed", for four
unrelated faults with four unrelated remedies: a configuration bound out of
range, an unusable hash secret, a file or lock that is not owner-only, a
second writer holding the sink lock, and a chain that no longer verifies.
From outside the process they are indistinguishable, and the wrong guess
sends an operator hunting for tampering in what is a permission bit.
Classify the fault at the boundary and append its cause to the same fixed
message, in the shape bundle immutability failures already use.
Security review notes:
- Each cause is a fixed &'static str chosen from the fault class. No path,
no secret, no chain content, and no operating-system message reaches it;
the audit path an operator needs is already in their runtime file.
- The classification is reporting only. Every fault stays fail-closed and
the service still refuses to start on any of them.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* feat(evidencectl): report every artifact mode the runtime will refuse
Evidence and Mint refuse a deployment artifact whose permissions or
ownership are wrong, and each refusal names one artifact. An operator who
has run `chmod -R` over a project therefore discovers a project-wide
mistake one restart at a time, and the audit chain and the caller keys are
refused by paths that are not part of the freeze the generated README
documents.
`evidencectl doctor --project <dir>` walks the project once and reports all
of them: the bundle tree and `runtime.yaml` under the immutability rule,
the secret root and every secret the bundle references, the audit chain and
its lock companion once they exist, and the key files of a paired Mint. It
starts nothing and needs no `evidence` binary, so it is usable before the
deployment is complete.
Secrets are discovered from the bundle's own `secret:file/` references
rather than by listing the secret directory, because `keygen signing`
writes the public half of a key into that directory at 0644 by design and a
directory walk would report a project the runtime accepts.
Security review notes: this is advisory and read-only. It stats artifacts
and reads only the two YAML configuration documents; it never opens a
secret, a key or the audit chain, and it reports modes, link counts and
uids but no file contents. It relaxes nothing: `evidence check` and startup
remain the only authority on what a deployment may run with, and doctor
compares ownership against the user running it rather than the user the
service runs as, which the module doc and the generated README both state.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* fix(evidence): name an unreachable access-token issuer and keep serving through its outage
A deployment whose `jwksUri` could not be retrieved answered `/ready` 200 and
then rejected every request with the same closed `401` a bad token receives,
with nothing in the log naming the issuer, the URI, or the transport error
underneath. Ready, 401, silence.
Underneath both symptoms was a third problem: `key_for_kid` propagated the
refresh transport error from its stale-cache arm, and `refresh` only writes
keys on success. Past `cache_ttl`, an issuer that had merely gone quiet caused
total rejection using a valid key still sitting in the cache.
The verifier now keeps serving an already-retrieved key set for `cache_ttl`
plus a bounded `outage_tolerance`, and only while the issuer cannot be reached.
Startup attempts the key set once and names a `jwksUri` it cannot use.
Readiness asks on every check and reports what comes back without letting the
answer decide readiness. Two rate-limited WARNs name an unretrievable key set
and a key set being served without being confirmed.
Security review notes:
- Authentication surface. No change to what is accepted: signature, issuer,
audience, algorithm, token type and claim extraction are untouched, and the
caller-facing rejection stays the same closed `401` with no added detail. The
new material is operator-facing logging and cache lifetime.
- Bounded outage tolerance. A key the issuer has withdrawn stays trusted for at
most `cache_ttl` (600s) plus `outage_tolerance` (900s), and only while the
issuer is unreachable; any successful refresh clears it immediately. The
window is bounded rather than open-ended precisely because an attacker who
can keep the issuer unreachable would otherwise hold it open indefinitely.
This trades a bounded revocation delay during an outage against total
rejection during one; the outage is reported for its whole duration rather
than degrading silently to a cliff.
- Log content. The WARNs carry the operator-configured `jwksUri`, an outage
duration, and a cause chain bounded to three causes and 512 bytes. No token,
claim, key material, or caller-supplied value reaches them, and they are
rate-limited to one line per minute so an issuer outage cannot drive log
volume.
- Readiness. Deliberately not a gate on the issuer. It is a shared dependency
no replica owns, so failing readiness on it would remove every replica from
rotation at once for a cause rotation cannot address, while the verifier was
still serving requests. This follows the same conclusion Envoy reaches with
its `fast_listener` escape hatch and Kubernetes guidance names as a
cascading-failure anti-pattern.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): add the acceptance-definition authoring tutorial
The first tutorial gets a reader to one passing assertion but leaves the
scaffold's abstract boolean in place. This second one has them author a
coequal acceptance definition end to end: a narrower selector profile, a
second source, a codelist that maps a register's fine-grained code to a
coarse disclosed one, a derivation, and its own fixture file.
Registered in the tutorial gate, which replays all thirteen command blocks
and applies the four documented before/after edits to bundle/evidence.yaml.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): add the institution-source connection tutorial
The first two tutorials work against the scaffold's stand-in source. This
third one connects a real institution read API: draft the source from its
OpenAPI document with evidencectl source suggest, review the draft rather
than trust it, write the prepare and extract scripts, and prove the adapter
offline from sanitized fixture cases before any live request.
It teaches the two runtime rules that are easiest to get wrong: a response
schema describes the response after projection, not what the API returns,
and an absent key needs get_path rather than direct indexing.
Registered in the tutorial gate, which replays all eleven command blocks and
applies the three documented before/after edits.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* ci: route the two new Evidence tutorials to the gate that replays them
A tutorial the change filter does not watch is a tutorial that can break
without any pull request noticing. The parity test already refuses a
registered tutorial missing from this set.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* fix(docs): restore the docs site check for the Evidence surface
The Evidence onboarding surface landed with three defects the site check
catches and nothing else does, so `npm run check` has been red since.
`reference/mint.mdx` wrote byte and entry ceilings as bare `<=` inside table
cells, which MDX reads as the start of a JSX tag and refuses to parse, taking
the whole build down. State the ceilings in words instead.
The Evidence API reference was registered with starlight-openapi but not
added to the list of generated bases, which three separate consumers each
kept their own copy of. Its pages therefore advertised a Markdown twin the
build never generates, failing both the coverage check and the built link
check. Move the list to one module, read it everywhere, and pin it to the
bases astro.config.mjs actually registers so the next API reference cannot
repeat this.
`security/evidence.mdx` linked to `report-a-vulnerability/` relative to a
page one level deeper than the one it was copied from.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): point tutorial readers at evidencectl doctor
Both tutorials explain that Evidence names one refused artifact per restart,
which is exactly the friction doctor was added to remove. Name it where the
reader is already stuck, and say plainly that the missing source bearer token
it also reports is expected in a project that only replays fixtures offline.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): teach the real response-schema defect in the source tutorial
The tutorial claimed projection drops an intermediate container when its
only selected leaf is absent, and built a repair step on that claim. It
does not: a key is omitted only when it is absent and its projection node
is terminal, and an absent intermediate is a projection violation. The
repair step was a no-op and the lesson contradicted the source contract.
Teach the defect the contract names instead. Requiring a projected leaf of
every record turns an ordinary incomplete record into a source-protocol
failure, so the requester is told the institution is unavailable rather
than that evidence is not available; the check belongs in the extract
script, which this project already does. The step is now load-bearing:
without it the fixtures fail.
Two other facts had gone stale against the merged source-suggest work: one
verbatim line of the drafting report, and the claim that --openapi never
fetches. Pin that report line in the gate so the next rewording fails CI
instead of leaving the quoted transcript wrong.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): cover $ref cycles in the source connection tutorial
A schema that refers to itself is common in institution documents: offices
nest, so an office names the office above it. evidencectl cuts the repeat at
its first repetition and reports it on standard error, and a reader whose
needed leaf sits below such a cut has to select members individually rather
than the subtree above it. The tutorial's synthetic document had no cycle,
so the page never showed this.
Adding one costs nothing downstream: the drafted schema, the derived-bounds
report and the source block are byte-identical with the cycle present, and
the fence count is unchanged. Pin one line of each quoted transcript in the
gate so a rewording fails CI rather than leaving the page stale.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(site): label every tutorial with whose it is
The four deployment roles start/when-to-use.mdx defines were prose only, so
nothing tied a tutorial to a reader. They are now a checked vocabulary: a
`persona:` key required on every doc_type: tutorial page, validated against
src/lib/doc-personas.mjs, rendered under the title as a link back to the
definitions.
A unit test holds the list and the page in step in both directions, so adding
a role to one without the other fails rather than drifting.
This is a different axis from `audience`, which names who reads a
specification (RS-TERMS Section 6). The two vocabularies stay apart.
No tutorial claims consumer or verifier yet: that page is E5, still unwritten.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* ci: bind the adopter image to the Debian 13 boundary
docker/Dockerfile was reviewed and committed but no check held it to the
same base-image contract as the release and per-product images, so the
digest pins could drift silently.
It does not fit the release shape: one file builds two binaries as two
targets, so there is no single stage named `runtime`, and there is no
HEALTHCHECK because distroless has no shell and neither binary has a
healthcheck subcommand. Rather than bend the file to a shape it should
not have, it is checked under its own: pinned frontend first, every
upstream base digest-pinned, the pinned Rust builder, a nonroot-owned
runtime root, and no shell, package manager, or fetch tooling in any
distroless stage.
Distroless stages are found by their base rather than by a stage name,
and an unpinned base still counts as a stage, so an unpinned base is
reported instead of dropping its stage out of the scan. Comments are
scanned out so a stage can say in prose why it has no shell or curl.
The nightly security workflow now retriggers on docker/ changes and
scans the adopter image for baked-in key or credential material beside
the release images.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): add the served-assertion tutorial
The first tutorial ends offline, and the next thing a reader has to do is
run the product as a service. Nothing walked them through it, and the two
things that make it non-obvious are both real constraints rather than
oversights, so the page teaches them instead of routing around them.
Evidence requires https for the token issuer and its key set with no
loopback exception, and outboundTls.trustProfiles governs only the calls
Evidence makes to sources, so a development certificate authority reaches
the JWKS client through SSL_CERT_FILE on the evidence process alone. That
puts a TLS terminator in front of Mint in the journey, which is what a real
deployment's ingress already is. Sources are exempt from https only for a
numeric loopback host, which is the one place the page can point at a plain
http stand-in, and it says so rather than leaving the asymmetry unexplained.
The gate pins a negative control. Restarting Evidence without the trust
anchor returns HTTP 401 and logs UnknownIssuer, so a passing run proves the
token is checked rather than proving a request succeeded.
No token is echoed or passed on a command line: mint token writes to a file
created under umask 077 and curl reads it with --header @file.
Mint changes now route to the Evidence tutorial job, because the gate builds
and runs mint.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): add the consumer verification tutorial
E5 completes the five-tutorial Evidence track and gives a tutorial the
consumer or verifier persona for the first time. It is the only page that
needs no deployment and no network: evidence verify opens no socket,
resolves no metadata, and fetches no key, so the reader is handed a stored
response and a pinned key set and writes the verification policy from state
their own service retained.
Both inputs are embedded rather than generated. A consumer can mint neither,
and evaluate --fixture signs with an ephemeral in-memory key that never
reaches disk, so there is no cheaper honest way to hand the reader bytes they
did not produce. The gate carries the regeneration recipe and the warning
that the policy values and the --at instants must be refreshed together.
Five negative controls are pinned, so a passing run proves the checks refuse
rather than proving one good response verifies. A replayed nonce and a
different subject both collapse to the single policy class, because a refusal
naming the failing comparison would be an oracle over exactly the retained
state the check protects. An incomplete policy refuses as malformed with no
authenticity verdict at all. A tampered payload byte refuses as signature,
and an unpinned key set refuses as key one stage earlier.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(mint): diagram the client, Mint, and Evidence round trip
The two Mint pages described each side of the token exchange but never the
whole path, so a reader had to assemble the round trip from the token
endpoint contract and the Evidence verification section themselves. Add a
sequence diagram covering it end to end, and point at it from the how-to.
Labels stay short and every wire shape they abbreviate is linked to the
section that gives it in full, so the diagram summarises the contracts on
the page rather than becoming a second source for them.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(site): make the Evidence tutorial track traversable
No sequence of in-page Next clicks reached all six Evidence tutorials:
one page dead-ended with no tutorial link, one pointed backward, and the
consumer verification page never mentioned production signing. Align
every first Next bullet with the sidebar order, and fix the production
signing prerequisite to ask for any scaffolded project rather than one
no intervening page tells the reader to keep.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(site): present two doors on when-to-use
The decision table still offered three, asking a newcomer to tell a
bounded answer from a minimum-disclosure answer before knowing what
either meant. Reduce it to reader intent: read specific data goes to
Registry Relay, learn only a fact goes to Evidence. Notary keeps one
unlinked sentence saying it is being retired; the retirement page is not
published yet. Replace the Relay-plus-Notary composition paragraph with
the Evidence-over-Relay pattern, and name Registry Mint once as the
token issuer for deployments with no identity provider.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(mint): show how to request a token from application code
Add a how-to with worked Python and TypeScript examples that build the
private_key_jwt assertion and exchange it, for callers integrating a
registered client rather than running `mint token` at a terminal. Both
examples were run against a real Mint deployment before being written down.
Also correct the reference errors table: a missing `grant_type` returns
`invalid_request`, not `unsupported_grant_type`, which only covers a
`grant_type` that is present and wrong (`server.rs`).
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): say what each generated key is for
The keygen step listed three commands and their output without saying what
the files do. Name each one against the bundle field that references it,
and explain the two symmetric secrets: the audit key both chains the log
and derives its pseudonyms, and the subject-binding key is scoped so two
audiences cannot correlate assertions about the same person.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(site): give Evidence a front door and a quickstart
Both front doors led with the retiring Notary path. Rebalance them on the
two-door split when-to-use already uses, and add the Evidence overview
route every other section has.
The new start/evidence-quickstart maps the six tutorials, their times, and
their outcomes, names the four coequal acceptance definitions without
privileging one, and states that the track ends at production signing, not
production approval. It carries no commands, so it does not compete with
the first-assertion tutorial.
Three IA assertions guard the result: the overview-route rule now covers
Evidence, and each front door must open an Evidence lane ahead of the
Notary tutorial. Nothing is deleted; removing a Notary lane belongs to the
retirement workstream.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs: record Notary retirement decision
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(plan): record D1, the composed Relay, Mint, and Evidence demo
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* refactor(registryctl): remove Notary tooling
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* fix(ci): expect Evidence contracts in Rust result
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): rewrite the Solmara Lab first run against the composed demo
The tutorial ended at `just smoke`, which proved the lab was alive and
nothing else. A reader finished it without ever seeing the thing the lab
now exists to show: a registry answering a question about a person
without handing over the record.
It now runs the Evidence overlay and closes on one hand-made call.
Reading two fields of one civil-register row through Relay, Evidence
returns a signed `true`, and the page reads the decoded payload back to
name what is not in it. The last Verify command fails unless the answer
is `true` and carries neither the subject reference nor the date of
birth, so the claim is checked rather than asserted.
The gate had drifted well past the Evidence work: it still expected
`redis` and three shared Notary instances the lab dropped some time ago.
It now names the 17 services the page names and asserts the running
total of 41 separately, so the count printed on the page is the count
the gate checks.
Two prerequisites stay documented rather than hidden. No release ships
Evidence or Mint, so the reader names a clean Registry Stack checkout;
and `just generate` rotates the Postgres password, so a second run
against kept volumes dies in bootstrap with a message naming no cause.
That failure now has a troubleshooting row, and the gate refuses to
start against a checkout still holding volumes rather than deleting
someone else's data.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* refactor(release): retire Notary release surface
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs: present Relay and Evidence as maintained products
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* refactor(notary): remove retired product
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): end the onboarding spine on Evidence over a Relay API
The quickstart chooser sent readers down one door and never showed the two
working together. Publish the composed Solmara Lab run, drop its redirect
back to the chooser, and close the quickstart on it, so both doors reach the
one place Evidence answers over a Relay-protected API rather than a local
fixture. Mark the Notary sense of evidence credential as retired in the
glossary.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* ci: retire Notary gates
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* refactor(platform): remove orphaned Notary primitives
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): rewrite the heavy pages around Relay, Evidence, and Mint
The 21 pages that carried most of the Notary product surface now describe
the stack an adopter can actually start on. A new gate,
check-notary-surface.mjs, holds the line: a published page may name Registry
Notary only in a block that also says it is retired.
Four inherited claims were false and are corrected rather than reworded.
Purpose-bound authorization does not narrow what a requirement discloses,
only whether it may be invoked. Evidence has no caller-selectable disclosure
modes, because its request body is closed on four members plus an optional
holder key. The shared platform error section described a helper only Notary
ever called. Solmara Lab builds Evidence and Mint from source, since no
release ships those binaries.
Sections that existed only to describe machinery Evidence deliberately does
not have are deleted, not given an invented equivalent: federation trust,
credential issuance and lifecycle, wallets, delegated subject access, the
Notary approval lane, and the Notary posture producer.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs: remove retired Notary product surface
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(evidence): redraw the two diagrams E1 left orphaned
The heavy-page rewrite removed both figures rather than replacing them,
leaving two SVGs required by the accessibility gate but referenced by no
page, and still drawing retired surfaces.
Trust boundaries now draws the request path Mint to caller to Evidence to
Relay to sources, with the seven boundary sections the page documents and
a lane for operator key material and the published key set. There is no
Mint to Evidence edge: Evidence holds an issuer URL and a key set, so an
edge would draw a runtime dependency the page denies.
The country mesh now draws authorities keeping custody and exposing
bounded outputs through Relay and Evidence, with consumers receiving
answers rather than becoming raw-record readers. The selectable-topology
story is dropped because registryctl cannot express an Evidence topology.
Both figures are restored with alt text restating every label.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* chore(release): drop the external integration retirement guard
The guard asserted that a deleted Notary runner and its evidence packet
stay absent, that a Relay script file still exists, and that CI never
names either path again. None of that is a statement about behaviour, so
a green run reported coverage the release does not have, and the absence
assertions would fail CI for anyone restoring source-read conformance
coverage under the same names. A retirement is better proven by the
absence of dangling references, which the surrounding checks already
enforce.
The Relay-only successor this leaves owed is tracked in the plan.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(plan): record the post-merge review decisions and open C9 and C10
Decisions 9 and 10 settle where the retirement line falls (products and
runtimes, not the layers that must still parse what shipped before it) and
what happens to previously issued approved baseline sets (rejected, with
re-approval as the remedy). C9 tracks the source-read conformance the
retired integration runner took with it. C10 tracks the manifest schema's
federation and PDP identifiers, which need a version decision rather than a
mechanical deletion.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* chore(ci): drop dangling Notary coverage flags and secret-scan allowlists
The three notary-* codecov flags carried coverage forward from paths that
no longer exist, which reads as coverage rather than as its absence. The
notary-postgres status entries move to relay-postgres, the postgres flag
the nightly job actually uploads, so postgres coverage keeps a reporting
surface; both stay informational, so no gate changes strength.
The removed gitleaks allowlist entries each waived a scan for a file or
line that is gone: the Notary holder-proof fixtures, the Notary OpenAPI
example identifiers, and three oid4vci and Notary test lines. A dead
allowlist entry is a standing exemption nobody is checking. Verified with
the CI-pinned gitleaks 8.30.1 over a clean export of the tracked tree:
identical findings before and after, so nothing new is exposed.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* docs(release): retire the Notary release evidence and repin its permalinks
The negative-path coverage map is marked, not trimmed: eight rows whose
every anchor is retired become "Retired evidence", six mixed rows keep
only their live anchors, and NP-20 and NP-21 drop from Covered to Partial
because the product-surface half of their evidence lived on the removed
credentials route. Deleting the rows would have erased the record of what
is now unproven; Partial is the stricter reading, and the Release Decision
now refuses to count a retired row as coverage.
Nine links to deleted Notary documents are repinned at v0.16.3, where each
target is confirmed to exist. The proof-level selector drops three
sensitive-path globs under products/notary, and the error-registry check
says which product set it means.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
* test(relay): restore real-loader coverage for the maintained examples
The Notary retirement deleted live_consultation_journeys.rs, and with it
the only test that staged each maintained operator example the way an
operator deploys it and then drove the real config loader over the result.
config_schema.rs schema-validates the examples in place and
opencrvs_profile.rs loads one profile from the tree; neither proves the
pinned artifact closure still resolves after the example is copied into …1 parent b8ed78f commit 66f4f98
1,281 files changed
Lines changed: 190861 additions & 389724 deletions
File tree
- .claude/commands
- .github
- scripts
- workflows
- crates
- registry-config-report
- fixtures/diagnostics
- src
- tests
- registry-evidencectl
- src
- suggest
- tests
- fixtures
- openapi
- samples
- support
- registry-evidence
- benches
- examples
- src
- tests
- registry-language-server
- src
- tests
- registry-manifest-cli/tests
- registry-manifest-core
- src
- tests
- registry-mint
- demo
- evidence-bundle
- adapters
- codelists
- derivations
- fixtures
- schemas
- support
- src
- tests
- registry-notary-client
- src
- federation
- oid4vci
- tests
- registry-notary-core
- config
- src
- config
- evidence
- tests
- registry-notary-server
- benches
- resources/scalar
- src
- api
- oid4vci
- tests
- bin
- federation
- relay_client
- runtime
- tests
- standalone
- auth
- signing
- tests
- transport
- state_plane
- migration
- tests
- standalone_http
- registry-notary-worker-harness
- src
- bin
- tests
- registry-notary
- src
- boot
- commands
- api_key
- audit
- config_bundle
- healthcheck
- state
- config_loader
- doctor
- env_file
- explain_config
- logging
- tests
- registry-platform-audit
- src
- registry-platform-cache
- src
- registry-platform-config/src
- registry-platform-oid4vci
- src
- registry-platform-oidc
- src
- registry-platform-ops
- src
- tests
- registry-platform-replay
- src
- registry-platform-sdjwt/src
- registry-platform-sts
- src
- bin
- registry-platform-testing
- src
- tests
- registry-relay
- demo/config
- docs
- openapi
- perf/config
- profiles
- dhis2-2.41.9-enrollment-status
- synthetic-snapshot-exact-person-status
- scripts
- src
- api
- config
- metadata
- tests
- registryctl
- agent-skills
- registry-stack-single-node-deploy
- agents
- registryctl-local-project-troubleshoot
- assets/project-starters
- bounded-http
- environments
- integrations/person-record/fixtures
- spreadsheet
- environments
- integrations/project-record-snapshot/fixtures
- docs
- schemas
- project-authoring
- project-documentation
- project-reports
- src
- project_authoring
- compiler
- tests
- approved_set_support
- fixtures
- project-authoring
- custom-system
- environments
- integrations/eligibility/fixtures
- dhis2-script
- environments
- integrations/health-record/fixtures
- dhis2-tracker
- environments
- integrations/health-record/fixtures
- fhir-r4-coverage-active
- environments
- integrations/coverage/fixtures
- opencrvs-country-variant
- environments
- integrations/birth-record/fixtures
- opencrvs-events-api
- environments
- integrations/birth-event-search/fixtures
- opencrvs
- environments
- integrations/birth-record/fixtures
- openspp-exact
- environments
- integrations/individual/fixtures
- snapshot-exact
- environments
- integrations/person-snapshot/fixtures
- snapshot-with-records
- environments
- integrations/person-snapshot/fixtures
- project-reports
- docker
- compose
- docs/site
- docs
- examples/registryctl/jsonplaceholder-todo-live
- environments
- integrations/public-todo/fixtures
- public
- examples
- evidence
- registryctl
- generated
- diagnostics
- images
- scripts
- src
- components
- content/docs
- configure
- decisions
- explanation
- generated-artifacts
- map
- operate
- advanced
- reference
- apis
- diagnostics
- security
- spec
- start
- tutorials
- verify
- data
- generated
- diagnostics
- lib
- plans
- products
- evidence
- contracts
- fixtures
- acceptance
- adult-status
- adapters
- derivations
- fixtures
- schemas
- all-definitions
- adapters
- codelists
- derivations
- fixtures
- schemas
- legal-parent-relationship
- adapters
- derivations
- fixtures
- schemas
- professional-licence
- adapters
- codelists
- derivations
- fixtures
- schemas
- residence-region
- adapters
- codelists
- derivations
- fixtures
- schemas
- conformance
- golden
- selectors
- adapters
- codelists
- derivations
- fixtures
- schemas
- supported-values
- adapters
- codelists
- derivations
- fixtures
- schemas
- source-shapes
- dhis2-tracker-style
- adapters
- responses
- schemas
- flat-rest
- adapters
- responses
- schemas
- opencrvs-record-search-style
- adapters
- responses
- schemas
- generated
- reference/request-adapter
- deployment-projects
- dhis2-tracker-evidence
- bundle
- adapters
- codelists
- derivations
- fixtures
- schemas
- opencrvs-family-evidence
- bundle
- adapters
- derivations
- fixtures
- schemas
- relay-protected-read-evidence
- bundle
- adapters
- codelists
- derivations
- fixtures
- schemas
- dhis2-tracker
- opencrvs-event-search
- scripts
- manifest
- docs
- fuzz
- notary
- .cargo
- .github
- agent-skills
- archive/specs
- bindings
- node
- src
- test
- python
- registry_notary
- tests
- docs
- fuzz
- corpus/core_request_bodies
- fuzz_targets
- openapi
- scripts
- security
- specs
- tests
- fixtures/sd_jwt_vc
- xtask
- src
- platform
- fuzz
- corpus/oid4vci_request_and_proof
- fuzz_targets
- release
- conformance
- adopter-runtime
- package
- generated
- operator/secrets
- integrations
- profiles
- schema
- openid
- relay-oidc
- contracts
- docker
- exercises
- manifests
- notes
- scripts
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
33 | | - | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | 33 | | |
49 | 34 | | |
50 | 35 | | |
| |||
64 | 49 | | |
65 | 50 | | |
66 | 51 | | |
67 | | - | |
68 | 52 | | |
69 | | - | |
70 | 53 | | |
71 | 54 | | |
72 | 55 | | |
| |||
77 | 60 | | |
78 | 61 | | |
79 | 62 | | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | | - | |
84 | | - | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
18 | | - | |
19 | 18 | | |
20 | 19 | | |
21 | 20 | | |
22 | 21 | | |
23 | 22 | | |
24 | | - | |
25 | 23 | | |
26 | 24 | | |
27 | 25 | | |
28 | | - | |
29 | 26 | | |
30 | 27 | | |
31 | 28 | | |
32 | 29 | | |
33 | 30 | | |
34 | 31 | | |
35 | 32 | | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | 33 | | |
| 34 | + | |
| 35 | + | |
45 | 36 | | |
46 | 37 | | |
47 | 38 | | |
48 | 39 | | |
49 | 40 | | |
50 | 41 | | |
51 | 42 | | |
52 | | - | |
| 43 | + | |
53 | 44 | | |
54 | 45 | | |
55 | 46 | | |
56 | 47 | | |
57 | | - | |
| 48 | + | |
58 | 49 | | |
59 | 50 | | |
60 | 51 | | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
61 | 78 | | |
62 | 79 | | |
63 | 80 | | |
| |||
307 | 324 | | |
308 | 325 | | |
309 | 326 | | |
310 | | - | |
311 | | - | |
| 327 | + | |
| 328 | + | |
312 | 329 | | |
313 | 330 | | |
314 | 331 | | |
| |||
387 | 404 | | |
388 | 405 | | |
389 | 406 | | |
390 | | - | |
391 | 407 | | |
392 | 408 | | |
393 | 409 | | |
| |||
396 | 412 | | |
397 | 413 | | |
398 | 414 | | |
399 | | - | |
400 | | - | |
401 | 415 | | |
402 | 416 | | |
403 | 417 | | |
| |||
472 | 486 | | |
473 | 487 | | |
474 | 488 | | |
475 | | - | |
476 | 489 | | |
477 | 490 | | |
478 | | - | |
479 | 491 | | |
480 | 492 | | |
481 | 493 | | |
482 | 494 | | |
483 | 495 | | |
484 | | - | |
485 | | - | |
486 | | - | |
487 | 496 | | |
488 | 497 | | |
489 | 498 | | |
| |||
503 | 512 | | |
504 | 513 | | |
505 | 514 | | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
506 | 521 | | |
507 | 522 | | |
508 | 523 | | |
| |||
521 | 536 | | |
522 | 537 | | |
523 | 538 | | |
524 | | - | |
525 | 539 | | |
| 540 | + | |
526 | 541 | | |
527 | 542 | | |
528 | 543 | | |
529 | 544 | | |
530 | 545 | | |
531 | 546 | | |
532 | 547 | | |
| 548 | + | |
533 | 549 | | |
534 | 550 | | |
535 | 551 | | |
| |||
0 commit comments