Commit Graph

41 Commits

Author SHA1 Message Date
Jon Chery c10779873b feat(P05): CLI-side scheduler + CEL constraints + affinity (REQ-083)
P05 — Scheduler moves from daemon-side to CLI-side (R-001) with runtime-awareness.

Scheduler (internal/scheduler/scheduler.go, REQ-083):
- Pure Schedule(nodes, req) -> []Placement. Job=1 best-fit, Service=count
  replicas (anti-affinity default, colocation permitted), DaemonSet=1 per
  matching node. Score(node, req) = (FreeCPU*1000 + FreeMem); fits checks
  runtime compat (wasm->wasmtime, pve-vm/ct->proxmox), constraints (CEL AND),
  capacity. Affinity scoring (target + weight, anti-affinity for spreading).

CEL evaluator (internal/scheduler/cel.go):
- Hand-rolled recursive-descent (no CEL dep in go.mod). Subset: node.* attrs,
  literals, ==/!=/>=/<=/></>, in/not in, and/or/not, parens. Anything outside
  subset returns error (no silent wrong answer). Schedule treats eval errors
  as non-fit (node skipped).

23 packages pass, 20 bats pass, gofmt clean, verify-reqs 90 consistent.
89.5% coverage on internal/scheduler.

---ci---
project: orca
phase: P05
milestone: v0.9
status: execute
---/ci---
2026-08-05 18:02:51 +00:00
Jon Chery ae6eb5a27b feat(P03,P04,P08): update stanza + lifecycle hooks + socket plumbing
P03 — Update stanza (rolling/canary/blue-green):
- internal/spec/schema/update.go: UpdateValidator (strategy enum, max_parallel
  1..count, duration parsing, canary int/% forms, auto_promote). 98.2% cov.
- internal/emitter/update.go: RenderUpdatePlan computes the step sequence
  (rolling batches, canary 1+promote+rest, blue-green all+cutover). Pure plan,
  no execution (v0.10-P10 is transactional). 73.7-100% cov.

P04 — Lifecycle hooks (systemd ExecStop semantics):
- Extended internal/emitter/systemd.go: post_start -> ExecStartPost=,
  pre_stop -> ExecStop=. Order: ExecStart -> ExecStartPost -> ExecStop ->
  socket lines. 8 lifecycle tests. 100% cov on systemd.go.

P08 — Socket plumbing (R-007):
- internal/emitter/socket.go: SocketEmitter renders RuntimeDirectory=orca/
  alloc-<id> per port (mode 0750, orca:orca). ExecStartPre TCP-bind marker
  when service.bind=127.0.0.1. SocketPath(allocID,portName) helper. 100% cov.
- Alloc-id is spec.Name placeholder; real id assigned by scheduler at submit.

22 packages pass, 20 bats pass, gofmt clean, verify-reqs 90 consistent.

---ci---
project: orca
phase: P03/P04/P08
milestone: v0.9
status: execute
---/ci---
2026-08-05 17:55:11 +00:00
Jon Chery 436641782c feat(P02): Service block + Traefik emitter + atomic reload (REQ-077, gate C-10)
P02 — Traefik dynamic config generation + atomic reload protocol.

Parser (internal/jobspec/markdown.go):
- Extended WorkloadSpec with Health, Constraints, Affinity, Lifecycle
  fields. Parsed restart/update/service/health/lifecycle/affinity/
  constraints blocks. HealthBlock, AffinityRule, LifecycleBlock types.

Schema (internal/spec/schema/schema.go):
- ServiceValidator: restart.mode enum (service/on-failure/never),
  update.strategy enum (rolling/canary/blue-green), health required,
  service.bind IP validation (R-007 loopback opt-in). 98.5% coverage.

Traefik emitter (internal/emitter/traefik.go, REQ-077):
- TraefikEmitter renders /etc/traefik/dynamic/orca-<name>.yaml with
  http.routers, http.services (servers = R-007 socket paths), TLS
  (certResolver=orca, trust domain), healthCheck. RenderDrain sets
  weight:0 per backend. RegisterTraefik wires process/podman/wasm.

Atomic reload (internal/emitter/traefik_atomic.go, gate C-10):
- WriteTraefikDynamic: write to path.tmp via WriteFileIdempotent, then
  mv -f path.tmp path (atomic POSIX rename, Traefik fsnotify observes
  IN_MOVED_TO). Traefik holds-last-good on malformed config. C-10 PASS.

22 packages pass, 20 bats pass, gofmt clean, verify-reqs 90 consistent.
Coverage: emitter 96.5%, jobspec 88.8%, schema 98.5%, sshpush 93.0%.

---ci---
project: orca
phase: P02
milestone: v0.9
status: execute
---/ci---
2026-08-05 17:48:04 +00:00
Jon Chery e92b18197c feat(P01): SSH-push transport layer — connection pool, retry, fan-out, idempotent writes (REQ-073)
P01 — Load-bearing replacement for v0.8 mTLS transport (R-001).

