52 lines
2.3 KiB
Python
52 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""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'
|
|
|
|
|
|
def git(root, *args):
|
|
return subprocess.check_output(['git', '-C', str(root), *args], text=True, stderr=subprocess.STDOUT).strip()
|
|
|
|
|
|
def check_checkout(root, updating=False):
|
|
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]:
|
|
if not updating:
|
|
raise ValueError('contract HEAD does not match the project pin; stage the verified contracts/schema pointer')
|
|
git(sub, 'merge-base', '--is-ancestor', entry[1], commit)
|
|
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():
|
|
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; offline references and historical provenance valid')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
try:
|
|
main()
|
|
except (OSError, ValueError, subprocess.CalledProcessError) as exc:
|
|
raise SystemExit(str(exc)) from exc
|