@@ -300,6 +300,107 @@ OpenAI API keys in Compose files.
300300Codex authentication still lives only in the mounted ` data/codex-home `
301301directory and must be completed inside the running container.
302302
303+ ## Pre-Merge pi-node2 Image Test
304+
305+ Use the ` candidate-image ` GitHub Actions workflow to publish a disposable image
306+ from a branch before merging it. The default target is ` linux/arm64 ` for
307+ ` pi-node2 ` validation, and the generated tag looks like:
308+
309+ ``` text
310+ codex-cli-provider-dev-branch-name-abcdef123456
311+ ```
312+
313+ Run the workflow from the branch you want to test. Leave ` image_tag ` empty
314+ unless you need a stable candidate tag; custom candidate tags must start with
315+ ` codex-cli-provider-dev- ` . Do not use ` latest ` .
316+
317+ On ` pi-node2 ` , keep using the image-only Compose file and the dedicated local
318+ ` data/codex-home ` auth mount:
319+
320+ ``` bash
321+ docker login ghcr.io
322+ export CODEX_CLI_PROVIDER_IMAGE=ghcr.io/subdepthtech/codex-cli-provider:codex-cli-provider-dev-branch-name-abcdef123456
323+ docker compose -f docker-compose.image.yml pull
324+ docker compose -f docker-compose.image.yml up -d
325+ python3 scripts/smoke_test_provider.py
326+ ```
327+
328+ To verify one real Codex-backed request after the container is healthy and
329+ logged in, run:
330+
331+ ``` bash
332+ python3 scripts/smoke_test_provider.py --chat
333+ ```
334+
335+ The non-chat smoke test checks ` /healthz ` , confirms ` /v1/models ` rejects
336+ unauthenticated callers, and confirms the authenticated model list includes
337+ ` codex-cli-default ` . The ` --chat ` check sends one live upstream request through
338+ the signed-in Codex CLI account.
339+
340+ After the ` pi-node2 ` smoke test passes, merge the branch and publish the release
341+ image. The release workflow publishes versioned tags like
342+ ` codex-cli-provider-0.1.2 ` from either a manual dispatch or a Git tag such as
343+ ` v0.1.2 ` .
344+
345+ ## Automated pi-node2 Deployment
346+
347+ The ` deploy-pi-node2 ` GitHub Actions workflow deploys an already-published
348+ candidate or release image on a self-hosted runner installed on ` pi-node2 ` .
349+ It intentionally does not use SSH keys or GitHub-hosted runner secrets.
350+
351+ One-time ` pi-node2 ` setup:
352+
353+ ``` bash
354+ mkdir -p ~ /projects
355+ git clone https://github.com/subdepthtech/codex-cli-provider.git ~ /projects/codex-cli-provider
356+ cd ~ /projects/codex-cli-provider
357+ cp .env.example .env
358+ mkdir -p data/codex-home data/codex-work data/secrets
359+ python3 - << 'PY '
360+ import pathlib, secrets
361+ path = pathlib.Path("data/secrets/proxy_api_key")
362+ path.write_text(secrets.token_urlsafe(48) + "\n")
363+ PY
364+ chmod 600 .env data/secrets/proxy_api_key
365+ chmod 700 data/codex-home data/codex-work data/secrets
366+ docker login ghcr.io
367+ ```
368+
369+ The deploy smoke test expects the dedicated ` data/codex-home ` mount on
370+ ` pi-node2 ` to already contain a valid Codex login. After starting the container
371+ with a candidate or release image for the first time, complete device login
372+ inside that container:
373+
374+ ``` bash
375+ docker exec -it codex-cli-provider \
376+ codex login --device-auth \
377+ -c forced_login_method=' "chatgpt"' \
378+ -c cli_auth_credentials_store=' "file"'
379+ ```
380+
381+ Install the GitHub self-hosted runner on ` pi-node2 ` with labels including
382+ ` self-hosted ` , ` linux ` , ` arm64 ` , and ` pi-node2 ` . In GitHub, create an
383+ environment named ` pi-node2 ` and require manual approval before deployment.
384+ For a public repository, do not let untrusted pull requests run jobs on this
385+ runner.
386+
387+ Run the ` deploy-pi-node2 ` workflow from a trusted branch, preferably ` main ` , and
388+ pass the exact image tag printed by ` candidate-image ` . The workflow uses
389+ ` /home/pi/projects/codex-cli-provider ` by default; set the repository or
390+ environment variable ` PI_NODE2_DEPLOY_DIR ` to override that path.
391+
392+ The deploy workflow updates the fixed checkout, validates the image tag, runs
393+ the image-only Compose security check, pulls the image, restarts the service,
394+ and runs ` scripts/smoke_test_provider.py ` . Enable ` chat_smoke ` to run one live
395+ Codex-backed request after restart.
396+
397+ ## Host Reimage Runbook
398+
399+ For rebuilding the homelab ` pi-node2 ` host, use
400+ [ ` docs/pi-node2-reimage.md ` ] ( docs/pi-node2-reimage.md ) . Keep host-specific
401+ values, backup locations, runner registration details, and credential recovery
402+ notes in the ignored top-level ` handoff.md ` file, not in tracked documentation.
403+
303404## Verification
304405
305406Run repository checks without live credentials:
@@ -316,9 +417,8 @@ PYTHONPATH=. .venv/bin/pytest -q
316417Live checks require a running container and the dedicated Codex login:
317418
318419``` bash
319- PROXY_API_KEY=" $( cat data/secrets/proxy_api_key) "
320- curl -f http://127.0.0.1:8320/healthz
321- curl -f -H " Authorization: Bearer $PROXY_API_KEY " http://127.0.0.1:8320/v1/models
420+ python3 scripts/smoke_test_provider.py
421+ python3 scripts/smoke_test_provider.py --chat
322422```
323423
324424Do not print or inspect ` data/codex-home/auth.json ` .
0 commit comments