# Evolution 7 — JIT authorization protocol review (cain42.talos.v3)

Code: `cain/talos/cain_talos_protocol.py`, `cain_jit_engine.py`, `talos_kernel.py`. Schema:
`schemas/cain-talos-envelope.schema.json`. A document that validates against the schema is well-formed and
nothing more.

## Versions

v1 signed action and target but not what was executed. v2 was a version string. Both are **withdrawn**: a v1 or
v2 envelope, even validly signed, is refused with `UNSUPPORTED_PROTOCOL_VERSION` (E7-A-005). There is no
compatibility mode because none would be safe and none is needed: no envelope was ever issued outside tests.

## Envelope

Signed fields (all of them; E7-P-002 mutates each one): `envelope_id decision_id request_id protocol_version
schema_version issuer audience principal_did tenant_id agent_id session_id action target resource_scope
parameters_digest context_digest policy_version policy_digest enforcement_profile decision reason_code iat exp
nonce kid signature_algorithm approval_reference constraints`.

Signing input: `"CAIN42/TALOS-AUTHORIZATION-ENVELOPE/v3\n" + canonical(fields)`. Algorithm: Ed25519 from the
`cryptography` package, the only one allowed. Not post-quantum.

Canonical form: JSON, sorted keys, no whitespace, ASCII-escaped. This is **not** RFC 8785. The difference is
unreachable because signed values are restricted to ASCII strings, bounded integers, booleans, null and
containers of those; floats are rejected by the parser.

## What is bound, where it is checked

| Binding | Issued by | Checked by TALOS against |
|---|---|---|
| issuer, kid, algorithm | CAIN | TALOS trust root (kid -> key, issuer, validity window) |
| audience | CAIN | the kernel's own configured name |
| principal, tenant, agent, session | CAIN | values supplied by the enforcement adapter |
| action, target | CAIN | values supplied by the enforcement adapter |
| parameters_digest | CAIN, from the `ExecutionRequest` | recomputed from the request about to run |
| resource_scope | CAIN, attenuated to the rule ceiling | the request's cwd and file path; then enforced by the kernel sandbox |
| policy_version, policy_digest | CAIN | values pinned in the kernel configuration, when configured |
| enforcement_profile | CAIN | profiles this kernel supports |
| iat, exp | CAIN | kernel clock: lifetime <= 300 s, skew <= 5 s, strict expiry |
| nonce, decision_id | CAIN | ledger, single use |
| human approval | approver key, separately | TALOS approver trust roots; signature covers envelope id, nonce, digest, action, target, principal, tenant |

`ExecutionRequest` = mode, argv, code, path, content, cwd, env. Loader and resolver variables (`LD_*`,
`PYTHON*`, `PATH`, `IFS`, `BASH_ENV`, ...) are refused in `env` even if signed (E7-E-013).

## Time, keys, revocation

* No usable clock -> `INDETERMINATE`. Expired -> `EXPIRED`. `exp <= iat` or absurd stamps -> `MALFORMED`.
* Clock rollback: the ledger stores the highest time it has seen; consumption more than the tolerance behind it
  is refused (E7-A-044).
* Rotation: a trust root has `not_before` / `not_after` on the issue time. Duplicate kids are a configuration error.
* Revocation: key and decision, in the ledger, read before consumption and again inside the transaction.
* Emergency: `raise_invalidation_floor()` voids everything that could have been issued before a moment.

## Reason codes

Verdicts are a closed enum; reason codes are fixed upper-case tokens with no field values, paths or exception
text (E7-A-080). Any exception in the verifier is `INDETERMINATE / VERIFIER_INTERNAL_ERROR`.

## Threat analysis — what the protocol does not give

* **Confidentiality.** Envelopes are signed, not encrypted.
* **Protection after key theft.** A stolen issuer key mints valid envelopes until it is revoked.
* **Proof the caller authenticated the principal.** TALOS compares the envelope with the identity the adapter
  passes; it does not authenticate the end user.
* **Executable identity.** `argv[0]` is resolved through a fixed PATH inside the sandbox at exec time.
* **Policy pinning by default.** If the deployer configures neither policy version nor digest, they are not checked.
* **Sender-constrained envelopes.** Possession of an unconsumed envelope plus the matching context is enough;
  there is no proof-of-possession by the agent.
* **Interoperability with other implementations.** Positive and negative vectors exist only as this suite.
