chore(deps): bump codecov/codecov-action from 5 to 7 #195
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [master, main] | |
| tags: | |
| - "v*" | |
| pull_request: | |
| branches: [master, main] | |
| # Least privilege: nothing is granted by default. Test/build jobs read only; | |
| # only the release jobs (which publish artifacts to a draft release) and the | |
| # post-release integrity job (which uploads SHA256SUMS.txt) need write access. | |
| permissions: {} | |
| jobs: | |
| backend-tests: | |
| name: Backend Tests | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: backend | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| cache: pip | |
| cache-dependency-path: backend/requirements-test.txt | |
| - run: pip install -r requirements-test.txt | |
| - name: Python lint (ruff) | |
| run: | | |
| pip install "ruff>=0.4" | |
| ruff check app | |
| - name: Env-example hygiene check (no phantom vars) | |
| run: python ../scripts/check-env-example.py | |
| # Supply-chain: fail on known-vulnerable Python packages. pip-audit | |
| # resolves the declared ranges against the OSV advisory database. | |
| - name: Python dependency audit (pip-audit) | |
| run: | | |
| pip install pip-audit | |
| pip-audit -r requirements.txt | |
| pip-audit -r requirements-test.txt | |
| - name: Run unit tests with coverage | |
| run: python -m pytest tests/unit/ -v --tb=short --cov --cov-report=term --cov-report=xml:coverage.xml | |
| # Run the WHOLE integration suite, not just one file (test_aws_integration.py | |
| # was previously never executed in CI). | |
| - run: python -m pytest tests/integration/ -v --tb=short | |
| - run: python -m pytest tests/e2e/ -v --tb=short --run-e2e | |
| - name: Upload backend coverage | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| files: backend/coverage.xml | |
| flags: backend | |
| fail_ci_if_error: false | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| lint-and-test: | |
| name: Lint & Test | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: frontend | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| cache-dependency-path: frontend/package-lock.json | |
| - run: npm ci | |
| # Supply-chain: fail on high/critical npm advisories. The only remaining | |
| # known findings are moderate react-router (<6→7 migration required) and | |
| # are tracked as accepted risk; --audit-level=high gates regressions. | |
| - run: npm audit --audit-level=high | |
| # Evidence vocabulary parity: the committed upload catalog must match the | |
| # canonical shared framework data (Phase 11) — drift fails CI. | |
| - run: npm run check:evidence | |
| - run: npm run lint | |
| - run: npx tsc --noEmit | |
| - name: Run unit tests with coverage | |
| run: npm test -- --run --reporter=verbose --coverage | |
| - name: Upload frontend coverage | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| files: frontend/coverage/lcov.info | |
| flags: frontend | |
| fail_ci_if_error: false | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| electron-tests: | |
| name: Electron Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| # Electron 43's toolchain (electron, @electron/rebuild, node-abi) | |
| # requires Node >= 22.12 — Node 20 fails the native-deps rebuild. | |
| node-version: 22 | |
| - name: Install dependencies | |
| run: npm ci | |
| # Supply-chain: fail on high/critical npm advisories in the desktop app. | |
| - run: npm audit --audit-level=high | |
| # vitest runs the electron tests under Node. better-sqlite3 >= 13 is | |
| # N-API based, so the same prebuilt binary works for the Node test run | |
| # and the packaged Electron app (no per-ABI rebuild needed). | |
| - name: Run electron test suite | |
| run: npm run test:scheduler | |
| e2e-tests: | |
| name: Full-stack E2E | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| cache: pip | |
| cache-dependency-path: backend/requirements.txt | |
| - run: pip install -r backend/requirements.txt | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| cache-dependency-path: frontend/package-lock.json | |
| - run: npm ci | |
| working-directory: frontend | |
| - name: Install Playwright browsers | |
| run: npx playwright install --with-deps chromium | |
| working-directory: frontend | |
| - name: Run full-stack E2E suite | |
| run: npm run test:e2e | |
| working-directory: frontend | |
| - name: Upload E2E artifacts on failure | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: playwright-report | |
| path: frontend/playwright-report | |
| retention-days: 7 | |
| build: | |
| name: Build | |
| runs-on: ubuntu-latest | |
| needs: [backend-tests, lint-and-test] | |
| defaults: | |
| run: | |
| working-directory: frontend | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| cache-dependency-path: frontend/package-lock.json | |
| - run: npm ci | |
| - run: npm run build | |
| docker-build: | |
| name: Docker Images Build (production Dockerfiles) | |
| runs-on: ubuntu-latest | |
| needs: [backend-tests, lint-and-test, build] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # Verify the exact Dockerfiles the docker-compose deployment ships build | |
| # from a clean context (repo root, shared/ included), so a broken | |
| # production container image cannot slip past CI. | |
| - name: Build backend image | |
| run: docker build -f backend/Dockerfile -t complianceguard-backend:ci . | |
| - name: Build frontend image | |
| run: docker build -f frontend/Dockerfile -t complianceguard-frontend:ci . | |
| release: | |
| name: Release Windows Installer | |
| runs-on: windows-latest | |
| # All test suites + build must pass before we cut a release. electron-tests | |
| # gates here because the desktop app IS the shipped Windows/macOS artifact. | |
| needs: [backend-tests, lint-and-test, electron-tests, e2e-tests, build] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| # Needed to upload installers + latest.yml to the draft release. | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Install root dependencies | |
| run: npm ci | |
| - name: Install frontend dependencies | |
| run: cd frontend && npm ci | |
| - name: Build and publish | |
| run: npm run publish | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Windows code signing. Two supported routes (see | |
| # docs/release-and-signing.md): classic PKCS#12 via WIN_CSC_LINK | |
| # (base64 of the .pfx) + WIN_CSC_KEY_PASSWORD, or Azure Trusted | |
| # Signing via AZURE_* (no EV hardware). When NONE of these are set, | |
| # electron-builder skips signing and the verification step below | |
| # fails loudly instead of shipping a silently-unsigned installer. | |
| WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }} | |
| WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }} | |
| AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} | |
| AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} | |
| AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} | |
| AZURE_KEY_VAULT_NAME: ${{ secrets.AZURE_KEY_VAULT_NAME }} | |
| AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }} | |
| - name: Verify installer Authenticode signature | |
| shell: pwsh | |
| run: | | |
| $installer = Get-ChildItem dist -Filter 'ComplianceGuard-Setup-*.exe' | Where-Object { $_.Name -notlike '*.blockmap' } | Select-Object -First 1 | |
| if (-not $installer) { Write-Error 'No NSIS installer found in dist/'; exit 1 } | |
| $sig = Get-AuthenticodeSignature -FilePath $installer.FullName | |
| Write-Host "Installer: $($installer.Name)" | |
| Write-Host "Signature status: $($sig.Status)" | |
| if ($sig.Status -ne 'Valid') { | |
| if ($env:WIN_CSC_LINK -or $env:AZURE_CLIENT_ID) { | |
| Write-Error "Signing credentials were provided but the installer is NOT signed (status: $($sig.Status)). Aborting release." | |
| exit 1 | |
| } | |
| Write-Warning "Installer is UNSIGNED (no signing credentials configured). This release will not support verified auto-updates — configure WIN_CSC_LINK or AZURE_* before publishing to customers." | |
| } else { | |
| Write-Host "Signer: $($sig.SignerCertificate.Subject)" | |
| } | |
| release-mac: | |
| name: Release macOS DMG | |
| runs-on: macos-latest | |
| # Serialized after the Windows release job so both publish into ONE draft | |
| # release: 'release' creates the draft + uploads the .exe, then 'release-mac' | |
| # finds that draft and uploads the .dmg. Avoids the split-draft race. | |
| needs: [backend-tests, lint-and-test, electron-tests, build, release] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| # Needed to upload the .dmg to the same draft release. | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| # Electron 43's toolchain requires Node >= 22.12 (matches the | |
| # electron-tests job). | |
| node-version: 22 | |
| - name: Install root dependencies | |
| run: npm ci | |
| - name: Install frontend dependencies | |
| run: cd frontend && npm ci | |
| - name: Build and publish | |
| run: npm run publish:mac | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # macOS signing + notarization (see docs/release-and-signing.md). | |
| # Without these, the .dmg is built unsigned. | |
| CSC_LINK: ${{ secrets.MAC_CSC_LINK }} | |
| CSC_KEY_PASSWORD: ${{ secrets.MAC_CSC_KEY_PASSWORD }} | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| release-integrity: | |
| name: Verify Release Integrity | |
| runs-on: ubuntu-latest | |
| needs: [release, release-mac] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| # Needs write to upload SHA256SUMS.txt to the draft release. | |
| permissions: | |
| contents: write | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Fetch draft release artifacts | |
| run: | | |
| gh release view "${{ github.ref_name }}" --json isDraft,assets --jq '{draft: .isDraft, assets: [.assets[].name]}' | |
| gh release download "${{ github.ref_name }}" --pattern '*.exe' --pattern '*.dmg' --pattern 'latest.yml' --dir release-assets | |
| ls -la release-assets | |
| - name: Fail if artifacts are missing | |
| run: | | |
| for f in 'ComplianceGuard-Setup-*.exe' 'ComplianceGuard-*.dmg' 'latest.yml'; do | |
| matches=$(ls release-assets/$f 2>/dev/null || true) | |
| if [ -z "$matches" ]; then | |
| echo "::error::Missing required release artifact: $f" | |
| exit 1 | |
| fi | |
| done | |
| echo "All expected artifacts present." | |
| - name: Generate and upload SHA256SUMS.txt | |
| run: | | |
| (cd release-assets && sha256sum *.exe *.dmg *.yml > SHA256SUMS.txt && cat SHA256SUMS.txt) | |
| gh release upload "${{ github.ref_name }}" release-assets/SHA256SUMS.txt --clobber | |
| # Supply-chain visibility: ship an SPDX SBOM alongside the installers so | |
| # consumers can audit the dependency inventory of the release. | |
| - name: Generate SBOM | |
| uses: anchore/sbom-action@v0 | |
| with: | |
| path: . | |
| format: spdx-json | |
| output-file: release-assets/sbom.spdx.json | |
| - name: Upload SBOM to release | |
| run: gh release upload "${{ github.ref_name }}" release-assets/sbom.spdx.json --clobber | |
| - name: Verify draft is still a draft (no accidental publish) | |
| run: | | |
| draft=$(gh release view "${{ github.ref_name }}" --json isDraft --jq .isDraft) | |
| echo "Release is draft: $draft" | |
| [ "$draft" = "true" ] || { echo '::error::Release is not a draft — expected draft until manual publish.'; exit 1; } |