Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@ MAX_REQUEST_BODY_BYTES=262144
MAX_MESSAGES=32
MAX_TOTAL_TEXT_CHARS=80000

# Local admission queue for short bursts while preserving one active Codex run.
# Local admission queue for short bursts while all Codex run slots are busy.
# 0 fails fast with wrapper_busy 429. Values above 0 wait up to that many
# seconds for the active run to finish. The app clamps this to 0-5 seconds.
# seconds for a run slot to open. The app clamps this to 0-5 seconds.
QUEUE_WAIT_SECONDS=0

# Optional provider-side parallelism. Keep 1 unless local wrapper_busy 429s are
# the bottleneck and the signed-in Codex account tolerates two concurrent CLI
# executions. The app clamps this to 1-2.
MAX_CONCURRENT_CODEX_RUNS=1
CORS_ALLOWED_ORIGINS=
LOG_LEVEL=INFO
124 changes: 124 additions & 0 deletions .github/workflows/candidate-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: candidate-image

on:
workflow_dispatch:
inputs:
image_tag:
description: "Optional candidate tag. Defaults to codex-cli-provider-dev-<branch>-<short-sha>."
required: false
type: string
platforms:
description: "Target image platform(s). Use linux/arm64 for pi-node2 validation."
required: true
default: linux/arm64
type: choice
options:
- linux/arm64
- linux/amd64
- linux/amd64,linux/arm64

permissions:
contents: read
packages: write

concurrency:
group: candidate-image-${{ github.ref }}
cancel-in-progress: true

jobs:
publish-candidate-image:
runs-on: ubuntu-latest
timeout-minutes: 45

steps:
- name: Checkout
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5

- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: "3.12"
cache: pip

- name: Install dependencies
run: pip install --requirement requirements.txt

- name: Unit tests
run: python -m pytest -q

- name: Syntax checks
run: python -m compileall -q src scripts tests

- name: Prepare throwaway local config
run: |
cp .env.example .env
mkdir -p data/secrets data/codex-home data/codex-work
python - <<'PY'
import pathlib
import secrets

pathlib.Path("data/secrets/proxy_api_key").write_text(secrets.token_urlsafe(48) + "\n", encoding="utf-8")
PY
chmod 600 .env
chmod 644 data/secrets/proxy_api_key
chmod 700 data/secrets data/codex-home data/codex-work

- name: Repo hygiene checks
run: python scripts/check_repo_hygiene.py

- name: Compose security checks
run: python scripts/check_compose_security.py

- name: Image Compose security checks
env:
COMPOSE_FILE: docker-compose.image.yml
CODEX_CLI_PROVIDER_IMAGE: ghcr.io/${{ github.repository }}:codex-cli-provider-dev-compose-check
run: python scripts/check_compose_security.py

- name: Resolve candidate tag
id: candidate
env:
REQUESTED_IMAGE_TAG: ${{ inputs.image_tag }}
run: >
python scripts/image_tags.py candidate
--ref-name "$GITHUB_REF_NAME"
--sha "$GITHUB_SHA"
--requested "$REQUESTED_IMAGE_TAG"
--github-output

- name: Set up QEMU
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0

- name: Log in to GHCR
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and publish candidate image
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: .
file: Dockerfile
platforms: ${{ inputs.platforms }}
push: true
tags: ghcr.io/${{ github.repository }}:${{ steps.candidate.outputs.tag }}
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.version=${{ steps.candidate.outputs.tag }}

- name: Inspect candidate image
run: docker buildx imagetools inspect ghcr.io/${{ github.repository }}:${{ steps.candidate.outputs.tag }}

- name: Print pi-node2 pull command
run: |
echo "Candidate image:"
echo "ghcr.io/${{ github.repository }}:${{ steps.candidate.outputs.tag }}"
echo
echo "pi-node2 command:"
echo "CODEX_CLI_PROVIDER_IMAGE=ghcr.io/${{ github.repository }}:${{ steps.candidate.outputs.tag }} docker compose -f docker-compose.image.yml up -d"
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
run: python -m pytest -q

