name: CI on: push: branches: [main] pull_request: schedule: - cron: '23 4 * * 1' workflow_dispatch: permissions: contents: read concurrency: group: ci-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} env: PYTHONUNBUFFERED: '1' PIP_DISABLE_PIP_VERSION_CHECK: '1' jobs: capabilities: name: Capabilities and shell quality runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install shell tools run: | sudo apt-get update sudo apt-get install --yes --no-install-recommends shellcheck jq - name: Check capabilities run: bash scripts/check-capabilities.sh - name: Validate Bash syntax run: git ls-files -z '*.sh' | xargs -0 -r -n1 bash -n - name: Lint Bash run: shellcheck --severity=warning $(git ls-files '*.sh') python: name: Python tests and compilation runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.6.0 with: python-version: '3.12' - name: Compile Python sources run: python -m compileall -q scripts shared - name: Run Python tests run: | set -euo pipefail for file in scripts/test-*.py; do echo "==> $file" python "$file" done - name: Validate generated configuration run: python scripts/validate-config.py generated/codex-powershell/config.toml generated/claude-powershell/settings.json powershell-on-ubuntu: name: PowerShell tests on Ubuntu runs-on: ubuntu-latest timeout-minutes: 20 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Check PowerShell runtime shell: bash run: | if command -v pwsh >/dev/null 2>&1; then echo 'POWERSHELL_AVAILABLE=true' >> "$GITHUB_ENV" exit 0 fi if sudo apt-get update && sudo apt-get install --yes --no-install-recommends powershell; then echo 'POWERSHELL_AVAILABLE=true' >> "$GITHUB_ENV" else echo 'POWERSHELL_AVAILABLE=false' >> "$GITHUB_ENV" echo '::warning::PowerShell is unavailable; PowerShell checks skipped for this runner.' fi - name: Run PowerShell tests shell: bash run: | if [ "${POWERSHELL_AVAILABLE:-false}" != true ]; then exit 0; fi pwsh -NoLogo -NoProfile -NonInteractive -File ./scripts/check-capabilities.ps1 for file in scripts/test-*.ps1; do echo "==> $file" pwsh -NoLogo -NoProfile -NonInteractive -File "$file" -Summary done build: name: Build and inspect generated packages runs-on: ubuntu-latest timeout-minutes: 15 needs: [capabilities, python] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Build packages env: REQUIRE_CODEX_SCHEMA: 'false' run: bash scripts/build.sh --summary - name: Run build validation run: bash scripts/test-build-validation.sh --summary - name: Check generated files are reproducible run: | before=$(find generated -type f -print0 | sort -z | xargs -0 sha256sum) bash scripts/build.sh --summary after=$(find generated -type f -print0 | sort -z | xargs -0 sha256sum) test "$before" = "$after" shell-integration: name: Bash integration and installation guards runs-on: ubuntu-latest timeout-minutes: 25 needs: [build] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run integration tests run: | set -euo pipefail bash scripts/test-install-guards.sh --summary bash scripts/test-plugin-selection.sh --summary bash scripts/test-quick-update.sh --summary bash scripts/test-managed-install.sh --summary bash scripts/test-shell-packages.sh --summary - name: Run doctor and prompt budget checks run: | bash scripts/doctor.sh --summary bash scripts/prompt-budget.sh --summary - name: Verify dry-run installation safety run: | bash scripts/install.sh --summary --dry-run --client both --shell bash bash scripts/update.sh --summary --dry-run --client both --shell bash retrieval: name: Qwen retrieval integration runs-on: ubuntu-latest timeout-minutes: 30 needs: [python] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.6.0 with: python-version: '3.12' cache: pip cache-dependency-path: shared/retrieval/requirements.txt - name: Install retrieval dependencies run: python -m pip install -r shared/retrieval/requirements.txt - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.2.3 with: path: .cache/huggingface key: qwen-retrieval-${{ runner.os }}-${{ hashFiles('shared/retrieval/requirements.txt') }} - name: Run retrieval tests with real models env: QWEN_TEST_MODEL_CACHE: ${{ github.workspace }}/.cache/huggingface run: python scripts/test-retrieval-server.py security: name: CI configuration security checks runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Reject unsafe workflow settings run: | set -euo pipefail ! grep -RInE 'runs-on:[[:space:]]*windows|pull_request_target|permissions:[[:space:]]*write-all|actions/checkout@v|actions/setup-python@v|curl[[:space:]].*\|[[:space:]]*(bash|sh)|wget[[:space:]].*\|[[:space:]]*(bash|sh)' .github/workflows test "$(grep -Roh 'runs-on: ubuntu-latest' .github/workflows | wc -l)" -ge 1 test "$(grep -Roh 'uses: actions/[^@]*@[0-9a-f]\{40\}' .github/workflows | wc -l)" -ge 1 - name: Check for tracked secrets run: | set -euo pipefail if git ls-files | grep -E '(^|/)(\.env($|\.)|.*\.(pem|key))$'; then echo 'Potential secret file or private key tracked' >&2 exit 1 fi if git ls-files -z | xargs -0 -r grep -IlE 'BEGIN (RSA|OPENSSH|EC) PRIVATE KEY'; then echo 'Potential private key material tracked' >&2 exit 1 fi