cpflow 5.0.1 → 5.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1371f70bf636d92e0dacd78322ad6ef7d87e29fbec6c853e487a01205be1528
4
- data.tar.gz: 9ad5116ccb84cc7e3757922c3c0580785caa1cfff96aed768c65d63c7ff01e93
3
+ metadata.gz: f6a3d49d8db4d5df28b82fa8cfb81af3470299d485169997c2904c683b1a56c6
4
+ data.tar.gz: 48cacf78f5d61ca95405b46e152b26547536a3862a06d93433efaa7c52f7f85d
5
5
  SHA512:
6
- metadata.gz: 6c96a1db55e94a5e22efa0640d51129566aa6afb16c8ea9887f5cf709a313ef3b1a690d5b64ba932b50cb1fb72efe85e7fa3371f8941b60242486d6fc1322566
7
- data.tar.gz: 5a91cc36014d13c3b36ea3af7620758821d1fa0000bab12b1742d47fe0240015353c59b5dae6d981680b7746bcaa9154bd44f00a1fc240dce651cd57926a253b
6
+ metadata.gz: 9158740f20c83981417325473f6f9d3b27fee1e0967b31746d44f32d4d6e0dca2d14ab17dfd05d2f27a10a745b33e663cc775c562919fdaa2311e554cddfb2af
7
+ data.tar.gz: c822be6375f28c6c01e13b397f5857fa4d3cd8463cc787cd6dc9be5a6f4967aa17a84af19f4e31c6b565e8325e19286de1c0fa398c22db4966a3f723e7adfb1a
data/CHANGELOG.md CHANGED
@@ -12,6 +12,14 @@ In addition to the standard keepachangelog.com categories, this project uses a l
12
12
 
13
13
  ## [Unreleased]
14
14
 