- name: Syntax checks
run: python -m py_compile src/server.py scripts/check_compose_security.py scripts/check_repo_hygiene.py tests/test_server.py
run: python -m compileall -q src scripts tests

- name: Prepare throwaway local config
run: |
Expand All @@ -62,5 +62,11 @@ jobs:
- name: Compose security checks
run: python scripts/check_compose_security.py

- name: Image Compose security checks
env:
COMPOSE_FILE: docker-compose.image.yml
CODEX_CLI_PROVIDER_IMAGE: registry.example.com/your-org/codex-cli-provider:codex-cli-provider-0.1.2
run: python scripts/check_compose_security.py

- name: Docker build
run: docker compose build
59 changes: 59 additions & 0 deletions .github/workflows/deploy-pi-node2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: deploy-pi-node2

on:
workflow_dispatch:
inputs:
image_tag:
description: "Candidate or release image tag to deploy, for example codex-cli-provider-dev-branch-abcdef123456."
required: true
type: string
chat_smoke:
description: "Run one live Codex-backed chat completion after deploy."
required: true
default: false
type: boolean

permissions:
contents: read

concurrency:
group: deploy-pi-node2
cancel-in-progress: false

jobs:
deploy:
runs-on: [self-hosted, linux, arm64, pi-node2]
environment: pi-node2
timeout-minutes: 20

steps:
- name: Update fixed deploy checkout
env:
DEPLOY_DIR: ${{ vars.PI_NODE2_DEPLOY_DIR || '/home/pi/projects/codex-cli-provider' }}
run: |
set -eu
mkdir -p "$(dirname "$DEPLOY_DIR")"
if [ ! -d "$DEPLOY_DIR/.git" ]; then
git clone "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git" "$DEPLOY_DIR"
fi
cd "$DEPLOY_DIR"
git fetch --prune origin "$GITHUB_REF"
git checkout --force "$GITHUB_SHA"

- name: Deploy and smoke test
env:
DEPLOY_DIR: ${{ vars.PI_NODE2_DEPLOY_DIR || '/home/pi/projects/codex-cli-provider' }}
IMAGE_REPOSITORY: ghcr.io/${{ github.repository }}
IMAGE_TAG: ${{ inputs.image_tag }}
CHAT_SMOKE: ${{ inputs.chat_smoke }}
run: |
set -eu
chat_arg=""
if [ "$CHAT_SMOKE" = "true" ]; then
chat_arg="--chat-smoke"
fi
cd "$DEPLOY_DIR"
python3 scripts/deploy_compose_image.py \
--image-repository "$IMAGE_REPOSITORY" \
--image-tag "$IMAGE_TAG" \
$chat_arg
17 changes: 15 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
workflow_dispatch:
inputs:
image_tag:
description: "Image tag to publish, for example v0.1.0 or test"
description: "Image tag to publish, for example codex-cli-provider-0.1.0"
required: true
type: string
push:
Expand All @@ -28,6 +28,19 @@ jobs:
- name: Checkout
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5

- name: Validate dispatch image tag
if: github.event_name == 'workflow_dispatch'
run: python scripts/image_tags.py validate --kind release "${{ inputs.image_tag }}"

- name: Validate git tag image tag
if: github.event_name == 'push'
run: |
release_tag="codex-cli-provider-${GITHUB_REF_NAME#v}"
python scripts/image_tags.py validate --kind release "$release_tag"

- name: Set up QEMU
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0

Expand All @@ -45,7 +58,7 @@ jobs:
images: ghcr.io/${{ github.repository }}
tags: |
type=raw,value=${{ inputs.image_tag }},enable=${{ github.event_name == 'workflow_dispatch' }}
type=ref,event=tag
type=semver,pattern=codex-cli-provider-{{version}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}

- name: Build and publish image
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ data/
logs/
tmp/
temp/
handoff.md

.DS_Store
.idea/
Expand Down
Loading
Loading