Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions continuityos/company_twin_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ def _authorize_actor(actor: Mapping[str, Any], operation: str) -> None:
elif operation == "EXPORT" and actor_kind == "HUMAN":
if authority not in {"OWNER", "WORKER", "READ_ONLY"}:
raise LifecycleAuthorizationError("unsupported human export authority")
elif operation == "EXPORT":
raise LifecycleAuthorizationError("unsupported export actor kind")


def retention_state(
Expand Down
16 changes: 16 additions & 0 deletions tests/test_company_twin_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,3 +316,19 @@ def test_hold_release_requires_owner():
set_hold(
held, hold=False, reason=None, changed_at="2026-01-03T00:00:00Z", changed_by=ROBOT
)


@pytest.mark.parametrize("actor_kind,authority", [
("ALIEN", "NONSENSE"),
("SERVICE", "NONE"),
("", "OWNER"),
("AGENT", "OWNER"),
])
def test_export_fail_closed_on_unrecognized_or_unauthorized_actor(actor_kind, authority):
requester = {"actor_id": "untrusted:synthetic", "actor_kind": actor_kind, "authority_class": authority}
with pytest.raises(LifecycleAuthorizationError):
build_export_bundle(
[record("cti_test")], tenant_id="tenant_demo",
authorized_scopes=["team:engineering"],
requested_at="2026-02-01T00:00:00Z", requested_by=requester,
)
21 changes: 21 additions & 0 deletions tests/test_person_twin_privacy_provenance.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,3 +764,24 @@ def test_r2_module_has_no_network_connector_oauth_or_runtime_effect_surface():
"can_trade",
)
assert all(token not in text for token in forbidden)


@pytest.mark.parametrize("actor_kind,authority", [
("ALIEN", "NONSENSE"),
("SERVICE", "NONE"),
("", "OWNER"),
])
def test_person_export_fails_closed_on_unrecognized_actor(actor_kind, authority):
from continuityos.company_twin_lifecycle import LifecycleAuthorizationError
identity, source, consent, ledger, record = _build()
requester = {
"actor_id": "untrusted:synthetic", "actor_kind": actor_kind, "authority_class": authority,
}
with pytest.raises(LifecycleAuthorizationError):
pp.build_person_twin_export_bundle(
[record], identity, authorized_scopes=[record["scope"]],
source_records={source["id"]: source},
consent_receipts={consent["consent_receipt_id"]: consent},
current_revocation_ledger=ledger,
purpose="person-memory", requested_at=AT, requested_by=requester,
)
Loading