Transport (internal/sshpush/transport.go, REQ-073):
- Transport struct with sync.Map connection pool (reuse *ssh.Client per peer).
- Exec with context timeout (10s default) + retry (100ms x2 cap 5s max 5
  attempts, +/-25% jitter — same backoff as v0.8 transport/retry.go).
- ReadFile, WriteFile (atomic heredoc + mv), Close.
- sshDialer + sshSession seams for testability. TOFU host-key verification
  reuses proxmox.TOFUHostKeyCallback. security.Flock for known_hosts.

Fan-out (internal/sshpush/fanout.go):
- ExecAll, WriteAll with errgroup + SetLimit semaphore (default 8 per I-B-001).
  Per-peer errors collected, don't cancel the group.

Idempotency (internal/sshpush/idempotency.go, C-18):
- WriteFileIdempotent: SHA-256 compare via ssh sha256sum; skip if content
  matches (written=false). Content-addressed idempotency replaces the v0.8
  X-Orca-Idempotency-Key header (C-18 capability map).

Tests: in-process fake SSH server (ssh.NewServerConn NoClientAuth ed25519)
for e2e + interface seams for pure-logic. 93.0% coverage. 20 packages pass.

---ci---
project: orca
phase: P01
milestone: v0.9
status: execute
---/ci---
2026-08-05 17:35:11 +00:00
Jon Chery 60b0357eb6 feat(P0c): Job/Service/DaemonSet schemas + emitter interface + systemd stub (REQ-074)
P0c — Kind-specific schema validators + Layer 4 emitter interface.

Schemas (internal/spec/schema/schema.go, REQ-074):
- Validator interface with JobValidator, ServiceValidator, DaemonSetValidator.
  JobValidator: count=1, no service block, optional schedule/timeout.
  ServiceValidator: ports required, count>=1, restart+update+runtime required.
  DaemonSetValidator: schedule mode required, no ports (D-175), no count.
  ValidatorFor(kind) dispatcher. 96.2% coverage.

Emitter interface (internal/emitter/emitter.go, REQ-074, I-B-002):
- File{Path,Content,Mode}, Emitter interface { Render(spec,node) []File },
  Registry keyed by kind:runtime, Register + Render lookup. 100% coverage.

Systemd stub (internal/emitter/systemd.go):
- SystemdEmitter for process runtime. Renders minimal [Service] unit at
  /etc/systemd/system/orca-v1-alloc-<name>.service (orca-v1- prefix per
  dual-write window REQ-090 — no overlap with v0.8 daemon's orca-<job>).

Flock test fix: TestFlock_concurrentBlocks rewritten to use non-blocking
tryFlockEx (LOCK_NB) instead of a leaked blocking goroutine. Eliminates
the temp-dir cleanup race.

20 packages pass, 20 bats pass, gofmt clean, verify-reqs 90 consistent.

---ci---
project: orca
phase: P0c
milestone: v0.9
status: execute
---/ci---
2026-08-05 17:17:02 +00:00
Jon Chery 667f20a7b3 feat(P0b): Markdown jobspec parser + dispatcher + fuzz harness (REQ-064,067)
P0b — Canonical Markdown+frontmatter jobspec parser (R-013/R-014).

Parser (internal/jobspec/markdown.go, REQ-064):
- WorkloadSpec/RuntimeBlock/PortSpec/VolumeSpec types. ParseMarkdown
  hand-rolled YAML frontmatter (no yaml.v3 dep). Kind validation (Job/
  Service/DaemonSet per R-012). BOM-stripped frontmatter, byte-exact body
  preservation (R-015) via the fuzz harness.

Dispatcher (internal/jobspec/dispatch.go, REQ-064):
- ParseFile/Dispatch routes on extension: .md->Markdown, .yaml/.yml->
  Markdown-with-empty-body, .hcl->ParseHCL adapter. HCL adapter converts
  Spec{Job,Tasks} to *WorkloadSpec (Kind=Job, Runtime.one_of=process).
  Backward compat preserved (REQ-090) — orca job run old-spec.hcl works.
- Legacy Parse renamed ParseHCLLegacy, marked // Deprecated per R-013.

Fuzz harness (internal/jobspec/markdown_fuzz_test.go, REQ-067, R-015):
- FuzzParseMarkdownRoundTrip with 10 seed corpus entries (CRLF, BOM,
  no-frontmatter, only-closing-separator, code-fence ---, trailing
  whitespace, empty body, etc). Asserts byte-exact body round-trip.

Tests: markdown_test.go (19 tests), dispatch_test.go (17 tests), fuzz
(10 seeds). jobspec package 89.2% coverage. cli 81.8% (no regression).

18 packages pass, 20 bats pass, gofmt clean, verify-reqs 90 consistent.

---ci---
project: orca
phase: P0b
milestone: v0.9
status: execute
---/ci---
2026-08-05 17:02:33 +00:00
Jon Chery 7bb31d4c09 feat(P0a2): namespace CRUD + inheritance engine (REQ-082)
P0a2 — Namespace inheritance resolver + orca ns CLI subcommands.

Resolver (REQ-082, internal/ns/resolve.go):
- Pure Resolve() function: DFS post-order chain assembly (most-specific
  first, _defaults implicit last D-185). Child-wins-scalar env merge, de-duped
  union constraints. Cycle detection with readable cycle path. Missing-parent
  + missing-_defaults + misordering (['_defaults','x']) rejection. Opt-out
  impossible (D-187). 89.6% coverage.

Parser (internal/ns/parse.go):
- ParseNSMd: hand-rolled YAML frontmatter (no yaml.v3 dep). Validates
  kind:Namespace + name, parses parents flow-array, inherits_env/secrets.
- ParseNSMdDir: walks root/*/ns.md, skips cluster/, requires _defaults.

CLI (internal/cli/ns.go, D-176):
- orca ns list/create/delete/inspect/validate. Inspect + validate use the
  resolver. Create refuses _defaults/cluster; delete refuses _defaults +
  non-empty namespaces. JSON output support. 85.2% coverage.
- Registered on rootCmd.

Tests: resolve_test.go (11 tests), parse_test.go (14 tests), ns_test.go
(21 tests). 18 packages pass, 20 bats pass, gofmt clean, verify-reqs 90
consistent.

---ci---
project: orca
phase: P0a2
milestone: v0.9
status: execute
---/ci---
2026-08-05 16:49:12 +00:00
Jon Chery 437aab39b4 feat(P0a1): multi-namespace path resolver + config demotion + known_hosts flock + CA migration spec (v0.9 P0a1)
P0a1 — Re-architecture Foundation (path resolver + config demotion).

Path resolver (REQ-070, R-002):
- internal/paths/paths.go: 23 functions for the multi-namespace layout
  (Root/ClusterDir/NamespaceDir/NS*/DefaultNamespace/CA/MasterKey/CacheDB/
  Txn/Peers/KnownHosts/SSH/Server/Config). Honors $ORCA_HOME. 100% coverage.
