628 lines
21 KiB
Python
628 lines
21 KiB
Python
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
|