The SIROS wallet engine's test vectors: engine-level HTTP and host transcripts, owned by neither engine, loaded by every runner.
This repository is language-neutral and engine-neutral. It holds the
vector-schema.json contract, the runner rules below, and one JSON file per
scenario. WMP wire vectors stay in the
wmp repository; what lives here is
one level up — the HTTP the engine sends, the world's answers, the sub-flows
it asks the wallet host for, and what must come of it.
Runners live with their engines:
- Go:
test/vectorrunin go-wallet-backend — runs the same vectors against the Go engine during the overlap. - Rust:
engine-conformancein siros-wallet-core — the vector runner of the Rust engine core.
A runner loads a sibling checkout of this repository when it can, a
configured path when the environment says one
(ENGINE_VECTORS_DIR), and a pinned revision in CI otherwise. A runner must
validate every vector against vector-schema.json before running it and
refuse the file on schema violations — an unvalidated vector is a typo away
from testing nothing.
Every vector carries a provenance, and the tag decides how much weight the
vector has:
- spec — required by a published specification clause, cited in
spec_refs. Normative. - oidf — confirmed by an OpenID Foundation conformance-suite run, with
the suite version, plan and test recorded in
spec_refs. Normative. - policy — a SIROS decision recorded in a review or issue, cited in
spec_refs. Normative until the decision is revisited. - go-observed — the Go engine does it, and nothing independent says it is right. A characterization, not a specification.
The go-observed rules that keep a copied bug from becoming a requirement:
- A go-observed vector never overrules a
spec,oidforpolicyvector. A disagreement between them is reviewed; the outcomes are fix the engine, fix Go and regenerate, or record aknown_divergencewith a link to the issue and the intended behaviour. It is never silently resolved by copying Go. - No vector asserts a behaviour that is slated for change. A known
bug in either engine is recorded as the
known_divergenceon the vector that asserts the behaviour we want — the expected behaviour in a vector is always the intended one, never the incumbent's. - Every go-observed vector carries
review_by, at most sixty days after generation. The runner fails once that date passes; extending it requires a writtenreview_reasonin the vector. - Hard sunset: when Phase B's first milestone is reached — the agreed OIDF plans green against the Rust core — no go-observed vector may remain as a gate. Each has been promoted (backed by spec, oidf or policy), replaced or deleted.
- Most of the value is in what the engine must refuse. A refusal vector
cites the clause or policy that demands the refusal; a refusal with no
citation is flagged
go-observedeven when generated from a passing run.
Vectors assert relations, not bytes. A PKCE challenge is asserted to be
S256 of the verifier; a DPoP proof to verify under the presented key with the
right htm, htu, ath and nonce; a JWE to decrypt under the test key.
Values the engine generates are matched by pattern and bound by name for
later steps. Where a vector needs exact bytes — a signature input — the
vector supplies the key and records the to-be-signed input. Time and
randomness come from setup so a run is reproducible.
Phase A vectors are generated by the test-only harness documented in
docs/phase-a-generator-design.md, at a
pinned go-wallet-backend commit recorded in each vector's generator.
Regeneration is a deliberate, reviewed act, never a side effect.
Where a specification allowed the engines a choice, or where the two
engines disagree and the disagreement has been decided rather than
copied, the decision is recorded in
docs/decisions.md and cited by its d.* identifier
in the testing vector's spec_refs. A decision is normative for both
engines; the Go engine's current behaviour where it differs is a
known_divergence on the vector, not a second valid answer.
BSD-2-Clause, like the rest of the SIROS repositories.