Skip to content

Commit 1663e03

Browse files
authored
test: cover invalid delegation signature in action evidence (#76)
* test: cover invalid delegation signature in action evidence Signed-off-by: BIN Zhang <joy7759@gmail.com> * test: strengthen action invalid signature ordering coverage Signed-off-by: BIN Zhang <joy7759@gmail.com> --------- Signed-off-by: BIN Zhang <joy7759@gmail.com>
1 parent 566e587 commit 1663e03

2 files changed

Lines changed: 33 additions & 1 deletion

File tree

tests/conformance/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ Spec: [trace-a2a-profile.md](../../docs/spec/trace-a2a-profile.md), [provenance-
101101
| ACTION-005 | MUST | A requested action outside the effective delegated scope is classified as authorization-invalid, not malformed provenance. | `SCOPE_NOT_PERMITTED`. |
102102
| ACTION-006 | MUST | A valid delegated action denied by local policy is classified as authorization-invalid, not malformed provenance. | `SCOPE_NOT_PERMITTED`. |
103103
| ACTION-007 | MUST | A valid delegated action whose controller outcome is negative remains valid evidence of a negative outcome. | `valid_negative_outcome`. |
104+
| ACTION-008 | MUST | An action whose delegation chain contains a credential with an invalid signature is rejected as provenance-invalid before authorization or outcome handling. | `INVALID_CREDENTIAL`. |

tests/conformance/test_profile_conformance.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from __future__ import annotations
77

8-
from dataclasses import dataclass
8+
from dataclasses import dataclass, replace
99

1010
import pytest
1111
from cryptography.hazmat.primitives.asymmetric import ec
@@ -404,3 +404,34 @@ def test_action_007_controller_rejection_is_valid_negative_outcome() -> None:
404404
LocalPolicy.of(["robot.move"]),
405405
)
406406
assert result == _ActionEvidenceResult("valid_negative_outcome", "CONTROLLER_REJECTED")
407+
408+
409+
def test_action_008_invalid_delegation_signature_is_provenance_invalid() -> None:
410+
chain = _action_chain()
411+
records = _records(chain)
412+
leaf = chain[-1]
413+
tampered_signature = f"{int(leaf.signature[:2], 16) ^ 1:02x}{leaf.signature[2:]}"
414+
bad_chain = [*chain[:-1], replace(leaf, signature=tampered_signature)]
415+
evidence = _action_evidence(
416+
records,
417+
requested_capability="robot.inspect",
418+
controller_decision="rejected",
419+
)
420+
restrictive_policy = LocalPolicy.of(["robot.move"])
421+
permissive_policy = LocalPolicy.of(["robot.move", "robot.inspect"])
422+
423+
# The controls establish both downstream classifications that invalid provenance must preempt.
424+
assert _verify_action_evidence(chain, records, evidence, restrictive_policy) == (
425+
_ActionEvidenceResult("authorization_invalid", "SCOPE_NOT_PERMITTED")
426+
)
427+
assert _verify_action_evidence(chain, records, evidence, permissive_policy) == (
428+
_ActionEvidenceResult("valid_negative_outcome", "CONTROLLER_REJECTED")
429+
)
430+
431+
# ACTION-008 verifies provenance validation precedes authorization and controller outcome classification.
432+
assert _verify_action_evidence(bad_chain, records, evidence, restrictive_policy) == (
433+
_ActionEvidenceResult("provenance_invalid", "INVALID_CREDENTIAL")
434+
)
435+
assert _verify_action_evidence(bad_chain, records, evidence, permissive_policy) == (
436+
_ActionEvidenceResult("provenance_invalid", "INVALID_CREDENTIAL")
437+
)

0 commit comments

Comments
 (0)