Move Go reference implementation to refimpl/go-lang/ and add new Python reference implementation in refimpl/python/. Update build.sh with renamed draft and simplified tool paths. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
101 lines
3.0 KiB
Markdown
101 lines
3.0 KiB
Markdown
# WIMSE ECT — Python Reference Implementation
|
|
|
|
Python reference implementation of [Execution Context Tokens (ECTs)](../../draft-nennemann-wimse-execution-context-00.txt) for WIMSE. Implements ECT creation (ES256), verification (Section 7), DAG validation (Section 6), and an in-memory audit ledger (Section 9).
|
|
|
|
## Layout
|
|
|
|
```
|
|
python/
|
|
├── pyproject.toml
|
|
├── ect/ # library
|
|
│ ├── __init__.py
|
|
│ ├── types.py # Payload, constants
|
|
│ ├── create.py # create(), generate_key()
|
|
│ ├── verify.py # parse(), verify(), VerifyOptions
|
|
│ ├── dag.py # validate_dag(), ECTStore, DAGConfig
|
|
│ ├── ledger.py # Ledger, MemoryLedger
|
|
│ ├── config.py # Config, load_config_from_env()
|
|
│ ├── jti_cache.py # JTICache for replay protection
|
|
│ └── validate.py # validate_ext, valid_uuid, validate_hash_format
|
|
├── tests/
|
|
│ ├── test_create.py
|
|
│ └── test_dag.py
|
|
├── testdata/
|
|
│ └── valid_root_ect_payload.json
|
|
└── demo.py # two-agent workflow demo
|
|
```
|
|
|
|
## Install
|
|
|
|
```bash
|
|
cd refimpl/python && pip install -e .
|
|
```
|
|
|
|
## Usage
|
|
|
|
```python
|
|
from ect import (
|
|
Payload,
|
|
create,
|
|
generate_key,
|
|
CreateOptions,
|
|
verify,
|
|
VerifyOptions,
|
|
MemoryLedger,
|
|
POL_DECISION_APPROVED,
|
|
)
|
|
|
|
cfg = load_config_from_env()
|
|
key = generate_key()
|
|
payload = Payload(
|
|
iss="spiffe://example.com/agent/a",
|
|
aud=["spiffe://example.com/agent/b"],
|
|
iat=int(time.time()),
|
|
exp=int(time.time()) + 600,
|
|
jti="550e8400-e29b-41d4-a716-446655440000",
|
|
exec_act="review_spec",
|
|
par=[],
|
|
pol="policy_v1",
|
|
pol_decision=POL_DECISION_APPROVED,
|
|
)
|
|
compact = create(payload, key, cfg.create_options("agent-a-key"))
|
|
|
|
store = MemoryLedger()
|
|
opts = cfg.verify_options()
|
|
opts.verifier_id = "spiffe://example.com/agent/b"
|
|
opts.resolve_key = lambda kid: key.public_key() if kid == "agent-a-key" else None
|
|
opts.store = store
|
|
parsed = verify(compact, opts)
|
|
store.append(compact, parsed.payload)
|
|
```
|
|
|
|
## Demo
|
|
|
|
```bash
|
|
cd refimpl/python && python3 demo.py
|
|
```
|
|
|
|
## Tests
|
|
|
|
```bash
|
|
cd refimpl/python && python3 -m pytest tests/ -v
|
|
```
|
|
|
|
Unit tests require **90% coverage** minimum (`pytest` is configured with `--cov-fail-under=90` in `pyproject.toml`). Install dev deps: `pip install -e ".[dev]"`. Uncovered lines are mainly abstract base methods and a few verify branches that need manually built tokens.
|
|
|
|
## Production configuration (environment)
|
|
|
|
Same env vars as the Go refimpl: `ECT_IAT_MAX_AGE_MINUTES`, `ECT_IAT_MAX_FUTURE_SEC`, `ECT_DEFAULT_EXPIRY_MIN`, `ECT_JTI_REPLAY_CACHE_SIZE`, `ECT_JTI_REPLAY_TTL_MIN`.
|
|
|
|
### Replay cache (multi-instance)
|
|
|
|
The provided JTI cache is in-memory only. For multiple verifier instances, use a shared store (Redis, DB) and pass a `jti_seen` callable that checks/records JTIs there. See refimpl/README for an overview.
|
|
|
|
## Dependencies
|
|
|
|
- PyJWT, cryptography (ES256).
|
|
|
|
## License
|
|
|
|
Same as the Internet-Draft (IETF Trust). Code under Revised BSD per BCP 78/79.
|