This repository was archived by the owner on Aug 12, 2026. It is now read-only.
fix: a sealed_from chain expands to the template it ultimately names (audit semantic F-06/F-07) - #23
Merged
Merged
Conversation
…(audit semantic F-06/F-07)
A template entry may itself be sealed from another template. Go expanded the
chain; Rust resolved exactly ONE level, and because a `sealed_from` node
declares no shape of its own the node then defaulted to object and materialized
as `{}`.
Two different objects from one schema:
go: values: from-inner
origin: [{sealed: {template: $inner, path: $.leaf}}, schema]
rust: values: {}
origin: [{sealed: {template: $outer, path: $.mid}}]
The corpus had no nested template — 003 and 004 cover a single level — so
neither runner could see it, and the divergence sat behind a claim that the two
implementations check each other.
What the expansion also settles, and the specification does not state: the
origin names the INNERMOST template and path, the place the value actually came
from, not the mount point where the chain was entered. Go answered that
question by implementation and nothing wrote it down. The vector pins it now;
SPEC §5 should say it (audit semantic F-06).
Expansion is bounded at 64 levels in both. Go had that bound; Rust had none,
which was harmless only because it did not recurse at all. Recursing without a
bound would have turned a chain of templates referring to each other into an
unbounded loop over input a caller supplies (audit semantic F-07). Measured: a
200-level chain now returns "template expansion exceeded the maximum depth"
rather than running.
Both implementations produce byte-identical output for the new vector. 38 now.
One thing the status-claims gate did while this landed, worth recording because
it is the first time it fired for real: adding the vector made
docs/en/architecture.md's "37 vectors" false, and `make ci` refused before
anything else ran. That is the class of defect it was written for, caught on the
commit that created it rather than by an audit months later.
---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEQCIAk1sTJ3nIGR30UpebXbjIscwc/ReWGCt3rfWBjlGLfvAiBGzDlrMq7ppr62+W+uoIbyUGLLlubZ4168qhmOBIS0aQ==
hash-algorithm = sha256
digest = Gc2FvV2yyH4ThVDStMZTrkjd/V+UeBuPeMTuv5BtdwE=
[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A template entry may itself be sealed from another template. Go expanded the chain; Rust resolved exactly one level — and because a
sealed_fromnode declares no shape of its own, the node then defaulted toobjectand materialized as{}.Two different objects from one schema:
The corpus had no nested template — vectors 003 and 004 cover a single level — so neither runner could see it, and the divergence sat behind a claim that the two implementations check each other.
What the expansion also settles
The origin names the innermost template and path — the place the value actually came from — not the mount point where the chain was entered.
Go answered that question by implementation and nothing wrote it down. The vector pins it now; SPEC §5 should say it (audit semantic F-06).
The bound
64 levels in both. Go had it; Rust had none, which was harmless only because it did not recurse at all. Recursing without a bound would turn a chain of templates referring to each other into an unbounded loop over caller-supplied input (audit semantic F-07).
Measured: a 200-level chain now returns
template expansion exceeded the maximum depthrather than running.Both implementations produce byte-identical output for the new vector. 38 vectors.
A note on the gate from #21
Adding this vector made
docs/en/architecture.md's "37 vectors" false, andmake cirefused before anything else ran.That is exactly the class of defect the status-claims gate was written for — caught on the commit that created it, rather than by an audit months later.
make cipasses. 17 of 37 audit findings closed.