| % SOV-KERNEL-MONSTER Logic Layer | |
| % Loaded by pre-receive hook via swipl. | |
| :- use_module(library(process)). | |
| % ---- Key Registry (MOCK) ---- | |
| % These are deterministic test fingerprints — safe to commit. | |
| % Replace with real Ed25519 fingerprints after running provision/sov-bootstrap.yml | |
| % and reading the audit output. NEVER commit real private keys. | |
| architect_key('mock:arch:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC'). | |
| engineer_key('mock:eng1:AB:CD:EF:01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF'). | |
| engineer_key('mock:eng2:BC:DE:F0:12:34:56:78:9A:BC:DE:F0:12:34:56:78:9A:BC:DE:F0'). | |
| engineer_key('mock:eng3:CD:EF:01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF:01'). | |
| engineer_key('mock:eng4:DE:F0:12:34:56:78:9A:BC:DE:F0:12:34:56:78:9A:BC:DE:F0:12'). | |
| engineer_key('mock:eng5:EF:01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF:01:23'). | |
| ci_bot_key('mock:hauki:F0:12:34:56:78:9A:BC:DE:F0:12:34:56:78:9A:BC:DE:F0:12:34'). | |
| authorized_key(K) :- architect_key(K). | |
| authorized_key(K) :- engineer_key(K). | |
| authorized_key(K) :- ci_bot_key(K). | |
| % ---- ASP_MAXIMAL: main branch requires Architect counter-signature ---- | |
| verify_push(NewRev, 'refs/heads/main') :- | |
| !, | |
| get_commit_signer(NewRev, Signer), | |
| ( architect_key(Signer) -> true | |
| ; format(user_error, "[ASP_MAXIMAL] Main branch push requires Architect counter-signature. Got: ~w~n", [Signer]), | |
| fail | |
| ). | |
| % ---- ASP_STRICT: feature branches require any authorized signer ---- | |
| verify_push(NewRev, Ref) :- | |
| Ref \= 'refs/heads/main', | |
| get_commit_signer(NewRev, Signer), | |
| ( authorized_key(Signer) -> true | |
| ; format(user_error, "[ASP_STRICT] Unauthorized committer: ~w~n", [Signer]), | |
| fail | |
| ). | |
| % ---- Fallback: allow if no signer info available (warn only) ---- | |
| verify_push(_, Ref) :- | |
| format(user_error, "[ASP_WARN] Could not verify signer for ref: ~w~n", [Ref]). | |
| % ---- Helper: extract signing key from commit ---- | |
| get_commit_signer(Commit, KeyID) :- | |
| process_create(path(git), ['show', '-s', '--format=%GK', Commit], | |
| [stdout(pipe(Out)), stderr(null)]), | |
| read_line_to_string(Out, Line), | |
| close(Out), | |
| ( Line \= "" -> atom_string(KeyID, Line) | |
| ; KeyID = 'UNSIGNED' | |
| ). | |