Use pinned shared Gitee contracts as the sole runtime source

This commit is contained in:
2026-10-08 14:43:25 +08:00
parent 0f5efc6031
commit 6bf305284a
107 changed files with 1289 additions and 2205 deletions
+7 -2
View File
@@ -45,6 +45,7 @@ python3 - "$OUT/manifest.json" "$VERSION" "$source_ref" "$source_dirty" "$go_ver
import hashlib
import json
import pathlib
import subprocess
import sys
manifest_path, version, source_ref, source_dirty, go_version, out, project_root = sys.argv[1:]
@@ -67,9 +68,13 @@ manifest = {
"go.mod": sha256("go.mod"),
"go.sum": sha256("go.sum"),
},
"contract_source": {
"repository": "git@gitee.com:zzmbac/sip-contracts.git",
"commit": subprocess.check_output(["git", "-C", str(project / "contracts/schema"), "rev-parse", "HEAD"], text=True).strip(),
},
"contract_attestation": {
"local_contract_manifest_sha256": project_sha256("contracts/local/manifest.json"),
"local_mq_topology_sha256": project_sha256("contracts/local/mq-topology.json"),
"contract_verification_manifest_sha256": project_sha256("contracts/manifest.json"),
"shared_mq_topology_sha256": project_sha256("contracts/schema/mq-topology.json"),
"historical_upstream_manifest_sha256": project_sha256("docs/archive/upstream/manifest.txt"),
"proto_manifest_sha256": project_sha256("proto/manifest.json"),
},
+39 -30
View File
@@ -1,40 +1,49 @@
#!/usr/bin/env python3
"""Check provenance and reproducible digests of the sole current local bundle."""
import hashlib
import json
"""Verify the pinned shared contract; never fetch or use a local fallback."""
import importlib.util
from pathlib import Path
import subprocess
URL = 'git@gitee.com:zzmbac/sip-contracts.git'
ROOT = Path(__file__).resolve().parents[1]
BUNDLE = ROOT / "contracts" / "local"
MANIFEST = BUNDLE / "manifest.json"
def git(root, *args):
return subprocess.check_output(['git', '-C', str(root), *args], text=True, stderr=subprocess.STDOUT).strip()
def digest(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def check_checkout(root):
if (root / 'contracts/local').exists():
raise ValueError('contracts/local is a forbidden parallel contract source')
entry = git(root, 'ls-files', '--stage', '--', 'contracts/schema').split()
if len(entry) != 4 or entry[0] != '160000' or entry[2] != '0':
raise ValueError('contracts/schema must be a tracked Git submodule')
sub = root / 'contracts/schema'
if not (sub / '.git').exists():
raise ValueError('contract submodule not initialized; run git submodule update --init --recursive')
configured = git(root, 'config', '-f', '.gitmodules', '--get', 'submodule.contracts/schema.url')
if configured != URL or git(sub, 'remote', 'get-url', 'origin') != URL:
raise ValueError('contract submodule origin must be ' + URL)
commit = git(sub, 'rev-parse', 'HEAD')
if commit != entry[1]:
raise ValueError('contract HEAD does not match the project pin; stage the verified contracts/schema pointer')
if git(sub, 'status', '--porcelain', '--untracked-files=all'):
raise ValueError('contract submodule has uncommitted changes; verify and commit them in the shared repository')
return commit
def main() -> None:
manifest = json.loads(MANIFEST.read_text(encoding="utf-8"))
for relative, expected in manifest["sources"].items():
path = ROOT / relative
actual = digest(path)
if actual != expected:
raise SystemExit(f"source hash mismatch: {relative}: {actual} != {expected}")
paths = sorted(
(p for p in BUNDLE.rglob("*.json")
if p != MANIFEST and (p.parent == BUNDLE or p.relative_to(BUNDLE).parts[0] == "examples")),
key=lambda p: p.relative_to(BUNDLE).as_posix(),
)
if len(paths) < 10:
raise SystemExit("missing current contract examples or schemas")
listing = "".join(f"{p.relative_to(BUNDLE).as_posix()} {digest(p)}\n" for p in paths)
actual = hashlib.sha256(listing.encode("utf-8")).hexdigest()
if actual != manifest["bundle_sha256"]:
raise SystemExit(f"contract bundle hash mismatch: {actual} != {manifest['bundle_sha256']}")
print(f"current local contract: {len(paths)} JSON files, source and bundle hashes valid")
def main():
root = Path(__file__).resolve().parents[1]
commit = check_checkout(root)
checker_path = root / 'contracts/verify.py'
spec = importlib.util.spec_from_file_location('shared_contract_verify', checker_path)
checker = importlib.util.module_from_spec(spec)
spec.loader.exec_module(checker)
count = checker.verify_bundle(checker_path.parent)
print(f'shared contract {commit}: {count} JSON files; source/bundle hashes and offline references valid')
if __name__ == "__main__":
main()
if __name__ == '__main__':
try:
main()
except (OSError, ValueError, subprocess.CalledProcessError) as exc:
raise SystemExit(str(exc)) from exc
+2
View File
@@ -2,4 +2,6 @@
set -euo pipefail
cd "$(dirname "$0")/.."
python3 scripts/check-current-contracts.py
python3 -m unittest discover -s scripts -p 'test_contract_checkout.py' -v
python3 -m unittest discover -s contracts -p 'test_*.py' -v
go test ./contracts -run 'TestCurrentContract' -count=1
+12 -5
View File
@@ -52,6 +52,8 @@ import json
import pathlib
import sys
import subprocess
root, release = map(pathlib.Path, sys.argv[1:])
manifest = json.loads((release / "manifest.json").read_text())
assert manifest["manifest_version"] == 1
@@ -60,20 +62,25 @@ assert manifest["security"] == {"credentials_embedded": False, "production_appro
assert manifest["binary"]["sha256"] == hashlib.sha256((release / "sip-go-agent").read_bytes()).hexdigest()
assert manifest["go_version"].startswith("go version go1.27.1 ")
topology = json.loads((root / "contracts/local/mq-topology.json").read_text())
assert manifest["contract_source"] == {
"repository": "git@gitee.com:zzmbac/sip-contracts.git",
"commit": subprocess.check_output(["git", "-C", str(root / "contracts/schema"), "rev-parse", "HEAD"], text=True).strip(),
}
topology = json.loads((root / "contracts/schema/mq-topology.json").read_text())
assert topology["ownership"] == "saas"
assert topology["dispatcher"]["control"]["queue"].endswith(".v1")
assert topology["dispatcher"]["task"]["queue"].endswith(".v1")
assert topology["saas"]["result"]["queue"].endswith(".v1")
expected_attestation = {
"local_contract_manifest_sha256": hashlib.sha256((root / "contracts/local/manifest.json").read_bytes()).hexdigest(),
"local_mq_topology_sha256": hashlib.sha256((root / "contracts/local/mq-topology.json").read_bytes()).hexdigest(),
"contract_verification_manifest_sha256": hashlib.sha256((root / "contracts/manifest.json").read_bytes()).hexdigest(),
"shared_mq_topology_sha256": hashlib.sha256((root / "contracts/schema/mq-topology.json").read_bytes()).hexdigest(),
"historical_upstream_manifest_sha256": hashlib.sha256((root / "docs/archive/upstream/manifest.txt").read_bytes()).hexdigest(),
"proto_manifest_sha256": hashlib.sha256((root / "proto/manifest.json").read_bytes()).hexdigest(),
}
assert manifest["contract_attestation"] == expected_attestation
print("local artifact SHA-256:", manifest["binary"]["sha256"])
print("current local contract SHA-256:", expected_attestation["local_contract_manifest_sha256"])
print("pinned shared contract:", manifest["contract_source"]["commit"])
print("contract verification manifest SHA-256:", expected_attestation["contract_verification_manifest_sha256"])
print("source dirty:", manifest["source_dirty"])
print("production approved:", manifest["security"]["production_approval"])
PY
@@ -121,7 +128,7 @@ assert manifest["version"] == version
assert manifest["scope"] == "local-development"
assert manifest["security"]["production_approval"] is False
assert set(manifest["contract_attestation"]) == {
"local_contract_manifest_sha256", "local_mq_topology_sha256",
"contract_verification_manifest_sha256", "shared_mq_topology_sha256",
"historical_upstream_manifest_sha256", "proto_manifest_sha256",
}
assert all(len(digest) == 64 for digest in manifest["contract_attestation"].values())
+69
View File
@@ -0,0 +1,69 @@
import importlib.util
from pathlib import Path
import subprocess
import tempfile
import unittest
spec = importlib.util.spec_from_file_location('contract_checker', Path(__file__).with_name('check-current-contracts.py'))
checker = importlib.util.module_from_spec(spec)
spec.loader.exec_module(checker)
URL = 'git@gitee.com:zzmbac/sip-contracts.git'
class ContractCheckoutTest(unittest.TestCase):
def git(self, cwd, *args):
return subprocess.check_output(['git', '-c', 'user.name=Contract Test', '-c', 'user.email=contracts@example.invalid', '-C', str(cwd), *args], stderr=subprocess.STDOUT, text=True).strip()
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
base = Path(self.temp.name)
source = base / 'source'
source.mkdir()
self.git(source, 'init', '-q')
(source / 'test.schema.json').write_text('{}\n')
self.git(source, 'add', '.')
self.git(source, 'commit', '-qm', 'initial')
self.root = base / 'consumer'
self.root.mkdir()
self.git(self.root, 'init', '-q')
self.git(self.root, '-c', 'protocol.file.allow=always', 'submodule', 'add', '-q', str(source), 'contracts/schema')
self.sub = self.root / 'contracts/schema'
self.git(self.sub, 'remote', 'set-url', 'origin', URL)
self.git(self.root, 'config', '-f', '.gitmodules', 'submodule.contracts/schema.url', URL)
self.git(self.root, 'add', '.')
self.git(self.root, 'commit', '-qm', 'pin contract')
def test_clean_pinned_checkout(self):
self.assertEqual(checker.check_checkout(self.root), self.git(self.sub, 'rev-parse', 'HEAD'))
def test_uninitialized_submodule_is_rejected(self):
self.git(self.root, 'submodule', 'deinit', '-f', '--', 'contracts/schema')
with self.assertRaisesRegex(ValueError, 'not initialized'):
checker.check_checkout(self.root)
def test_unpinned_commit_is_rejected(self):
(self.sub / 'test.schema.json').write_text('{"changed": true}\n')
self.git(self.sub, 'add', '.')
self.git(self.sub, 'commit', '-qm', 'changed')
with self.assertRaisesRegex(ValueError, 'does not match'):
checker.check_checkout(self.root)
def test_dirty_submodule_is_rejected(self):
(self.sub / 'untracked.txt').write_text('unexpected\n')
with self.assertRaisesRegex(ValueError, 'uncommitted'):
checker.check_checkout(self.root)
def test_wrong_origin_is_rejected(self):
self.git(self.sub, 'remote', 'set-url', 'origin', 'https://example.invalid/other.git')
with self.assertRaisesRegex(ValueError, 'origin'):
checker.check_checkout(self.root)
def test_parallel_local_contract_is_rejected(self):
(self.root / 'contracts/local').mkdir()
with self.assertRaisesRegex(ValueError, 'parallel'):
checker.check_checkout(self.root)
if __name__ == '__main__':
unittest.main()
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
# Explicit maintenance operation: fetch latest shared main before contract edits.
set -euo pipefail
cd "$(dirname "$0")/.."
sub=contracts/schema
if [[ ! -e "$sub/.git" ]]; then
git submodule update --init -- "$sub"
fi
python3 scripts/check-current-contracts.py
git -C "$sub" fetch origin main
git -C "$sub" merge --ff-only FETCH_HEAD
if [[ "$(git -C "$sub" rev-parse HEAD)" != "$(git -C "$sub" rev-parse FETCH_HEAD)" ]]; then
echo 'Contract checkout is ahead of shared main; publish/reconcile it explicitly before updating.' >&2
exit 1
fi
python3 contracts/verify.py
python3 -m unittest discover -s contracts -p 'test_*.py' -v
# This stages only the contract pointer. Implementations, tests and the pointer
# still need a reviewed consumer-project commit; unrelated files are untouched.
git add -- "$sub"
python3 scripts/check-current-contracts.py
printf 'Shared contract updated to %s; pointer staged, consumer changes still require verification and commit.\n' "$(git -C "$sub" rev-parse HEAD)"