name: CI Gate # CI quality gate for the release pipeline. # # Ensures all PR-quality checks (linting, type checking, tests, validation) # run and pass before any release proceeds. Complements the security-focused # release-gate.yml with code quality and correctness checks. # # Architecture: # release.yml → ci-gate.yml → {pre-commit, mypy, docker-tests, ...} # Nesting depth: release.yml(1) → ci-gate.yml(2) → workflow(3) — safe limit. on: workflow_call: # Called by release.yml secrets: OPENROUTER_API_KEY: required: false workflow_dispatch: # Manual trigger permissions: {} # Minimal top-level for OSSF Scorecard jobs: # ============================================ # Code Quality # ============================================ pre-commit: uses: ./.github/workflows/pre-commit.yml permissions: contents: read mypy-type-check: uses: ./.github/workflows/mypy-type-check.yml permissions: contents: read # ============================================ # Test Suites # ============================================ docker-tests: uses: ./.github/workflows/docker-tests.yml with: strict-mode: true permissions: contents: write # Needed by pytest-tests for gh-pages deployment pull-requests: write # Needed by pytest-tests for PR comments (no-ops in release context) secrets: OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} # ============================================ # Validation # ============================================ validate-image-pinning: uses: ./.github/workflows/validate-image-pinning.yml permissions: contents: read file-whitelist-check: uses: ./.github/workflows/file-whitelist-check.yml with: check-all-files: true permissions: contents: read check-env-vars: uses: ./.github/workflows/check-env-vars.yml permissions: contents: read security-file-write-check: uses: ./.github/workflows/security-file-write-check.yml permissions: contents: read # ============================================ # Summary job that reports overall status # ============================================ ci-gate-summary: name: CI Gate Summary runs-on: ubuntu-latest needs: # Code Quality - pre-commit - mypy-type-check # Test Suites - docker-tests # Validation - validate-image-pinning - file-whitelist-check - check-env-vars - security-file-write-check if: always() permissions: contents: read steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 with: egress-policy: audit - name: Check CI scan results env: PRE_COMMIT_RESULT: ${{ needs.pre-commit.result }} MYPY_RESULT: ${{ needs.mypy-type-check.result }} DOCKER_TESTS_RESULT: ${{ needs.docker-tests.result }} IMAGE_PINNING_RESULT: ${{ needs.validate-image-pinning.result }} FILE_WHITELIST_RESULT: ${{ needs.file-whitelist-check.result }} ENV_VARS_RESULT: ${{ needs.check-env-vars.result }} FILE_WRITE_RESULT: ${{ needs.security-file-write-check.result }} run: | # Redirect all output to GITHUB_STEP_SUMMARY (fixes SC2129) exec >> "$GITHUB_STEP_SUMMARY" # Count results first FAILED="" PASS_COUNT=0 FAIL_COUNT=0 check_result() { local result="$1" if [ "$result" = "success" ]; then PASS_COUNT=$((PASS_COUNT + 1)) return 0 else FAIL_COUNT=$((FAIL_COUNT + 1)) FAILED="true" return 1 fi } # Check all results silently first check_result "$PRE_COMMIT_RESULT" || true check_result "$MYPY_RESULT" || true check_result "$DOCKER_TESTS_RESULT" || true check_result "$IMAGE_PINNING_RESULT" || true check_result "$FILE_WHITELIST_RESULT" || true check_result "$ENV_VARS_RESULT" || true check_result "$FILE_WRITE_RESULT" || true TOTAL=$((PASS_COUNT + FAIL_COUNT)) # ============================================ # BIG STATUS BANNER # ============================================ if [ -z "$FAILED" ]; then echo "# :white_check_mark: CI GATE: PASSED" echo "" echo "> **All $TOTAL CI checks passed successfully.**" echo "> This release is approved from a code quality perspective." else echo "# :x: CI GATE: FAILED" echo "" echo "> **$FAIL_COUNT of $TOTAL checks failed.** Release is blocked." echo "> Review the failures below and fix before releasing." fi echo "" echo "---" echo "" echo "## Detailed Results" echo "" # Reset for detailed output FAILED="" # ============================================ # Code Quality # ============================================ echo "### Code Quality" if [ "$PRE_COMMIT_RESULT" = "success" ]; then echo ":white_check_mark: **Pre-commit (linting, formatting)**: Passed" else echo ":x: **Pre-commit (linting, formatting)**: $PRE_COMMIT_RESULT" FAILED="true" fi if [ "$MYPY_RESULT" = "success" ]; then echo ":white_check_mark: **Mypy Type Check**: Passed" else echo ":x: **Mypy Type Check**: $MYPY_RESULT" FAILED="true" fi # ============================================ # Test Suites # ============================================ echo "" echo "### Test Suites" if [ "$DOCKER_TESTS_RESULT" = "success" ]; then echo ":white_check_mark: **Docker Tests (pytest + UI + LLM + infra + smoke)**: Passed" else echo ":x: **Docker Tests (pytest + UI + LLM + infra + smoke)**: $DOCKER_TESTS_RESULT" FAILED="true" fi # ============================================ # Validation # ============================================ echo "" echo "### Validation" if [ "$IMAGE_PINNING_RESULT" = "success" ]; then echo ":white_check_mark: **Docker Image Pinning**: Passed" else echo ":x: **Docker Image Pinning**: $IMAGE_PINNING_RESULT" FAILED="true" fi if [ "$FILE_WHITELIST_RESULT" = "success" ]; then echo ":white_check_mark: **File Whitelist Security**: Passed" else echo ":x: **File Whitelist Security**: $FILE_WHITELIST_RESULT" FAILED="true" fi if [ "$ENV_VARS_RESULT" = "success" ]; then echo ":white_check_mark: **Environment Variables**: Passed" else echo ":x: **Environment Variables**: $ENV_VARS_RESULT" FAILED="true" fi if [ "$FILE_WRITE_RESULT" = "success" ]; then echo ":white_check_mark: **Security File Writes**: Passed" else echo ":x: **Security File Writes**: $FILE_WRITE_RESULT" FAILED="true" fi # ============================================ # Final result with prominent summary # ============================================ echo "" echo "---" echo "" if [ -n "$FAILED" ]; then echo "## :rotating_light: Action Required" echo "" echo "| Status | Result |" echo "|--------|--------|" echo "| **Gate** | :x: **BLOCKED** |" echo "| **Passed** | $PASS_COUNT |" echo "| **Failed** | $FAIL_COUNT |" echo "" echo "_Fix the failing checks above before releasing._" exit 1 else echo "## :tada: Ready for Release" echo "" echo "| Status | Result |" echo "|--------|--------|" echo "| **Gate** | :white_check_mark: **APPROVED** |" echo "| **Passed** | $PASS_COUNT / $TOTAL |" echo "" echo "_All CI checks passed. Security scans run as separate gate in release pipeline._" fi