prodex 0.40.0

OpenAI profile pooling and safe auto-rotate for Codex CLI and Claude Code
Documentation
name: CI

on:
  push:
    branches:
      - main
  pull_request:

permissions:
  contents: read

concurrency:
  group: ci-${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  fmt:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2

      - name: Check formatting
        run: cargo fmt --check

  docs-lint:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Install Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 22
          package-manager-cache: false

      - name: Lint markdown docs
        run: npm run docs:lint

  secret-scan:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Scan repository for leaked credentials
        shell: bash
        run: |
          set -euo pipefail
          docker run --rm \
            -v "${PWD}:/repo" \
            ghcr.io/gitleaks/gitleaks:v8.30.1 \
            detect --source /repo --no-git --redact --no-banner --config /repo/.gitleaks.toml

  supply-chain:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2
        with:
          cache-bin: false

      - name: Cache cargo supply-chain tools
        id: cargo-supply-chain-cache
        uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/bin/cargo-audit
            ~/.cargo/bin/cargo-deny
          key: ${{ runner.os }}-cargo-supply-chain-tools-audit-0.22.1-deny-0.19.0

      - name: Check locked compile graph
        run: cargo check --locked --all-targets --all-features

      - name: Run clippy warning gate
        run: cargo clippy --locked --all-targets --all-features -- -D warnings

      - name: Install cargo-audit
        shell: bash
        run: |
          set -euo pipefail
          if ! command -v cargo-audit >/dev/null 2>&1; then
            cargo install cargo-audit --locked --version 0.22.1
          fi

      - name: Run cargo audit
        run: cargo audit

      - name: Install cargo-deny
        shell: bash
        run: |
          set -euo pipefail
          if ! command -v cargo-deny >/dev/null 2>&1; then
            cargo install cargo-deny --locked --version 0.19.0
          fi

      - name: Run cargo deny checks
        run: cargo deny check advisories sources

  release-sync:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Verify release/version sync
        shell: bash
        run: |
          set -euo pipefail
          npm run npm:sync-version
          git diff --exit-code -- Cargo.toml npm README.md QUICKSTART.md scripts/npm

  npm-package-smoke:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2

      - name: Install Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 22
          package-manager-cache: false

      - name: Build host release binary
        run: cargo build --release --locked --target x86_64-unknown-linux-gnu

      - name: Smoke staged npm package
        run: node scripts/ci/npm-package-smoke.mjs --binary-dir target/x86_64-unknown-linux-gnu/release

  auto-rotate:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2

      - name: Run auto-rotate integration tests
        run: cargo test --test auto_rotate

  profile-commands-internal:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2

      - name: Run profile command internal tests
        run: |
          cargo test --lib profile_commands_internal_tests:: -- --test-threads=1

  main-internal-core:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2

      - name: Run main internal tests without runtime proxy shard
        run: |
          set -euo pipefail
          cargo test --lib main_internal_tests:: -- --skip runtime_proxy_ --test-threads=1

  env-sensitive-parallel-guard:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2

      - name: Run env-sensitive parallel guard
        run: node scripts/ci/runtime-env-parallel.mjs --runs 2 --test-threads 4

  main-internal-runtime-proxy:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2

      - name: Run runtime proxy internal test shard
        run: |
          set -euo pipefail
          for attempt in 1 2; do
            echo "runtime proxy shard attempt ${attempt}"
            if cargo test --lib main_internal_tests::runtime_proxy_ -- --test-threads=1; then
              exit 0
            fi
            if [ "${attempt}" -eq 2 ]; then
              exit 1
            fi
            echo "retrying runtime proxy shard after a transient failure"
            sleep 5
          done

  runtime-stress:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2

      - name: Run runtime proxy stress tests
        run: npm run ci:runtime-stress -- --suite stress

      - name: Run serialized runtime-sensitive stress tests
        run: npm run ci:runtime-stress -- --suite serialized

      - name: Rerun continuation-heavy tests
        run: npm run ci:runtime-stress -- --suite continuation