Skip to content

Commit 5eb5600

Browse files
committed
test sca
1 parent a3b8527 commit 5eb5600

2 files changed

Lines changed: 289 additions & 44 deletions

File tree

.github/workflows/ci-dev.yml

Lines changed: 96 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ env:
2828
# ========================================
2929
RUN_TESTS: "false" # Usually disabled in dev for speed
3030
RUN_SONARQUBE: "true" # Enable for testing the new dotnet-coverage integration
31+
RUN_SCA_SCAN: "true" # Enable SCA Scan
3132

3233
# ========================================
3334
# Tag Stategy for Build and GitOps
@@ -54,8 +55,11 @@ jobs:
5455
cluster_name: ${{ steps.config.outputs.cluster_name }}
5556
environment: ${{ steps.config.outputs.environment }}
5657
load_custom_vars: ${{ steps.config.outputs.load_custom_vars }}
58+
project_name: ${{ steps.config.outputs.project_name }}
59+
project_version: ${{ steps.config.outputs.project_version }}
5760
run_tests: ${{ steps.config.outputs.run_tests }}
5861
run_sonarqube: ${{ steps.config.outputs.run_sonarqube }}
62+
run_sca_scan: ${{ steps.config.outputs.run_sca_scan }}
5963
service_name: ${{ steps.config.outputs.service_name }} # e.g., your service name
6064
service_type: ${{ steps.config.outputs.service_type }} # e.g., webclient, webservice, winservice
6165
sonarqube_host: ${{ steps.config.outputs.sonarqube_host }} # e.g., https://code.selise.biz
@@ -91,6 +95,7 @@ jobs:
9195
echo "cluster_name=${{ env.CLUSTER_NAME }}" >> $GITHUB_OUTPUT
9296
echo "load_custom_vars=${{ env.LOAD_CUSTOM_VARS }}" >> $GITHUB_OUTPUT
9397
echo "tag_strategy=${{ env.TAG_STRATEGY }}" >> $GITHUB_OUTPUT
98+
echo "run_sca_scan=${{ env.RUN_SCA_SCAN }}" >> $GITHUB_OUTPUT
9499
95100
# From vars.env (if loaded) or fallback to defaults
96101
echo "dockerfile_path=${DOCKERFILE:-./Dockerfile}" >> $GITHUB_OUTPUT
@@ -104,6 +109,11 @@ jobs:
104109
echo "package_manager=${PACKAGE_MANAGER:-npm}" >> $GITHUB_OUTPUT
105110
echo "node_version=${NODE_VERSION:-21}" >> $GITHUB_OUTPUT
106111
112+
# Project configuration for SCA Scan
113+
echo "project_name=${PROJECT_NAME:-${{ github.event.repository.name }}}" >> $GITHUB_OUTPUT
114+
echo "project_version=${PROJECT_VERSION:-${{ github.ref_name }}}" >> $GITHUB_OUTPUT
115+
echo "dependency_track_host=${DEPENDENCY_TRACK_HOST:-api-dt.seliseblocks.com}" >> $GITHUB_OUTPUT
116+
107117
# SonarQube specific configurations (map from vars.env names)
108118
echo "sonar_project_key=${SONAR_KEY:-}" >> $GITHUB_OUTPUT
109119
echo "sonar_organization=${AUTHOR:-}" >> $GITHUB_OUTPUT
@@ -203,47 +213,89 @@ jobs:
203213
# secrets:
204214
# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN_GLOBAL }}
205215

