Files
orca/.ciagent/RESEARCH_v0.5.md
T
Jon Chery 3b8a2c4e75 docs(P00): research findings
R-001: Gitea container registry (OCI, docker login/push, anon pull when public)
R-002: tea repos edit --private false (visibility flip for REQ-045)
R-003: Gitea releases API (Authorization: token header, asset download URLs)
R-004: ORCA_HOME propagation audit (3 sites: certpaths/store/init)
R-005: distroless static-debian12 base (CGO-free, modernc/sqlite)
R-006: install.sh curl|sh conventions + in-place update pattern
Pitfalls P-001..P-003 (docker-in-CI, public-history leak, CGO_ENABLED=0)
PERSONAS.md: devops-engineer reactivated, data/security/network deactivated for v0.5

---ci---
project: orca
phase: 0
milestone: v0.5
status: research
---/ci---
2026-08-03 18:00:26 +00:00

7.7 KiB

Research: Orca v0.5 — Distribution

Research findings for the v0.5 Distribution milestone (install, namespace, docker, public releases). Conducted during P0 RESEARCH under full autonomy.

R-001: Gitea Container Registry

Source: https://docs.gitea.com/usage/packages/container (Gitea 1.27.1 docs)

Findings:

  • Gitea ships a built-in OCI-compliant container registry.
  • Image naming convention: {registry}/{owner}/{image}:{tag}. For orca: git.cloudinit.dev/coreci/orca:{tag}.
  • Auth: docker login git.cloudinit.dev with username + personal access token (or password if no 2FA). The GITEA_TOKEN env var already used for release publishing works as the password.
  • Push: docker push git.cloudinit.dev/coreci/orca:v0.4.4.
  • Pull: anonymous pull works if the repo is public (REQ-045 flips this). For private repos, pull requires auth.
  • Tags are case-insensitive — use lowercase image names.
  • The registry supports multi-arch manifests via docker buildx.

Implication for P03: scripts/release.sh must add a docker build

  • docker login + docker push step. The .coreci.yml release pipeline needs a container-publish step. Credential is GITEA_TOKEN (reused from the existing release flow — no new secret needed).

R-002: tea repos edit — Repo Visibility

Source: tea repos edit --help (tea 0.14.1 installed locally)

Findings:

  • Command: tea repos edit --private false --repo coreci/orca
  • The --private flag accepts true/false (string, not bool).
  • Default login bot (cloudinit-bot) is already configured and is the default login. No extra auth needed.
  • The change is immediate and reversible (re-run with --private true).

Implication for P0 ship: Run this as an operational step during the P0 ship. Verify with unauth curl against the releases API afterward.

R-003: Gitea Releases API — Asset Download URLs

Source: /api/v1/repos/coreci/orca/releases/latest (authed probe)

Findings:

  • Auth header format: Authorization: token <GITEA_TOKEN> (NOT basic auth — basic auth returns "invalid username, password or token").
  • Latest release endpoint: GET /api/v1/repos/coreci/orca/releases/latest → JSON with tag_name, name, body, assets[].
  • Each asset has browser_download_url — the direct download URL.
  • Public access: once the repo is public (R-002), the releases API and asset downloads work without authentication. This is what install.sh relies on (REQ-043).
  • Asset naming convention from existing releases: orca-{version}-linux-amd64.tar.gz (per scripts/release.sh).

Implication for P02 install.sh:

  1. Query GET /api/v1/repos/coreci/orca/releases/latest (unauth, post-R-002).
  2. Parse tag_name for the version.
  3. Find the asset with name matching orca-{tag}-linux-{arch}.tar.gz.
  4. Download browser_download_url with curl -fsSL.
  5. Extract and install.

R-004: ORCA_HOME Propagation Points (Codebase Audit)

