Skip to content

ci: restructure PR pipeline — shared path gates and workflow separation #2796

Description

@DerekRoberts

Context

Recent CI pain (#2790, #2712, #2781) exposed structural issues in how PR workflows decide what to run. Interim fixes are landing in #2790 (Trivy report-only, narrowed deploy triggers). This issue captures a longer-term rearchitecture for later refinement.

Problems observed

1. Trigger logic is duplicated and easy to drift

Path matching lives inside bcgov action inputs (triggers: (...) on action-builder-ghcr and action-deployer-openshift). Any future paths-filter or job-level if: would duplicate the same rules in a second place.

#2712 (May 2026) replaced a targeted trigger (.github/workflows/.deploy.yml) with a blanket .github/workflows/ directory match. CI-only edits (analysis.yml, merge.yml, scheduled.yml) started spinning up OpenShift builds, deploys, and five-minute post-deploy test suites.

2. Multiple workflows, one word: "Tests"

Workflow What runs Deploy dependency
analysis.yml Backend Tests, Frontend Tests (unit) None — always on PR
pr-open.ymlreusable-tests.yml Integration, E2E, Load (k6, 5 min) Gated on deploys.outputs.triggered == 'true'

The post-deploy gate works correctly when triggers are narrow. The confusion is structural: two unrelated test suites share similar names on the checks page.

3. Deploy jobs ≠ deployment happened

reusable-deploy.yml always runs init + matrix jobs even when the action logs NOT TRIGGERED. Jobs show green; OpenShift apply is skipped. Cheap (~1–2 runner-minutes) but misleading on the checks UI.

4. Security scanning role unclear

Trivy as a merge gate (#2781) blocked PRs on third-party advisory timing, not diff content. Report-only with Security tab triage is the interim fix (#2790). Longer term: clarify which tools gate merges vs report vs block at push time (GitHub secret scanning push protection already covers committed secrets).

Interim state (after #2790)

  • Trivy: report every severity, exit-code: 0, triage in Security tab
  • PR deploy triggers: app paths + .github/workflows/pr-open.yml only
  • Post-deploy tests: still gated on needs.deploys.outputs.triggered == 'true'
  • cancel-in-progress: true on PR number — only latest push matters

Proposed direction (for refinement)

Option A: Shared path-gate job (incremental)

Add a single upstream job (e.g. changes) whose outputs drive downstream jobs:

jobs:
  changes:
    outputs:
      app: ...
      pipeline: ...   # pr-open.yml touched
    # one path definition — feeds builds, deploy, tests if: conditions

bcgov triggers strings stay aligned with (or derived from) that one definition. Mitigates drift without a full rewrite.

Option B: Workflow separation (rearchitecture)

Explicit separation of concerns:

  1. Verify app — unit tests, lint (analysis.yml); no cluster
  2. Verify pipeline — only when pr-open.yml or deploy manifests change; optional PR namespace
  3. Report security — Trivy, CodeQL, Socket; report to Security tab, no merge gate on ambient advisories
  4. Deploy & integration — only when app paths or shared manifests change

Replace path-string tuples passed into bcgov actions with explicit workflow inputs from a shared gate job, or document a single source of truth both actions read.

Explicitly out of scope for now

Open questions

  • Should docs-only PRs skip the entire pr-open.yml workflow, or still require PR Results?
  • Workflow-level paths: filters vs shared changes job vs bcgov action triggers — pick one source of truth
  • Should load/integration/e2e run on every app-path PR, or only when backend/frontend/migrations specifically change?
  • Template guidance: document which workflow files affect PR deploy vs CI-only vs post-merge

References

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status
New

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions