Skip to content

Commit 6ab284f

Browse files
committed
Validate cpflow gem and workflow pins
1 parent 8ad88b0 commit 6ab284f

12 files changed

Lines changed: 131 additions & 3 deletions

File tree

.github/actions/cpflow-setup-environment/action.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ inputs:
3737
without publishing a release.
3838
required: false
3939
default: ""
40+
control_plane_flow_ref:
41+
description: >-
42+
control-plane-flow GitHub ref used by the calling reusable workflow. When
43+
cpflow_version is set, this must be the matching release tag.
44+
required: false
45+
default: ""
4046

4147
runs:
4248
using: composite
@@ -83,6 +89,7 @@ runs:
8389
- name: Install Control Plane CLI and cpflow gem
8490
shell: bash
8591
env:
92+
CONTROL_PLANE_FLOW_REF: ${{ inputs.control_plane_flow_ref }}
8693
CPLN_CLI_VERSION: ${{ inputs.cpln_cli_version }}
8794
CPFLOW_VERSION: ${{ inputs.cpflow_version }}
8895
CPFLOW_SOURCE_DIR: ${{ github.action_path }}/../../..
@@ -95,6 +102,46 @@ runs:
95102
96103
CPLN_CLI_VERSION="${CPLN_CLI_VERSION:-${default_cpln_cli_version}}"
97104
105+
normalize_version() {
106+
local version="${1#v}"
107+
108+
if [[ "${version}" =~ ^([0-9]+\.[0-9]+\.[0-9]+)([.-](test|beta|alpha|rc|pre|dev|snapshot|nightly)([.-]?([0-9]+))?)?$ ]]; then
109+
if [[ -n "${BASH_REMATCH[3]}" ]]; then
110+
echo "${BASH_REMATCH[1]}.${BASH_REMATCH[3]}${BASH_REMATCH[5]:+.${BASH_REMATCH[5]}}"
111+
else
112+
echo "${BASH_REMATCH[1]}"
113+
fi
114+
fi
115+
}
116+
117+
normalize_release_ref() {
118+
local ref="${1#refs/tags/}"
119+
120+
[[ "${ref}" == v* ]] || return 0
121+
normalize_version "${ref}"
122+
}
123+
124+
validate_cpflow_version_pin() {
125+
[[ -z "${CPFLOW_VERSION}" ]] && return 0
126+
127+
local actual_version
128+
local expected_version
129+
actual_version="$(normalize_version "${CPFLOW_VERSION}")"
130+
expected_version="$(normalize_release_ref "${CONTROL_PLANE_FLOW_REF}")"
131+
132+
if [[ -z "${expected_version}" ]]; then
133+
echo "::error::CPFLOW_VERSION can only be used when control_plane_flow_ref is a release tag like v${CPFLOW_VERSION}. Current control_plane_flow_ref: ${CONTROL_PLANE_FLOW_REF:-<empty>}. Leave CPFLOW_VERSION unset when testing a commit SHA or branch so cpflow is built from the same source as the reusable workflow."
134+
exit 1
135+
fi
136+
137+
if [[ "${actual_version}" != "${expected_version}" ]]; then
138+
echo "::error::CPFLOW_VERSION must match control_plane_flow_ref. CPFLOW_VERSION=${CPFLOW_VERSION}, normalized CPFLOW_VERSION=${actual_version:-<unrecognized>}, control_plane_flow_ref=${CONTROL_PLANE_FLOW_REF}, expected CPFLOW_VERSION=${expected_version}."
139+
exit 1
140+
fi
141+
}
142+
143+
validate_cpflow_version_pin
144+
98145
npm_global_prefix="${HOME}/.npm-global"
99146
mkdir -p "${npm_global_prefix}"
100147
echo "${npm_global_prefix}/bin" >> "$GITHUB_PATH"

.github/workflows/cpflow-cleanup-stale-review-apps.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ jobs:
5353
working_directory: .cpflow
5454
cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
5555
cpflow_version: ${{ vars.CPFLOW_VERSION }}
56+
control_plane_flow_ref: ${{ inputs.control_plane_flow_ref }}
5657

5758
- name: Checkout caller repository
5859
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd

.github/workflows/cpflow-delete-review-app.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ jobs:
9797
working_directory: app
9898
cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
9999
cpflow_version: ${{ vars.CPFLOW_VERSION }}
100+
control_plane_flow_ref: ${{ inputs.control_plane_flow_ref }}
100101

101102
- name: Set workflow links
102103
if: steps.config.outputs.ready == 'true'

.github/workflows/cpflow-deploy-review-app.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ jobs:
202202
org: ${{ vars.CPLN_ORG_STAGING }}
203203
cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
204204
cpflow_version: ${{ vars.CPFLOW_VERSION }}
205+
control_plane_flow_ref: ${{ inputs.control_plane_flow_ref }}
205206
working_directory: app
206207

207208
- name: Detect release phase support

.github/workflows/cpflow-deploy-staging.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ jobs:
107107
working_directory: .cpflow
108108
cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
109109
cpflow_version: ${{ vars.CPFLOW_VERSION }}
110+
control_plane_flow_ref: ${{ inputs.control_plane_flow_ref }}
110111

