@microagi/alchemy-gcp 0.7.0 → 0.8.1

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 (93) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/lib/ArtifactRegistry/Operations.d.ts +2 -2
  3. package/lib/ArtifactRegistry/Operations.d.ts.map +1 -1
  4. package/lib/ArtifactRegistry/Repository.d.ts +1 -1
  5. package/lib/ArtifactRegistry/Validation.d.ts.map +1 -1
  6. package/lib/Auth/AuthProvider.d.ts.map +1 -1
  7. package/lib/Auth/AuthProvider.js.map +1 -1
  8. package/lib/Auth/Credentials.d.ts +1 -1
  9. package/lib/Auth/Credentials.d.ts.map +1 -1
  10. package/lib/CloudResourceManager/Project.d.ts +1 -1
  11. package/lib/CloudResourceManager/ProjectIamMember.d.ts.map +1 -1
  12. package/lib/Compute/Address.d.ts +1 -1
  13. package/lib/Compute/Firewall.d.ts +1 -1
  14. package/lib/Compute/ForwardingRule.d.ts +1 -1
  15. package/lib/Compute/GlobalAddress.d.ts +1 -1
  16. package/lib/Compute/Network.d.ts +1 -1
  17. package/lib/Compute/Network.d.ts.map +1 -1
  18. package/lib/Compute/Operations.d.ts +4 -4
  19. package/lib/Compute/Operations.d.ts.map +1 -1
  20. package/lib/Compute/Subnetwork.d.ts +1 -1
  21. package/lib/Compute/SubnetworkIamMember.d.ts.map +1 -1
  22. package/lib/Container/Cluster.d.ts +1 -1
  23. package/lib/Container/NodePool.d.ts +11 -1
  24. package/lib/Container/NodePool.d.ts.map +1 -1
  25. package/lib/Container/NodePool.js +4 -0
  26. package/lib/Container/NodePool.js.map +1 -1
  27. package/lib/Container/Operations.d.ts +2 -2
  28. package/lib/Container/Operations.d.ts.map +1 -1
  29. package/lib/Iam/ServiceAccount.d.ts +104 -0
  30. package/lib/Iam/ServiceAccount.d.ts.map +1 -0
  31. package/lib/Iam/ServiceAccount.js +255 -0
  32. package/lib/Iam/ServiceAccount.js.map +1 -0
  33. package/lib/Iam/ServiceAccountIamMember.d.ts +49 -0
  34. package/lib/Iam/ServiceAccountIamMember.d.ts.map +1 -0
  35. package/lib/Iam/ServiceAccountIamMember.js +50 -0
  36. package/lib/Iam/ServiceAccountIamMember.js.map +1 -0
  37. package/lib/Iam/ServiceAccountKey.d.ts +72 -0
  38. package/lib/Iam/ServiceAccountKey.d.ts.map +1 -0
  39. package/lib/Iam/ServiceAccountKey.js +164 -0
  40. package/lib/Iam/ServiceAccountKey.js.map +1 -0
  41. package/lib/Iam/index.d.ts +6 -0
  42. package/lib/Iam/index.d.ts.map +1 -0
  43. package/lib/Iam/index.js +4 -0
  44. package/lib/Iam/index.js.map +1 -0
  45. package/lib/Kubernetes/KubernetesManifest.d.ts +1 -1
  46. package/lib/Kubernetes/Secret.d.ts +1 -1
  47. package/lib/Kubernetes/client.d.ts.map +1 -1
  48. package/lib/Kubernetes/connection.d.ts.map +1 -1
  49. package/lib/ManagedLustre/Instance.d.ts +1 -1
  50. package/lib/Providers.d.ts +1 -1
  51. package/lib/Providers.d.ts.map +1 -1
  52. package/lib/Providers.js +7 -1
  53. package/lib/Providers.js.map +1 -1
  54. package/lib/Run/IamMember.d.ts.map +1 -1
  55. package/lib/Run/IamSync.d.ts.map +1 -1
  56. package/lib/Run/Job.d.ts +1 -1
  57. package/lib/Run/Operations.d.ts +2 -2
  58. package/lib/Run/Operations.d.ts.map +1 -1
  59. package/lib/Run/Service.d.ts +1 -1
  60. package/lib/Run/Validation.d.ts.map +1 -1
  61. package/lib/Sqladmin/Instance.d.ts +1 -1
  62. package/lib/Sqladmin/Operations.d.ts +2 -2
  63. package/lib/Sqladmin/Operations.d.ts.map +1 -1
  64. package/lib/Sqladmin/Types.d.ts.map +1 -1
  65. package/lib/Sqladmin/Validation.d.ts.map +1 -1
  66. package/lib/Storage/Bucket.d.ts +117 -0
  67. package/lib/Storage/Bucket.d.ts.map +1 -0
  68. package/lib/Storage/Bucket.js +239 -0
  69. package/lib/Storage/Bucket.js.map +1 -0
  70. package/lib/Storage/BucketIamMember.d.ts +29 -0
  71. package/lib/Storage/BucketIamMember.d.ts.map +1 -0
  72. package/lib/Storage/BucketIamMember.js +26 -0
  73. package/lib/Storage/BucketIamMember.js.map +1 -0
  74. package/lib/Storage/index.d.ts +4 -0
  75. package/lib/Storage/index.d.ts.map +1 -0
  76. package/lib/Storage/index.js +3 -0
  77. package/lib/Storage/index.js.map +1 -0
  78. package/lib/Tags.d.ts.map +1 -1
  79. package/lib/index.d.ts +2 -0
  80. package/lib/index.d.ts.map +1 -1
  81. package/lib/index.js +2 -0
  82. package/lib/index.js.map +1 -1
  83. package/package.json +3 -3
  84. package/src/Container/NodePool.ts +12 -0
  85. package/src/Iam/ServiceAccount.ts +450 -0
  86. package/src/Iam/ServiceAccountIamMember.ts +56 -0
  87. package/src/Iam/ServiceAccountKey.ts +284 -0
  88. package/src/Iam/index.ts +8 -0
  89. package/src/Providers.ts +18 -0
  90. package/src/Storage/Bucket.ts +439 -0
  91. package/src/Storage/BucketIamMember.ts +33 -0
  92. package/src/Storage/index.ts +10 -0
  93. package/src/index.ts +2 -0
