Jon Chery
fed24b93e9
fix(P1): drop embed build tag — coreci run doesn't need web assets
...
Release / ci (push) Failing after 6m12s
Release / container-orca (push) Has been skipped
Release / container-traefik (push) Has been skipped
The embed build tag requires web/build (SvelteKit SPA) and bin/coreci-func
(Rust sidecar) — both are gitignored generated artifacts not present in
a shallow clone. coreci run only needs the CLI (no web UI), so building
without embed works: assets.go (!embed tag) returns ErrNoEmbeddedAssets
which is only referenced by the server's static asset serving, not by
the run command.
---ci---
project: orca
phase: 1
milestone: v0.16
status: execute
---/ci---
2026-08-12 21:11:56 +00:00
Jon Chery
3be86e6daf
fix(P1): Gitea Actions clone auth + .coreci.yml native format rewrite (REQ-183,184)
...
Release / ci (push) Failing after 5m13s
Release / container-orca (push) Has been skipped
Release / container-traefik (push) Has been skipped
REQ-183: Fix .gitea/workflows/release.yml — the git clone of the private
coreci repo failed because the clone command had no credentials. The
actions/checkout@v4 step only injects auth for the orca repo. Fix: pass
GITEA_TOKEN env to the Install CoreCI step and embed it in the clone
URL (https://cloudinit-bot:${GITEA_TOKEN}@git.cloudinit.dev/ ...).
REQ-184: Rewrite .coreci.yml from the invalid pipelines:/steps:/image:/
commands: format to CoreCI's native jobs:/plugin:/invoke:/vars: format
with a proper DAG (needs:). CoreCI's Pipeline struct only recognizes
jobs:/services:/env: top-level keys — unknown fields are silently dropped
by yaml.Unmarshal, producing an empty Jobs map → zero jobs execute.
The rewrite:
- 8 jobs: go-vet → fan-out (verify-reqs, gosec, govulncheck, gitleaks)
→ build → test → release
- plugin: docker://golang:1.25.12 + invoke: on each job (container path
with shell-isolated fallback — Go is installed on the runner)
- GITEA_TOKEN via vars: with ${{ secrets.GITEA_TOKEN }} (resolved from
env via CoreCI's secret resolver os.Getenv fallback)
- CI_COMMIT_BRANCH (tag name on tag push) and CI_COMMIT_SHA for version
injection — no ${VAR} interpolation in YAML fields (shell expansion
only works inside invoke: via sh -c)
- No apk add (runner is ubuntu, not alpine — uses curl for tool downloads)
- Release job handles duplicate release (ship workflow creates release
first with title+body; coreci run attaches binary assets later via API
fallback if tea releases create fails)
- Release job verifies asset count ≥ 2 (REQ-097 gate C-21) with retry
Root cause: all 87 releases in repo history had zero binary assets
because coreci run never executed any jobs (empty Jobs map from the
invalid format) and the Gitea Actions workflow failed before reaching
coreci run (private repo clone had no credentials).
---ci---
project: orca
phase: 1
milestone: v0.16
status: execute
requirements:
covered: [183, 184]
partial: []
---/ci---
2026-08-12 21:05:21 +00:00
Jon Chery
437908662f
docs(P00): create phase plans — v0.16 release binary asset fix
...
Release / ci (push) Failing after 5m1s
Release / container-orca (push) Has been skipped
Release / container-traefik (push) Has been skipped
Phase 1 plan: two independent file fixes (single wave).
- Task 1.1 (REQ-183): auth the coreci clone in release.yml
- Task 1.2 (REQ-184): rewrite .coreci.yml to CoreCI native jobs: format
9 must-have verification gates defined.
---ci---
project: orca
phase: 0
milestone: v0.16
status: plan
---/ci---
v0.15.0
2026-08-12 21:03:48 +00:00
Jon Chery
1c2843a39d
docs(P00): research findings — v0.16 release binary asset fix
...
Validated root cause against CoreCI source code:
- .coreci.yml uses invalid format (pipelines:/steps:/image:/commands:)
→ CoreCI silently drops unknown fields → empty Jobs map → zero jobs
- Gitea Actions clone of private coreci repo has no credentials
- CoreCI executor chain, env forwarding, secret resolution all
validated against source (run.go, isolated_shell.go, pass_through.go,
github.go, pipeline.go)
---ci---
project: orca
phase: 0
milestone: v0.16
status: research
---/ci---
2026-08-12 21:03:36 +00:00
Jon Chery
82dfe7a941
docs(P00): clarify — v0.16 release binary asset fix decisions
...
7 decisions (D-269..D-275) validated against CoreCI source code:
- D-270: .coreci.yml uses invalid format (pipelines:/steps:/image:/
commands:) — CoreCI silently drops unknown fields → empty Jobs map
- D-272: CI_COMMIT_BRANCH contains tag name on tag pushes (CoreCI
github.go maps GITHUB_REF_NAME → CI_COMMIT_BRANCH)
- D-273: handle duplicate release (ship workflow creates release
first; coreci run attaches assets later via API fallback)
- D-274: shell-friendly jobs (runner is ubuntu, not alpine — no apk)
---ci---
project: orca
phase: 0
milestone: v0.16
status: clarify
---/ci---
2026-08-12 21:03:15 +00:00
Jon Chery
699196f368
docs(init): validate specification — v0.16 release binary asset fix
...
Establish milestone v0.16 to fix the root cause of releases shipping
with zero binary assets. v0.15 added a Gitea Actions workflow but it
never executed successfully due to two compounding bugs (documented in
REQUIREMENTS.md REQ-183, REQ-184). All 87 releases in the repo's
history have zero binary assets — this has never worked.
---ci---
project: orca
phase: 0
milestone: v0.16
status: specify
---/ci---
2026-08-12 21:02:58 +00:00
Jon Chery
61c97c847c
fix(P1): recompute TARBALL after fallback version walk (REQ-132)
...
The fallback walk (REQ-098) reassigns VERSION from the requested
release to the nearest older release carrying a binary asset, but
never recomputed TARBALL (set once at line 106 from the requested
version). The stale tarball name then flowed into:
- grep -F "$TARBALL" SHA256SUMS -> matched nothing (the fallback
release's SHA256SUMS only lists the fallback tarball)
- sha256sum -c - -> empty stdin -> "no properly
formatted checksum lines found" -> REQ-132 refusal
- tar -xzf "${TMPDIR}/${TARBALL}" -> would look for the wrong
filename (download saved under the stale name too)
User-visible symptom (v0.14.2 latest had no asset, fell back to
v0.12.18):
install: verifying checksum...
sha256sum: 'standard input': no properly formatted checksum lines found
install: error: checksum verification failed (REQ-132); refusing to install
Fix: recompute TARBALL immediately after VERSION is reassigned in the
fallback branch, so download/grep/sha256sum/tar all reference the
fallback version's tarball. ASSET_URL and SHA256SUMS_URL were already
correct (derived from the API/ASSET_URL); TARBALL was the only stale
variable.
Reproduced the exact error before the fix; confirmed end-to-end
install succeeds after (orca-v0.12.18-linux-amd64.tar.gz: OK ->
extracting -> installed). Added a bats regression test pinning
--version v0.14.2 and asserting the dry-run "would install" line
references the fallback version (not the stale pinned one).
---ci---
project: orca
phase: 1
milestone: v0.15
status: execute
decisions:
- id: D-001
decision: Recompute TARBALL in the fallback branch immediately
after VERSION is reassigned, so grep/sha256sum/tar use the
fallback version's filename instead of the stale requested
version's.
rationale: Reproduced the exact user error ("no properly formatted
checksum lines found") by running grep -F "$TARBALL" SHA256SUMS
| sha256sum -c with a stale v0.14.2 tarball name against v0.12.18
SHA256SUMS. TARBALL is the only stale variable: ASSET_URL and
VERSION are correctly updated from API output, and SHA256SUMS_URL
derives from ASSET_URL. Single-line fix, minimal blast radius,
preserves the working non-fallback path.
confidence: 0.96
alternatives:
- lazy TARBALL via a function (over-engineering for one stale
assignment)
- move TARBALL= assignment past the fallback block (breaks
find_asset_url which needs the requested version's name
pre-walk)
lessons:
- When a fallback/walk mutates one variable (VERSION), audit every
variable derived from it (TARBALL) for the same mutation. The
user-facing info line at 167 constructed the name inline and
looked correct, masking that the variable itself was stale.
---/ci---
dev
2026-08-10 21:18:24 +00:00
Jon Chery
6f04b22df0
docs(milestone): complete v0.15 CI release pipeline fix
...
Release / ci (push) Failing after 4m57s
Release / container-orca (push) Has been skipped
Release / container-traefik (push) Has been skipped
All 3 requirements (REQ-180..182) complete. Gitea Actions workflow +
kaniko container publishing (no DinD). PAT_TOKEN secret configured.
---ci---
project: orca
phase: 2
milestone: v0.15
status: complete
requirements:
covered: [180,181,182]
partial: []
---/ci---
v0.14.2
2026-08-10 21:01:56 +00:00
Jon Chery
eadf2cc2c5
fix(P1): Gitea Actions workflow + kaniko container publishing (REQ-180,181)
...
Release / ci (push) Failing after 4m55s
Release / container-orca (push) Has been skipped
Release / container-traefik (push) Has been skipped
New .gitea/workflows/release.yml:
- Triggers on push: tags: ['v*'] (deterministic)
- Job 'ci': checkout + install Go + install coreci binary +
coreci run (executes .coreci.yml: validate, build, test, release)
- Job 'container-orca': kaniko executor:debug with --entrypoint
/bin/sh, builds+pushes orca image (no DinD)
- Job 'container-traefik': same, builds+pushes orca-traefik image
(skips if Dockerfile.traefik absent at that tag)
- Uses PAT_TOKEN secret (Gitea reserves GITEA_ prefix)
.coreci.yml:
- Removed container-publish + container-publish-traefik steps
(moved to Gitea Actions — CoreCI's podman executor appends sh -c
which conflicts with kaniko's /kaniko/executor entrypoint)
- Keeps validate/build/test/release (tarball + Gitea release)
scripts/trigger_coreci.sh:
- Added tag ref handling (refs/tags/*) so pre-push hook triggers
CoreCI for tag pushes too (Gitea Actions webhook is secondary)
---ci---
project: orca
phase: 1
milestone: v0.15
status: execute
---/ci---
v0.14.1
2026-08-10 20:59:10 +00:00
Jon Chery
93ac4bda66
docs(P00): clarify+research+plan — v0.15 CI release pipeline
...
Key finding: CoreCI podman executor appends sh -c to step image,
which conflicts with kaniko's /kaniko/executor entrypoint. Container
publishing moves to Gitea Actions workflow (supports entrypoint
override). CoreCI keeps validate/build/test/release (tarball).
---ci---
project: orca
phase: 0
milestone: v0.15
status: plan
---/ci---
v0.14.0
2026-08-10 20:57:55 +00:00
Jon Chery
454040fdd1
docs(init): validate specification — v0.15 CI release pipeline fix
...
3 requirements (REQ-180..182). REQ-182 complete (PAT_TOKEN secret
created via tea). Fix milestone — CI infrastructure, no DinD, kaniko.
---ci---
project: orca
phase: 0
milestone: v0.15
status: specify
---/ci---
2026-08-10 20:55:03 +00:00
Jon Chery
c95bd73e42
docs(milestone): complete v0.14 ingress bootstrap
...
All 9 requirements (REQ-171..179) marked complete. 9 phases shipped
(v0.13.0..v0.13.8). R-024 adopted: traefik as podman container, three
ingress topologies (linux, proxmox native, proxmox floating-IP).
---ci---
project: orca
phase: 8
milestone: v0.14
status: complete
requirements:
covered: [171,172,173,174,175,176,177,178,179]
partial: []
---/ci---
v0.13.8
2026-08-10 20:26:26 +00:00
Jon Chery
ecdba833d9
feat(P7): doctor ingress + docs + integration tests (REQ-177,178,179)
...
New 'orca doctor ingress' command: verifies podman orca-traefik
container running, nft DNAT+SNAT, /etc/traefik/dynamic exists,
step-ca root CA present.
UAT signoff script: replaced assertion 36 (systemd → podman
container), added assertions 40-46 (nft table, DNAT, SNAT, dynamic
dir, step-ca CA, traefik.yml, doctor ingress pass).
docs/ingress.md: R-024 podman traefik section — three topologies,
container config, nft ruleset, doctor ingress, Dockerfile.traefik.
TLS model updated (drop certResolver, tls:{} for v0.14, mTLS v0.15).
ARCHITECTURE.md: v0.14 deltas section — R-024, three topologies,
nft emitter changes, TLS model, migration 0009, new CLI.
Integration tests (tests/ingress_bootstrap_test.go): nft postrouting
+ DNATTarget, priority -10, traefik TLS model (tls:{} no
certResolver), image ref resolution, floating-IP LXC provisioning
commands (pct create with hwaddr/ip/gw/features), MAC generation.
---ci---
project: orca
phase: 7
milestone: v0.14
status: execute
---/ci---
v0.13.7
2026-08-10 20:24:13 +00:00
Jon Chery
6e65eadaa5
feat(P6): proxmox floating-IP LXC ingress + interactive prompt (REQ-176)
...
New internal/proxmox/ingress_lxc.go: ProvisionIngressLXC creates an
Ubuntu LXC named 'ingress' that owns the floating IP (net0
bridge=vmbr0,hwaddr=<mac>,ip=<floating-ip>/<prefix>,gw=<gateway>).
Unprivileged with --features nesting=1,keyctl=1,fuse=1 (research
Topic 3). Installs podman inside, runs orca-traefik container,
applies nft DNAT+SNAT INSIDE the LXC, pushes step-ca root CA.
GenerateRandomMAC: 02:XX:XX:XX:XX:XX for interactive mode (D-261).
Interactive prompting in joinProxmox: when --ingress-mode empty +
!--json, prompt for mode + floating IP + gateway + MAC (auto-
generate + confirm). Validate IP/MAC/gateway/prefix.
Floating-IP routing: calls ProvisionIngressLXC + registers:
1. PVE host as 'proxmox' node (IngressMode=floating-ip)
2. Ingress LXC as 'linux' node (name=ingress, addr=<floating-ip>:8443)
so orca job run pushes traefik dynamic config to it.
---ci---
project: orca
phase: 6
milestone: v0.14
status: execute
---/ci---
v0.13.6
2026-08-10 20:19:47 +00:00
Jon Chery
1b7aac71f6
feat(P5): proxmox native ingress mode — LXC + podman traefik (REQ-175)
...
Add --ingress-mode flag (native default, floating-ip) + --floating-ip,
--gateway, --mac, --net-prefix flags to 'orca node join'.
Native mode (default): provision an unprivileged LXC with
--features nesting=1,keyctl=1,fuse=1 (research Topic 3), install
podman inside it, run orca-traefik container. nft on PVE host DNATs
to the LXC bridge IP (DNATTarget parameterization, C-55: discover
LXC IP before first nft apply, no downtime window).
LXC provisioning: deterministic VMID 200, hostname orca-traefik,
--onboot 1, 2GB RAM. Idempotent (C-53: command -v podman check).
podman-restart.service enabled inside LXC (research Topic 6).
step-ca root CA pushed into LXC via pct exec heredoc.
traefik static config rendered + written into LXC.
nft ruleset rendered with DNATTarget=LXC-IP + applied on PVE host.
Migration 0009_ingress_mode.sql (C-59: NOT 0007 — already taken by
certs_serial_unique). ALTER TABLE nodes ADD COLUMN ingress_mode.
IngressMode field added to model.Node + set on proxmox node record.
---ci---
project: orca
phase: 5
milestone: v0.14
status: execute
---/ci---
v0.13.5
2026-08-10 20:16:40 +00:00
Jon Chery
ea42a17474
feat(P4): linux node join remote ingress bootstrap (REQ-174)
...
Add ingress.BootstrapRemoteIngress: renders+writes traefik static
config, renders+writes+applies nft DNAT/SNAT, pushes step-ca root CA,
ensures podman traefik container — all over SSH exec. Uses a heredoc-
based remoteWriteFile with a random delimiter (F9 injection guard).
Wired into linux/bootstrap.go Step 4d, replacing the standalone
EnsureTraefikContainerRemote call with the full ingress stack.
C-60: uses certpaths.CACertPath() (not CAPath).
C-58: mounts host-side traefik.yml (preserves REQ-100 opt-out).
C-55: pre-creates nft table before nft -f.
---ci---
project: orca
phase: 4
milestone: v0.14
status: execute
---/ci---
v0.13.4
2026-08-10 20:11:32 +00:00
Jon Chery
5013209e31
feat(P3): nft SNAT+DNAT + orca init ingress bootstrap (REQ-173)
...
nft emitter (internal/emitter/nft.go):
- Add DNATTarget field (C-51: validated via net.ParseIP; injection
guard). Default 127.0.0.1; proxmox native uses LXC bridge IP.
- Add EnableSNAT field (default true for zero-value config).
- Add postrouting masquerade chain (research Topic 1):
ip saddr 127.0.0.0/8 oifname != lo masquerade
- Shift input/forward priority from filter (=0) to -10 (research
Topic 2: pve-firewall coexistence — avoids same-priority undefined
evaluation order).
internal/ingress/bootstrap.go (new):
- BootstrapLocalIngress: mkdir dirs, push step-ca root CA (C-60:
certpaths.CACertPath not CAPath), render+write traefik static
config (C-58: preserves traefik-on-public-ip opt-out), render+
write+apply nft ruleset, pre-create table (C-55: avoids first-
apply flush-table error), ensure podman container. All non-fatal.
init.go: Step 4d now calls ingress.BootstrapLocalIngress (R-024).
doctor_nft.go: assert postrouting masquerade + priority -10.
Tests: nft_test.go — DNATTarget substitution, invalid DNATTarget
rejection (C-51), EnableSNAT=false omits postrouting, priority -10.
---ci---
project: orca
phase: 3
milestone: v0.14
status: execute
---/ci---
v0.13.3
2026-08-10 20:09:26 +00:00
Jon Chery
dea472f443
feat(P2): podman traefik reconciler + TLS model fix (REQ-172)
...
Replace internal/traefik/install.go binary+systemd installer with a
podman-container reconciler (R-024). The reconciler is idempotent:
inspect → start-if-stopped → pull+run-if-absent.
Container run flags (research-validated):
--restart=unless-stopped (not always; research Topic 6)
--network host (binds 127.0.0.1:8080/8443 on host/LXC loopback)
-v /etc/traefik/traefik.yml:ro (overrides baked default; C-58)
-v /etc/traefik/dynamic:ro (orca writes atomically via SSH-push)
-v /etc/orca/step-ca-root.crt:ro (future mTLS; v0.14 uses tls:{})
No :Z SELinux flag (research Topic 7)
C-50: ensurePodmanLocal/Remote installs podman if absent.
C-57: removeLegacySystemdUnitLocal/Remote stops+disables+removes
the v0.13 orca-traefik.service + /usr/local/bin/traefik before
starting the podman container (upgrade path).
upgrade.go cutover rewritten to use the reconciler.
TLS model fix (research Topic 4): drop certResolver: orca from
dynamic config (traefik v3.3 only supports acme/tailscale resolvers,
not CA-file-based). Emit tls: {} instead. Real mTLS via dynamic
tls.certificates + clientAuth.caFiles deferred to v0.15 (grill
G-003, confidence 0.55 < 0.60).
Callsites updated:
init.go: installTraefikLocal → ensureTraefikContainerLocal
linux/bootstrap.go: traefik.InstallRemote → EnsureTraefikContainerRemote
proxmox/bootstrap.go: same
traefik_install.go: wrapper updated
Tests: internal/traefik/install_test.go (new) — ImageRef, podmanRunArgs,
container-running/stopped/absent paths, legacy systemd removal (C-57).
---ci---
project: orca
phase: 2
milestone: v0.14
status: execute
---/ci---
v0.13.2
2026-08-10 20:04:20 +00:00
Jon Chery
dccdb746ea
feat(P1): orca-traefik container image + release pipeline (REQ-171)
...
Dockerfile.traefik: extends traefik:v3.3.0 with baked default
static config (entrypoints 127.0.0.1:8080/8443/8081, file provider
watching /etc/traefik/dynamic, json log). Host-side traefik.yml
mounted :ro at runtime to override baked default (preserves
traefik-on-public-ip opt-out, REQ-100, C-58).
No certificatesResolvers — traefik v3.3 only supports acme/tailscale
(research finding). tls: {} in dynamic config for v0.14; real mTLS
deferred to v0.15 (grill G-003, confidence 0.55 < 0.60).
release.sh: second docker block builds+pushes orca-traefik image.
.coreci.yml: container-publish-traefik step mirrors container-publish.
Verified: docker build -f Dockerfile.traefik . succeeds; image starts
traefik v3.3.0 with --configFile=/etc/traefik/traefik.yml.
---ci---
project: orca
phase: 1
milestone: v0.14
status: execute
---/ci---
v0.13.1
2026-08-10 18:30:37 +00:00
Jon Chery
080919fde6
chore(P00): phase 0 complete — checkpoint update
...
---ci---
project: orca
phase: 0
milestone: v0.14
status: complete
---/ci---
2026-08-10 18:27:10 +00:00
Jon Chery
3551b37ac0
docs(P00): grill + plan revision — v0.14 binding conditions
...
Grill verdict: RETHINK (0.45) → revised plan addresses all 12
binding conditions (C-50..C-61):
- C-50: install podman if absent (linux/lead)
- C-51: DNATTarget validation (nft injection guard)
- C-53: apt-get idempotency (command -v podman check)
- C-54: offline-first tension documented (podman pull exception)
- C-55: native-mode nft single-apply (discover LXC IP first)
- C-56: MAC collision check against registry
- C-57: v0.13→v0.14 upgrade path (remove legacy systemd+binary)
- C-58: mount static config from host (preserve REQ-100 opt-out)
- C-59: migration 0009 (not 0007)
- C-60: certpaths.CACertPath() (not CAPath())
- C-61: --restart=unless-stopped, omit :Z
- C-62/G-003: mTLS deferred to v0.15 (confidence 0.55 < 0.60)
---ci---
project: orca
phase: 0
milestone: v0.14
status: grill
---/ci---
v0.13.0
2026-08-10 18:26:33 +00:00
Jon Chery
65e50e465b
docs(P00): grill v0.14 — red-team review, RETHINK verdict
...
Adversarial review of PLAN_v0.14.md across 9 axes. Verdict: RETHINK
(confidence 0.45). The research foundation is strong but the plan
diverges from it and from the codebase in load-bearing ways.
4 binding decisions (G-001..G-004):
- G-001: migration number 0009 (not 0007 — already taken by certs)
- G-002: omit :Z flag (contradicts CLARIFY D-258 + REQ-172)
- G-003: wire real mTLS now (scope expansion — plan has no such phase)
- G-004: P2 T6 must remove legacy systemd unit + binary on upgrade
12 binding conditions (C-50..C-61) + 14 phase challenges (PC-01..14).
1 escalation (E-001): G-003 mTLS direction undetermined in plan.
Key findings:
- F1.1: migration 0007 collision (BLOCKER)
- F1.2: certpaths.CAPath() does not exist (compile BLOCKER)
- F2.2: REQ-100 traefik-on-public-ip opt-out regressed by baked image
- F5.1: no v0.13 -> v0.14 upgrade path (BLOCKER)
- F7.2: podman pull violates R-001 offline-first
---ci---
status: grill
milestone: v0.14
binding-decisions:
- G-001: migration 0009_ingress_mode.sql (not 0007)
- G-002: omit :Z, use :ro on both mounts
- G-003: wire real mTLS now (scope expansion, plan must add phase)
- G-004: P2 T6 must remove legacy systemd unit + binary on upgrade
escalations:
- E-001: G-003 mTLS direction chosen but plan has no phase for it (conf 0.55)
verdict: rethink
confidence: 0.45
2026-08-10 18:24:32 +00:00
Jon Chery
0e7ee4f324
docs(P00): create phase plans — v0.14 ingress bootstrap
...
9 phases (P0+P1..P7+P8 final). Plan incorporates research findings:
nft postrouting masquerade scoped to 127.0.0.0/8, pve-firewall
priority shift to -10, LXC fuse=1 feature, traefik TLS model
change (drop certResolver, use dynamic tls.certificates), podman
--restart=unless-stopped + podman-restart.service, omit SELinux :Z.
---ci---
project: orca
phase: 0
milestone: v0.14
status: plan
---/ci---
2026-08-10 18:13:59 +00:00
Jon Chery
b925fda3aa
docs(P00): research findings — v0.14 ingress bootstrap
...
7 research topics: nft SNAT masquerade syntax, pve-firewall
coexistence (priority collision fix), podman-in-LXC (fuse=1
requirement), traefik v3.3 TLS model (certResolver does not exist —
use dynamic tls.certificates), pct create floating-IP syntax, podman
restart persistence (podman-restart.service), SELinux :Z omission.
Key findings that change the plan:
- nft postrouting: ip saddr 127.0.0.0/8 oifname != lo masquerade
- nft first-apply: pre-create table before nft -f
- pve-firewall: shift orca input/forward to priority -10
- LXC features: nesting=1,keyctl=1,fuse=1 (fuse=1 for fuse-overlayfs)
- traefik TLS: drop certResolver: orca, use dynamic tls.certificates
- podman: --restart=unless-stopped + enable podman-restart.service
- volumes: omit :Z flag, use :ro on both mounts
---ci---
project: orca
phase: 0
milestone: v0.14
status: research
---/ci---
2026-08-10 18:12:59 +00:00
Jon Chery
9853aee589
docs(P00): clarify — v0.14 ingress bootstrap decisions
...
9 decisions (D-255..D-263) resolved: podman container model,
--network host, mounted step-ca CA, dynamic config volume mount,
floating-IP LXC registered as linux node, IngressMode on model.Node,
MAC generation rules, native-mode DNAT target = LXC IP, LXC nesting.
---ci---
project: orca
phase: 0
milestone: v0.14
status: clarify
---/ci---
2026-08-10 18:08:26 +00:00
Jon Chery
5e0b899f1a
docs(init): validate specification — v0.14 ingress bootstrap
...
---ci---
project: orca
phase: 0
milestone: v0.14
status: specify
---/ci---
2026-08-10 18:07:55 +00:00
Jon Chery
0424f8ce02
feat(init): interactive remote pre-staging via ssh-copy-id
...
orca init now interactively prompts for remote host addresses and runs
ssh-copy-id automatically (password prompt passes through to the
operator). This makes orca init the single entry point — no manual
pre-staging of SSH keys required.
- Interactive: enter host addresses (one per line, empty line to finish)
- ssh-copy-id deploys the orca public key to each host
- Skipped in --json mode (non-interactive)
- Idempotent: re-running init can stage additional hosts
Also fixed: install.sh defaults to /usr/local/bin (on PATH for all users).
Non-root without sudo falls back to ~/.local/bin + auto-adds to .bashrc.
2026-08-10 17:37:42 +00:00
Jon Chery
5600531bd7
fix(install): default to /usr/local/bin (on PATH for all users)
...
Root or writable /usr/local/bin: install there (no PATH edits needed).
Non-root without sudo: fall back to ~/.local/bin + auto-add to .bashrc.
This eliminates the 'NOTE: not on your PATH' message for the common case.
2026-08-10 17:22:42 +00:00
Jon Chery
d324939699
fix: PVE role/user idempotency + init pre-staging instructions
...
- createPVERole: use grep -qF + fallback to pveum role mod (was broken
by single-quote-in-grep pattern: grep -q '^'OrcaOperator'')
- createPVEUser: same idempotency fix (grep -qF + fallback to mod)
- orca init: prints ssh-copy-id instructions with the orca public key
path after generating the SSH keypair
- docs/uat.md: removed manual pre-staging (ssh-keygen, ssh-copy-id
with operator key, host-key fingerprint pinning). orca init handles
key generation; node join uses the orca key by default; TOFU is
automatic. Updated node join examples to not pass --ssh-key or
--host-key-fingerprint.
---ci---
project: orca
status: fix
---/ci---
2026-08-10 17:07:30 +00:00
Jon Chery
00efe25ce4
fix(release): clean release assets + SHA256SUMS URL lookup fix
2026-08-10 16:56:17 +00:00
Jon Chery
1ad6780df1
fix(release): install.sh asset matching + SHA256SUMS + Dockerfile 1.25.12
...
install.sh:
- find_asset_url now matches by asset NAME (python3 JSON parse), not
URL path — Gitea attachment URLs are opaque UUIDs that don't contain
the tarball name. This was the root cause of the v0.12.18 install
failure (asset existed but install.sh couldn't find it).
- find_asset_in_releases walks recent releases by asset name and
returns both URL + version for the fallback walk.
- Handles 404 (tag without release) gracefully via fallback walk.
Dockerfile:
- golang:1.25 -> golang:1.25.12 (go.mod requires 1.25.12; the Docker
image was using patch 0, causing `go mod download` to fail with
"go.mod requires go >= 1.25.12 (running go 1.25.10)")
coreci.yml:
- All golang:1.25 images -> golang:1.25.12
- Release pipeline: add SHA256SUMS generation (sha256sum tarball)
- Release pipeline: attach SHA256SUMS alongside tarball
- Release pipeline: verify assets are actually attached after
tea releases create (REQ-097 gate C-21); auto-attach via API if
tea failed silently
release.sh:
- Add SHA256SUMS generation (sha256sum tarball > SHA256SUMS)
---ci---
project: orca
milestone: v0.12.18
phase: release-fix
status: complete
---/ci---
2026-08-10 16:54:11 +00:00
Jon Chery
7dc7980d74
docs(E): UAT docs + signoff script fixes + pve-ct example (REQ-170)
...
- docs/uat.md: remove --rp-id from cluster seal (belongs to auth init-idp);
fix secrets set syntax (positional KEY=value, not --value flag); add
auth init-idp step; add troubleshooting section (ORCA_HOME, known_hosts,
Traefik, SSH, job list, Proxmox runtime)
- scripts/uat-signoff.sh: fix 6 assertions (#04 SKIP if no linux, #08
check node field in JSON, #14 verify file exists first, #27 fix pprof
grep, #34/35 already passing); add 3 new assertions (#36 traefik
installed, #37 known_hosts exists, #38 master_key exists); total 38
- examples/full-stack/web-app-lxc.md: pve-ct jobspec variant for Proxmox
LXC container deployment
---ci---
project: orca
milestone: v0.12.18
phase: E
status: complete
requirements:
covered: [170]
---/ci---
v0.12.18
2026-08-10 16:37:57 +00:00
Jon Chery
790109ea24
feat(D): capacity auto-discovery + partial updates + ACL debug + UX (REQ-168,169)
...
- node capacity set: partial updates (only set dimensions passed;
read-modify-write on existing row)
- node capacity auto [percentage]: SSH to node, discover CPU (nproc),
memory (/proc/meminfo), disk (df), multiply by percentage (default 75)
- ACL check --verbose: prints resolved ACLPath + all entries + identity
- job list UX: short 8-char IDs, NODE column, conditional EXIT (- for
non-terminal statuses)
---ci---
project: orca
milestone: v0.12.18
phase: D
status: complete
requirements:
covered: [168, 169]
---/ci---
v0.12.17
2026-08-10 16:33:27 +00:00
Jon Chery
64cbbd543e
feat(C): remote deployment correctness — PVE runtime, DB record, Traefik (REQ-166)
...
- deployRemote branches on runtime: pve-ct/pve-vm on proxmox nodes
invoke runtime.Registry.Prepare+Start (creates LXC/VM via SSH);
process runtime on linux nodes uses systemd emitter; process on
proxmox is rejected with clear error
- deployRemote emits Traefik dynamic config when spec has ports
(TraefikEmitter.Render + SSH-push to /etc/traefik/dynamic/)
- model.Job: added Node field so job list --json reports deployed node
- job run remote case: inserts model.Job + alloc_history after
deployRemote succeeds (job list and job stop now work for remote)
- --target name lookup: legacy dispatcher tries NodeID match
- job list UX: short 8-char IDs, NODE column, conditional EXIT (- for
non-terminal statuses)
- emitter/traefik.go: directory provider (was single file), pve-ct/pve-vm
registered in RegisterTraefik
- runtime/pve.go: shellQuote for image, idempotent create check
---ci---
project: orca
milestone: v0.12.18
phase: C
status: complete
requirements:
covered: [166]
---/ci---
v0.12.16
2026-08-10 16:21:50 +00:00
Jon Chery
16440a89f2
feat(B): Traefik deployment to all nodes during init/join (REQ-165, REQ-167)
...
- internal/traefik/install.go: shared Traefik installer (download +
systemd unit + dynamic dir). Default v3.3.0, configurable.
- orca init: installs Traefik on localhost (idempotent, non-fatal
if offline)
- proxmox bootstrap: installs Traefik on PVE host + downloads LXC
template (default ubuntu-24.04, --lxc-template flag)
- linux bootstrap: installs Traefik on worker
- emitter/traefik.go: directory provider (was single file);
register pve-ct/pve-vm in RegisterTraefik
- --lxc-template flag on node join (default ubuntu-24.04)
---ci---
project: orca
milestone: v0.12.18
phase: B
status: complete
requirements:
covered: [165, 167]
---/ci---
v0.12.15
2026-08-10 16:09:48 +00:00
Jon Chery
a6ceb13491
fix(A): bootstrap plumbing — init creates SSH key + known_hosts + master key (REQ-164)
...
Fixes UAT issues 1, 8, 9, 12C, 13:
- orca init: generates SSH keypair (GenerateOrLoadSSHKey), creates
empty known_hosts (0600), generates master key (GenerateMasterKey +
SaveMasterKey). All were missing from runInit — every downstream
SSH/secrets/cluster operation failed on a fresh init.
- TOFUHostKeyCallbackPath: creates known_hosts file if it doesn't exist
(defense-in-depth alongside init)
- Linux bootstrap: replaces buggy inline TOFU with
proxmox.TOFUHostKeyCallbackPath (first-connect key capture works)
- --type flag help: includes "linux" (was "localhost or proxmox")
- doctor network: SSH exec probe (was HTTP /healthz to :8443 — no
daemon in SSH-push model R-001)
---ci---
project: orca
milestone: v0.12.18
phase: A
status: complete
requirements:
covered: [164]
---/ci---
v0.12.14
2026-08-10 16:02:19 +00:00
Jon Chery
c0ba30824e
chore(P13): final review + audit — v0.13 milestone complete
...
All 15 v0.13 requirements (REQ-149..REQ-163) marked complete.
All 14 phases shipped (P0..P13, tags v0.12.0..v0.12.12).
163 requirements consistent with roadmap (verify-reqs passes).
ROADMAP.md marks v0.13 COMPLETE.
All Go tests pass. Build clean.
Milestone deliverables:
- R-022: orca job run deploys to remote nodes via scheduler+emitter+SSH-push
- R-023: zero-trust enforcement wired (acl.Check on every request path)
- 11 injection vectors fixed
- Go toolchain bumped to 1.25.12 (24 stdlib vulns closed)
- Audit chain race fixed (BEGIN IMMEDIATE)
- Concurrency safety (SQLite busy_timeout, flock, cache invalidation)
- Transport safety (typed errors, IPv6, SSH timeouts, signal handler)
- Migration safety (job stop real systemctl, backup+atomic-rename)
- Observability (7 new metrics, security headers)
- Doc drift fixed (README, cli.md, CHANGELOG, verify-reqs regex)
- --type linux SSH-join for Ubuntu workers
- docs/uat.md (3-host topology, 35-claim matrix)
- scripts/uat-signoff.sh (35 assertions, idempotent, v1.0 gate)
- scripts/uat-smoke.sh (13 CI assertions)
v1.0.0 production-ready tag stays deferred for UAT signoff.
Operator runs scripts/uat-signoff.sh, pastes output, CI agent cuts v1.0.0.
---ci---
project: orca
phase: 13
milestone: v0.13
status: complete
requirements:
covered: [149,150,151,152,153,154,155,156,157,158,159,160,161,162,163]
---/ci---
v0.12.13
2026-08-10 14:37:33 +00:00
Jon Chery
52e17aefbf
feat(P12): --type linux SSH-join + UAT plan + signoff script (REQ-161..163)
...
--type linux (REQ-161):
- internal/linux/bootstrap.go: SSH bootstrap for generic Linux workers
(orcas pubkey, system user, drift-events dir; no PVE role/sudoers)
- internal/cli/node.go: joinLinux function + --type linux dispatch
- peer-setup kept as documented fallback
UAT plan (REQ-162):
- docs/uat.md: 3-host topology (lead Ubuntu + pve01 Proxmox + worker01
Ubuntu), 22 step-by-step commands, 35-claim matrix, Proxmox
prerequisite + alternative 3xUbuntu path (C-48), signoff procedure
UAT signoff script (REQ-163, C-47):
- scripts/uat-signoff.sh: 35 idempotent read-only assertions, exit 0
iff all pass. Includes 4 critical-path assertions: job deploys to
remote, ACL deny-by-default, seal/unseal round-trip, OIDC health
- scripts/uat-smoke.sh: 13 CI-tested pure-CLI assertions for .coreci.yml
Tests: node join --type linux test, fingerprint test updated, smoke
test all 13 pass.
---ci---
project: orca
phase: 12
milestone: v0.13
status: complete
requirements:
covered: [161, 162, 163]
---/ci---
v0.12.12
2026-08-10 14:33:29 +00:00
Jon Chery
b6dd86fdf3
docs(P11): doc drift round 2 — README, cli.md, CHANGELOG, verify-reqs (REQ-160)
...
- README: status banner v0.12+v0.13, latest tag v0.12.10, subcommand
table expanded (auth/nft/peer-setup/secrets rotate-master), "mTLS by
default" corrected to "SSH-push canonical", docs table updated
- docs/cli.md: complete rewrite (521->1465 lines), all ~40 subcommands
- CHANGELOG: regenerated from git log (v0.11.29..HEAD)
- help text: job run HCL->markdown, job stop daemon->SSH-push
- docs/security-runbook.md: expanded to match P05 reality (seal/unseal,
doctor audit/modes/oidc, incident response)
- docs/webauthn.md: added auth register (P06)
- docs/namespace.md: added inherit + set-constraint
- internal/proxmox/bootstrap.go: comments password->key auth
- internal/cli/status.go: deprecation warning
- scripts/verify-docs.sh + make verify-docs: cli.md <-> orca --help
- cmd/verify-reqs/main.go: fix bold-format regex (was bypassing v0.12)
+ case-insensitive status matching
- .ciagent/REQUIREMENTS.md: v0.12 REQs marked complete
- .ciagent/ROADMAP.md: v0.12 bolded COMPLETE
---ci---
project: orca
phase: 11
milestone: v0.13
status: complete
requirements:
covered: [160]
---/ci---
v0.12.11
2026-08-10 14:18:27 +00:00
Jon Chery
ed91d68fbf
feat(P10): observability expansion — metrics + security headers (REQ-159)
...
New metrics:
- orca_jobs_running / orca_jobs_failed / orca_jobs_complete (gauges)
- orca_audit_chain_head (gauge, chain integrity)
- orca_drift_events_total, orca_ssh_errors_total (counters)
- orca_txn_apply_total, orca_txn_rollback_total (counters)
- orca_acl_denials_total (counter)
Security headers on metrics + healthz endpoints:
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY
New file: docs/metrics.md (Prometheus reference + scrape config)
---ci---
project: orca
phase: 10
milestone: v0.13
status: complete
requirements:
covered: [159]
---/ci---
v0.12.10
2026-08-10 13:44:04 +00:00
Jon Chery
531b36924c
fix(P09): migration + operational safety — job stop, retention, logs cap (REQ-158)
...
- job stop: real systemctl stop via SSH (was DB-only soft stop)
resolves node from alloc_history or --peer flag
- doctor db-retention: row count check for jobs/tasks/audit_log
warns at 100k rows, suggests backup + cleanup
- logs --lines: cap at 50000 (default 1000); --since upper bound 7d
prevents OOM from unbounded journalctl
- cache DB mode 0600 (was 0644; matches store.Open)
- upgrade cutover: backup file + atomic rename (was sed -i)
rollback restores from backup on failure
Tests: job stop SSH, DB retention warning, logs lines cap, cache mode,
cutover backup-restore + atomic rename.
---ci---
project: orca
phase: 9
milestone: v0.13
status: complete
requirements:
covered: [158]
---/ci---
v0.12.9
2026-08-10 13:37:28 +00:00
Jon Chery
3a3ea74d76
fix(P08): transport + SSH safety — typed errors, IPv6, timeouts, signal (REQ-157)
...
- transport.IsTransient: typed sentinels (ErrTransient/ErrPermanent) +
standard net.Error/io errors.Is; substring matching removed
- sshpush.isTransient: same typed-error classification
- rotateSSHKeys: 2-phase atomic swap (stage peers -> swap local ->
verify -> cleanup old); no more partial-result window
- known_hosts: dial() reads stored field (was reading v0.8 path directly)
- IPv6: net.JoinHostPort in proxmox SSH dial + drain splitHostPort
- SSH timeouts: context.WithTimeout on peer-setup, drift, txn rollback,
job restart (default 2m)
- verifyCutover: orca CA pool TLS config (was default http.Client)
- OIDC callback: ReadHeaderTimeout 5s (slowloris defense)
- root Execute: signal.NotifyContext for SIGINT/SIGTERM (clean exit
for non-watch commands)
Tests: typed-error classification table, IPv6 JoinHostPort, signal
handler context cancellation.
---ci---
project: orca
phase: 8
milestone: v0.13
status: complete
requirements:
covered: [157]
---/ci---
v0.12.8
2026-08-10 13:11:07 +00:00
Jon Chery
0358efe95b
fix(P07): concurrency safety — SQLite, flock, cache, atomic writes (REQ-156)
...
- SQLite busy_timeout(5000) + SetMaxOpenConns(1) on all 4 DSNs
- secrets file flock (concurrent set on same ns no longer loses data)
- upgrade lock file (refuse concurrent orca upgrade)
- backup lock file (refuse concurrent backup)
- cache invalidation by writes (read-after-write consistency)
- Executor.Run mutex scope fix (hold only for DB inserts)
- ns create/inherit/set-constraint atomic writeNSMdAtomic
- writeCurrentLead + rotateSSHKeys atomic
- consolidate 3 writeAtomic impls onto security.WriteAtomic
- WebAuthn session stores guarded with sync.Mutex
Tests: concurrent secrets set, upgrade lock rejection, cache
read-after-write, WebAuthn session thread-safety (pass under -race).
---ci---
project: orca
phase: 7
milestone: v0.13
status: complete
requirements:
covered: [156]
---/ci---
v0.12.7
2026-08-10 12:27:05 +00:00
Jon Chery
978334a4bc
feat(P06): auth init-idp real + auth register + doctor oidc (REQ-155)
...
Implements the v0.12 R-021 load-bearing change's working IdP path:
- orca auth init-idp: renders Dex config + systemd unit + Traefik route
(atomic deploy, RP ID from --rp-id, C-38)
- orca auth register: opens browser to WebAuthn registration page
- loadOIDCConfig: config-file loading (oidc block + cluster_domain),
falls back to flags + env vars
- orca doctor oidc: health check (systemctl is-active + .well-known)
- config.go: OIDCConfig block + ClusterDomain field
- markdown.go: oidc block parsing in config frontmatter
---ci---
project: orca
phase: 6
milestone: v0.13
status: complete
requirements:
covered: [155]
---/ci---
v0.12.6
2026-08-10 11:55:01 +00:00
Jon Chery
9e832387c6
feat(P05): seal/audit CLI + chain race fix + key zeroing (REQ-154)
...
New CLI commands:
- orca cluster seal: OIDC/CA-derived seal + Shamir 3-of-5 shards
- orca cluster unseal: OIDC/CA unseal + --recovery Shamir path
- orca doctor audit: VerifyChain + chain head report
- orca doctor modes: EnforceFileModes across ORCA_HOME
Fixes:
- audit hash-chain race: Append uses BEGIN IMMEDIATE transaction
(concurrent appends no longer corrupt tamper-evidence)
- secrets rotate-master: re-seals to OIDC on sealed clusters
(was writing raw key, docstring claimed re-seal)
- key zeroing: ZeroKey helper + defer after master/namespace key use
(defense-in-depth against pprof heap extraction)
- store.Open: busy_timeout(5000) pragma (concurrent writers wait)
Tests: 18 new test functions (seal round-trip, Shamir recovery, doctor
audit tamper detection, doctor modes 0644 rejection, concurrent append
chain integrity, rotate-master re-seal, key zeroing).
---ci---
project: orca
phase: 5
milestone: v0.13
status: complete
requirements:
covered: [154]
---/ci---
v0.12.5
2026-08-07 21:06:39 +00:00
Jon Chery
5232fcb808
fix(P04): wire ACL enforcement + WebAuthn reg auth + audit actor (REQ-153)
...
R-023: Zero-trust enforcement operationally wired.
ACL enforcement (C-45 staged rollout):
- acl.Check wired into all 5 daemon handlers (dispatch/jobs/nodes/tasks)
- health endpoints exempt (liveness probes not gated)
- ACL log-only mode default (config acl.enforce=false); enforce after
bootstrap ACL verified
- sshpush auth: ORCA_OIDC_TOKEN validated against JWKS before apply
- txn apply: Authorize hook validates OIDC token before running pull
- acl.json mode 0600 (was 0644)
- flock on acl.json for concurrent grant/revoke
- bootstrap ACL: init grants cluster-admin to orca-admins group + SVID
Audit actor identity:
- currentActor reads OIDC sub from credentials.json (was hardcoded "cli")
- threaded through all audit.Record calls via context
WebAuthn registration auth:
- BeginRegistration/FinishRegistration require authenticated session
- fail-closed 401 when no authFunc configured
New files: internal/daemon/acl.go, internal/cli/authactor.go,
internal/engine/actor.go, internal/identity/authtoken.go,
internal/sshpush/auth.go, internal/txn/auth_test.go
---ci---
project: orca
phase: 4
milestone: v0.13
status: complete
requirements:
covered: [153]
---/ci---
v0.12.4
2026-08-07 20:33:39 +00:00
Jon Chery
cf3d98eb2b
feat(P03): wire scheduler into job run + fix jobspec parser (REQ-151, REQ-152)
...
R-022: orca job run now deploys to remote nodes via scheduler -> emitter
-> SSH-push. Local exec fallback only when no remote nodes registered.
jobspec parser (REQ-152):
- schedule: and timeout: now parsed (were silently dropped)
- DaemonSet Count no longer defaults to 1 (was breaking DaemonSet)
- restart: policy translated to systemd Restart=/StartLimitBurst
- job lint: advisory warnings for cron/health/update/affinity (honest)
scheduler wiring (REQ-151, C-44):
- new internal/cli/job_dispatch.go: dispatchDecision + deployRemote
- scheduler.Schedule evaluates constraints/capacity/affinity
- --target overrides scheduler (manual pinning)
- local fallback only when len(ready non-localhost nodes)==0
- C-44: SSH-push failure returns error (no silent local fallback)
- systemd-analyze verify on rendered unit before deploy
Tests: 22 new test functions covering scheduler, parser, C-44, local
fallback, target override, systemd-analyze skip, restart directives.
---ci---
project: orca
phase: 3
milestone: v0.13
status: complete
requirements:
covered: [151, 152]
---/ci---
v0.12.3
2026-08-07 19:59:31 +00:00
Jon Chery
4b70e31cf4
fix(P02): input validation + injection hardening — 11 vectors (REQ-150)
...
Critical fixes:
- logs --job: validate ^[A-Za-z0-9_-]+$ + shellQuote (was %q backtick RCE)
- pprof: isLoopback treats empty host as bind-all (was :6060 bypass)
- backup restore: filepath.Rel containment check (was tar-slip via a/../..)
- WebAuthn reg auth deferred to P04 (requires session infra)
High fixes:
- txn rollback/show/apply: validate ^T-[0-9a-f]{16}$ + shellQuote
- nft diff --against: validate txn ID before filepath.Join
- drain stopAlloc: validate allocID ^[A-Za-z0-9_-]+$
- cluster_compat: shellQuote peer dir name
- podman image: shellQuote (was %q backtick injection)
- nft TrustedProbes: net.ParseIP/CIDR validation + split v4/v6 sets
- sudoers: validate --proxmox-user/--proxmox-role ^[a-zA-Z_][a-zA-Z0-9_-]{0,31}$
fixed path /etc/sudoers.d/orca; shellQuote pveum/useradd; validateSudoers
checks actual file
- nft country block: validate ^[A-Z]{2}$ (was len==2 only)
New file: internal/cli/validate.go (shared validators + shellQuote)
All 38 Go test packages pass. go vet + gofmt clean.
---ci---
project: orca
phase: 2
milestone: v0.13
status: complete
requirements:
covered: [150]
---/ci---
v0.12.2
2026-08-07 19:28:01 +00:00
Jon Chery
b0158c96e9
fix(P01): bump go toolchain to 1.25.12 + fix pre-existing test bugs (REQ-149)
...
Toolchain:
- go.mod: go 1.25.0 -> 1.25.12 (closes 24 stdlib vulns: archive/tar,
crypto/tls, crypto/x509, net/http, net/url, encoding/pem, os)
- go mod tidy clean; make build + test + lint pass
Pre-existing test bugs fixed (surfaced by toolchain bump):
- acl_test.go: KindToken always denies (R-021); tests updated to KindOidc
- acl.go: parseIdentity defaults to KindOidc (was KindToken, making
acl grant/check CLI path non-functional for non-spiffe identities)
- init_test.go: migration version updated to 0008 (was 0007, stale since v0.12)
- doctor.go: CertCA now checks CA cert exists (was only checking file modes,
passing when no CA present)
- scenarios_test.go: ACL integration test uses KindOidc + acl.json 0600
---ci---
project: orca
phase: 1
milestone: v0.13
status: complete
requirements:
covered: [149]
---/ci---
v0.12.1
2026-08-07 19:07:17 +00:00
Jon Chery
7479cd1534
docs(checkpoint): P0 shipped — v0.12.0 tagged
2026-08-07 18:50:08 +00:00