diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index e3c2685f7..f869ab05d 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -77,6 +77,12 @@ jobs: distribution: 'temurin' java-version: '17' + - name: Validate Docker and Pre-Pull Edgescan Image + run: | + docker --version + docker ps + docker pull edgescan/cicd-integration:latest # Ensure Edgescan image is available in this job and verify Docker access + - name: Verify required environment variables run: | if [ -z "$SONAR_TOKEN" ]; then @@ -91,8 +97,18 @@ jobs: echo "Error: SNYK_TOKEN is not set." exit 1 fi + if [ -z "$ES_API_TOKEN" ]; then + echo "Error: ES_API_TOKEN is not set." + exit 1 + fi + if [ -z "$ES_ASSET_ID" ]; then + echo "Error: ES_ASSET_ID is not set." + exit 1 + fi echo "All required environment variables are set." env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} GH_TOKEN: ${{ secrets.GH_TOKEN }} SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + ES_API_TOKEN: ${{ secrets.ES_API_TOKEN }} + ES_ASSET_ID: ${{ secrets.ES_ASSET_ID }} diff --git a/.snyk b/.snyk index aaedea816..1d9351d92 100644 --- a/.snyk +++ b/.snyk @@ -3,7 +3,7 @@ ignore: 'SNYK-JS-SIRV-12558119': - '* > sirv@2.0.4': reason: 'Transitive dependency in Docusaurus; not exploitable in static site serving context (dev-only asset handler)' - expires: '2025-12-31T00:00:00.000Z' + expires: '2026-01-19T00:00:00.000Z' created: '2025-11-06T15:57:00.000Z' 'SNYK-JS-JSYAML-13961110': - '* > js-yaml': @@ -27,4 +27,9 @@ ignore: - '@docusaurus/preset-classic@3.9.2 > * > express': reason: 'Transitive dependency in Docusaurus; not exploitable in current usage.' expires: '2025-12-31T00:00:00.000Z' - created: '2025-12-02T09:39:00.000Z' \ No newline at end of file + created: '2025-12-02T09:39:00.000Z' + 'SNYK-JS-QS-14724253': + - '* > qs': + reason: 'Transitive dependency in express, @docusaurus/core, @apollo/server, apollo-link-rest; not exploitable in current usage.' + expires: '2026-01-19T00:00:00.000Z' + created: '2026-01-05T09:39:00.000Z' \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 700826ef0..39cd13fc2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -12,10 +12,11 @@ pool: vmImage: ubuntu-latest variables: - - group: sonarcloud-credential-cellixjs + - group: edgescan-credential-cellixjs - group: github-credential-cellixjs - - group: ui-community-settings-cellixjs - group: snyk-credential-cellixjs + - group: sonarcloud-credential-cellixjs + - group: ui-community-settings-cellixjs - name: deploymentDefaultLocation value: 'eastus2' - name: ServiceConnectionName @@ -63,4 +64,11 @@ stages: resourceGroupName: 'rg-sharethrift' appSettingsJsonFileRelativePathPri: 'apps/api/build-pipelines/config/dev-pri.json' frontDoorProfileName: 'simnova-afd' - frontDoorEndpointName: 'ocm-fde-ged3a8gxcvfxafaf' \ No newline at end of file + frontDoorEndpointName: 'ocm-fde-ged3a8gxcvfxafaf' + + - template: ./build-pipeline/core/monorepo-edgescan-stage.yml + parameters: + stageName: 'EdgeScan_DEV' + dependsOn: 'DEV' + vmImageName: $(vmImageName) + esAssetId: $(ES_ASSET_ID_DEV) \ No newline at end of file diff --git a/build-pipeline/core/monorepo-edgescan-stage.yml b/build-pipeline/core/monorepo-edgescan-stage.yml new file mode 100644 index 000000000..d16e5b315 --- /dev/null +++ b/build-pipeline/core/monorepo-edgescan-stage.yml @@ -0,0 +1,79 @@ +parameters: +- name: stageName + type: string + default: 'EdgeScan' +- name: dependsOn + type: string +- name: esAssetId + type: string +- name: vmImageName + type: string + default: 'ubuntu-latest' + +stages: +- stage: ${{parameters.stageName}} + displayName: 'EdgeScan Security Scan' + dependsOn: ${{parameters.dependsOn}} + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + jobs: + - job: EdgeScan + displayName: 'EdgeScan CI/CD Integration' + variables: + # Generates a monthly key like "2026-01" to ensure the image is refreshed monthly + cacheMonth: $[format('{0:yyyy-MM}', pipeline.startTime)] + pool: + vmImage: ${{parameters.vmImageName}} + steps: + - task: Cache@2 + displayName: 'Cache EdgeScan Docker Image' + inputs: + key: 'docker | edgescan | latest | $(cacheMonth)' + path: $(Pipeline.Workspace)/docker-cache + cacheHitVar: DOCKER_CACHE_HIT + + - task: Bash@3 + displayName: 'Pull or Restore EdgeScan Image' + inputs: + targetType: 'inline' + script: | + set -euo pipefail + mkdir -p $(Pipeline.Workspace)/docker-cache + + if [ "${DOCKER_CACHE_HIT:-}" = "true" ] && [ -f "$(Pipeline.Workspace)/docker-cache/edgescan.tar" ]; then + echo "Restoring EdgeScan image from cache..." + docker load -i $(Pipeline.Workspace)/docker-cache/edgescan.tar + else + echo "Cache miss or missing tarball. Pulling from Docker Hub..." + docker pull edgescan/cicd-integration:latest + echo "Saving image to cache for future runs..." + docker save edgescan/cicd-integration:latest -o $(Pipeline.Workspace)/docker-cache/edgescan.tar + fi + + - task: Bash@3 + displayName: 'Run EdgeScan Scan' + inputs: + targetType: 'inline' + script: | + set -euo pipefail + + if [ -z "$ES_API_TOKEN" ]; then + echo "Error: ES_API_TOKEN must be set in the variable group." + exit 1 + fi + + if [ -z "${{ parameters.esAssetId }}" ]; then + echo "Error: ES_ASSET_ID_DEV must be set in the variable group." + exit 1 + fi + + echo "Triggering EdgeScan for Asset ID: ${{ parameters.esAssetId }}" + + docker run --tty --rm \ + edgescan/cicd-integration:latest \ + --api-token "$ES_API_TOKEN" \ + --asset-id "${{ parameters.esAssetId }}" \ + --start-scan \ + --max-risk-threshold 3 \ + --wait --color + env: + ES_API_TOKEN: $(ES_API_TOKEN) diff --git a/package.json b/package.json index 489aee8f4..7f4bda89b 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,8 @@ "snyk:iac": "snyk iac test iac/build/**/*.json --org=cellixjs --remote-repo-url=https://github.com/CellixJs/cellixjs", "snyk:iac:report": "snyk iac test iac/build/**/*.json --org=cellixjs --remote-repo-url=https://github.com/CellixJs/cellixjs --target-reference=main --target-name=cellixjs-iac --report", "analyze": "pnpm -r exec -- pnpm dlx @e18e/cli analyze", - "prepare": "husky" + "prepare": "husky", + "edgescan:run": "docker run --tty --rm edgescan/cicd-integration:latest --api-token $ES_API_TOKEN --asset-id $ES_ASSET_ID --start-scan --max-risk-threshold 3 --wait --color" }, "devDependencies": { "@amiceli/vitest-cucumber": "^5.1.2", @@ -75,6 +76,11 @@ "vitest": "catalog:" }, "pnpm": { + "auditConfig": { + "ignoreGhsas": [ + "GHSA-6rw7-vpxm-498p" + ] + }, "overrides": { "vite": "catalog:", "jiti": "2.6.1"