@caelo-cms/provisioning 0.10.55 → 0.10.58

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.
Files changed (221) hide show
  1. package/dist/agent-db.js +97 -24
  2. package/dist/cli-routing.js +1 -1
  3. package/dist/cli-routing.js.map +1 -1
  4. package/dist/cli.js +4 -1
  5. package/dist/cli.js.map +1 -1
  6. package/dist/compose.js +5 -0
  7. package/dist/compose.js.map +1 -1
  8. package/dist/converge-checkpoint.d.ts +66 -0
  9. package/dist/converge-checkpoint.d.ts.map +1 -0
  10. package/dist/converge-checkpoint.js +61 -0
  11. package/dist/converge-checkpoint.js.map +1 -0
  12. package/dist/converge-job-gcp.d.ts +46 -0
  13. package/dist/converge-job-gcp.d.ts.map +1 -0
  14. package/dist/converge-job-gcp.js +368 -0
  15. package/dist/converge-job-gcp.js.map +1 -0
  16. package/dist/converge-job-setup.d.ts +62 -0
  17. package/dist/converge-job-setup.d.ts.map +1 -0
  18. package/dist/converge-job-setup.js +228 -0
  19. package/dist/converge-job-setup.js.map +1 -0
  20. package/dist/converge-job.d.ts +141 -0
  21. package/dist/converge-job.d.ts.map +1 -0
  22. package/dist/converge-job.js +325 -0
  23. package/dist/converge-job.js.map +1 -0
  24. package/dist/gcp-names.d.ts +9 -0
  25. package/dist/gcp-names.d.ts.map +1 -1
  26. package/dist/gcp-names.js +13 -0
  27. package/dist/gcp-names.js.map +1 -1
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +2 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/infra-contract.d.ts +1 -1
  33. package/dist/infra-contract.d.ts.map +1 -1
  34. package/dist/infra-contract.js +33 -1
  35. package/dist/infra-contract.js.map +1 -1
  36. package/dist/install-job.d.ts +11 -3
  37. package/dist/install-job.d.ts.map +1 -1
  38. package/dist/install-job.js +22 -12
  39. package/dist/install-job.js.map +1 -1
  40. package/dist/lifecycle.d.ts +13 -1
  41. package/dist/lifecycle.d.ts.map +1 -1
  42. package/dist/lifecycle.js +115 -58
  43. package/dist/lifecycle.js.map +1 -1
  44. package/dist/operator-access.d.ts +4 -0
  45. package/dist/operator-access.d.ts.map +1 -1
  46. package/dist/operator-access.js +43 -7
  47. package/dist/operator-access.js.map +1 -1
  48. package/dist/release-contract.d.ts +3 -2
  49. package/dist/release-contract.d.ts.map +1 -1
  50. package/dist/release-contract.js +5 -2
  51. package/dist/release-contract.js.map +1 -1
  52. package/dist/release-manifest.d.ts +2 -0
  53. package/dist/release-manifest.d.ts.map +1 -1
  54. package/dist/release-manifest.js.map +1 -1
  55. package/dist/remote-mcp-edge.d.ts +114 -0
  56. package/dist/remote-mcp-edge.d.ts.map +1 -0
  57. package/dist/remote-mcp-edge.js +116 -0
  58. package/dist/remote-mcp-edge.js.map +1 -0
  59. package/dist/remote-mcp.d.ts +139 -0
  60. package/dist/remote-mcp.d.ts.map +1 -0
  61. package/dist/remote-mcp.js +434 -0
  62. package/dist/remote-mcp.js.map +1 -0
  63. package/dist/runtime-secrets.d.ts +12 -0
  64. package/dist/runtime-secrets.d.ts.map +1 -1
  65. package/dist/runtime-secrets.js +32 -4
  66. package/dist/runtime-secrets.js.map +1 -1
  67. package/dist/seal-key-rotation.d.ts +38 -0
  68. package/dist/seal-key-rotation.d.ts.map +1 -0
  69. package/dist/seal-key-rotation.js +206 -0
  70. package/dist/seal-key-rotation.js.map +1 -0
  71. package/dist/stack-contract.d.ts +206 -3
  72. package/dist/stack-contract.d.ts.map +1 -1
  73. package/dist/stack-contract.js +219 -4
  74. package/dist/stack-contract.js.map +1 -1
  75. package/dist/stack-converge.d.ts +53 -1
  76. package/dist/stack-converge.d.ts.map +1 -1
  77. package/dist/stack-converge.js +124 -4
  78. package/dist/stack-converge.js.map +1 -1
  79. package/dist/state-lock-lease.d.ts +142 -0
  80. package/dist/state-lock-lease.d.ts.map +1 -0
  81. package/dist/state-lock-lease.js +347 -0
  82. package/dist/state-lock-lease.js.map +1 -0
  83. package/dist/state-store.d.ts +66 -9
  84. package/dist/state-store.d.ts.map +1 -1
  85. package/dist/state-store.js +249 -30
  86. package/dist/state-store.js.map +1 -1
  87. package/dist/upgrade/app-roll.d.ts +36 -7
  88. package/dist/upgrade/app-roll.d.ts.map +1 -1
  89. package/dist/upgrade/app-roll.js +53 -19
  90. package/dist/upgrade/app-roll.js.map +1 -1
  91. package/dist/upgrade/audit-job-roll.d.ts.map +1 -1
  92. package/dist/upgrade/audit-job-roll.js +3 -1
  93. package/dist/upgrade/audit-job-roll.js.map +1 -1
  94. package/dist/upgrade/converge.d.ts.map +1 -1
  95. package/dist/upgrade/converge.js +125 -12
  96. package/dist/upgrade/converge.js.map +1 -1
  97. package/dist/upgrade/gcp-lookup.d.ts +27 -10
  98. package/dist/upgrade/gcp-lookup.d.ts.map +1 -1
  99. package/dist/upgrade/gcp-lookup.js +46 -7
  100. package/dist/upgrade/gcp-lookup.js.map +1 -1
  101. package/dist/upgrade/record-rolled.d.ts +40 -0
  102. package/dist/upgrade/record-rolled.d.ts.map +1 -0
  103. package/dist/upgrade/record-rolled.js +46 -0
  104. package/dist/upgrade/record-rolled.js.map +1 -0
  105. package/dist/upgrade/upgrade.d.ts +45 -1
  106. package/dist/upgrade/upgrade.d.ts.map +1 -1
  107. package/dist/upgrade/upgrade.js +60 -17
  108. package/dist/upgrade/upgrade.js.map +1 -1
  109. package/dist/upgrader-assess.d.ts +15 -1
  110. package/dist/upgrader-assess.d.ts.map +1 -1
  111. package/dist/upgrader-assess.js +36 -6
  112. package/dist/upgrader-assess.js.map +1 -1
  113. package/dist/upgrader-gcp.d.ts +15 -0
  114. package/dist/upgrader-gcp.d.ts.map +1 -1
  115. package/dist/upgrader-gcp.js +42 -7
  116. package/dist/upgrader-gcp.js.map +1 -1
  117. package/dist/upgrader-iam-preflight.d.ts +123 -0
  118. package/dist/upgrader-iam-preflight.d.ts.map +1 -0
  119. package/dist/upgrader-iam-preflight.js +414 -0
  120. package/dist/upgrader-iam-preflight.js.map +1 -0
  121. package/dist/upgrader-job.d.ts +33 -9
  122. package/dist/upgrader-job.d.ts.map +1 -1
  123. package/dist/upgrader-job.js +169 -27
  124. package/dist/upgrader-job.js.map +1 -1
  125. package/dist/upgrader-records.d.ts +58 -0
  126. package/dist/upgrader-records.d.ts.map +1 -0
  127. package/dist/upgrader-records.js +87 -0
  128. package/dist/upgrader-records.js.map +1 -0
  129. package/dist/upgrader-reporter.d.ts +3 -2
  130. package/dist/upgrader-reporter.d.ts.map +1 -1
  131. package/dist/upgrader-reporter.js +10 -2
  132. package/dist/upgrader-reporter.js.map +1 -1
  133. package/dist/upgrader-setup.d.ts +25 -3
  134. package/dist/upgrader-setup.d.ts.map +1 -1
  135. package/dist/upgrader-setup.js +123 -11
  136. package/dist/upgrader-setup.js.map +1 -1
  137. package/dist/wizards/gcp-cost.d.ts.map +1 -1
  138. package/dist/wizards/gcp-cost.js +11 -3
  139. package/dist/wizards/gcp-cost.js.map +1 -1
  140. package/dist/wizards/gcp-pulumi.d.ts +6 -0
  141. package/dist/wizards/gcp-pulumi.d.ts.map +1 -1
  142. package/dist/wizards/gcp-pulumi.js +14 -2
  143. package/dist/wizards/gcp-pulumi.js.map +1 -1
  144. package/dist/wizards/gcp.d.ts.map +1 -1
  145. package/dist/wizards/gcp.js +106 -4
  146. package/dist/wizards/gcp.js.map +1 -1
  147. package/package.json +2 -2
  148. package/src/agent/run.test.ts +14 -1
  149. package/src/audit-job-setup.test.ts +7 -1
  150. package/src/cli-routing.ts +1 -1
  151. package/src/cli.ts +4 -1
  152. package/src/compose.ts +5 -0
  153. package/src/converge-checkpoint.ts +75 -0
  154. package/src/converge-entrypoint.test.ts +213 -0
  155. package/src/converge-job-gcp.test.ts +222 -0
  156. package/src/converge-job-gcp.ts +443 -0
  157. package/src/converge-job-setup.test.ts +152 -0
  158. package/src/converge-job-setup.ts +268 -0
  159. package/src/converge-job.test.ts +486 -0
  160. package/src/converge-job.ts +542 -0
  161. package/src/gateway-env-isolation.test.ts +8 -1
  162. package/src/gcp-names.ts +15 -0
  163. package/src/gcp-url-map.test.ts +9 -1
  164. package/src/index.ts +8 -0
  165. package/src/infra-contract.test.ts +8 -4
  166. package/src/infra-contract.ts +33 -1
  167. package/src/install-job.test.ts +3 -1
  168. package/src/install-job.ts +31 -14
  169. package/src/lifecycle.ts +137 -71
  170. package/src/operator-access.test.ts +24 -1
  171. package/src/operator-access.ts +44 -6
  172. package/src/release-contract.ts +5 -2
  173. package/src/release-manifest.test.ts +42 -0
  174. package/src/release-manifest.ts +2 -0
  175. package/src/remote-mcp-edge.ts +137 -0
  176. package/src/remote-mcp.test.ts +690 -0
  177. package/src/remote-mcp.ts +524 -0
  178. package/src/runtime-secrets.test.ts +31 -6
  179. package/src/runtime-secrets.ts +41 -3
  180. package/src/seal-key-rotation.test.ts +131 -0
  181. package/src/seal-key-rotation.ts +258 -0
  182. package/src/stack-contract-parity.test.ts +20 -3
  183. package/src/stack-contract.test.ts +32 -2
  184. package/src/stack-contract.ts +363 -4
  185. package/src/stack-converge-secrets.test.ts +4 -0
  186. package/src/stack-converge.test.ts +21 -5
  187. package/src/stack-converge.ts +162 -7
  188. package/src/state-attach.test.ts +7 -1
  189. package/src/state-lock-lease.test.ts +302 -0
  190. package/src/state-lock-lease.ts +423 -0
  191. package/src/state-lock.test.ts +568 -0
  192. package/src/state-store.ts +347 -27
  193. package/src/upgrade/app-roll.ts +102 -21
  194. package/src/upgrade/audit-job-roll.ts +3 -1
  195. package/src/upgrade/converge.ts +148 -10
  196. package/src/upgrade/gcp-lookup.test.ts +80 -0
  197. package/src/upgrade/gcp-lookup.ts +65 -8
  198. package/src/upgrade/record-rolled.test.ts +105 -0
  199. package/src/upgrade/record-rolled.ts +91 -0
  200. package/src/upgrade/upgrade.test.ts +203 -3
  201. package/src/upgrade/upgrade.ts +120 -24
  202. package/src/upgrader-assess.test.ts +92 -3
  203. package/src/upgrader-assess.ts +58 -9
  204. package/src/upgrader-gcp.ts +47 -8
  205. package/src/upgrader-iam-preflight.test.ts +393 -0
  206. package/src/upgrader-iam-preflight.ts +510 -0
  207. package/src/upgrader-job.test.ts +586 -15
  208. package/src/upgrader-job.ts +237 -53
  209. package/src/upgrader-records.ts +151 -0
  210. package/src/upgrader-reporter.test.ts +6 -0
  211. package/src/upgrader-reporter.ts +7 -2
  212. package/src/upgrader-setup.test.ts +3 -3
  213. package/src/upgrader-setup.ts +128 -11
  214. package/src/wizards/gcp-cost.ts +12 -3
  215. package/src/wizards/gcp-pulumi.test.ts +15 -0
  216. package/src/wizards/gcp-pulumi.ts +18 -2
  217. package/src/wizards/gcp.ts +134 -4
  218. package/stacks/aws/index.ts +10 -0
  219. package/stacks/azure/index.ts +9 -0
  220. package/stacks/gcp/index.ts +47 -7
  221. package/stacks/gcp-firebase/index.ts +38 -6