- internal/certpaths/certpaths.go: refactored as thin shim delegating to
  paths, preserving the v0.8 flat-layout API for backward compat during
  the dual-write window (REQ-090). Package doc explains the v0.10-P14
  migration plan. certpaths deleted after v0.10-P14. 100% coverage.

Config demotion (REQ-069, R-014):
- internal/config/markdown.go: minimal hand-rolled YAML frontmatter parser
  (no new dep — yaml.v3 not in go.mod). Returns same *Config struct as HCL.
- internal/config/config.go: renamed Load body to LoadHCL (// Deprecated
  per R-013), added dispatcher Load() routing on extension (.hcl->HCL,
  .md->Markdown, .yaml->Markdown). Signature preserved so root.go unchanged.
- dispatch_test.go + markdown_test.go: 89.8% coverage on config package.

Known_hosts flock (REQ-063, deferred P1 from REVIEW_v0.8 A2):
- internal/security/flock.go: stdlib syscall.Flock advisory lock helper.
- internal/proxmox/bootstrap.go: TOFUHostKeyCallback capture + ResetHostKey
  both acquire the flock before read-modify-write on known_hosts. Prevents
  concurrent writers under v0.9 parallel SSH fan-out. 3 flock tests.

CA migration spec (grill C-07):
- .ciagent/CA_MIGRATION_SPEC_v0.9.md: Option A (preserve trust root,
  RECOMMENDED) vs Option B (forced re-bootstrap). Pre-flight checks,
  migration steps, rollback, post-migration invariants, spike plan.

Verification: build pass, 17/17 Go packages pass, 20/20 bats pass, gofmt
clean, go vet clean, verify-reqs 90 consistent. Coverage: paths 100%,
certpaths 100%, config 89.8%, emit covered.

---ci---
project: orca
phase: P0a1
milestone: v0.9
status: execute
---/ci---
2026-08-05 16:38:26 +00:00
Jon Chery fc94326b0e feat(P00): deprecation sweep + bash tooling gate + render contract + doc banners (v0.9 P00)
P00 — Re-architecture Foundation (deprecation/migration/test-infra/persona/docs).

Deprecation sweep (REQ-068, REQ-072, REQ-089):
- Add // Deprecated: doc comments to internal/daemon (R-001), internal/transport
  (REQ-073), internal/security/ca.go+csr.go (D-101/REQ-076), internal/engine/
  dispatcher.go+peer.go (CLI-side scheduler), internal/cli/daemon.go.
- orca daemon emits slog.Warn deprecation banner on every run (ungated); fires
  R-001 + v0.10-P05 drain-and-stop + v0.10-P14 deletion.
- orca cert and orca node join (mTLS path) emit deprecation warnings; proxmox
  SSH path (the v0.9 replacement) does not warn.
- Add --no-deprecation-warnings global flag on root command (PersistentPreRunE)
  for orca upgrade migrations.
