From 1cc965e23bda7ae9a9d2697ac536f38e5534d9b6 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Fri, 7 Aug 2026 03:37:24 +0000 Subject: [PATCH] docs(specify): adopt R-017..R-020, D-215..D-237, REQ-099..REQ-118 for v0.11 SPECIFY stage: adopt 5 research docs into authoritative ciagent files. - PRD_v0.11.md: new file extending R-series 16->20 (R-017 ingress hybrid, R-018/R-019/R-020 drift detection) - PROJECT.md: append D-215..D-237 (23 new decisions, no collisions with D-001..D-206) - REQUIREMENTS.md: append REQ-099..REQ-118 (20 net-new; ingress 099-102, drift 103-113, CLI 114-118) - ROADMAP.md: update v0.11 section (fold ingress into P15.5 per Q3=A, expand P09/P10, add CLI REQs to P05/P06/P14a/P14b per Q2=C) ---ci--- project: orca phase: 0 milestone: v0.11 status: specify ---/ci--- --- .ciagent/PRD_v0.11.md | 41 +++++++++++++++++++++++++++++ .ciagent/PROJECT.md | 41 +++++++++++++++++++++++++++++ .ciagent/REQUIREMENTS.md | 50 +++++++++++++++++++++++++++++++++++ .ciagent/ROADMAP.md | 56 ++++++++++++++++++++++++++-------------- 4 files changed, 169 insertions(+), 19 deletions(-) create mode 100644 .ciagent/PRD_v0.11.md diff --git a/.ciagent/PRD_v0.11.md b/.ciagent/PRD_v0.11.md new file mode 100644 index 0000000..ce3eadf --- /dev/null +++ b/.ciagent/PRD_v0.11.md @@ -0,0 +1,41 @@ +# PRD v0.11 Extension: Production Hardening + +**Status**: This file EXTENDS (does not supersede) `PRD_v0.9.md`. The +16 load-bearing rules R-001…R-016 remain in effect; this file adds +R-017…R-020, adopted per operator decision Q1=A (2026-08-07) after +ingestion of 5 research documents covering ingress hardening, drift +detection, platform-engineer positioning, strategic framing, and the +systemd Path unit implementation. + +## New load-bearing rules (R-017…R-020) + +| ID | Rule | +|---|---| +| R-017 | Cluster ingress default is the hybrid: Traefik binds on `127.0.0.1:8443` (and `127.0.0.1:8080` for HTTP). Public `:443` / `:80` traffic is DNAT'd via nftables to Traefik. Cross-node cluster mesh stays on the cluster-internal private IP. Operators can opt out with `orca cluster config --public-binding=...`. Workloads can opt in to pure iptables with `service { ingress: native }`. In all cases, mTLS termination is unchanged: Traefik holds the certs. | +| R-018 | Default drift detection cadence is 60s. Operators can tune per-path: critical_paths (5s default, systemd Path units enabled), standard_paths (30s default), file_watch_paths (systemd Path units, event-driven, R-001-clean). | +| R-019 | Drift detector is a BACKSTOP. Primary failure detection is: systemd (`Type=notify`) for process state, Traefik health checks for routing state, step-ca cert notifications for cert expiry, Syncthing completion events for replication state. Drift detector exists to catch config divergence, not workload failures. | +| R-020 | Hard gate: applier refuses new txns if pre-flight consistency check fails. Drift must be resolved before new state is committed. Auto-remediation is enabled by default for critical config paths but disabled for systemd unit files (require operator approval). Override: `--force` flag + per-namespace scoping (a drifted peer in ns-A does not block ns-B). | + +## Relationship to R-001…R-016 + +R-017…R-020 are *extensions*, not reversals. They are compatible with: +- R-001 (no Orca binary on servers) — systemd Path units are OS-native; nftables is OS-native; no Orca daemon introduced. +- R-006 (mTLS by default; Traefik load-bearing) — R-017 preserves Traefik as the mTLS termination point; only the binding address changes. +- R-007 (sockets by default) — unchanged; R-017 is about the public-ingress edge, not inter-workload sockets. +- R-010 (transactional control plane) — R-018/R-019/R-020 refine the txn plane's drift-detection contract (C-09). + +## New D-series (D-215…D-237) + +D-215…D-226 (ingress hybrid, doc 1) and D-227…D-237 (drift detection, doc 5) +are recorded in `PROJECT.md` § v0.11 Clarified Decisions. No collisions with +existing D-series (ends at D-206). + +## Milestone scope + +v0.11 "Production Hardening" — 23 phases (P00…P16). Research adds scope to +P09 (drift-event aggregation), P10 (drift detection + transactional plane), +and P15.5 (ingress hybrid + threat model). Five net-new CLI commands +(`orca cluster rotate-lead`, `orca upgrade`, `orca job migrate`, +`orca logs --all-nodes`, `orca doctor mTLS`) are folded into existing +phases per operator decision Q2=C. No new phases added (Q3=A folds ingress +into P15.5). diff --git a/.ciagent/PROJECT.md b/.ciagent/PROJECT.md index f42ecc6..f288b69 100644 --- a/.ciagent/PROJECT.md +++ b/.ciagent/PROJECT.md @@ -504,3 +504,44 @@ re-architecture foundation without modifying any Go orchestration code. | D-192 | Should the existing v0.8.15 release be backfilled with a binary asset, or only fix the pipeline forward? | **Fix forward only; no backfill** | Backfilling a past release is an ops task, not a docs milestone deliverable. The next tagged phase (this milestone's P1 ship at v0.9.1) will be the first correctly-asseted release; install.sh's new fallback walk handles the gap until then. | 0.88 | | D-193 | Should `release.sh` build only `linux-amd64` or also `linux-arm64`? | **Cross-build `linux-amd64` explicitly (host-arch-independent); arm64 deferred to a follow-up** | The install.sh user base is amd64 today (the `.coreci.yml` release step hardcodes `--asset orca-${VERSION}-linux-amd64.tar.gz`). Building amd64 regardless of host arch (via `GOOS=linux GOARCH=amd64 go build`) guarantees the asset the install script expects. arm64 support is a separate enhancement. | 0.85 | | D-194 | Should `install.sh` add a `--check` dry-run mode? | **Yes, lightweight** | A dry-run mode (`--check`) that prints the version + asset URL + install path without writing is cheap to add and useful for debugging the "which release will I get?" question that the v0.4.5 incident surfaced. | 0.80 | + +## v0.11 Clarified Decisions (D-series, full autonomy — Phase 0 pre-execution) + +The following 23 decisions (D-215…D-237) extend the locked D-series +(ends at D-206). They derive from 5 research documents ingested +2026-08-07 covering ingress hardening, drift detection, platform-engineer +positioning, strategic framing, and the systemd Path unit implementation. +Operator decisions Q1=A, Q2=C, Q3=A, Q4=A, Q5=A are adopted. + +### Ingress hybrid (D-215…D-226, from research doc 1) + +| ID | Question | Decision | Rationale | Confidence | +|----|----------|----------|-----------|------------| +| D-215 | Public-binding default? | **Hybrid: nft DNAT → Traefik on `127.0.0.1:8443`** | Defense-in-depth (kernel + app layer); mature pattern (kube-proxy, Linkerd2-proxy, F5/HAProxy+nginx). Smaller Traefik attack surface. R-017. | 0.93 | +| D-216 | Opt-out? | **`orca cluster config --public-binding=traefik-on-public-ip` for the simple case** | Operators who want simplicity get it with a one-line config change. | 0.94 | +| D-217 | nftables emitter? | **Yes; renders `/etc/nftables.d/orca.nft`; idempotent `nft -f` apply** | Same emitter pattern as Traefik/systemd emitters (R-001-clean). | 0.93 | +| D-218 | nftables tool vs iptables? | **`nft` (modern) over legacy `iptables`** | Atomic rule-set swap; modern kernel API. | 0.96 | +| D-219 | Cross-node cluster mesh? | **Stays bound on private IP `192.168.x.x:8443`; unchanged** | Avoids adding iptables rules for cross-node mesh; keeps mesh logic unchanged. | 0.94 | +| D-220 | Traefik `address` in static config? | **`127.0.0.1:8443` in default, `:443` in opt-out** | Single line change; certs/mTLS/dynamic config unchanged. | 0.97 | +| D-221 | `orca doctor nft`? | **Yes; checks table, expected rules, file hash; drift detection via hash comparison** | Parity with `orca doctor traefik`; integrates with R-018 critical_paths. | 0.95 | +| D-222 | Rate-limit meter? | **`ora_rl` set as part of the default rule set; configurable via `orca nft rate limit set`** | Kernel-level line-rate rate limiting; defense against SYN floods. | 0.91 | +| D-223 | GeoIP blocking? | **Operator-opt-in via `orca nft country block add`**; cli + ipset extension | Not a default; operators opt in. | 0.88 | +| D-224 | `nftables` not `iptables` in `.coreci.yml` pipelines? | **Yes; integration tests use `nft` exclusively** | Matches D-218. | 0.94 | +| D-225 | Per-workload `ingress: native` coexists with hybrid default? | **Yes; `service { ingress: native }` opts into pure iptables + stunnel sidecars** | Workload-level opt-in; doesn't affect cluster default. | 0.93 | +| D-226 | `nftables` rule hash baseline? | **`cluster/state/baseline.nft.hash` per peer; drift detection per §17** | Integrates with R-018 drift detection. | 0.90 | + +### Drift detection (D-227…D-237, from research doc 5) + +| ID | Question | Decision | Rationale | Confidence | +|----|----------|----------|-----------|------------| +| D-227 | Drift detection architecture? | **systemd Path units for critical paths + 60s polling backstop + auto-remediation** | R-001-clean (systemd is OS, not Orca); ~10s event-driven latency on critical paths. R-018/R-019. | 0.94 | +| D-228 | Path unit event payload? | **Oneshot service; receives path via `%f`; computes sha256; writes event JSON to `/etc/orca/state/drift-events/`** | Stateless, self-contained, idempotent. | 0.93 | +| D-229 | Lead-side pickup? | **Aggregator timer reads each peer's drift-events/, validates against applied txn hashes, triggers remediation** | Reuses existing 10s aggregator cadence (C-11); single SSH pull per tick. | 0.94 | +| D-230 | Critical path polling cadence? | **5s backstop; systemd Path unit provides ~10s event-driven latency** | Closes the gap to K8s-comparable drift detection on critical paths. | 0.92 | +| D-231 | Auto-remediation policy? | **Per-path config; critical paths default to auto; systemd units default to require-approval** | Config files are safe to re-push; service units may need careful ordering (don't restart serving workloads). | 0.93 | +| D-232 | Remediation rate limit? | **5-minute cooldown per path; applies only on SUCCESSFUL remediation; transient failures retry on next aggregator tick** | Prevents loops from buggy external actors; avoids a 30s network blip blocking re-remediation for 5 min (refined per CLARIFY C4). | 0.92 | +| D-233 | NFS path detection? | **`orca node setup` detects NFS mounts; falls back to polling for affected paths** | systemd Path units use inotify which doesn't work across NFS. | 0.90 | +| D-234 | Secrets path exclusion? | **`/etc/orca/credentials/*` excluded from drift detection** | Re-remediating secrets might clobber intentional out-of-band rotation. | 0.95 | +| D-235 | EnvironmentFile drift? | **Triggers `orca job restart ` instead of file-level remediation** | Workload already running won't pick up env changes without a restart. | 0.89 | +| D-236 | `orca drift watch` semantics? | **`iter.Seq2[Event, error]` per D-017; `signal.NotifyContext` per D-023; default 2s poll** | Consistent with existing `--watch` pattern (D-017/D-023). | 0.95 | +| D-237 | Aggregator timer changes? | **Existing 10s cadence; extended to also pull drift-events/ and remediate** | Reuses C-11 aggregator; no new timer. | 0.95 | diff --git a/.ciagent/REQUIREMENTS.md b/.ciagent/REQUIREMENTS.md index 7667949..6f5f52a 100644 --- a/.ciagent/REQUIREMENTS.md +++ b/.ciagent/REQUIREMENTS.md @@ -201,3 +201,53 @@ that guarantees every Gitea release carries a Linux binary asset. | REQ-096 | `docs/namespace.md` v0.9 multi-namespace layout update: replace v0.8 flat path table with v0.9 layout (`cluster/`, `_defaults/`, per-ns `db/jobs/alloc/ns.md`), `ORCA_HOME`/`--system` resolution, `orca ns` subcommand cross-link, v0.8 flat layout flagged deprecated | Medium | **v0.10 P4** | **Complete** | | REQ-097 | `scripts/release.sh` release pipeline fix: cross-build `linux-amd64` tarball regardless of host arch (`GOOS=linux GOARCH=amd64 go build`); post-create asset verification (query `/releases/tags/$VERSION`, assert the tarball in attachments, retry/fail loudly if missing). Guarantees every Gitea release carries the Linux binary asset (root cause of v0.4.5 install) | High | **v0.10 P1** | **Complete** | | REQ-098 | `scripts/install.sh` asset fallback walk: if the latest/pinned release lacks the matching `orca---.tar.gz`, walk backward through `/releases?limit=20` to the most recent release that has it, with a clear warning. Keeps pulling from releases (not main). Optional `--check` dry-run mode | High | **v0.10 P1** | **Complete** | + +## v0.11 Production Hardening Milestone Requirements + +The following requirements (REQ-099…REQ-NN) are scoped to the v0.11 +production-hardening milestone. They cover the ingress hybrid default +(R-017), drift detection (R-018/R-019/R-020), the systemd Path unit +implementation (D-227…D-237), and five net-new CLI commands added per +operator decision Q2=C. + +### Ingress hybrid (R-017, D-215…D-226) + +| ID | Requirement | Priority | Phase | Status | +|----|-------------|----------|-------|--------| +| REQ-099 | `internal/emitter/nft.go`: nftables emitter renders `/etc/nftables.d/orca.nft` with DNAT (`:443`→`127.0.0.1:8443`, `:80`→`127.0.0.1:8080`), SYN-flood `tcp-flags` filter, `ora_rl` rate-limit meter (default 100/s burst 200), `orca_trusted_probes` set; idempotent `nft -f` apply; atomic rule-set swap (R-017, D-217, D-218, D-222) | High | **v0.11 P15.5** | Pending | +| REQ-100 | Traefik static config emitter update: `entryPoints.websecure.address` changes from `:443` to `127.0.0.1:8443` (default); `entryPoints.web.address` changes to `127.0.0.1:8080`; `--public-binding=traefik-on-public-ip` opt-out emits `:443`/`:80` instead; certs/mTLS/dynamic config unchanged (R-017, D-220, D-216) | High | **v0.11 P15.5** | Pending | +| REQ-101 | `orca doctor nft`: checks `table inet orca-ingress` exists, expected DNAT rules present, rate-limit meter present, `/etc/nftables.d/orca.nft` parses cleanly (`nft -c -f`), file hash matches latest applied txn; drift detection via hash comparison (R-018 critical_paths, D-221, D-226) | High | **v0.11 P15.5** | Pending | +| REQ-102 | `orca nft` CLI: `show [--peer]`, `diff --against `, `doctor` (alias for `orca doctor nft`), `country block add ` (opt-in GeoIP), `rate limit set --rate N/s`; all Layer-5 orchestrators that SSH into peers and parse `nft` output (D-223, D-222) | Medium | **v0.11 P15.5** | Pending | + +### Drift detection (R-018/R-019/R-020, D-227…D-237) + +| ID | Requirement | Priority | Phase | Status | +|----|-------------|----------|-------|--------| +| REQ-103 | `internal/drift` package: `Detector` interface (`Watch`, `Aggregate`, `Remediate`, `Acknowledge`), `Event`, `Config`, `PathSpec`, `RemediationPolicy` types; `iter.Seq2[Event, error]` per D-017; `signal.NotifyContext` per D-023 (R-018, D-236) | High | **v0.11 P10** | Pending | +| REQ-104 | `orca drift` CLI tree: `watch [--interval=2s] [--paths=...] [--json]`, `show [--peer]`, `acknowledge `, `remediate [--force]`, `config show`, `config validate`; uses `iter.Seq2` + `signal.NotifyContext` (D-236) | High | **v0.11 P10** | Pending | +| REQ-105 | systemd Path unit emitter: for each critical path, emit `orca-drift-.path` (`PathChanged=`, `RateLimitIntervalSec=1s`, `RateLimitBurst=5`) + `orca-drift-.service` (`Type=oneshot`, `ExecStart=/usr/local/bin/orca-drift-notify.sh %f`, `User=orca`, security hardening: `NoNewPrivileges`, `ProtectSystem=strict`); R-001-clean (R-018, D-227, D-228) | High | **v0.11 P10** | Pending | +| REQ-106 | `scripts/orca-drift-notify.sh`: receives changed path as `$1`, computes sha256 (or "DELETED"), writes event JSON to `/etc/orca/state/drift-events/.json` (event_id, ts, host, path, status, new_sha256, latest_txn, triggered_by); stateless, idempotent; `flock` for serialization (D-228) | High | **v0.11 P10** | Pending | +| REQ-107 | `scripts/orca-aggregate.sh` extension: existing 10s aggregator cadence (C-11) now also rsyncs each peer's `/etc/orca/state/drift-events/`, validates event hashes against `/etc/orca/state/applied//manifest.json`, triggers `orca-remediate.sh` for auto-remediable paths, consumes (deletes) event files on peers (D-229, D-237) | High | **v0.11 P09** | Pending | +| REQ-108 | `scripts/orca-remediate.sh`: re-pushes latest applied txn's per-peer render tree via rsync, runs peer-side applier; 5-min cooldown per path applies ONLY on successful remediation (transient failures retry next tick); cooldown state at `/etc/orca/state/remediation-cooldown/` (D-231, D-232 refined per CLARIFY C4) | High | **v0.11 P10** | Pending | +| REQ-109 | Drift cadence config in `config.md` (`kind: ClusterConfig`): `drift.polling.{enabled,default_interval,max_concurrent_peers}`, `drift.paths.{critical,standard,excluded}` (each with `systemd_path_unit`, `interval`, `paths` list), `drift.remediate.{auto,auto_paths,require_approval_paths,notify_on_remediation}`; critical defaults: Traefik dynamic, nftables, sudoers, orca-alloc services; secrets + `/run/orca/*` + drift-events dir excluded (R-018, D-231, D-234) | High | **v0.11 P10** | Pending | +| REQ-110 | Pre-flight consistency gate in applier: `orca-pull.sh` (C-09) refuses new txns if drift detected on the target peer/namespace; `--force` flag overrides; per-namespace scoping means a drifted peer in ns-A does not block ns-B (R-020, Q4=A) | High | **v0.11 P10** | Pending | +| REQ-111 | `orca` system user on peers: peer-setup emits `useradd -r orca` (system account, no login shell); `orca-drift-*.service` runs as `User=orca Group=orca`; SSH key access to lead for aggregator; idempotent at peer setup (net-new operational requirement from doc 5) | High | **v0.11 P10** | Pending | +| REQ-112 | NFS detection at peer setup: `orca node join` / peer-setup detects NFS mounts on orca state dirs; if `/etc/orca` is on NFS, systemd Path units are disabled for those paths and polling is the only detection; logs a warning (D-233) | Medium | **v0.11 P10** | Pending | +| REQ-113 | `orca job restart `: restarts an allocation to pick up EnvironmentFile drift; goes through normal allocation lifecycle (not file-level remediation); triggers on drift of `/etc/orca/allocs//env` (D-235) | Medium | **v0.11 P10** | Pending | + +### Net-new CLI surface (Q2=C — all five commands added to v0.11) + +| ID | Requirement | Priority | Phase | Status | +|----|-------------|----------|-------|--------| +| REQ-114 | `orca cluster rotate-lead`: moves cluster CA + lead state to a new bare-Linux peer (R-003 enforces bare-Linux-only lead); workloads keep running (certs already distributed); SSH key rotation; idempotent (Q2=C, folds into P14b daemon cutover) | High | **v0.11 P14b** | Pending | +| REQ-115 | `orca upgrade --to-vX`: thin wrapper around `install.sh` + `orca restore` (binary upgrade only, not full cluster rolling upgrade); handles Traefik binding cutover from `:443` to `127.0.0.1:8443` for existing v0.9/v0.10 clusters (R-017 migration path, CLARIFY C1, C2=a thin wrapper); full cluster-rolling-upgrade defers to v1.x (Q2=C) | High | **v0.11 P14a** | Pending | +| REQ-116 | `orca job migrate --to `: drain+reschedule composite (uses P05 drain + P06 alloc history); live-migrate with storage replication defers to v1.x (CLARIFY C3=a); idempotent (Q2=C) | Medium | **v0.11 P05** | Pending | +| REQ-117 | `orca logs --all-nodes --since 5m`: aggregates journald logs across peers via SSH; uses P06 alloc-history cache DB; `iter.Seq` streaming per D-017; `--since` duration flag; `--all-nodes` fans out (Q2=C, folds into P06) | Medium | **v0.11 P06** | Pending | +| REQ-118 | `orca doctor mTLS`: verifies trust chain (CA → server cert → workload SVIDs exist + not expired) AND live mTLS handshake probe to each peer (reuses P01 metrics endpoint + P01.5 SPIFFE spike infra); both chain verification + live probe (CLARIFY C5, Q2=C, folds into P15.5) | High | **v0.11 P15.5** | Pending | + +### Scope notes + +- REQ-099…REQ-118 = 20 net-new requirements (REQ count grows 98→118). +- No new phases added (Q3=A folds ingress into P15.5; Q2=C folds CLI commands into existing phases). +- P09 expands (REQ-107 aggregator extension); P10 expands (REQ-103…REQ-113, the largest phase); P15.5 expands (REQ-099…REQ-102 ingress + REQ-118 mTLS doctor). +- P05 gains REQ-116 (migrate); P06 gains REQ-117 (logs --all-nodes); P14a gains REQ-115 (upgrade); P14b gains REQ-114 (rotate-lead). diff --git a/.ciagent/ROADMAP.md b/.ciagent/ROADMAP.md index 634f3fa..1b8873a 100644 --- a/.ciagent/ROADMAP.md +++ b/.ciagent/ROADMAP.md @@ -300,7 +300,13 @@ releases if the latest lacks the asset. **Scope**: ship a cluster that operators can run. Builds on the v0.9 re-architecture foundation with the production-grade subsystems: secrets, transactions, ACL/SPIFFE, backup/restore, drain, recovery, and -the v0.8→v1.0 migration. +the v0.8→v1.0 migration. **Phase 0 adopts 4 new load-bearing rules +(R-017…R-020) and 23 new decisions (D-215…D-237) from 5 research docs +covering ingress hardening, drift detection, platform-engineer +positioning, strategic framing, and the systemd Path unit +implementation.** No new phases added; scope is folded into existing +phases per operator decisions Q2=C (add 5 CLI commands), Q3=A (fold +ingress into P15.5). **Milestone type**: feature (multiple `feat` phases). @@ -311,20 +317,20 @@ the v0.8→v1.0 migration. - [ ] Phase P02: ACL (SPIFFE + token identities) — tag `v0.10.4` - [ ] Phase P03: Secrets subsystem (REQ-080; **gate C-19** threat model) — tag `v0.10.5` - [ ] Phase P04: Backup/restore (tar + signed) — tag `v0.10.6` -- [ ] Phase P05: Drain + daemon drain-and-stop (REQ-061) — tag `v0.10.7` -- [ ] Phase P06: Alloc history (CLI-side SQLite retention; REQ-071 cache DB) — tag `v0.10.8` +- [ ] Phase P05: Drain + daemon drain-and-stop (REQ-061) + **`orca job migrate` (REQ-116)** — tag `v0.10.7` +- [ ] Phase P06: Alloc history (CLI-side SQLite retention; REQ-071 cache DB) + **`orca logs --all-nodes --since` (REQ-117)** — tag `v0.10.8` - [ ] Phase P07: Recovery (`orca restore`) — tag `v0.10.9` -- [ ] Phase P08: Integration tests — expand hermetic harness (REQ-087) — tag `v0.10.10` -- [ ] Phase P09: Collector + aggregator (opt-in; **gates C-11, C-12, C-14**) — tag `v0.10.11` -- [ ] Phase P10: Transactional plane (REQ-075, REQ-079; **gate C-09** orca-pull.sh failure contract) — tag `v0.10.12` +- [ ] Phase P08: Integration tests — expand hermetic harness (REQ-087) + **drift-detection integration tests (auto-remediation, NFS fallback, cooldown, secret exclusion)** — tag `v0.10.10` +- [ ] Phase P09: Collector + aggregator (opt-in; **gates C-11, C-12, C-14**) + **drift-event aggregation extension (REQ-107, D-237)** — tag `v0.10.11` +- [ ] Phase P10: Transactional plane (REQ-075, REQ-079; **gate C-09**) + **drift detection (R-018/R-019/R-020, REQ-103..REQ-113; `orca drift` CLI, systemd Path unit emitter, `orca-drift-notify.sh`, `orca-remediate.sh`, cadence config, `--force`+per-ns gate, `orca` system user, NFS detection)** — tag `v0.10.12` - [ ] Phase P11: `orca job lint` (REQ-084) — tag `v0.10.13` - [ ] Phase P12: `orca job verify` (dry-run txn through lead) — tag `v0.10.14` - [ ] Phase P13: `orca ns` subcommands (full surface) + deprecation warnings (REQ-068) — tag `v0.10.15` -- [ ] Phase P14a: v0.8→v1.0 data migration (REQ-066; **gate C-07** CA migration spec) — tag `v0.10.16` -- [ ] Phase P14b: Daemon cutover + running-allocation adoption — tag `v0.10.17` +- [ ] Phase P14a: v0.8→v1.0 data migration (REQ-066; **gate C-07**) + **`orca upgrade --to-vX` (REQ-115, thin wrapper, handles R-017 binding cutover)** — tag `v0.10.16` +- [ ] Phase P14b: Daemon cutover + running-allocation adoption + **`orca cluster rotate-lead` (REQ-114)** — tag `v0.10.17` - [ ] Phase P14c: Mixed-version tolerance + no-orca-on-server enforcement (REQ-065, REQ-086; implements C-13) — tag `v0.10.18` -- [ ] Phase P15: README quickstart (REQ-089) — tag `v0.10.19` -- [ ] Phase P15.5: Threat model + security review (**gate C-19**) — tag `v0.10.20` +- [ ] Phase P15: README quickstart (REQ-089; **Nomad-inspired framing per Q5=A, honest-trade-offs table from research doc 3**) — tag `v0.10.19` +- [ ] Phase P15.5: Threat model + security review (**gate C-19**) + **ingress hybrid (R-017; nft emitter REQ-099, Traefik binding REQ-100, `orca doctor nft` REQ-101, `orca nft` CLI REQ-102) + `orca doctor mTLS` (REQ-118)** — tag `v0.10.20` - [ ] Phase P16: Final review + ship + audit — **v0.11.0 milestone release** — tag `v0.10.21` (v1.0.0 cut separately after UAT sign-off) **Milestone tag**: `v0.11.0` (the v0.11 milestone release tag; v1.0.0 is @@ -338,24 +344,36 @@ tags: `v0.10.0`…`v0.10.21`. - **P00** — CLI cache (R-008) - **P01.5** — SPIFFE spike (REQ-076; C-08) - **P03** — Secrets (REQ-080; C-19) -- **P05** — Drain + daemon stop (REQ-061) -- **P06** — Alloc history (REQ-071 cache DB) -- **P08** — Integration tests (REQ-087) -- **P10** — Transactional plane (REQ-075, REQ-079; C-09) +- **P05** — Drain + daemon stop (REQ-061) + `orca job migrate` (REQ-116) +- **P06** — Alloc history (REQ-071 cache DB) + `orca logs --all-nodes --since` (REQ-117) +- **P08** — Integration tests (REQ-087) + drift-detection integration tests +- **P09** — Collector + aggregator (C-11, C-12, C-14) + drift-event aggregation (REQ-107, D-237) +- **P10** — Transactional plane (REQ-075, REQ-079; C-09) + drift detection (R-018/R-019/R-020; REQ-103..REQ-113) - **P11** — Job lint (REQ-084) - **P13** — ns subcommands + deprecation warnings (REQ-068) -- **P14a/b/c** — Migration (REQ-066, REQ-065, REQ-086; C-07, C-13) -- **P15** — README (REQ-089) -- **P15.5** — Threat model (C-19) +- **P14a/b/c** — Migration (REQ-066, REQ-065, REQ-086; C-07, C-13) + `orca upgrade` (REQ-115) + `orca cluster rotate-lead` (REQ-114) +- **P15** — README (REQ-089; Q5=A framing) +- **P15.5** — Threat model (C-19) + ingress hybrid (R-017; REQ-099..REQ-102) + `orca doctor mTLS` (REQ-118) -### Risk register (from grill, for ongoing monitoring) +### New load-bearing rules adopted in Phase 0 + +- **R-017** — Ingress hybrid: nft DNAT → Traefik on `127.0.0.1:8443`; opt-out via `--public-binding`; `service { ingress: native }` per-workload opt-in +- **R-018** — Drift cadence: default 60s; critical 5s + systemd Path units; standard 30s +- **R-019** — Drift detector is a BACKSTOP; primary = systemd/Traefik/step-ca/Syncthing +- **R-020** — Hard gate: applier refuses txns on pre-flight drift; `--force` + per-ns scoping override + +### Risk register (from grill + research, for ongoing monitoring) - **step-ca single-instance SPOF** (mitigation: C-12 doc; v1.x HA via systemd failover) - **master.key passphrase-less 0600** (mitigation: C-19 threat model; consider OS keyring in v1.x) - **wasmtime CGO breaks cross-compile** (mitigation: C-01 spike; fallback to podman/process primary) - **bash control plane drift** (mitigation: C-15..C-18 render-format contract + bats gate) - **daemon cutover orphans running allocs** (mitigation: P14b split; test adoption) -- **27→35+ phase scope** (mitigation: C-04 resolved — operator decision: keep 2 milestones v0.9 + v0.11, keep all phases, v1.0 is UAT-gated after v0.11; current count v0.9=18 + v0.11=22 = 40 phases, exceeds 35 soft limit but operator accepted) +- **27→35+ phase scope** (mitigation: C-04 resolved — operator accepted 40 phases; v0.11 stays at 23 phases with scope folded in, no new phases) +- **R-020 deadlock** (mitigation: `--force` flag + per-namespace scoping per Q4=A; drifted peer in ns-A doesn't block ns-B) +- **P10 sizing** (mitigation: P10 is the largest phase — drift detection + txn plane; grill may split into P10a/P10b if vertical slice is too large) +- **Ingress default migration** (mitigation: `orca upgrade` [REQ-115] handles Traefik binding cutover from `:443` to `127.0.0.1:8443` for existing v0.9/v0.10 clusters) +- **`orca` system user on peers** (mitigation: net-new operational requirement; peer-setup emits `useradd -r orca` idempotently; documented in P10) ## Deferred to v1.x (out of scope for v0.11)