Skip to content

Added badges

Added badges #24

Workflow file for this run

# =============================================================================
# CycloneDX Assessors Studio - CI Pipeline
# =============================================================================
# Security hardening:
# - All actions pinned to full commit SHAs (not tags)
# - Top-level permissions deny-all; each job grants minimum needed
# - persist-credentials: false on every checkout
# - npm ci with frozen lockfile (no mutation)
# - No use of pull_request_target
# - No secret exposure to PR builds
# =============================================================================
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
workflow_dispatch:
# Deny all permissions by default. Each job opts in to exactly what it needs.
permissions: {}
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
# ---------------------------------------------------------------------------
# Backend
# ---------------------------------------------------------------------------
backend-build:
name: "Backend / Build & Typecheck"
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read # checkout only
defaults:
run:
working-directory: backend
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: backend/package-lock.json
- name: Install dependencies
run: npm ci --ignore-scripts
env:
NODE_ENV: development
# argon2 requires a native build step; run it explicitly after npm ci
- name: Rebuild native modules
run: npm rebuild argon2
- name: Typecheck
run: npx tsc --noEmit
- name: Lint (if configured)
run: |
if [ -f .eslintrc.js ] || [ -f .eslintrc.json ] || [ -f .eslintrc.yml ] || [ -f eslint.config.js ] || [ -f eslint.config.mjs ]; then
npx eslint .
else
echo "No ESLint config found, skipping"
fi
backend-test:
name: "Backend / Test"
runs-on: ubuntu-latest
timeout-minutes: 10
needs: backend-build
permissions:
contents: read
defaults:
run:
working-directory: backend
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: backend/package-lock.json
- name: Install dependencies
run: npm ci --ignore-scripts
- name: Rebuild native modules
run: npm rebuild argon2
- name: Run tests with coverage
run: npx vitest run --reporter=verbose --coverage
env:
DATABASE_PROVIDER: pglite
PGLITE_DATA_DIR: ./data/test-pglite
JWT_SECRET: ci-testing-secret-that-is-at-least-32-characters-long
PORT: "3001"
LOG_LEVEL: error
CORS_ORIGIN: http://localhost:5173
- name: Upload backend coverage
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: backend-coverage
path: backend/coverage/lcov.info
retention-days: 5
if-no-files-found: warn
# ---------------------------------------------------------------------------
# Frontend
# ---------------------------------------------------------------------------
frontend-build:
name: "Frontend / Build & Typecheck"
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
defaults:
run:
working-directory: frontend
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install dependencies
run: npm ci --ignore-scripts
env:
NODE_ENV: development
- name: Typecheck
run: npx vue-tsc -b
- name: Lint (if configured)
run: |
if [ -f .eslintrc.js ] || [ -f .eslintrc.json ] || [ -f .eslintrc.yml ] || [ -f eslint.config.js ] || [ -f eslint.config.mjs ]; then
npx eslint .
else
echo "No ESLint config found, skipping"
fi
- name: Production build
run: npx vite build
- name: Upload build artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: frontend-dist
path: frontend/dist/
retention-days: 5
if-no-files-found: error
frontend-test:
name: "Frontend / Test"
runs-on: ubuntu-latest
timeout-minutes: 10
needs: frontend-build
permissions:
contents: read
defaults:
run:
working-directory: frontend
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install dependencies
run: npm ci --ignore-scripts
- name: Run tests with coverage
run: npx vitest run --reporter=verbose --coverage.enabled --coverage.reporter=text --coverage.reporter=lcov --coverage.reportsDirectory=./coverage
- name: Upload frontend coverage
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: frontend-coverage
path: frontend/coverage/lcov.info
retention-days: 5
if-no-files-found: warn
# ---------------------------------------------------------------------------
# Codacy coverage (main branch only) - upload coverage from test jobs
# ---------------------------------------------------------------------------
codacy-coverage:
name: "Codacy / Upload Coverage"
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 5
needs: [backend-test, frontend-test]
permissions:
contents: read
steps:
- name: Download backend coverage
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
name: backend-coverage
path: backend-coverage
- name: Download frontend coverage
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
name: frontend-coverage
path: frontend-coverage
continue-on-error: true
- name: Resolve coverage report paths
id: coverage-paths
run: |
REPORTS=""
if [ -f backend-coverage/lcov.info ]; then
REPORTS="backend-coverage/lcov.info"
fi
if [ -f frontend-coverage/lcov.info ]; then
if [ -n "$REPORTS" ]; then
REPORTS="$REPORTS,frontend-coverage/lcov.info"
else
REPORTS="frontend-coverage/lcov.info"
fi
fi
echo "reports=$REPORTS" >> "$GITHUB_OUTPUT"
- name: Upload coverage to Codacy
if: steps.coverage-paths.outputs.reports != ''
uses: codacy/codacy-coverage-reporter-action@89d6c85cfafaec52c72b6c5e8b2878d33104c699 # v1.3.0
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: ${{ steps.coverage-paths.outputs.reports }}
# ---------------------------------------------------------------------------
# Dependency review (PR only) - block PRs that introduce known vulns
# ---------------------------------------------------------------------------
dependency-review:
name: "Dependency Review"
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
pull-requests: write # post review comments
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Dependency Review
uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
with:
fail-on-severity: moderate
deny-licenses: AGPL-3.0, GPL-3.0
comment-summary-in-pr: always
# ---------------------------------------------------------------------------
# Docker snapshot (main branch only) - build and push snapshot image
# ---------------------------------------------------------------------------
docker:
name: "Docker / Snapshot"
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 30
needs: [backend-test, frontend-test]
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Log in to Docker Hub
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push snapshot image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
file: deploy/docker/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: cyclonedx/cyclonedx-assessors-studio:snapshot
cache-from: type=gha
cache-to: type=gha,mode=max