- 12 new daemon/cert/node deprecation tests in internal/cli/daemon_test.go
  (cli coverage 81.9%, warnDeprecated 100%).
- Add DEPRECATED banners to v0.8 sections of ARCHITECTURE.md (verified the
  v0.9 supersession section + Supersession Table from prior turn are present).

Bash tooling gate (grill C-06, C-15, C-16, C-17, C-18):
- scripts/tests/test_helper.bash + example_test.bash — bats framework + helpers.
- scripts/lib/orca-log.sh — slog-compatible JSON logging to syslog (C-17).
- scripts/orca-verify-render.sh — render-contract validator skeleton (C-16).
- scripts/tests/orca-log_test.bash + orca-verify-render_test.bash — 20 bats
  tests total (happy + failure paths per C-15).
- .shellcheckrc — project shellcheck config.
- Makefile: test-bash + lint-bash targets (graceful skip if tools missing);
  wired into test + lint targets.
- internal/emit/contract.go + contract_test.go — versioned JSON render
  contract (orca.emit/v1) between Go emitters and bash appliers (C-16).
- .ciagent/BASH_CAPABILITY_MAP_v0.9.md — maps shipped internal/transport
  capabilities to bash-side equivalents or accepted drops (C-18).
- D-186 recorded in PROJECT.md: bash exempt from Go coverage gate; compensating
  control is bats + shellcheck + shfmt (C-06).

verify-reqs: 90 requirements consistent. Build/test/lint/fmt all green.
20 bats tests pass. Go tests pass. No v0.8 code deleted — only marked deprecated
(deletion deferred to v0.10-P14 per REQ-090 dual-write window).

---ci---
project: orca
phase: P00
milestone: v0.9
status: execute
---/ci---
2026-08-05 16:26:26 +00:00
Jon Chery 11da458883 test(cli): --host-key-fingerprint non-proxmox validation (T02.11, REQ-058)
---ci---
project: orca
phase: 2
milestone: v0.8
status: execute
---/ci---
2026-08-04 12:04:28 +00:00
Jon Chery d66b3b9a0a test(proxmox,cli): end-to-end trust-surface integration tests (T02.10, REQ-058, REQ-059)
---ci---
project: orca
phase: 2
milestone: v0.8
status: execute
---/ci---
2026-08-04 12:04:24 +00:00
Jon Chery 2dcb14377a fix(doctor): TOFU capture-fix parity with bootstrap — v0.6 ship-defect (T02.9)
---ci---
project: orca
phase: 2
milestone: v0.8
status: execute
---/ci---
2026-08-04 11:56:45 +00:00
Jon Chery 13e6762f0f feat(cli): orca node key-reset <node> — local known_hosts reset (T02.8, REQ-059)
---ci---
project: orca
phase: 2
milestone: v0.8
status: execute
---/ci---
2026-08-04 11:51:47 +00:00
Jon Chery 325a5662f4 feat(proxmox): populate Result.HostKeyFingerprint (T02.7, REQ-058)
---ci---
project: orca
phase: 2
milestone: v0.8
status: execute
---/ci---
2026-08-04 11:48:00 +00:00
Jon Chery 8b0cbe10ae fix(proxmox): TOFU capture bug — v0.6 ship-defect first-connect join always failed (T02.6)
---ci---
project: orca
phase: 2
milestone: v0.8
status: execute
---/ci---
2026-08-04 11:46:38 +00:00
Jon Chery bd17e6e114 feat(proxmox): pinnedHostKeyCallback for --host-key-fingerprint (T02.5, REQ-058)
---ci---
project: orca
phase: 2
milestone: v0.8
status: execute
---/ci---
2026-08-04 11:45:53 +00:00
Jon Chery 7cb12c52ce feat(proxmox): HostKeyFingerprint field on Options (T02.4, REQ-058)
---ci---
project: orca
phase: 2
milestone: v0.8
status: execute
---/ci---
2026-08-04 11:38:39 +00:00
Jon Chery 08481d35ce feat(cli): --host-key-fingerprint flag on node join (T02.3, REQ-058)
---ci---
project: orca
phase: 2
milestone: v0.8
status: execute
---/ci---
2026-08-04 11:37:01 +00:00
Jon Chery 00869c6f5b refactor(security): export WriteAtomic (T02.2, REQ-059)
---ci---
project: orca
phase: 2
milestone: v0.8
status: execute
---/ci---
2026-08-04 11:36:42 +00:00
Jon Chery aa3462826b feat(security): SSHFingerprintSHA256 helper (T02.1, REQ-058)
---ci---
project: orca
phase: 2
milestone: v0.8
status: execute
---/ci---
2026-08-04 11:35:59 +00:00
Jon Chery 6408342a7f test(cli): coverage uplift to ≥70% excl daemon.go (T01.6, REQ-057)
Add table-driven rootCmd.Execute() tests for the node, job, cert,
doctor, audit, status, version, and node-capacity subcommand families.
Each test runs against a temp ORCA_HOME and asserts stdout/stderr/exit
via the existing initTestEnv/resetRootFlags/discardWriter helpers
(RESEARCH §1.2). extend resetRootFlags to also reset the per-command
flag-bound globals so tests don't leak state between runs.

