AUR-360 — Fixar Go toolchain e módulos
Documento histórico do board. Pode descrever componentes removidos; para uso atual, consulte o guia do produto.
Purpose
Pins the Go toolchain version and the exact, immutable module set the
repository depends on: go 1.21 (from go.mod), the module path
github.com/Mpaape/AurumCode, a recomputed SHA-256 digest of go.mod and of
go.sum, and, for every module recorded in go.sum, its immutable version
plus its module-content checksum (h1:..., the standard Go module checksum
already present in go.sum). tests/acceptance/AUR-360.sh verifies the
sealed lock is present, well-formed, free of mutable references, and
cross-checked field-by-field against the real go.mod/go.sum it claims to
pin — it never downloads or resolves a module (see Non-goals below and in
the card).
Artifacts and schema
.board/bootstrap/locks/go.yml
Flat key: value document, LC_ALL=C, one pair per line, no trailing
whitespace. Fields:
| Key | Value | Source |
|---|---|---|
schema |
bootstrap-lock-v1 |
fixed |
card |
AUR-360 |
fixed |
go_version |
1.21 |
go.mod:3 (go 1.21) |
module |
github.com/Mpaape/AurumCode |
go.mod:1 (module github.com/Mpaape/AurumCode) |
go_mod_sha256 |
sha256:2e5f37fb9db0206e74c34a1500f9c53e11c33c9d1d0ee39d6377a553aabeafb6 |
recomputed sha256sum go.mod |
go_sum_sha256 |
sha256:b9142883d8f8e46998f705fbcd9964d6f386e17381ddf95a0c3173c832ce25e8 |
recomputed sha256sum go.sum |
module_count |
3 |
count of distinct modules in go.sum |
module_<n>_path |
e.g. github.com/gorilla/mux |
go.sum column 1 |
module_<n>_version |
e.g. v1.8.1 |
go.sum column 2 |
module_<n>_checksum |
e.g. h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= |
go.sum column 3 (module content hash, the non-/go.mod row) |
The three modules pinned, all taken verbatim from go.sum in this
repository:
| Module | Version | Checksum |
|---|---|---|
github.com/gorilla/mux |
v1.8.1 |
h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= |
gopkg.in/check.v1 |
v0.0.0-20161208181325-20d25e280405 |
h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= |
gopkg.in/yaml.v3 |
v3.0.1 |
h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= |
gopkg.in/check.v1 is an indirect (test-only) dependency of gopkg.in/yaml.v3
recorded in go.sum but not directly required by go.mod; it is pinned
here because the card's Outcome requires "cada módulo" (every module) that
go.sum records, not only the direct requirements.
No network call, go mod download, go mod tidy, or module resolution was
performed to produce this file — every value above is read directly from the
committed go.mod / go.sum already in the repository (the card's
read_paths).
Bounds
| Bound | Value | Source |
|---|---|---|
tests/bootstrap/locks/AUR-360/cases.tsv size |
4 MiB |
card Precondition |
cases.tsv rows |
256 |
card Precondition |
| Acceptance wall-clock (informational) | 15 s |
card Precondition |
.board/bootstrap/locks/go.yml size |
4096 bytes |
builder judgment call: the card names no separate numeric ceiling for the lock document itself; this reuses the "small flat manifest" reasoning tests/acceptance/AUR-359.sh already applies to its own sibling lock, .board/bootstrap/locks/trust-root.yml |
module_count |
256 |
builder judgment call: the card names no separate numeric ceiling for the module count; this reuses the same 256 the card already fixes for cases.tsv rows rather than inventing an unrelated second number |
Codes
Typed dispositions tests/acceptance/AUR-360.sh::AC-001 actually emits on
stderr as AUR-360/AC-001/<code> (exit 1), each now produced by a
go.mod/go.sum cross-check, not a structural check alone:
| Code | Trigger (as implemented) |
|---|---|
go_lock_mismatch |
.board/bootstrap/locks/go.yml is absent or not a regular file; go_version differs from go.mod's go directive; a module go.sum records is unpinned, version-drifted, or pinned with the wrong checksum; or the lock pins a module go.sum does not record. |
source_integrity_error |
.board/bootstrap/locks/go.yml is a symlink; or the recomputed SHA-256 of go.mod or of go.sum no longer matches the lock's own go_mod_sha256/go_sum_sha256 field (the lock's declared "source hash lock" no longer holds). |
invalid_lock_or_manifest |
Missing the exact line schema: bootstrap-lock-v1 or card: AUR-360; no sha256:[0-9a-f]{64} pattern anywhere; a required field (go_version, module, go_mod_sha256, go_sum_sha256, module_count) absent or empty; module_count non-numeric, zero, or not equal to the number of module_<n>_path: lines actually present; or a module_<n>_path/module_<n>_version pair missing or duplicated. |
mutable_reference |
The file contains a bare latest token or an @main/@master/@HEAD-style reference. |
input_limit_exceeded |
.board/bootstrap/locks/go.yml exceeds 4096 bytes, or module_count exceeds 256 — checked before any per-module parsing, so an over-limit module_count never requires fabricating that many module lines to observe. |
module-path-mismatch |
The lock's module: field differs from go.mod's module directive (MUT-001's exact scenario: the module path changed in the snapshot after the source hash was locked, while go_mod_sha256 still matches the untouched go.mod). |
module-checksum-missing |
A module go.sum records is pinned in the lock with the correct path and version but an empty/absent module_<n>_checksum (MUT-002's exact scenario: the checksum removed, the version kept). |
unknown-selector (exit 64) is emitted for any first argument outside
AC-001, ContractAUR360, IntegrationAUR360, E2EAUR360; all four
accepted selectors currently run the identical body above.
Known gap — round 2 closure
Round 1 sealed a structural-only oracle (three checks: schema line present,
some sha256: pattern present, no mutable token) that never read go.mod
or go.sum and could not observe MUT-001 or MUT-002 at all — both mutations
left the script's exit at 0. Round 2 replaces the oracle body with
verify_go_lock(), which parses .board/bootstrap/locks/go.yml field by
field and cross-checks go_version, module, go_mod_sha256,
go_sum_sha256, and every module_<n>_path/version/checksum triple
against the real, materialized go.mod/go.sum (a bijection both ways: no
go.sum module unpinned, no lock entry phantom), before any other consumer
of the domain runs. This closes every gap round 1 recorded:
- Module path / go_version drift, per-module version/checksum drift:
now detected —
module-path-mismatch,go_lock_mismatch(go_version),go_lock_mismatch(per-module version/checksum drift or an unpinned real module),module-checksum-missing(checksum removed but version kept). Reproduced live against the real lock for MUT-001 and MUT-002 (see the acceptance evidence for this round), plus one extra mutation of the same supply-chain class this round adds: a present-but-wrongmodule_1_checksum(as opposed to MUT-002's missing checksum), which is deliberately a distinct disposition (go_lock_mismatch, notmodule-checksum-missing) because the field is present and parseable — only its value is wrong. input_limit_exceeded: now reachable —module_countover256(theoverlimitfixture) or the lock document over4096bytes both short-circuit to this code before any per-module parsing.- Symlink vs
source_integrity_error: a symlinked lock now reportssource_integrity_error, notgo_lock_mismatch; the same code now also covers ago.mod/go.sumwhose recomputed digest no longer matches the lock's owngo_mod_sha256/go_sum_sha256("tamper in the source" per the card'sThenclause —go.mod/go.sumare the "source" MUT-001's own phrasing names,"...depois do source hash lock").
Residual, documented tension (not closed, by design): the card's
Public contract line enumerates exactly four codes
(go_lock_mismatch|source_integrity_error|invalid_lock_or_manifest|
input_limit_exceeded), while Skeptical mutations MUT-001/MUT-002 name two
further, more specific literal codes (module-path-mismatch,
module-checksum-missing) for what is, read one way, the same underlying
"module field drifted from go.mod/go.sum" condition the Public
contract's go_lock_mismatch already covers. .board/cards is this card's
own forbidden_paths entry, so round 2 cannot edit the card text to
reconcile the two lists; instead it honors the more specific, literally
quoted MUT-001/MUT-002 strings — the two mutations the skeptical approver
actually replays and checks byte-for-byte — as the authoritative
requirement for those two exact scenarios, and keeps go_lock_mismatch for
every other drift the AC-001 Then clause groups under that name (whole
go_version drift, per-module version/checksum drift not matching either
MUT's exact shape, and phantom pins). A future card correcting the card
text itself (not this one, and not this file) would need to either fold
module-path-mismatch/module-checksum-missing into the four-code
contract list explicitly, or drop the two literal strings from the
Skeptical mutations prose.
Diagnostic example (synthetic)
$ ./.board/bin/oci-run --profile bootstrap-readonly-v1 --card AUR-360
{"card":"AUR-360","scenario":"AC-001","selector":"AC-001","fixture_cases":11,"result":"pass"}
An absent lock instead produces, on stderr, exit 1:
AUR-360/AC-001/go_lock_mismatch
AUR-360/AC-001/detail source=.board/bootstrap/locks/go.yml
A lock whose module: field no longer matches go.mod's module line
(MUT-001's exact scenario) produces, on stderr, exit 1:
AUR-360/AC-001/module-path-mismatch
AUR-360/AC-001/detail source=.board/bootstrap/locks/go.yml
Offline OCI command
This is the card's accept: line, run through the frozen bootstrap profile
(bootstrap-readonly-v1, pinned to
bash@sha256:ae4668c2560999e65e89532cd2ad1b6688bb23298189f0bd229ef80fa4bd0831,
"pull": "never"), reproducible offline once that image is present in the
local cache:
./.board/bin/oci-run --profile bootstrap-readonly-v1 --card AUR-360
oci-run materializes only this card's paths: (git-tracked) into the
read-only, network-none, non-root worker before running
tests/acceptance/AUR-360.sh inside it.
Fixtures
tests/bootstrap/locks/AUR-360/cases.tsv seals eleven fixture cases under
tests/bootstrap/locks/AUR-360/fixtures/, each reproducing one of the codes
above against the exact verify_go_lock() check logic
tests/acceptance/AUR-360.sh runs, cross-checked against the same real
go.mod/go.sum Phase 1 already trusted (see tests/acceptance/AUR-360.sh
Phase 2 for the loop; the acceptance program now self-tests against
cases.tsv, mirroring its sibling tests/acceptance/AUR-359.sh):
| Case | Fixture change from nominal |
Expected |
|---|---|---|
nominal |
none | pass |
absence |
no go.yml present |
go_lock_mismatch |
symlink |
go.yml is a symlink to nominal's |
source_integrity_error |
tamper |
schema: line removed |
invalid_lock_or_manifest |
invalid |
go_mod_sha256/go_sum_sha256 (all sha256: patterns) removed |
invalid_lock_or_manifest |
mutable |
module_1_version rewritten to latest |
mutable_reference |
overlimit |
module_count: 257 (over the 256 bound) |
input_limit_exceeded |
module_path_mismatch |
module: rewritten to a value go.mod does not have (MUT-001's exact change) |
module-path-mismatch |
module_checksum_missing |
module_1_checksum line removed, module_1_version kept (MUT-002's exact change) |
module-checksum-missing |
checksum_mismatch |
module_1_checksum present but rewritten to a wrong (not empty) value — this round's own extra mutation, same supply-chain class as MUT-002 but a different disposition |
go_lock_mismatch |
go_version_mismatch |
go_version: 1.20 while go.mod still declares go 1.21 |
go_lock_mismatch |
No entry contains a real credential. Every non-sha256: digest in
cases.tsv was recomputed with sha256sum against the fixture file as
committed in this patch, never invented.
Non-goals (restated from the card)
This card never runs go mod tidy, go mod download, go get, or any
other command that resolves, updates, or promotes a Go module version. Every
value in .board/bootstrap/locks/go.yml is read from the go.mod/go.sum
already committed in this repository.