@@ -0,0 +1,255 @@
1
+ import { ConfigError } from "@distilled.cloud/gcp";
2
+ import * as iam from "@distilled.cloud/gcp/unstable/iam-v1";
3
+ import { Resource } from "alchemy";
4
+ import { Unowned } from "alchemy/AdoptPolicy";
5
+ import { isResolved } from "alchemy/Diff";
6
+ import * as Provider from "alchemy/Provider";
7
+ import { diffTags } from "alchemy/Tags";
8
+ import * as Duration from "effect/Duration";
9
+ import * as Effect from "effect/Effect";
10
+ import * as Schedule from "effect/Schedule";
11
+ import { descriptionHasAlchemyMarker, gcpAlchemyDescription, stripAlchemyMarker, } from "../Tags.js";
12
+ export const ServiceAccount = Resource("GCP.ServiceAccount");
13
+ const toAttributes = (sa) => {
14
+ const accountId = (sa.email ?? "").split("@")[0];
15
+ return {
16
+ name: sa.name ?? "",
17
+ email: sa.email ?? "",
18
+ uniqueId: sa.uniqueId ?? "",
19
+ projectId: sa.projectId ?? "",
20
+ accountId,
21
+ displayName: sa.displayName,
22
+ description: stripAlchemyMarker(sa.description),
23
+ disabled: sa.disabled ?? false,
24
+ };
25
+ };
26
+ export const ServiceAccountProvider = () => Provider.effect(ServiceAccount, Effect.gen(function* () {
27
+ const getProjectsServiceAccounts = yield* iam.getProjectsServiceAccounts;
28
+ const createProjectsServiceAccounts = yield* iam.createProjectsServiceAccounts;
29
+ const patchProjectsServiceAccounts = yield* iam.patchProjectsServiceAccounts;
30
+ const deleteProjectsServiceAccounts = yield* iam.deleteProjectsServiceAccounts;
31
+ const listProjectsServiceAccounts = yield* iam.listProjectsServiceAccounts;
32
+ const getIamPolicyProjectsServiceAccounts = yield* iam.getIamPolicyProjectsServiceAccounts;
33
+ const setIamPolicyProjectsServiceAccounts = yield* iam.setIamPolicyProjectsServiceAccounts;
34
+ const resourceName = (projectId, accountId) => `projects/${projectId}/serviceAccounts/${accountId}`;
35
+ const observeServiceAccount = (projectId, accountId) => getProjectsServiceAccounts({
36
+ name: resourceName(projectId, accountId),
37
+ }).pipe(
38
+ // GSAs that don't exist OR that the caller can't see both
39
+ // collapse to "absent" — same 403→missing pattern as the
40
+ // project observer.
41
+ Effect.catchTag("NotFound", () => Effect.succeed(undefined)), Effect.catchTag("Forbidden", () => Effect.succeed(undefined)));
42
+ const requireServiceAccount = (projectId, accountId, context) => observeServiceAccount(projectId, accountId).pipe(Effect.flatMap((sa) => sa
43
+ ? Effect.succeed(sa)
44
+ : Effect.fail(new ConfigError({
45
+ message: `ServiceAccount ${accountId} in project ${projectId} ${context}.`,
46
+ }))));
47
+ // List-page scan for cold recovery. Alchemy marker in the
48
+ // description field identifies our GSAs; the page boundary is
49
+ // arbitrary — we still need to page through to find any marker
50
+ // that happens to fall past the first page.
51
+ const findByAlchemyMarker = Effect.fn(function* (id, projectId) {
52
+ let pageToken;
53
+ // Up to 100 pages × 100 items per page = 10000 GSAs; well past
54
+ // any realistic project size. If we ever exceed that we should
55
+ // cap and warn rather than silently miss matches.
56
+ for (let i = 0; i < 100; i++) {
57
+ const page = yield* listProjectsServiceAccounts({
58
+ name: `projects/${projectId}`,
59
+ ...(pageToken ? { pageToken } : {}),
60
+ pageSize: 100,
61
+ });
62
+ for (const sa of page.accounts ?? []) {
63
+ if (yield* descriptionHasAlchemyMarker(id, sa.description)) {
64
+ return sa;
65
+ }
66
+ }
67
+ pageToken = page.nextPageToken;
68
+ if (!pageToken)
69
+ return undefined;
70
+ }
71
+ return undefined;
72
+ });
73
+ // Sync mutable fields: displayName + description. Both use
74
+ // `updateMask` so we only PATCH what actually changed. Diff
75
+ // against OBSERVED state, not `olds`, so adoption converges
76
+ // correctly when a foreign description is on the GSA.
77
+ const syncMutable = Effect.fn(function* (observed, desired) {
78
+ const updateMaskFields = [];
79
+ if (desired.displayName !== observed.displayName) {
80
+ updateMaskFields.push("display_name");
81
+ }
82
+ const descDiff = diffTags({ description: observed.description ?? "" }, { description: desired.descriptionWithMarker });
83
+ if (descDiff.removed.length > 0 ||
84
+ descDiff.upsert.length > 0) {
85
+ updateMaskFields.push("description");
86
+ }
87
+ if (updateMaskFields.length === 0)
88
+ return observed;
89
+ return yield* patchProjectsServiceAccounts({
90
+ name: observed.name,
91
+ body: {
92
+ updateMask: updateMaskFields.join(","),
93
+ serviceAccount: {
94
+ displayName: desired.displayName,
95
+ description: desired.descriptionWithMarker,
96
+ },
97
+ },
98
+ });
99
+ });
100
+ // Apply merged IAM bindings as a single setIamPolicy. Same
101
+ // foreign-binding preservation + etag-retry pattern as the
102
+ // Project's `syncIam` — see `src/CloudResourceManager/Project.ts:421-474`.
103
+ const syncIam = (args) => Effect.gen(function* () {
104
+ const desiredByRole = new Map();
105
+ for (const b of args.bindings) {
106
+ for (const ib of b.data.iamBindings) {
107
+ const set = desiredByRole.get(ib.role) ?? new Set();
108
+ for (const m of ib.members)
109
+ set.add(m);
110
+ desiredByRole.set(ib.role, set);
111
+ }
112
+ }
113
+ if (desiredByRole.size === 0)
114
+ return;
115
+ const current = yield* getIamPolicyProjectsServiceAccounts({
116
+ resource: args.resourceName,
117
+ "options.requestedPolicyVersion": 3,
118
+ });
119
+ const existingBindings = (current.bindings ?? []).map((b) => ({
120
+ ...b,
121
+ members: [...(b.members ?? [])],
122
+ }));
123
+ let mutated = false;
124
+ for (const [role, members] of desiredByRole) {
125
+ let existing = existingBindings.find((b) => b.role === role && !b.condition);
126
+ if (!existing) {
127
+ existing = { role, members: [] };
128
+ existingBindings.push(existing);
129
+ }
130
+ const merged = new Set([...(existing.members ?? []), ...members]);
131
+ if (merged.size !== (existing.members?.length ?? 0))
132
+ mutated = true;
133
+ existing.members = [...merged];
134
+ }
135
+ if (!mutated)
136
+ return;
137
+ yield* setIamPolicyProjectsServiceAccounts({
138
+ resource: args.resourceName,
139
+ body: {
140
+ policy: { ...current, bindings: existingBindings, version: 3 },
141
+ },
142
+ });
143
+ }).pipe(Effect.retry({
144
+ schedule: Schedule.exponential(Duration.seconds(2)).pipe(Schedule.both(Schedule.recurs(8))),
145
+ }));
146
+ return {
147
+ // Stable identity: accountId + project; both immutable; either
148
+ // change → replace. The server-assigned uniqueId is also stable
149
+ // for the lifetime of the GSA (re-create gets a different one).
150
+ stables: ["accountId", "projectId", "uniqueId", "name", "email"],
151
+ diff: Effect.fn(function* ({ id, news, olds = {}, output }) {
152
+ if (!isResolved(news))
153
+ return undefined;
154
+ // Replace ONLY when a prior identity is actually known AND differs.
155
+ // A partial/adopted state can lack the persisted accountId/projectId
156
+ // (an adoption that never persisted full Attributes leaves
157
+ // output.projectId === "" / undefined). Treating that "unknown" as a
158
+ // replace spuriously deletes+recreates a live, correctly-named GSA
159
+ // (and churns its uniqueId → breaks Workload-Identity bindings).
160
+ // When the prior identity is absent, fall through to reconcile, which
161
+ // observes the live resource and re-persists its Attributes. The
162
+ // truthiness guard covers both `undefined` and the `""` toAttributes
163
+ // default; a genuine accountId/project change still has a non-empty
164
+ // prior value to compare against, so real replacements are unaffected.
165
+ // `||` (not `??`): toAttributes persists `accountId`/`projectId` as
166
+ // `""` when absent, and an empty string must fall through to `olds`
167
+ // (the previous Props) rather than mask it — otherwise a genuine
168
+ // identity change with an empty `output` but a populated `olds` would
169
+ // skip the replace and adopt/create at the new identity without
170
+ // deleting the old GSA.
171
+ const priorAccount = output?.accountId || olds.accountId;
172
+ const priorProject = output?.projectId || olds.project;
173
+ if ((priorAccount && news.accountId !== priorAccount) ||
174
+ (priorProject && news.project !== priorProject)) {
175
+ return { action: "replace" };
176
+ }
177
+ return undefined;
178
+ }),
179
+ reconcile: Effect.fn(function* ({ id, news, bindings }) {
180
+ const descriptionWithMarker = yield* gcpAlchemyDescription(id, news.description);
181
+ // 1. Observe — cloud state is authoritative. A second
182
+ // scan-by-marker covers the cold-recovery case where
183
+ // persisted `output`/`olds` lost the uniqueId after
184
+ // state loss. We prefer the direct-by-name probe first
185
+ // (cheap) and fall back to the scan only when direct
186
+ // observation returned `undefined`.
187
+ let observed = yield* observeServiceAccount(news.project, news.accountId);
188
+ if (!observed) {
189
+ observed = yield* findByAlchemyMarker(id, news.project);
190
+ }
191
+ // 2. Ensure — create if missing. createProjectsServiceAccounts
192
+ // is synchronous (returns the SA, not an LRO). Conflict
193
+ // covers a peer reconciler race — re-observe.
194
+ if (!observed) {
195
+ observed = yield* createProjectsServiceAccounts({
196
+ name: `projects/${news.project}`,
197
+ body: {
198
+ accountId: news.accountId,
199
+ serviceAccount: {
200
+ displayName: news.displayName,
201
+ description: descriptionWithMarker,
202
+ },
203
+ },
204
+ }).pipe(Effect.catchTag("Conflict", () => Effect.succeed(undefined)));
205
+ if (!observed) {
206
+ observed = yield* requireServiceAccount(news.project, news.accountId, "did not appear after create");
207
+ }
208
+ }
209
+ // 3. Sync mutable fields against OBSERVED state.
210
+ const synced = yield* syncMutable(observed, {
211
+ displayName: news.displayName ?? observed.displayName,
212
+ descriptionWithMarker,
213
+ descriptionUserOnly: news.description,
214
+ });
215
+ // 4. Sync IAM bindings (Workload Identity, impersonators, …).
216
+ // Single setIamPolicy on the GSA with merged bindings;
217
+ // foreign roles preserved. Etag-retried internally.
218
+ yield* syncIam({
219
+ resourceName: synced.name,
220
+ bindings,
221
+ });
222
+ return toAttributes(synced);
223
+ }),
224
+ delete: Effect.fn(function* ({ output }) {
225
+ // Synchronous delete — Empty response, no LRO. NotFound
226
+ // means the GSA was already deleted (or never existed in our
227
+ // scope); both are idempotent successes.
228
+ yield* deleteProjectsServiceAccounts({
229
+ name: output.name,
230
+ }).pipe(Effect.catchTag("NotFound", () => Effect.void), Effect.catchTag("Forbidden", () => Effect.void));
231
+ }),
232
+ read: Effect.fn(function* ({ id, output, olds }) {
233
+ // Direct-by-name probe when we have any handle on the
234
+ // accountId. Falls back to a project-wide scan-by-marker
235
+ // for cold recovery after state loss.
236
+ const accountId = output?.accountId ?? olds?.accountId;
237
+ const projectId = output?.projectId ?? olds?.project;
238
+ let observed;
239
+ if (accountId && projectId) {
240
+ observed = yield* observeServiceAccount(projectId, accountId);
241
+ }
242
+ if (!observed && projectId) {
243
+ observed = yield* findByAlchemyMarker(id, projectId);
244
+ }
245
+ if (!observed)
246
+ return undefined;
247
+ const attrs = toAttributes(observed);
248
+ // Adoption gate via description marker (see Tags.ts §description).
249
+ return (yield* descriptionHasAlchemyMarker(id, observed.description))
250
+ ? attrs
251
+ : Unowned(attrs);
252
+ }),
253
+ };
254
+ }));
255
+ //# sourceMappingURL=ServiceAccount.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceAccount.js","sourceRoot":"","sources":["../../src/Iam/ServiceAccount.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import * as Effect from "effect/Effect";
2
+ import type { ServiceAccount } from "./ServiceAccount.ts";
3
+ /**
4
+ * Bind a single `(role, member)` IAM grant onto a {@link ServiceAccount}.
5
+ *
6
+ * This is a **target-side binding** — it records the grant onto the
7
+ * GSA's binding bag (`stack.bindings[gsa]`); the ServiceAccount
8
+ * provider's `reconcile` later merges all such bindings (across all
9
+ * callers, including parallel ones from different stack stages) into
10
+ * a single `setIamPolicy` call on the GSA. Same pattern as
11
+ * `projectIamMember` / `subnetworkIamMember`.
12
+ *
13
+ * Identity for dedup: the rendered SID is `IamMember(<gsa>, <key>)`.
14
+ * The engine collapses binds by SID, so callers MUST supply a
15
+ * stack-unique `key` per (gsa, role, member) triple — otherwise a
16
+ * later bind silently overwrites an earlier one with the same key.
17
+ *
18
+ * The reason `key` exists: `member` is usually an `Output<string>`
19
+ * (e.g. `Output.interpolate\`...${cluster.projectId}...\``), and
20
+ * `Output` expressions stringify by their AST shape, not by the
21
+ * eventual value. Two interpolations of the same shape but different
22
+ * literal templates render the same SID. `key` sidesteps that by
23
+ * forcing a static, caller-supplied label into the SID.
24
+ *
25
+ * Use this for the "Pulumi `gcp.serviceAccount.IAMMember`" pattern:
26
+ * authoritative-for-(role, member)-tuple, additive (does not displace
27
+ * other members on the same role).
28
+ *
29
+ * @example Workload Identity binding for one cluster
30
+ * ```typescript
31
+ * yield* GCP.serviceAccountIamMember(gsa, "ClusterA-WorkloadIdentity", {
32
+ * role: "roles/iam.workloadIdentityUser",
33
+ * member: `serviceAccount:${clusterA.projectId}.svc.id.goog[researchers/build]`,
34
+ * });
35
+ * ```
36
+ *
37
+ * @example Same GSA, second cluster (separate key → distinct SID)
38
+ * ```typescript
39
+ * yield* GCP.serviceAccountIamMember(gsa, "ClusterB-WorkloadIdentity", {
40
+ * role: "roles/iam.workloadIdentityUser",
41
+ * member: `serviceAccount:${clusterB.projectId}.svc.id.goog[researchers/build]`,
42
+ * });
43
+ * ```
44
+ */
45
+ export declare const serviceAccountIamMember: (gsa: ServiceAccount, key: string, args: {
46
+ role: string;
47
+ member: string;
48
+ }) => Effect.Effect<void>;
49
+ //# sourceMappingURL=ServiceAccountIamMember.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceAccountIamMember.d.ts","sourceRoot":"","sources":["../../src/Iam/ServiceAccountIamMember.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,uBAAuB,QAC7B,cAAc,OACd,MAAM,QACL;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,KACrC,MAAM,CAAC,MAAM,CAAC,IAAI,CAMiB,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Bind a single `(role, member)` IAM grant onto a {@link ServiceAccount}.
3
+ *
4
+ * This is a **target-side binding** — it records the grant onto the
5
+ * GSA's binding bag (`stack.bindings[gsa]`); the ServiceAccount
6
+ * provider's `reconcile` later merges all such bindings (across all
7
+ * callers, including parallel ones from different stack stages) into
8
+ * a single `setIamPolicy` call on the GSA. Same pattern as
9
+ * `projectIamMember` / `subnetworkIamMember`.
10
+ *
11
+ * Identity for dedup: the rendered SID is `IamMember(<gsa>, <key>)`.
12
+ * The engine collapses binds by SID, so callers MUST supply a
13
+ * stack-unique `key` per (gsa, role, member) triple — otherwise a
14
+ * later bind silently overwrites an earlier one with the same key.
15
+ *
16
+ * The reason `key` exists: `member` is usually an `Output<string>`
17
+ * (e.g. `Output.interpolate\`...${cluster.projectId}...\``), and
18
+ * `Output` expressions stringify by their AST shape, not by the
19
+ * eventual value. Two interpolations of the same shape but different
20
+ * literal templates render the same SID. `key` sidesteps that by
21
+ * forcing a static, caller-supplied label into the SID.
22
+ *
23
+ * Use this for the "Pulumi `gcp.serviceAccount.IAMMember`" pattern:
24
+ * authoritative-for-(role, member)-tuple, additive (does not displace
25
+ * other members on the same role).
26
+ *
27
+ * @example Workload Identity binding for one cluster
28
+ * ```typescript
29
+ * yield* GCP.serviceAccountIamMember(gsa, "ClusterA-WorkloadIdentity", {
30
+ * role: "roles/iam.workloadIdentityUser",
31
+ * member: `serviceAccount:${clusterA.projectId}.svc.id.goog[researchers/build]`,
32
+ * });
33
+ * ```
34
+ *
35
+ * @example Same GSA, second cluster (separate key → distinct SID)
36
+ * ```typescript
37
+ * yield* GCP.serviceAccountIamMember(gsa, "ClusterB-WorkloadIdentity", {
38
+ * role: "roles/iam.workloadIdentityUser",
39
+ * member: `serviceAccount:${clusterB.projectId}.svc.id.goog[researchers/build]`,
40
+ * });
41
+ * ```
42
+ */
43
+ export const serviceAccountIamMember = (gsa, key, args) =>
44
+ // Tagged-template `.bind` records into the target's binding bag.
45
+ // ServiceAccount's reconcile sees `bindings: ResourceBinding<…>[]`
46
+ // and merges all entries by role into one setIamPolicy call.
47
+ gsa.bind `IamMember(${gsa}, ${key})`({
48
+ iamBindings: [{ role: args.role, members: [args.member] }],
49
+ });
50
+ //# sourceMappingURL=ServiceAccountIamMember.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceAccountIamMember.js","sourceRoot":"","sources":["../../src/Iam/ServiceAccountIamMember.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,GAAmB,EACnB,GAAW,EACX,IAAsC,EACjB,EAAE;AACvB,iEAAiE;AACjE,mEAAmE;AACnE,6DAA6D;AAC7D,GAAG,CAAC,IAAI,CAAA,aAAa,GAAG,KAAK,GAAG,GAAG,CAAC;IAClC,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;CAC3D,CAAmC,CAAC"}
@@ -0,0 +1,72 @@
1
+ import { Resource } from "alchemy";
2
+ import * as Provider from "alchemy/Provider";
3
+ import type * as GCP from "../Providers.ts";
4
+ /**
5
+ * A user-managed service account key (JSON credentials file). Lives
6
+ * under a {@link import("./ServiceAccount.ts").ServiceAccount} and
7
+ * produces a `privateKeyData` field (base64-encoded JSON key file)
8
+ * available ONLY on create — `get`/`list` never return it.
9
+ *
10
+ * The `privateKeyData` attribute is marked stable so the engine
11
+ * preserves it across reconciles (it cannot be re-read from the API).
12
+ * On cold recovery (state loss), if the key exists but
13
+ * `privateKeyData` is absent from state, the old key is deleted and a
14
+ * new one is created so the `privateKeyData` is re-obtained.
15
+ *
16
+ * SA keys carry no labels or description, so adoption cannot be gated
17
+ * by marker — the SA itself is alchemy-owned, and the key is managed
18
+ * exclusively through this resource.
19
+ *
20
+ * @section Creating a ServiceAccountKey
21
+ * @example Mint a JSON key for a GSA
22
+ * ```typescript
23
+ * const key = yield* GCP.ServiceAccountKey("TempBucketKey", {
24
+ * serviceAccount: sa.name, // projects/{p}/serviceAccounts/{email}
25
+ * });
26
+ * // key.privateKeyData is the base64-encoded JSON key file
27
+ * ```
28
+ */
29
+ export type ServiceAccountKeyProps = {
30
+ /**
31
+ * The resource name of the parent service account, in the format
32
+ * `projects/{PROJECT_ID}/serviceAccounts/{EMAIL_ADDRESS}`.
33
+ * Immutable — changing it triggers a replacement (the key is
34
+ * scoped to the SA).
35
+ */
36
+ serviceAccount: string;
37
+ /**
38
+ * Key algorithm. Defaults to `KEY_ALG_RSA_2048`. Immutable after
39
+ * create.
40
+ */
41
+ keyAlgorithm?: "KEY_ALG_RSA_2048" | "KEY_ALG_RSA_1024";
42
+ /**
43
+ * Output format for the private key. Defaults to
44
+ * `TYPE_GOOGLE_CREDENTIALS_FILE` (the Google Credentials JSON
45
+ * format usable by gcloud, gsutil, and the gcsfuse CSI driver).
46
+ */
47
+ privateKeyType?: "TYPE_GOOGLE_CREDENTIALS_FILE" | "TYPE_PKCS12_FILE";
48
+ };
49
+ export type ServiceAccountKey = Resource<"GCP.ServiceAccountKey", ServiceAccountKeyProps, {
50
+ /** Full resource name: `projects/{p}/serviceAccounts/{email}/keys/{keyId}`. */
51
+ name: string;
52
+ /**
53
+ * Base64-encoded private key data (JSON key file). Only available
54
+ * on create — not returned by `get`/`list`. Preserved in alchemy
55
+ * state; on state loss the old key is deleted + a new one is
56
+ * created to re-obtain it.
57
+ */
58
+ privateKeyData: string | undefined;
59
+ /** Key algorithm used. */
60
+ keyAlgorithm: string | undefined;
61
+ /** Key type: `USER_MANAGED` or `SYSTEM_MANAGED`. */
62
+ keyType: string | undefined;
63
+ /** Key origin: `USER_PROVIDED` or `GOOGLE_PROVIDED`. */
64
+ keyOrigin: string | undefined;
65
+ /** Timestamp after which the key is valid (RFC 3339). */
66
+ validAfterTime: string | undefined;
67
+ /** Whether the key is disabled. */
68
+ disabled: boolean | undefined;
69
+ }, never, GCP.Providers>;
70
+ export declare const ServiceAccountKey: import("alchemy").ResourceClass<ServiceAccountKey>;
71
+ export declare const ServiceAccountKeyProvider: () => import("effect/Layer").Layer<Provider.Provider<ServiceAccountKey>, never, import("@distilled.cloud/gcp").Credentials | import("effect/unstable/http/HttpClient").HttpClient>;
72
+ //# sourceMappingURL=ServiceAccountKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceAccountKey.d.ts","sourceRoot":"","sources":["../../src/Iam/ServiceAccountKey.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC;;;;;OAKG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,kBAAkB,GAAG,kBAAkB,CAAC;IACvD;;;;OAIG;IACH,cAAc,CAAC,EAAE,8BAA8B,GAAG,kBAAkB,CAAC;CACtE,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CACtC,uBAAuB,EACvB,sBAAsB,EACtB;IACE,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,0BAA0B;IAC1B,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,oDAAoD;IACpD,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,wDAAwD;IACxD,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,yDAAyD;IACzD,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,mCAAmC;IACnC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/B,EACD,KAAK,EACL,GAAG,CAAC,SAAS,CACd,CAAC;AAEF,eAAO,MAAM,iBAAiB,oDAE7B,CAAC;AAYF,eAAO,MAAM,yBAAyB,oLA2LnC,CAAC"}
@@ -0,0 +1,164 @@
1
+ import { ConfigError } from "@distilled.cloud/gcp";
2
+ import * as iam from "@distilled.cloud/gcp/unstable/iam-v1";
3
+ import { Resource } from "alchemy";
4
+ import { isResolved } from "alchemy/Diff";
5
+ import * as Provider from "alchemy/Provider";
6
+ import * as Effect from "effect/Effect";
7
+ export const ServiceAccountKey = Resource("GCP.ServiceAccountKey");
8
+ const toAttributes = (k) => ({
9
+ name: k.name ?? "",
10
+ privateKeyData: k.privateKeyData,
11
+ keyAlgorithm: k.keyAlgorithm,
12
+ keyType: k.keyType,
13
+ keyOrigin: k.keyOrigin,
14
+ validAfterTime: k.validAfterTime,
15
+ disabled: k.disabled,
16
+ });
17
+ export const ServiceAccountKeyProvider = () => Provider.effect(ServiceAccountKey, Effect.gen(function* () {
18
+ const createProjectsServiceAccountsKeys = yield* iam.createProjectsServiceAccountsKeys;
19
+ const deleteProjectsServiceAccountsKeys = yield* iam.deleteProjectsServiceAccountsKeys;
20
+ const listProjectsServiceAccountsKeys = yield* iam.listProjectsServiceAccountsKeys;
21
+ const getProjectsServiceAccountsKeys = yield* iam.getProjectsServiceAccountsKeys;
22
+ // Find a user-managed key by name (direct probe).
23
+ // NotFound → undefined (key doesn't exist). Forbidden is NOT
24
+ // swallowed — if the caller lacks permission to read this key,
25
+ // propagating the error is safer than treating it as "missing"
26
+ // and potentially creating a duplicate on the SA.
27
+ const observeKey = (keyName) => getProjectsServiceAccountsKeys({
28
+ name: keyName,
29
+ publicKeyType: "TYPE_GOOGLE_CREDENTIALS_FILE",
30
+ }).pipe(Effect.catchTag("NotFound", () => Effect.succeed(undefined)));
31
+ // List all user-managed keys for the SA. Used for cold recovery
32
+ // when the key name is not in state. Returns the first
33
+ // user-managed key found (the SA is dedicated to this resource,
34
+ // so there should be at most one user-managed key).
35
+ const findUserManagedKey = Effect.fn(function* (serviceAccount) {
36
+ const page = yield* listProjectsServiceAccountsKeys({
37
+ name: serviceAccount,
38
+ keyTypes: "USER_MANAGED",
39
+ });
40
+ const keys = page.keys ?? [];
41
+ if (keys.length === 0)
42
+ return undefined;
43
+ if (keys.length === 1)
44
+ return keys[0];
45
+ // Multiple user-managed keys — GCP allows multiple keys per
46
+ // SA, so creating another would silently succeed (not
47
+ // Conflict as an earlier comment assumed). Surface an error
48
+ // so the user cleans up the extra keys and re-runs.
49
+ return yield* Effect.fail(new ConfigError({
50
+ message: `Service account ${serviceAccount} has ${keys.length} user-managed keys; ` +
51
+ `cannot determine which to adopt. Delete the extra keys and re-run.`,
52
+ }));
53
+ });
54
+ return {
55
+ // privateKeyData is stable: it's set on create and never
56
+ // changes. The engine preserves it across reconciles and
57
+ // does not use it for drift detection.
58
+ stables: ["name", "privateKeyData", "keyAlgorithm", "keyType"],
59
+ diff: Effect.fn(function* ({ news, olds = {} }) {
60
+ if (!isResolved(news))
61
+ return undefined;
62
+ const priorSa = olds.serviceAccount;
63
+ const priorKeyAlgorithm = olds.keyAlgorithm;
64
+ const priorPrivateKeyType = olds.privateKeyType;
65
+ if ((priorSa && news.serviceAccount !== priorSa) ||
66
+ (priorKeyAlgorithm && news.keyAlgorithm !== priorKeyAlgorithm) ||
67
+ (priorPrivateKeyType &&
68
+ news.privateKeyType !== priorPrivateKeyType)) {
69
+ return { action: "replace" };
70
+ }
71
+ return undefined;
72
+ }),
73
+ reconcile: Effect.fn(function* ({ id, news, output }) {
74
+ // 1. Observe — check if the key exists by name (from
75
+ // state output). Fall back to listing user-managed
76
+ // keys for cold recovery.
77
+ const keyName = output?.name;
78
+ let observed;
79
+ if (keyName) {
80
+ observed = yield* observeKey(keyName);
81
+ }
82
+ if (!observed) {
83
+ observed = yield* findUserManagedKey(news.serviceAccount);
84
+ }
85
+ // 2. Ensure — create if missing. If the key exists but
86
+ // privateKeyData is not in state (state loss), delete
87
+ // the old key and create a new one so privateKeyData is
88
+ // re-obtained.
89
+ if (!observed) {
90
+ const created = yield* createProjectsServiceAccountsKeys({
91
+ name: news.serviceAccount,
92
+ body: {
93
+ privateKeyType: news.privateKeyType ?? "TYPE_GOOGLE_CREDENTIALS_FILE",
94
+ keyAlgorithm: news.keyAlgorithm ?? "KEY_ALG_RSA_2048",
95
+ },
96
+ });
97
+ return toAttributes(created);
98
+ }
99
+ // Key exists. If it is the same key we created before, preserve
100
+ // privateKeyData from state. If the name differs, the key was
101
+ // swapped out-of-band — fall through to delete + recreate so
102
+ // privateKeyData matches the live key.
103
+ if (output?.privateKeyData && observed.name === output.name) {
104
+ return {
105
+ ...toAttributes(observed),
106
+ privateKeyData: output.privateKeyData,
107
+ };
108
+ }
109
+ // privateKeyData is missing from state. Only delete + recreate
110
+ // when we can PROVE the observed key is ours: output.name must
111
+ // be set and match. SA keys carry no labels, so on cold recovery
112
+ // (output undefined) a found key might be pre-existing or
113
+ // manually rotated — deleting it would destroy someone else's
114
+ // credentials. Fail instead and ask the user to clean up.
115
+ if (output?.name && observed.name === output.name) {
116
+ yield* deleteProjectsServiceAccountsKeys({
117
+ name: observed.name,
118
+ }).pipe(Effect.catchTag("NotFound", () => Effect.void));
119
+ const created = yield* createProjectsServiceAccountsKeys({
120
+ name: news.serviceAccount,
121
+ body: {
122
+ privateKeyType: news.privateKeyType ?? "TYPE_GOOGLE_CREDENTIALS_FILE",
123
+ keyAlgorithm: news.keyAlgorithm ?? "KEY_ALG_RSA_2048",
124
+ },
125
+ });
126
+ return toAttributes(created);
127
+ }
128
+ // Key exists but we can't prove ownership. Don't delete it.
129
+ return yield* Effect.fail(new ConfigError({
130
+ message: `Service account key ${observed.name} exists on ${news.serviceAccount} ` +
131
+ `but cannot be verified as ours (no matching state). ` +
132
+ `Delete it manually and re-run to create a fresh key.`,
133
+ }));
134
+ }),
135
+ delete: Effect.fn(function* ({ output }) {
136
+ yield* deleteProjectsServiceAccountsKeys({
137
+ name: output.name,
138
+ }).pipe(Effect.catchTag("NotFound", () => Effect.void), Effect.catchTag("Forbidden", () => Effect.void));
139
+ }),
140
+ read: Effect.fn(function* ({ id, output, olds }) {
141
+ const keyName = output?.name;
142
+ const serviceAccount = olds.serviceAccount;
143
+ let observed;
144
+ if (keyName) {
145
+ observed = yield* observeKey(keyName);
146
+ }
147
+ if (!observed && serviceAccount) {
148
+ observed = yield* findUserManagedKey(serviceAccount);
149
+ }
150
+ if (!observed)
151
+ return undefined;
152
+ // privateKeyData is not available from get/list — preserve it
153
+ // from state output only when it still describes this key.
154
+ const privateKeyData = output?.name && observed.name === output.name
155
+ ? output.privateKeyData
156
+ : undefined;
157
+ return {
158
+ ...toAttributes(observed),
159
+ privateKeyData,
160
+ };
161
+ }),
162
+ };
163
+ }));
164
+ //# sourceMappingURL=ServiceAccountKey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceAccountKey.js","sourceRoot":"","sources":["../../src/Iam/ServiceAccountKey.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { ServiceAccount, ServiceAccountProvider } from "./ServiceAccount.ts";
2
+ export type { ServiceAccountProps } from "./ServiceAccount.ts";
3
+ export * from "./ServiceAccountIamMember.ts";
4
+ export { ServiceAccountKey, ServiceAccountKeyProvider, } from "./ServiceAccountKey.ts";
5
+ export type { ServiceAccountKeyProps } from "./ServiceAccountKey.ts";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Iam/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,cAAc,8BAA8B,CAAC;AAC7C,OAAO,EACL,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}