Watch
1
0
Fork
You've already forked RedFlag
0

RAF: convert [[wiki-links]] to standard markdown for GitHub rendering

This commit is contained in:
Fimeg 2026-06-11 11:47:44 -04:00
commit 47fe315e8f
15 changed files with 126 additions and 126 deletions

View file

@ -29,11 +29,11 @@ Packages move through a server-owned state machine (`pending` through `installed
lifecycle orchestrator drives auto-advance and recovers stuck states.
**Architecture docs:**
- [[core/01-ethos]] — the five principles
- [[core/02-architecture-decisions]] — the twelve foundational choices
- [[security/02-authentication-stack]] — four-layer auth (reg tokens, JWT, refresh, machine binding)
- [[security/01-trust-boundaries]] — endpoint classification and middleware matrix
- [[flows/06-update-lifecycle]] — state machine, two execution paths, orchestrator
- [core/01-ethos](core/01-ethos.md) — the five principles
- [core/02-architecture-decisions](core/02-architecture-decisions.md) — the twelve foundational choices
- [security/02-authentication-stack](security/02-authentication-stack.md) — four-layer auth (reg tokens, JWT, refresh, machine binding)
- [security/01-trust-boundaries](security/01-trust-boundaries.md) — endpoint classification and middleware matrix
- [flows/06-update-lifecycle](flows/06-update-lifecycle.md) — state machine, two execution paths, orchestrator
### Tier 2: Supply Chain Gate
@ -52,7 +52,7 @@ Auto-confirm shares the same `ClosureCleared` predicate as manual approval — t
paths cannot drift on what counts as a clean closure.
**Architecture docs:**
- [[security/05-supply-chain-gate]] — the design of record: capability model, wire contract,
- [security/05-supply-chain-gate](security/05-supply-chain-gate.md) — the design of record: capability model, wire contract,
load-bearing constraints, enforcement layers, trust chain, hash registry
- `docs/tasks/GATE-000-supply-chain-gate-plan.md` — build status & implementation tracking (not design)
@ -68,8 +68,8 @@ Process Explorer) and delivered to agents on check-in. Listening ports use socke
inode correlation against `/proc/net/tcp` — not system-wide assignment.
**Architecture docs:**
- [[scanners/05-process-scanner]] — data model, collection, caps
- [[flows/07-process-scan]] — command-dispatch flow, API endpoints, schema
- [scanners/05-process-scanner](scanners/05-process-scanner.md) — data model, collection, caps
- [flows/07-process-scan](flows/07-process-scan.md) — command-dispatch flow, API endpoints, schema
---
@ -115,19 +115,19 @@ From `security/05-supply-chain-gate.md` — do not regress these:
| Section | What It Describes |
|---------|-------------------|
| [[core]] | ETHOS principles, architectural decisions |
| [[components]] | Server, agent, web, helper — package structure and responsibilities |
| [[security]] | Trust boundaries, auth stack, machine binding, supply chain gate |
| [[verification]] | Ed25519 signing pipeline, agent verification, key rotation, replay protection |
| [[scanners]] | Per-ecosystem scanner behavior and integration points (incl. process scanner) |
| [[flows]] | Data flows — registration, command execution, upgrade, heartbeat, capability advertisement, update lifecycle |
| [[reference]] | File mappings, glossary |
| [core](core/) | ETHOS principles, architectural decisions |
| [components](components/) | Server, agent, web, helper — package structure and responsibilities |
| [security](security/) | Trust boundaries, auth stack, machine binding, supply chain gate |
| [verification](verification/) | Ed25519 signing pipeline, agent verification, key rotation, replay protection |
| [scanners](scanners/) | Per-ecosystem scanner behavior and integration points (incl. process scanner) |
| [flows](flows/) | Data flows — registration, command execution, upgrade, heartbeat, capability advertisement, update lifecycle |
| [reference](reference/) | File mappings, glossary |
---
## Honest Gaps
- **Gate policy visibility**: the soak and age gates are live policies as of v0.2.6.2 (`supply_chain.*` settings — see [[security/05-supply-chain-gate]] §4), but the dashboard doesn't yet surface their configuration; operators tune them blind. The live install-through-helper path completed e2e on 2026-06-05
- **Gate policy visibility**: the soak and age gates are live policies as of v0.2.6.2 (`supply_chain.*` settings — see [security/05-supply-chain-gate](security/05-supply-chain-gate.md) §4), but the dashboard doesn't yet surface their configuration; operators tune them blind. The live install-through-helper path completed e2e on 2026-06-05
- **Closure transitivity split by platform**: dnf/apt resolve via dry-run (full closure); npm/pypi still single-entry
- **Signer in-process**: key encapsulated in SigningService, minter is the only caller — but true process isolation not built
- **Legacy ecosystems ungated**: docker, winget, windows_update still direct-mutation

View file

@ -4,7 +4,7 @@
This is the design of record, published in the open. Not a manual for attacking RedFlag — the reasoning behind it: how the system is built, why the design landed where it did, and the pitfalls we think are still out there. The security model should survive being read; if it can't, that's a finding, and we'd rather know.
It describes a system under active development. Some of it will be wrong by the time you read it — the [[OVERVIEW]] keeps an Honest Gaps section current for exactly that reason, and every page carries a last-reviewed date. Trust the code over the doc when they disagree, and tell us.
It describes a system under active development. Some of it will be wrong by the time you read it — the [OVERVIEW](OVERVIEW.md) keeps an Honest Gaps section current for exactly that reason, and every page carries a last-reviewed date. Trust the code over the doc when they disagree, and tell us.
---
@ -12,26 +12,26 @@ It describes a system under active development. Some of it will be wrong by the
| Section | Description |
|---------|-------------|
| [[OVERVIEW]] | **START HERE** — architecture overview: what RedFlag is, the two capability tiers, architectural boundaries, honest gaps |
| [[core]] | ETHOS principles, the foundational architectural decisions |
| [[components]] | Server, agent, web, helper — component breakdowns |
| [[security]] | Trust boundaries, auth stack, refresh-token lifecycle, machine binding, supply chain gate, standalone authority |
| [[verification]] | Ed25519 signing pipeline, agent verification, key rotation, replay protection |
| [[scanners]] | Every scanner (APT, DNF, Winget, WUA, Docker, process explorer) with interaction analysis |
| [[flows]] | Data flows — registration, command execution, upgrade, heartbeat, capability advertisement, update lifecycle |
| [[deployment]] | Docker stack, native agent services, CI/CD, release gate, operations runbook pointers |
| [[testing]] | Test pyramid, structural tests, live testing, honest gaps |
| [[reference]] | File mappings, [[reference/02-glossary|glossary]] |
| [OVERVIEW](OVERVIEW.md) | **START HERE** — architecture overview: what RedFlag is, the two capability tiers, architectural boundaries, honest gaps |
| [core](core/) | ETHOS principles, the foundational architectural decisions |
| [components](components/) | Server, agent, web, helper — component breakdowns |
| [security](security/) | Trust boundaries, auth stack, refresh-token lifecycle, machine binding, supply chain gate, standalone authority |
| [verification](verification/) | Ed25519 signing pipeline, agent verification, key rotation, replay protection |
| [scanners](scanners/) | Every scanner (APT, DNF, Winget, WUA, Docker, process explorer) with interaction analysis |
| [flows](flows/) | Data flows — registration, command execution, upgrade, heartbeat, capability advertisement, update lifecycle |
| [deployment](deployment/) | Docker stack, native agent services, CI/CD, release gate, operations runbook pointers |
| [testing](testing/) | Test pyramid, structural tests, live testing, honest gaps |
| [reference](reference/) | File mappings, [glossary](reference/02-glossary.md) |
---
## Reading Order
1. **[[OVERVIEW]]** — the shape of the system and where its protection boundary currently ends
2. **[[core]]** — ETHOS principles and the decisions everything else hangs off
3. **[[flows]]** — trace the critical data flows end-to-end
4. **[[security]] + [[verification]]** — the trust model and the cryptographic pipeline
5. **[[scanners]] + [[components]]** — per-ecosystem behavior and package structure
1. **[OVERVIEW](OVERVIEW.md)** — the shape of the system and where its protection boundary currently ends
2. **[core](core/)** — ETHOS principles and the decisions everything else hangs off
3. **[flows](flows/)** — trace the critical data flows end-to-end
4. **[security](security/) + [verification](verification/)** — the trust model and the cryptographic pipeline
5. **[scanners](scanners/) + [components](components/)** — per-ecosystem behavior and package structure
---
@ -41,8 +41,8 @@ RedFlag is free and will never be monetized. If community adoption takes off, ow
Before proposing architectural changes:
1. Read [[core]] → [[flows]] → [[verification]] for context — most "why is it like this" questions are answered there
2. The five ETHOS principles and the six load-bearing constraints ([[OVERVIEW]]) are the floor, not a starting position
1. Read [core](core/) → [flows](flows/) → [verification](verification/) for context — most "why is it like this" questions are answered there
2. The five ETHOS principles and the six load-bearing constraints ([OVERVIEW](OVERVIEW.md)) are the floor, not a starting position
3. Update the relevant page *and its cross-references*; stale links are bugs
A note on `docs/tasks/` references: several pages point at the maintainer's task tracker

View file

@ -53,8 +53,8 @@ server/
| Admin | `admin-only` | `WebAuthMiddleware + AdminRoleMiddleware` | `/api/v1/admin/*` |
**Cross-references:**
- [[security/01-trust-boundaries]] (full trust boundary matrix)
- [[security/02-authentication-stack]] (auth layers)
- [security/01-trust-boundaries](security/01-trust-boundaries.md) (full trust boundary matrix)
- [security/02-authentication-stack](security/02-authentication-stack.md) (auth layers)
---
@ -71,8 +71,8 @@ server/
- 055: process explorer tables (`agent_process_snapshots`, `agent_processes`, `agent_process_related`)
**Cross-references:**
- [[deployment/01-docker-stack]] (database configuration)
- [[testing/01-test-pyramid]] (migration test coverage)
- [deployment/01-docker-stack](deployment/01-docker-stack.md) (database configuration)
- [testing/01-test-pyramid](testing/01-test-pyramid.md) (migration test coverage)
---
@ -98,8 +98,8 @@ func SignCommand(cmd *Command, privateKey *ed25519.PrivateKey) (*Signature, erro
```
**Cross-references:**
- [[verification/01-signing-pipeline]] (signing service)
- [[verification/02-agent-verification]] (verification flow)
- [verification/01-signing-pipeline](verification/01-signing-pipeline.md) (signing service)
- [verification/02-agent-verification](verification/02-agent-verification.md) (verification flow)
---
@ -130,8 +130,8 @@ func DownloadAgent(w http.ResponseWriter, r *http.Request) {
```
**Cross-references:**
- [[flows/03-agent-upgrade]] (agent download flow)
- [[security/04-machine-binding]] (download authentication)
- [flows/03-agent-upgrade](flows/03-agent-upgrade.md) (agent download flow)
- [security/04-machine-binding](security/04-machine-binding.md) (download authentication)
**Known issues:**
- BUG-003: `version="latest"` doesn't match any signed package → signature header not set
@ -151,9 +151,9 @@ func DownloadAgent(w http.ResponseWriter, r *http.Request) {
- Checks maintenance windows before creating install commands
**Cross-references:**
- [[flows/05-capability-advertisement]] (capability advertisement integration)
- [[components/02-agent]] (agent polling loop)
- [[core/02-architecture-decisions]] §12 (scheduler job eviction)
- [flows/05-capability-advertisement](flows/05-capability-advertisement.md) (capability advertisement integration)
- [components/02-agent](components/02-agent.md) (agent polling loop)
- [core/02-architecture-decisions](core/02-architecture-decisions.md) §12 (scheduler job eviction)
---
@ -175,11 +175,11 @@ func DownloadAgent(w http.ResponseWriter, r *http.Request) {
## Cross-References
- **HTTP API** → [[security/01-trust-boundaries]]
- **Database** → [[deployment/01-docker-stack]]
- **Command signing** → [[verification/01-signing-pipeline]]
- **Binary distribution** → [[flows/03-agent-upgrade]]
- **Scheduler** → [[flows/05-capability-advertisement]]
- **HTTP API** → [security/01-trust-boundaries](security/01-trust-boundaries.md)
- **Database** → [deployment/01-docker-stack](deployment/01-docker-stack.md)
- **Command signing** → [verification/01-signing-pipeline](verification/01-signing-pipeline.md)
- **Binary distribution** → [flows/03-agent-upgrade](flows/03-agent-upgrade.md)
- **Scheduler** → [flows/05-capability-advertisement](flows/05-capability-advertisement.md)
---

View file

@ -6,7 +6,7 @@
## Doctrine
The agent does not track lifecycle states, make policy decisions, or hold install privileges on gated ecosystems. The server owns every state transition. The agent's only autonomous decisions are: verify this signature, check this nonce, reject this replay. See [[core/02-architecture-decisions]].
The agent does not track lifecycle states, make policy decisions, or hold install privileges on gated ecosystems. The server owns every state transition. The agent's only autonomous decisions are: verify this signature, check this nonce, reject this replay. See [core/02-architecture-decisions](core/02-architecture-decisions.md).
---
@ -73,9 +73,9 @@ agent/
Discovery (scan, dry-run, hash-resolve) always runs unprivileged through `DiscoveryRunner`. Sudoers grants only discovery commands plus the single helper invocation line — zero sudo otherwise.
**Cross-references:**
- [[security/05-supply-chain-gate]] (token contract)
- [[flows/02-command-execution]] (command path)
- [[flows/07-process-scan]] (process explorer flow)
- [security/05-supply-chain-gate](security/05-supply-chain-gate.md) (token contract)
- [flows/02-command-execution](flows/02-command-execution.md) (command path)
- [flows/07-process-scan](flows/07-process-scan.md) (process explorer flow)
---
@ -87,14 +87,14 @@ Discovery (scan, dry-run, hash-resolve) always runs unprivileged through `Discov
- Signing-required is doctrine, not config. There is no skip path.
**Cross-references:**
- [[verification/02-agent-verification]] (full pipeline)
- [[verification/04-replay-protection]]
- [verification/02-agent-verification](verification/02-agent-verification.md) (full pipeline)
- [verification/04-replay-protection](verification/04-replay-protection.md)
---
## Resilience Machinery
- **Instance lock**`Global\RedFlagAgent_v1` mutex / flock; prevents two agents racing one `config.json` and burning refresh-token rotations ([[security/03-refresh-tokens]])
- **Instance lock**`Global\RedFlagAgent_v1` mutex / flock; prevents two agents racing one `config.json` and burning refresh-token rotations ([security/03-refresh-tokens](security/03-refresh-tokens.md))
- **Circuit breakers** — fragile scanners (notably WUA) trip open instead of hammering; health reported to server
- **TeeLogger** — every loop event goes to both structured local log and server-bound buffer; tracker save failures tee inward (ETHOS #1)
- **At-least-once acks**`acknowledgment/tracker.go` persists until the server confirms result-recorded

View file

@ -8,7 +8,7 @@
React 18 + TypeScript 5 + Vite + Tailwind 3, react-router 6, react-hot-toast. No state framework beyond a small store (`lib/store.ts`); server is the source of truth, the UI polls.
**Build embedding:** the production bundle is staged into `server/internal/webui/dist` before the server compiles — that directory is gitignored, so a bare `go build` embeds an *empty* UI. The release pipeline stages it; local dev runs Vite separately. See [[deployment/01-docker-stack]].
**Build embedding:** the production bundle is staged into `server/internal/webui/dist` before the server compiles — that directory is gitignored, so a bare `go build` embeds an *empty* UI. The release pipeline stages it; local dev runs Vite separately. See [deployment/01-docker-stack](deployment/01-docker-stack.md).
**Aesthetic:** hand-crafted 90's Novell look. This is deliberate and load-bearing for the project's identity — no modern flat-design rewrites.
@ -45,13 +45,13 @@ web/src/
- **One way to render state.** Status and severity render through `StatusBadge` / `SeverityBadge` — never ad-hoc colored spans. Tables that sort use `SortableTable`.
- **Polling intervals** come from `POLL.*` in `lib/polling.ts` — no hardcoded milliseconds in components.
- **Render the divergence, not the union** (framework §11.8): when agent-reported and server-expected state differ, the UI shows the difference, it does not paper over it.
- All routes sit behind `WebAuthMiddleware` (admin routes additionally behind `AdminRoleMiddleware`) — see [[security/01-trust-boundaries]].
- All routes sit behind `WebAuthMiddleware` (admin routes additionally behind `AdminRoleMiddleware`) — see [security/01-trust-boundaries](security/01-trust-boundaries.md).
---
## Honest Gaps
- No automated web tests ([[testing/01-test-pyramid]])
- No automated web tests ([testing/01-test-pyramid](testing/01-test-pyramid.md))
- Mobile layout usable, not optimized
- Several UI coverage gaps tracked as `UI-*` tasks (not architecture — task tier)

View file

@ -8,13 +8,13 @@
The helper (`helper/src/main.rs`, a single ~2,000-line binary) is the only thing on a gated host allowed to mutate packages, and it earns that privilege by being structurally incapable of being talked into anything. It has no network stack in play, reads its trust inputs from root-owned pinned files, and performs exactly one operation per invocation — the one described by a validly signed capability token. Everything else is a typed denial.
Deny-by-default is the architecture, not a configuration: every failure path returns a `Denial` with a distinct exit code and a `log_security` entry. There is no flag that weakens verification. See [[security/05-supply-chain-gate]] for the token contract this enforces.
Deny-by-default is the architecture, not a configuration: every failure path returns a `Denial` with a distinct exit code and a `log_security` entry. There is no flag that weakens verification. See [security/05-supply-chain-gate](security/05-supply-chain-gate.md) for the token contract this enforces.
---
## Invocation
The agent invokes it via `sudo systemd-run --pipe --property=ProtectSystem=no` — a transient unit with full filesystem access, separate from the agent's own locked-down unit. The token arrives on stdin (or a file path for self-update flows). The agent holds zero install sudo; the sudoers file grants discovery commands plus this one invocation line. See [[components/02-agent]].
The agent invokes it via `sudo systemd-run --pipe --property=ProtectSystem=no` — a transient unit with full filesystem access, separate from the agent's own locked-down unit. The token arrives on stdin (or a file path for self-update flows). The agent holds zero install sudo; the sudoers file grants discovery commands plus this one invocation line. See [components/02-agent](components/02-agent.md).
---
@ -24,7 +24,7 @@ The agent invokes it via `sudo systemd-run --pipe --property=ProtectSystem=no`
1. **Trust-input self-validation (SEC-021)**`validate_trusted_path`: every file the helper relies on (keyring dir, agent-id file, state) must be root-owned, not a symlink, and not group/other-writable. The helper defends its own inputs instead of trusting that the installer set permissions correctly.
2. **Keyring load** — pinned Ed25519 public keys from `/etc/redflag/trusted-keys`. Verify keys, not servers (load-bearing constraint #4).
3. **Closure hash**`closure_hash()` recomputes the canonical hash over the token's resolved closure. This must be **byte-identical** to the Go implementation; cross-language tests pin the contract ([[testing/01-test-pyramid]]).
3. **Closure hash**`closure_hash()` recomputes the canonical hash over the token's resolved closure. This must be **byte-identical** to the Go implementation; cross-language tests pin the contract ([testing/01-test-pyramid](testing/01-test-pyramid.md)).
4. **Signature**`verify_signature()` checks the token's Ed25519 signature over the signed message (which embeds the closure hash) against the keyring, by `key_id`.
5. **Artifact hashes**`verify_artifacts()` SHA-256s every artifact the token authorizes. A mismatch anywhere is a denial.
6. **Replay check**`replay_check_and_record()`: token IDs are recorded in local state; a token executes once.
@ -35,13 +35,13 @@ The agent invokes it via `sudo systemd-run --pipe --property=ProtectSystem=no`
## Binary Self-Update Path
Agent, helper, and desktop binaries update through the same gate as packages: `stage_and_verify_binary` (hash check before anything moves) → `atomic_replace_binary` (rename, never write-in-place; failed swap leaves `<binary>.bak`). During agent upgrades, `reconcile_agent_unit_dropin()` heals fleet systemd units to the current template — this is how pre-`AmbientCapabilities` units get fixed without manual fleet surgery ([[deployment/01-docker-stack]]).
Agent, helper, and desktop binaries update through the same gate as packages: `stage_and_verify_binary` (hash check before anything moves) → `atomic_replace_binary` (rename, never write-in-place; failed swap leaves `<binary>.bak`). During agent upgrades, `reconcile_agent_unit_dropin()` heals fleet systemd units to the current template — this is how pre-`AmbientCapabilities` units get fixed without manual fleet surgery ([deployment/01-docker-stack](deployment/01-docker-stack.md)).
---
## Standalone Mint Mode
The helper also carries a local-authority minting path (`MintRequest` / `MintedToken` / `load_mint_key`) for deployments where the signing authority runs beside the host rather than on a central server. Design of record: [[security/06-standalone-authority]].
The helper also carries a local-authority minting path (`MintRequest` / `MintedToken` / `load_mint_key`) for deployments where the signing authority runs beside the host rather than on a central server. Design of record: [security/06-standalone-authority](security/06-standalone-authority.md).
---

View file

@ -253,7 +253,7 @@ func (c *CommandHandler) handleCommand(cmd *Command) {
- No recurring costs — $0/agent/month vs ConnectWise's $50/agent/month.
**Trade-offs:**
- No built-in monitoring/alerting (requires external tools)
- No built-in monitoring/alerting infrastructure (no retry queues, no delivery guarantees, no SMTP relay pool). RedFlag pushes events to external tools the operator owns — Wazuh, ntfy, SMTP — via one-shot emitters on the server. This is the precedent set by `flows/08-wazuh-event-emitter.md` and extended by `docs/tasks/NOTIFY-001-notification-system.md`. The dashboard remains the source of truth; external notifications are a courtesy tap on the shoulder.
- No multi-tenant support (single-tenant by design)
- Requires operational overhead (updates, backups, maintenance)

View file

@ -112,7 +112,7 @@ RedFlag event types → Wazuh custom rule IDs (999xxx user range):
## Cross-references
- **Trust boundaries** → [[../security/01-trust-boundaries]] — pull-only
- **Trust boundaries** → [../security/01-trust-boundaries](../security/01-trust-boundaries.md) — pull-only
doctrine section; this emitter is explicitly distinguished from the agent
control channel.
- **Task spec**`docs/tasks/INTEG-001-wazuh-event-emitter.md`

View file

@ -6,26 +6,26 @@
| Term | Meaning |
|------|---------|
| **Agent** | Stateless Go executor on each managed host. Polls, verifies, executes, reports. Never decides. [[components/02-agent]] |
| **Capability token** | Ed25519-signed grant describing exactly one operation over a resolved closure, with every artifact hash pinned. Minted at approval, executed once. [[security/05-supply-chain-gate]] |
| **Agent** | Stateless Go executor on each managed host. Polls, verifies, executes, reports. Never decides. [components/02-agent](components/02-agent.md) |
| **Capability token** | Ed25519-signed grant describing exactly one operation over a resolved closure, with every artifact hash pinned. Minted at approval, executed once. [security/05-supply-chain-gate](security/05-supply-chain-gate.md) |
| **Closure (dependency closure)** | The full set of artifacts an operation will touch — the named package *and* every transitive dependency resolved at dry-run time. |
| **Closure hash** | Canonical hash over the closure, embedded in the token's signed message. Computed byte-identically in Go (server) and Rust (helper) — the cross-language contract. |
| **Discovery vs. mutation** | Discovery (scan, dry-run, hash-resolve) runs unprivileged through `DiscoveryRunner`. Mutation happens only through the helper on gated ecosystems. The agent cannot install. |
| **Doctrine / doctrinal** | A guarantee with no configuration knob: signing-required, forward-only versioning, no verification skip path. If it's doctrine, there is nothing to misconfigure. [[core/01-ethos]] |
| **Doctrine / doctrinal** | A guarantee with no configuration knob: signing-required, forward-only versioning, no verification skip path. If it's doctrine, there is nothing to misconfigure. [core/01-ethos](core/01-ethos.md) |
| **Drift detection** | Knowing what *should* be installed vs. what *is*, and bridging the gap into update packages. |
| **ETHOS** | The five principles every change is held to: errors are history, no unauthenticated endpoints, assume failure, idempotency, no marketing fluff in logs. [[core/01-ethos]] |
| **ETHOS** | The five principles every change is held to: errors are history, no unauthenticated endpoints, assume failure, idempotency, no marketing fluff in logs. [core/01-ethos](core/01-ethos.md) |
| **Fail-closed** | When verification can't succeed, the operation doesn't happen. A registered hash that can't be checked blocks; an unknown vulnerability state blocks under `block` enforcement. The opposite of "warn and continue." |
| **Family revocation** | Refresh tokens form a lineage (`family_id`); replaying a stale token burns the entire family loudly. Theft is detected, not coexisted with. [[security/03-refresh-tokens]] |
| **Family revocation** | Refresh tokens form a lineage (`family_id`); replaying a stale token burns the entire family loudly. Theft is detected, not coexisted with. [security/03-refresh-tokens](security/03-refresh-tokens.md) |
| **Forward-only** | No downgrades. Versions move forward; the release gate enforces it; there is no override. |
| **Helper** | The privileged, network-less Rust executor — the only mutation path on gated ecosystems. [[components/04-helper]] |
| **Legacy command path** | Direct signed-command execution for docker / winget / windows_update — ecosystems the capability gate doesn't cover yet. A documented gap, not a feature. [[OVERVIEW]] |
| **Machine binding** | Hardware fingerprint registered at enrollment and checked on every authenticated request, including token renewal. A stolen `config.json` is inert elsewhere. [[security/04-machine-binding]] |
| **Nonce** | Per-command signed value with a 10-minute window; agents track executed nonces and reject replays. [[verification/04-replay-protection]] |
| **Helper** | The privileged, network-less Rust executor — the only mutation path on gated ecosystems. [components/04-helper](components/04-helper.md) |
| **Legacy command path** | Direct signed-command execution for docker / winget / windows_update — ecosystems the capability gate doesn't cover yet. A documented gap, not a feature. [OVERVIEW](OVERVIEW.md) |
| **Machine binding** | Hardware fingerprint registered at enrollment and checked on every authenticated request, including token renewal. A stolen `config.json` is inert elsewhere. [security/04-machine-binding](security/04-machine-binding.md) |
| **Nonce** | Per-command signed value with a 10-minute window; agents track executed nonces and reject replays. [verification/04-replay-protection](verification/04-replay-protection.md) |
| **OSV** | OSV.dev, the open vulnerability database. Queried in batches across full closures at detection time; verdicts persist and gate approval. |
| **RAF** | This document tree — the RedFlag Architecture Framework, the design of record. What the system is, not what's currently on the task list. |
| **Soak gate / age gate** | Time-based supply-chain policies: minimum package age before approval (Shai-Hulud defense) and a version soak window before install. Policies, not doctrine — configurable, with enforcement modes. [[security/05-supply-chain-gate]] |
| **TOFU** | Trust-on-first-use: the agent caches the server's public key at first connect and verifies everything after against the cached roster, by `key_id`. [[verification/03-key-rotation]] |
| **Two execution paths** | Capability gate (dnf, apt — token + helper) and legacy command (everything else, for now). [[OVERVIEW]] |
| **Soak gate / age gate** | Time-based supply-chain policies: minimum package age before approval (Shai-Hulud defense) and a version soak window before install. Policies, not doctrine — configurable, with enforcement modes. [security/05-supply-chain-gate](security/05-supply-chain-gate.md) |
| **TOFU** | Trust-on-first-use: the agent caches the server's public key at first connect and verifies everything after against the cached roster, by `key_id`. [verification/03-key-rotation](verification/03-key-rotation.md) |
| **Two execution paths** | Capability gate (dnf, apt — token + helper) and legacy command (everything else, for now). [OVERVIEW](OVERVIEW.md) |
---

View file

@ -9,9 +9,9 @@
Every HTTP endpoint must be classified by who is allowed to call it and which middleware enforces that classification.
**Cross-references:**
- [[security/02-authentication-stack]] (auth layers)
- [[security/03-refresh-tokens]] (token lifecycle)
- [[security/04-machine-binding]] (machine ID binding)
- [security/02-authentication-stack](security/02-authentication-stack.md) (auth layers)
- [security/03-refresh-tokens](security/03-refresh-tokens.md) (token lifecycle)
- [security/04-machine-binding](security/04-machine-binding.md) (machine ID binding)
---
@ -75,8 +75,8 @@ Grace is *structural*, not timed: "successor still unconsumed" is the discrimina
Ties to SEC-012 (renewal atomicity): the server side is now fully transactional; the agent↔server two-phase (server commits rotation / agent persists token) is reconciled by the grace path rather than true cross-network atomicity.
**Cross-references:**
- [[flows/01-registration]] (registration flow)
- [[flows/03-agent-upgrade]] (download endpoint)
- [flows/01-registration](flows/01-registration.md) (registration flow)
- [flows/03-agent-upgrade](flows/03-agent-upgrade.md) (download endpoint)
---
@ -94,8 +94,8 @@ Ties to SEC-012 (renewal atomicity): the server side is now fully transactional;
- **Download endpoint** (`GET /api/v1/downloads/updates/:package_id`) requires machine binding to prevent any authenticated agent from downloading any package
**Cross-references:**
- [[security/02-authentication-stack]] (JWT validation)
- [[security/04-machine-binding]] (machine ID validation)
- [security/02-authentication-stack](security/02-authentication-stack.md) (JWT validation)
- [security/04-machine-binding](security/04-machine-binding.md) (machine ID validation)
---
@ -109,7 +109,7 @@ Ties to SEC-012 (renewal atomicity): the server side is now fully transactional;
- Admin-only routes use `AdminRoleMiddleware`
**Cross-references:**
- [[security/02-authentication-stack]] (web JWT)
- [security/02-authentication-stack](security/02-authentication-stack.md) (web JWT)
---
@ -125,7 +125,7 @@ Ties to SEC-012 (renewal atomicity): the server side is now fully transactional;
- Can trigger machine rebind
**Cross-references:**
- [[security/03-refresh-tokens]] (token revocation)
- [security/03-refresh-tokens](security/03-refresh-tokens.md) (token revocation)
---
@ -138,8 +138,8 @@ Ties to SEC-012 (renewal atomicity): the server side is now fully transactional;
**Fix:** Moved endpoint to `admin-only` group with `WebAuthMiddleware + AdminRoleMiddleware`.
**Cross-references:**
- [[core/01-ethos]] (principle #2: Security is Non-Negotiable)
- [[flows/02-command-execution]] (polling loop)
- [core/01-ethos](core/01-ethos.md) (principle #2: Security is Non-Negotiable)
- [flows/02-command-execution](flows/02-command-execution.md) (polling loop)
---
@ -167,11 +167,11 @@ bounded by what agents choose to fetch and verify.
## Cross-References
- **Auth layers** → [[security/02-authentication-stack]]
- **Refresh tokens** → [[security/03-refresh-tokens]]
- **Machine binding** → [[security/04-machine-binding]]
- **Registration** → [[flows/01-registration]]
- **Command execution** → [[flows/02-command-execution]]
- **Auth layers** → [security/02-authentication-stack](security/02-authentication-stack.md)
- **Refresh tokens** → [security/03-refresh-tokens](security/03-refresh-tokens.md)
- **Machine binding** → [security/04-machine-binding](security/04-machine-binding.md)
- **Registration** → [flows/01-registration](flows/01-registration.md)
- **Command execution** → [flows/02-command-execution](flows/02-command-execution.md)
---

View file

@ -42,8 +42,8 @@
```
**Cross-references:**
- [[flows/01-registration]] (registration flow)
- [[security/03-refresh-tokens]] (refresh tokens)
- [flows/01-registration](flows/01-registration.md) (registration flow)
- [security/03-refresh-tokens](security/03-refresh-tokens.md) (refresh tokens)
---
@ -113,8 +113,8 @@ func AuthMiddleware() gin.HandlerFunc {
```
**Cross-references:**
- [[security/01-trust-boundaries]] (trust boundary matrix)
- [[flows/02-command-execution]] (polling loop)
- [security/01-trust-boundaries](security/01-trust-boundaries.md) (trust boundary matrix)
- [flows/02-command-execution](flows/02-command-execution.md) (polling loop)
---
@ -162,8 +162,8 @@ Headers: `X-Machine-ID` (required), `Content-Type: application/json`
The agent must persist `refresh_token` to disk; if it crashes before doing so, accept-previous-once grace recovers on the next attempt.
**Cross-references:**
- [[flows/01-registration]] (registration flow)
- [[flows/02-command-execution]] (renewal in polling loop)
- [flows/01-registration](flows/01-registration.md) (registration flow)
- [flows/02-command-execution](flows/02-command-execution.md) (renewal in polling loop)
---
@ -183,8 +183,8 @@ The agent must persist `refresh_token` to disk; if it crashes before doing so, a
**Middleware:** `server/internal/api/middleware/machine_binding.go`
**Cross-references:**
- [[security/01-trust-boundaries]] (trust boundary matrix)
- [[flows/01-registration]] (machine ID generation)
- [security/01-trust-boundaries](security/01-trust-boundaries.md) (trust boundary matrix)
- [flows/01-registration](flows/01-registration.md) (machine ID generation)
---
@ -192,13 +192,13 @@ The agent must persist `refresh_token` to disk; if it crashes before doing so, a
**Assumption:** Trust On First Use (TOFU) model — agent caches server public key at registration and uses it for all future verification.
**Connection:** [[security/01-trust-boundaries]] (trust boundary matrix)
**Connection:** [security/01-trust-boundaries](security/01-trust-boundaries.md) (trust boundary matrix)
**Connection:** [[security/04-machine-binding]] (hardware-bound auth)
**Connection:** [security/04-machine-binding](security/04-machine-binding.md) (hardware-bound auth)
**Connection:** [[verification/01-signing-pipeline]] (Ed25519 signing)
**Connection:** [verification/01-signing-pipeline](verification/01-signing-pipeline.md) (Ed25519 signing)
**Connection:** [[verification/02-agent-verification]] (command verification)
**Connection:** [verification/02-agent-verification](verification/02-agent-verification.md) (command verification)
---

View file

@ -9,8 +9,8 @@
Agents authenticate with short-lived JWTs minted against a long-lived refresh token (90-day TTL). Every renewal *rotates* the refresh token: a successor is minted, the old token is marked consumed. The rotation lineage is the security mechanism — replaying a consumed token is how theft announces itself.
**Cross-references:**
- [[security/02-authentication-stack]] (where this sits in the four-layer stack)
- [[security/04-machine-binding]] (the renewal endpoint is machine-bound)
- [security/02-authentication-stack](security/02-authentication-stack.md) (where this sits in the four-layer stack)
- [security/04-machine-binding](security/04-machine-binding.md) (the renewal endpoint is machine-bound)
---
@ -42,13 +42,13 @@ Tokens are stored hashed (`HashRefreshToken`), never plaintext. Queries live in
| Consumed, successor **unconsumed** | Crash-recovery grace | Agent saved the old token but died before persisting the new one. Accept once; issue a fresh successor |
| Consumed, successor **also consumed** | Reuse = theft | Revoke the entire `family_id`, log security event, return terminal error |
The grace window is **accept-previous-once** — exactly one step back in the lineage, exactly once. Forward-only is doctrine ([[core/01-ethos]]); there is no knob to widen it.
The grace window is **accept-previous-once** — exactly one step back in the lineage, exactly once. Forward-only is doctrine ([core/01-ethos](core/01-ethos.md)); there is no knob to widen it.
---
## Agent Side
- Terminal sentinel errors (`ErrRefreshTokenInvalid`, `ErrMachineMismatch`) stop the polling loop's retry machinery — these are not transient network failures and are logged `[CRITICAL]`. See [[components/02-agent]].
- Terminal sentinel errors (`ErrRefreshTokenInvalid`, `ErrMachineMismatch`) stop the polling loop's retry machinery — these are not transient network failures and are logged `[CRITICAL]`. See [components/02-agent](components/02-agent.md).
- The **instance lock** exists largely for this mechanism: two agent processes sharing one `config.json` would race rotations and trip family revocation on themselves. One config, one process, enforced by flock/mutex.
---

View file

@ -357,9 +357,9 @@ are defense-in-depth on top, not a prerequisite. Userspace wrappers alone are by
shell, and a stripped environment; the agent that hands it tokens is unprivileged and holds no
signing key.
**Connection:** [[security/01-trust-boundaries]] (kernel enforcement as trust boundary)
**Connection:** [security/01-trust-boundaries](security/01-trust-boundaries.md) (kernel enforcement as trust boundary)
**Connection:** [[security/04-machine-binding]] (agent identity verification)
**Connection:** [security/04-machine-binding](security/04-machine-binding.md) (agent identity verification)
---

View file

@ -9,9 +9,9 @@
All commands and binaries are signed with Ed25519 private key on the server. Agents verify signatures before execution.
**Cross-references:**
- [[verification/02-agent-verification]] (agent-side verification)
- [[verification/03-key-rotation]] (key rotation support)
- [[security/01-trust-boundaries]] (signature as trust boundary)
- [verification/02-agent-verification](verification/02-agent-verification.md) (agent-side verification)
- [verification/03-key-rotation](verification/03-key-rotation.md) (key rotation support)
- [security/01-trust-boundaries](security/01-trust-boundaries.md) (signature as trust boundary)
---
@ -166,11 +166,11 @@ func (s *BuildOrchestratorService) BuildAndSignAgent(version, platform, architec
**Assumption:** Ed25519 signing is enabled when `REDFLAG_SIGNING_PRIVATE_KEY` environment variable is set.
**Connection:** [[verification/02-agent-verification]] (agent-side signature verification)
**Connection:** [verification/02-agent-verification](verification/02-agent-verification.md) (agent-side signature verification)
**Connection:** [[verification/03-key-rotation]] (multi-key rotation support)
**Connection:** [verification/03-key-rotation](verification/03-key-rotation.md) (multi-key rotation support)
**Connection:** [[security/01-trust-boundaries]] (cryptographic trust boundary)
**Connection:** [security/01-trust-boundaries](security/01-trust-boundaries.md) (cryptographic trust boundary)
---

View file

@ -9,9 +9,9 @@
Agent verifies Ed25519 signatures, timestamps, and nonces before executing commands.
**Cross-references:**
- [[verification/01-signing-pipeline]] (server-side signing)
- [[verification/03-key-rotation]] (key rotation)
- [[verification/04-replay-protection]] (replay protection)
- [verification/01-signing-pipeline](verification/01-signing-pipeline.md) (server-side signing)
- [verification/03-key-rotation](verification/03-key-rotation.md) (key rotation)
- [verification/04-replay-protection](verification/04-replay-protection.md) (replay protection)
---
@ -152,10 +152,10 @@ func (h *UpdateHandler) verifyDownload(binaryData []byte, checksum string) error
## Cross-References
- **Server signing** → [[verification/01-signing-pipeline]]
- **Key rotation** → [[verification/03-key-rotation]]
- **Replay protection** → [[verification/04-replay-protection]]
- **Install script** → [[flows/01-registration]] (TOFU key caching)
- **Server signing** → [verification/01-signing-pipeline](verification/01-signing-pipeline.md)
- **Key rotation** → [verification/03-key-rotation](verification/03-key-rotation.md)
- **Replay protection** → [verification/04-replay-protection](verification/04-replay-protection.md)
- **Install script** → [flows/01-registration](flows/01-registration.md) (TOFU key caching)
---