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.yml → reusable-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:
- Verify app — unit tests, lint (analysis.yml); no cluster
- Verify pipeline — only when
pr-open.yml or deploy manifests change; optional PR namespace
- Report security — Trivy, CodeQL, Socket; report to Security tab, no merge gate on ambient advisories
- 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
References
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: (...)onaction-builder-ghcrandaction-deployer-openshift). Any futurepaths-filteror job-levelif: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"
analysis.ymlpr-open.yml→reusable-tests.ymldeploys.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.ymlalways runs init + matrix jobs even when the action logsNOT 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)
exit-code: 0, triage in Security tab.github/workflows/pr-open.ymlonlyneeds.deploys.outputs.triggered == 'true'cancel-in-progress: trueon PR number — only latest push mattersProposed direction (for refinement)
Option A: Shared path-gate job (incremental)
Add a single upstream job (e.g.
changes) whose outputs drive downstream jobs:bcgov
triggersstrings stay aligned with (or derived from) that one definition. Mitigates drift without a full rewrite.Option B: Workflow separation (rearchitecture)
Explicit separation of concerns:
pr-open.ymlor deploy manifests change; optional PR namespaceReplace 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
if:conditionals around already-no-op deploy jobs (marginal savings, drift risk)Open questions
pr-open.ymlworkflow, or still require PR Results?paths:filters vs sharedchangesjob vs bcgov action triggers — pick one source of truthReferences
.github/workflows/trigger (May 2026)