Files
codebase-memory-mcp/.github/workflows/_security.yml
T
Martin Vogel 5afdfcaac9 ci(codeql): run CodeQL on main, dry run and release, not per PR
CodeQL ran on every pull_request push, and PR CI's security / codeql-gate
job polled up to 150 min for that run before ci-ok could pass. With ~30 PRs
pushed at once, the gate jobs held runners while the CodeQL runs they waited
for queued behind them, and PR CI starved for hours.

- codeql.yml: triggers are push to main, a weekly schedule, workflow_call
  and workflow_dispatch; pull_request is gone. The open-alert check moves
  here, unchanged and still fail-closed, as the `alerts` job (needs
  analyze), so every main push and every weekly run fails while any
  code-scanning alert is open. Push runs keep cancel-in-progress; called and
  scheduled runs get a group of their own. The analysis key is pinned to the
  push configuration so dry-run/release uploads do not open configurations
  of their own on main.
- _security.yml: codeql-gate removed; callers grant contents: read only.
- dry-run.yml, release.yml: a `codeql` job calls codeql.yml on the
  dispatched commit; release verify needs it and requires success.
- select-lanes.sh, require-all-green.sh: the codeql-gate lane is gone from
  the selector universe and from ci-ok's job map; no other lane changes.
- tests: the fail-closed contract follows the check to codeql.yml and now
  also pins the triggers, the derived callers' grants and release verify;
  lane fixtures drop codeql-gate.
- SECURITY.md, MAINTAINERS.md: say where CodeQL runs now.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-20 22:37:22 +02:00

57 lines
2.1 KiB
YAML

# Reusable: security-static + license gate.
# CodeQL is not here: PRs do not run it. It runs on push to main, weekly, and
# inside dry-run.yml / release.yml, which call codeql.yml directly.
# Runs independently from lint/test/build — does not block the main pipeline.
# Affects overall workflow success status.
name: Security Gate
on:
workflow_call:
inputs:
lanes:
description: 'PR lane selection (scripts/ci/select-lanes.sh JSON list); "all" = every job (dry run, release)'
type: string
default: all
permissions:
contents: read
jobs:
security-static:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: "Layer 1: Static allow-list audit"
run: |
bash tests/test_security_audit_subprocess_calls.sh
scripts/security-audit.sh
- name: "Layer 6: UI security audit"
run: |
bash tests/test_security_ui_urls.sh
scripts/security-ui.sh
- name: "Layer 8: Vendored dependency integrity"
run: scripts/security-vendored.sh
license-gate:
if: ${{ inputs.lanes == 'all' || contains(fromJSON(inputs.lanes), 'license-gate') }}
runs-on: ubuntu-latest
timeout-minutes: 240
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install ScanCode Toolkit
# Pinned: an unpinned install picked up pluggy 1.7.0, which breaks
# scancode at import (see .github/scancode-constraints.txt).
env:
PIP_CONSTRAINT: ${{ github.workspace }}/.github/scancode-constraints.txt
run: pipx install scancode-toolkit==32.5.0
- name: "Gate self-test (a planted violation must be detected)"
run: scripts/license-gate.sh --selftest
- name: "License compliance gate (one finding fails)"
run: scripts/license-gate.sh
- name: "License provenance audit (byte-identity vs upstream)"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: scripts/audit-license-provenance.py