abc8f0ceab
End-of-session snapshot for /clear. In-flight compressed (four majors landed: zonos-gateway 0.2.1 emotion presets, soong-lab containerized cutover, Wyrd + wtsdk credential provisions). New Recent-decisions + Tried entries and three detail files capture the durable lessons (fleet Gitea build recipe, the vh-is-a-user package-write constraint, soong-lab deploy layout).
58 lines
3.4 KiB
Markdown
58 lines
3.4 KiB
Markdown
- `[2026-07-18]` **Fleet Gitea-Actions build recipe + the `vh`-is-a-user package-write constraint** (learned the hard way across 3 failed soong-lab validation builds; reusable for ANY fleet CI image build or package publish).
|
|
|
|
**The runner.** One `act_runner` (`gitea/act_runner`) on ana-docker, labels
|
|
`pfi-fleet` / `ana-docker` → both map to job image **`node:20-bookworm-slim`**,
|
|
which has **NO docker and NO git**. Config `/opt/docker/conf/gitea-runner/data/config.yaml`:
|
|
`valid_volumes: []` (no socket propagated to job containers). So:
|
|
- `actions/checkout@v4` fails (needs git); `docker/*` marketplace actions fail
|
|
(need docker) — a workflow built on those dies at the first step (~15s).
|
|
|
|
**The working recipe (mirror Worldtree `deploy.yml`).** Run the job in a
|
|
docker-capable image + drive docker with RAW commands, not the JS actions:
|
|
```yaml
|
|
runs-on: pfi-fleet
|
|
container:
|
|
image: docker:24.0.7-cli # has docker+buildx; add git+node
|
|
steps:
|
|
- run: apk add --no-cache git nodejs # so actions/checkout@v4 works
|
|
- uses: actions/checkout@v4
|
|
- name: login # RAW, not docker/login-action
|
|
run: echo "$REGISTRY_TOKEN" | docker login gitea.phasefinal.com -u "$REGISTRY_USER" --password-stdin
|
|
- name: buildx builder
|
|
run: docker buildx create --name X --driver docker-container --use; docker buildx inspect --bootstrap
|
|
- name: build+push # RAW, not docker/build-push-action
|
|
run: docker buildx build --secret id=<name>,env=<TOKEN> -t <img>:latest --push .
|
|
```
|
|
The runner mounts the host docker socket into ITSELF; the docker:cli job reaches
|
|
the daemon through that. The `docker/*` JS actions are unreliable on act_runner —
|
|
raw commands are the fleet convention.
|
|
|
|
**`vh` is a USER account, not an org.** Consequences that bit repeatedly:
|
|
1. `GET /api/v1/orgs/vh` → 404 "user redirect"; there are **no org teams** to add
|
|
a service account to.
|
|
2. **User-owned packages are OWNER-WRITE-ONLY.** claude-bot (even repo
|
|
admin-*collaborator* on `vh/soong-lab`, even with `write:package` scope + full
|
|
basic-auth) gets **`401 unauthorized`** on `docker push` to `vh/soong-lab`, and
|
|
`npm publish` to `vh/npm/` would 401 too. Only `vh` itself can write vh packages.
|
|
→ CI must authenticate AS `vh` for the push (a vh-owned `write:package` PAT as
|
|
`REGISTRY_TOKEN` + `REGISTRY_USER=vh`), exactly how WT pushes `vh/worldtree`.
|
|
claude-bot CAN still: clone/read repos, READ packages (pulled the image fine),
|
|
dispatch workflows, mint demo Worldtree keys.
|
|
3. **Repo Actions secrets are OWNER-ONLY too** — `PUT .../actions/secrets/X` as
|
|
claude-bot (repo admin-collab) → 403 "user should be the owner of the repo".
|
|
Only `vh` can set a repo's secrets.
|
|
|
|
**Other gotchas:**
|
|
- Gitea **reserves the `GITEA_` secret-name prefix** — a secret named
|
|
`GITEA_PYPI_TOKEN` is illegal; use e.g. `PYPI_TOKEN`.
|
|
- Gitea **package auth is token-based / username-lenient** — `docker login` /
|
|
PyPI basic-auth authenticate via the token; the username is nominal (tested
|
|
`-u gitea` and `-u claude-bot` both 200 against the vh PyPI). So a Dockerfile
|
|
hardcoding `UV_INDEX_GITEA_USERNAME=gitea` is fine with any valid token.
|
|
- Homepage (esh-docker-vm) docker-label auto-discovery only covers the 5 endpoints
|
|
in its `docker.yaml` (esh-vm-docker, ana-docker, ana-ml2, nh3-docker, irv-ml1);
|
|
**corviduo-dev is NOT watched** → services there need a manual `services.yaml`
|
|
entry, not labels.
|
|
|
|
Applied in the soong-lab CI: [[2026-07-18-soong-lab-containerize-cutover]].
|