chore: scaffold Gitea Actions pipelines per ADR-0015 / ADR-0017
Wire the CI/CD pipeline scaffolding. Implements the level-2 (Gitea
Actions) part of ADR-0015 with the thin-YAML pattern, plus the perf
gate from ADR-0017. The level-1 decisions (gates list, branch model,
secrets policy) are unchanged.
Files:
- .nvmrc pins Node 24 (latest LTS major) for actions/setup-node.
- package.json gains four ci:* scripts that the workflows call:
- ci:check - 'nx affected -t format:check lint test build'
- ci:audit - 'pnpm audit --audit-level=moderate'
- ci:commits- 'commitlint --from $COMMIT_LINT_FROM --to HEAD'
- ci:perf - 'nx build portal-shell --configuration=production
&& lhci autorun --config=./lighthouserc.js'
All four runnable locally; CI workflows are thin wrappers.
- @lhci/cli added as a dev dependency for ci:perf.
- lighthouserc.js encodes the Core Web Vitals thresholds from
ADR-0017 (LCP <= 2500ms, CLS <= 0.1, TBT <= 200ms, server
response <= 800ms, Performance >= 0.9). v1 measures only the
static-served portal-shell bundle (Nx Welcome placeholder); the
critical-routes list expands as real screens land.
- .gitea/workflows/ci.yml runs five jobs on PR + push to main:
check, scan (audit + Trivy + gitleaks), commits (PR-only), perf,
a11y. The a11y job is a placeholder that no-ops with a clear
message; it wires up for real with the first Playwright e2e suite
(ADR-0016). All gates are blocking - branch protection on main
will require all five jobs green.
- .gitea/workflows/security-scheduled.yml runs weekly (Mon 04:00
UTC) for full-tree Trivy + gitleaks (no severity filter, no
skip-dirs - broader than per-PR) plus a Lighthouse run against
the prod URL when vars.LHCI_PROD_URL is set.
Slight deviation from ADR-0015 §'Level 2': Trivy and gitleaks are
binaries (Go) and don't have clean npm wrappers, so they are
invoked through their official Gitea-Actions-compatible actions
inside the YAML rather than via 'pnpm ci:scan'. The high-level
decision (gates: audit + secret-scan + dep-scan) is unchanged; the
script/action boundary is shifted by one tool. Documented here for
traceability; no ADR amendment needed.
Operational TODOs (not blocking the scaffold):
- pnpm audit currently reports 6 moderate transitive vulnerabilities
(ajv, brace-expansion, yaml, @hono/node-server, follow-redirects,
uuid) in deep deps of Nx/Angular plugins. CI will fail on this
gate until upstream updates land or Renovate bumps; expected and
documented.
- act_runner self-hosted instances are not yet registered against
the Gitea organisation; the workflows reference [self-hosted,
on-prem] runner labels per ADR-0015. CI will not actually execute
until the runners are up - that's an infra task.
- Branch protection rules on main (require all five jobs green) are
configured in Gitea UI, not in this commit.
- Lighthouse-prod scheduled job runs only when vars.LHCI_PROD_URL
is set - skipped silently otherwise. To be configured once a prod
environment exists.
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
# Per ADR-0015 (CI/CD on Gitea Actions).
|
||||
# Thin YAML — orchestration lives in package.json scripts (ci:check,
|
||||
# ci:audit, ci:commits, ci:perf) and Nx targets. Any change to gate
|
||||
# behaviour belongs in those scripts, not in this file.
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: [self-hosted, on-prem]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
- uses: pnpm/action-setup@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'pnpm'
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm ci:check
|
||||
|
||||
scan:
|
||||
runs-on: [self-hosted, on-prem]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'pnpm'
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm ci:audit
|
||||
# Dependency vulnerability scan (binary tool, invoked via official
|
||||
# action — Trivy is a Go binary, not an npm package, so it cannot
|
||||
# live in package.json scripts as cleanly as audit/lint do).
|
||||
- uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
scan-type: fs
|
||||
ignore-unfixed: true
|
||||
skip-dirs: node_modules
|
||||
exit-code: '1'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
# Secret scan, same reasoning (gitleaks is a Go binary).
|
||||
- uses: gitleaks/gitleaks-action@v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
commits:
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: [self-hosted, on-prem]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: pnpm/action-setup@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'pnpm'
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: COMMIT_LINT_FROM=origin/main pnpm ci:commits
|
||||
|
||||
perf:
|
||||
runs-on: [self-hosted, on-prem]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'pnpm'
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm ci:perf
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: lighthouseci-report
|
||||
path: .lighthouseci/
|
||||
retention-days: 30
|
||||
|
||||
a11y:
|
||||
runs-on: [self-hosted, on-prem]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'pnpm'
|
||||
- run: pnpm install --frozen-lockfile
|
||||
# Placeholder until the e2e a11y suite (axe-core via Playwright,
|
||||
# per ADR-0016) is wired with the first real screens. The job
|
||||
# exists so branch protection can require it from day one - it
|
||||
# currently no-ops with a clear message.
|
||||
- run: echo "a11y gate placeholder - axe-core via Playwright wires up with the first real screens (ADR-0016)."
|
||||
@@ -0,0 +1,56 @@
|
||||
# Per ADR-0015 (CI/CD on Gitea Actions). Weekly full-tree security
|
||||
# scans plus a Lighthouse run against the production environment when
|
||||
# its URL is configured. Complements the per-PR ci.yml workflow with
|
||||
# broader / longer-running checks that don't fit the per-PR budget.
|
||||
|
||||
name: Security and perf — scheduled
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Mondays, 04:00 UTC — outside business hours; before the week starts.
|
||||
- cron: '0 4 * * 1'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
full-tree-scan:
|
||||
runs-on: [self-hosted, on-prem]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'pnpm'
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm audit
|
||||
# Full-tree Trivy (no skip-dirs, no severity filter — the per-PR
|
||||
# gate filters by severity for speed; this run wants the full
|
||||
# surface for the security feed).
|
||||
- uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
scan-type: fs
|
||||
ignore-unfixed: true
|
||||
- uses: gitleaks/gitleaks-action@v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
lighthouse-prod:
|
||||
# Skipped silently if the prod URL hasn't been configured yet.
|
||||
if: vars.LHCI_PROD_URL != ''
|
||||
runs-on: [self-hosted, on-prem]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'pnpm'
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm exec lhci collect --url=${{ vars.LHCI_PROD_URL }} --numberOfRuns=3
|
||||
- run: pnpm exec lhci assert --config=./lighthouserc.js
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: lighthouseci-prod-report
|
||||
path: .lighthouseci/
|
||||
retention-days: 90
|
||||
Reference in New Issue
Block a user