Pin Bun 1.4.3 with packageManager, and force every bun run script onto the Bun runtime through bunfig so ng, ESLint and Prettier never fall back to an installed Node. Type checking uses bun check for the application and test projects, next to the Angular build. CI jobs install the pinned release from a checksum-verified download instead of npm and run project steps in a shell without Node on PATH, which stays available only for the checkout and upload actions. The image test's fake docker runs on Bun. Refs #290, #293 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
238 lines
9.4 KiB
YAML
238 lines
9.4 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
pull_request:
|
|
types: [opened, reopened, synchronize, edited]
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
# Gitea's checkout and upload-artifact actions are JavaScript actions that the runner
|
|
# executes with the job container's own `node`, so those containers keep Node. Project
|
|
# commands never use it: the jobs that run them install the pinned Bun with
|
|
# scripts/install-bun.sh and run `run:` steps under a shell whose PATH has Bun but no Node.
|
|
|
|
concurrency:
|
|
group: ci-${{ github.event_name }}-${{ github.ref }}
|
|
cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
|
|
jobs:
|
|
policy:
|
|
name: policy
|
|
runs-on: ubuntu-latest
|
|
container: node:24.21.0
|
|
defaults:
|
|
run:
|
|
shell: env PATH=/opt/bun/bin:/usr/bin:/bin bash -e {0}
|
|
outputs:
|
|
slug: ${{ steps.policy.outputs.slug }}
|
|
tag: ${{ steps.policy.outputs.tag }}
|
|
steps:
|
|
- uses: https://gitea.com/actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
- name: Install Bun
|
|
run: sh scripts/install-bun.sh
|
|
- name: Policy regression tests
|
|
run: bun scripts/ci-policy.test.mjs && bun scripts/ci-image.test.mjs
|
|
- name: Validate event and commit
|
|
id: policy
|
|
run: bun scripts/ci-policy.mjs
|
|
|
|
validate:
|
|
name: validate
|
|
runs-on: ubuntu-latest
|
|
container: node:24.21.0
|
|
defaults:
|
|
run:
|
|
shell: env PATH=/opt/bun/bin:/usr/bin:/bin bash -e {0}
|
|
steps:
|
|
- uses: https://gitea.com/actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
- name: Install Bun
|
|
run: sh scripts/install-bun.sh
|
|
- run: bun install --frozen-lockfile
|
|
- run: bun run lint
|
|
- run: bun run format:check
|
|
- run: bun run typecheck
|
|
|
|
test:
|
|
name: test
|
|
runs-on: ubuntu-latest
|
|
container: node:24.21.0
|
|
defaults:
|
|
run:
|
|
shell: env PATH=/opt/bun/bin:/usr/bin:/bin bash -e {0}
|
|
steps:
|
|
- uses: https://gitea.com/actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
- name: Install Bun
|
|
run: sh scripts/install-bun.sh
|
|
- run: bun install --frozen-lockfile
|
|
- run: bun scripts/generate-langs.js
|
|
- name: Functional coverage
|
|
run: bun test --config=bunfig.coverage.toml --isolate --path-ignore-patterns='**/benchmark/**'
|
|
- name: Coverage report
|
|
if: ${{ always() }}
|
|
run: bun scripts/coverage-reports.mjs
|
|
- name: Upload coverage
|
|
if: ${{ always() }}
|
|
uses: https://gitea.com/actions/upload-artifact@v3
|
|
with:
|
|
name: coverage
|
|
path: coverage/
|
|
retention-days: 7
|
|
if-no-files-found: error
|
|
|
|
benchmark:
|
|
name: benchmark
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: node:24.21.0
|
|
options: --memory=3g
|
|
defaults:
|
|
run:
|
|
shell: env PATH=/opt/bun/bin:/usr/bin:/bin bash -e {0}
|
|
steps:
|
|
- uses: https://gitea.com/actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
- name: Install Bun
|
|
run: sh scripts/install-bun.sh
|
|
- run: bun install --frozen-lockfile
|
|
- run: bun scripts/generate-langs.js
|
|
- name: Benchmark protocol with relative gate
|
|
run: timeout 600s bun test src/app/benchmark --timeout=600000
|
|
|
|
build:
|
|
name: build
|
|
runs-on: ubuntu-latest
|
|
container: node:24.21.0
|
|
defaults:
|
|
run:
|
|
shell: env PATH=/opt/bun/bin:/usr/bin:/bin bash -e {0}
|
|
steps:
|
|
- uses: https://gitea.com/actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
- name: Install Bun
|
|
run: sh scripts/install-bun.sh
|
|
- run: bun install --frozen-lockfile
|
|
- run: bun run build -- --configuration production
|
|
- uses: https://gitea.com/actions/upload-artifact@v3
|
|
with:
|
|
name: dist
|
|
path: dist/
|
|
retention-days: 7
|
|
if-no-files-found: error
|
|
|
|
security:
|
|
name: security
|
|
runs-on: ubuntu-latest
|
|
container: node:24.21.0
|
|
steps:
|
|
- uses: https://gitea.com/actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
- name: Install scanners
|
|
run: |
|
|
apt-get update
|
|
apt-get install --yes --no-install-recommends python3-venv
|
|
python3 -m venv /tmp/semgrep
|
|
/tmp/semgrep/bin/pip install semgrep==1.180.0
|
|
case "$(uname -m)" in
|
|
x86_64) trivy_arch=64bit ;;
|
|
aarch64) trivy_arch=ARM64 ;;
|
|
*) echo 'Unsupported Trivy architecture' >&2; exit 1 ;;
|
|
esac
|
|
archive="trivy_0.75.0_Linux-${trivy_arch}.tar.gz"
|
|
curl --fail --location --silent --show-error "https://github.com/aquasecurity/trivy/releases/download/v0.75.0/${archive}" --output "/tmp/${archive}"
|
|
curl --fail --location --silent --show-error https://github.com/aquasecurity/trivy/releases/download/v0.75.0/trivy_0.75.0_checksums.txt --output /tmp/trivy-checksums.txt
|
|
(cd /tmp && sha256sum --check --ignore-missing trivy-checksums.txt)
|
|
tar -xzf "/tmp/${archive}" -C /usr/local/bin trivy
|
|
- name: JavaScript and TypeScript SAST
|
|
run: /tmp/semgrep/bin/semgrep scan --config p/javascript --config p/typescript --metrics off --sarif --output semgrep-results.sarif src scripts
|
|
- name: Dependency and secret scan
|
|
if: ${{ !cancelled() }}
|
|
run: trivy fs --db-repository public.ecr.aws/aquasecurity/trivy-db:2 --format sarif --output trivy-results.sarif --skip-dirs node_modules,dist,coverage .
|
|
- name: Security reports
|
|
if: ${{ always() }}
|
|
uses: https://gitea.com/actions/upload-artifact@v3
|
|
with:
|
|
name: security
|
|
path: '*-results.sarif'
|
|
retention-days: 7
|
|
if-no-files-found: error
|
|
|
|
images:
|
|
name: images
|
|
needs: [policy, validate, test, benchmark, build, security]
|
|
if: >-
|
|
success() &&
|
|
(github.event_name == 'push' ||
|
|
(github.event_name == 'pull_request' &&
|
|
github.event.pull_request.head.repo.full_name == github.repository))
|
|
runs-on: ubuntu-latest
|
|
container: docker:29.8.2
|
|
concurrency:
|
|
group: image-${{ needs.policy.outputs.tag != '' && 'stable' || needs.policy.outputs.slug }}
|
|
cancel-in-progress: false
|
|
services:
|
|
docker:
|
|
image: docker:29.8.2-dind
|
|
env:
|
|
DOCKER_TLS_CERTDIR: ''
|
|
options: >-
|
|
--privileged
|
|
--health-cmd "docker info"
|
|
--health-interval 5s
|
|
--health-timeout 5s
|
|
--health-retries 12
|
|
env:
|
|
DOCKER_HOST: tcp://docker:2375
|
|
DOCKER_TLS_CERTDIR: ''
|
|
defaults:
|
|
run:
|
|
shell: sh
|
|
steps:
|
|
# Alpine's nodejs package is for the checkout action only (it shares /usr/bin
|
|
# with git); Bun needs libgcc and libstdc++ and the installer needs curl.
|
|
- name: Install checkout runtime and tools
|
|
run: apk add --no-cache nodejs git curl libgcc libstdc++
|
|
- uses: https://gitea.com/actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
- name: Install Bun
|
|
run: sh scripts/install-bun.sh
|
|
- name: Build branch images or promote a release
|
|
env:
|
|
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
|
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
|
run: /opt/bun/bin/bun scripts/ci-image.mjs
|
|
|
|
required:
|
|
name: required
|
|
if: ${{ always() }}
|
|
needs: [policy, validate, test, benchmark, build, security, images]
|
|
runs-on: ubuntu-latest
|
|
container: node:24.21.0
|
|
env:
|
|
CHECK_RESULTS: ${{ needs.policy.result }} ${{ needs.validate.result }} ${{ needs.test.result }} ${{ needs.benchmark.result }} ${{ needs.build.result }} ${{ needs.security.result }}
|
|
IMAGE_RESULT: ${{ needs.images.result }}
|
|
IMAGE_EXPECTED: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) }}
|
|
steps:
|
|
- name: Require successful validation and expected publication
|
|
run: |
|
|
test "$CHECK_RESULTS" = 'success success success success success success' || exit 1
|
|
if [ "$IMAGE_EXPECTED" = 'true' ]; then
|
|
test "$IMAGE_RESULT" = 'success'
|
|
else
|
|
test "$IMAGE_RESULT" = 'skipped'
|
|
fi
|