from __future__ import annotations from datetime import datetime, timezone import json from pathlib import Path import sqlite3 import sys import pytest ROOT=Path(__file__).resolve().parents[1] APP=ROOT/"active-runtime/app" sys.path.insert(0,str(APP)) import aios_durable_owner_authorization as auth NOW=datetime(2026,8,19,6,0,0,tzinfo=timezone.utc) ACCOUNT="chatgpt-governed-implementer-singlehost" def write_root_file(path: Path, value: object) -> Path: path.parent.mkdir(parents=True,exist_ok=True) path.write_text(json.dumps(value,sort_keys=True)+"\n",encoding="utf-8") path.chmod(0o600) return path def policy_value(**overrides): value={ "schema":auth.POLICY_SCHEMA, "grant_id":"owner-permanent-preparation-20260819", "owner_identity":"owner-singlehost", "account":ACCOUNT, "capabilities":[ "governed-task:project", "release:candidate", ], "issued_at":"2026-08-19T05:00:00Z", "not_before":"2026-08-19T05:00:00Z", "persistent_until_revoked":True, "constraints":{ "repository":"aios/aios", "allowed_target_prefix":"agent/", "release_version_prefix":"V2R2C", "max_task_risk":"engineering", }, } value.update(overrides) return value def load_policy(tmp_path,monkeypatch,**overrides): path=write_root_file(tmp_path/"policy.json",policy_value(**overrides)) revocations=write_root_file( tmp_path/"revocations.json", {"revoked_grant_ids":[]}, ) monkeypatch.setattr(auth,"validate_root_file",lambda path,**kwargs:path) return auth.DurablePolicy.load( path, revocations, now=NOW, ),path,revocations def governed_request(**overrides): value={ "task_id":"r42-owner-auth-projection-test-20260819", "repository":"aios/aios", "base_oid":"8"*40, "expected_branch_oid":"8"*40, "target_branch":"agent/r42-owner-auth-projection-test-20260819", "generation":1, "risk":"engineering", "description":"project existing governed task", "idempotency_key":"binding-owner-auth-projection-v1", "branch_mode":"CREATE_NEW", "priority":100, "max_attempts":3, "require_online_task_projection":True, "online_task":{ "goal":"Analyze source read-only.", "instructions":"Use source capture first.", "success_criteria":[ {"id":"source","description":"Return source snapshot."} ], "constraints":{"repository_mutation":"forbidden"}, "required_capabilities":["git.read","git.test"], "priority":100, "max_attempts":3, }, "execution":{ "action":"source_capture", "adapter":"source_capture", "capability_scope":["git.read","git.test"], "source_signals":["durable authorization projection"], }, } value.update(overrides) return value def release_request(**overrides): value={ "candidate_id":"r42-pf1-release-candidate-20260819", "source_commit":"8"*40, "version":"V2R2C2", } value.update(overrides) return value class FakeUpstream: def __init__(self): self.project_calls=[] def project_governed_task(self,body): self.project_calls.append(dict(body)) return 200,{ "task_id":body["task_id"], "job_id":"job-"+"a"*32, "state":"BOUND", } def broker(tmp_path,monkeypatch): policy,path,revocations=load_policy(tmp_path,monkeypatch) store=auth.ReceiptStore(tmp_path/"receipts.sqlite3") upstream=FakeUpstream() instance=auth.Broker( policy_path=path, revocation_path=revocations, store=store, upstream=upstream, expected_account=ACCOUNT, ) monkeypatch.setattr( auth.DurablePolicy, "load", classmethod(lambda cls,*args,**kwargs:policy), ) return instance,upstream,store,policy def test_allowed_persistent_capabilities_are_only_preparation_scopes(): assert auth.ALLOWED_PERSISTENT_CAPABILITIES=={ "governed-task:project", "release:candidate", } assert auth.ALLOWED_PERSISTENT_CAPABILITIES.isdisjoint( auth.FORBIDDEN_PERSISTENT_CAPABILITIES ) @pytest.mark.parametrize( "capability", sorted(auth.FORBIDDEN_PERSISTENT_CAPABILITIES), ) def test_policy_rejects_high_risk_persistent_capability( tmp_path,monkeypatch,capability ): bad=policy_value( capabilities=["governed-task:project",capability] ) path=write_root_file(tmp_path/"policy.json",bad) revocations=write_root_file( tmp_path/"revocations.json", {"revoked_grant_ids":[]}, ) monkeypatch.setattr(auth,"validate_root_file",lambda path,**kwargs:path) with pytest.raises( auth.AuthorizationError, match="POLICY_CAPABILITY_NOT_PERSISTABLE", ): auth.DurablePolicy.load(path,revocations,now=NOW) def test_policy_is_persistent_until_revoked(tmp_path,monkeypatch): policy,_,_=load_policy(tmp_path,monkeypatch) assert policy.persistent_until_revoked is True assert policy.account==ACCOUNT assert policy.capabilities=={ "governed-task:project", "release:candidate", } def test_revocation_fails_closed(tmp_path,monkeypatch): path=write_root_file(tmp_path/"policy.json",policy_value()) revocations=write_root_file( tmp_path/"revocations.json", {"revoked_grant_ids":["owner-permanent-preparation-20260819"]}, ) monkeypatch.setattr(auth,"validate_root_file",lambda path,**kwargs:path) with pytest.raises(auth.AuthorizationError,match="OWNER_GRANT_REVOKED"): auth.DurablePolicy.load(path,revocations,now=NOW) def test_future_policy_is_not_active(tmp_path,monkeypatch): with pytest.raises(auth.AuthorizationError,match="POLICY_NOT_ACTIVE"): load_policy( tmp_path, monkeypatch, issued_at="2026-08-20T05:00:00Z", not_before="2026-08-20T05:00:00Z", ) def test_governed_projection_request_is_tightly_constrained( tmp_path,monkeypatch ): policy,_,_=load_policy(tmp_path,monkeypatch) decision=policy.authorize( "governed-task:project", governed_request(), ) assert decision["decision"]=="ALLOW" assert decision["persistent_until_revoked"] is True bad_caps=governed_request() bad_caps["online_task"]={ **bad_caps["online_task"], "required_capabilities":["release:candidate"], } bad_action=governed_request() bad_action["execution"]={ **bad_action["execution"], "action":"deterministic", "adapter":"deterministic", } bad_scope=governed_request() bad_scope["execution"]={ **bad_scope["execution"], "capability_scope":["git.read"], } for bad in ( governed_request(repository="other/repo"), governed_request(target_branch="main"), governed_request(generation=2), governed_request(risk="high"), governed_request(expected_branch_oid="9"*40), governed_request(branch_mode="CONTINUE_EXISTING"), governed_request(priority=101), governed_request(max_attempts=4), governed_request(require_online_task_projection=False), bad_caps, bad_action, bad_scope, ): with pytest.raises(auth.AuthorizationError): policy.authorize("governed-task:project",bad) def test_write_capable_projection_is_allowed_only_as_source_capture_placeholder( tmp_path,monkeypatch ): policy,_,_=load_policy(tmp_path,monkeypatch) request=governed_request() request["online_task"]={ **request["online_task"], "required_capabilities":[ "git.read", "git.test", "governed.write.branch", "governed.write.file", ], } request["execution"]={ **request["execution"], "capability_scope":[ "git.read", "git.test", "governed.write.branch", "governed.write.file", ], } decision=policy.authorize("governed-task:project",request) assert decision["decision"]=="ALLOW" assert request["execution"]["action"]=="source_capture" def test_release_candidate_request_is_tightly_constrained( tmp_path,monkeypatch ): policy,_,_=load_policy(tmp_path,monkeypatch) decision=policy.authorize("release:candidate",release_request()) assert decision["decision"]=="ALLOW" with pytest.raises( auth.AuthorizationError, match="RELEASE_VERSION_NOT_AUTHORIZED", ): policy.authorize( "release:candidate", release_request(version="V3R1C1"), ) with pytest.raises( auth.AuthorizationError, match="RELEASE_CANDIDATE_FIELDS_INVALID", ): policy.authorize( "release:candidate", {**release_request(),"execute":True}, ) def test_governed_task_projection_executes_canonical_upstream( tmp_path,monkeypatch ): instance,upstream,store,_=broker(tmp_path,monkeypatch) request=governed_request() response=instance.execute( "governed-task:project", request, idempotency_key="owner-auth-projection-operation-0001", ) assert len(upstream.project_calls)==1 assert upstream.project_calls[0]==request assert response["operation_state"]=="EXECUTED" assert response["external_capability_projection_required"] is False assert response["separate_owner_release_approval_still_required"] is True def test_release_candidate_authorization_does_not_invent_builder_upstream( tmp_path,monkeypatch ): instance,upstream,store,_=broker(tmp_path,monkeypatch) response=instance.execute( "release:candidate", release_request(), idempotency_key="owner-auth-release-candidate-operation-0001", ) assert upstream.project_calls==[] assert response["operation_state"]==( "AUTHORIZED_PENDING_EXTERNAL_CAPABILITY_PROJECTION" ) assert response["upstream_status"] is None assert response["upstream_response"] is None assert response["external_capability_projection_required"] is True assert response["projection_id"].startswith("projection-") assert response["projection_state"]=="PENDING_EXTERNAL_CONNECTOR" assert response["separate_owner_release_approval_still_required"] is True def test_release_authorization_creates_durable_projection_outbox( tmp_path,monkeypatch ): instance,_,store,policy=broker(tmp_path,monkeypatch) request=release_request() response=instance.execute( "release:candidate", request, idempotency_key="owner-auth-release-outbox-0001", ) projection=store.get_projection(response["projection_id"]) assert projection is not None assert projection["schema"]==auth.PROJECTION_SCHEMA assert projection["state"]=="PENDING_EXTERNAL_CONNECTOR" assert projection["grant_id"]==policy.grant_id assert projection["account"]==ACCOUNT assert projection["capability"]=="release:candidate" assert projection["request"]==request assert projection["separate_owner_release_approval_still_required"] is True listed=instance.projections() assert listed["schema"]==auth.PROJECTION_LIST_SCHEMA assert listed["count"]==1 assert listed["items"][0]["projection_id"]==response["projection_id"] assert listed["external_connector_ack_supported"] is False def test_existing_pre_outbox_release_receipt_is_backfilled_on_exact_retry( tmp_path,monkeypatch ): instance,_,store,policy=broker(tmp_path,monkeypatch) request=release_request() decision=policy.authorize("release:candidate",request) key="owner-auth-release-pre-outbox-0001" legacy_response={ "schema":auth.RECEIPT_SCHEMA, "grant_id":policy.grant_id, "owner_identity":policy.owner_identity, "account":policy.account, "capability":"release:candidate", "policy_sha256":policy.policy_sha256, "request_sha256":decision["request_sha256"], "idempotency_key":key, "operation_state":"AUTHORIZED_PENDING_EXTERNAL_CAPABILITY_PROJECTION", "upstream_status":None, "upstream_response":None, "external_capability_projection_required":True, "separate_owner_release_approval_still_required":True, } store.put( key, "release:candidate", decision["request_sha256"], legacy_response, ) response=instance.execute( "release:candidate", request, idempotency_key=key, ) assert response["projection_id"].startswith("projection-") assert response["projection_state"]=="PENDING_EXTERNAL_CONNECTOR" assert store.get_projection(response["projection_id"]) is not None persisted=store.get(key)["response"] assert persisted["projection_id"]==response["projection_id"] def test_projection_id_is_deterministic_and_exact_retry_does_not_duplicate( tmp_path,monkeypatch ): instance,_,store,_=broker(tmp_path,monkeypatch) key="owner-auth-release-outbox-0002" first=instance.execute("release:candidate",release_request(),idempotency_key=key) second=instance.execute("release:candidate",release_request(),idempotency_key=key) assert second==first con=sqlite3.connect(store.path) rows=con.execute("select projection_id from projection_outbox").fetchall() assert rows==[(first["projection_id"],)] def test_projection_enqueue_recovers_crash_between_outbox_and_receipt( tmp_path,monkeypatch ): instance,_,store,policy=broker(tmp_path,monkeypatch) request=release_request() decision=policy.authorize("release:candidate",request) key="owner-auth-release-outbox-crash-0001" first=store.enqueue_projection( idempotency_key=key, grant_id=policy.grant_id, account=policy.account, capability="release:candidate", policy_sha256=policy.policy_sha256, request_sha256=decision["request_sha256"], request=request, ) # Simulate a later retry after the process crashed before receipt creation. second=store.enqueue_projection( idempotency_key=key, grant_id=policy.grant_id, account=policy.account, capability="release:candidate", policy_sha256=policy.policy_sha256, request_sha256=decision["request_sha256"], request=request, ) assert second==first def test_projection_idempotency_conflict_is_fail_closed( tmp_path,monkeypatch ): instance,_,store,policy=broker(tmp_path,monkeypatch) first=release_request() first_decision=policy.authorize("release:candidate",first) key="owner-auth-release-outbox-conflict-0001" store.enqueue_projection( idempotency_key=key, grant_id=policy.grant_id, account=policy.account, capability="release:candidate", policy_sha256=policy.policy_sha256, request_sha256=first_decision["request_sha256"], request=first, ) second=release_request(version="V2R2C3") second_decision=policy.authorize("release:candidate",second) with pytest.raises(auth.AuthorizationError,match="PROJECTION_IDEMPOTENCY_CONFLICT"): store.enqueue_projection( idempotency_key=key, grant_id=policy.grant_id, account=policy.account, capability="release:candidate", policy_sha256=policy.policy_sha256, request_sha256=second_decision["request_sha256"], request=second, ) def test_revocation_blocks_projection_enumeration(tmp_path,monkeypatch): instance,_,store,policy=broker(tmp_path,monkeypatch) response=instance.execute( "release:candidate", release_request(), idempotency_key="owner-auth-release-outbox-revoke-0001", ) # Restore real policy loading and write a revocation for this grant. monkeypatch.undo() revocations=instance.revocation_path revocations.write_text( json.dumps({"revoked_grant_ids":[policy.grant_id]})+"\n", encoding="utf-8", ) revocations.chmod(0o600) monkeypatch.setattr(auth,"validate_root_file",lambda path,**kwargs:path) with pytest.raises(auth.AuthorizationError,match="OWNER_GRANT_REVOKED"): instance.projections() # Evidence is retained; revocation does not erase history. assert store.get_projection(response["projection_id"]) is not None def test_projection_outbox_contains_no_credentials(tmp_path,monkeypatch): instance,_,store,_=broker(tmp_path,monkeypatch) instance.execute( "release:candidate", release_request(), idempotency_key="owner-auth-release-outbox-schema-0001", ) con=sqlite3.connect(store.path) columns=[row[1] for row in con.execute("pragma table_info(projection_outbox)")] joined=" ".join(columns).lower() for forbidden in ("token","credential","private_key","secret"): assert forbidden not in joined payload=con.execute("select payload_json from projection_outbox").fetchone()[0] assert "Bearer " not in payload assert "submitOwnerApproval" not in payload assert "startDeployment" not in payload def test_exact_retry_returns_same_receipt_without_second_projection( tmp_path,monkeypatch ): instance,upstream,_,_=broker(tmp_path,monkeypatch) request=governed_request() first=instance.execute( "governed-task:project", request, idempotency_key="owner-auth-projection-operation-0002", ) second=instance.execute( "governed-task:project", request, idempotency_key="owner-auth-projection-operation-0002", ) assert second==first assert len(upstream.project_calls)==1 def test_idempotency_conflict_fails_closed(tmp_path,monkeypatch): instance,_,_,_=broker(tmp_path,monkeypatch) instance.execute( "release:candidate", release_request(), idempotency_key="owner-auth-release-operation-0002", ) with pytest.raises(auth.AuthorizationError,match="IDEMPOTENCY_CONFLICT"): instance.execute( "release:candidate", release_request(version="V2R2C3"), idempotency_key="owner-auth-release-operation-0002", ) def test_receipt_store_contains_no_owner_policy_or_credentials( tmp_path,monkeypatch ): instance,_,store,_=broker(tmp_path,monkeypatch) instance.execute( "release:candidate", release_request(), idempotency_key="owner-auth-release-operation-0003", ) con=sqlite3.connect(store.path) columns=[row[1] for row in con.execute("pragma table_info(receipts)")] joined=" ".join(columns).lower() assert "token" not in joined assert "credential" not in joined assert "policy_json" not in columns def test_systemd_broker_uses_unix_socket_and_only_host_control_credential(): unit=( ROOT/"deploy/systemd/aios-owner-durable-authorization-broker.service" ).read_text() assert "LoadCredential=agent_task_control_token:" in unit assert "release_candidate_token" not in unit assert "18947" not in unit assert "AIOS_RELEASE_CANDIDATE_API_URL" not in unit assert "AIOS_OWNER_AUTH_BROKER_SOCKET=%t/aios-owner-authorization-broker/broker.sock" in unit assert "Group=aios-executor-exchange" in unit assert "RestrictAddressFamilies=AF_UNIX AF_INET" in unit assert "IPAddressDeny=any" in unit assert "IPAddressAllow=127.0.0.0/8" in unit assert "InaccessiblePaths=/data/aios-gitops /home" in unit def test_source_contains_no_release_builder_endpoint_or_high_risk_execution(): source=( ROOT/"active-runtime/app/aios_durable_owner_authorization.py" ).read_text() assert "/createReleaseCandidate" not in source assert "18947" not in source assert "ThreadingHTTPServer" not in source assert "ThreadingUnixStreamServer" in source assert "startDeployment" in source assert "tag_publish" in source assert "baseline_registry_finalize" in source assert "runtime_switch" in source assert "AUTHORIZED_PENDING_EXTERNAL_CAPABILITY_PROJECTION" in source assert "PENDING_EXTERNAL_CONNECTOR" in source assert "projection_outbox" in source assert "external_connector_ack_supported" in source assert "SAFE_PROJECTED_TASK_CAPABILITIES" in source assert "INITIAL_EXECUTION_ACTION_NOT_AUTHORIZED" in source def test_docs_avoid_new_broker_bearer_secret(): doc=( ROOT/"docs/superpowers/specs/2026-08-19-durable-owner-authorization.md" ).read_text() assert "AF_UNIX" in doc assert "avoids introducing another long-lived bearer secret" in doc def test_docs_preserve_separate_owner_release_approval(): doc=( ROOT/"docs/superpowers/specs/2026-08-19-durable-owner-authorization.md" ).read_text() assert "persistent until explicitly revoked" in doc.lower() assert "Owner signature" in doc assert "AUTHORIZED_PENDING_EXTERNAL_CAPABILITY_PROJECTION" in doc assert "PENDING_EXTERNAL_CONNECTOR" in doc