autonomy-unit-tests 23 passed on exact PR head
autonomy-smoke-tests executor CLI smoke passed on exact PR head
git-diff-check 11 additive paths; protected paths unchanged
py-compile 5 runtime modules compiled
reconciliation-contract Authority/Gitea main and branch OIDs reconciled
release-state-machine executor and metadata tests passed
secret-scan 11 changed files scanned; no secret markers
signer-validator-contract validator self-test and signer CLI contract passed
owner-approval-gate Owner actor 2 auto-merge intent verified for exact current head; protected target main; no unresolved conversations; signed-commit gate not required
153 lines
5.0 KiB
Python
153 lines
5.0 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import sys
|
|
import types
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(ROOT / "active-runtime" / "app"))
|
|
|
|
import owner_local_auth_ingress as ingress
|
|
|
|
|
|
TARGET = "c7adece1cc8beffe7c718d53c775898b45d6c7f8"
|
|
|
|
|
|
def binding():
|
|
return {
|
|
"schema": ingress.BINDING_SCHEMA,
|
|
"owner_identity": "aiman",
|
|
"owner_role": "owner",
|
|
"authenticated_scope": "commit:create",
|
|
"request": {
|
|
"action": ingress.ACTION,
|
|
"task_id": "V2R1C7_PRODUCTION_EXECUTOR_BOOTSTRAP",
|
|
"repository": "aios/aios",
|
|
"base_ref": "refs/heads/main",
|
|
"base_oid": TARGET,
|
|
"target_branch": "agent/v2r1c7-production-executor-bootstrap-20260807-r2",
|
|
"one_time_use": True,
|
|
"expires_in_seconds": 300,
|
|
"production_change_authorized": False,
|
|
"tag_change_authorized": False,
|
|
"baseline_change_authorized": False,
|
|
"main_write_authorized": False,
|
|
"allowed_operations": sorted(ingress.EXPECTED_ALLOWED_OPERATIONS),
|
|
"denied_operations": sorted(ingress.EXPECTED_DENIED_OPERATIONS),
|
|
},
|
|
}
|
|
|
|
|
|
def test_exact_binding_passes():
|
|
result = ingress.validate_binding(binding())
|
|
assert result["owner_identity"] == "aiman"
|
|
assert result["authenticated_scope"] == "commit:create"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("path", "value", "error"),
|
|
[
|
|
(("owner_identity",), "owner", None),
|
|
(("authenticated_scope",), "*", "OWNER_SCOPE_INVALID"),
|
|
(("request", "target_branch"), "patch/not-allowed", "TARGET_BRANCH_REJECTED"),
|
|
(("request", "production_change_authorized"), True, "CONSEQUENTIAL_CAPABILITY_REJECTED"),
|
|
(("request", "tag_change_authorized"), True, "CONSEQUENTIAL_CAPABILITY_REJECTED"),
|
|
(("request", "baseline_change_authorized"), True, "CONSEQUENTIAL_CAPABILITY_REJECTED"),
|
|
(("request", "main_write_authorized"), True, "CONSEQUENTIAL_CAPABILITY_REJECTED"),
|
|
(("request", "expires_in_seconds"), 901, "EXPIRY_REJECTED"),
|
|
],
|
|
)
|
|
def test_negative_binding_contract(path, value, error):
|
|
payload = binding()
|
|
target = payload
|
|
for item in path[:-1]:
|
|
target = target[item]
|
|
target[path[-1]] = value
|
|
if error is None:
|
|
# Structurally valid but not the deployment allowlisted identity;
|
|
# the live Broker performs that final allowlist check.
|
|
assert ingress.validate_binding(payload)["owner_identity"] == "owner"
|
|
else:
|
|
with pytest.raises(ingress.BootstrapError, match=error):
|
|
ingress.validate_binding(payload)
|
|
|
|
|
|
def test_request_summary_never_grants_consequential_capability():
|
|
summary = ingress.request_summary(ingress.validate_binding(binding()))
|
|
assert summary["production_change_authorized"] is False
|
|
assert summary["tag_change_authorized"] is False
|
|
assert summary["baseline_change_authorized"] is False
|
|
assert summary["main_write_authorized"] is False
|
|
|
|
|
|
def test_safe_result_rejects_secret_material():
|
|
with pytest.raises(ingress.BootstrapError, match="SENSITIVE_DATA"):
|
|
ingress.safe_result({"status": "READY", "raw_token": "secret"})
|
|
|
|
|
|
def test_safe_result_keeps_only_allowlisted_fields():
|
|
result = ingress.safe_result(
|
|
{
|
|
"status": "READY_FOR_CODE_AUTHORING",
|
|
"grant_id": "grant-1",
|
|
"some_untrusted_extra": "drop-me",
|
|
}
|
|
)
|
|
assert result == {
|
|
"grant_id": "grant-1",
|
|
"status": "READY_FOR_CODE_AUTHORING",
|
|
}
|
|
|
|
|
|
def test_invoke_broker_constructs_narrow_principal(monkeypatch):
|
|
captured = {}
|
|
|
|
class Config:
|
|
allowed_owner_identities = frozenset({"aiman"})
|
|
allowed_intake_scopes = frozenset({"commit:create"})
|
|
max_expiry_seconds = 900
|
|
|
|
@classmethod
|
|
def from_environment(cls):
|
|
return cls()
|
|
|
|
class Principal:
|
|
def __init__(self, **kwargs):
|
|
captured["principal"] = kwargs
|
|
|
|
class Broker:
|
|
def __init__(self, config):
|
|
captured["config"] = config
|
|
|
|
def authorize_and_provision(self, request, principal):
|
|
captured["request"] = request
|
|
return {
|
|
"status": "READY_FOR_CODE_AUTHORING",
|
|
"grant_id": "grant-test",
|
|
}
|
|
|
|
module = types.SimpleNamespace(
|
|
OwnerAuthorizationBroker=Broker,
|
|
OwnerAuthorizationBrokerConfig=Config,
|
|
OwnerPrincipal=Principal,
|
|
)
|
|
monkeypatch.setitem(sys.modules, "owner_authorization_broker", module)
|
|
result = ingress.invoke_broker(ingress.validate_binding(binding()))
|
|
assert result["status"] == "READY_FOR_CODE_AUTHORING"
|
|
assert captured["principal"] == {
|
|
"identity": "aiman",
|
|
"role": "owner",
|
|
"authenticated_scope": "commit:create",
|
|
"token_scopes": frozenset({"commit:create"}),
|
|
"credential_id": "",
|
|
}
|
|
|
|
|
|
def test_confirmation_phrase_is_exact():
|
|
challenge = "abc123"
|
|
assert f"AUTHORIZE {challenge}" == "AUTHORIZE abc123"
|