Pular para conteúdo

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-wrong module_1_checksum (as opposed to MUT-002's missing checksum), which is deliberately a distinct disposition (go_lock_mismatch, not module-checksum-missing) because the field is present and parseable — only its value is wrong.
  • input_limit_exceeded: now reachable — module_count over 256 (the overlimit fixture) or the lock document over 4096 bytes both short-circuit to this code before any per-module parsing.
  • Symlink vs source_integrity_error: a symlinked lock now reports source_integrity_error, not go_lock_mismatch; the same code now also covers a go.mod/go.sum whose recomputed digest no longer matches the lock's own go_mod_sha256/go_sum_sha256 ("tamper in the source" per the card's Then clause — go.mod/go.sum are 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.