CI / policy (push) Successful in 7s
CI / validate (push) Successful in 1m23s
CI / test (push) Successful in 3m17s
CI / benchmark (push) Failing after 5m52s
CI / build (push) Successful in 1m31s
CI / security (push) Successful in 1m39s
CI / images (push) Skipped
CI / policy (pull_request) Successful in 7s
CI / validate (pull_request) Successful in 1m11s
CI / test (pull_request) Successful in 3m17s
CI / benchmark (pull_request) Failing after 5m57s
CI / build (pull_request) Successful in 1m30s
CI / security (pull_request) Successful in 1m40s
CI / images (pull_request) Skipped
CI / required (push) Failing after 2s
CI / required (pull_request) Failing after 1s
Reduce objective evaluation and calendar allocation work while preserving planner outcomes and deterministic explanations. Restore required benchmark gating and record the unchanged protocol, differential checks, and browser evidence for #78.
209 lines
8.2 KiB
YAML
209 lines
8.2 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
pull_request:
|
|
types: [opened, reopened, synchronize, edited]
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
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
|
|
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: Policy regression tests
|
|
run: node scripts/ci-policy.test.mjs && node scripts/ci-image.test.mjs
|
|
- name: Validate event and commit
|
|
id: policy
|
|
run: node scripts/ci-policy.mjs
|
|
|
|
validate:
|
|
name: validate
|
|
runs-on: ubuntu-latest
|
|
container: node:24.21.0
|
|
steps:
|
|
- uses: https://gitea.com/actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
- run: npm install --global bun@1.4.2
|
|
- run: bun install --frozen-lockfile
|
|
- run: bun run lint
|
|
- run: bun run format:check
|
|
- run: bunx prettier --check 'scripts/ci-*.mjs' '.gitea/workflows/*.yml'
|
|
- run: bunx tsc --noEmit -p tsconfig.app.json
|
|
- run: bunx tsc --noEmit -p tsconfig.spec.json
|
|
|
|
test:
|
|
name: test
|
|
runs-on: ubuntu-latest
|
|
container: node:24.21.0
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=2048
|
|
steps:
|
|
- uses: https://gitea.com/actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
- run: npm install --global bun@1.4.2
|
|
- run: bun install --frozen-lockfile
|
|
- run: bun scripts/generate-langs.js
|
|
- name: Functional coverage
|
|
run: bunx vitest run --coverage --maxWorkers=1 --exclude='src/app/benchmark/**'
|
|
- name: Coverage report
|
|
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: node:24.21.0
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=2048
|
|
steps:
|
|
- uses: https://gitea.com/actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
- run: npm install --global bun@1.4.2
|
|
- run: bun install --frozen-lockfile
|
|
- run: bun scripts/generate-langs.js
|
|
- name: Unchanged benchmark protocol
|
|
run: timeout 300s bunx vitest run src/app/benchmark/leave-planner-benchmark.spec.ts --maxWorkers=1
|
|
|
|
build:
|
|
name: build
|
|
runs-on: ubuntu-latest
|
|
container: node:24.21.0
|
|
steps:
|
|
- uses: https://gitea.com/actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
- run: npm install --global bun@1.4.2
|
|
- 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:
|
|
- name: Install checkout and policy runtimes
|
|
run: apk add --no-cache nodejs git
|
|
- uses: https://gitea.com/actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
- name: Build branch images or promote a release
|
|
env:
|
|
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
|
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
|
run: node 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
|