Skip to content

Build, Attest and Release #21

Build, Attest and Release

Build, Attest and Release #21

Workflow file for this run

name: Build, Attest and Release
on:
workflow_dispatch:
inputs:
version:
description: "Version to release (vX.Y.Z format)"
required: true
default: "v0.1.0"
prerelease:
description: "Is this a pre-release?"
type: boolean
default: false
push:
tags:
- "v*"
# Restrict top-level permissions to minimum required defaults
permissions: read-all
jobs:
prepare:
name: Prepare Release
runs-on: ubuntu-latest
# Only prepare job needs write permissions for commit and tagging
permissions:
contents: write # Required for git auto-commit
outputs:
version: ${{ steps.get-version.outputs.version }}
is_prerelease: ${{ github.event.inputs.prerelease || 'false' }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- name: Get version
id: get-version
run: |
if [[ "${{ github.event_name }}" == "push" ]]; then
VERSION=${GITHUB_REF#refs/tags/}
else
VERSION=${{ github.event.inputs.version }}
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Version: ${VERSION}"
- name: Setup display and dependencies
run: |
sudo apt-get update
sudo apt-get install -y xvfb libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libnss3 libxss1 libasound2t64 libxtst6 xauth
sudo mkdir -p /var/run/dbus
sudo dbus-daemon --system --fork
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "22"
cache: "npm"
- name: Cache dependencies
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Cache Cypress binary
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: ~/.cache/Cypress
key: cypress-${{ runner.os }}-${{ hashFiles('**/package.json') }}
- name: Install dependencies
run: npm ci
- name: Set Version for release
if: github.event_name == 'workflow_dispatch'
run: |
PLAIN_VERSION="${{ github.event.inputs.version }}"
# Remove 'v' prefix if present
PLAIN_VERSION="${PLAIN_VERSION#v}"
npm version $PLAIN_VERSION --no-git-tag-version
- uses: stefanzweifel/git-auto-commit-action@e348103e9026cc0eee72ae06630dbe30c8bf7a79 # v5.1.0
if: github.event_name == 'workflow_dispatch'
with:
commit_message: "chore(release): bump version to ${{ github.event.inputs.version }}"
tagging_message: "${{ github.event.inputs.version }}"
- name: Check licenses
run: npm run test:licenses
- name: Verify Cypress
run: npx cypress verify
- name: Start app and run Cypress tests
run: |
xvfb-run --auto-servernum --server-args="-screen 0 1280x720x24" npm run test:e2e
env:
CYPRESS_VIDEO: false
- name: Install GraphViz
run: |
sudo apt-get update
sudo apt-get install -y graphviz
# Run tests with coverage
- name: Run tests with coverage
run: npm run coverage
# Create coverage directory in docs
- name: Prepare coverage directory
run: |
mkdir -p docs/coverage docs/dependencies
echo "Coverage directory prepared at $(date)" > docs/coverage/build-info.txt
# Generate documentation bundle
- name: Generate Documentation
id: generate-docs
run: |
npm run docs:bundle || (echo "::error::Documentation generation failed" && exit 1)
echo "Documentation generation completed at $(date)" > docs/docs-build-info.txt
- name: Merge e2e test report
run: npm run test:e2ereportmerge
- name: Generate e2e html report
run: npm run test:e2ereporthtmlall
# Always deploy documentation in prepare phase
- name: Deploy Documentation to GitHub Pages
uses: JamesIves/github-pages-deploy-action@6c2d9db40f9296374acc17b90404b6e8864128c8 # v4.7.3
with:
folder: docs
target-folder: docs
branch: main
clean: false
commit-message: "docs: update documentation for ${{ needs.prepare.outputs.version || 'development' }}"
build:
name: Build Release Package
needs: [prepare]
runs-on: ubuntu-latest
# Build job needs specific permissions for attestations
permissions:
contents: read
id-token: write # Required for OIDC
attestations: write # Required for SBOM and build attestations
steps:
- name: Harden Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
# Use GITHUB_REF directly for tag events
ref: ${{ github.event_name == 'push' && github.ref || github.event_name == 'workflow_dispatch' && github.event.inputs.version || '' }}
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "22"
cache: "npm"
- name: Cache dependencies
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
env:
VITE_APP_VERSION: ${{ needs.prepare.outputs.version }}
- name: Create artifacts directory
run: |
mkdir -p release-artifacts
# Use build directory instead of dist to match vite config
cd build
zip -r ../cia-compliance-manager-${{ needs.prepare.outputs.version }}.zip .
- name: Upload build artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: build-artifacts
path: |
build/
cia-compliance-manager-${{ needs.prepare.outputs.version }}.zip
if-no-files-found: error
- name: Generate SBOM
uses: anchore/sbom-action@f325610c9f50a54015d37c8d16cb3b0e2c8f4de0 # v0.18.0
id: sbom
with:
format: spdx-json
output-file: cia-compliance-manager-${{ needs.prepare.outputs.version }}.spdx.json
artifact-name: cia-compliance-manager-${{ needs.prepare.outputs.version }}
- name: Generate artifact attestation
uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3
id: attest
with:
subject-path: cia-compliance-manager-${{ needs.prepare.outputs.version }}.zip
subject-digest-algorithm: sha256
bundle-path: cia-compliance-manager-${{ needs.prepare.outputs.version }}.zip.intoto.jsonl
- name: Copy artifact attestation for zip
run: cp ${{ steps.attest.outputs.bundle-path }} cia-compliance-manager-${{ needs.prepare.outputs.version }}.zip.intoto.jsonl
- name: Generate SBOM attestation
id: attestsbom
uses: actions/attest-sbom@115c3be05ff3974bcbd596578934b3f9ce39bf68 # v2.2.0
with:
subject-path: cia-compliance-manager-${{ needs.prepare.outputs.version }}.zip
sbom-path: cia-compliance-manager-${{ needs.prepare.outputs.version }}.spdx.json
- name: Copy SBOM attestation for zip
run: cp ${{ steps.attestsbom.outputs.bundle-path }} cia-compliance-manager-${{ needs.prepare.outputs.version }}.spdx.json.intoto.jsonl
- name: Upload security artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: security-artifacts
path: |
cia-compliance-manager-${{ needs.prepare.outputs.version }}.spdx.json
cia-compliance-manager-${{ needs.prepare.outputs.version }}.zip.intoto.jsonl
cia-compliance-manager-${{ needs.prepare.outputs.version }}.spdx.json.intoto.jsonl
if-no-files-found: error
release:
name: Create Release
needs: [prepare, build]
runs-on: ubuntu-latest
# Release job needs specific permissions to create GitHub releases
permissions:
contents: write # Required to create releases
id-token: write # Required for OIDC
steps:
- name: Harden Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
# Use GITHUB_REF directly for tag events
ref: ${{ github.event_name == 'push' && github.ref || github.event_name == 'workflow_dispatch' && github.event.inputs.version || '' }}
- name: Download build artifacts
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
with:
name: build-artifacts
path: artifacts/build
- name: Download security artifacts
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
with:
name: security-artifacts
path: artifacts/security
- name: Draft Release Notes
id: release-drafter
uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0
with:
version: ${{ needs.prepare.outputs.version }}
tag: ${{ needs.prepare.outputs.version }}
name: CIA Compliance Manager ${{ needs.prepare.outputs.version }}
publish: false
prerelease: ${{ needs.prepare.outputs.is_prerelease }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Create GitHub Release with all artifacts
- name: Create GitHub Release
uses: ncipollo/release-action@440c8c1cb0ed28b9f43e4d1d670870f059653174 # v1.16.0
with:
tag: ${{ needs.prepare.outputs.version }}
name: CIA Compliance Manager ${{ needs.prepare.outputs.version }}
body: ${{ steps.release-drafter.outputs.body }}
generateReleaseNotes: true
draft: false
prerelease: ${{ needs.prepare.outputs.is_prerelease }}
artifacts: |
artifacts/build/cia-compliance-manager-${{ needs.prepare.outputs.version }}.zip
artifacts/security/cia-compliance-manager-${{ needs.prepare.outputs.version }}.spdx.json
artifacts/security/cia-compliance-manager-${{ needs.prepare.outputs.version }}.zip.intoto.jsonl
artifacts/security/cia-compliance-manager-${{ needs.prepare.outputs.version }}.spdx.json.intoto.jsonl
token: ${{ secrets.GITHUB_TOKEN }}
# Selectively clean only application files
- name: Clean application files
run: |
# Only remove specific application files, preserving documentation
rm -rf docs/index.html docs/assets
# Log the cleanup for debugging
echo "Application files cleaned at $(date)" > docs/app-update-info.txt
# Deploy new application version
- name: Deploy new version
run: |
mkdir -p docs
unzip -o artifacts/build/cia-compliance-manager-${{ needs.prepare.outputs.version }}.zip -d docs/
# Create version marker for traceability
echo "Version ${{ needs.prepare.outputs.version }} deployed at $(date)" > docs/version.txt
# Final deployment with all components
- name: Deploy to GitHub Pages
uses: JamesIves/github-pages-deploy-action@6c2d9db40f9296374acc17b90404b6e8864128c8 # v4.7.3
with:
folder: docs
target-folder: docs
branch: main
clean: false
commit-message: "chore(release): deploy version ${{ needs.prepare.outputs.version }}"