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
29 changes: 21 additions & 8 deletions specs/hosted-api-operations/status.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,38 +127,51 @@
{
"id": "GRAPHOS-OPS-R006",
"title": "Consume the engine's packaged wire-callable contract",
"delivery_state": "LANDED",
"delivery_state": "VERIFIED",
"landed_in": [
"100d015ca012"
],
"verified_by": []
"verified_by": [
"tests/api/test_eg_binding.py:190"
]
},
{
"id": "GRAPHOS-OPS-R007",
"title": "Immutable operation registry with digest and authorization",
"delivery_state": "LANDED",
"delivery_state": "VERIFIED",
"landed_in": [
"4b83c69e2b41"
],
"verified_by": []
"verified_by": [
"tests/api/test_api_registry.py:110",
"tests/api/test_api_registry.py:63"
]
},
{
"id": "GRAPHOS-OPS-R008",
"title": "Generated engine-bound operations with exclusions",
"delivery_state": "LANDED",
"delivery_state": "VERIFIED",
"landed_in": [
"4b83c69e2b41"
],
"verified_by": []
"verified_by": [
"tests/api/test_eg_binding.py:133",
"tests/api/test_eg_binding.py:88"
]
},
{
"id": "GRAPHOS-OPS-R009",
"title": "Single invoke pipeline for authority, effect, and audit",
"delivery_state": "LANDED",
"delivery_state": "VERIFIED",
"landed_in": [
"deb2b45bf83d"
],
"verified_by": []
"verified_by": [
"tests/api/test_invoke_contract.py:238",
"tests/api/test_invoke_governance.py:193",
"tests/api/test_invoke_governance.py:250",
"tests/api/test_invoke_governance.py:87"
]
},
{
"id": "GRAPHOS-OPS-R010",
Expand Down
2 changes: 2 additions & 0 deletions tests/api/test_api_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def allow_all(_op: OpSpec, _caller: Caller) -> bool:
return True


@pytest.mark.spec("GRAPHOS-OPS-R007")
def test_registry_digest_is_order_independent_and_covers_contract() -> None:
first = make_op()
second = make_op("identity.users.list", effect=Effect.READ)
Expand Down Expand Up @@ -106,6 +107,7 @@ def test_eg_generated_method_id_preserves_contract_case() -> None:
assert make_op("eg.query.Uql").id == "eg.query.Uql"


@pytest.mark.spec("GRAPHOS-OPS-R007")
def test_discovery_requires_principal_scopes_policy_and_surface() -> None:
op = make_op()
registry = Registry([op])
Expand Down
15 changes: 15 additions & 0 deletions tests/api/test_eg_binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def _curated(method: str, op_id: str) -> OpSpec:
)


@pytest.mark.spec("GRAPHOS-OPS-R008")
def test_generates_exact_caller_bound_ops(tmp_path: Path) -> None:
contract, exclusions = _fixture(tmp_path)
ops = load_eg_bindings(contract_root=contract, exclusions_path=exclusions)
Expand Down Expand Up @@ -129,6 +130,7 @@ def test_curated_binding_cannot_weaken_engine_scope(tmp_path: Path) -> None:
)


@pytest.mark.spec("GRAPHOS-OPS-R008")
def test_exclusion_needs_current_method_and_valid_reason(tmp_path: Path) -> None:
contract, exclusions = _fixture(tmp_path)
exclusions.write_text("exclusions:\n - method: Read\n reason: service-only\n")
Expand Down Expand Up @@ -183,3 +185,16 @@ def test_missing_schema_pointer_fails_closed(tmp_path: Path) -> None:
path.write_text(json.dumps(document))
with pytest.raises(EgContractError, match="missing schema pointer"):
load_eg_bindings(contract_root=contract, exclusions_path=exclusions)


@pytest.mark.spec("GRAPHOS-OPS-R006")
def test_method_not_marked_wire_callable_is_not_bound(tmp_path: Path) -> None:
contract, exclusions = _fixture(tmp_path)
path = contract / "methods.json"
document = json.loads(path.read_text())
for row in document["methods"]:
if row["id"] == "Service":
row["is_wire_callable"] = False
path.write_text(json.dumps(document))
ops = load_eg_bindings(contract_root=contract, exclusions_path=exclusions)
assert {op.id for op in ops} == {"eg.query.Admin", "eg.query.Read"}
1 change: 1 addition & 0 deletions tests/api/test_invoke_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ def run(
)


@pytest.mark.spec("GRAPHOS-OPS-R009")
@pytest.mark.parametrize("surface", list(Surface))
def test_equivalent_surface_authority_and_result(surface):
services, runtime, audit, _, _ = setup_services()
Expand Down
3 changes: 3 additions & 0 deletions tests/api/test_invoke_governance.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ async def dispatch():
asyncio.run(scenario())


@pytest.mark.spec("GRAPHOS-OPS-R009")
@pytest.mark.parametrize("failure", ["dispatch", "audit", "completion", "timeout"])
def test_uncertain_outcome_stays_pending_without_redispatch(failure):
services, runtime, audit, journal, _ = setup_services()
Expand Down Expand Up @@ -189,6 +190,7 @@ async def native_dispatch(op, params, context):
assert len(runtime.calls) == 1


@pytest.mark.spec("GRAPHOS-OPS-R009")
def test_destructive_plan_single_consumption_and_replay():
services, runtime, audit, _, leases = setup_services(
operation(effect=Effect.DESTRUCTIVE)
Expand Down Expand Up @@ -245,6 +247,7 @@ def test_fuzzy_write_only_previews():
assert not runtime.calls and not audit.events


@pytest.mark.spec("GRAPHOS-OPS-R009")
def test_console_admin_requires_same_human_fresh_mfa_and_session():
op = operation(effect=Effect.ADMIN, principals=PrincipalRule.HUMAN_UNDELEGATED)
services, runtime, _, _, _ = setup_services(op)
Expand Down
Loading