Strategic work for IETF submission of draft-nennemann-act-01 and
draft-nennemann-wimse-ect-02:
Package restructure:
- move ACT and ECT refimpls to workspace/packages/{act,ect}/
- ietf-act and ietf-ect distribution names (sibling packages)
- cross-spec interop test plan (INTEROP-TEST-PLAN.md)
ACT draft -01 revisions:
- rename 'par' claim to 'pred' (align with ECT)
- rename 'Agent Compact Token' to 'Agent Context Token' (semantic
alignment with ECT family)
- add Applicability section (MCP, OpenAI, LangGraph, A2A, CrewAI)
- add DAG vs Linear Delegation Chains section (differentiator vs
txn-tokens-for-agents actchain, Agentic JWT, AIP/IBCTs)
- add Related Work: AIP, SentinelAgent, Agentic JWT, txn-tokens-for-agents,
HDP, SCITT-AI-agent-execution
- pin SCITT arch to -22, note AUTH48 status
Outreach drafts:
- Emirdag liaison email (SCITT-AI coordination)
- OAuth ML response on txn-tokens-for-agents-06
Strategy document:
- STRATEGY.md with phased action plan, risk register, timeline
Submodule:
- update workspace/drafts/ietf-wimse-ect pointer to -02 commit
95 lines
3.5 KiB
Python
95 lines
3.5 KiB
Python
"""Additional tests for create module."""
|
|
|
|
import time
|
|
|
|
import pytest
|
|
|
|
from ect import Payload, create, generate_key, CreateOptions, default_create_options
|
|
|
|
|
|
def test_default_create_options():
|
|
opts = default_create_options()
|
|
assert opts.key_id == ""
|
|
|
|
|
|
def test_create_errors():
|
|
key = generate_key()
|
|
p = Payload(iss="i", aud=["a"], iat=1, exp=2, jti="j", exec_act="e", pred=[])
|
|
with pytest.raises(ValueError, match="KeyID|required"):
|
|
create(p, key, CreateOptions(key_id=""))
|
|
with pytest.raises((ValueError, TypeError, AttributeError)):
|
|
create(None, key, CreateOptions(key_id="k"))
|
|
|
|
|
|
def test_create_optional_pol():
|
|
key = generate_key()
|
|
now = int(time.time())
|
|
p = Payload(
|
|
iss="iss", aud=["a"], iat=now, exp=now + 3600,
|
|
jti="jti-nopol", exec_act="act", pred=[],
|
|
)
|
|
compact = create(p, key, CreateOptions(key_id="kid"))
|
|
assert compact
|
|
|
|
|
|
def test_create_validation_errors():
|
|
key = generate_key()
|
|
base = dict(iss="i", aud=["a"], iat=1, exp=2, jti="j", exec_act="e", pred=[])
|
|
with pytest.raises(ValueError, match="iss"):
|
|
create(Payload(**{**base, "iss": ""}), key, CreateOptions(key_id="k"))
|
|
with pytest.raises(ValueError, match="aud"):
|
|
create(Payload(**{**base, "aud": []}), key, CreateOptions(key_id="k"))
|
|
with pytest.raises(ValueError, match="jti"):
|
|
create(Payload(**{**base, "jti": ""}), key, CreateOptions(key_id="k"))
|
|
with pytest.raises(ValueError, match="exec_act"):
|
|
create(Payload(**{**base, "exec_act": ""}), key, CreateOptions(key_id="k"))
|
|
|
|
|
|
def test_create_ext_compensation_reason_requires_required():
|
|
key = generate_key()
|
|
p = Payload(
|
|
iss="i", aud=["a"], iat=1, exp=2, jti="j", exec_act="e", pred=[],
|
|
ext={"compensation_reason": "rollback", "compensation_required": False},
|
|
)
|
|
with pytest.raises(ValueError, match="compensation_required"):
|
|
create(p, key, CreateOptions(key_id="k"))
|
|
|
|
|
|
def test_create_zero_expiry_uses_default():
|
|
key = generate_key()
|
|
p = Payload(iss="i", aud=["a"], iat=0, exp=0, jti="j", exec_act="e", pred=[])
|
|
compact = create(p, key, CreateOptions(key_id="k", default_expiry_sec=300))
|
|
assert compact
|
|
# create() works on a copy; decode the token to verify defaults were applied
|
|
import jwt
|
|
claims = jwt.decode(compact, options={"verify_signature": False})
|
|
assert claims["exp"] > claims["iat"]
|
|
|
|
|
|
def test_create_validate_uuids_rejects_non_uuid_jti():
|
|
key = generate_key()
|
|
now = int(time.time())
|
|
p = Payload(iss="i", aud=["a"], iat=now, exp=now + 3600, jti="not-a-uuid", exec_act="e", pred=[])
|
|
with pytest.raises(ValueError, match="jti must be UUID"):
|
|
create(p, key, CreateOptions(key_id="k", validate_uuids=True))
|
|
|
|
|
|
def test_create_max_pred_length():
|
|
key = generate_key()
|
|
now = int(time.time())
|
|
p = Payload(iss="i", aud=["a"], iat=now, exp=now + 3600, jti="550e8400-e29b-41d4-a716-446655440000", exec_act="e", pred=["p1", "p2"])
|
|
with pytest.raises(ValueError, match="pred exceeds max length"):
|
|
create(p, key, CreateOptions(key_id="k", max_pred_length=1))
|
|
|
|
|
|
def test_create_ext_size_rejected():
|
|
from ect.validate import EXT_MAX_SIZE
|
|
key = generate_key()
|
|
now = int(time.time())
|
|
p = Payload(
|
|
iss="i", aud=["a"], iat=now, exp=now + 3600, jti="550e8400-e29b-41d4-a716-446655440000", exec_act="e", pred=[],
|
|
ext={"x": "y" * (EXT_MAX_SIZE - 5)},
|
|
)
|
|
with pytest.raises(ValueError, match="ext exceeds max size"):
|
|
create(p, key, CreateOptions(key_id="k"))
|