daemon.go is excluded from the ≥70% target (documented in node_test.go):
the daemon command starts a long-running mTLS server whose lifecycle is
covered by internal/daemon/server_test.go; only its --pprof flag
registration is verified here (daemon_test.go).

Coverage: go test -cover ./internal/cli → 76.2% overall (78.7% by
-func), which includes daemon.go's untested RunE; the non-daemon files
exceed 70% comfortably. go test -race PASS.

---ci---
project: orca
phase: 1
milestone: v0.8
status: execute
---/ci---
2026-08-04 01:43:38 +00:00
Jon Chery 9727edf4df test(certpaths): first tests, ≥50% toe-hold (T01.10, REQ-057)
---ci---
project: orca
phase: 1
milestone: v0.8
status: execute
---/ci---
2026-08-04 01:13:43 +00:00
Jon Chery e45232f395 test(jobspec): coverage uplift to ≥70% + golden HCL fixtures (T01.8, REQ-057)
---ci---
project: orca
phase: 1
milestone: v0.8
status: execute
---/ci---
2026-08-04 01:12:59 +00:00
Jon Chery 82f3bcacfd test(store): coverage uplift to ≥70% + missing cert_repo_test.go (T01.7, REQ-057)
---ci---
project: orca
phase: 1
milestone: v0.8
status: execute
---/ci---
2026-08-04 01:12:12 +00:00
Jon Chery 7a834357ec test(proxmox): coverage uplift to ≥70% (T01.5, REQ-057)
Extend bootstrap_test.go with FullFlow_IdempotentReRun (two
sequential bootstraps on the same fake SSH server — verifies the
idempotent no-op path end-to-end), FullFlow_NoPasswordInLogs
(asserts the SSH password never appears in slog output, D-031),
FullFlow_ValidateSudoersFails (forceSudoersInvalid flag →
wrapped 'validate sudoers' error), FullFlow_CreateLinuxUserFails
(ProxmoxUser=root exercises the /root home branch in deployPubKey),
DefaultSSHDialer_DialContext_ConnectionRefused (covers the real
defaultSSHDialer.DialContext concrete path), and
SSHSessionRunner_CombinedOutput_NewSessionError (closed-client →
'new session' error branch). Add forceSudoersInvalid knob +
funcDialer helper to ssh_session_test.go.

Coverage: 83.2% → 87.1%. go test -race PASS. No production code
changed (T01.1 sessionRunner seam already in place).

---ci---
project: orca
phase: 1
milestone: v0.8
status: execute
---/ci---
2026-08-04 01:05:12 +00:00
Jon Chery 40906a0697 test(engine): coverage uplift to ≥70% (T01.4, REQ-057)
Add registry_test.go (NEW) covering NodeRegistry Join/Leave/Forget/
List/Get (success + not-found + duplicate), NewNodeRegistry nil-
logger, Audit Record success/error (sqlite-backed via openTestDB
pattern) + NewAudit nil-logger. Extend scheduler_test.go with
MemLocalNode/Capacity (happy + nil), JobSpecScore nil/over-capacity/
fits, JobSpecFits nil, PickNode empty. Extend dispatcher_test.go
with Submit error paths: bad spec, explicit target no-registry,
target peer-not-found, peer-pick missing CA, no peer registry, nil
capacity fallthrough, all-peers-fail PickNode.

Coverage: 65.1% → 88.9%. go test -race PASS. No production code
changed; T01.2 peerDispatcher seam NOT needed (error-path tests
via stubbed LocalExecutor + PeerRegistry reached 89% without it;
httptest.NewTLSServer was not required either since dispatchToPeer
CA-missing and PickNode-fail branches cover the remote path).

---ci---
project: orca
phase: 1
milestone: v0.8
status: execute
---/ci---
2026-08-04 01:05:09 +00:00
Jon Chery 16e4f8a1f2 test(transport): coverage uplift to ≥70% (T01.3, REQ-057)
Add retry_test.go (NEW) covering DefaultRetryPolicy, first-attempt
success, idempotent-verb retry, idempotency-key retry, MaxAttempts
exhaustion, zero-MaxAttempts defaulting, transient+non-idempotent+
no-key bail, ctx-cancel mid-backoff, exponential backoff growth +
cap, and contains() substring helper. Extend idempotency_test.go
with Sweep, empty-key Put/Get, and empty-key WithIdempotencyKey.
Extend handshake_log_test.go with LogHandshakeFromCert happy path
(real x509 cert → fingerprint) and FingerprintOfCert round-trip.

Coverage: 84.6% → 93.0%. go test -race PASS. No production code
changed; no new seams (httptest already covered DispatchClient).

