chore(ci): add auto-bump-images + pkg/** path filter to all build-*-controller workflows (Closes #2006)
TBD-A69. PR #2005 fixed build-organization-controller.yaml only. The other six controller workflows (application, blueprint, continuum, environment, sandbox, useraccess) had the same gaps that caused the #1997 18h deploy gap: - application-controller: missing pkg/** in path filter (auto-bump already present from earlier work). - blueprint, continuum, environment, useraccess: missing BOTH pkg/** path filter AND auto-bump pipeline (permissions promotion + values.yaml bump + commit/push + blueprint-release dispatch). - sandbox: already complete (pkg/** + auto-bump to platform/sandbox chart) — left untouched. Each updated workflow inherits the canonical shape from build-organization-controller.yaml (PR #2005): 1. `core/controllers/pkg/**` added to BOTH push.paths and pull_request.paths. Without this, a fix that only touches the shared HTTP-client tree (gitea/keycloak/kc-mappers) silently fails to rebuild the controller image. 2. `permissions.contents: write` + `actions: write` so the build job can push the values.yaml bump and dispatch the downstream chart re-publish. 3. An awk-scoped `Bump controllers.<who>.image.tag in values.yaml` step that updates ONLY the targeted controller's tag (verified locally — sibling tags remain untouched). 4. A commit/push step that bumps products/catalyst/chart/values.yaml (or products/continuum/chart/values.yaml for continuum, which has its own chart). 5. A `gh workflow run blueprint-release.yaml` dispatch so the bot-pushed commit fires the downstream chart re-publish (GitHub Actions silently filters bot pushes from path-trigger workflows otherwise). Adds two new files to lock the shape in: - `scripts/check-controller-workflow-uniformity.sh` — a CI regression test that grep-asserts every controller workflow has the canonical pkg/** filter + auto-bump pipeline. Fails loudly if any new controller workflow ships without the canonical shape, or if an existing one regresses. - `.github/workflows/check-controller-workflow-uniformity.yaml` — push-on-touch + pull_request-on-touch event-driven wrapper that runs the script. Mirrors the shape of check-vendor-coupling.yaml. Verified locally: - YAML syntax valid for all 7 controller workflows + the new check workflow. - Regression script passes on all 7 controller workflows. - Simulated awk bumps against products/catalyst/chart/values.yaml and products/continuum/chart/values.yaml — each script bumps ONLY the targeted controller's tag, sibling tags untouched. No chart bumps. No Go/chart changes. CI-workflow-only. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4568298c9b
commit
354ddd5711
@ -20,6 +20,15 @@ on:
|
||||
paths:
|
||||
- 'core/controllers/application/**'
|
||||
- 'core/controllers/internal/**'
|
||||
# core/controllers/pkg/** is the shared HTTP-client tree (gitea,
|
||||
# keycloak, kc-mappers, …) consumed by every Group C controller's
|
||||
# Containerfile via `COPY core/controllers/pkg`. Without this path
|
||||
# entry a change to the shared pkg/ tree rebuilds the image only
|
||||
# if the same PR also happens to touch files under application/ —
|
||||
# which silently held the t38 #1997 gitea-405 fix in main for
|
||||
# ~12h. Uniform pattern across every build-*-controller.yaml
|
||||
# (TBD-A69 #2006).
|
||||
- 'core/controllers/pkg/**'
|
||||
- 'core/controllers/go.mod'
|
||||
- 'core/controllers/go.sum'
|
||||
- '.github/workflows/build-application-controller.yaml'
|
||||
@ -28,6 +37,7 @@ on:
|
||||
paths:
|
||||
- 'core/controllers/application/**'
|
||||
- 'core/controllers/internal/**'
|
||||
- 'core/controllers/pkg/**'
|
||||
- 'core/controllers/go.mod'
|
||||
- 'core/controllers/go.sum'
|
||||
- '.github/workflows/build-application-controller.yaml'
|
||||
|
||||
@ -21,6 +21,15 @@ on:
|
||||
paths:
|
||||
- 'core/controllers/blueprint/**'
|
||||
- 'core/controllers/internal/**'
|
||||
# core/controllers/pkg/** is the shared HTTP-client tree (gitea,
|
||||
# keycloak, kc-mappers, …) consumed by every Group C controller's
|
||||
# Containerfile via `COPY core/controllers/pkg`. Without this path
|
||||
# entry a change to the shared pkg/ tree rebuilds the image only
|
||||
# if the same PR also happens to touch files under blueprint/ —
|
||||
# which silently held the t38 #1997 gitea-405 fix in main for
|
||||
# ~12h. Uniform pattern across every build-*-controller.yaml
|
||||
# (TBD-A69 #2006).
|
||||
- 'core/controllers/pkg/**'
|
||||
- 'core/controllers/go.mod'
|
||||
- 'core/controllers/go.sum'
|
||||
- '.github/workflows/build-blueprint-controller.yaml'
|
||||
@ -29,6 +38,7 @@ on:
|
||||
paths:
|
||||
- 'core/controllers/blueprint/**'
|
||||
- 'core/controllers/internal/**'
|
||||
- 'core/controllers/pkg/**'
|
||||
- 'core/controllers/go.mod'
|
||||
- 'core/controllers/go.sum'
|
||||
- '.github/workflows/build-blueprint-controller.yaml'
|
||||
@ -42,10 +52,19 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
# contents: write — the deploy step below pushes a values.yaml SHA
|
||||
# bump back to main so the bp-catalyst-platform chart picks up the
|
||||
# newly-built image without an operator manually editing the file
|
||||
# (per `feedback_no_mvp_no_workarounds.md` rule 1: target-state,
|
||||
# never "manual follow-up bump"). Pre-#2006 this workflow shipped
|
||||
# without auto-bump — same deploy-gap class as #1997.
|
||||
contents: write
|
||||
packages: write
|
||||
# id-token write is required by cosign keyless signing (Sigstore).
|
||||
id-token: write
|
||||
# actions: write — required for `gh workflow run` to dispatch the
|
||||
# downstream blueprint-release chart re-publish workflow.
|
||||
actions: write
|
||||
outputs:
|
||||
sha_short: ${{ steps.vars.outputs.sha_short }}
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
@ -133,3 +152,67 @@ jobs:
|
||||
--predicate <(echo '{"sbom":"in-toto-spdx attached at build time"}') \
|
||||
--type spdx \
|
||||
"${IMAGE}@${DIGEST}"
|
||||
|
||||
# Auto-bump the chart values.yaml tag so the next Sovereign chart
|
||||
# rollout picks up this image without a manual edit. Per
|
||||
# `feedback_no_mvp_no_workarounds.md` rule 1 (target-state, no
|
||||
# operator-action gates) and `feedback_inviolable_principles.md`
|
||||
# (event-driven, never cron). Mirrors the pattern in
|
||||
# build-application-controller.yaml + build-organization-controller.yaml.
|
||||
# Added as part of TBD-A69 (#2006) — pre-#2006 this workflow shipped
|
||||
# without auto-bump, so the same deploy-gap class as #1997 was live
|
||||
# for every blueprint-controller code fix.
|
||||
- name: Bump controllers.blueprint.image.tag in values.yaml
|
||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
||||
env:
|
||||
SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
|
||||
run: |
|
||||
VALUES="products/catalyst/chart/values.yaml"
|
||||
# awk: find ` blueprint:` under `controllers:`, then update
|
||||
# the next `tag: "..."` line. Stops at the next top-level key
|
||||
# so we don't accidentally bump a sibling controller's tag.
|
||||
awk -v sha="${SHA_SHORT}" '
|
||||
/^controllers:/ { in_ctrls=1 }
|
||||
in_ctrls && /^ blueprint:/ { print; in_bp=1; next }
|
||||
in_ctrls && /^ [a-z]/ && !/^ blueprint:/ { in_bp=0 }
|
||||
in_bp && /^ tag:/ { sub(/"[^"]*"/, "\"" sha "\""); in_bp=0 }
|
||||
{ print }
|
||||
' "${VALUES}" > "${VALUES}.tmp" && mv "${VALUES}.tmp" "${VALUES}"
|
||||
echo "values.yaml after bump:"
|
||||
grep -A4 "^ blueprint:" "${VALUES}" | head -10
|
||||
|
||||
- name: Commit and push values.yaml bump
|
||||
id: deploy_commit
|
||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
||||
env:
|
||||
SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
if git diff --quiet products/catalyst/chart/values.yaml; then
|
||||
echo "no values.yaml change — already pinned to ${SHA_SHORT}"
|
||||
echo "pushed=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
git add products/catalyst/chart/values.yaml
|
||||
git commit -m "deploy: bump blueprint-controller image to ${SHA_SHORT}"
|
||||
# Pull-rebase to avoid races with parallel build commits.
|
||||
git pull --rebase --autostash origin main || true
|
||||
git push origin HEAD:main
|
||||
echo "pushed=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# GitHub Actions does NOT trigger workflows from bot pushes by
|
||||
# default (anti-recursion safeguard). Without this dispatch the
|
||||
# rebuilt image is NEVER baked into a new chart version, so
|
||||
# Sovereigns keep installing the previous chart with the previous
|
||||
# image tag (`feedback_no_mvp_no_workarounds.md` rule 1 violation).
|
||||
- name: Dispatch blueprint-release for chart re-publish
|
||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' && steps.deploy_commit.outputs.pushed == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh workflow run blueprint-release.yaml \
|
||||
--repo "${GITHUB_REPOSITORY}" \
|
||||
--ref main \
|
||||
-f blueprint=catalyst \
|
||||
-f tree=products
|
||||
|
||||
@ -20,6 +20,15 @@ on:
|
||||
paths:
|
||||
- 'core/controllers/continuum/**'
|
||||
- 'core/controllers/internal/**'
|
||||
# core/controllers/pkg/** is the shared HTTP-client tree (gitea,
|
||||
# keycloak, kc-mappers, …) consumed by every Group C controller's
|
||||
# Containerfile via `COPY core/controllers/pkg`. Without this path
|
||||
# entry a change to the shared pkg/ tree rebuilds the image only
|
||||
# if the same PR also happens to touch files under continuum/ —
|
||||
# which silently held the t38 #1997 gitea-405 fix in main for
|
||||
# ~12h. Uniform pattern across every build-*-controller.yaml
|
||||
# (TBD-A69 #2006).
|
||||
- 'core/controllers/pkg/**'
|
||||
- 'core/controllers/go.mod'
|
||||
- 'core/controllers/go.sum'
|
||||
- 'products/continuum/**'
|
||||
@ -29,6 +38,7 @@ on:
|
||||
paths:
|
||||
- 'core/controllers/continuum/**'
|
||||
- 'core/controllers/internal/**'
|
||||
- 'core/controllers/pkg/**'
|
||||
- 'core/controllers/go.mod'
|
||||
- 'core/controllers/go.sum'
|
||||
- 'products/continuum/**'
|
||||
@ -43,10 +53,19 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
# contents: write — the deploy step below pushes a values.yaml SHA
|
||||
# bump back to main so the products/continuum chart picks up the
|
||||
# newly-built image without an operator manually editing the file
|
||||
# (per `feedback_no_mvp_no_workarounds.md` rule 1: target-state,
|
||||
# never "manual follow-up bump"). Pre-#2006 this workflow shipped
|
||||
# without auto-bump — same deploy-gap class as #1997.
|
||||
contents: write
|
||||
packages: write
|
||||
# id-token write is required by cosign keyless signing (Sigstore).
|
||||
id-token: write
|
||||
# actions: write — required for `gh workflow run` to dispatch the
|
||||
# downstream blueprint-release chart re-publish workflow.
|
||||
actions: write
|
||||
outputs:
|
||||
sha_short: ${{ steps.vars.outputs.sha_short }}
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
@ -184,6 +203,72 @@ jobs:
|
||||
--type spdx \
|
||||
"${IMAGE}@${DIGEST}"
|
||||
|
||||
# Auto-bump the chart values.yaml tag so the next Sovereign chart
|
||||
# rollout picks up this image without a manual edit. Per
|
||||
# `feedback_no_mvp_no_workarounds.md` rule 1 (target-state, no
|
||||
# operator-action gates) and `feedback_inviolable_principles.md`
|
||||
# (event-driven, never cron). Unlike sibling controllers that ship
|
||||
# in the catalyst chart, continuum-controller has its own
|
||||
# standalone chart at products/continuum/chart/values.yaml whose
|
||||
# top-level `continuum.image.tag` is what gets stamped.
|
||||
# Added as part of TBD-A69 (#2006) — pre-#2006 this workflow shipped
|
||||
# without auto-bump, so the same deploy-gap class as #1997 was live
|
||||
# for every continuum-controller code fix.
|
||||
- name: Bump continuum.image.tag in products/continuum/chart/values.yaml
|
||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
||||
env:
|
||||
SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
|
||||
run: |
|
||||
VALUES="products/continuum/chart/values.yaml"
|
||||
# awk: find top-level `continuum:`, then update the next
|
||||
# `tag: "..."` line under its `image:` sub-block. Stops at the
|
||||
# next top-level key so we don't accidentally bump an unrelated
|
||||
# tag.
|
||||
awk -v sha="${SHA_SHORT}" '
|
||||
/^continuum:/ { in_cont=1 }
|
||||
in_cont && /^[a-z]/ && !/^continuum:/ { in_cont=0 }
|
||||
in_cont && /^ tag:/ { sub(/"[^"]*"/, "\"" sha "\""); in_cont=0 }
|
||||
{ print }
|
||||
' "${VALUES}" > "${VALUES}.tmp" && mv "${VALUES}.tmp" "${VALUES}"
|
||||
echo "values.yaml after bump:"
|
||||
grep -A4 "^continuum:" "${VALUES}" | head -10
|
||||
|
||||
- name: Commit and push values.yaml bump
|
||||
id: deploy_commit
|
||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
||||
env:
|
||||
SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
if git diff --quiet products/continuum/chart/values.yaml; then
|
||||
echo "no values.yaml change — already pinned to ${SHA_SHORT}"
|
||||
echo "pushed=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
git add products/continuum/chart/values.yaml
|
||||
git commit -m "deploy: bump continuum-controller image to ${SHA_SHORT}"
|
||||
# Pull-rebase to avoid races with parallel build commits.
|
||||
git pull --rebase --autostash origin main || true
|
||||
git push origin HEAD:main
|
||||
echo "pushed=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# GitHub Actions does NOT trigger workflows from bot pushes by
|
||||
# default (anti-recursion safeguard). Without this dispatch the
|
||||
# rebuilt image is NEVER baked into a new chart version, so
|
||||
# Sovereigns keep installing the previous chart with the previous
|
||||
# image tag (`feedback_no_mvp_no_workarounds.md` rule 1 violation).
|
||||
- name: Dispatch blueprint-release for chart re-publish
|
||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' && steps.deploy_commit.outputs.pushed == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh workflow run blueprint-release.yaml \
|
||||
--repo "${GITHUB_REPOSITORY}" \
|
||||
--ref main \
|
||||
-f blueprint=continuum \
|
||||
-f tree=products
|
||||
|
||||
notify:
|
||||
# repository_dispatch on success → triggers downstream chart-bump
|
||||
# workflow that stamps the image SHA into per-Sovereign overlay
|
||||
|
||||
@ -15,6 +15,15 @@ on:
|
||||
paths:
|
||||
- 'core/controllers/environment/**'
|
||||
- 'core/controllers/internal/**'
|
||||
# core/controllers/pkg/** is the shared HTTP-client tree (gitea,
|
||||
# keycloak, kc-mappers, …) consumed by every Group C controller's
|
||||
# Containerfile via `COPY core/controllers/pkg`. Without this path
|
||||
# entry a change to the shared pkg/ tree rebuilds the image only
|
||||
# if the same PR also happens to touch files under environment/ —
|
||||
# which silently held the t38 #1997 gitea-405 fix in main for
|
||||
# ~12h. Uniform pattern across every build-*-controller.yaml
|
||||
# (TBD-A69 #2006).
|
||||
- 'core/controllers/pkg/**'
|
||||
- 'core/controllers/go.mod'
|
||||
- 'core/controllers/go.sum'
|
||||
- '.github/workflows/build-environment-controller.yaml'
|
||||
@ -23,6 +32,7 @@ on:
|
||||
paths:
|
||||
- 'core/controllers/environment/**'
|
||||
- 'core/controllers/internal/**'
|
||||
- 'core/controllers/pkg/**'
|
||||
- 'core/controllers/go.mod'
|
||||
- 'core/controllers/go.sum'
|
||||
- '.github/workflows/build-environment-controller.yaml'
|
||||
@ -36,10 +46,19 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
# contents: write — the deploy step below pushes a values.yaml SHA
|
||||
# bump back to main so the bp-catalyst-platform chart picks up the
|
||||
# newly-built image without an operator manually editing the file
|
||||
# (per `feedback_no_mvp_no_workarounds.md` rule 1: target-state,
|
||||
# never "manual follow-up bump"). Pre-#2006 this workflow shipped
|
||||
# without auto-bump — same deploy-gap class as #1997.
|
||||
contents: write
|
||||
packages: write
|
||||
# id-token write is required by cosign keyless signing (Sigstore).
|
||||
id-token: write
|
||||
# actions: write — required for `gh workflow run` to dispatch the
|
||||
# downstream blueprint-release chart re-publish workflow.
|
||||
actions: write
|
||||
outputs:
|
||||
sha_short: ${{ steps.vars.outputs.sha_short }}
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
@ -127,3 +146,67 @@ jobs:
|
||||
--predicate <(echo '{"sbom":"in-toto-spdx attached at build time"}') \
|
||||
--type spdx \
|
||||
"${IMAGE}@${DIGEST}"
|
||||
|
||||
# Auto-bump the chart values.yaml tag so the next Sovereign chart
|
||||
# rollout picks up this image without a manual edit. Per
|
||||
# `feedback_no_mvp_no_workarounds.md` rule 1 (target-state, no
|
||||
# operator-action gates) and `feedback_inviolable_principles.md`
|
||||
# (event-driven, never cron). Mirrors the pattern in
|
||||
# build-application-controller.yaml + build-organization-controller.yaml.
|
||||
# Added as part of TBD-A69 (#2006) — pre-#2006 this workflow shipped
|
||||
# without auto-bump, so the same deploy-gap class as #1997 was live
|
||||
# for every environment-controller code fix.
|
||||
- name: Bump controllers.environment.image.tag in values.yaml
|
||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
||||
env:
|
||||
SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
|
||||
run: |
|
||||
VALUES="products/catalyst/chart/values.yaml"
|
||||
# awk: find ` environment:` under `controllers:`, then update
|
||||
# the next `tag: "..."` line. Stops at the next top-level key
|
||||
# so we don't accidentally bump a sibling controller's tag.
|
||||
awk -v sha="${SHA_SHORT}" '
|
||||
/^controllers:/ { in_ctrls=1 }
|
||||
in_ctrls && /^ environment:/ { print; in_env=1; next }
|
||||
in_ctrls && /^ [a-z]/ && !/^ environment:/ { in_env=0 }
|
||||
in_env && /^ tag:/ { sub(/"[^"]*"/, "\"" sha "\""); in_env=0 }
|
||||
{ print }
|
||||
' "${VALUES}" > "${VALUES}.tmp" && mv "${VALUES}.tmp" "${VALUES}"
|
||||
echo "values.yaml after bump:"
|
||||
grep -A4 "^ environment:" "${VALUES}" | head -10
|
||||
|
||||
- name: Commit and push values.yaml bump
|
||||
id: deploy_commit
|
||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
||||
env:
|
||||
SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
if git diff --quiet products/catalyst/chart/values.yaml; then
|
||||
echo "no values.yaml change — already pinned to ${SHA_SHORT}"
|
||||
echo "pushed=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
git add products/catalyst/chart/values.yaml
|
||||
git commit -m "deploy: bump environment-controller image to ${SHA_SHORT}"
|
||||
# Pull-rebase to avoid races with parallel build commits.
|
||||
git pull --rebase --autostash origin main || true
|
||||
git push origin HEAD:main
|
||||
echo "pushed=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# GitHub Actions does NOT trigger workflows from bot pushes by
|
||||
# default (anti-recursion safeguard). Without this dispatch the
|
||||
# rebuilt image is NEVER baked into a new chart version, so
|
||||
# Sovereigns keep installing the previous chart with the previous
|
||||
# image tag (`feedback_no_mvp_no_workarounds.md` rule 1 violation).
|
||||
- name: Dispatch blueprint-release for chart re-publish
|
||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' && steps.deploy_commit.outputs.pushed == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh workflow run blueprint-release.yaml \
|
||||
--repo "${GITHUB_REPOSITORY}" \
|
||||
--ref main \
|
||||
-f blueprint=catalyst \
|
||||
-f tree=products
|
||||
|
||||
49
.github/workflows/check-controller-workflow-uniformity.yaml
vendored
Normal file
49
.github/workflows/check-controller-workflow-uniformity.yaml
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
name: Controller-workflow uniformity guardrail
|
||||
|
||||
# Regression test for TBD-A69 (#2006). Asserts every
|
||||
# build-*-controller.yaml + *-controller-build.yaml workflow contains
|
||||
# the canonical CI shape:
|
||||
#
|
||||
# 1. `core/controllers/pkg/**` in BOTH push.paths and pull_request.paths.
|
||||
# 2. `contents: write` + auto-bump step that stamps short SHA into
|
||||
# the chart values.yaml.
|
||||
# 3. blueprint-release.yaml dispatch after the bot push (catalyst
|
||||
# bundle workflows only; sandbox is exempt — its own chart).
|
||||
#
|
||||
# Pre-#2006: only build-organization-controller.yaml carried the full
|
||||
# shape (added in PR #2005); the other six controllers had partial /
|
||||
# missing pieces and shipped the #1997 18h deploy gap.
|
||||
#
|
||||
# Per CLAUDE.md "every workflow MUST be event-driven, NEVER scheduled":
|
||||
# this workflow is push-on-merge + pull-request-on-touch. No cron.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- '.github/workflows/build-*-controller.yaml'
|
||||
- '.github/workflows/*-controller-build.yaml'
|
||||
- '.github/workflows/check-controller-workflow-uniformity.yaml'
|
||||
- 'scripts/check-controller-workflow-uniformity.sh'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/build-*-controller.yaml'
|
||||
- '.github/workflows/*-controller-build.yaml'
|
||||
- '.github/workflows/check-controller-workflow-uniformity.yaml'
|
||||
- 'scripts/check-controller-workflow-uniformity.sh'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Controller-workflow uniformity
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run controller-workflow uniformity check
|
||||
run: bash scripts/check-controller-workflow-uniformity.sh
|
||||
@ -17,6 +17,15 @@ on:
|
||||
paths:
|
||||
- 'core/controllers/useraccess/**'
|
||||
- 'core/controllers/internal/**'
|
||||
# core/controllers/pkg/** is the shared HTTP-client tree (gitea,
|
||||
# keycloak, kc-mappers, …) consumed by every Group C controller's
|
||||
# Containerfile via `COPY core/controllers/pkg`. Without this path
|
||||
# entry a change to the shared pkg/ tree rebuilds the image only
|
||||
# if the same PR also happens to touch files under useraccess/ —
|
||||
# which silently held the t38 #1997 gitea-405 fix in main for
|
||||
# ~12h. Uniform pattern across every build-*-controller.yaml
|
||||
# (TBD-A69 #2006).
|
||||
- 'core/controllers/pkg/**'
|
||||
- 'core/controllers/go.mod'
|
||||
- 'core/controllers/go.sum'
|
||||
- '.github/workflows/useraccess-controller-build.yaml'
|
||||
@ -26,6 +35,7 @@ on:
|
||||
paths:
|
||||
- 'core/controllers/useraccess/**'
|
||||
- 'core/controllers/internal/**'
|
||||
- 'core/controllers/pkg/**'
|
||||
- 'core/controllers/go.mod'
|
||||
- 'core/controllers/go.sum'
|
||||
- '.github/workflows/useraccess-controller-build.yaml'
|
||||
@ -68,9 +78,18 @@ jobs:
|
||||
if: github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
# contents: write — the deploy step below pushes a values.yaml SHA
|
||||
# bump back to main so the bp-catalyst-platform chart picks up the
|
||||
# newly-built image without an operator manually editing the file
|
||||
# (per `feedback_no_mvp_no_workarounds.md` rule 1: target-state,
|
||||
# never "manual follow-up bump"). Pre-#2006 this workflow shipped
|
||||
# without auto-bump — same deploy-gap class as #1997.
|
||||
contents: write
|
||||
packages: write
|
||||
id-token: write
|
||||
# actions: write — required for `gh workflow run` to dispatch the
|
||||
# downstream blueprint-release chart re-publish workflow.
|
||||
actions: write
|
||||
outputs:
|
||||
sha_short: ${{ steps.vars.outputs.sha_short }}
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
@ -114,3 +133,67 @@ jobs:
|
||||
# Keep the image small and reproducible: no labels added by
|
||||
# build-push-action's defaults; the Containerfile is the
|
||||
# single source of truth.
|
||||
|
||||
# Auto-bump the chart values.yaml tag so the next Sovereign chart
|
||||
# rollout picks up this image without a manual edit. Per
|
||||
# `feedback_no_mvp_no_workarounds.md` rule 1 (target-state, no
|
||||
# operator-action gates) and `feedback_inviolable_principles.md`
|
||||
# (event-driven, never cron). Mirrors the pattern in
|
||||
# build-application-controller.yaml + build-organization-controller.yaml.
|
||||
# Added as part of TBD-A69 (#2006) — pre-#2006 this workflow shipped
|
||||
# without auto-bump, so the same deploy-gap class as #1997 was live
|
||||
# for every useraccess-controller code fix.
|
||||
- name: Bump controllers.useraccess.image.tag in values.yaml
|
||||
if: github.ref == 'refs/heads/main'
|
||||
env:
|
||||
SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
|
||||
run: |
|
||||
VALUES="products/catalyst/chart/values.yaml"
|
||||
# awk: find ` useraccess:` under `controllers:`, then update
|
||||
# the next `tag: "..."` line. Stops at the next top-level key
|
||||
# so we don't accidentally bump a sibling controller's tag.
|
||||
awk -v sha="${SHA_SHORT}" '
|
||||
/^controllers:/ { in_ctrls=1 }
|
||||
in_ctrls && /^ useraccess:/ { print; in_ua=1; next }
|
||||
in_ctrls && /^ [a-z]/ && !/^ useraccess:/ { in_ua=0 }
|
||||
in_ua && /^ tag:/ { sub(/"[^"]*"/, "\"" sha "\""); in_ua=0 }
|
||||
{ print }
|
||||
' "${VALUES}" > "${VALUES}.tmp" && mv "${VALUES}.tmp" "${VALUES}"
|
||||
echo "values.yaml after bump:"
|
||||
grep -A4 "^ useraccess:" "${VALUES}" | head -10
|
||||
|
||||
- name: Commit and push values.yaml bump
|
||||
id: deploy_commit
|
||||
if: github.ref == 'refs/heads/main'
|
||||
env:
|
||||
SHA_SHORT: ${{ steps.vars.outputs.sha_short }}
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
if git diff --quiet products/catalyst/chart/values.yaml; then
|
||||
echo "no values.yaml change — already pinned to ${SHA_SHORT}"
|
||||
echo "pushed=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
git add products/catalyst/chart/values.yaml
|
||||
git commit -m "deploy: bump useraccess-controller image to ${SHA_SHORT}"
|
||||
# Pull-rebase to avoid races with parallel build commits.
|
||||
git pull --rebase --autostash origin main || true
|
||||
git push origin HEAD:main
|
||||
echo "pushed=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# GitHub Actions does NOT trigger workflows from bot pushes by
|
||||
# default (anti-recursion safeguard). Without this dispatch the
|
||||
# rebuilt image is NEVER baked into a new chart version, so
|
||||
# Sovereigns keep installing the previous chart with the previous
|
||||
# image tag (`feedback_no_mvp_no_workarounds.md` rule 1 violation).
|
||||
- name: Dispatch blueprint-release for chart re-publish
|
||||
if: github.ref == 'refs/heads/main' && steps.deploy_commit.outputs.pushed == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh workflow run blueprint-release.yaml \
|
||||
--repo "${GITHUB_REPOSITORY}" \
|
||||
--ref main \
|
||||
-f blueprint=catalyst \
|
||||
-f tree=products
|
||||
|
||||
116
scripts/check-controller-workflow-uniformity.sh
Executable file
116
scripts/check-controller-workflow-uniformity.sh
Executable file
@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env bash
|
||||
# check-controller-workflow-uniformity.sh
|
||||
#
|
||||
# Regression test for TBD-A69 (#2006). Asserts that every
|
||||
# build-*-controller.yaml + *-controller-build.yaml workflow contains the
|
||||
# canonical CI shape that auto-deploys controller code fixes:
|
||||
#
|
||||
# 1. `core/controllers/pkg/**` is in BOTH the push.paths and
|
||||
# pull_request.paths filters. Without this, a fix that only touches
|
||||
# the shared client tree (gitea/keycloak/kc-mappers) silently fails
|
||||
# to rebuild the image — root cause of the 18h #1997 deploy gap.
|
||||
#
|
||||
# 2. `permissions.contents: write` and an auto-bump step that stamps
|
||||
# the freshly-built short SHA into the chart values.yaml. Without
|
||||
# this, the chart's image-tag pin lags main HEAD across multiple
|
||||
# chart releases (same #1997 class).
|
||||
#
|
||||
# 3. A `gh workflow run blueprint-release.yaml` dispatch after the
|
||||
# auto-bump commits. Without this, GitHub Actions' anti-recursion
|
||||
# safeguard silently drops the bot-pushed values.yaml change and
|
||||
# the chart never re-publishes.
|
||||
#
|
||||
# Failure here is a hard CI-fail: future controller workflows must
|
||||
# inherit the canonical shape or the same deploy-gap class re-opens.
|
||||
#
|
||||
# Mirrors scripts/check-vendor-coupling.sh's shape (single script,
|
||||
# fail-loudly, no external deps beyond grep/awk).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
WORKFLOWS_DIR=".github/workflows"
|
||||
|
||||
# Canonical list. Every controller image whose source lives under
|
||||
# core/controllers/ MUST have a workflow in this list. New controllers
|
||||
# get appended here at the same time as their workflow file lands.
|
||||
CONTROLLERS=(
|
||||
"build-application-controller.yaml"
|
||||
"build-blueprint-controller.yaml"
|
||||
"build-continuum-controller.yaml"
|
||||
"build-environment-controller.yaml"
|
||||
"build-organization-controller.yaml"
|
||||
"build-sandbox-controller.yaml"
|
||||
"useraccess-controller-build.yaml"
|
||||
)
|
||||
|
||||
fail=0
|
||||
|
||||
check_pkg_path_filter() {
|
||||
local file="$1"
|
||||
# Both push.paths and pull_request.paths must contain
|
||||
# core/controllers/pkg/**. We count occurrences (expected ≥ 2 — one
|
||||
# under push.paths, one under pull_request.paths).
|
||||
local count
|
||||
count=$(grep -cE "^[[:space:]]+- 'core/controllers/pkg/\*\*'" "${file}" || true)
|
||||
if [ "${count}" -lt 2 ]; then
|
||||
echo "::error file=${file}::missing 'core/controllers/pkg/**' in push.paths AND pull_request.paths (found ${count} occurrences, expected ≥ 2)"
|
||||
fail=1
|
||||
fi
|
||||
}
|
||||
|
||||
check_auto_bump() {
|
||||
local file="$1"
|
||||
# 1. contents: write must be present (so the auto-bump commit can
|
||||
# push back to main).
|
||||
if ! grep -qE "^[[:space:]]+contents:[[:space:]]+write" "${file}"; then
|
||||
echo "::error file=${file}::missing 'contents: write' permission — auto-bump cannot push values.yaml"
|
||||
fail=1
|
||||
fi
|
||||
# 2. A step that bumps the image tag into a values.yaml file.
|
||||
if ! grep -qE "Bump .*image\.tag|Bump .*\.image\.tag in values\.yaml" "${file}"; then
|
||||
echo "::error file=${file}::missing auto-bump step (no 'Bump …image.tag…' step name) — controller image pin will lag main"
|
||||
fail=1
|
||||
fi
|
||||
# 3. A commit/push step.
|
||||
if ! grep -qE "Commit and push values\.yaml bump" "${file}"; then
|
||||
echo "::error file=${file}::missing 'Commit and push values.yaml bump' step — auto-bump never lands in repo"
|
||||
fail=1
|
||||
fi
|
||||
}
|
||||
|
||||
check_blueprint_release_dispatch() {
|
||||
local file="$1"
|
||||
# sandbox-controller has its own product chart and does NOT need the
|
||||
# catalyst blueprint-release dispatch — it auto-bumps to
|
||||
# platform/sandbox/chart/values.yaml. Exempt by filename.
|
||||
case "$(basename "${file}")" in
|
||||
build-sandbox-controller.yaml) return 0 ;;
|
||||
esac
|
||||
if ! grep -qE "gh workflow run blueprint-release\.yaml" "${file}"; then
|
||||
echo "::error file=${file}::missing 'gh workflow run blueprint-release.yaml' dispatch — bot push won't fire downstream chart re-publish"
|
||||
fail=1
|
||||
fi
|
||||
}
|
||||
|
||||
echo "Checking ${#CONTROLLERS[@]} controller workflows for canonical auto-bump shape (TBD-A69)…"
|
||||
|
||||
for wf in "${CONTROLLERS[@]}"; do
|
||||
file="${WORKFLOWS_DIR}/${wf}"
|
||||
if [ ! -f "${file}" ]; then
|
||||
echo "::error::expected workflow file ${file} not found — CONTROLLERS list out of sync with .github/workflows/"
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
check_pkg_path_filter "${file}"
|
||||
check_auto_bump "${file}"
|
||||
check_blueprint_release_dispatch "${file}"
|
||||
done
|
||||
|
||||
if [ "${fail}" -ne 0 ]; then
|
||||
echo
|
||||
echo "FAIL: one or more controller workflows are missing the canonical auto-bump shape."
|
||||
echo "See scripts/check-controller-workflow-uniformity.sh + PR #2005 for the canonical pattern."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "OK: all ${#CONTROLLERS[@]} controller workflows carry the canonical pkg/** filter + auto-bump pipeline."
|
||||
Loading…
Reference in New Issue
Block a user