diff --git a/apps/docs/docs/intro.md b/apps/docs/docs/intro.md index b9e783954..15d0d35e7 100644 --- a/apps/docs/docs/intro.md +++ b/apps/docs/docs/intro.md @@ -26,7 +26,7 @@ Clone the Sharethrift repository and set up the development environment: ```bash git clone https://github.com/Sharethrift/sharethrift.git cd sharethrift -``` +```i Install dependencies and build the project: @@ -67,3 +67,52 @@ Sharethrift follows these core patterns: - **API Layer**: GraphQL and REST endpoints via Azure Functions Open any file in the `packages/` directory and start exploring: the project uses hot reloading for rapid development! + +## Local EdgeScan Setup + +EdgeScan is a Dynamic Application Security Testing (DAST) platform that scans live running applications to identify runtime vulnerabilities and security weaknesses. Unlike static analysis tools like Snyk or SonarCloud that scan source code, EdgeScan tests the actual deployed application behavior. + +### How to use + +- Use `pnpm run edgescan:dev` to run local security validation scans. +- **DO NOT** use `edgescan:agent` locally; it is strictly reserved for the GitHub Copilot AI Coding Agent and CI/CD automation. + +### Prerequisites + +#### 1. Apple Native Containers + +One-time setup for macOS developers: + +1. Download the signed installer package from Apple's container releases page. +2. Run the installer. +3. Start the container system with: + ```bash + container system start + ``` + Input 'Y' when prompted. +4. Confirm it is working with: + ```bash + container system status + ``` + Expected output: + ``` + container system status + apiserver is running + ``` + +#### 2. EdgeScan API Token + +1. Log in to https://intealth.edgescan.com +2. Go to Profile Settings and generate an API token +3. Export it in the terminal (optionally add to ~/.zshrc or ~/.bashrc for persistence): + ```bash + export ES_API_TOKEN="your token here" + ``` + +#### 3. EdgeScan Asset ID + +This is the asset you want to scan (provided by the EdgeScan team or available from the EdgeScan UI). Export it: + +```bash +export ES_ASSET_ID="your asset id here" +``` diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a3db070ac..4123c234f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -12,6 +12,7 @@ pool: vmImage: ubuntu-latest variables: + - group: edgescan-credential-sharethrift - group: sonarcloud-credential-sharethrift - group: github-credential-sharethrift - group: ui-sharethrift-settings-sharethrift @@ -62,4 +63,12 @@ stages: resourceGroupName: 'rg-sharethrift' appSettingsJsonFileRelativePathPri: 'apps/api/build-pipelines/config/dev-pri.json' frontDoorProfileName: 'simnova-afd' - frontDoorEndpointName: 'sth-fde-bzbjd6edbfhmcnam' \ No newline at end of file + frontDoorEndpointName: 'sth-fde-bzbjd6edbfhmcnam' + + + - 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/knip.json b/knip.json index 97c3b8dda..496caf033 100644 --- a/knip.json +++ b/knip.json @@ -96,5 +96,5 @@ "tsx", "vite" ], - "ignoreBinaries": ["func"] + "ignoreBinaries": ["func", "container"] } diff --git a/package.json b/package.json index 70c39c710..6288e74cb 100644 --- a/package.json +++ b/package.json @@ -51,8 +51,10 @@ "snyk:code": "snyk code test --org=simnova --remote-repo-url=https://github.com/simnova/sharethrift --severity-threshold=medium", "snyk:code:report": "snyk code test --org=simnova --remote-repo-url=https://github.com/simnova/sharethrift --target-reference=main --project-name=sharethrift-code --report", "snyk:iac": "snyk iac test iac/**/*.bicep apps/**/iac/**/*.bicep --org=simnova --remote-repo-url=https://github.com/simnova/sharethrift", - "snyk:iac:report": "snyk iac test iac/**/*.bicep apps/**/iac/**/*.bicep --org=simnova --remote-repo-url=https://github.com/simnova/sharethrift --target-reference=main --target-name=sharethrift-iac --report" - }, + "snyk:iac:report": "snyk iac test iac/**/*.bicep apps/**/iac/**/*.bicep --org=simnova --remote-repo-url=https://github.com/simnova/sharethrift --target-reference=main --target-name=sharethrift-iac --report", + "edgescan:agent": "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", + "edgescan:dev": "container run --tty --rm --platform linux/amd64 edgescan/cicd-integration:latest --api-token $ES_API_TOKEN --asset-id 74469 --start-scan --max-risk-threshold 3 --wait --color" + }, "pnpm": { "auditConfig": { "ignoreGhsas": [