# 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.