CI / policy (push) Successful in 32s
CI / validate (push) Successful in 55s
CI / build (push) Successful in 37s
CI / policy (pull_request) Successful in 9s
CI / security (push) Successful in 55s
CI / validate (pull_request) Successful in 43s
CI / test (push) Successful in 2m26s
CI / build (pull_request) Successful in 35s
CI / security (pull_request) Successful in 45s
CI / test (pull_request) Successful in 2m10s
CI / benchmark (push) Failing after 5m52s
CI / images (push) Skipped
CI / required (push) Failing after 2s
CI / benchmark (pull_request) Failing after 15m10s
CI / images (pull_request) Skipped
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 --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
|