---ci---
project: orca
phase: 1
milestone: v0.8
status: execute
---/ci---
2026-08-04 01:05:03 +00:00
Jon Chery 2786de166d refactor(proxmox): extract sessionRunner seam for testability (T01.1, REQ-057)
---ci---
project: orca
phase: 1
milestone: v0.8
status: execute
---/ci---
2026-08-04 00:51:15 +00:00
Jon Chery d7d6961261 fix(P05): final review fixes — PERSONAS.md body, config --addr precedence, migration 0007 dedup
Audit fix: PERSONAS.md body roster updated for v0.7 (was stale v0.6
content). Review P1-004: daemon --addr now uses cmd.Flags().Changed()
to detect explicit flag, so config listen_addr only applies when --addr
was not explicitly passed (correct flag>env>file>default precedence).
Review P1-001: migration 0007 now dedups existing duplicate serial_hex
rows before creating the UNIQUE index (backward-compat with v0.6 DBs
that accumulated duplicates before the constraint existed).

---ci---
project: orca
phase: 5
milestone: v0.7
status: execute
requirements:
  covered: [REQ-053, REQ-054, REQ-055, REQ-056]
  partial: []
---/ci---
2026-08-04 00:28:48 +00:00
Jon Chery 0b58286ca2 feat(P04): --pprof opt-in on orca daemon (REQ-056, I-308)
Separate *http.Server + *http.ServeMux (AD-024), default disabled.
Operator opts in via --pprof <addr>. WARN logged on startup. All pprof
handlers explicitly registered on dedicated mux (no DefaultServeMux
side-effect). I-308 deferred since v0.2 now implemented. 6 new tests.

---ci---
project: orca
phase: 4
milestone: v0.7
status: verify
requirements:
  covered: [REQ-056]
  partial: []
---/ci---
2026-08-04 00:22:17 +00:00
Jon Chery d9d0beda3b test(P03): coverage uplift — engine/transport/proxmox/audit ≥50% + dispatch.go EOF fix (REQ-055)
94 new tests across 4 packages. Coverage: engine 8.3%→65.1%, transport
26.3%→84.6%, proxmox 5.1%→82.7%, audit 0%→100%. Bug fix: dispatch.go
bytesReadCloser.Read returned fmt.Errorf("EOF") instead of io.EOF —
broke HTTP request body transmission (latent since v0.2 P02).

---ci---
project: orca
phase: 3
milestone: v0.7
status: verify
requirements:
  covered: [REQ-055]
  partial: []
---/ci---
2026-08-04 00:18:58 +00:00
Jon Chery cd07e435d9 feat(P02): HCL config file parsing — internal/config package (REQ-054)
New internal/config package: Config struct (HCL tags), Load(paths...),
MergeOverrides(flags, env) with flag>env>file>default precedence (D-039).
No package-level state (AD-023). --config persistent flag on root command;
daemon uses cfg.ListenAddr when flag at default. 11 config tests + 2 cli tests.

---ci---
project: orca
phase: 2
milestone: v0.7
status: verify
requirements:
  covered: [REQ-054]
  partial: []
---/ci---
2026-08-04 00:09:33 +00:00
Jon Chery 04d9dccd41 fix(P01): register orca cert command tree + cert_repo tests (REQ-053)
The `orca cert` command (ca-init, gen, show, renew, fingerprint) was
fully implemented in internal/cli/cert.go but never registered on
rootCmd — unreachable from the CLI. Added init() registration (AD-022).
Added cert_test.go (regression) + cert_smoke_test.go (e2e). Added
cert_repo_test.go (11 tests) + migration 0007 (UNIQUE serial_hex, I-107).

---ci---
project: orca
phase: 1
milestone: v0.7
status: verify
requirements:
  covered: [REQ-053]
  partial: []
---/ci---
2026-08-04 00:05:10 +00:00
Jon Chery f66472fd37 feat(P03): doctor os + doctor proxmox + audit logging
Extends orca doctor with two new checks (REQ-052):
- doctor os: re-runs OS detection from /etc/os-release, compares to
  stored localhost node's os field. Drift = WARN (re-run orca init);
  match = PASS; missing localhost node = FAIL.
- doctor proxmox: iterates kind=proxmox nodes, SSH-probes each with
  `pveversion` (3s timeout per node, clones Network() pattern).
  Zero proxmox nodes = WARN; reachable = PASS; unreachable = FAIL.

Changes:
- internal/osdetect: new shared package (Detect + ParseID) extracted
  from internal/cli to avoid import cycle (cli + doctor both need it)
- internal/cli/osdetect.go: thin wrapper delegating to osdetect package
- internal/doctor/doctor.go: OS() and Proxmox() checks; All() extended;
  probeProxmoxPVEVersion uses orca SSH key + knownhosts TOFU
- internal/cli/doctor.go: doctor os + doctor proxmox subcommands (--json)
- internal/doctor/doctor_test.go: 5 new tests (OS match/drift/missing,
  proxmox no-nodes/unreachable)