@@ -0,0 +1,123 @@
1
+ import type { HttpFetch } from "./runtime-secrets.js";
2
+ /** A resource IAM can be asked about. */
3
+ export type IamResource = {
4
+ readonly kind: "project";
5
+ readonly projectId: string;
6
+ } | {
7
+ readonly kind: "service-account";
8
+ readonly projectId: string;
9
+ readonly email: string;
10
+ } | {
11
+ readonly kind: "run-job";
12
+ readonly projectId: string;
13
+ readonly region: string;
14
+ readonly name: string;
15
+ } | {
16
+ readonly kind: "bucket";
17
+ readonly bucket: string;
18
+ }
19
+ /** Objects under `prefix/` in `bucket`, behind a name-conditioned grant (probed). */
20
+ | {
21
+ readonly kind: "bucket-objects";
22
+ readonly bucket: string;
23
+ readonly prefix: string;
24
+ } | {
25
+ readonly kind: "artifact-repository";
26
+ readonly projectId: string;
27
+ readonly location: string;
28
+ readonly repository: string;
29
+ };
30
+ /** One thing the run will do, the permissions it takes, and where. */
31
+ export interface AccessCheck {
32
+ /** What the upgrader could not do without them, in plain words. */
33
+ readonly need: string;
34
+ readonly resource: IamResource;
35
+ readonly permissions: readonly string[];
36
+ }
37
+ /** A check with the permissions it lacks. */
38
+ export interface MissingAccess {
39
+ readonly check: AccessCheck;
40
+ readonly missing: readonly string[];
41
+ /**
42
+ * Permissions that could not be judged because another one is missing
43
+ * first (storage.objects.get needs storage.objects.list to be testable).
44
+ */
45
+ readonly unchecked?: readonly string[];
46
+ }
47
+ /** The permissions IAM confirmed on one resource, or why it could not be asked. */
48
+ export type GrantedResult = {
49
+ readonly ok: true;
50
+ readonly granted: readonly string[];
51
+ } | {
52
+ readonly ok: false;
53
+ readonly error: string;
54
+ };
55
+ /** Asks IAM which of `permissions` the job's identity holds on `resource`. */
56
+ export interface IamTester {
57
+ granted(resource: IamResource, permissions: readonly string[]): Promise<GrantedResult>;
58
+ }
59
+ /** How the self-check came out. */
60
+ export type PreflightOutcome = {
61
+ readonly kind: "ok";
62
+ } | {
63
+ readonly kind: "missing";
64
+ readonly missing: readonly MissingAccess[];
65
+ }
66
+ /** IAM could not be asked about at least one resource; nothing was judged missing. */
67
+ | {
68
+ readonly kind: "error";
69
+ readonly errors: readonly string[];
70
+ };
71
+ /** The object the `install/` probes name. It is never written: every probe fails its precondition. */
72
+ export declare const PREFLIGHT_PROBE_OBJECT = ".caelo-iam-preflight";
73
+ /**
74
+ * Every permission an upgrader run needs after its decision, grouped by
75
+ * what it is for (upgrade/app-roll.ts, migration-runner.ts, backup.ts,
76
+ * health.ts, state-store.ts, the self-update in upgrader-job.ts). Keep in
77
+ * step with the grants in upgrader-setup.ts: a permission listed here that
78
+ * setup does not grant stops every update.
79
+ */
80
+ export declare function upgraderAccessChecks(target: {
81
+ readonly projectId: string;
82
+ readonly region: string;
83
+ readonly env: string;
84
+ }): AccessCheck[];
85
+ /** Ask IAM about every check (one call per resource); never throws. */
86
+ export declare function runIamPreflight(checks: readonly AccessCheck[], tester: IamTester): Promise<PreflightOutcome>;
87
+ /**
88
+ * The request's end reason for missing permissions: every one of them, each
89
+ * with what it is for, then the one next step.
90
+ */
91
+ export declare function preflightMissingReason(missing: readonly MissingAccess[]): string;
92
+ /** The request's end reason when IAM could not be asked. */
93
+ export declare function preflightErrorReason(errors: readonly string[]): string;
94
+ /** A resource's full name, as IAM and the messages name it. */
95
+ export declare function resourceName(r: IamResource): string;
96
+ /**
97
+ * The real {@link IamTester}: Google's REST APIs with the job's own access
98
+ * token. `token` is asked once per call (gcloud caches it).
99
+ *
100
+ * @example
101
+ * const tester = restIamTester({ http: fetch, token: async () => "<access token>" });
102
+ * await tester.granted({ kind: "project", projectId: "acme" }, ["run.services.get"]);
103
+ */
104
+ export declare function restIamTester(deps: {
105
+ readonly http: HttpFetch;
106
+ readonly token: () => Promise<string>;
107
+ }): IamTester;
108
+ /** The testIamPermissions request for a resource that has one. */
109
+ export declare function testIamCall(resource: Exclude<IamResource, {
110
+ kind: "bucket-objects";
111
+ }>, permissions: readonly string[]): {
112
+ url: string;
113
+ method: "GET" | "POST";
114
+ body?: string;
115
+ };
116
+ /** The precondition-guarded request that tests one object permission (see the file comment). */
117
+ export declare function objectProbeCall(resource: Extract<IamResource, {
118
+ kind: "bucket-objects";
119
+ }>, permission: string): {
120
+ url: string;
121
+ method: "GET" | "POST" | "DELETE";
122
+ } | null;
123
+ //# sourceMappingURL=upgrader-iam-preflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrader-iam-preflight.d.ts","sourceRoot":"","sources":["../src/upgrader-iam-preflight.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,414 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * The upgrader job's IAM self-check (#818): before it takes the state lock
4
+ * or changes anything, the job asks Google Cloud whether its own service
5
+ * account holds every permission the run will need, and stops with ALL the
6
+ * missing ones named when it does not.
7
+ *
8
+ * Why: the first live in-app update died at its first bucket write (#799)
9
+ * because a grant that looked right could never match the call. Unit tests
10
+ * against a fake gcloud cannot catch that class of bug; asking IAM can, and
11
+ * asking first means a missing grant ends the run before the backup, the
12
+ * migrations or the roll, with a reason a non-technical Owner can pass on
13
+ * ("Run the upgrade once with Cloud Shell" re-converges the grants).
14
+ *
15
+ * How each permission is checked, without doing the action:
16
+ *
17
+ * - `testIamPermissions` on the resource the call acts on — the project,
18
+ * a service account, the upgrader's own job, the ops bucket, the release
19
+ * image repository. Google returns the subset the CALLER holds; no
20
+ * permission is needed to ask.
21
+ * - The `install/` objects in the ops bucket are the exception. The
22
+ * upgrader's object rights there are an IAM grant CONDITIONED on the
23
+ * object name (upgrader-setup.ts `installStateCondition`), and a bucket's
24
+ * testIamPermissions evaluates conditions against the bucket's own
25
+ * resource name, never an object's — it would report a grant that works
26
+ * as missing (the mirror image of #799). Cloud Storage has no object
27
+ * testIamPermissions on uniform-access buckets, so those three are
28
+ * probed with requests that can never change anything: a read of an
29
+ * object that does not exist, and an upload + a delete preconditioned
30
+ * on generation 1, which no object ever has. Cloud Storage authorizes a
31
+ * request before it evaluates its preconditions, so 403 means the
32
+ * permission is missing and 404/412 means it is held — with one
33
+ * exception: a read of an absent object is answered 403 whenever the
34
+ * caller lacks storage.objects.list, so objects.get is probed only once
35
+ * the bucket check confirmed list, and reported "unchecked" otherwise.
36
+ *
37
+ * Direct VPC egress (#818): the migration job and both services are
38
+ * deployed with `--network/--subnet`. Google documents the compute
39
+ * permissions for that (`compute.subnetworks.use`, …) on the Cloud Run
40
+ * SERVICE AGENT (roles/run.serviceAgent has them), not on the principal
41
+ * that deploys, so they are not checked here and the upgrader gets no
42
+ * compute role (UPGRADER_FORBIDDEN_ROLES). The real-GCP upgrader smoke test
43
+ * (.github/workflows/upgrader-smoke.yml) is where that shows on real GCP:
44
+ * each stable release, installed on the smoke install through Settings →
45
+ * Updates, must serve cleanly before the next tag ships.
46
+ *
47
+ * Everything here is pure except {@link restIamTester}, which takes its
48
+ * HTTP client and token source as arguments.
49
+ */
50
+ import { z } from "zod";
51
+ import { auditServiceAccountEmail, gatewayServiceAccountEmail, mcpIapServiceAccountEmail, runServiceAccountEmail, upgraderJobName, upgraderServiceAccountEmail, } from "./gcp-names.js";
52
+ import { OPS_INSTALL_PREFIX, opsBucketName } from "./state-backend.js";
53
+ import { RELEASE_REGISTRY } from "./upgrade/release-images.js";
54
+ /** The object the `install/` probes name. It is never written: every probe fails its precondition. */
55
+ export const PREFLIGHT_PROBE_OBJECT = ".caelo-iam-preflight";
56
+ /**
57
+ * Every permission an upgrader run needs after its decision, grouped by
58
+ * what it is for (upgrade/app-roll.ts, migration-runner.ts, backup.ts,
59
+ * health.ts, state-store.ts, the self-update in upgrader-job.ts). Keep in
60
+ * step with the grants in upgrader-setup.ts: a permission listed here that
61
+ * setup does not grant stops every update.
62
+ */
63
+ export function upgraderAccessChecks(target) {
64
+ const { projectId, region, env } = target;
65
+ const project = { kind: "project", projectId };
66
+ const sa = (email) => ({ kind: "service-account", projectId, email });
67
+ const bucket = opsBucketName(projectId);
68
+ return [
69
+ {
70
+ need: "read which release the site's admin and gateway serve",
71
+ resource: project,
72
+ permissions: [
73
+ "run.services.get",
74
+ "run.services.list",
75
+ "run.revisions.get",
76
+ "run.revisions.list",
77
+ ],
78
+ },
79
+ {
80
+ need: "deploy the new release to the admin and gateway and move their traffic",
81
+ resource: project,
82
+ permissions: ["run.services.update", "run.operations.get"],
83
+ },
84
+ {
85
+ need: "run the database migrations as a one-off job (and check whether an earlier run still holds the install's lock)",
86
+ resource: project,
87
+ permissions: [
88
+ "run.jobs.create",
89
+ "run.jobs.delete",
90
+ "run.jobs.get",
91
+ "run.jobs.run",
92
+ "run.executions.get",
93
+ ],
94
+ },
95
+ {
96
+ need: "back up the database before anything changes",
97
+ resource: project,
98
+ permissions: [
99
+ "cloudsql.backupRuns.create",
100
+ "cloudsql.backupRuns.get",
101
+ "cloudsql.backupRuns.list",
102
+ "cloudsql.instances.get",
103
+ "cloudsql.instances.list",
104
+ ],
105
+ },
106
+ {
107
+ need: "run the admin and the migration job as the admin's service account",
108
+ resource: sa(runServiceAccountEmail(projectId, env)),
109
+ permissions: ["iam.serviceAccounts.actAs"],
110
+ },
111
+ {
112
+ need: "run the gateway as its service account",
113
+ resource: sa(gatewayServiceAccountEmail(projectId, env)),
114
+ permissions: ["iam.serviceAccounts.actAs"],
115
+ },
116
+ {
117
+ // #875 — every app-roll moves the audit job onto the new admin image
118
+ // (upgrade/audit-job-roll.ts), and upgrader-setup.ts grants actAs on
119
+ // the job's account for exactly that.
120
+ need: "move the quality-audit job onto the new admin image",
121
+ resource: project,
122
+ permissions: ["run.jobs.update"],
123
+ },
124
+ {
125
+ need: "run the quality-audit job as its service account after moving it",
126
+ resource: sa(auditServiceAccountEmail(projectId, env)),
127
+ permissions: ["iam.serviceAccounts.actAs"],
128
+ },
129
+ {
130
+ need: "keep the upgrader job running as its own service account after it updates itself",
131
+ resource: sa(upgraderServiceAccountEmail(projectId, env)),
132
+ permissions: ["iam.serviceAccounts.actAs"],
133
+ },
134
+ {
135
+ need: "sign in to the admin (through its identity proxy) for the health check",
136
+ resource: sa(mcpIapServiceAccountEmail(projectId)),
137
+ permissions: ["iam.serviceAccounts.signJwt"],
138
+ },
139
+ {
140
+ need: "move the upgrader itself onto the new release",
141
+ resource: { kind: "run-job", projectId, region, name: upgraderJobName(env) },
142
+ permissions: ["run.jobs.get", "run.jobs.update"],
143
+ },
144
+ {
145
+ need: "list the install's ops bucket (every write there lists it first)",
146
+ resource: { kind: "bucket", bucket },
147
+ permissions: ["storage.objects.list"],
148
+ },
149
+ {
150
+ need: `read and write the install's records and its state lock (${OPS_INSTALL_PREFIX}/ in the ops bucket)`,
151
+ resource: { kind: "bucket-objects", bucket, prefix: OPS_INSTALL_PREFIX },
152
+ permissions: ["storage.objects.get", "storage.objects.create", "storage.objects.delete"],
153
+ },
154
+ {
155
+ need: "read Caelo's release images",
156
+ resource: {
157
+ kind: "artifact-repository",
158
+ projectId: RELEASE_REGISTRY.project,
159
+ location: RELEASE_REGISTRY.region,
160
+ repository: RELEASE_REGISTRY.repo,
161
+ },
162
+ permissions: ["artifactregistry.repositories.downloadArtifacts"],
163
+ },
164
+ ];
165
+ }
166
+ /** Ask IAM about every check (one call per resource); never throws. */
167
+ export async function runIamPreflight(checks, tester) {
168
+ // One question per resource: the project alone carries four checks.
169
+ const byResource = new Map();
170
+ for (const c of checks) {
171
+ const key = resourceName(c.resource);
172
+ const entry = byResource.get(key) ?? { resource: c.resource, permissions: new Set() };
173
+ for (const p of c.permissions)
174
+ entry.permissions.add(p);
175
+ byResource.set(key, entry);
176
+ }
177
+ const granted = new Map();
178
+ /** Permissions that could not be judged (see the object probes below). */
179
+ const unverified = new Map();
180
+ const errors = [];
181
+ const ask = async (key, resource, permissions) => {
182
+ let r;
183
+ try {
184
+ r = await tester.granted(resource, [...permissions].sort());
185
+ }
186
+ catch (e) {
187
+ r = { ok: false, error: e instanceof Error ? e.message : String(e) };
188
+ }
189
+ if (r.ok)
190
+ granted.set(key, new Set(r.granted));
191
+ else
192
+ errors.push(`${key}: ${r.error}`);
193
+ };
194
+ const entries = [...byResource];
195
+ await Promise.all(entries
196
+ .filter(([, e]) => e.resource.kind !== "bucket-objects")
197
+ .map(([key, e]) => ask(key, e.resource, [...e.permissions])));
198
+ // The object probes go second: Cloud Storage answers a read of an absent
199
+ // object with 403 — not 404 — when the caller lacks storage.objects.list
200
+ // on the bucket, so the objects.get probe means something only once list
201
+ // is confirmed. Without it, get is reported as unchecked, never missing.
202
+ await Promise.all(entries
203
+ .filter(([, e]) => e.resource.kind === "bucket-objects")
204
+ .map(([key, e]) => {
205
+ const r = e.resource;
206
+ const listHeld = granted.get(resourceName({ kind: "bucket", bucket: r.bucket }))?.has(OBJECT_LIST) ??
207
+ false;
208
+ const asked = [...e.permissions].filter((p) => listHeld || p !== OBJECT_GET);
209
+ if (asked.length < e.permissions.size)
210
+ unverified.set(key, new Set([OBJECT_GET]));
211
+ return ask(key, e.resource, asked);
212
+ }));
213
+ if (errors.length > 0)
214
+ return { kind: "error", errors: errors.sort() };
215
+ const missing = [];
216
+ for (const check of checks) {
217
+ const key = resourceName(check.resource);
218
+ const held = granted.get(key) ?? new Set();
219
+ const unknown = unverified.get(key) ?? new Set();
220
+ const lacking = check.permissions.filter((p) => !held.has(p) && !unknown.has(p));
221
+ const unchecked = check.permissions.filter((p) => unknown.has(p));
222
+ if (lacking.length > 0 || unchecked.length > 0) {
223
+ missing.push({ check, missing: lacking, ...(unchecked.length > 0 ? { unchecked } : {}) });
224
+ }
225
+ }
226
+ return missing.length === 0 ? { kind: "ok" } : { kind: "missing", missing };
227
+ }
228
+ const OBJECT_LIST = "storage.objects.list";
229
+ const OBJECT_GET = "storage.objects.get";
230
+ /**
231
+ * The request's end reason for missing permissions: every one of them, each
232
+ * with what it is for, then the one next step.
233
+ */
234
+ export function preflightMissingReason(missing) {
235
+ const lines = missing.map((m) => {
236
+ const where = resourceName(m.check.resource);
237
+ const parts = [
238
+ ...(m.missing.length > 0 ? [`missing ${m.missing.join(", ")} on ${where}`] : []),
239
+ ...(m.unchecked && m.unchecked.length > 0
240
+ ? [
241
+ `${m.unchecked.join(", ")} on ${where} could not be checked: without storage.objects.list Cloud Storage answers 403 for any absent object, held or not`,
242
+ ]
243
+ : []),
244
+ ];
245
+ return `it ${m.missing.length > 0 ? "cannot" : "may not be able to"} ${m.check.need} (${parts.join("; ")})`;
246
+ });
247
+ return `Nothing was changed: the upgrader checked its access before starting and is missing permissions this update needs — ${lines.join("; ")}. Run the upgrade once with Cloud Shell; it repairs the upgrader's access.`;
248
+ }
249
+ /** The request's end reason when IAM could not be asked. */
250
+ export function preflightErrorReason(errors) {
251
+ return `Nothing was changed: the upgrader could not check its access before starting (${errors.join("; ")}). Try again in a few minutes; if it keeps failing, run the upgrade once with Cloud Shell.`;
252
+ }
253
+ /** A resource's full name, as IAM and the messages name it. */
254
+ export function resourceName(r) {
255
+ switch (r.kind) {
256
+ case "project":
257
+ return `projects/${r.projectId}`;
258
+ case "service-account":
259
+ return `projects/${r.projectId}/serviceAccounts/${r.email}`;
260
+ case "run-job":
261
+ return `projects/${r.projectId}/locations/${r.region}/jobs/${r.name}`;
262
+ case "bucket":
263
+ return `gs://${r.bucket}`;
264
+ case "bucket-objects":
265
+ return `gs://${r.bucket}/${r.prefix}/`;
266
+ case "artifact-repository":
267
+ return `projects/${r.projectId}/locations/${r.location}/repositories/${r.repository}`;
268
+ }
269
+ }
270
+ const testIamResponse = z.object({ permissions: z.array(z.string()).optional() });
271
+ /**
272
+ * The real {@link IamTester}: Google's REST APIs with the job's own access
273
+ * token. `token` is asked once per call (gcloud caches it).
274
+ *
275
+ * @example
276
+ * const tester = restIamTester({ http: fetch, token: async () => "<access token>" });
277
+ * await tester.granted({ kind: "project", projectId: "acme" }, ["run.services.get"]);
278
+ */
279
+ export function restIamTester(deps) {
280
+ return {
281
+ async granted(resource, permissions) {
282
+ const bearer = await deps.token();
283
+ if (!bearer)
284
+ return { ok: false, error: "no access token for the upgrader's account" };
285
+ const auth = { Authorization: `Bearer ${bearer}` };
286
+ if (resource.kind === "bucket-objects") {
287
+ return probeObjects(deps.http, auth, resource, permissions);
288
+ }
289
+ const call = testIamCall(resource, permissions);
290
+ const res = await deps.http(call.url, {
291
+ method: call.method,
292
+ headers: { ...auth, ...(call.body ? { "Content-Type": "application/json" } : {}) },
293
+ ...(call.body ? { body: call.body } : {}),
294
+ });
295
+ const text = await res.text();
296
+ if (!res.ok)
297
+ return { ok: false, error: `HTTP ${res.status} ${text.trim().slice(0, 300)}` };
298
+ let raw;
299
+ try {
300
+ raw = JSON.parse(text);
301
+ }
302
+ catch {
303
+ return { ok: false, error: "testIamPermissions answered without JSON" };
304
+ }
305
+ const parsed = testIamResponse.safeParse(raw);
306
+ if (!parsed.success) {
307
+ return { ok: false, error: "testIamPermissions answered without a permission list" };
308
+ }
309
+ // An empty answer omits `permissions`: none of them is held.
310
+ return { ok: true, granted: parsed.data.permissions ?? [] };
311
+ },
312
+ };
313
+ }
314
+ /** The testIamPermissions request for a resource that has one. */
315
+ export function testIamCall(resource, permissions) {
316
+ const body = JSON.stringify({ permissions });
317
+ switch (resource.kind) {
318
+ case "project":
319
+ return {
320
+ url: `https://cloudresourcemanager.googleapis.com/v1/projects/${encodeURIComponent(resource.projectId)}:testIamPermissions`,
321
+ method: "POST",
322
+ body,
323
+ };
324
+ case "service-account":
325
+ return {
326
+ url: `https://iam.googleapis.com/v1/projects/${encodeURIComponent(resource.projectId)}/serviceAccounts/${encodeURIComponent(resource.email)}:testIamPermissions`,
327
+ method: "POST",
328
+ body,
329
+ };
330
+ case "run-job":
331
+ return {
332
+ url: `https://run.googleapis.com/v2/projects/${encodeURIComponent(resource.projectId)}/locations/${encodeURIComponent(resource.region)}/jobs/${encodeURIComponent(resource.name)}:testIamPermissions`,
333
+ method: "POST",
334
+ body,
335
+ };
336
+ case "bucket": {
337
+ const q = permissions.map((p) => `permissions=${encodeURIComponent(p)}`).join("&");
338
+ return {
339
+ url: `https://storage.googleapis.com/storage/v1/b/${encodeURIComponent(resource.bucket)}/iam/testPermissions?${q}`,
340
+ method: "GET",
341
+ };
342
+ }
343
+ case "artifact-repository":
344
+ return {
345
+ url: `https://artifactregistry.googleapis.com/v1/projects/${encodeURIComponent(resource.projectId)}/locations/${encodeURIComponent(resource.location)}/repositories/${encodeURIComponent(resource.repository)}:testIamPermissions`,
346
+ method: "POST",
347
+ body,
348
+ };
349
+ }
350
+ }
351
+ const OBJECT_PROBES = {
352
+ // A read of an object that does not exist: 404 once authorized.
353
+ "storage.objects.get": { method: "GET", held: [404, 200] },
354
+ // An upload that must match generation 1: never true, so 412 once authorized.
355
+ "storage.objects.create": { method: "POST", held: [412] },
356
+ // A delete that must match generation 1: 404 (absent) or 412 once authorized.
357
+ "storage.objects.delete": { method: "DELETE", held: [404, 412] },
358
+ };
359
+ /** The precondition-guarded request that tests one object permission (see the file comment). */
360
+ export function objectProbeCall(resource, permission) {
361
+ const probe = OBJECT_PROBES[permission];
362
+ if (!probe)
363
+ return null;
364
+ const bucket = encodeURIComponent(resource.bucket);
365
+ const object = encodeURIComponent(`${resource.prefix}/${PREFLIGHT_PROBE_OBJECT}`);
366
+ switch (probe.method) {
367
+ case "GET":
368
+ return {
369
+ url: `https://storage.googleapis.com/storage/v1/b/${bucket}/o/${object}`,
370
+ method: "GET",
371
+ };
372
+ case "POST":
373
+ return {
374
+ url: `https://storage.googleapis.com/upload/storage/v1/b/${bucket}/o?uploadType=media&name=${object}&ifGenerationMatch=1`,
375
+ method: "POST",
376
+ };
377
+ case "DELETE":
378
+ return {
379
+ url: `https://storage.googleapis.com/storage/v1/b/${bucket}/o/${object}?ifGenerationMatch=1`,
380
+ method: "DELETE",
381
+ };
382
+ }
383
+ }
384
+ async function probeObjects(http, auth, resource, permissions) {
385
+ const granted = [];
386
+ for (const permission of permissions) {
387
+ const call = objectProbeCall(resource, permission);
388
+ const probe = OBJECT_PROBES[permission];
389
+ if (!call || !probe) {
390
+ return { ok: false, error: `no probe for ${permission} on ${resourceName(resource)}` };
391
+ }
392
+ const res = await http(call.url, {
393
+ method: call.method,
394
+ headers: call.method === "POST" ? { ...auth, "Content-Type": "application/octet-stream" } : auth,
395
+ ...(call.method === "POST" ? { body: "" } : {}),
396
+ });
397
+ const text = await res.text();
398
+ if (probe.held.includes(res.status)) {
399
+ // 200 on the upload would mean an object was written; held[] for
400
+ // create has no 200, so that lands below as an error, loudly.
401
+ granted.push(permission);
402
+ }
403
+ else if (res.status === 403) {
404
+ }
405
+ else {
406
+ return {
407
+ ok: false,
408
+ error: `probing ${permission} on ${resourceName(resource)}: HTTP ${res.status} ${text.trim().slice(0, 300)}`,
409
+ };
410
+ }
411
+ }
412
+ return { ok: true, granted };
413
+ }
414
+ //# sourceMappingURL=upgrader-iam-preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrader-iam-preflight.js","sourceRoot":"","sources":["../src/upgrader-iam-preflight.ts"],"names":[],"mappings":"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"}
@@ -10,18 +10,34 @@
10
10
  * but cannot change IAM, service accounts or secrets. One run:
11
11
  *
12
12
  * 1. claim the oldest pending request (ending a run that died mid-way);
13
- * 2. read what the install runs from install.json in its ops bucket;
13
+ * 2. read what the install runs from install.json in its ops bucket; when
14
+ * it names other images than the ones serving, judge against the
15
+ * serving release if a signed release manifest names both its images,
16
+ * else stop (upgrader-records.ts, #860);
14
17
  * 3. fetch the release manifest from the FIXED registry and verify its
15
18
  * signature (release-manifest.ts) — no registry, identity or digest
16
19
  * ever comes from the request, the env or argv;
17
20
  * 4. decide (upgrader-assess.ts): refuse a bad signature, a downgrade, a
18
21
  * release below its minFromVersion, an automatic run the policy does
19
- * not allow; hand an infrastructure change to Cloud Shell;
22
+ * not allow; hand an infrastructure change back (the admin routes
23
+ * it to the converge job, #819; Cloud Shell on installs without one);
24
+ * -- ask IAM whether the job's account holds every permission the rest
25
+ * of the run needs (upgrader-iam-preflight.ts, #818); any missing one
26
+ * ends the run as needs-Cloud-Shell, all of them named, nothing changed;
27
+ * -- only now take the install's state lock (#815), confirm install.json
28
+ * is unchanged since step 2, and write step 2's correction. Everything
29
+ * above only reads, so no lock problem can hide the verdict; a stop
30
+ * verdict still corrects the records when the lock is free. Only a
31
+ * verdict judged on drift asks for the lock even when it stops: the
32
+ * serving images were read without it, and a run that holds it may be
33
+ * half-way through its own roll — then the answer is "another install
34
+ * operation is running", never a drift or Cloud Shell verdict;
20
35
  * 5. take a Cloud SQL backup — no backup, no change;
21
36
  * 6. app-roll (upgrade/app-roll.ts) with no converge hooks: migrations
22
37
  * with the new admin image, admin then gateway, deep health check,
23
38
  * traffic back onto the previous revisions on any failure;
24
- * 7. record the new digests + version in install.json;
39
+ * 7. record the new digests + version in install.json (a failed write
40
+ * ends the run as failed, never as succeeded);
25
41
  * 8. move this job onto the release's own ops image, last.
26
42
  *
27
43
  * Every step is narrated into `platform_update_events` (upgrader-reporter.ts).
@@ -35,6 +51,7 @@ import type { InstallMetadata } from "./install-state.js";
35
51
  import type { ReleaseManifestResult } from "./release-manifest.js";
36
52
  import { type AppRollPlan } from "./upgrade/app-roll.js";
37
53
  import type { HealthProbe } from "./upgrade/health.js";
54
+ import { type IamTester } from "./upgrader-iam-preflight.js";
38
55
  import { type JobLog } from "./upgrader-reporter.js";
39
56
  /** A request the job claimed, with the policy as it stood at claim time. */
40
57
  export interface ClaimedUpdate {
@@ -88,15 +105,22 @@ export interface UpgraderJobDeps {
88
105
  readonly env: string;
89
106
  /** This Cloud Run execution, for the log link; null outside Cloud Run. */
90
107
  readonly execution: string | null;
108
+ /**
109
+ * Asks IAM which permissions the job's own account holds (#818), for the
110
+ * self-check right after the decision. Never the action itself.
111
+ */
112
+ readonly iam: IamTester;
91
113
  /** fetchVerifiedReleaseManifest against the fixed registry. */
92
114
  readonly fetchManifest: (version: string) => Promise<ReleaseManifestResult>;
93
115
  /**
94
- * Take the install's state lock (the one `pulumi up` and `state migrate`
95
- * hold) for the whole run; returns its release. Throws when another run
96
- * holds it.
116
+ * Take the install's state lock (the one `pulumi up`, `state migrate` and
117
+ * the CLI `upgrade` hold) right before the run's first write; returns its
118
+ * release. Breaks a lock whose holder has ended and reports that through
119
+ * `onBreak` (state-store.ts). Throws StateLockHeldError when a live run
120
+ * holds it, any other error when it cannot be taken or judged.
97
121
  */
98
- readonly lockState: () => () => void;
99
- /** install.json from the install's ops bucket (null when absent). */
122
+ readonly lockState: (onBreak: (message: string) => void) => () => void;
123
+ /** install.json as the ops bucket holds it NOW (null when absent) — never cached. */
100
124
  readonly readInstall: () => InstallMetadata | null;
101
125
  readonly writeInstall: (meta: InstallMetadata) => void;
102
126
  /** Runs both migration targets with the NEW admin image. */
@@ -129,5 +153,5 @@ export declare function runUpgraderJob(deps: UpgraderJobDeps): Promise<UpgraderR
129
153
  *
130
154
  * @returns whether the end was written (false after the last attempt failed)
131
155
  */
132
- export declare function recordUpdateEnd(queue: UpdateQueue, requestId: string, end: UpdateEnd, log: JobLog, sleep?: Sleep): Promise<boolean>;
156
+ export declare function recordUpdateEnd(queue: Pick<UpdateQueue, "finish">, requestId: string, end: UpdateEnd, log: JobLog, sleep?: Sleep): Promise<boolean>;
133
157
  //# sourceMappingURL=upgrader-job.d.ts.map