|
7 | 7 |
|
8 | 8 | env: |
9 | 9 | REGISTRY: ghcr.io |
10 | | - IMAGE_BASE: ${{ github.repository }} |
11 | 10 |
|
12 | 11 | jobs: |
13 | | - build-and-push: |
| 12 | + # --- JOB 1: BACKEND (Dockerized for GHCR) --- |
| 13 | + build-backend: |
14 | 14 | runs-on: ubuntu-latest |
15 | | - strategy: |
16 | | - fail-fast: false |
17 | | - matrix: |
18 | | - include: |
19 | | - - service: backend |
20 | | - context: ./backend |
21 | | - image: ghcr.io/${{ github.repository }}/backend |
22 | | - - service: frontend |
23 | | - context: ./frontend |
24 | | - image: ghcr.io/${{ github.repository }}/frontend |
25 | | - |
26 | 15 | permissions: |
27 | 16 | contents: read |
28 | 17 | packages: write |
29 | | - id-token: write # Required for OIDC and Build Provenance |
30 | | - security-events: write |
31 | | - attestations: write # NEW: Specifically required for official GitHub Attestations |
32 | | - |
| 18 | + id-token: write |
| 19 | + security-events: write |
| 20 | + attestations: write |
33 | 21 | steps: |
34 | 22 | - name: Checkout repository |
35 | 23 | uses: actions/checkout@v4 |
36 | 24 |
|
37 | 25 | - name: Set up Docker Buildx |
38 | 26 | uses: docker/setup-buildx-action@v3 |
39 | 27 |
|
40 | | - - name: Log in to the Container registry |
| 28 | + - name: Log in to GHCR |
41 | 29 | uses: docker/login-action@v3 |
42 | 30 | with: |
43 | 31 | registry: ${{ env.REGISTRY }} |
44 | 32 | username: ${{ github.actor }} |
45 | 33 | password: ${{ secrets.GITHUB_TOKEN }} |
46 | 34 |
|
47 | | - - name: Extract metadata |
48 | | - id: meta |
49 | | - uses: docker/metadata-action@v5 |
50 | | - with: |
51 | | - images: ${{ matrix.image }} |
52 | | - tags: | |
53 | | - type=semver,pattern={{version}} |
54 | | - type=sha,prefix=sha- |
55 | | - type=raw,value=latest,enable=${{ github.event_name == 'release' }} |
56 | | -
|
57 | | - - name: Build and push Docker image |
| 35 | + - name: Build and push Backend Image |
58 | 36 | id: build-push |
59 | | - uses: docker/build-push-action@v6 # Updated to v6 |
| 37 | + uses: docker/build-push-action@v6 |
60 | 38 | with: |
61 | | - context: ${{ matrix.context }} |
| 39 | + context: ./backend |
62 | 40 | push: true |
63 | | - tags: ${{ steps.meta.outputs.tags }} |
64 | | - labels: ${{ steps.meta.outputs.labels }} |
| 41 | + # Tags both 'latest' and the specific release version (e.g., v1.0.0) |
| 42 | + tags: | |
| 43 | + ${{ env.REGISTRY }}/${{ github.repository }}/backend:latest |
| 44 | + ${{ env.REGISTRY }}/${{ github.repository }}/backend:${{ github.event.release.tag_name || github.sha }} |
65 | 45 | cache-from: type=gha |
66 | 46 | cache-to: type=gha,mode=max |
67 | 47 |
|
68 | | - - name: Run Trivy vulnerability scanner |
69 | | - # Pinned to v0.35.0 specifically for security after March 2026 compromise |
70 | | - uses: aquasecurity/trivy-action@v0.35.0 |
71 | | - with: |
72 | | - image-ref: ${{ matrix.image }}@${{ steps.build-push.outputs.digest }} |
73 | | - format: 'sarif' |
74 | | - output: 'trivy-results.sarif' |
75 | | - severity: 'CRITICAL,HIGH' |
| 48 | + - name: Sign Backend Image |
| 49 | + run: | |
| 50 | + cosign sign --yes "${{ env.REGISTRY }}/${{ github.repository }}/backend@${{ steps.build-push.outputs.digest }}" |
| 51 | +
|
| 52 | + # --- JOB 2: FRONTEND (ZIP Archive for Release Assets) --- |
| 53 | + build-frontend: |
| 54 | + runs-on: ubuntu-latest |
| 55 | + permissions: |
| 56 | + contents: write # Required to upload the ZIP to the Release |
| 57 | + id-token: write |
| 58 | + attestations: write |
76 | 59 |
|
77 | | - - name: Upload Trivy scan results to GitHub Security |
78 | | - uses: github/codeql-action/upload-sarif@v3 |
| 60 | + steps: |
| 61 | + - name: Checkout repository |
| 62 | + uses: actions/checkout@v4 |
| 63 | + |
| 64 | + - name: Set up Node.js |
| 65 | + uses: actions/setup-node@v4 |
79 | 66 | with: |
80 | | - sarif_file: 'trivy-results.sarif' |
81 | | - category: ${{ matrix.service }} |
| 67 | + node-version: '20' |
| 68 | + cache: 'npm' |
| 69 | + cache-dependency-path: frontend/package-lock.json |
| 70 | + |
| 71 | + - name: Install dependencies |
| 72 | + run: npm ci |
| 73 | + working-directory: frontend |
| 74 | + |
| 75 | + - name: Create Placeholder Config |
| 76 | + # This ensures the Angular build doesn't fail due to missing environment files |
| 77 | + run: | |
| 78 | + mkdir -p src/assets |
| 79 | + echo '{"production": true}' > src/assets/config.json |
| 80 | + working-directory: frontend |
| 81 | + |
| 82 | + - name: Build Angular App |
| 83 | + run: npm run build -- --configuration=production |
| 84 | + working-directory: frontend |
| 85 | + |
| 86 | + - name: Package Assets |
| 87 | + run: | |
| 88 | + cd frontend/dist/creative-studio |
| 89 | + zip -r ../../../frontend-assets.zip . |
| 90 | + cd ../../../ |
| 91 | + # Generate SHA-256 checksum |
| 92 | + sha256sum frontend-assets.zip > frontend-assets.zip.sha256 |
82 | 93 |
|
83 | 94 | - name: Install Cosign |
84 | 95 | uses: sigstore/cosign-installer@v3.5.0 |
85 | 96 |
|
86 | | - - name: Sign image and Attest SBOM |
87 | | - env: |
88 | | - DIGEST: ${{ steps.build-push.outputs.digest }} |
| 97 | + - name: Sign Frontend Blob |
| 98 | + # This signs the ZIP file using GitHub's OIDC identity |
89 | 99 | run: | |
90 | | - cosign sign --yes "${{ matrix.image }}@${{ env.DIGEST }}" |
91 | | - cosign attest --yes --type cyclonedx --predicate <(trivy image --format cyclonedx "${{ matrix.image }}@${{ env.DIGEST }}") "${{ matrix.image }}@${{ env.DIGEST }}" |
| 100 | + cosign sign-blob --yes frontend-assets.zip \ |
| 101 | + --bundle frontend-assets.zip.bundle |
92 | 102 |
|
93 | | - - name: Attest Build Provenance |
94 | | - # Official name for the GA version of build provenance |
95 | | - uses: actions/attest-build-provenance@v1 |
| 103 | + - name: Upload Artifacts to Release |
| 104 | + uses: softprops/action-gh-release@v2 |
96 | 105 | with: |
97 | | - subject-name: ${{ matrix.image }} |
98 | | - subject-digest: ${{ steps.build-push.outputs.digest }} |
99 | | - push-to-registry: true |
| 106 | + files: | |
| 107 | + frontend-assets.zip |
| 108 | + frontend-assets.zip.sha256 |
| 109 | + frontend-assets.zip.bundle |
| 110 | + env: |
| 111 | + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
0 commit comments