Watch
1
0
Fork
You've already forked RedFlag
0
RedFlag/protocol/README.md
Fimeg f5eb83ca94 feat: pin mutation manifest authority bytes
Introduce a dormant MutationEnvelope beside the current closure token. Server, Agent, and helper now agree on length-prefixed manifest and authorization bytes, with one shared fixture pinning the hash, key identity, and Ed25519 signature.\n\nExecutor-affecting provenance, location, target, backend, and backend payload now have a signed home before any runtime path migrates. Exact duplicates stay visible in the hash; ordering does not. Current APT/DNF and Windows behavior remains untouched.
2026-08-26 16:07:19 -04:00

126 lines
3.4 KiB
Markdown

# Mutation manifest wire contract
This directory owns the language-independent bytes shared by RedFlag Server, Agent, and
helper. The current closure-based capability token remains the only runtime execution path;
the mutation envelope is pinned and tested but not wired to a backend yet.
## Envelope
```text
MutationEnvelope
├── MutationManifest
│ ├── protocol_version
│ ├── operation_id
│ ├── target_id
│ ├── backend
│ ├── operation
│ ├── resolved_actions[]
│ │ ├── kind
│ │ ├── identity
│ │ └── payload exact backend-owned UTF-8 JSON bytes
│ └── evidence[]
│ ├── kind
│ └── digest SHA-256 hex
└── MutationAuthorization
├── protocol_version
├── authorization_id
├── manifest_hash
├── authority_kind
├── authority_id
├── target_id
├── issued_at / not_before / expires_at
├── decision
├── key_id
└── signature
```
The protocol envelope begins at format `1` in its own namespace. It is not a new numbered
generation of `CapabilityToken`; the two named contracts coexist until a backend migrates.
Unknown format values fail closed.
## Canonical records
Every value is encoded as UTF-8 `decimal_byte_length:value`, with no separator between
fields. Each record begins with a length-prefixed domain string.
Manifest field order:
```text
redflag.mutation-manifest
protocol_version
operation_id
target_id
backend
operation
resolved_action_count
sorted(length-prefixed resolved-action records)
evidence_count
sorted(length-prefixed evidence records)
```
Resolved action field order:
```text
redflag.resolved-action
kind
identity
payload
```
Evidence field order:
```text
redflag.evidence
kind
digest
```
Authorization field order:
```text
redflag.mutation-authorization
protocol_version
authorization_id
manifest_hash
authority_kind
authority_id
target_id
issued_at
not_before
expires_at
decision
key_id
```
`manifest_hash` is lowercase hex SHA-256 over the manifest canonical bytes. The Ed25519
signature is over the authorization canonical bytes. The signature itself is not included
in those bytes; every other authorization field, including `key_id`, is.
## Collection semantics
Resolved actions and evidence are unordered multisets. Their canonical records are sorted
bytewise for hashing. Exact duplicates remain present, increment the count, and change the
hash. No implementation may convert either collection to a set.
A backend that needs ordered execution encodes the sequence inside one signed payload. The
common layer never infers package, WUA, Winget, Docker, or self-update semantics from that
payload.
Provenance is evidence. Cache paths, URLs, repository selectors, WUA identities, and other
execution inputs belong in the exact signed backend payload or must be derived
deterministically from it.
## Golden fixture
`testdata/mutation-golden.json` pins:
- manifest canonical bytes and hash;
- authorization canonical bytes;
- authority key ID;
- deterministic Ed25519 signature;
- action/evidence ordering behavior;
- duplicate retention;
- tamper refusal for provenance, execution location, target, backend, resolved action,
authorization metadata, decision, time window, and unknown formats.
Go tests live in both capability packages. Rust tests live in `helper/src/mutation_protocol.rs`.