E2E: orca init -> orca doctor shows 6 PASS / 1 WARN (proxmox=none) /
1 FAIL (network=daemon not running). doctor os --json valid.

---ci---
project: orca
phase: 3
milestone: v0.6
status: execute
---/ci---
2026-08-03 19:59:51 +00:00
Jon Chery 797bc2f412 feat(P02): Proxmox SSH join + OrcaOperator role + sudoers
orca node join --type proxmox bootstraps a remote Proxmox VE 8/9 host
via SSH (REQ-050, REQ-051). The password is used only for initial auth;
subsequent access uses the deployed orca SSH key (D-031).

Changes:
- go.mod: add golang.org/x/crypto v0.54.0 (ssh + ssh/knownhosts + ed25519)
  bump x/sys to v0.47.0, add x/term (indirect)
- internal/certpaths: SSHKeyPath, SSHPubPath, KnownHostsPath (D-037)
- internal/security/sshkey.go: GenerateOrLoadSSHKey (Ed25519, PKCS8 PEM,
  0600/0644 modes, idempotent load per D-036)
- internal/proxmox/bootstrap.go: BootstrapProxmox SSH dance:
  1. Generate/load SSH key
  2. SSH dial (password + knownhosts.New TOFU per D-035)
  3. Deploy pubkey to ~orca/.ssh/authorized_keys (idempotent)
  4. useradd -m orca (idempotent)
  5. pveum role add OrcaOperator --privs 'VM.Audit Datastore.AllocateSpace SDN.Use'
  6. pveum user add orca@pam (AD-019: PAM realm, not @pve)
  7. pveum acl modify / -user orca@pam -role OrcaOperator
  8. Write /etc/sudoers.d/orca (AD-020: NOEXEC on pct/qm, no NOEXEC on
     apt-get/dpkg, pvesh EXCLUDED — API execute bypasses NOEXEC)
  9. visudo -cf validation (abort on failure)
  All steps idempotent; audit-logged.
- internal/cli/node.go: --type/--host/--ssh-user/--password/--ssh-port/
  --proxmox-user/--proxmox-role flags; joinProxmox() wires to
  proxmox.BootstrapProxmox + registers node with kind=proxmox, os=pve.
  Password zeroed after use (D-031).
- tests: sshkey generate/load round-trip, idempotency, file modes;
  proxmox sudoers content (NOEXEC/NOPASSWD/pvesh-excluded),
  privilege set, validation; node join flag wiring

---ci---
project: orca
phase: 2
milestone: v0.6
status: execute
---/ci---
2026-08-03 19:55:14 +00:00
Jon Chery 56fcf8b399 feat(P01): orca init full bootstrap + schema 0006
orca init transforms from a bare mkdir into a full single-node cluster
bootstrap. After `orca init`, `orca doctor` passes with zero FAILs
on the bootstrap checks (CA, cert, db, localhost node).

Changes:
- migration 0006: nodes.kind + nodes.os nullable columns (REQ-049)
- model.Node: Kind + OS fields + NodeKind constants (localhost|linux|proxmox)
- NodeRepo: extended Insert/Get/List/Watch/scanNode for kind/os columns
  (NULL -> "" mapping); added GetByName + UpdateLastSeenAndOS helpers
- internal/cli/osdetect.go: detectOS() from /etc/os-release ID= field
  (D-032); fallback to /usr/lib/os-release then "linux"
- internal/cli/init.go: full bootstrap sequence (REQ-047, REQ-048):
  1. MkdirAll namespace dir
  2. store.Open (runs migrations 0001..0006)
  3. security.CAInit (idempotent fast-path)
  4. server cert gen if absent (D-036: skip if present)
  5. detectOS from /etc/os-release
  6. localhost node upsert (insert if new, refresh last_seen+os if exists)
  Idempotent re-run: no duplicate node, no cert regen, id/joined_at preserved
- --json output: full bootstrap summary (namespace, db, ca_fp, cert_fp,
  os, node_id, steps array)
- tests: init idempotency, osdetect parsing (ubuntu/debian/alpine/pve),
  kind/os round-trip, NULL->"" mapping, GetByName, UpdateLastSeenAndOS

E2E smoke test: orca init -> 5 PASS / 0 WARN / 1 FAIL (network=daemon
not running, expected); orca node list shows localhost node (os=ubuntu).

---ci---
project: orca
phase: 1
milestone: v0.6
status: execute
---/ci---
2026-08-03 19:47:59 +00:00
Jon Chery 4bfc246be4 feat(P01): unified namespace root via ORCA_HOME + --system flag
REQ-041: ORCA_HOME is now the single namespace root for all components
  (db, certs, init, daemon). store.Open("") and init command both
  route through certpaths.Dir()/DBPath() instead of hardcoding ~/.orca.
  Backward compatible: empty ORCA_HOME -> ~/.orca.

