Watch
1
0
Fork
You've already forked RedFlag
0

RAF: full docs pass — components, flows, security, scanners, reference, testing, verification, overview

This commit is contained in:
Fimeg 2026-06-11 11:32:21 -04:00
commit a19dcf4f14
34 changed files with 5085 additions and 28 deletions

104
RAF/components/02-agent.md Normal file
View file

@ -0,0 +1,104 @@
# Agent Component
**Stateless Go executor that polls the server, verifies every command cryptographically, and reports everything back.**
---
## 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]].
---
## Package Structure
```
agent/
├── cmd/agent/ # Entry point, flag parsing, service bootstrap
├── internal/
│ ├── agent/loop.go # RunAgentLoop → RunPollingLoop — the heartbeat of the process
│ ├── handlers/ # Command handlers, routed by dispatch.go
│ │ ├── dispatch.go # Command-type → handler routing
│ │ ├── scan.go # Subsystem scan execution
│ │ ├── install.go # Legacy-path installs (docker, winget, windows_update)
│ │ ├── dry_run.go # Dependency resolution + hash discovery
│ │ ├── agent_update.go # Self-update commands
│ │ ├── heartbeat.go # Heartbeat + rapid polling
│ │ ├── processes.go # On-demand process explorer scans
│ │ ├── local_approve.go # Desktop-self local approval flow
│ │ └── reboot.go, screenshot.go, upgrade_attestation.go
│ ├── scanner/ # apt, dnf, winget, windows (WUA), detect
│ ├── installer/ # DiscoveryRunner + per-ecosystem installers
│ │ ├── discovery.go # Single chokepoint for read-only package ops
│ │ ├── apt.go, dnf.go # Gated: 4-method interface, no mutation
│ │ ├── docker.go, winget.go, windows.go # Legacy: direct mutation via type assertion
│ │ └── artifact_hash.go # SHA-256 resolution for closure pinning
│ ├── supplychain/ # consumer.go — capability-token → helper invocation
│ ├── crypto/ # TOFU pubkey cache, signature/nonce/replay verification
│ ├── instancelock/ # flock (Unix) / named mutex (Windows) — one agent per config
│ ├── circuitbreaker/ # Per-scanner circuit breakers
│ ├── event/ # TeeLogger (structured dual-output), buffered event reporting
│ ├── system/ # machine_id, system info, /proc process explorer
│ ├── cache/ # Hash cache, local state
│ ├── config/ # config.json, subsystems, kernel enforcement flags
│ ├── localapi/, desktop/ # Local API + desktop tray session integration
│ ├── kernel/ # eBPF scaffold (inert — not wired to capability model)
│ └── registration/, recovery/, retry/, receipt/, acknowledgment/
└── pkg/windowsupdate/ # WUA COM bindings (vendored fork, Apache 2.0)
```
---
## The Polling Loop
`RunAgentLoop` (`agent/internal/agent/loop.go`) initializes config, instance lock, crypto, and circuit breakers, then enters `RunPollingLoop`:
1. **Check in** — report metrics, buffered events, security events, circuit-breaker health
2. **Fetch commands** — verify signature, nonce, timestamp on each; reject replays
3. **`processCommands`** — route through `dispatch.go` to handlers
4. **`processCapabilityTokens`** — fetch minted tokens, hand to `supplychain/consumer.go`
5. **Sleep** — server-controlled interval (`applyServerPolling`), jittered
**Failure handling:** `classifyFailure` buckets errors into failure classes; `delayForFailure` applies a unified backoff policy per class (BUG-014). Typed sentinel errors (`ErrUnauthorized`, `ErrRefreshTokenInvalid`, `ErrMachineMismatch`) are terminal — not retried, logged as `[CRITICAL]`.
---
## Two Execution Paths (agent side)
| Path | Ecosystems | Mechanism |
|------|-----------|-----------|
| Capability gate | dnf, apt | Token fetched in loop → `consumer.ProcessToken``sudo systemd-run --pipe``redflag-helper` verifies + executes. Agent never runs the install command. |
| Legacy command | docker, winget, windows_update | Signed command → handler → installer mutation method (type-asserted). |
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)
---
## Verification (every command, no exceptions)
- **TOFU pubkey cache** (`crypto/pubkey.go`) — keys cached by `key_id`; unknown signer triggers re-fetch, no restart needed
- **Signature** — Ed25519 over the v3 message format
- **Nonce + timestamp** — 10-minute validity window, executed-nonce tracking, replay rejection
- Signing-required is doctrine, not config. There is no skip path.
**Cross-references:**
- [[verification/02-agent-verification]] (full pipeline)
- [[verification/04-replay-protection]]
---
## 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]])
- **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
---
*Last reviewed: 2026-06-11*