15
+ ## [5.0.2] - 2026-05-25
16
+
17
+ ### Fixed
18
+
19
+ - **Fixed generated Dockerfiles so Node package-manager shims (`npm`, `npx`, and `corepack`) remain working symlinks in the final Ruby image instead of broken dereferenced files.** [PR 322](https://github.com/shakacode/control-plane-flow/pull/322) by [Justin Gordon](https://github.com/justin808). Generated Dockerfiles now fail fast if the Node shim paths are no longer valid.
20
+ - **Fixed generated Control Plane templates so app workloads receive app identity links, templated YAML scalars are parseable, and generated Postgres resources/secrets are app-scoped.** [PR 322](https://github.com/shakacode/control-plane-flow/pull/322) by [Justin Gordon](https://github.com/justin808). This lets review apps resolve `cpln://secret/...` values reliably from Rails, worker, renderer, and release jobs.
21
+ - **Fixed `cpflow run` so existing runner workloads stay in sync with the source workload `identityLink`.** [PR 322](https://github.com/shakacode/control-plane-flow/pull/322) by [Justin Gordon](https://github.com/justin808). Existing runner jobs now gain or drop the app identity as the source workload changes.
22
+
15
23
  ## [5.0.1] - 2026-05-24
16
24
 
17
25
  ### Breaking Changes
@@ -374,7 +382,8 @@ Deprecated `cpl` gem. New gem is `cpflow`.
374
382
 
375
383
  First release.
376
384
 
377
- [Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v5.0.1...HEAD
385
+ [Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v5.0.2...HEAD
386
+ [5.0.2]: https://github.com/shakacode/control-plane-flow/compare/v5.0.1...v5.0.2
378
387
  [5.0.1]: https://github.com/shakacode/control-plane-flow/compare/v5.0.0...v5.0.1
379
388
  [5.0.0]: https://github.com/shakacode/control-plane-flow/compare/v5.0.0.rc.3...v5.0.0
380
389
  [5.0.0.rc.3]: https://github.com/shakacode/control-plane-flow/compare/v5.0.0.rc.1...v5.0.0.rc.3
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cpflow (5.0.1)
4
+ cpflow (5.0.2)
5
5
  dotenv (~> 3.1)
6
6
  jwt (~> 3.1)
7
7
  psych (~> 5.2)
@@ -20,7 +20,7 @@ prompt tells the agent to stop on.
20
20
  ```text
21
21
  Set up Control Plane GitHub Flow for this repo. Start with `cpflow github-flow-readiness` and stop on any reported blockers. The repo must be deployable from a clean clone: published package versions, complete runtime scaffold, and a production Dockerfile that can build the app. If any package version is unpublished, inaccessible from CI, or requires credentials that are not already modeled in the repo or GitHub settings, stop and report the blocker instead of generating workflow files. If the repo is a legacy sample pinned to an obsolete Ruby or Bundler toolchain, if it does not even have a production Dockerfile yet, or if it is a monorepo without an already-decided single app boundary for this flow, stop and report that as a prerequisite instead of forcing the rollout.
22
22
 
23
- If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `+review-app-deploy`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. Do not hand-edit duplicated upstream refs into the generated wrappers: the only downstream Control Plane Flow pin should be the reusable workflow `uses: ...@vX.Y.Z` value generated from the installed `cpflow` gem version, and upstream workflows load their matching shared actions automatically. Keep the standard path simple: review apps require only `CPLN_TOKEN_STAGING` when the generated review app config can be inferred. For production promotion, document a protected `production` GitHub Environment with required reviewers, prevent self-review, and `CPLN_TOKEN_PRODUCTION` stored as an environment secret, not as a repository or organization secret.
23
+ If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `+review-app-deploy`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. Do not hand-edit duplicated upstream refs into the generated wrappers: the only downstream Control Plane Flow pin should be the reusable workflow `uses: ...@vX.Y.Z` value generated from the installed `cpflow` gem version, and upstream workflows load their matching shared actions automatically. Keep the standard path simple: review apps require only `CPLN_TOKEN_STAGING` when the generated review app config can be inferred. Document the one-time Control Plane bootstrap command for persistent staging and production apps with `cpflow setup-app --skip-post-creation-hook`; for existing apps or later template updates, document `cpflow apply-template` and the need for the app identity to have `reveal` on the app secret policy. Do not imply the staging deploy or promotion workflows create those persistent GVCs. For production promotion, document a protected `production` GitHub Environment with required reviewers, prevent self-review, and `CPLN_TOKEN_PRODUCTION` stored as an environment secret, not as a repository or organization secret.
24
24
 
25
25
  Keep Node available in the final image if asset compilation or SSR depends on ExecJS, Yarn, `pnpm`, or npm after the main install layer. Make sure the generated Dockerfile uses a Ruby base image compatible with the app's declared Ruby requirement. Preserve repo-defined frontend build hooks: if `config/shakapacker.yml` defines a `precompile_hook`, or React on Rails enables `config.auto_load_bundle = true`, confirm the generated Dockerfile runs that codegen step before `rails assets:precompile`. If `config/database.yml` shows SQLite in production, confirm that the generated scaffold uses persistent `db` and `storage` volumes plus a release script that runs `rails db:prepare`; otherwise keep the default Postgres workload. If the public workload is not named `rails`, set `PRIMARY_WORKLOAD` or adjust the generated workflows. Inspect the Dockerfile and package sources for private GitHub dependencies or `RUN --mount=type=ssh`; if present, wire `DOCKER_BUILD_SSH_KEY`, optionally set `DOCKER_BUILD_SSH_KNOWN_HOSTS` for non-GitHub SSH hosts, and keep `DOCKER_BUILD_EXTRA_ARGS` to newline-delimited single tokens such as `--build-arg=FOO=bar`.
26
26
 
@@ -214,6 +214,56 @@ needs. They do not use `secrets: inherit`; the production token is supplied by
214
214
  the protected `production` Environment after approval, not forwarded from a
215
215
  repository secret.
216
216
 
217
+ ## First-Time Control Plane Bootstrap
218
+
219
+ GitHub settings only give the workflows permission to act. They do not create
220
+ the persistent staging or production GVCs for you on the first merge.
221
+
222
+ Before the first staging deploy, bootstrap the staging app once:
223
+
224
+ ```sh
225
+ cpflow setup-app -a my-app-staging --org my-org-staging --skip-post-creation-hook
226
+ ```
227
+
228
+ `setup-app` reads the `setup_app_templates` list from
229
+ `.controlplane/controlplane.yml`. It creates the persistent staging GVC,
230
+ workloads, app identity, app secret dictionary, app secret policy, and policy
231
+ binding that grants the app identity `reveal` permission on that dictionary.
232
+ Use `--skip-post-creation-hook` for first-time bootstrap so a database hook does
233
+ not try to run before the first image exists.
234
+
235
+ After the persistent app exists, use `apply-template` for later template
236
+ updates. Adjust the template list to match your repo, such as adding `worker`,
237
+ `sidekiq`, `renderer`, `redis`, or other templates present under
238
+ `.controlplane/templates`:
239
+
240
+ ```sh
241
+ cpflow apply-template app postgres rails -a my-app-staging --org my-org-staging --yes --add-app-identity
242
+ ```
243
+
244
+ If you use `apply-template` to create or repair an existing app, also confirm
245
+ that the app identity has `reveal` permission on the app secret policy. Without
246
+ that binding, workloads that reference `cpln://secret/<app-secrets>.*` stay
247
+ paused until the policy is fixed.
248
+
249
+ Before the first production promotion, run the same kind of bootstrap for the
250
+ production app in the production org:
251
+
252
+ ```sh
253
+ cpflow setup-app -a my-app-production --org my-org-production --skip-post-creation-hook
254
+ ```
255
+
256
+ Use production-only runtime secrets and values for the production app. The
257
+ protected GitHub Environment controls who can run the promotion workflow, but
258
+ the production app resources still need to exist before the first promotion.
259
+
260
+ Review apps are different: the generated `+review-app-deploy` workflow creates
261
+ temporary PR apps as needed, including the identity and secret policy binding.
262
+ You still need the shared review-app runtime secret values described by your
263
+ templates, and the staging token must have access to create and update
264
+ review-app GVCs, workloads, images, identities, policies, and secrets in the
265
+ staging org.
266
+
217
267
  ### Production Promotion Safety
218
268
 
219
269
  `CPLN_TOKEN_PRODUCTION` can change live production workloads, images, releases,
data/docs/commands.md CHANGED
@@ -503,7 +503,7 @@ cpflow run -a $APP_NAME --entrypoint /app/alternative-entrypoint.sh -- rails db:
503
503
 
504
504
  - Creates an app and all its workloads
505
505
  - Specify the templates for the app and workloads through `setup_app_templates` in the `.controlplane/controlplane.yml` file
506
- - This should only be used for temporary apps like review apps, never for persistent apps like production or staging (to update workloads for those, use 'cpflow apply-template' instead)
506
+ - Use this for temporary apps like review apps and for first-time bootstrap of persistent staging or production apps; after a persistent app exists, use 'cpflow apply-template' for template updates
507
507
  - Configures app to have org-level secrets with default name `"{APP_PREFIX}-secrets"`
508
508
  using org-level policy with default name `"{APP_PREFIX}-secrets-policy"` (names can be customized, see docs)
509
509
  - Creates identity for secrets if it does not exist
@@ -32,7 +32,7 @@ module Command
32
32
  <<~PROMPT
33
33
  Set up Control Plane GitHub Flow for this repo. Start with `cpflow github-flow-readiness` and stop on any reported blockers. The repo must be deployable from a clean clone: published package versions, complete runtime scaffold, and a production Dockerfile that can build the app. If any package version is unpublished, inaccessible from CI, or requires credentials that are not already modeled in the repo or GitHub settings, stop and report the blocker instead of generating workflow files. If the repo is a legacy sample pinned to an obsolete Ruby or Bundler toolchain, if it does not even have a production Dockerfile yet, or if it is a monorepo without an already-decided single app boundary for this flow, stop and report that as a prerequisite instead of forcing the rollout.
34
34
 
35
- If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default (`#{inferred_app_prefix}`) and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `+review-app-deploy`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. Do not hand-edit duplicated upstream refs into the generated wrappers: the only downstream Control Plane Flow pin should be the reusable workflow `uses: ...@vX.Y.Z` value generated from the installed `cpflow` gem version, and upstream workflows load their matching shared actions automatically. Keep the standard path simple: review apps require only `CPLN_TOKEN_STAGING` when the generated review app config can be inferred. For production promotion, document a protected `production` GitHub Environment with required reviewers, prevent self-review, and `CPLN_TOKEN_PRODUCTION` stored as an environment secret, not as a repository or organization secret.
35
+ If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default (`#{inferred_app_prefix}`) and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `+review-app-deploy`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. Do not hand-edit duplicated upstream refs into the generated wrappers: the only downstream Control Plane Flow pin should be the reusable workflow `uses: ...@vX.Y.Z` value generated from the installed `cpflow` gem version, and upstream workflows load their matching shared actions automatically. Keep the standard path simple: review apps require only `CPLN_TOKEN_STAGING` when the generated review app config can be inferred. Document the one-time Control Plane bootstrap command for persistent staging and production apps with `cpflow setup-app --skip-post-creation-hook`; for existing apps or later template updates, document `cpflow apply-template` and the need for the app identity to have `reveal` on the app secret policy. Do not imply the staging deploy or promotion workflows create those persistent GVCs. For production promotion, document a protected `production` GitHub Environment with required reviewers, prevent self-review, and `CPLN_TOKEN_PRODUCTION` stored as an environment secret, not as a repository or organization secret.
36
36
 
37
37
  Keep Node available in the final image if asset compilation or SSR depends on ExecJS, Yarn, `pnpm`, or npm after the main install layer. Make sure the generated Dockerfile uses a Ruby base image compatible with the app's declared Ruby requirement. Preserve repo-defined frontend build hooks: if `config/shakapacker.yml` defines a `precompile_hook`, or React on Rails enables `config.auto_load_bundle = true`, confirm the generated Dockerfile runs that codegen step before `rails assets:precompile`. If `config/database.yml` shows SQLite in production, confirm that the generated scaffold uses persistent `db` and `storage` volumes plus a release script that runs `rails db:prepare`; otherwise keep the default Postgres workload. If the public workload is not named `rails`, set `PRIMARY_WORKLOAD` or adjust the generated workflows. Inspect the Dockerfile and package sources for private GitHub dependencies or `RUN --mount=type=ssh`; if present, wire `DOCKER_BUILD_SSH_KEY`, optionally set `DOCKER_BUILD_SSH_KNOWN_HOSTS` for non-GitHub SSH hosts, and keep `DOCKER_BUILD_EXTRA_ARGS` to newline-delimited single tokens such as `--build-arg=FOO=bar`.
38
38
 
data/lib/command/run.rb CHANGED
@@ -197,7 +197,7 @@ module Command
197
197
  spec = nil
198
198
 
199
199
  step("Checking if runner workload '#{runner_workload}' needs to be updated") do # rubocop:disable Metrics/BlockLength
200
- _, original_container_spec = base_workload_specs(original_workload)
200
+ original_spec, original_container_spec = base_workload_specs(original_workload)
201
201
  spec, container_spec = base_workload_specs(runner_workload)
202
202
 
203
203
  # Keep ENV synced between original and runner workloads
@@ -208,6 +208,16 @@ module Command
208
208
  should_update = true
209
209
  end
210
210
 
211
+ # Keep the app identity in sync so runner jobs can resolve GVC-level secrets.
212
+ if spec["identityLink"] != original_spec["identityLink"]
213
+ if original_spec["identityLink"]
214
+ spec["identityLink"] = original_spec["identityLink"]
215
+ else
216
+ spec.delete("identityLink")
217
+ end
218
+ should_update = true
219
+ end
220
+
211
221
  if container_spec["image"] != default_image
212
222
  container_spec["image"] = default_image
213
223
  should_update = true
@@ -13,7 +13,7 @@ module Command
13
13
  LONG_DESCRIPTION = <<~DESC
14
14
  - Creates an app and all its workloads
15
15
  - Specify the templates for the app and workloads through `setup_app_templates` in the `.controlplane/controlplane.yml` file
16
- - This should only be used for temporary apps like review apps, never for persistent apps like production or staging (to update workloads for those, use 'cpflow apply-template' instead)
16
+ - Use this for temporary apps like review apps and for first-time bootstrap of persistent staging or production apps; after a persistent app exists, use 'cpflow apply-template' for template updates
17
17
  - Configures app to have org-level secrets with default name `"{APP_PREFIX}-secrets"`
18
18
  using org-level policy with default name `"{APP_PREFIX}-secrets-policy"` (names can be customized, see docs)
19
19
  - Creates identity for secrets if it does not exist
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cpflow
4
- VERSION = "5.0.1"
4
+ VERSION = "5.0.2"
5
5
  MIN_CPLN_VERSION = "3.1.0"
6
6
  end
@@ -17,12 +17,17 @@ WORKDIR /app
17
17
  # rely on ExecJS in production. Narrowed to just what the node stage actually
18
18
  # ships under /usr/local so we don't drag in unused Debian libs from that image.
19
19
  COPY --from=node /usr/local/bin/node /usr/local/bin/node
20
- COPY --from=node /usr/local/bin/npm /usr/local/bin/npm
21
- COPY --from=node /usr/local/bin/npx /usr/local/bin/npx
22
- COPY --from=node /usr/local/bin/corepack /usr/local/bin/corepack
23
20
  COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules
24
21
  COPY --from=node /usr/local/include/node /usr/local/include/node
25
22
 
23
+ RUN ln -sf ../lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \
24
+ ln -sf ../lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx && \
25
+ ln -sf ../lib/node_modules/corepack/dist/corepack.js /usr/local/bin/corepack && \
26
+ chmod +x /usr/local/lib/node_modules/npm/bin/npm-cli.js \
27
+ /usr/local/lib/node_modules/npm/bin/npx-cli.js \
28
+ /usr/local/lib/node_modules/corepack/dist/corepack.js && \
29
+ node --version && npm --version && corepack --version
30
+
26
31
  # Expose Corepack-managed shims so later build steps can call yarn/pnpm
27
32
  # directly during asset precompilation hooks.
28
33
  RUN printf '%s\n' '#!/bin/sh' 'exec corepack yarn "$@"' > /usr/bin/yarn && \
@@ -1,6 +1,6 @@
1
1
  # Template setup of the GVC, roughly corresponding to a Heroku app
2
2
  kind: gvc
3
- name: {{APP_NAME}}
3
+ name: "{{APP_NAME}}"
4
4
  spec:
5
5
  env:
6
6
  - name: DATABASE_URL
@@ -12,7 +12,7 @@ spec:
12
12
  - name: RAILS_SERVE_STATIC_FILES
13
13
  value: "true"
14
14
  - name: SECRET_KEY_BASE
15
- value: cpln://secret/{{APP_SECRETS}}.SECRET_KEY_BASE
15
+ value: "cpln://secret/{{APP_SECRETS}}.SECRET_KEY_BASE"
16
16
  staticPlacement:
17
17
  locationLinks:
18
- - {{APP_LOCATION_LINK}}
18
+ - "{{APP_LOCATION_LINK}}"
@@ -2,8 +2,8 @@
2
2
  # https://github.com/controlplane-com/examples/blob/main/examples/postgres/manifest.yaml
3
3
 
4
4
  kind: volumeset
5
- name: postgres-poc-vs
6
- description: postgres-poc-vs
5
+ name: "{{APP_NAME}}-pg-vs"
6
+ description: "{{APP_NAME}}-pg-vs"
7
7
  spec:
8
8
  autoscaling:
9
9
  maxCapacity: 1000
@@ -18,7 +18,7 @@ spec:
18
18
 
19
19
  ---
20
20
  kind: secret
21
- name: postgres-poc-credentials
21
+ name: "{{APP_NAME}}-pg"
22
22
  description: ''
23
23
  type: dictionary
24
24
  data:
@@ -27,7 +27,7 @@ data:
27
27
 
28
28
  ---
29
29
  kind: secret
30
- name: postgres-poc-entrypoint-script
30
+ name: "{{APP_NAME}}-pg-script"
31
31
  type: opaque
32
32
  data:
33
33
  encoding: base64
@@ -92,13 +92,13 @@ data:
92
92
 
93
93
  ---
94
94
  kind: identity
95
- name: postgres-poc-identity
96
- description: postgres-poc-identity
95
+ name: "{{APP_NAME}}-pg-identity"
96
+ description: "{{APP_NAME}}-pg-identity"
97
97
 
98
98
  ---
99
99
  kind: policy
100
- name: postgres-poc-access
101
- description: postgres-poc-access
100
+ name: "{{APP_NAME}}-pg-access"
101
+ description: "{{APP_NAME}}-pg-access"
102
102
  bindings:
103
103
  - permissions:
104
104
  - reveal
@@ -106,11 +106,14 @@ bindings:
106
106
  # - use
107
107
  # - view
108
108
  principalLinks:
109
- - //gvc/{{APP_NAME}}/identity/postgres-poc-identity
109
+ - "//gvc/{{APP_NAME}}/identity/{{APP_NAME}}-pg-identity"
110
+ # cpflow apply-template replaces {{APP_IDENTITY_LINK}} with the full app workload identity link.
111
+ # Example: //gvc/{{APP_NAME}}/identity/{{APP_NAME}}-identity.
112
+ - "{{APP_IDENTITY_LINK}}"
110
113
  targetKind: secret
111
114
  targetLinks:
112
- - //secret/postgres-poc-credentials
113
- - //secret/postgres-poc-entrypoint-script
115
+ - "//secret/{{APP_NAME}}-pg"
116
+ - "//secret/{{APP_NAME}}-pg-script"
114
117
 
115
118
  ---
116
119
  kind: workload
@@ -130,9 +133,9 @@ spec:
130
133
  - name: PGDATA #The location postgres stores the db. This can be anything other than /var/lib/postgresql/data, but it must be inside the mount point for the volume set
131
134
  value: "/var/lib/postgresql/data/pg_data"
132
135
  - name: POSTGRES_PASSWORD #The password for the default user
133
- value: cpln://secret/postgres-poc-credentials.password
136
+ value: "cpln://secret/{{APP_NAME}}-pg.password"
134
137
  - name: POSTGRES_USER #The name of the default user
135
- value: cpln://secret/postgres-poc-credentials.username
138
+ value: "cpln://secret/{{APP_NAME}}-pg.username"
136
139
  name: postgres
137
140
  image: postgres:15
138
141
  command: /bin/bash
@@ -146,10 +149,10 @@ spec:
146
149
  - number: 5432
147
150
  protocol: tcp
148
151
  volumes:
149
- - uri: cpln://volumeset/postgres-poc-vs
152
+ - uri: "cpln://volumeset/{{APP_NAME}}-pg-vs"
150
153
  path: "/var/lib/postgresql/data"
151
154
  # Make the ENV value for the entry script a file
152
- - uri: cpln://secret/postgres-poc-entrypoint-script
155
+ - uri: "cpln://secret/{{APP_NAME}}-pg-script"
153
156
  path: "/usr/local/bin/cpln-entrypoint.sh"
154
157
  inheritEnv: false
155
158
  livenessProbe:
@@ -160,7 +163,7 @@ spec:
160
163
  tcpSocket:
161
164
  port: 5432
162
165
  failureThreshold: 1
163
- identityLink: //identity/postgres-poc-identity
166
+ identityLink: "//identity/{{APP_NAME}}-pg-identity"
164
167
  defaultOptions:
165
168
  capacityAI: false
166
169
  autoscaling:
@@ -8,7 +8,7 @@ spec:
8
8
  - name: rails
9
9
  cpu: 300m
10
10
  inheritEnv: true
11
- image: {{APP_IMAGE_LINK}}
11
+ image: "{{APP_IMAGE_LINK}}"
12
12
  memory: 512Mi
13
13
  ports:
14
14
  - number: 3000
@@ -29,3 +29,5 @@ spec:
29
29
  - 0.0.0.0/0
30
30
  outboundAllowCIDR:
31
31
  - 0.0.0.0/0
32
+ # cpflow apply-template replaces {{APP_IDENTITY_LINK}} with the app workload identity link.
33
+ identityLink: "{{APP_IDENTITY_LINK}}"
@@ -1,5 +1,5 @@
1
1
  kind: gvc
2
- name: {{APP_NAME}}
2
+ name: "{{APP_NAME}}"
3
3
  spec:
4
4
  env:
5
5
  - name: RAILS_ENV
@@ -9,7 +9,7 @@ spec:
9
9
  - name: RAILS_SERVE_STATIC_FILES
10
10
  value: "true"
11
11
  - name: SECRET_KEY_BASE
12
- value: cpln://secret/{{APP_SECRETS}}.SECRET_KEY_BASE
12
+ value: "cpln://secret/{{APP_SECRETS}}.SECRET_KEY_BASE"
13
13
  staticPlacement:
14
14
  locationLinks:
15
- - {{APP_LOCATION_LINK}}
15
+ - "{{APP_LOCATION_LINK}}"
@@ -6,7 +6,7 @@ spec:
6
6
  - name: rails
7
7
  cpu: 300m
8
8
  inheritEnv: true
9
- image: {{APP_IMAGE_LINK}}
9
+ image: "{{APP_IMAGE_LINK}}"
10
10
  memory: 512Mi
11
11
  ports:
12
12
  - number: 3000
@@ -34,3 +34,5 @@ spec:
34
34
  - 0.0.0.0/0
35
35
  outboundAllowCIDR:
36
36
  - 0.0.0.0/0
37
+ # cpflow apply-template replaces {{APP_IDENTITY_LINK}} with the app workload identity link.
38
+ identityLink: "{{APP_IDENTITY_LINK}}"
@@ -39,6 +39,23 @@ Optional overrides exist for forks, clones, and unusual apps:
39
39
  ## Staging And Production
40
40
 
41
41
  Staging deploys use the same `CPLN_TOKEN_STAGING` secret plus `STAGING_APP_NAME`.
42
+ Before the first staging deploy, bootstrap the persistent staging app once:
43
+
44
+ ```sh
45
+ cpflow setup-app -a "$STAGING_APP_NAME" --org "$CPLN_ORG_STAGING" --skip-post-creation-hook
46
+ ```
47
+
48
+ `setup-app` reads `.controlplane/controlplane.yml`'s `setup_app_templates` and
49
+ creates the app identity, app secret dictionary, app secret policy, policy
50
+ binding, and template resources. Use `--skip-post-creation-hook` so first-time
51
+ bootstrap does not try to run database setup before an image exists. For later
52
+ template updates on an existing persistent app, use `cpflow apply-template`
53
+ with the same template list and make sure the app identity has `reveal`
54
+ permission on the app secret policy.
55
+
56
+ Review apps are temporary and are created by the `+review-app-deploy` workflow,
57
+ but staging and production are persistent apps and should be bootstrapped
58
+ explicitly.
42
59
 
43
60
  Production promotion is part of the generated flow, but keep it protected:
44
61
 
@@ -53,6 +70,9 @@ prevent self-review. The generated promotion wrapper passes only the staging
53
70
  token from repository secrets; GitHub injects `CPLN_TOKEN_PRODUCTION` only after
54
71
  the environment approval gate passes.
55
72
 
73
+ Before the first promotion, bootstrap the production app the same way in the
74
+ production org, using production-only secrets and values.
75
+
56
76
  ## Version Locking
57
77
 
58
78
  Generated wrappers pin Control Plane Flow once with the reusable workflow
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cpflow
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.1
4
+ version: 5.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Gordon