autonomy-smoke-tests pr81 PASS evidence_sha256=e9b29f42e72804aedf5a269d4507aafa7270b39400c6923bbb014d8a335fe788
autonomy-unit-tests pr81 PASS evidence_sha256=068610c15e2716ad9dbda4df158f891693e53cb7da2c57aef3783e722fb6f354
campaign-approval-gate pr81 PASS evidence_sha256=0616d6aa11496391686dcbd658123e51d8d057e1f02661af7ef8512554e404d8
git-diff-check pr81 PASS evidence_sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
py-compile pr81 PASS evidence_sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
reconciliation-contract pr81 PASS evidence_sha256=f96a26b816cb58aec4639ca90e87da07ed8cf7d041d82fb67d755bbd5085dfca
release-state-machine pr81 PASS evidence_sha256=6cea88752b3e58ae5cee56ff3b1b13eab34117918d6bad9661194c031e2dc157
secret-scan pr81 PASS evidence_sha256=e85624b4ea35c4f7019bc9d9a3d7d44124afca891c3487fe9f550faf6c743245
signer-validator-contract pr81 PASS evidence_sha256=775b7aa27d0c17f48b3feff20c836f14b6ed8ebcb90ec7e0b76d2a13c579268a
aios.owner-final-merge-authorization-v2 real v2 contract tests passed
Narrow v1.2 delta: add the Owner approval-reopen POST path to SILENT_RELEASE_POST_PATHS so reopen can proceed in Shadow without enabling AIOS_GITOPS_WRITES_ENABLED. Route handler, release:approve guard, global write check and all other allow-list paths are unchanged. Adds tests/test_reopen_shadow_gate_contract.py covering: - reopen is a narrow silent-release POST (route requires release:approve) - global write gate is not enabled by this source patch - all existing silent-release POST paths remain present
76 lines
2.8 KiB
Python
76 lines
2.8 KiB
Python
from __future__ import annotations
|
|
|
|
import ast
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
STAGING = ROOT / "active-runtime" / "app" / "aios_model_api_staging.py"
|
|
if not STAGING.is_file():
|
|
pytest.skip(
|
|
"shadow-gate contract runs after package is applied to an AIOS checkout",
|
|
allow_module_level=True,
|
|
)
|
|
|
|
|
|
def _literal_string_set(node: ast.AST) -> set[str]:
|
|
"""Extract string literals from a set or frozenset({...}) literal.
|
|
|
|
The governed codebase represents allow-lists as ``frozenset({...})``; a
|
|
plain ``{...}`` set literal is also accepted. Only string literal members
|
|
are allowed in the silent-release allow-list.
|
|
"""
|
|
if isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id == "frozenset":
|
|
if len(node.args) == 1:
|
|
node = node.args[0]
|
|
if not isinstance(node, ast.Set):
|
|
raise AssertionError("SILENT_RELEASE_POST_PATHS must remain a set literal")
|
|
values: set[str] = set()
|
|
for elt in node.elts:
|
|
if not isinstance(elt, ast.Constant) or not isinstance(elt.value, str):
|
|
raise AssertionError("silent-release allow-list must contain only string literals")
|
|
values.add(elt.value)
|
|
return values
|
|
|
|
|
|
def test_reopen_is_narrow_silent_release_post():
|
|
tree = ast.parse(STAGING.read_text(encoding="utf-8"))
|
|
allow = None
|
|
for node in tree.body:
|
|
if not isinstance(node, ast.Assign):
|
|
continue
|
|
if any(isinstance(t, ast.Name) and t.id == "SILENT_RELEASE_POST_PATHS" for t in node.targets):
|
|
allow = _literal_string_set(node.value)
|
|
break
|
|
assert allow is not None
|
|
assert "/reopenOwnerApproval" in allow
|
|
# Existing governed silent-release paths must stay present.
|
|
assert {
|
|
"/createReleaseCandidate",
|
|
"/createReleaseIntent",
|
|
"/submitSignedApproval",
|
|
"/submitOwnerApproval",
|
|
"/startDeployment",
|
|
}.issubset(allow)
|
|
|
|
|
|
def test_reopen_route_still_requires_release_approve():
|
|
import re
|
|
|
|
source = STAGING.read_text(encoding="utf-8")
|
|
# Locate the route handler (the `== "/reopenOwnerApproval"` comparison),
|
|
# independent of single/double-quote style on the allow-list entry.
|
|
m = re.search(r'==\s*["\']/reopenOwnerApproval["\']', source)
|
|
assert m is not None, "reopen handler route comparison not found"
|
|
tail = source[m.start() : m.start() + 1200]
|
|
assert 'self.need("release:approve")' in tail
|
|
assert "reopen_owner_approval(silent_release_service(), data)" in tail
|
|
|
|
|
|
def test_global_write_gate_is_not_enabled_by_source_patch():
|
|
source = STAGING.read_text(encoding="utf-8")
|
|
# v1.2 must not hard-code or synthesize a global write enable.
|
|
assert 'AIOS_GITOPS_WRITES_ENABLED=true' not in source
|
|
assert 'AIOS_GITOPS_WRITES_ENABLED="true"' not in source
|