111112
- name: Build Docker image
112113
uses: ./.cpflow/.github/actions/cpflow-build-docker-image
@@ -145,6 +146,7 @@ jobs:
145146
working_directory: .cpflow
146147
cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
147148
cpflow_version: ${{ vars.CPFLOW_VERSION }}
149+
control_plane_flow_ref: ${{ inputs.control_plane_flow_ref }}
148150

149151
- name: Detect release phase support
150152
id: release-phase

.github/workflows/cpflow-promote-staging-to-production.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ jobs:
9292
working_directory: .cpflow
9393
cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
9494
cpflow_version: ${{ vars.CPFLOW_VERSION }}
95+
control_plane_flow_ref: ${{ inputs.control_plane_flow_ref }}
9596

9697
# Runs after Setup production environment so the pinned Ruby (>= 3.1) is on PATH.
9798
# YAML.load_file(..., aliases: true) is not supported on Ruby 3.0 (system Ruby on ubuntu-22.04).

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ In addition to the standard keepachangelog.com categories, this project uses a l
1212

1313
## [Unreleased]
1414

15+
### Added
16+
17+
- Added a generated workflow guard that fails early when `CPFLOW_VERSION` does not match the `control_plane_flow_ref` release tag. This prevents review apps from running with reusable workflow/composite action code from one `control-plane-flow` version and a `cpflow` gem from another.
18+
19+
### Fixed
20+
21+
- Fixed generated Control Plane entrypoints so database preparation runs through `./bin/rails`, stops the container on failure, and only runs for Rails server commands instead of every workload sharing the image.
22+
1523
## [5.0.0] - 2026-05-23
1624

1725
### Breaking Changes

docs/ci-automation.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,13 @@ feature-branch refs.
301301
pinning the wrappers to the matching `v<version>` tag, or set
302302
`CPFLOW_VERSION` to that same released gem version without the leading `v`.
303303

304+
The setup action fails early when `CPFLOW_VERSION` and `control_plane_flow_ref`
305+
are out of sync. `CPFLOW_VERSION=5.0.0` is accepted only when
306+
`control_plane_flow_ref` is `v5.0.0` (or `refs/tags/v5.0.0`). When testing an
307+
upstream commit SHA or branch, leave `CPFLOW_VERSION` unset so the workflow
308+
builds `cpflow` from the same source that supplies the reusable workflow and
309+
composite actions.
310+
304311
## Testing Unreleased Upstream Changes Downstream
305312

306313
You can test a `control-plane-flow` PR in a downstream app before merging or
@@ -319,7 +326,10 @@ releasing it. Use an immutable commit SHA from the upstream PR branch:
319326
local experiments that should not be committed.
320327

321328
3. Keep `CPFLOW_VERSION` unset so the workflow builds `cpflow` from the same
322-
upstream SHA that supplies the reusable workflow and composite actions.
329+
upstream SHA that supplies the reusable workflow and composite actions. If
330+
`CPFLOW_VERSION` is set while `control_plane_flow_ref` is a SHA, the setup
331+
action fails before deployment because the gem and action code cannot be
332+
proven to match.
323333
4. Run:
324334

325335
```sh
Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
11
#!/bin/sh
2+
set -e
23
# Runs before the main command
34

4-
echo " -- Preparing database"
5-
rails db:prepare
5+
is_rails_server_command() {
6+
if [ "${1:-}" = "bundle" ] && [ "${2:-}" = "exec" ]; then
7+
shift 2
8+
fi
9+
10+
if [ "${1:-}" = "./bin/thrust" ]; then
11+
shift
12+
fi
13+
14+
{ [ "${1:-}" = "rails" ] || [ "${1:-}" = "./bin/rails" ]; } &&
15+
{ [ "${2:-}" = "server" ] || [ "${2:-}" = "s" ]; }
16+
}
17+
18+
# Match generated Rails server commands; workers and renderers skip DB prep.
19+
if is_rails_server_command "$@"; then
20+
echo " -- Preparing database"
21+
./bin/rails db:prepare
22+
fi
623

724
echo " -- Finishing entrypoint.sh, executing command"
825
exec "$@"

lib/github_flow_templates/.github/cpflow-help.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ For normal releases, point both pins at a release tag such as `v5.0.0`.
7070
You may leave `CPFLOW_VERSION` unset, or set it to the matching RubyGems version
7171
without the leading `v`, such as `5.0.0`.
7272

73+
If `CPFLOW_VERSION` is set, the setup action verifies that it matches the
74+
`control_plane_flow_ref` release tag before installing anything. For example,
75+
`CPFLOW_VERSION=5.0.0` requires `control_plane_flow_ref: v5.0.0`. A mismatch
76+
fails the workflow before the review app build/deploy starts.
77+
7378
For temporary downstream testing of an upstream PR before a gem is released, pin
7479
both values to the exact 40-character commit SHA and leave `CPFLOW_VERSION`
7580
unset:

0 commit comments

Comments
 (0)