Skip to content
This repository was archived by the owner on Aug 12, 2026. It is now read-only.

fix: five audit findings — origin term shape, non-string keys, a quadratic scan, and two unfollowable documents - #22

Merged
sinkog merged 1 commit into
develfrom
fix/audit-batch-2
Aug 9, 2026
Merged

fix: five audit findings — origin term shape, non-string keys, a quadratic scan, and two unfollowable documents#22
sinkog merged 1 commit into
develfrom
fix/audit-batch-2

Conversation

@sinkog

@sinkog sinkog commented Aug 9, 2026

Copy link
Copy Markdown
Member

1. The origin term's shape (adversarial, additional gaps)

INV-013 says the grammar has exactly four productions. The sequence was matched against them; the sealed constructor was not. Both implementations accepted:

origin: [{sealed: {template: $t, path: $.a, extra: junk}}]
origin: [{sealed: {template: [a, b], path: $.a}}]

A term with a third member, or a template that is a sequence, is no production the grammar contains. The same presence-versus-shape mistake the sequence check fixed one level up — one level down. Both now require exactly two members, both scalars.

2. Non-string mapping keys (adversarial, additional gaps)

Go read a key through the YAML node's textual .Value without looking at its tag, so 1: x arrived as the name "1"indistinguishable from '1': x, which is a different key in YAML, in a model whose purpose is unique addressing. Rust refused such documents outright.

The two did not agree on which names a document contains.

Go now rejects the key form; the quoted spelling is still refused for the ordinary reason (nothing declares it).

The Go test asserted the old behaviour — INV-029, "the key is not declared" — a rejection for the wrong reason. One of its cases was explicitly left unpinned, with a comment saying pinning it would pin behaviour nobody designed. It is designed now.

3. A quadratic scan, twice (adversarial F-08)

The duplicate-key pre-scan carried a comment claiming it is linear in the input's own size. It ran Vec::contains before every push — n(n-1)/2 comparisons — and Map::insert searched the whole vector again per key. Two quadratics, one comment.

before   10k 1.0s    20k 2.9s    40k 11.6s   (389 KB)
after    10k 0.20s   20k 0.26s   40k 0.45s   80k 0.75s

A set for the scan, and an append for the parser — safe because the scan has already refused duplicates, so there is nothing to overwrite.

4. The descriptor could not validate against its own schema (claim F-02)

project.yaml declares repo_type: spec; project.schema.yaml permitted schema, workflow, module. Added — and worth saying why it survived: nothing runs that validation.

5. Two documents that could not be followed (claim F-09)

docs/{en,hu}/workflow.md and both cheatsheets instructed make release-dependency and make release-schema. Neither target has ever existed here — both inherited from the base template — so make -n returns "No rule to make target", and anyone following either page could not begin.

Replaced with the real path: subject → verify → external review → pull request into main. Each page says what it used to say and why that was impossible, rather than quietly becoming correct.


make ci passes. Go 90.6%. 15 of 37 audit findings closed.

…ratic scan, and two documents that could not be followed

ORIGIN TERM SHAPE. INV-013 says the grammar has exactly four productions. The
sequence was matched against them, and the sealed CONSTRUCTOR was not: both
implementations accepted `{sealed: {template: $t, path: $.a, extra: junk}}` and
`{sealed: {template: [a, b], path: $.a}}`. A term carrying a third member, or a
template that is a sequence, is no production the grammar contains. The same
presence-versus-shape mistake the sequence check fixed one level up, one level
down. Both now require exactly two members, both scalars.

NON-STRING MAPPING KEYS. Go read a key through the YAML node's textual value
without looking at its tag, so `1: x` arrived as the name "1" —
indistinguishable from `'1': x`, which is a different key in YAML, in a model
whose purpose is unique addressing. Rust refused such documents outright, so the
two did not agree on which names a document contains. Go now rejects the key
FORM, and the quoted spelling is still refused for the ordinary reason: nothing
declares it.

The Go test asserted the old behaviour — INV-029, "the key is not declared" —
which was a rejection for the wrong reason, and one of its cases was explicitly
left unpinned with a comment saying pinning it would pin behaviour nobody
designed. It is designed now.

A QUADRATIC SCAN, TWICE. The duplicate-key pre-scan carried a comment claiming
it is linear in the input's own size. It ran `Vec::contains` before every push —
n(n-1)/2 comparisons — and `Map::insert` searched the whole vector again per
key. Two quadratics, one comment.

  before   10k 1.0s   20k 2.9s   40k 11.6s   (389 KB)
  after    10k 0.20s  20k 0.26s  40k 0.45s   80k 0.75s

A set for the scan, and an append for the parser, which is safe because the scan
has already refused duplicates so there is nothing to overwrite. 40k keys went
from 11.6 seconds to 0.45, and the curve is linear.

THE DESCRIPTOR COULD NOT VALIDATE AGAINST ITS OWN SCHEMA. project.yaml declares
`repo_type: spec`; project.schema.yaml permitted `schema`, `workflow`, `module`.
Added, and worth saying why it survived: nothing runs that validation.

TWO DOCUMENTS THAT COULD NOT BE FOLLOWED. docs/{en,hu}/workflow.md and the
cheatsheets instructed `make release-dependency` and `make release-schema`.
Neither target has EVER existed here — both inherited from the base template —
so `make -n` returns "No rule to make target" and anyone following either page
could not begin. Replaced with the real release path: subject, verify, external
review, then the pull request into main. Each page says what it used to say and
why that was impossible, rather than quietly becoming correct.

make ci passes. Go 90.6%.

---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEUCIQCie0vnRd5jTopKqdpfsxuVzqniT9SdPSlik91jQSPODwIgdDWdw8elW6pjKuJGAFlf06H2ZfV5yExrDF2w7fczq5I=
hash-algorithm = sha256
digest = 7g9KFBiLsyVJqZXEP28xOWsGf9aksb3XqtEl7i3/Gfg=

[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-----
@sinkog
sinkog merged commit cf8e491 into devel Aug 9, 2026
2 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant