|
4 | 4 | push: |
5 | 5 | branches: |
6 | 6 | - core |
7 | | - - basic |
8 | 7 | pull_request: |
9 | 8 | branches: |
10 | 9 | - core |
11 | | - - basic |
12 | 10 |
|
13 | 11 | env: |
14 | 12 | NODE_VERSION: "22.x" |
15 | 13 |
|
| 14 | + # ----- Static analysis toggles & config ----- |
| 15 | + # Flip to "false" to disable a tool. |
| 16 | + SNYK_ENABLED: "true" |
| 17 | + SONARCLOUD_ENABLED: "true" |
| 18 | + |
| 19 | + # The branch on which static-analysis jobs run (push or PR target). |
| 20 | + # Fork users: change to your default branch (e.g. "main"). |
| 21 | + STATIC_ANALYSIS_BRANCH: "core" |
| 22 | + |
| 23 | + # Fork users: replace these with your own SonarCloud org slug and project key. |
| 24 | + # Find the project key in SonarCloud: |
| 25 | + # - the `id=...` value in the project page URL, OR |
| 26 | + # - Project -> Administration -> Information -> Key. |
| 27 | + # GitHub-imported projects typically use "<org>_<repo>"; manually-created ones may differ. |
| 28 | + SONAR_ORGANIZATION: "bartstc" |
| 29 | + SONAR_PROJECT_KEY: "bartstc_vite-ts-react-template" |
| 30 | + |
16 | 31 | jobs: |
| 32 | + # Exposes workflow-level env vars as outputs so they can be referenced in |
| 33 | + # job-level `if:` expressions (the `env` context is not available there). |
| 34 | + config: |
| 35 | + runs-on: ubuntu-latest |
| 36 | + outputs: |
| 37 | + snyk_enabled: ${{ steps.set.outputs.snyk_enabled }} |
| 38 | + sonarcloud_enabled: ${{ steps.set.outputs.sonarcloud_enabled }} |
| 39 | + static_analysis_branch: ${{ steps.set.outputs.static_analysis_branch }} |
| 40 | + steps: |
| 41 | + - id: set |
| 42 | + run: | |
| 43 | + echo "snyk_enabled=$SNYK_ENABLED" >> "$GITHUB_OUTPUT" |
| 44 | + echo "sonarcloud_enabled=$SONARCLOUD_ENABLED" >> "$GITHUB_OUTPUT" |
| 45 | + echo "static_analysis_branch=$STATIC_ANALYSIS_BRANCH" >> "$GITHUB_OUTPUT" |
| 46 | +
|
17 | 47 | lint-tests: |
18 | 48 | uses: ./.github/workflows/run-tests.yml |
19 | 49 | with: |
@@ -163,6 +193,96 @@ jobs: |
163 | 193 | name: storybook-coverage-report |
164 | 194 | path: coverage/**/* |
165 | 195 |
|
| 196 | + snyk: |
| 197 | + needs: config |
| 198 | + if: > |
| 199 | + ${{ needs.config.outputs.snyk_enabled == 'true' |
| 200 | + && (github.ref_name == needs.config.outputs.static_analysis_branch |
| 201 | + || github.base_ref == needs.config.outputs.static_analysis_branch) }} |
| 202 | + runs-on: ubuntu-latest |
| 203 | + permissions: |
| 204 | + contents: read |
| 205 | + security-events: write |
| 206 | + steps: |
| 207 | + - name: Checkout |
| 208 | + uses: actions/checkout@v4 |
| 209 | + |
| 210 | + - name: Enable corepack |
| 211 | + run: corepack enable |
| 212 | + |
| 213 | + - name: Setup Node.js |
| 214 | + uses: actions/setup-node@v4 |
| 215 | + with: |
| 216 | + node-version: ${{ env.NODE_VERSION }} |
| 217 | + cache: "pnpm" |
| 218 | + |
| 219 | + - name: Install dependencies |
| 220 | + run: pnpm install --no-frozen-lockfile --ignore-scripts |
| 221 | + |
| 222 | + - name: Install Snyk CLI |
| 223 | + run: npm install -g snyk |
| 224 | + |
| 225 | + - name: Snyk Open Source (SCA) |
| 226 | + env: |
| 227 | + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} |
| 228 | + run: | |
| 229 | + snyk test \ |
| 230 | + --all-projects \ |
| 231 | + --strict-out-of-sync=false \ |
| 232 | + --severity-threshold=high \ |
| 233 | + --sarif-file-output=snyk-deps.sarif |
| 234 | +
|
| 235 | + - name: Snyk Code (SAST) |
| 236 | + env: |
| 237 | + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} |
| 238 | + run: | |
| 239 | + snyk code test \ |
| 240 | + --severity-threshold=high \ |
| 241 | + --sarif-file-output=snyk-code.sarif |
| 242 | +
|
| 243 | + - name: Upload Snyk SARIF to GitHub Security |
| 244 | + if: always() |
| 245 | + uses: github/codeql-action/upload-sarif@v3 |
| 246 | + with: |
| 247 | + sarif_file: . |
| 248 | + category: snyk |
| 249 | + |
| 250 | + sonarcloud: |
| 251 | + needs: [config, unit-tests, storybook-tests] |
| 252 | + if: > |
| 253 | + ${{ needs.config.outputs.sonarcloud_enabled == 'true' |
| 254 | + && (github.ref_name == needs.config.outputs.static_analysis_branch |
| 255 | + || github.base_ref == needs.config.outputs.static_analysis_branch) }} |
| 256 | + runs-on: ubuntu-latest |
| 257 | + steps: |
| 258 | + - name: Checkout |
| 259 | + uses: actions/checkout@v4 |
| 260 | + with: |
| 261 | + fetch-depth: 0 # full history for blame & new-code detection |
| 262 | + |
| 263 | + - name: Download coverage artifacts |
| 264 | + uses: actions/download-artifact@v4 |
| 265 | + with: |
| 266 | + pattern: "*-coverage-report" |
| 267 | + |
| 268 | + - name: Rewrite LCOV source paths for Sonar |
| 269 | + run: | |
| 270 | + # vitest's `projectRoot: "./src"` makes SF: paths relative to src/. |
| 271 | + # Sonar expects paths relative to repo root, so prepend src/. |
| 272 | + sed -i 's|^SF:|SF:src/|' \ |
| 273 | + unit-coverage-report/lcov.info \ |
| 274 | + storybook-coverage-report/lcov.info |
| 275 | +
|
| 276 | + - name: SonarCloud Scan |
| 277 | + uses: SonarSource/sonarqube-scan-action@v4 |
| 278 | + env: |
| 279 | + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 280 | + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} |
| 281 | + with: |
| 282 | + args: > |
| 283 | + -Dsonar.projectKey=${{ env.SONAR_PROJECT_KEY }} |
| 284 | + -Dsonar.organization=${{ env.SONAR_ORGANIZATION }} |
| 285 | +
|
166 | 286 | build: |
167 | 287 | needs: |
168 | 288 | [ |
|
0 commit comments