add release snap workflow #238
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: CI pipeline | |
on: | |
push: | |
branches: | |
- main | |
workflow_dispatch: | |
env: | |
HEROKU_APP: threatdragon-v2 | |
HEROKU_EMAIL: jon.gadsden@owasp.org | |
HEROKU_HEALTH: https://www.threatdragon.com/healthz | |
# threatdragon is the working area on docker hub so use this area | |
# owasp/threat-dragon is the final release area so DO NOT use that | |
IMAGE_NAME: threatdragon/owasp-threat-dragon:latest | |
ZAP_FILE: zap-scan-push | |
# for security reasons the github actions are pinned to specific release versions | |
jobs: | |
server_unit_tests: | |
name: Server unit tests | |
runs-on: ubuntu-24.04 | |
defaults: | |
run: | |
working-directory: td.server | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4.2.0 | |
- name: Use node LTS 20.14.0 | |
uses: actions/setup-node@v4.1.0 | |
with: | |
node-version: '20.14.0' | |
- name: Cache NPM dir | |
uses: actions/cache@v4.1.1 | |
with: | |
path: ~/.npm | |
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} | |
restore-keys: | | |
${{ runner.os }}-node- | |
${{ runner.os }}- | |
- name: Install packages | |
run: npm clean-install | |
- name: lint | |
run: npm run lint | |
- name: Unit test | |
run: npm run test:unit | |
- name: Create SBOM | |
run: npm run make-sbom | |
- name: Save SBOM artifact | |
uses: actions/upload-artifact@v4.4.0 | |
with: | |
name: sboms-server | |
path: './td.server/sbom.*' | |
include-hidden-files: true | |
site_unit_tests: | |
name: Site unit tests | |
runs-on: ubuntu-24.04 | |
defaults: | |
run: | |
working-directory: td.vue | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4.2.0 | |
- name: Use node LTS 20.14.0 | |
uses: actions/setup-node@v4.1.0 | |
with: | |
node-version: '20.14.0' | |
- name: Cache NPM dir | |
uses: actions/cache@v4.1.1 | |
with: | |
path: ~/.npm | |
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} | |
restore-keys: | | |
${{ runner.os }}-node- | |
${{ runner.os }}- | |
- name: Install packages | |
run: npm clean-install | |
- name: lint | |
run: npm run lint | |
- name: Unit test | |
run: npm run test:unit | |
desktop_unit_tests: | |
name: Desktop unit tests | |
runs-on: ubuntu-24.04 | |
defaults: | |
run: | |
working-directory: td.vue | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4.2.0 | |
- name: Use node LTS 20.14.0 | |
uses: actions/setup-node@v4.1.0 | |
with: | |
node-version: '20.14.0' | |
- name: Cache NPM dir | |
uses: actions/cache@v4.1.1 | |
with: | |
path: ~/.npm | |
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} | |
restore-keys: | | |
${{ runner.os }}-node- | |
${{ runner.os }}- | |
- name: Install packages | |
run: npm clean-install | |
- name: lint | |
run: npm run lint:desktop | |
- name: Unit test | |
run: npm run test:desktop | |
codeql: | |
name: Analyze with codeql | |
runs-on: ubuntu-24.04 | |
needs: [server_unit_tests, site_unit_tests] | |
permissions: | |
security-events: write | |
strategy: | |
fail-fast: false | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@v4.2.0 | |
- name: Initialize CodeQL | |
uses: github/codeql-action/init@v3.27.0 | |
with: | |
languages: 'javascript' | |
config-file: ./.github/codeql/codeql-config.yml | |
# If you wish to specify custom queries, you can do so here or in a config file. | |
# By default, queries listed here will override any specified in a config file. | |
# Prefix the list here with "+" to use these queries and those in the config file. | |
- name: CodeQL autobuild | |
uses: github/codeql-action/autobuild@v3.27.0 | |
- name: Perform vulnerability analysis | |
uses: github/codeql-action/analyze@v3.27.0 | |
build_docker_image: | |
name: Build latest docker | |
runs-on: ubuntu-24.04 | |
needs: [site_unit_tests, server_unit_tests] | |
if: github.repository == 'OWASP/threat-dragon' | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4.2.0 | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3.2.0 | |
- name: Set up Docker Buildx | |
id: buildx | |
uses: docker/setup-buildx-action@v3.7.0 | |
with: | |
install: true | |
- name: Cache Docker layers | |
uses: actions/cache@v4.1.1 | |
with: | |
path: /tmp/.buildx-cache | |
key: ${{ runner.os }}-buildx-${{ hashFiles('Dockerfile') }} | |
restore-keys: | | |
${{ runner.os }}-buildx- | |
${{ runner.os }}- | |
- name: Login to Docker Hub | |
uses: docker/login-action@v3.3.0 | |
with: | |
username: ${{ secrets.DOCKERHUB_USERNAME }} | |
password: ${{ secrets.DOCKERHUB_TOKEN }} | |
# platform manifests not (yet) supported, so split out architectures | |
- name: Build for amd64 and push latest | |
id: docker_build_amd64 | |
uses: docker/build-push-action@v6.10.0 | |
with: | |
context: ./ | |
file: ./Dockerfile | |
builder: ${{ steps.buildx.outputs.name }} | |
push: true | |
tags: ${{ env.IMAGE_NAME }} | |
cache-from: type=local,src=/tmp/.buildx-cache | |
cache-to: type=local,dest=/tmp/.buildx-cache,mode=max | |
platforms: linux/amd64 | |
load: true | |
- name: Build for arm64 and push latest-arm64 | |
id: docker_build_arm64 | |
uses: docker/build-push-action@v6.10.0 | |
with: | |
context: ./ | |
file: ./Dockerfile | |
builder: ${{ steps.buildx.outputs.name }} | |
push: true | |
tags: ${{ env.IMAGE_NAME }}-arm64 | |
cache-from: type=local,src=/tmp/.buildx-cache | |
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max | |
platforms: linux/arm64 | |
load: true | |
- name: fetch app SBOMs | |
run: docker run --rm --entrypoint tar "$IMAGE_ID" -c boms | tar -xv | |
env: | |
IMAGE_ID: ${{ steps.docker_build_amd64.outputs.imageid }} | |
- name: Save SBOM artifact | |
uses: actions/upload-artifact@v4.4.0 | |
with: | |
name: sboms-container-image-app | |
path: './boms/*' | |
include-hidden-files: true | |
if-no-files-found: error | |
- # Temp fix for large cache bug | |
# https://github.com/docker/build-push-action/issues/252 | |
name: Move cache | |
run: | | |
rm -rf /tmp/.buildx-cache | |
mv /tmp/.buildx-cache-new /tmp/.buildx-cache | |
heroku_deploy: | |
name: Upload to Heroku | |
runs-on: ubuntu-22.04 # ubuntu-24.04 does not have heroku cli, yet | |
needs: build_docker_image | |
steps: | |
- uses: actions/checkout@v4.2.0 | |
- uses: akhileshns/heroku-deploy@v3.13.15 | |
with: | |
heroku_api_key: ${{ secrets.HEROKU_API_KEY }} | |
heroku_app_name: ${{ env.HEROKU_APP }} | |
heroku_email: ${{ env.HEROKU_EMAIL }} | |
healthcheck: ${{ env.HEROKU_HEALTH }} | |
rollbackonhealthcheckfailed: true | |
usedocker: true | |
browserstack_smoke_test: | |
name: Browserstack smoke test | |
runs-on: ubuntu-24.04 | |
needs: heroku_deploy | |
defaults: | |
run: | |
working-directory: td.vue | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4.2.0 | |
- name: Use node LTS 20.14.0 | |
uses: actions/setup-node@v4.1.0 | |
with: | |
node-version: '20.14.0' | |
- name: Cache NPM dir | |
uses: actions/cache@v4.1.1 | |
with: | |
path: ~/.npm | |
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} | |
restore-keys: | | |
${{ runner.os }}-node- | |
${{ runner.os }}- | |
- name: Install packages | |
run: npm clean-install | |
- name: BrowserStack Env Setup | |
uses: browserstack/github-actions/setup-env@v1.0.1 | |
with: | |
username: ${{ secrets.BROWSERSTACK_USERNAME }} | |
access-key: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} | |
- name: Run cross-browser smoke tests | |
run: npm run test:e2e-smokes | |
e2e_smokes: | |
name: Site e2e smokes | |
runs-on: ubuntu-24.04 | |
needs: build_docker_image | |
defaults: | |
run: | |
working-directory: td.vue | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4.2.0 | |
- name: Run Threat Dragon | |
run: | | |
docker run -d \ | |
-p 3000:3000 \ | |
-e ENCRYPTION_JWT_REFRESH_SIGNING_KEY='${{ secrets.CI_JWT_REFRESH_SIGNING_KEY }}' \ | |
-e ENCRYPTION_JWT_SIGNING_KEY='${{ secrets.CI_JWT_SIGNING_KEY }}' \ | |
-e ENCRYPTION_KEYS='${{ secrets.CI_SESSION_ENCRYPTION_KEYS }}' \ | |
-e GITHUB_CLIENT_ID='${{ secrets.CI_GITHUB_CLIENT_ID }}' \ | |
-e GITHUB_CLIENT_SECRET='${{ secrets.CI_GITHUB_CLIENT_SECRET }}' \ | |
-e NODE_ENV='development' \ | |
-e SERVER_API_PROTOCOL='http' \ | |
${{ env.IMAGE_NAME }} | |
- name: Use node LTS 20.14.0 | |
uses: actions/setup-node@v4.1.0 | |
with: | |
node-version: '20.14.0' | |
- name: Cache NPM dir | |
uses: actions/cache@v4.1.1 | |
with: | |
path: ~/.npm | |
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} | |
restore-keys: | | |
${{ runner.os }}-node- | |
${{ runner.os }}- | |
- name: Install packages | |
run: npm clean-install | |
- name: Run e2e tests | |
run: npm run test:e2e-ci-smokes | |
- name: Upload e2e videos | |
uses: actions/upload-artifact@v4.4.0 | |
with: | |
name: e2e_vids.zip | |
path: td.vue/tests/e2e/videos | |
if: ${{ failure() && hashFiles('td.vue/tests/e2e/videos/') != '' }} | |
e2e_tests: | |
name: Site e2e tests | |
runs-on: ubuntu-24.04 | |
needs: e2e_smokes | |
defaults: | |
run: | |
working-directory: td.vue | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4.2.0 | |
- name: Run Threat Dragon | |
run: | | |
docker run -d \ | |
-p 3000:3000 \ | |
-e GITHUB_CLIENT_ID='${{ secrets.CI_GITHUB_CLIENT_ID }}' \ | |
-e GITHUB_CLIENT_SECRET='${{ secrets.CI_GITHUB_CLIENT_SECRET }}' \ | |
-e ENCRYPTION_JWT_REFRESH_SIGNING_KEY='${{ secrets.CI_JWT_REFRESH_SIGNING_KEY }}' \ | |
-e ENCRYPTION_JWT_SIGNING_KEY='${{ secrets.CI_JWT_SIGNING_KEY }}' \ | |
-e ENCRYPTION_KEYS='${{ secrets.CI_SESSION_ENCRYPTION_KEYS }}' \ | |
-e NODE_ENV='development' \ | |
-e SERVER_API_PROTOCOL='http' \ | |
${{ env.IMAGE_NAME }} | |
- name: Use node LTS 20.14.0 | |
uses: actions/setup-node@v4.1.0 | |
with: | |
node-version: '20.14.0' | |
- name: Cache NPM dir | |
uses: actions/cache@v4.1.1 | |
with: | |
path: ~/.npm | |
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} | |
restore-keys: | | |
${{ runner.os }}-node- | |
${{ runner.os }}- | |
- name: Install packages | |
run: npm clean-install | |
- name: Run e2e tests | |
run: npm run test:e2e-ci | |
- name: Upload e2e videos | |
uses: actions/upload-artifact@v4.4.0 | |
with: | |
name: e2e_vids.zip | |
path: td.vue/tests/e2e/videos | |
if: ${{ failure() && hashFiles('td.vue/tests/e2e/videos/') != '' }} | |
zap_scan_web_app: | |
name: Local site zap scan | |
runs-on: ubuntu-24.04 | |
needs: build_docker_image | |
steps: | |
- name: Run Threat Dragon | |
run: | | |
docker run -d \ | |
-p 3000:3000 \ | |
-e GITHUB_CLIENT_ID='${{ secrets.CI_GITHUB_CLIENT_ID }}' \ | |
-e GITHUB_CLIENT_SECRET='${{ secrets.CI_GITHUB_CLIENT_SECRET }}' \ | |
-e ENCRYPTION_JWT_REFRESH_SIGNING_KEY='${{ secrets.CI_JWT_REFRESH_SIGNING_KEY }}' \ | |
-e ENCRYPTION_JWT_SIGNING_KEY='${{ secrets.CI_JWT_SIGNING_KEY }}' \ | |
-e ENCRYPTION_KEYS='${{ secrets.CI_SESSION_ENCRYPTION_KEYS }}' \ | |
-e NODE_ENV='development' \ | |
-e SERVER_API_PROTOCOL='http' \ | |
${{ env.IMAGE_NAME }} | |
- name: Checkout | |
uses: actions/checkout@v4.2.0 | |
- name: ZAP Scan | |
uses: zaproxy/action-full-scan@v0.12.0 | |
with: | |
token: ${{ secrets.GITHUB_TOKEN }} | |
target: 'http://localhost:3000' | |
rules_file_name: '.github/workflows/.zap-rules-web.tsv' | |
allow_issue_writing: false | |
fail_action: true | |
artifact_name: ${{ env.ZAP_FILE }} | |
cmd_options: '-a' | |
scan_image_with_trivy: | |
name: Scan image with Trivy | |
runs-on: ubuntu-24.04 | |
needs: build_docker_image | |
permissions: | |
contents: write | |
security-events: write | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4.2.0 | |
- name: Run Trivy vulnerability scanner | |
uses: aquasecurity/trivy-action@0.29.0 | |
with: | |
image-ref: '${{ env.IMAGE_NAME }}' | |
format: 'template' | |
template: '@/contrib/sarif.tpl' | |
trivyignores: '.github/workflows/.trivyignore' | |
output: 'trivy-results.sarif' | |
- name: Upload scan results to GitHub Security tab | |
uses: github/codeql-action/upload-sarif@v3.27.0 | |
with: | |
sarif_file: 'trivy-results.sarif' | |
desktop_windows_test: | |
name: Windows desktop build test | |
runs-on: windows-latest | |
needs: [desktop_unit_tests, site_unit_tests] | |
defaults: | |
run: | |
working-directory: td.vue | |
steps: | |
- name: Check out | |
uses: actions/checkout@v4.2.0 | |
- name: Use node LTS 20.14.0 | |
uses: actions/setup-node@v4.1.0 | |
with: | |
node-version: '20.14.0' | |
- name: Cache NPM dir | |
uses: actions/cache@v4.1.1 | |
with: | |
path: ~/.npm | |
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} | |
restore-keys: | | |
${{ runner.os }}-node- | |
${{ runner.os }}- | |
- name: Install packages | |
run: npm install | |
- name: Build Windows executable | |
run: npm run build:desktop -- --windows --publish never | |
- name: Save SBOM artifact | |
uses: actions/upload-artifact@v4.4.0 | |
with: | |
name: sboms-desktop-windows-site | |
path: './td.vue/dist-desktop/bundled/.sbom/*' | |
include-hidden-files: true | |
if-no-files-found: error | |
desktop_macos_test: | |
name: MacOS desktop build test | |
runs-on: macos-latest | |
needs: [desktop_unit_tests, site_unit_tests] | |
defaults: | |
run: | |
working-directory: td.vue | |
steps: | |
- name: Check out | |
uses: actions/checkout@v4.2.0 | |
- name: Use node LTS 20.14.0 | |
uses: actions/setup-node@v4.1.0 | |
with: | |
node-version: '20.14.0' | |
- name: Cache NPM dir | |
uses: actions/cache@v4.1.1 | |
with: | |
path: ~/.npm | |
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} | |
restore-keys: | | |
${{ runner.os }}-node- | |
${{ runner.os }}- | |
- name: Install packages | |
run: npm install | |
- name: Build MacOS disk image | |
env: | |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: npm run build:desktop -- --mac --publish never | |
- name: Save SBOM artifact | |
uses: actions/upload-artifact@v4.4.0 | |
with: | |
name: sboms-desktop-macos-site | |
path: './td.vue/dist-desktop/bundled/.sbom/*' | |
include-hidden-files: true | |
if-no-files-found: error | |
desktop_linux_test: | |
name: Linux desktop build test | |
runs-on: ubuntu-24.04 | |
needs: [desktop_unit_tests, site_unit_tests] | |
defaults: | |
run: | |
working-directory: td.vue | |
steps: | |
- name: Check out | |
uses: actions/checkout@v4.2.0 | |
- name: Use node LTS 20.14.0 | |
uses: actions/setup-node@v4.1.0 | |
with: | |
node-version: '20.14.0' | |
- name: Cache NPM dir | |
uses: actions/cache@v4.1.1 | |
with: | |
path: ~/.npm | |
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} | |
restore-keys: | | |
${{ runner.os }}-node- | |
${{ runner.os }}- | |
- name: Install packages | |
run: npm install | |
- name: Build Linux app images | |
shell: bash | |
env: | |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: npm run build:desktop -- --linux AppImage deb rpm --publish never | |
- name: Print logs on error | |
if: ${{ failure() }} | |
run: find . -name "*.log" -exec cat '{}' \; -print | |
- name: Save SBOM artifact | |
uses: actions/upload-artifact@v4.4.0 | |
with: | |
name: sboms-desktop-linux-site | |
path: './td.vue/dist-desktop/bundled/.sbom/*' | |
include-hidden-files: true | |
if-no-files-found: error | |
desktop_linux_snap_test: | |
name: Linux snap build test | |
runs-on: ubuntu-24.04 | |
needs: [desktop_unit_tests, site_unit_tests] | |
defaults: | |
run: | |
working-directory: td.vue | |
steps: | |
- name: Check out | |
uses: actions/checkout@v4.2.0 | |
- name: Use node LTS 20.14.0 | |
uses: actions/setup-node@v4.1.0 | |
with: | |
node-version: '20.14.0' | |
- name: Cache NPM dir | |
uses: actions/cache@v4.1.1 | |
with: | |
path: ~/.npm | |
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} | |
restore-keys: | | |
${{ runner.os }}-node- | |
${{ runner.os }}- | |
- name: Install packages | |
run: npm install | |
- name: Build Linux snap | |
shell: bash | |
env: | |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: npm run build:desktop -- --linux snap | |
- name: Print logs on error | |
if: ${{ failure() }} | |
run: find . -name "*.log" -exec cat '{}' \; -print | |
- name: Save SBOM artifact | |
uses: actions/upload-artifact@v4.4.0 | |
with: | |
name: sboms-desktop-linux-snap-site | |
path: './td.vue/dist-desktop/bundled/.sbom/*' | |
include-hidden-files: true | |
if-no-files-found: error | |
sbom_combiner_test: | |
name: SBOM combiner test | |
runs-on: ubuntu-24.04 | |
needs: | |
- server_unit_tests | |
- desktop_macos_test | |
- desktop_linux_test | |
- desktop_linux_snap_test | |
- desktop_windows_test | |
- build_docker_image | |
steps: | |
- name: Fetch prepared SBOM artifacts | |
uses: actions/download-artifact@v4.1.7 | |
with: | |
pattern: 'sboms-*' | |
merge-multiple: false | |
path: 'raw/' | |
- name: Fetch SBOMs | |
run: | | |
set -eux | |
mkdir -p sboms/threat-dragon-container-image/app/ | |
cp raw/sboms-server/sbom.json sboms/threat-dragon-server-bom.json | |
cp raw/sboms-server/sbom.xml sboms/threat-dragon-server-bom.xml | |
cp raw/sboms-desktop-windows-site/bom.json sboms/threat-dragon-desktop-windows-site-bom.json | |
cp raw/sboms-desktop-windows-site/bom.xml sboms/threat-dragon-desktop-windows-site-bom.xml | |
cp raw/sboms-desktop-macos-site/bom.json sboms/threat-dragon-desktop-macos-site-bom.json | |
cp raw/sboms-desktop-macos-site/bom.xml sboms/threat-dragon-desktop-macos-site-bom.xml | |
cp raw/sboms-desktop-linux-site/bom.json sboms/threat-dragon-desktop-linux-site-bom.json | |
cp raw/sboms-desktop-linux-site/bom.xml sboms/threat-dragon-desktop-linux-site-bom.xml | |
cp raw/sboms-desktop-linux-snap-site/bom.json sboms/threat-dragon-desktop-linux-snap-site-bom.json | |
cp raw/sboms-desktop-linux-snap-site/bom.xml sboms/threat-dragon-desktop-linux-snap-site-bom.xml | |
cp raw/sboms-container-image-app/* sboms/threat-dragon-container-image/app/ | |
- name: Save SBOM artifact | |
uses: actions/upload-artifact@v4.4.0 | |
with: | |
name: sboms | |
path: 'sboms/' | |
include-hidden-files: true |