Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 35 additions & 16 deletions .github/workflows/container-security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ name: container-security
#
# These checks used to live in `frontend-e2e.yml`, which is `ui`-label
# gated and therefore skipped on backend infrastructure PRs — the exact
# PRs that can break them. This workflow runs unconditionally on any PR
# (and push to dev/main) that touches the relevant Docker / compose /
# bootstrap surface, so the guard executes whenever it could possibly
# regress.
# PRs that can break them. This workflow runs on every PR (and push to
# dev/main); the heavy `verify-non-root` job is gated by the `changes`
# detector so it executes whenever the Docker / compose / bootstrap
# surface changes and is SKIPPED (→ passing required check) otherwise.
# That keeps it a safe required status check — see #1222.
#
# Scope:
# - `verify-non-root`: every Trinity-built service that holds platform
Expand All @@ -25,19 +26,7 @@ name: container-security
on:
push:
branches: [dev, main]
paths:
- 'docker/**'
- 'docker-compose*.yml'
- 'scripts/deploy/start.sh'
- 'src/mcp-server/Dockerfile'
- '.github/workflows/container-security.yml'
pull_request:
paths:
- 'docker/**'
- 'docker-compose*.yml'
- 'scripts/deploy/start.sh'
- 'src/mcp-server/Dockerfile'
- '.github/workflows/container-security.yml'
workflow_dispatch:

# Least-privilege GITHUB_TOKEN: only `contents: read` is needed for
Expand All @@ -48,7 +37,37 @@ permissions:
contents: read

jobs:
# Cheap path detector — runs on every PR/push so the required `verify-non-root`
# context is ALWAYS produced. The heavy stack-boot job below is gated on it, so
# an unrelated PR skips it (→ passing required check) rather than leaving the
# context "expected" forever (the #1222 freeze).
changes:
runs-on: ubuntu-latest
# paths-filter resolves the PR's changed-file list via the API; the heavy
# verify-non-root job keeps the workflow-level least-privilege contents: read.
permissions:
contents: read
pull-requests: read
outputs:
docker: ${{ steps.filter.outputs.docker }}
steps:
- uses: actions/checkout@v6
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
docker:
- 'docker/**'
- 'docker-compose*.yml'
- 'scripts/deploy/start.sh'
- 'src/mcp-server/Dockerfile'
- '.github/workflows/container-security.yml'

verify-non-root:
needs: changes
# Skipped (→ reported as a passing required check) when no docker/compose
# paths changed; boots the stack and verifies UIDs for real when they did.
if: needs.changes.outputs.docker == 'true'
runs-on: ubuntu-latest
timeout-minutes: 20

Expand Down
62 changes: 42 additions & 20 deletions .github/workflows/schema-parity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,56 @@ name: Schema Parity Gate
# SQLite snapshots (schema-only vs full init_database lifecycle) and diffs
# tables/columns/indexes/triggers.
#
# MAINTAINER NOTE: do NOT add this job to required-status-checks in branch
# protection until it has been green for ~1 week of normal PR traffic.
# Otherwise any path-filter false-negative (e.g. a future module move that
# bypasses the filter) would brick PRs that don't touch DB files. The
# workflow self-skips on unrelated PRs (no path match -> no run -> no
# required check needed) so leaving it optional is safe.
# REQUIRED-CHECK SAFE (#1222): path filtering lives on the `changes` job below
# (job-level `if:`), NOT on `on.pull_request.paths`. The workflow runs on every
# PR, so the `schema-parity` context is always produced: on an unrelated PR the
# job is SKIPPED, which GitHub counts as a passing required check; when DB paths
# change it runs for real and can block. This supersedes the earlier "do not
# make this required" note — a required check filtered via `on.paths` posts NO
# status on unrelated PRs, which froze the entire dev merge queue (#1222).

on:
pull_request:
paths:
- 'src/backend/db/**'
- 'src/backend/database.py'
- 'src/backend/utils/helpers.py'
- 'tests/unit/test_schema_parity.py'
- 'tests/requirements-test.txt'
- '.github/workflows/schema-parity.yml'
push:
branches: [main, dev]
paths:
- 'src/backend/db/**'
- 'src/backend/database.py'
- 'src/backend/utils/helpers.py'
- 'tests/unit/test_schema_parity.py'
- 'tests/requirements-test.txt'
- '.github/workflows/schema-parity.yml'
workflow_dispatch:

permissions:
contents: read

jobs:
# Cheap path detector — runs on every PR/push so the required `schema-parity`
# context is ALWAYS produced. The heavy job below is gated on its output, so an
# unrelated PR skips it (→ passing required check) instead of leaving the
# context "expected" forever (the #1222 freeze).
changes:
runs-on: ubuntu-latest
# paths-filter resolves the PR's changed-file list via the API; the heavy
# schema-parity job keeps the workflow-level least-privilege contents: read.
permissions:
contents: read
pull-requests: read
outputs:
db: ${{ steps.filter.outputs.db }}
steps:
- uses: actions/checkout@v6
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
db:
- 'src/backend/db/**'
- 'src/backend/database.py'
- 'src/backend/utils/helpers.py'
- 'tests/unit/test_schema_parity.py'
- 'tests/requirements-test.txt'
- '.github/workflows/schema-parity.yml'

schema-parity:
needs: changes
# Skipped (→ reported as a passing required check) when no DB paths changed;
# runs for real and can block when they did. See #1222.
if: needs.changes.outputs.db == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
Expand Down
Loading