name: CI on: pull_request: push: branches: [main] permissions: contents: read jobs: verify: runs-on: ubuntu-latest timeout-minutes: 20 steps: - uses: actions/checkout@v4 with: { fetch-depth: 0 } - uses: actions/setup-node@v4 with: { node-version: 22, cache: npm } - run: npm ci - run: npm run build - run: npm run typecheck - run: npm test - run: npm run test:integration - run: npm run smoke - name: Reject secrets and control-plane artifacts shell: bash run: | set -euo pipefail ! git ls-files | grep -E '(^|/)(\.env|id_rsa|id_ed25519|credentials|secrets?|tokens?)(\.|$|/)' ! git ls-files | grep -E '(^|/)\.qwen/|qwen-agent-run/' - name: Scan content and Git history for secrets env: GITLEAKS_CONFIG_COMMIT: 83d9cd684c87d95d656c1458ef04895a7f1cbd8e GITLEAKS_CONFIG_SHA256: e163e53b9e7e8a8511e77271e2b323ed057759542a6d988258afe3a1fa329caf GITLEAKS_SHA256: 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb GITLEAKS_VERSION: 8.30.1 shell: bash run: | set -euo pipefail archive="$RUNNER_TEMP/gitleaks.tar.gz" curl --fail --location --proto '=https' --tlsv1.2 \ --output "$archive" \ "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" echo "$GITLEAKS_SHA256 $archive" | sha256sum --check --strict tar -xzf "$archive" -C "$RUNNER_TEMP" gitleaks scanner_dir="$RUNNER_TEMP/gitleaks-scan" mkdir -p "$scanner_dir" config="$scanner_dir/gitleaks.toml" ignore_file="$scanner_dir/.gitleaksignore" curl --fail --location --proto '=https' --tlsv1.2 \ --output "$config" \ "https://raw.githubusercontent.com/gitleaks/gitleaks/${GITLEAKS_CONFIG_COMMIT}/config/gitleaks.toml" echo "$GITLEAKS_CONFIG_SHA256 $config" | sha256sum --check --strict : > "$ignore_file" ( cd "$scanner_dir" "$RUNNER_TEMP/gitleaks" git \ --config "$config" \ --gitleaks-ignore-path "$ignore_file" \ --ignore-gitleaks-allow \ --no-banner \ --redact \ --verbose \ "$GITHUB_WORKSPACE" ) - run: npm audit --omit=dev --audit-level=high