206-
# # Build and push image
207-
# build:
208-
# needs: [initialization, sonarqube]
209-
# if: ${{ github.event_name == 'push' && (success() || needs.sonarqube.result == 'skipped' ) }}
210-
# uses: ./.github/workflows/build-push.yml
211-
# with:
212-
# SERVICE_NAME: ${{ needs.initialization.outputs.service_name }}
213-
# # SERVICE_TYPE: ${{ needs.initialization.outputs.service_type }}
214-
# SERVICE_TYPE: "webservice" # e.g., webclient, webservice, winservice
215-
# ENVIRONMENT: ${{ needs.initialization.outputs.environment }}
216-
# TAG_STRATEGY: ${{ needs.initialization.outputs.tag_strategy }} # Options: "both" (default), "semantic", "commit"
217-
# DOCKERFILE_PATH: ${{ needs.initialization.outputs.dockerfile_path }}
218-
# VERSION: ${{ needs.initialization.outputs.version }} # Optional: Comment out to skip version suffix
219-
# BUILD_ARGS: |
220-
# ci_build=dev
221-
# secrets:
222-
# AZURE_CREDENTIALS: ${{ secrets.AZURE_AKS_BLOCKS_CREDENTIALS }}
223-
# AZURE_CONTAINER_REGISTRY: ${{ secrets.AZURE_BLOCKS_CONTAINER_REGISTRY }}
224-
# ACR_RESOURCE_GROUP: ${{ secrets.ClUSTER_AKS_BLOCKS_RESOURCE_GROUP }}
225-
# SELISE_GITHUB_PAT: ${{ secrets.SELISE_GITHUB_PAT }}
226-
227-
# # Update GitOps repository
228-
# update-gitops:
229-
# needs: [initialization, build]
230-
# if: |
231-
# github.event_name == 'push' &&
232-
# always() &&
233-
# needs.initialization.result == 'success' &&
234-
# needs.build.result == 'success'
235-
# uses: ./.github/workflows/update-gitops.yml
236-
# with:
237-
# SERVICE_NAME: ${{ needs.initialization.outputs.service_name }}
238-
# SERVICE_TYPE: "webservice" # Match the service type from build job
239-
# ENVIRONMENT: ${{ needs.initialization.outputs.environment }}
240-
# VERSION: ${{ needs.initialization.outputs.version }} # Pass version for proper file naming
241-
# IMAGE_TAG: ${{ needs.build.outputs.image_tag }}
242-
# COMMIT_TAG: ${{ needs.build.outputs.commit_tag }}
243-
# SEMANTIC_TAG: ${{ needs.build.outputs.semantic_tag }}
244-
# TAG_STRATEGY: ${{ needs.initialization.outputs.tag_strategy }} # Options: "commit" (default), "semantic", or "primary"
245-
# CLUSTER_NAME: ${{ needs.initialization.outputs.cluster_name }}
246-
# # GITOPS_BRANCH: "main"
247-
# secrets:
248-
# SELISE_GITHUB_PAT: ${{ secrets.SELISE_GITHUB_PAT }}
249-
# AZURE_CONTAINER_REGISTRY: ${{ secrets.AZURE_BLOCKS_CONTAINER_REGISTRY }}
216+
# ==============================================
217+
# SCA Scan - Pass variables as inputs
218+
# ==============================================
219+
sca-scan:
220+
if: needs.initialization.outputs.run_sca_scan == 'true'
221+
needs: [initialization]
222+
uses: ./.github/workflows/sca-scan-js-recommended.yml
223+
with:
224+
# Project Configuration
225+
PROJECT_NAME: ${{ needs.initialization.outputs.project_name }}
226+
PROJECT_VERSION: ${{ needs.initialization.outputs.project_version }}
227+
228+
# Node Configuration
229+
NODE_VERSION: ${{ needs.initialization.outputs.node_version }}
230+
PACKAGE_MANAGER: ${{ needs.initialization.outputs.package_manager }}
231+
INSTALL_COMMAND: "ci"
232+
233+
# Dependency-Track Configuration
234+
DEPENDENCY_TRACK_HOST: ${{ needs.initialization.outputs.dependency_track_host }}
235+
AUTO_CREATE_PROJECT: true
236+
ARTIFACT_RETENTION_DAYS: 7
237+
238+
# Optional Features
239+
HAS_SUBMODULES: ${{ needs.initialization.outputs.has_submodules == 'true' }}
240+
241+
secrets:
242+
DEPENDENCY_TRACK_API_KEY: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
243+
SELISE_GITHUB_PAT: ${{ secrets.SELISE_GITHUB_PAT }}
244+
# ==============================================
245+
# ALTERNATIVE: Simple Direct Passing (No Init Job)
246+
# ==============================================
247+
# If you don't need vars.env, you can pass values directly:
248+
#
249+
# jobs:
250+
# sca-scan:
251+
# uses: ./.github/workflows/sca-scan-js-recommended.yml
252+
# with:
253+
# PROJECT_NAME: "my-project"
254+
# DEPENDENCY_TRACK_HOST: "api-dt.seliseblocks.com"
255+
# secrets:
256+
# DEPENDENCY_TRACK_API_KEY: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
257+
258+
# # Build and push image
259+
# build:
260+
# needs: [initialization, sonarqube]
261+
# if: ${{ github.event_name == 'push' && (success() || needs.sonarqube.result == 'skipped' ) }}
262+
# uses: ./.github/workflows/build-push.yml
263+
# with:
264+
# SERVICE_NAME: ${{ needs.initialization.outputs.service_name }}
265+
# # SERVICE_TYPE: ${{ needs.initialization.outputs.service_type }}
266+
# SERVICE_TYPE: "webservice" # e.g., webclient, webservice, winservice
267+
# ENVIRONMENT: ${{ needs.initialization.outputs.environment }}
268+
# TAG_STRATEGY: ${{ needs.initialization.outputs.tag_strategy }} # Options: "both" (default), "semantic", "commit"
269+
# DOCKERFILE_PATH: ${{ needs.initialization.outputs.dockerfile_path }}
270+
# VERSION: ${{ needs.initialization.outputs.version }} # Optional: Comment out to skip version suffix
271+
# BUILD_ARGS: |
272+
# ci_build=dev
273+
# secrets:
274+
# AZURE_CREDENTIALS: ${{ secrets.AZURE_AKS_BLOCKS_CREDENTIALS }}
275+
# AZURE_CONTAINER_REGISTRY: ${{ secrets.AZURE_BLOCKS_CONTAINER_REGISTRY }}
276+
# ACR_RESOURCE_GROUP: ${{ secrets.ClUSTER_AKS_BLOCKS_RESOURCE_GROUP }}
277+
# SELISE_GITHUB_PAT: ${{ secrets.SELISE_GITHUB_PAT }}
278+
279+
# # Update GitOps repository
280+
# update-gitops:
281+
# needs: [initialization, build]
282+
# if: |
283+
# github.event_name == 'push' &&
284+
# always() &&
285+
# needs.initialization.result == 'success' &&
286+
# needs.build.result == 'success'
287+
# uses: ./.github/workflows/update-gitops.yml
288+
# with:
289+
# SERVICE_NAME: ${{ needs.initialization.outputs.service_name }}
290+
# SERVICE_TYPE: "webservice" # Match the service type from build job
291+
# ENVIRONMENT: ${{ needs.initialization.outputs.environment }}
292+
# VERSION: ${{ needs.initialization.outputs.version }} # Pass version for proper file naming
293+
# IMAGE_TAG: ${{ needs.build.outputs.image_tag }}
294+
# COMMIT_TAG: ${{ needs.build.outputs.commit_tag }}
295+
# SEMANTIC_TAG: ${{ needs.build.outputs.semantic_tag }}
296+
# TAG_STRATEGY: ${{ needs.initialization.outputs.tag_strategy }} # Options: "commit" (default), "semantic", or "primary"
297+
# CLUSTER_NAME: ${{ needs.initialization.outputs.cluster_name }}
298+
# # GITOPS_BRANCH: "main"
299+
# secrets:
300+
# SELISE_GITHUB_PAT: ${{ secrets.SELISE_GITHUB_PAT }}
301+
# AZURE_CONTAINER_REGISTRY: ${{ secrets.AZURE_BLOCKS_CONTAINER_REGISTRY }}
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
name: Reusable - SCA Scan JS/TS
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
# ========================================
7+
# General Configuration
8+
# ========================================
9+
PROJECT_NAME:
10+
description: "Project name for Dependency-Track (defaults to repository name)"
11+
required: false
12+
type: string
13+
default: ""
14+
15+
PROJECT_VERSION:
16+
description: "Project version for Dependency-Track (defaults to branch/tag name)"
17+
required: false
18+
type: string
19+
default: ""
20+
21+
NODE_VERSION:
22+
description: "Node.js version to use"
23+
required: false
24+
type: string
25+
default: "18"
26+
27+
# ========================================
28+
# Package Manager Configuration
29+
# ========================================
30+
PACKAGE_MANAGER:
31+
description: "Package manager to use (npm, yarn, pnpm)"
32+
required: false
33+
type: string
34+
default: "npm"
35+
36+
INSTALL_COMMAND:
37+
description: "Command to install dependencies (e.g., 'ci', 'install --frozen-lockfile')"
38+
required: false
39+
type: string
40+
default: "ci"
41+
42+
# ========================================
43+
# Dependency-Track Configuration
44+
# ========================================
45+
DEPENDENCY_TRACK_HOST:
46+
description: "Dependency-Track server hostname"
47+
required: false
48+
type: string
49+
default: "api-dt.seliseblocks.com"
50+
51+
SBOM_FILENAME:
52+
description: "SBOM filename to generate"
53+
required: false
54+
type: string
55+
default: "bom.xml"
56+
57+
AUTO_CREATE_PROJECT:
58+
description: "Auto-create project in Dependency-Track if it doesn't exist"
59+
required: false
60+
type: boolean
61+
default: true
62+
63+
ARTIFACT_RETENTION_DAYS:
64+
description: "Number of days to retain SBOM artifact"
65+
required: false
66+
type: number
67+
default: 7
68+
69+
# ========================================
70+
# Optional Features
71+
# ========================================
72+
HAS_SUBMODULES:
73+
description: "Set to true if repository uses Git submodules"
74+
required: false
75+
type: boolean
76+
default: false
77+
78+
secrets:
79+
DEPENDENCY_TRACK_API_KEY:
80+
required: true
81+
description: "Dependency-Track API key"
82+
83+
SELISE_GITHUB_PAT:
84+
required: false
85+
description: "GitHub PAT for private repositories and submodules"
86+
87+
jobs:
88+
sca-scan:
89+
name: SCA Scan & SBOM Upload
90+
runs-on: ubuntu-latest
91+
permissions:
92+
contents: read
93+
id-token: write
94+
95+
steps:
96+
- name: Checkout repository
97+
uses: actions/checkout@v4
98+
with:
99+
fetch-depth: 0
100+
submodules: ${{ inputs.HAS_SUBMODULES && 'recursive' || 'false' }}
101+
token: ${{ secrets.SELISE_GITHUB_PAT || github.token }}
102+
103+
- name: Update submodules
104+
if: inputs.HAS_SUBMODULES
105+
run: |
106+
git submodule update --init --recursive
107+
echo "✅ Submodules updated" >> $GITHUB_STEP_SUMMARY
108+
109+
- name: Setup Node.js
110+
uses: actions/setup-node@v4
111+
with:
112+
node-version: ${{ inputs.NODE_VERSION }}
113+
cache: ${{ inputs.PACKAGE_MANAGER }}
114+
115+
- name: Install dependencies
116+
run: |
117+
echo "📦 Installing dependencies with ${{ inputs.PACKAGE_MANAGER }}..."
118+
${{ inputs.PACKAGE_MANAGER }} ${{ inputs.INSTALL_COMMAND }}
119+
120+
- name: Determine project configuration
121+
id: config
122+
run: |
123+
# Determine project name
124+
if [ -n "${{ inputs.PROJECT_NAME }}" ]; then
125+
PROJECT_NAME="${{ inputs.PROJECT_NAME }}"
126+
else
127+
PROJECT_NAME="${{ github.event.repository.name }}"
128+
fi
129+
echo "project_name=$PROJECT_NAME" >> $GITHUB_OUTPUT
130+
131+
# Determine project version
132+
if [ -n "${{ inputs.PROJECT_VERSION }}" ]; then
133+
PROJECT_VERSION="${{ inputs.PROJECT_VERSION }}"
134+
else
135+
PROJECT_VERSION="${{ github.ref_name }}"
136+
fi
137+
echo "project_version=$PROJECT_VERSION" >> $GITHUB_OUTPUT
138+
139+
# Summary
140+
echo "### 🔍 SCA Scan Configuration" >> $GITHUB_STEP_SUMMARY
141+
echo "- **Project**: \`$PROJECT_NAME\`" >> $GITHUB_STEP_SUMMARY
142+
echo "- **Version**: \`$PROJECT_VERSION\`" >> $GITHUB_STEP_SUMMARY
143+
echo "- **Package Manager**: ${{ inputs.PACKAGE_MANAGER }}" >> $GITHUB_STEP_SUMMARY
144+
echo "- **Node Version**: ${{ inputs.NODE_VERSION }}" >> $GITHUB_STEP_SUMMARY
145+
146+
- name: Generate CycloneDX SBOM
147+
run: |
148+
echo "📋 Generating SBOM..."
149+
npx @cyclonedx/cyclonedx-npm \
150+
--output-file ${{ inputs.SBOM_FILENAME }} \
151+
--output-format xml
152+
153+
echo "✅ SBOM generated: ${{ inputs.SBOM_FILENAME }}" >> $GITHUB_STEP_SUMMARY
154+
155+
# Show SBOM stats
156+
if [ -f "${{ inputs.SBOM_FILENAME }}" ]; then
157+
COMPONENT_COUNT=$(grep -c "<component" ${{ inputs.SBOM_FILENAME }} || echo "0")
158+
echo "- **Components found**: $COMPONENT_COUNT" >> $GITHUB_STEP_SUMMARY
159+
fi
160+
161+
- name: Upload SBOM as workflow artifact
162+
uses: actions/upload-artifact@v4
163+
with:
164+
name: sbom-cyclonedx-xml
165+
path: ${{ inputs.SBOM_FILENAME }}
166+
retention-days: ${{ inputs.ARTIFACT_RETENTION_DAYS }}
167+
if-no-files-found: error
168+
169+
- name: Upload to Dependency-Track
170+
id: dt-upload
171+
uses: DependencyTrack/gh-upload-sbom@v3.1.0
172+
with:
173+
serverhostname: ${{ inputs.DEPENDENCY_TRACK_HOST }}
174+
apikey: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
175+
projectname: ${{ steps.config.outputs.project_name }}
176+
projectversion: ${{ steps.config.outputs.project_version }}
177+
bomfilename: ${{ inputs.SBOM_FILENAME }}
178+
autocreate: ${{ inputs.AUTO_CREATE_PROJECT }}
179+
180+
- name: SCA Scan Summary
181+
if: always()
182+
run: |
183+
echo "## 📊 SCA Scan Complete" >> $GITHUB_STEP_SUMMARY
184+
echo "" >> $GITHUB_STEP_SUMMARY
185+
echo "### Configuration" >> $GITHUB_STEP_SUMMARY
186+
echo "- **Project**: ${{ steps.config.outputs.project_name }}" >> $GITHUB_STEP_SUMMARY
187+
echo "- **Version**: ${{ steps.config.outputs.project_version }}" >> $GITHUB_STEP_SUMMARY
188+
echo "- **SBOM Format**: CycloneDX XML" >> $GITHUB_STEP_SUMMARY
189+
echo "" >> $GITHUB_STEP_SUMMARY
190+
echo "### Results" >> $GITHUB_STEP_SUMMARY
191+
echo "- **Dependency-Track**: https://${{ inputs.DEPENDENCY_TRACK_HOST }}" >> $GITHUB_STEP_SUMMARY
192+
echo "- **Project URL**: https://${{ inputs.DEPENDENCY_TRACK_HOST }}/projects" >> $GITHUB_STEP_SUMMARY
193+
echo "- **SBOM Artifact**: Available in workflow artifacts for ${{ inputs.ARTIFACT_RETENTION_DAYS }} days" >> $GITHUB_STEP_SUMMARY

0 commit comments

Comments
 (0)