Added missing files #45
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
| # ============================================================================= | |
| # CycloneDX Assessors Studio - CI Pipeline | |
| # ============================================================================= | |
| # Security hardening: | |
| # - All actions pinned to full commit SHAs (not tags) | |
| # - Top-level permissions deny-all; each job grants minimum needed | |
| # - persist-credentials: false on every checkout | |
| # - npm ci with frozen lockfile (no mutation) | |
| # - No use of pull_request_target | |
| # - No secret exposure to PR builds | |
| # ============================================================================= | |
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| types: [opened, synchronize, reopened] | |
| workflow_dispatch: | |
| # Deny all permissions by default. Each job opts in to exactly what it needs. | |
| permissions: {} | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Backend | |
| # --------------------------------------------------------------------------- | |
| backend-build: | |
| name: "Backend / Build & Typecheck" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: read # checkout only | |
| defaults: | |
| run: | |
| working-directory: backend | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Node | |
| uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 | |
| with: | |
| node-version-file: .node-version | |
| cache: npm | |
| cache-dependency-path: backend/package-lock.json | |
| - name: Install dependencies | |
| run: npm ci --ignore-scripts | |
| env: | |
| NODE_ENV: development | |
| # argon2 requires a native build step; run it explicitly after npm ci | |
| - name: Rebuild native modules | |
| run: npm rebuild argon2 | |
| - name: Typecheck | |
| run: npx tsc --noEmit | |
| - name: Lint (if configured) | |
| run: | | |
| if [ -f .eslintrc.js ] || [ -f .eslintrc.json ] || [ -f .eslintrc.yml ] || [ -f eslint.config.js ] || [ -f eslint.config.mjs ]; then | |
| npx eslint . | |
| else | |
| echo "No ESLint config found, skipping" | |
| fi | |
| backend-test: | |
| name: "Backend / Test" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| needs: backend-build | |
| permissions: | |
| contents: read | |
| defaults: | |
| run: | |
| working-directory: backend | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Node | |
| uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 | |
| with: | |
| node-version-file: .node-version | |
| cache: npm | |
| cache-dependency-path: backend/package-lock.json | |
| - name: Install dependencies | |
| run: npm ci --ignore-scripts | |
| - name: Rebuild native modules | |
| run: npm rebuild argon2 | |
| - name: Run tests with coverage | |
| run: npx vitest run --reporter=verbose --coverage | |
| env: | |
| DATABASE_PROVIDER: pglite | |
| PGLITE_DATA_DIR: ./data/test-pglite | |
| JWT_SECRET: ci-testing-secret-that-is-at-least-32-characters-long | |
| PORT: "3001" | |
| LOG_LEVEL: error | |
| CORS_ORIGIN: http://localhost:5173 | |
| - name: Upload backend coverage | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: backend-coverage | |
| path: backend/coverage/lcov.info | |
| retention-days: 5 | |
| if-no-files-found: warn | |
| # --------------------------------------------------------------------------- | |
| # Frontend | |
| # --------------------------------------------------------------------------- | |
| frontend-build: | |
| name: "Frontend / Build & Typecheck" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: read | |
| defaults: | |
| run: | |
| working-directory: frontend | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Node | |
| uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 | |
| with: | |
| node-version-file: .node-version | |
| cache: npm | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Install dependencies | |
| run: npm ci --ignore-scripts | |
| env: | |
| NODE_ENV: development | |
| - name: Typecheck | |
| run: npx vue-tsc -b | |
| - name: Lint (if configured) | |
| run: | | |
| if [ -f .eslintrc.js ] || [ -f .eslintrc.json ] || [ -f .eslintrc.yml ] || [ -f eslint.config.js ] || [ -f eslint.config.mjs ]; then | |
| npx eslint . | |
| else | |
| echo "No ESLint config found, skipping" | |
| fi | |
| - name: Production build | |
| run: npx vite build | |
| - name: Upload build artifact | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: frontend-dist | |
| path: frontend/dist/ | |
| retention-days: 5 | |
| if-no-files-found: error | |
| frontend-test: | |
| name: "Frontend / Test" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| needs: frontend-build | |
| permissions: | |
| contents: read | |
| defaults: | |
| run: | |
| working-directory: frontend | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Node | |
| uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 | |
| with: | |
| node-version-file: .node-version | |
| cache: npm | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Install dependencies | |
| run: npm ci --ignore-scripts | |
| - name: Run tests with coverage | |
| run: npx vitest run --reporter=verbose --coverage.enabled --coverage.reporter=text --coverage.reporter=lcov --coverage.reportsDirectory=./coverage | |
| - name: Upload frontend coverage | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: frontend-coverage | |
| path: frontend/coverage/lcov.info | |
| retention-days: 5 | |
| if-no-files-found: warn | |
| # --------------------------------------------------------------------------- | |
| # Codacy coverage (main branch only) - upload coverage from test jobs | |
| # --------------------------------------------------------------------------- | |
| codacy-coverage: | |
| name: "Codacy / Upload Coverage" | |
| if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| needs: [backend-test, frontend-test] | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Download backend coverage | |
| uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 | |
| with: | |
| name: backend-coverage | |
| path: backend-coverage | |
| - name: Download frontend coverage | |
| uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 | |
| with: | |
| name: frontend-coverage | |
| path: frontend-coverage | |
| continue-on-error: true | |
| - name: Resolve coverage report paths | |
| id: coverage-paths | |
| run: | | |
| REPORTS="" | |
| if [ -f backend-coverage/lcov.info ]; then | |
| REPORTS="backend-coverage/lcov.info" | |
| fi | |
| if [ -f frontend-coverage/lcov.info ]; then | |
| if [ -n "$REPORTS" ]; then | |
| REPORTS="$REPORTS,frontend-coverage/lcov.info" | |
| else | |
| REPORTS="frontend-coverage/lcov.info" | |
| fi | |
| fi | |
| echo "reports=$REPORTS" >> "$GITHUB_OUTPUT" | |
| - name: Upload coverage to Codacy | |
| if: steps.coverage-paths.outputs.reports != '' | |
| uses: codacy/codacy-coverage-reporter-action@89d6c85cfafaec52c72b6c5e8b2878d33104c699 # v1.3.0 | |
| with: | |
| project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} | |
| coverage-reports: ${{ steps.coverage-paths.outputs.reports }} | |
| # --------------------------------------------------------------------------- | |
| # Dependency review (PR only) - block PRs that introduce known vulns | |
| # --------------------------------------------------------------------------- | |
| dependency-review: | |
| name: "Dependency Review" | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| permissions: | |
| contents: read | |
| pull-requests: write # post review comments | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Dependency Review | |
| uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 | |
| with: | |
| fail-on-severity: moderate | |
| deny-licenses: AGPL-3.0, GPL-3.0 | |
| comment-summary-in-pr: always | |
| # --------------------------------------------------------------------------- | |
| # Docker snapshot (main branch only) - build and push snapshot image | |
| # --------------------------------------------------------------------------- | |
| docker: | |
| name: "Docker / Snapshot" | |
| if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| needs: [backend-test, frontend-test] | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 | |
| - name: Log in to Docker Hub | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Build and push snapshot image | |
| uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 | |
| with: | |
| context: . | |
| file: deploy/docker/Dockerfile | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: cyclonedx/cyclonedx-assessors-studio:snapshot | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max |