Source: grep for UserHomeDir|os.Getenv("ORCA|\.orca across *.go

Findings — exactly 3 production code sites determine the namespace root today:

File Current behavior Needs change?
internal/certpaths/certpaths.go:21-26 Dir() honors ORCA_HOME~/.orca No — this is the single source of truth. Already correct.
internal/store/store.go:13-19 Open("") hardcodes ~/.orca/orca.db (ignores ORCA_HOME) Yes — route through certpaths.DBPath() instead.
internal/cli/init.go:16-22 Hardcodes ~/.orca via os.UserHomeDir() Yes — route through certpaths.Dir().

All other call sites (node.go:openDB, daemon.go, job.go, doctor.go, cert.go) already go through certpaths.DBPath() or certpaths.Dir() indirectly. No other files need changes for REQ-041.

For REQ-042 (--system): Add a --system persistent flag on rootCmd. When set, rootCmd.PersistentPreRunE sets os.Setenv("ORCA_HOME", "/root/.orca") before any subcommand runs. This is the minimal-touch approach — all downstream code already honors ORCA_HOME. The flag is a CLI convenience that maps to the env var, not a parallel mechanism.

Backward compatibility: empty ORCA_HOME + no --system~/.orca (unchanged). Existing tests that t.Setenv("ORCA_HOME", ...) continue to work.

R-005: Distroless Base Image for CGO-free Go Binaries

Source: Go module audit — modernc.org/sqlite (pure Go, CGO-free), go.mod has no CGO dependencies.

Findings:

  • gcr.io/distroless/static-debian12 is the correct base for static Go binaries with no CGO and no libc dependency. ~2MB image.
  • orca uses modernc.org/sqlite (pure Go) — no CGO, no libc. ✓
  • Multi-stage Dockerfile:
    • Stage 1 (golang:1.25): build with -trimpath -ldflags (same as Makefile), output bin/orca.
    • Stage 2 (gcr.io/distroless/static-debian12): COPY bin/orca /orca, ENTRYPOINT ["/orca"].
  • CGO_ENABLED=0 must be set in the build stage to guarantee a static binary (Go defaults to CGO_ENABLED=1 on platforms with a C compiler).
  • The image runs as nonroot user by default in distroless — but orca writes to ~/.orca (or /root/.orca for --system). For the container image, default ORCA_HOME=/var/lib/orca and document volume mount at that path.

Implication for P03: Dockerfile is ~15 lines. The .coreci.yml release pipeline adds a docker build --build-arg VERSION=$VERSION -t git.cloudinit.dev/coreci/orca:$VERSION . step + login + push.

R-006: install.sh Conventions (curl|sh pattern)

Source: Common patterns from deno, rustup, homebrew installers.

Findings:

  • 1-liner: curl -fsSL <url> | bash (or | bash -s -- --system).
  • The script must be downloadable from a stable URL. orca's script lives at scripts/install.sh in the repo, accessible via https://git.cloudinit.dev/coreci/orca/raw/branch/main/scripts/install.sh (once repo is public per R-002).
  • Args passed via bash -s -- --system --version v0.4.4.
  • In-place update: detect existing binary at install path, read its version via orca version --json (parse version field), print "updated from X to Y", overwrite binary. Never touch the namespace dir (~/.orca or /root/.orca) — that's user state.
  • User-level default: ~/.local/bin/orca (XDG-ish, on PATH on most modern distros). System-level: /usr/local/bin/orca (requires root).

Implication for P02: install.sh is ~80-100 lines of bash. Idempotent. Tested via a scripts/install_test.sh that mocks the download and verifies path selection + update-in-place.

Pitfalls (P-001..P-003)

  • P-001: docker may not be available in the CoreCI release pipeline container. The .coreci.yml release step uses image: golang:1.25 which does NOT include docker. Mitigation: the release pipeline must use a docker:dind sidecar or a step image that has the docker CLI. Alternatively, scripts/release.sh handles docker publish only when run locally or in a CI step that has docker. The .coreci.yml container step must use an image with docker CLI (e.g., catthehacker/docker:docker-latest or a custom image).

  • P-002: Making the repo public exposes git history including the pre-existing .env SHA-1 leak (commit 00127ce documented the rotate-forward decision; .gitleaks-baseline.json suppresses it for scanning). The leak is a non-secret (the token was rotated). This is an accepted risk per the existing decision — no new action needed, but document it in the P0 ship commit.

  • P-003: CGO_ENABLED=0 must be explicit in the Dockerfile build stage. Without it, go build in golang:1.25 may produce a dynamically-linked binary that won't run in distroless. Verified: orca has no CGO deps, but CGO_ENABLED=0 is belt-and-suspenders.