diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 9e28b04..a5b73c2 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,6 +1,15 @@ # CI on the self-hosted Gitea, ported from .gitlab-ci.yml during the move off # GitLab (2026-09-22). Gitea reads .gitea/workflows and ignores .github/ once -# this directory exists; .github/workflows stays as it was for GitHub. +# this directory exists. +# +# BUILD_ON: an org variable, set on both forges. Gitea push-mirrors this +# repository to GitHub, and with BUILD_ON=github the check jobs here skip and +# GitHub Actions runs the same checks on the mirrored copy +# (.github/workflows/ci.yml, on faster runners). The `github` job at the end +# waits for the result that workflow reports back, so this run still passes or +# fails with the checks. Unset, everything runs here as before -- which is +# also the fallback if GitHub is ever unavailable. Command lines are policy: +# change them in both files or neither. # # Every job runs in an image pinned by digest (tag in the trailing comment), # and the only action used is coffey-labs/actions/checkout pinned by SHA. The @@ -30,6 +39,7 @@ concurrency: jobs: # ----------------------------------------------------- license compliance -- rust-licenses: + if: ${{ vars.BUILD_ON != 'github' }} runs-on: light container: image: rust:1-bookworm@sha256:93ce27a88655056a51dbdd8f5f2d7ddc071c7b0070fb288a37b5a285fc83971e # 1-bookworm @@ -44,6 +54,7 @@ jobs: - run: cargo deny --manifest-path "$CRATE_DIR/Cargo.toml" check licenses go-licenses: + if: ${{ vars.BUILD_ON != 'github' }} runs-on: light container: image: golang:1.26-bookworm@sha256:a688600ca24f8a4d3ca77f95b0dd40704a9fc787c826660eb7ba0b641b8b175d # 1.26-bookworm @@ -64,6 +75,7 @@ jobs: --ignore github.com/segmentio/asm npm-licenses: + if: ${{ vars.BUILD_ON != 'github' }} runs-on: light container: image: node:22-bookworm-slim@sha256:48e4b67d85f87bd551df43704e24d252f56cc5f8e9718841aace50f19948f0f9 # 22-bookworm-slim @@ -78,6 +90,7 @@ jobs: # ---------------------------------------------------------- security scan -- rust-advisories: + if: ${{ vars.BUILD_ON != 'github' }} needs: [rust-licenses, go-licenses, npm-licenses] runs-on: light container: @@ -93,6 +106,7 @@ jobs: - run: cargo deny --manifest-path "$CRATE_DIR/Cargo.toml" check advisories go-vulncheck: + if: ${{ vars.BUILD_ON != 'github' }} needs: [rust-licenses, go-licenses, npm-licenses] runs-on: light container: @@ -111,6 +125,7 @@ jobs: govulncheck ./... npm-audit: + if: ${{ vars.BUILD_ON != 'github' }} needs: [rust-licenses, go-licenses, npm-licenses] runs-on: light container: @@ -126,6 +141,7 @@ jobs: # Both of these shell out to `go`, so they need the Go image rather than a # bare debian. tenant-boundary: + if: ${{ vars.BUILD_ON != 'github' }} needs: [rust-advisories, go-vulncheck, npm-audit] runs-on: light container: @@ -135,6 +151,7 @@ jobs: - run: bash hack/check-tenant-boundary.sh web-routes: + if: ${{ vars.BUILD_ON != 'github' }} needs: [rust-advisories, go-vulncheck, npm-audit] runs-on: light container: @@ -144,6 +161,7 @@ jobs: - run: bash hack/check-web-routes.sh conformance-corpus: + if: ${{ vars.BUILD_ON != 'github' }} needs: [rust-advisories, go-vulncheck, npm-audit] runs-on: light container: @@ -151,3 +169,37 @@ jobs: steps: - uses: coffey-labs/actions/checkout@fab0c4d45e0162963965f1555df27b7bed5e20ec - run: python3 processing/conformance/validate.py + + # ------------------------------------------------------------ github ------ + # With BUILD_ON=github the jobs above skip and GitHub Actions builds this + # commit on the push-mirrored copy (.github/workflows/ci.yml). This job waits + # for the commit status that workflow reports back, and passes or fails with + # it, so this run -- what pull requests and merges look at -- still carries + # the real result. If GitHub never reports, it times out and fails: the cue + # to unset BUILD_ON and build here again. + github: + if: ${{ vars.BUILD_ON == 'github' }} + runs-on: light + timeout-minutes: 150 + container: + image: node:26-bookworm-slim@sha256:582460f614631b59b824ac6020533b9bf339c7fdf3a6d7db31abb6b4065f0212 # 26-bookworm-slim + env: + READ_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SHA: ${{ github.event.pull_request.head.sha || github.sha }} + CONTEXT: ${{ github.ref_type == 'tag' && 'github/ci (tag)' || 'github/ci (branch)' }} + steps: + - run: apt-get update -qq && apt-get install -y -qq --no-install-recommends ca-certificates curl jq >/dev/null + - shell: bash + run: | + set -uo pipefail + url="${CI_SERVER_INTERNAL}/api/v1/repos/${GITHUB_REPOSITORY}/commits/${SHA}/statuses?limit=50" + echo "Waiting for '${CONTEXT}' on ${SHA}" + while :; do + # The newest status for the context is the one that counts. + s="$(curl -fsS -H "Authorization: token ${READ_TOKEN}" "$url" | jq -r --arg c "$CONTEXT" '[.[] | select(.context == $c)] | sort_by(.id) | last | "\(.status) \(.target_url)"' 2>/dev/null)" + case "$s" in + success\ *) echo "GitHub: ${s}"; exit 0 ;; + failure\ *|error\ *) echo "GitHub: ${s}" >&2; exit 1 ;; + esac + sleep 20 + done diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 7752a64..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,76 +0,0 @@ -version: 2 -updates: - # Fifteen Go modules, each with its own go.mod and no workspace tying them - # together, so a single entry cannot reach them: `directories` with a glob - # is what covers the hack/ fixtures without listing every one by hand. - # Grouped, because the alternative is what prompted this file -- one - # advisory in a shared dependency opened nine separate alerts. - - package-ecosystem: gomod - directories: - - "/api" - - "/ingest" - - "/alerting" - - "/enterprise" - - "/proto" - - "/cli" - - "/terraform" - - "/deploy/operator" - - "/hack/*" - schedule: - interval: weekly - day: tuesday - time: "09:00" - timezone: Etc/UTC - open-pull-requests-limit: 5 - groups: - # Majors stay out: a Go major is an import path change, never a bump. - go-minor-and-patch: - update-types: - - minor - - patch - - package-ecosystem: cargo - directories: - - "/agent" - - "/search" - schedule: - interval: weekly - day: tuesday - time: "09:00" - timezone: Etc/UTC - groups: - cargo-minor-and-patch: - update-types: - - minor - - patch - - package-ecosystem: npm - directory: "/web" - schedule: - interval: weekly - day: tuesday - time: "09:00" - timezone: Etc/UTC - ignore: - # TypeScript 7 cannot be installed here at all: no @sveltejs/kit - # release accepts it. 2.70.3 (latest) peers `^5.3.3 || ^6.0.0` and - # even 3.0.0-next.27 peers `^6.0.0`; svelte-check caps at 6 as well. - # `npm ci` fails ERESOLVE before anything is built, so the PR cannot - # be made green from this side. Drop this entry once a SvelteKit - # release peers ^7 -- minor and patch updates still come through. - - dependency-name: typescript - update-types: ["version-update:semver-major"] - groups: - npm-minor-and-patch: - update-types: - - minor - - patch - - package-ecosystem: github-actions - directory: "/" - schedule: - interval: weekly - day: tuesday - time: "09:00" - timezone: Etc/UTC - groups: - actions: - patterns: - - "*" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..72d8472 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,202 @@ +# The license, security and conformance checks on GitHub Actions, for the +# GitHub replica of this repository. Gitea (git.coffeylabs.org) is the source +# of truth: it pushes every commit here through a push mirror, and this +# workflow checks what arrives. Pull requests live on Gitea, so there is no +# pull_request trigger -- a PR's branch reaches this copy as an ordinary push. +# +# The switch is the org variable BUILD_ON, set on both forges. With +# BUILD_ON=github every job here runs, the jobs in .gitea/workflows/ci.yml +# skip, and Gitea's own run waits for the result this workflow reports back. +# With it unset, every job here skips and Gitea runs the checks as before -- +# which is also the way back if GitHub is ever unavailable: unset it on Gitea. +# +# The jobs are .gitea/workflows/ci.yml's, job for job, in the same images +# pinned by digest: these checks make a statement about what is in the tree, +# and the command lines -- including the ignore and allow lists -- are license +# policy, not configuration. Change them in both files or neither. cargo-deny +# is installed in the job, not through a third-party action. +# +# The only action used is actions/checkout, pinned to a full commit SHA with +# the release in a trailing comment. +name: ci + +on: + push: + branches: ['**'] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + GITEA_URL: ${{ vars.GITEA_URL }} + +jobs: + # Tells Gitea a result is on its way, so the commit does not look unchecked + # while the checks run. + pending: + if: ${{ vars.BUILD_ON == 'github' }} + runs-on: ubuntu-latest + steps: + - env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + CONTEXT: github/ci (${{ github.ref_type }}) + run: | + jq -n --arg c "$CONTEXT" --arg u "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \ + '{state:"pending", context:$c, target_url:$u, description:"GitHub Actions"}' | + curl -fsS -o /dev/null -X POST -H "Authorization: token $GITEA_TOKEN" -H 'Content-Type: application/json' \ + --data @- "$GITEA_URL/api/v1/repos/$GITHUB_REPOSITORY/statuses/$GITHUB_SHA" + + # ----------------------------------------------------- license compliance -- + rust-licenses: + if: ${{ vars.BUILD_ON == 'github' }} + runs-on: ubuntu-latest + container: + image: rust:1-bookworm@sha256:93ce27a88655056a51dbdd8f5f2d7ddc071c7b0070fb288a37b5a285fc83971e # 1-bookworm + strategy: + matrix: + CRATE_DIR: [agent, search] + env: + CRATE_DIR: ${{ matrix.CRATE_DIR }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: cargo install cargo-deny --locked --quiet || cargo install cargo-deny --locked + - run: cargo deny --manifest-path "$CRATE_DIR/Cargo.toml" check licenses + + go-licenses: + if: ${{ vars.BUILD_ON == 'github' }} + runs-on: ubuntu-latest + container: + image: golang:1.26-bookworm@sha256:a688600ca24f8a4d3ca77f95b0dd40704a9fc787c826660eb7ba0b641b8b175d # 1.26-bookworm + strategy: + matrix: + MODULE_DIR: [api, ingest, alerting, enterprise, deploy/operator, terraform, proto, hack/benchmark-fixture, hack/windows-fixture] + env: + MODULE_DIR: ${{ matrix.MODULE_DIR }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: go install github.com/google/go-licenses@latest + - run: | + export PATH="$(go env GOPATH)/bin:$PATH" + cd "$MODULE_DIR" + go-licenses check ./... \ + --allowed_licenses=MIT,Apache-2.0,BSD-2-Clause,BSD-3-Clause,ISC,MPL-2.0,0BSD,Unlicense \ + --ignore github.com/cairnobs/cairnobs \ + --ignore github.com/segmentio/asm + + npm-licenses: + if: ${{ vars.BUILD_ON == 'github' }} + runs-on: ubuntu-latest + container: + image: node:22-bookworm-slim@sha256:48e4b67d85f87bd551df43704e24d252f56cc5f8e9718841aace50f19948f0f9 # 22-bookworm-slim + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: | + cd web + npm ci + npx --yes license-checker \ + --onlyAllow "MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC;0BSD;MPL-2.0" \ + --excludePackages "web@0.0.1" + + # ---------------------------------------------------------- security scan -- + rust-advisories: + if: ${{ vars.BUILD_ON == 'github' }} + needs: [rust-licenses, go-licenses, npm-licenses] + runs-on: ubuntu-latest + container: + image: rust:1-bookworm@sha256:93ce27a88655056a51dbdd8f5f2d7ddc071c7b0070fb288a37b5a285fc83971e # 1-bookworm + strategy: + matrix: + CRATE_DIR: [agent, search] + env: + CRATE_DIR: ${{ matrix.CRATE_DIR }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: cargo install cargo-deny --locked --quiet || cargo install cargo-deny --locked + - run: cargo deny --manifest-path "$CRATE_DIR/Cargo.toml" check advisories + + go-vulncheck: + if: ${{ vars.BUILD_ON == 'github' }} + needs: [rust-licenses, go-licenses, npm-licenses] + runs-on: ubuntu-latest + container: + image: golang:1.26-bookworm@sha256:a688600ca24f8a4d3ca77f95b0dd40704a9fc787c826660eb7ba0b641b8b175d # 1.26-bookworm + strategy: + matrix: + MODULE_DIR: [api, ingest, alerting, enterprise, deploy/operator, terraform, proto, hack/benchmark-fixture, hack/windows-fixture] + env: + MODULE_DIR: ${{ matrix.MODULE_DIR }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: go install golang.org/x/vuln/cmd/govulncheck@latest + - run: | + export PATH="$(go env GOPATH)/bin:$PATH" + cd "$MODULE_DIR" + govulncheck ./... + + npm-audit: + if: ${{ vars.BUILD_ON == 'github' }} + needs: [rust-licenses, go-licenses, npm-licenses] + runs-on: ubuntu-latest + container: + image: node:22-bookworm-slim@sha256:48e4b67d85f87bd551df43704e24d252f56cc5f8e9718841aace50f19948f0f9 # 22-bookworm-slim + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: | + cd web + npm ci + npm audit --omit=dev + + # ----------------------------------------------------------- other checks -- + # Both of these shell out to `go`, so they need the Go image rather than a + # bare debian. + tenant-boundary: + if: ${{ vars.BUILD_ON == 'github' }} + needs: [rust-advisories, go-vulncheck, npm-audit] + runs-on: ubuntu-latest + container: + image: golang:1.26-bookworm@sha256:a688600ca24f8a4d3ca77f95b0dd40704a9fc787c826660eb7ba0b641b8b175d # 1.26-bookworm + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: bash hack/check-tenant-boundary.sh + + web-routes: + if: ${{ vars.BUILD_ON == 'github' }} + needs: [rust-advisories, go-vulncheck, npm-audit] + runs-on: ubuntu-latest + container: + image: golang:1.26-bookworm@sha256:a688600ca24f8a4d3ca77f95b0dd40704a9fc787c826660eb7ba0b641b8b175d # 1.26-bookworm + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: bash hack/check-web-routes.sh + + conformance-corpus: + if: ${{ vars.BUILD_ON == 'github' }} + needs: [rust-advisories, go-vulncheck, npm-audit] + runs-on: ubuntu-latest + container: + image: python:3.13-slim@sha256:8d9d0b8bcf6506481eae4907c18f5e3e7902e629f5f6d684f9e7c32e85e3ddf0 # 3.13-slim + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: python3 processing/conformance/validate.py + + # One commit status on Gitea for the whole run. Gitea's ci.yml `github` job + # waits on exactly this context. + report: + if: ${{ always() && vars.BUILD_ON == 'github' }} + needs: [pending, rust-licenses, go-licenses, npm-licenses, rust-advisories, go-vulncheck, npm-audit, tenant-boundary, web-routes, conformance-corpus] + runs-on: ubuntu-latest + steps: + - env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + CONTEXT: github/ci (${{ github.ref_type }}) + STATE: ${{ (contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) && 'failure' || 'success' }} + run: | + jq -n --arg s "$STATE" --arg c "$CONTEXT" --arg u "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \ + '{state:$s, context:$c, target_url:$u, description:"GitHub Actions"}' | + curl -fsS -o /dev/null -X POST -H "Authorization: token $GITEA_TOKEN" -H 'Content-Type: application/json' \ + --data @- "$GITEA_URL/api/v1/repos/$GITHUB_REPOSITORY/statuses/$GITHUB_SHA" diff --git a/.github/workflows/license-compliance.yml b/.github/workflows/license-compliance.yml deleted file mode 100644 index b022909..0000000 --- a/.github/workflows/license-compliance.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: License compliance - -# Enforces the AGPLv3-project-wide license policy from the Phase 6 -# license audit (/docs/compliance/license-policy.md) on every PR -- -# a new dependency with an incompatible license fails the build here, -# not months later when someone happens to re-run the one-time audit. -# See /docs/compliance/license-audit-report.md for the audit this -# policy was derived from. -# -# This is the first CI workflow in this repo. Several docs -# (architecture.md, phase-4-isolation-design.md, phase-4-rbac-design.md) -# already say "enforced in CI by hack/check-tenant-boundary.sh" -- that -# was true of the *script*, but nothing had actually wired it into a -# running CI system yet. Fixed here as part of standing up the first -# real workflow file, not left as a second gap next to this one. - -on: - push: - branches: [master, main] - pull_request: - -jobs: - rust-licenses: - name: Rust license check (cargo-deny) - runs-on: ubuntu-latest - strategy: - matrix: - crate_dir: [agent, search] - steps: - - uses: actions/checkout@v7 - - uses: EmbarkStudios/cargo-deny-action@v2 - with: - manifest-path: ${{ matrix.crate_dir }}/Cargo.toml - command: check licenses - - go-licenses: - name: Go license check (go-licenses) - runs-on: ubuntu-latest - strategy: - matrix: - # Every Go module with real third-party dependencies -- cli, - # hack/webhook-sink, and hack/alert-load-test are stdlib-only - # (confirmed at audit time) and intentionally excluded, not - # forgotten; add them here if they ever gain a dependency. - module_dir: - - api - - ingest - - alerting - - enterprise - - deploy/operator - - terraform - - proto - - hack/benchmark-fixture - - hack/windows-fixture - steps: - - uses: actions/checkout@v7 - - uses: actions/setup-go@v7 - with: - go-version-file: ${{ matrix.module_dir }}/go.mod - - run: go install github.com/google/go-licenses@latest - - name: Check licenses - working-directory: ${{ matrix.module_dir }} - run: | - go-licenses check ./... \ - --allowed_licenses=MIT,Apache-2.0,BSD-2-Clause,BSD-3-Clause,ISC,MPL-2.0,0BSD,Unlicense \ - --ignore github.com/cairnobs/cairnobs \ - --ignore github.com/segmentio/asm - - npm-licenses: - name: npm license check (license-checker) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 - with: - node-version: 22 - - working-directory: web - run: npm ci - - name: Check licenses - working-directory: web - run: | - npx --yes license-checker \ - --onlyAllow "MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC;0BSD;MPL-2.0" \ - --excludePackages "web@0.0.1" - - tenant-boundary: - name: Architectural boundary check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - run: bash hack/check-tenant-boundary.sh diff --git a/.github/workflows/processing-conformance.yml b/.github/workflows/processing-conformance.yml deleted file mode 100644 index 4d3bf43..0000000 --- a/.github/workflows/processing-conformance.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Processing conformance corpus - -# /processing/conformance/cases IS the Phase 8 rule language spec: two -# implementations (Rust in the agent, Go at ingest) will each be held to -# it, and two hand-written implementations of one language diverge -# unless something shared pins them. -# -# Neither implementation exists yet, so nothing here executes rules. -# What this checks is that the corpus stays well-formed in the meantime -# -- known actions, addressable fields, compilable patterns, no case -# quietly depending on record_id. Cheap insurance against the spec -# rotting during the gap between writing it and building against it. -# -# Its own workflow, following web-routes.yml's reasoning: license- -# compliance.yml already carries one unrelated check for historical -# reasons, and that is not worth compounding. - -on: - push: - branches: [master, main] - pull_request: - -jobs: - conformance-corpus: - name: processing conformance corpus check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - run: python3 processing/conformance/validate.py diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml deleted file mode 100644 index bc3bd29..0000000 --- a/.github/workflows/security-scan.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: Security scan - -# Closes a real gap the security audit found: license-compliance.yml -# (this repo's only other workflow) checks license text, never -# vulnerabilities -- and agent/deny.toml and search/deny.toml already -# ship an [advisories] policy that nothing in CI ever invoked. Same -# matrix-per-language shape as license-compliance.yml, extended to the -# equivalent vulnerability-scanning tool per ecosystem: cargo-deny's -# other command for Rust, govulncheck for Go, npm audit for the one -# npm package. A new dependency with a known vulnerability now fails -# the build here, not months later when someone happens to re-run this -# by hand. - -on: - push: - branches: [master, main] - pull_request: - -jobs: - rust-advisories: - name: Rust vulnerability check (cargo-deny) - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - crate_dir: [agent, search] - steps: - - uses: actions/checkout@v7 - - uses: EmbarkStudios/cargo-deny-action@v2 - with: - manifest-path: ${{ matrix.crate_dir }}/Cargo.toml - command: check advisories - - go-vulncheck: - name: Go vulnerability check (govulncheck) - runs-on: ubuntu-latest - strategy: - # One module's findings must not cancel the other eight -- with - # fail-fast a single failure hid the whole matrix behind one log. - fail-fast: false - matrix: - # Same module list as license-compliance.yml's go-licenses job -- - # see that job's own comment for why cli/hack-webhook-sink/ - # hack-alert-load-test are excluded (no third-party dependencies - # at audit time). - module_dir: - - api - - ingest - - alerting - - enterprise - - deploy/operator - - terraform - - proto - - hack/benchmark-fixture - - hack/windows-fixture - steps: - - uses: actions/checkout@v7 - - uses: actions/setup-go@v7 - with: - # Deliberately NOT go-version-file. Each go.mod pins an exact - # patch, so go-version-file made CI scan against the *unpatched* - # standard library of that patch and fail on 28 stdlib CVEs -- - # crypto/x509 quadratic name-constraint parsing (GO-2025-4007) - # and friends, all long since fixed. None of it was real: every - # Dockerfile builds `FROM golang:1.26-alpine`, a floating tag - # that resolves to the newest 1.26.x, so the shipped binaries - # already had the fixes. The go directive states the minimum - # language version, not the toolchain to audit with. Track the - # floating 1.26 line so this scans what production actually - # builds, and keep it in step with the Dockerfiles above all -- - # a mismatch here fails every module at once. - go-version: '1.26' - - run: go install golang.org/x/vuln/cmd/govulncheck@latest - - name: Check for known vulnerabilities - working-directory: ${{ matrix.module_dir }} - run: govulncheck ./... - - npm-audit: - name: npm vulnerability check (npm audit) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 - with: - node-version: 22 - - working-directory: web - run: npm ci - - name: Audit production dependencies - working-directory: web - # --omit=dev, not the deprecated --production: this deliberately - # only gates the runtime bundle a real deployment actually - # ships. The one known finding in web's full dependency tree - # today (a `cookie` advisory) lives entirely in the SvelteKit - # build toolchain, not the production bundle -- fixing it needs - # a deliberate, tested major-version bump, not an automated - # `audit fix --force`, so it's out of scope for this gate. - run: npm audit --omit=dev diff --git a/.github/workflows/web-routes.yml b/.github/workflows/web-routes.yml deleted file mode 100644 index 57d7fc9..0000000 --- a/.github/workflows/web-routes.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Web route check - -# web/nginx.conf answers 404 for any path that isn't a route, which means -# it has to know which routes exist. Most it infers from the build output, -# but dynamic routes (dashboards/[id] and friends) and non-prerendered -# routes (/data-sources) have no file on disk and are hand-listed there. -# -# That list drifting is a production-only failure: `vite dev` and -# `npm run preview` route from the client manifest and never read -# nginx.conf, so a new dynamic route works perfectly everywhere a -# developer would look and 404s the moment it ships. This job is what -# catches it. Its own workflow rather than another job bolted onto -# license-compliance.yml, which already carries one unrelated check -# (tenant-boundary) for historical reasons worth not compounding. - -on: - push: - branches: [master, main] - pull_request: - -jobs: - web-routes: - name: nginx route allowlist check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - run: bash hack/check-web-routes.sh