From 117cdb33ab514b5b021e9e6648b2c94d643cc07d Mon Sep 17 00:00:00 2001 From: Julian Lechner Date: Fri, 18 Sep 2026 11:37:50 +0200 Subject: [PATCH] ci: expand workflow coverage --- .gitea/workflows/ci.yml | 208 ++++++++++++++++++++++++++++++++++----- .github/workflows/ci.yml | 56 +++++++---- 2 files changed, 219 insertions(+), 45 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 1709494..23ed2d3 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,4 +1,4 @@ -name: CI +name: CI on: push: @@ -6,40 +6,194 @@ on: 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: - linux: + capabilities: + name: Capabilities and shell quality runs-on: ubuntu-latest + timeout-minutes: 10 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - name: Bash syntax - shell: bash + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - 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/commands/check-capabilities.sh + - name: Validate Bash syntax run: git ls-files -z '*.sh' | xargs -0 -r -n1 bash -n - - name: PowerShell checks when runtime exists - shell: bash + - 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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: '3.12' + - name: Compile Python sources + run: python -m compileall -q scripts shared + - name: Run Python tests run: | - if ! command -v pwsh >/dev/null 2>&1; then - echo '::warning::PowerShell unavailable; PowerShell checks skipped.' - exit 0 - fi - for file in $(git ls-files '*.ps1'); do - pwsh -NoLogo -NoProfile -NonInteractive -Command "\$tokens=\$null; \$errors=\$null; [System.Management.Automation.Language.Parser]::ParseFile((Resolve-Path '$file'),[ref]\$tokens,[ref]\$errors)|Out-Null; if(\$errors.Count){\$errors|%{Write-Error \"$file: \$_\"}; exit 1}" + set -euo pipefail + for file in scripts/tests/test-*.py; do + echo "==> $file" + python "$file" done - - name: Build - shell: bash - run: bash scripts/build.sh --summary - - name: Bash install dry run - shell: bash - run: bash scripts/install.sh --summary --dry-run --client both --shell bash - - name: Bash update dry run - shell: bash - run: bash scripts/update.sh --summary --dry-run --client both --shell bash - - name: PowerShell install and update dry runs + - name: Validate generated configuration + run: python scripts/checks/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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Check PowerShell runtime shell: bash run: | - if ! command -v pwsh >/dev/null 2>&1; then - echo '::warning::PowerShell unavailable; PowerShell dry runs skipped.' + if command -v pwsh >/dev/null 2>&1; then + echo 'POWERSHELL_AVAILABLE=true' >> "$GITHUB_ENV" exit 0 fi - pwsh -NoLogo -NoProfile -NonInteractive -File ./scripts/install.ps1 -Summary -DryRun -Client Both -Shell PowerShell - pwsh -NoLogo -NoProfile -NonInteractive -File ./scripts/update.ps1 -Summary -DryRun -Client Both -Shell PowerShell + 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/commands/check-capabilities.ps1 + for file in scripts/tests/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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Build packages + env: + REQUIRE_CODEX_SCHEMA: 'false' + run: bash scripts/commands/build.sh --summary + - name: Run build validation + run: bash scripts/tests/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/commands/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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Run integration tests + run: | + set -euo pipefail + bash scripts/tests/test-install-guards.sh --summary + bash scripts/tests/test-plugin-selection.sh --summary + bash scripts/tests/test-quick-update.sh --summary + bash scripts/tests/test-managed-install.sh --summary + bash scripts/tests/test-shell-packages.sh --summary + - name: Run doctor and prompt budget checks + run: | + bash scripts/commands/doctor.sh --summary + bash scripts/commands/prompt-budget.sh --summary + - name: Verify dry-run installation safety + run: | + bash scripts/commands/install.sh --summary --dry-run --client both --shell bash + bash scripts/commands/update.sh --summary --dry-run --client both --shell bash + + client-smoke: + name: Installed client configuration smoke tests + runs-on: ubuntu-latest + timeout-minutes: 15 + needs: [build] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v22.16.0 + with: + node-version: '24' + - name: Install current client CLIs + run: npm install --global @openai/codex @anthropic-ai/claude-code + - name: Validate current Codex and Claude settings + run: | + set -euo pipefail + schema_home=$(mktemp -d) + cp generated/codex-powershell/config.toml "$schema_home/config.toml" + CODEX_HOME="$schema_home" codex --strict-config --help >/dev/null + claude --settings generated/claude-powershell/settings.json --help >/dev/null + + retrieval: + name: Qwen retrieval integration + runs-on: ubuntu-latest + timeout-minutes: 30 + needs: [python] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.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@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + 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/tests/test-retrieval-server.py + + security: + name: CI configuration security checks + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - 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 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 83531f0..23ed2d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: sudo apt-get update sudo apt-get install --yes --no-install-recommends shellcheck jq - name: Check capabilities - run: bash scripts/check-capabilities.sh + run: bash scripts/commands/check-capabilities.sh - name: Validate Bash syntax run: git ls-files -z '*.sh' | xargs -0 -r -n1 bash -n - name: Lint Bash @@ -51,12 +51,12 @@ jobs: - name: Run Python tests run: | set -euo pipefail - for file in scripts/test-*.py; do + for file in scripts/tests/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 + run: python scripts/checks/validate-config.py generated/codex-powershell/config.toml generated/claude-powershell/settings.json powershell-on-ubuntu: name: PowerShell tests on Ubuntu @@ -81,8 +81,8 @@ jobs: 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 + pwsh -NoLogo -NoProfile -NonInteractive -File ./scripts/commands/check-capabilities.ps1 + for file in scripts/tests/test-*.ps1; do echo "==> $file" pwsh -NoLogo -NoProfile -NonInteractive -File "$file" -Summary done @@ -97,13 +97,13 @@ jobs: - name: Build packages env: REQUIRE_CODEX_SCHEMA: 'false' - run: bash scripts/build.sh --summary + run: bash scripts/commands/build.sh --summary - name: Run build validation - run: bash scripts/test-build-validation.sh --summary + run: bash scripts/tests/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 + bash scripts/commands/build.sh --summary after=$(find generated -type f -print0 | sort -z | xargs -0 sha256sum) test "$before" = "$after" @@ -117,19 +117,39 @@ jobs: - 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 + bash scripts/tests/test-install-guards.sh --summary + bash scripts/tests/test-plugin-selection.sh --summary + bash scripts/tests/test-quick-update.sh --summary + bash scripts/tests/test-managed-install.sh --summary + bash scripts/tests/test-shell-packages.sh --summary - name: Run doctor and prompt budget checks run: | - bash scripts/doctor.sh --summary - bash scripts/prompt-budget.sh --summary + bash scripts/commands/doctor.sh --summary + bash scripts/commands/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 + bash scripts/commands/install.sh --summary --dry-run --client both --shell bash + bash scripts/commands/update.sh --summary --dry-run --client both --shell bash + + client-smoke: + name: Installed client configuration smoke tests + runs-on: ubuntu-latest + timeout-minutes: 15 + needs: [build] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v22.16.0 + with: + node-version: '24' + - name: Install current client CLIs + run: npm install --global @openai/codex @anthropic-ai/claude-code + - name: Validate current Codex and Claude settings + run: | + set -euo pipefail + schema_home=$(mktemp -d) + cp generated/codex-powershell/config.toml "$schema_home/config.toml" + CODEX_HOME="$schema_home" codex --strict-config --help >/dev/null + claude --settings generated/claude-powershell/settings.json --help >/dev/null retrieval: name: Qwen retrieval integration @@ -152,7 +172,7 @@ jobs: - name: Run retrieval tests with real models env: QWEN_TEST_MODEL_CACHE: ${{ github.workspace }}/.cache/huggingface - run: python scripts/test-retrieval-server.py + run: python scripts/tests/test-retrieval-server.py security: name: CI configuration security checks