docs: publish State multiselect verification and native evidence
This commit is contained in:
@@ -0,0 +1 @@
|
||||
* -text
|
||||
@@ -0,0 +1,58 @@
|
||||
# State multiselect source identity evidence
|
||||
|
||||
The source receipts bind two historical captured input maps to exact Git trees:
|
||||
|
||||
| Gate | Commit | Inputs | Input-map SHA-256 |
|
||||
| --- | --- | ---: | --- |
|
||||
| desktop-2 | 2a3b9ba822a49ead233c4b5f98412a07c1c1da12 | 733 | 9cf85879dfb0bb5ec3b15c66b23df316e6bfe8451b6cf0c895bf7b9b5fbdde4a |
|
||||
| lint-2 | 3480b54201a5f361cca0bcd0d45dd6546a7a7bc9 | 735 | 4215d0ca0319282768f1acdf05c2c094ea7432e17ed3a715df73aa05cef851bf |
|
||||
|
||||
The original receipts are preserved without rewriting. The verifier fixes their
|
||||
exact byte pins, commit IDs, map pins/counts and explicitCompileTimeFixtures.
|
||||
The historical 733-input scope excludes two compile-time fixtures; the final
|
||||
735-input scope explicitly includes both:
|
||||
|
||||
- harness/experiments/edge-attachments-20260922/native-fixture.arcadia
|
||||
- harness/experiments/textual-authoring-20260911/alarm-response.arcadia
|
||||
|
||||
Matching an old Git tree does not correct those historical scope omissions or
|
||||
establish the final source's behavior. A gate applies to its captured input map.
|
||||
Later native build maps must independently match the final 735-input map before
|
||||
using this source identity evidence for those builds.
|
||||
|
||||
From this tool directory, prepare against completed raw captures without writing:
|
||||
|
||||
```
|
||||
python -B prepare.py --raw-gates CHECKOUT/.local/state-group-gates --repo CHECKOUT --check-only
|
||||
```
|
||||
|
||||
After the strict sibling checks package is complete, add --checks CHECKS_PACKAGE,
|
||||
omit --check-only, and provide --output NEW_SOURCE_PACKAGE. Existing output is
|
||||
refused. Preparation preserves the source receipts, tools and README, writes
|
||||
files.json pins, and performs readback. No ZIP is created by the source preparer.
|
||||
|
||||
A completed portable package can be verified without the original checkout:
|
||||
|
||||
```
|
||||
python -B SOURCE_PACKAGE/verify.py
|
||||
```
|
||||
|
||||
By default it reads the sibling ../checks package; override with --checks PATH.
|
||||
It verifies checks outer/member pins, capsule relationships and both selected
|
||||
nested source ZIPs against their exact maps. It checks source receipt identity,
|
||||
accepted unchanged gate flags, scope/counts and all source package pins. Run the
|
||||
sibling checks verifier separately for full process/helper/stream relationships.
|
||||
|
||||
Add --repo CHECKOUT to independently repeat the complete filtered Git inventory
|
||||
and exact blob-byte comparison against both pinned commits already present there.
|
||||
Without --repo, verification checks historical receipt/capsule consistency and
|
||||
explicitly reports that Git comparison was not rerun. No archived helpers or
|
||||
source executables are run; no build, checkout, extraction or network is needed.
|
||||
|
||||
verify-committed-inputs.py remains the generic comparator used to create source
|
||||
receipts. Its --include-fixtures option includes both explicit fixtures; omission
|
||||
keeps the historical scope. It accepts explicit gate/full commit IDs, defaults to
|
||||
read-only comparison, and writes only an optional new --output receipt.
|
||||
|
||||
Receipts and pins establish internal byte consistency, not external authentication,
|
||||
hermetic toolchains, test execution, native usability or complete issue acceptance.
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
".gitattributes": {
|
||||
"bytes": 9,
|
||||
"sha256": "8b9c3028d6467ff3be7c793141927841d70f47f52d0590677438f488ca154992"
|
||||
},
|
||||
"README.md": {
|
||||
"bytes": 3092,
|
||||
"sha256": "b122e41bb9c52b4384e09cd62ee4115a68ff16d5aefee2f92fe632b07276d017"
|
||||
},
|
||||
"prepare.py": {
|
||||
"bytes": 2100,
|
||||
"sha256": "1be2f2a402b493a1c9700044f1119ed8ccddaa02baec2ecd25a185aba6253112"
|
||||
},
|
||||
"source-desktop-2.json": {
|
||||
"bytes": 428,
|
||||
"sha256": "6012bdc52a3843c9cfd5f3c80ec4270a7c0f1e13ef4738b0e3f4ed048ff8d885"
|
||||
},
|
||||
"source-lint-2.json": {
|
||||
"bytes": 583,
|
||||
"sha256": "e0a6deab68683278965643f6f34a1038fcea25c1f242b6f75f5559b7697ec7d6"
|
||||
},
|
||||
"verify-committed-inputs.py": {
|
||||
"bytes": 5712,
|
||||
"sha256": "3cd4f0155cd29c6786f467562d458a380084b2a510eac6454a29388f8f048772"
|
||||
},
|
||||
"verify.py": {
|
||||
"bytes": 10126,
|
||||
"sha256": "e670dc47e89a6ad5cdf7f9adfb6a50797270e475d6b312f159f7aef941ae723b"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
"""Prepare pinned source receipts after raw/sibling capture validation; never build."""
|
||||
from pathlib import Path
|
||||
import argparse, json
|
||||
from verify import HERE, SPECS, TOOLS, FILES, need, pin, verify_data, raw_captures, packaged, verify_package
|
||||
|
||||
def main():
|
||||
parser=argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--raw-gates',type=Path,required=True,help='original raw gates and source-RUN.json receipts')
|
||||
parser.add_argument('--checks',type=Path,help='completed sibling checks package; required when writing')
|
||||
parser.add_argument('--repo',type=Path,help='optionally rerun exact committed Git-blob comparison')
|
||||
parser.add_argument('--output',type=Path,help='new source package directory')
|
||||
parser.add_argument('--check-only',action='store_true')
|
||||
args=parser.parse_args()
|
||||
receipts={run:(args.raw_gates/('source-'+run+'.json')).read_bytes() for run in SPECS}
|
||||
captured=packaged(args.checks) if args.checks else raw_captures(args.raw_gates)
|
||||
summary=verify_data(receipts,captured,args.repo)
|
||||
if args.check_only:
|
||||
print('PASS source check-only; no package written:',summary); return
|
||||
need(args.checks is not None,'written portable source package requires completed --checks package')
|
||||
need(args.output is not None,'explicit new --output required')
|
||||
out=args.output.resolve(); need(not out.exists(),'existing package refused')
|
||||
payload={name:(HERE/name).read_bytes() for name in TOOLS}
|
||||
payload.update({'source-'+run+'.json':data for run,data in receipts.items()})
|
||||
need(set(payload)==FILES,'exact source files')
|
||||
out.mkdir(parents=True)
|
||||
for name,data in payload.items():
|
||||
with (out/name).open('xb') as stream: stream.write(data)
|
||||
with (out/'files.json').open('x',encoding='utf-8') as stream:
|
||||
json.dump({name:pin(data) for name,data in sorted(payload.items())},stream,indent=2)
|
||||
# Git comparison was already performed above when requested; readback is byte-only.
|
||||
verify_package(out,args.checks)
|
||||
print('PASS written source package readback:',out,summary)
|
||||
if __name__=='__main__': main()
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"checked": "2026-09-23T10:37:38.419535+00:00",
|
||||
"commit": "2a3b9ba822a49ead233c4b5f98412a07c1c1da12",
|
||||
"gate": "desktop-2",
|
||||
"inputCount": 733,
|
||||
"inputMap": {
|
||||
"bytes": 122682,
|
||||
"sha256": "9cf85879dfb0bb5ec3b15c66b23df316e6bfe8451b6cf0c895bf7b9b5fbdde4a"
|
||||
},
|
||||
"comparison": "Exact committed Git blobs equal every captured input; same complete filtered inventory",
|
||||
"explicitCompileTimeFixtures": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"checked": "2026-09-23T10:37:40.478617+00:00",
|
||||
"commit": "3480b54201a5f361cca0bcd0d45dd6546a7a7bc9",
|
||||
"gate": "lint-2",
|
||||
"inputCount": 735,
|
||||
"inputMap": {
|
||||
"bytes": 123053,
|
||||
"sha256": "4215d0ca0319282768f1acdf05c2c094ea7432e17ed3a715df73aa05cef851bf"
|
||||
},
|
||||
"comparison": "Exact committed Git blobs equal every captured input; same complete filtered inventory",
|
||||
"explicitCompileTimeFixtures": [
|
||||
"harness/experiments/edge-attachments-20260922/native-fixture.arcadia",
|
||||
"harness/experiments/textual-authoring-20260911/alarm-response.arcadia"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
"""Compare captured input maps to exact named Git trees; no builds or checkouts."""
|
||||
from pathlib import Path, PurePosixPath
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import zipfile
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
COMPARISON = "Exact committed Git blobs equal every captured input; same complete filtered inventory"
|
||||
EXPLICIT_FIXTURES = {
|
||||
"harness/experiments/edge-attachments-20260922/native-fixture.arcadia",
|
||||
"harness/experiments/textual-authoring-20260911/alarm-response.arcadia",
|
||||
}
|
||||
INCLUDE_FIXTURES = False
|
||||
|
||||
|
||||
def need(ok, message):
|
||||
if not ok:
|
||||
raise ValueError(message)
|
||||
|
||||
|
||||
def pin(data):
|
||||
return {"bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()}
|
||||
|
||||
|
||||
def parsed(data):
|
||||
def unique(items):
|
||||
result = {}
|
||||
for key, value in items:
|
||||
need(key not in result, "duplicate JSON key: " + key)
|
||||
result[key] = value
|
||||
return result
|
||||
return json.loads(data, object_pairs_hook=unique)
|
||||
|
||||
|
||||
def safe(name):
|
||||
return (isinstance(name, str) and bool(name) and "\\" not in name and ":" not in name
|
||||
and not PurePosixPath(name).is_absolute()
|
||||
and all(part not in ("", ".", "..") for part in name.split("/")))
|
||||
|
||||
|
||||
def relevant(path):
|
||||
return (INCLUDE_FIXTURES and path in EXPLICIT_FIXTURES) or path in ("Cargo.toml", "Cargo.lock", "rust-toolchain.toml") or path.startswith(
|
||||
("crates/", "build/", ".cargo/", "scripts/", "docs/", "examples/", "harness/fixtures/", "harness/prototypes/"))
|
||||
|
||||
|
||||
def git(repo, *arguments, data=None):
|
||||
environment = dict(os.environ, GIT_NO_LAZY_FETCH="1")
|
||||
return subprocess.run(["git", *arguments], cwd=repo, input=data, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, check=True, env=environment).stdout
|
||||
|
||||
|
||||
def compare_commit(repo, commit, inputs):
|
||||
need(git(repo, "rev-parse", "--verify", commit + "^{commit}").decode().strip() == commit, "named commit unavailable")
|
||||
entries = git(repo, "ls-tree", "-r", "--full-tree", "-z", commit).split(b"\0")
|
||||
blobs = {}
|
||||
for entry in filter(None, entries):
|
||||
header, path_bytes = entry.split(b"\t", 1)
|
||||
path = path_bytes.decode("utf-8")
|
||||
if relevant(path):
|
||||
_mode, kind, oid = header.split()
|
||||
need(kind == b"blob", "relevant non-blob tree entry: " + path)
|
||||
need(path not in blobs, "duplicate tree path")
|
||||
blobs[path] = oid
|
||||
need(set(blobs) == set(inputs), "complete filtered Git inventory differs; missing="
|
||||
+ repr(sorted(set(inputs) - set(blobs))) + "; additional=" + repr(sorted(set(blobs) - set(inputs))))
|
||||
# Object IDs avoid path quoting and commit:path interpretation in batch input.
|
||||
paths = sorted(blobs)
|
||||
data = git(repo, "cat-file", "--batch", data=b"".join(blobs[path] + b"\n" for path in paths))
|
||||
offset, actual = 0, {}
|
||||
for path in paths:
|
||||
end = data.index(b"\n", offset)
|
||||
oid, kind, size_bytes = data[offset:end].split()
|
||||
size = int(size_bytes)
|
||||
need(oid == blobs[path] and kind == b"blob" and size >= 0, "Git batch object relationship")
|
||||
content = data[end + 1:end + 1 + size]
|
||||
need(len(content) == size and data[end + 1 + size:end + 2 + size] == b"\n", "Git batch framing")
|
||||
actual[path] = pin(content)
|
||||
offset = end + 2 + size
|
||||
need(offset == len(data), "trailing Git batch bytes")
|
||||
different = [path for path in paths if actual[path] != inputs[path]]
|
||||
need(not different, "captured bytes differ from named commit: " + repr(different))
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
import datetime
|
||||
global INCLUDE_FIXTURES
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--repo", type=Path, required=True)
|
||||
parser.add_argument("--raw-gates", type=Path, required=True)
|
||||
parser.add_argument("--gate", required=True)
|
||||
parser.add_argument("--commit", required=True, help="exact full commit object ID, not a branch")
|
||||
parser.add_argument("--include-fixtures", action="store_true", help="include both compile-time fixtures for the revised 735-input scope; default preserves historical 733-input scope")
|
||||
parser.add_argument("--output", type=Path, help="optional new receipt file; otherwise read-only check")
|
||||
args = parser.parse_args()
|
||||
INCLUDE_FIXTURES = args.include_fixtures
|
||||
need(safe(args.gate) and "/" not in args.gate, "safe gate name")
|
||||
folder = args.raw_gates / args.gate
|
||||
map_bytes = (folder / "inputs.json").read_bytes()
|
||||
result = parsed((folder / "result.json").read_bytes())
|
||||
inputs = parsed(map_bytes)
|
||||
need(result["exitCode"] == 0 and result["inputsUnchanged"] is True, "accepted unchanged gate required")
|
||||
need(result["inputs"] == pin(map_bytes) and result["inputCount"] == len(inputs), "map relationship")
|
||||
need(all(safe(path) and relevant(path) for path in inputs), "input scope")
|
||||
need(sum(path.startswith("crates/vendor/iced_widget/") for path in inputs) == 71, "vendor inventory")
|
||||
compare_commit(args.repo, args.commit, inputs)
|
||||
report = {"checked": datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
||||
"commit": args.commit, "gate": args.gate, "inputCount": len(inputs),
|
||||
"inputMap": pin(map_bytes), "comparison": COMPARISON,
|
||||
"explicitCompileTimeFixtures": sorted(EXPLICIT_FIXTURES) if INCLUDE_FIXTURES else []}
|
||||
if args.output:
|
||||
with args.output.open("x", encoding="utf-8") as stream:
|
||||
json.dump(report, stream, indent=2)
|
||||
print("PASS exact Git tree/blobs:", json.dumps(report))
|
||||
print("Source identity only; separately verify capture/archive consistency. No build, checkout or native acceptance claim.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,173 @@
|
||||
"""Verify pinned State source receipts against sibling capture capsules; optionally compare Git blobs."""
|
||||
from pathlib import Path, PurePosixPath
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import zipfile
|
||||
import io
|
||||
import stat
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
COMPARISON = "Exact committed Git blobs equal every captured input; same complete filtered inventory"
|
||||
EXPLICIT_FIXTURES = {
|
||||
"harness/experiments/edge-attachments-20260922/native-fixture.arcadia",
|
||||
"harness/experiments/textual-authoring-20260911/alarm-response.arcadia",
|
||||
}
|
||||
INCLUDE_FIXTURES = False
|
||||
|
||||
|
||||
def need(ok, message):
|
||||
if not ok:
|
||||
raise ValueError(message)
|
||||
|
||||
|
||||
def pin(data):
|
||||
return {"bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()}
|
||||
|
||||
|
||||
def parsed(data):
|
||||
def unique(items):
|
||||
result = {}
|
||||
for key, value in items:
|
||||
need(key not in result, "duplicate JSON key: " + key)
|
||||
result[key] = value
|
||||
return result
|
||||
return json.loads(data, object_pairs_hook=unique)
|
||||
|
||||
|
||||
def safe(name):
|
||||
return (isinstance(name, str) and bool(name) and "\\" not in name and ":" not in name
|
||||
and not PurePosixPath(name).is_absolute()
|
||||
and all(part not in ("", ".", "..") for part in name.split("/")))
|
||||
|
||||
|
||||
def relevant(path):
|
||||
return (INCLUDE_FIXTURES and path in EXPLICIT_FIXTURES) or path in ("Cargo.toml", "Cargo.lock", "rust-toolchain.toml") or path.startswith(
|
||||
("crates/", "build/", ".cargo/", "scripts/", "docs/", "examples/", "harness/fixtures/", "harness/prototypes/"))
|
||||
|
||||
|
||||
def git(repo, *arguments, data=None):
|
||||
environment = dict(os.environ, GIT_NO_LAZY_FETCH="1")
|
||||
return subprocess.run(["git", *arguments], cwd=repo, input=data, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, check=True, env=environment).stdout
|
||||
|
||||
|
||||
def compare_commit(repo, commit, inputs):
|
||||
need(git(repo, "rev-parse", "--verify", commit + "^{commit}").decode().strip() == commit, "named commit unavailable")
|
||||
entries = git(repo, "ls-tree", "-r", "--full-tree", "-z", commit).split(b"\0")
|
||||
blobs = {}
|
||||
for entry in filter(None, entries):
|
||||
header, path_bytes = entry.split(b"\t", 1)
|
||||
path = path_bytes.decode("utf-8")
|
||||
if relevant(path):
|
||||
_mode, kind, oid = header.split()
|
||||
need(kind == b"blob", "relevant non-blob tree entry: " + path)
|
||||
need(path not in blobs, "duplicate tree path")
|
||||
blobs[path] = oid
|
||||
need(set(blobs) == set(inputs), "complete filtered Git inventory differs; missing="
|
||||
+ repr(sorted(set(inputs) - set(blobs))) + "; additional=" + repr(sorted(set(blobs) - set(inputs))))
|
||||
# Object IDs avoid path quoting and commit:path interpretation in batch input.
|
||||
paths = sorted(blobs)
|
||||
data = git(repo, "cat-file", "--batch", data=b"".join(blobs[path] + b"\n" for path in paths))
|
||||
offset, actual = 0, {}
|
||||
for path in paths:
|
||||
end = data.index(b"\n", offset)
|
||||
oid, kind, size_bytes = data[offset:end].split()
|
||||
size = int(size_bytes)
|
||||
need(oid == blobs[path] and kind == b"blob" and size >= 0, "Git batch object relationship")
|
||||
content = data[end + 1:end + 1 + size]
|
||||
need(len(content) == size and data[end + 1 + size:end + 2 + size] == b"\n", "Git batch framing")
|
||||
actual[path] = pin(content)
|
||||
offset = end + 2 + size
|
||||
need(offset == len(data), "trailing Git batch bytes")
|
||||
different = [path for path in paths if actual[path] != inputs[path]]
|
||||
need(not different, "captured bytes differ from named commit: " + repr(different))
|
||||
|
||||
|
||||
|
||||
SPECS = {'desktop-2': {'commit': '2a3b9ba822a49ead233c4b5f98412a07c1c1da12', 'inputCount': 733, 'inputMap': {'bytes': 122682, 'sha256': '9cf85879dfb0bb5ec3b15c66b23df316e6bfe8451b6cf0c895bf7b9b5fbdde4a'}, 'explicitCompileTimeFixtures': [], 'receiptPin': {'bytes': 428, 'sha256': '6012bdc52a3843c9cfd5f3c80ec4270a7c0f1e13ef4738b0e3f4ed048ff8d885'}}, 'lint-2': {'commit': '3480b54201a5f361cca0bcd0d45dd6546a7a7bc9', 'inputCount': 735, 'inputMap': {'bytes': 123053, 'sha256': '4215d0ca0319282768f1acdf05c2c094ea7432e17ed3a715df73aa05cef851bf'}, 'explicitCompileTimeFixtures': ['harness/experiments/edge-attachments-20260922/native-fixture.arcadia', 'harness/experiments/textual-authoring-20260911/alarm-response.arcadia'], 'receiptPin': {'bytes': 583, 'sha256': 'e0a6deab68683278965643f6f34a1038fcea25c1f242b6f75f5559b7697ec7d6'}}}
|
||||
TOOLS = {".gitattributes", "prepare.py", "verify.py", "verify-committed-inputs.py", "README.md"}
|
||||
FILES = TOOLS | {"source-" + run + ".json" for run in SPECS}
|
||||
|
||||
def inventory(archive, expected):
|
||||
names = archive.namelist()
|
||||
need(len(names) == len(set(names)) and set(names) == set(expected), "exact ZIP inventory")
|
||||
for item in archive.infolist():
|
||||
need(safe(item.filename) and not item.is_dir() and not stat.S_ISLNK(item.external_attr >> 16), "safe ZIP member")
|
||||
need(pin(archive.read(item.filename)) == expected[item.filename], "ZIP member pin: " + item.filename)
|
||||
|
||||
def verify_data(receipts, captured, repo=None):
|
||||
global INCLUDE_FIXTURES
|
||||
need(set(receipts) == set(captured) == set(SPECS), "exact source run inventory")
|
||||
for run, spec in SPECS.items():
|
||||
receipt_bytes = receipts[run]
|
||||
need(pin(receipt_bytes) == spec["receiptPin"], run + ": exact historical receipt bytes")
|
||||
receipt = parsed(receipt_bytes)
|
||||
need(receipt["gate"] == run and receipt["comparison"] == COMPARISON, run + ": receipt identity")
|
||||
need(all(receipt[key] == spec[key] for key in ("commit", "inputCount", "inputMap", "explicitCompileTimeFixtures")), run + ": pinned receipt relationships")
|
||||
map_bytes, result, archive_bytes = captured[run]
|
||||
need(pin(map_bytes) == spec["inputMap"] == result["inputs"], run + ": exact captured input map")
|
||||
need(result["exitCode"] == 0 and result["inputsUnchanged"] is True, run + ": accepted unchanged gate")
|
||||
inputs = parsed(map_bytes)
|
||||
need(len(inputs) == spec["inputCount"] == result["inputCount"], run + ": input counts")
|
||||
INCLUDE_FIXTURES = bool(spec["explicitCompileTimeFixtures"])
|
||||
need(spec["explicitCompileTimeFixtures"] == (sorted(EXPLICIT_FIXTURES) if INCLUDE_FIXTURES else []), run + ": exact fixture scope")
|
||||
need(all(safe(name) and relevant(name) for name in inputs), run + ": input scope")
|
||||
need((EXPLICIT_FIXTURES & set(inputs)) == (EXPLICIT_FIXTURES if INCLUDE_FIXTURES else set()), run + ": explicit fixture membership")
|
||||
need(sum(name.startswith("crates/vendor/iced_widget/") for name in inputs) == 71, run + ": vendor count")
|
||||
need(pin(archive_bytes) == result["archive"], run + ": source capsule pin")
|
||||
with zipfile.ZipFile(io.BytesIO(archive_bytes)) as archive:
|
||||
inventory(archive, inputs)
|
||||
if repo is not None:
|
||||
compare_commit(repo, spec["commit"], inputs)
|
||||
print("PASS", run, spec["commit"], len(inputs), "source pins" + (" and exact Git blobs" if repo is not None else " (Git comparison not rerun)"))
|
||||
return {"runs": len(SPECS), "gitCompared": repo is not None}
|
||||
|
||||
def raw_captures(gates):
|
||||
return {run: ((gates/run/"inputs.json").read_bytes(), parsed((gates/run/"result.json").read_bytes()),
|
||||
(gates/run/"inputs.zip").read_bytes()) for run in SPECS}
|
||||
|
||||
def packaged(checks):
|
||||
files = parsed((checks/"files.json").read_bytes())
|
||||
need(set(files) == {"prepare.py", "verify.py", "README.md", "manifest.json", "evidence.zip"}, "checks outer inventory")
|
||||
for name, expected in files.items():
|
||||
need(pin((checks/name).read_bytes()) == expected, "checks outer pin: " + name)
|
||||
manifest = parsed((checks/"manifest.json").read_bytes())
|
||||
need(manifest["schema"] == 1 and manifest["kind"] == "multiselect-cargo-gates", "checks kind")
|
||||
logical, members = manifest["logicalFiles"], manifest["members"]
|
||||
need(all(safe(name) and safe(target) for name,target in logical.items()) and set(logical.values()) == set(members), "checks logical inventory")
|
||||
captured = {}
|
||||
with zipfile.ZipFile(checks/"evidence.zip") as archive:
|
||||
inventory(archive, members)
|
||||
for run in SPECS:
|
||||
prefix = "cargo/" + run + "/"
|
||||
result = parsed(archive.read(logical[prefix + "result.json"]))
|
||||
spec = manifest["runs"][run]
|
||||
need(all(result[key] == spec[key] for key in ("command", "head", "exitCode", "inputCount")), run + ": checks relationships")
|
||||
for name in ("inputs.json", "inputs.zip"):
|
||||
member = logical[prefix+name]
|
||||
need(member == "capsules/" + members[member]["sha256"] + Path(name).suffix, run + ": source capsule mapping")
|
||||
captured[run] = (archive.read(logical[prefix+"inputs.json"]), result, archive.read(logical[prefix+"inputs.zip"]))
|
||||
return captured
|
||||
|
||||
def verify_package(package, checks, repo=None):
|
||||
files = parsed((package/"files.json").read_bytes())
|
||||
need(set(files) == FILES, "source outer inventory")
|
||||
need({p.name for p in package.iterdir()} == FILES | {"files.json"}, "source exact package inventory")
|
||||
for name, expected in files.items():
|
||||
need((package/name).is_file() and not (package/name).is_symlink() and pin((package/name).read_bytes()) == expected, "source outer pin: " + name)
|
||||
return verify_data({run:(package/("source-"+run+".json")).read_bytes() for run in SPECS}, packaged(checks), repo)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("package", nargs="?", type=Path, default=HERE)
|
||||
parser.add_argument("--checks", type=Path, help="sibling checks package; default PACKAGE/../checks")
|
||||
parser.add_argument("--repo", type=Path, help="optional repository containing both exact commits, for renewed Git-blob comparison")
|
||||
args = parser.parse_args()
|
||||
print("PASS source evidence:", verify_package(args.package, args.checks or args.package.parent/"checks", args.repo))
|
||||
print("No builds, checkouts, helper execution or native acceptance claim. Run the checks verifier separately for full gate relationships.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user