3ea36ef3ab
Squash merge of phase/03-l2-modules-and-core-scripts; 4 L2s + 5 core scripts; verify_phase03.sh green.
55 lines
1.7 KiB
Python
Executable File
55 lines
1.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""confidence_signal.py — REQ-08 / D-024
|
|
|
|
Reads a contract.yaml, invokes policy_checker.py as a subprocess, and emits
|
|
a deterministic JSON confidence score.
|
|
|
|
policy pass -> {"score": 0.90, "reason": "POLICY_PASS"}
|
|
policy fail -> {"score": 0.40, "reason": "<violation code>"}
|
|
|
|
Exit 0 ALWAYS (per D-024): the pipeline decides the gate, not this script's
|
|
exit code.
|
|
|
|
Input: argv[1] = path to a contract.yaml file.
|
|
"""
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
def main() -> int:
|
|
if len(sys.argv) < 2:
|
|
print("usage: confidence_signal.py <contract.yaml>", file=sys.stderr)
|
|
return 1
|
|
|
|
contract_path = sys.argv[1]
|
|
|
|
# Resolve policy_checker.py relative to this script so it works regardless
|
|
# of cwd. Use python3 + script path (not ./) per the contract.
|
|
here = os.path.dirname(os.path.abspath(__file__))
|
|
policy_checker = os.path.join(here, "policy_checker.py")
|
|
|
|
proc = subprocess.run(
|
|
["python3", policy_checker, contract_path],
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
|
|
if proc.returncode == 0:
|
|
score = "0.90"
|
|
# POLICY_PASS is the expected stdout; strip any trailing whitespace.
|
|
reason = proc.stdout.strip() or "POLICY_PASS"
|
|
else:
|
|
score = "0.40"
|
|
# The violation code (e.g. "POLICY_VIOLATION:PUBLIC_INGRESS") is on stdout.
|
|
reason = proc.stdout.strip() or "POLICY_VIOLATION:UNKNOWN"
|
|
|
|
# Emit with literal score (two-decimal form per the contract) and a quoted
|
|
# reason. Constructed manually so json.dumps does not collapse 0.90 -> 0.9.
|
|
print('{"score": ' + score + ', "reason": ' + json.dumps(reason) + '}')
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main()) |