name: CI on: pull_request: push: branches: - main workflow_dispatch: permissions: contents: read concurrency: group: ci-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: quality: runs-on: ubuntu-24.04 timeout-minutes: 20 steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 env: GIT_CONFIG_COUNT: "1" GIT_CONFIG_KEY_0: init.defaultBranch GIT_CONFIG_VALUE_0: main with: fetch-depth: 0 persist-credentials: false - name: Setup Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 26 cache: npm - name: Install dependencies run: npm run install-scripts:check && npm run npm-install-policy:check && npm ci --strict-allow-scripts && npm run dependencies:check - name: Validate version metadata run: npm run version:check - name: Audit dependency tree run: npm audit - name: Run tests run: npm test -- --test-timeout=60000 - name: Lint source files run: npm run lint - name: Check source formatting run: npm run format:check - name: Check script syntax run: npm run lint:scripts - name: Build production bundle run: npm run build - name: Check committed whitespace shell: bash env: BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }} HEAD_SHA: ${{ github.sha }} run: | set -euo pipefail if [[ -n "$BASE_SHA" && "$BASE_SHA" != "0000000000000000000000000000000000000000" ]]; then git diff --check "$BASE_SHA" "$HEAD_SHA" else git show --check --format= "$HEAD_SHA" fi - name: Lint GitHub Actions workflows run: docker run --rm --network none -v "$PWD:/repo:ro" -w /repo rhysd/actionlint@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 - name: Validate Docker build definition run: docker build --check . - name: Validate Compose configurations run: | docker compose config --quiet docker compose -f docker-compose.yml -f docker-compose.memory.yml config --quiet docker compose -f docker-compose.yml -f docker-compose.postgres.yml config --quiet docker-runtime: needs: quality runs-on: ubuntu-24.04 timeout-minutes: 20 steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 env: GIT_CONFIG_COUNT: "1" GIT_CONFIG_KEY_0: init.defaultBranch GIT_CONFIG_VALUE_0: main with: persist-credentials: false - name: Build production image run: docker build --build-arg VCS_REF="${GITHUB_SHA}" --tag gpt-image-playground-customer:ci . - name: Start production container run: >- docker run --detach --name gpt-image-playground-customer-ci --env GIP_COMPOSE_DEPLOYMENT=true --env GIP_BIND_HOST=127.0.0.1 --publish 127.0.0.1:4783:4783 gpt-image-playground-customer:ci - name: Verify production endpoint shell: bash run: | set -euo pipefail for attempt in {1..120}; do health_status="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}missing{{end}}' gpt-image-playground-customer-ci)" if [[ "$health_status" == "healthy" ]] && curl --fail --silent --max-time 5 http://127.0.0.1:4783/api/auth-status >/tmp/auth-status.json; then node --input-type=module -e "import { readFileSync } from 'node:fs'; const response = JSON.parse(readFileSync('/tmp/auth-status.json', 'utf8')); if (response.passwordRequired !== false) throw new Error('Expected the CI container auth-status endpoint to report passwordRequired=false.');" image_revision="$(docker image inspect --format '{{ index .Config.Labels "org.opencontainers.image.revision" }}' gpt-image-playground-customer:ci)" if [[ "$image_revision" != "$GITHUB_SHA" ]]; then printf 'Image revision mismatch: expected %s, received %s\n' "$GITHUB_SHA" "$image_revision" docker logs gpt-image-playground-customer-ci exit 1 fi exit 0 fi printf 'Waiting for healthy production container and auth-status endpoint (attempt %s/120, health=%s)\n' "$attempt" "$health_status" if (( attempt < 120 )); then sleep 1 fi done docker logs gpt-image-playground-customer-ci exit 1 - name: Stop production container if: always() run: docker rm --force gpt-image-playground-customer-ci || true postgres-contract: runs-on: ubuntu-24.04 timeout-minutes: 15 steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 env: GIT_CONFIG_COUNT: "1" GIT_CONFIG_KEY_0: init.defaultBranch GIT_CONFIG_VALUE_0: main with: persist-credentials: false - name: Setup Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 26 cache: npm - name: Install dependencies run: npm run install-scripts:check && npm run npm-install-policy:check && npm ci --strict-allow-scripts && npm run dependencies:check - name: Run PostgreSQL state contract run: npm run test:postgres