REQ-042: --system persistent flag on rootCmd sets ORCA_HOME=/root/.orca
  via PersistentPreRunE. Errors on conflict with pre-set ORCA_HOME.

Tests: 7 new tests in namespace_test.go (default, ORCA_HOME override,
  --system sets root, conflict detection, init --json, flag registered).
  Full suite passes (no regressions).

Docs: docs/namespace.md covers default, ORCA_HOME, --system, ORCA_DB,
  resolution order, and path layout tables.

---ci---
project: orca
phase: 1
milestone: v0.5
status: verify
---/ci---
2026-08-03 18:05:01 +00:00
Jon Chery df58bc25a3 docs(milestone): complete scheduling-streaming (v0.3)
---ci---
project: orca
phase: 3
milestone: v0.3
status: complete
requirements:
  covered: [REQ-022, REQ-030, REQ-032]
  partial: []
---/ci---

v0.3 milestone merged to main. Includes all v0.2 work (P08-P10) that
was previously on the milestone branch but not yet merged to main, plus
the v0.3 completion work (iter.Seq streaming + doctor network/db).

v0.2 phases included: P08 (mTLS), P09 (scheduling), P10 (security scan).
v0.3 phases: P0 (pre-execution), P1 (iter.Seq streaming), P2 (doctor),
P3 (final review+ship).

Total: 40 requirements, all complete. No new go.mod dependencies.
Full test suite passes under -race. gofmt + go vet clean.
2026-08-01 20:06:47 +00:00
ciagent 31ccb52114 feat(P08): mTLS daemon + transport + cert CLI + doctor
Wave B/C/D of P01 mTLS implementation.

- internal/audit/audit.go — thin wrapper around engine.Audit for
  cert/handshake events (Action* and Result* constants; REQ-038).
- internal/certpaths/ — extracted path constants out of cli to break
  the cli<->doctor import cycle; cli re-exports the helpers for
  backward compat.
- internal/security/ca.go — public WriteCert/WriteKey helpers (0600
  for keys, 0644 for certs; REQ-033); used by the cert CLI and
  integration test.
- internal/daemon/tls.go — mTLS server with GetCertificate hot-swap
  callback. Plaintext HTTP remains the default for v0.1 compat;
  StartMTLS() flips the server into mTLS mode.
- internal/daemon/server.go — adds mtls *MTLSState field; MTLSActive()
  getter for health endpoints.
- internal/transport/mtls.go — mTLS client with VerifyPeerCertificate
  for pinned peer identity; DialContext for raw TLS.
- internal/transport/handshake_log.go — structured slog helpers for
  handshake ok/fail (REQ-038 fields: event, result, peer, cert_fp).
- internal/cli/cert.go — orca cert {ca-init,gen,show,renew,fingerprint}
  subcommands; file mode enforcement at every entry; redacted cert
  show (REQ-035).
- internal/cli/doctor.go — orca doctor {cert,network,db} subcommands
  (REQ-032); --json output supported.
- internal/cli/node.go — adds --ca-fingerprint to orca node join
  (REQ-026); fails fast on mismatch.
- internal/doctor/doctor.go — 6 checks: cert.ca, cert.server,
  cert.expiry, cert.fingerprint, network stub, db stub.
- internal/doctor/doctor_test.go — happy + sad path coverage.
- internal/security/integration_test.go — end-to-end: CA-init, CSR
  generation, mTLS handshake, mismatch failure, rotation alarm,
  redaction, file mode enforcement.

All tests pass with -race; gofmt -l . clean; go vet ./... clean.

---ci---
project: orca
phase: 8
milestone: v0.2
status: execute
---/ci---
2026-06-03 21:33:41 +00:00
Jon Chery 181cc769e6 feat(P08): CA, CSR, fingerprint, rotation, redact, TLS config + cert repo
Internal CA with CSR join, mTLS 1.3 config builders, rotation alarm,
PEM redaction, and cert inventory schema (REQ-033/034/035/036).

- internal/security/ca.go: CAInit/LoadCA/SignCSR, file mode enforcement
  (ca.crt 0644, ca.key 0600) per REQ-033
- internal/security/csr.go: GenerateCSR with DNS + IP SANs (REQ-036)
- internal/security/fingerprint.go: SHA-256 hex of cert DER
- internal/security/rotation.go: 30d pre-expiry alarm, history pruning
- internal/security/redact.go: PEM private key block stripping (REQ-035)
- internal/security/tls_config.go: TLS 1.3 with AEAD allowlist
- internal/security/certgen_test.go: round-trip + mode + rotation + redact
- internal/store/migrations/0004_certs.sql: cert inventory table
- internal/store/cert_repo.go: CRUD + PruneOlderThan (REQ-025)

---ci---
project: orca
phase: 8
milestone: v0.2
status: execute
---/ci---
2026-06-03 21:18:50 +00:00
cloudinit-bot be9afa2d2c ship: v0.1 Foundation milestone complete (#1) 2026-06-03 20:08:57 +00:00