@microagi/alchemy-gcp 0.10.0 → 0.11.0

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.
@@ -12,9 +12,20 @@ import type * as GCP from "../Providers.ts";
12
12
  * cannot do — **removes it again on delete**, so grants revoke when the
13
13
  * declaring resource leaves the stack.
14
14
  *
15
- * Identity is the `(bucket, role, member)` triple; all three are
16
- * immutable — changing any replaces (the old triple is revoked, the new
17
- * one granted).
15
+ * Identity is the `(bucket, role, member, condition.expression)` tuple;
16
+ * all are immutable — changing any replaces (the old grant is revoked,
17
+ * the new one granted).
18
+ *
19
+ * With a `condition`, the member lands in the binding whose condition
20
+ * **expression** matches (CEL, compared byte-for-byte) — the binding is
21
+ * created with the given title/description if absent. Title and
22
+ * description are create-time metadata only: an existing binding with
23
+ * the same expression but a different title is adopted as-is, never
24
+ * retitled (that lets hand-applied conditional grants converge into the
25
+ * stack without a duplicate binding). Conditional bindings require the
26
+ * bucket to have uniform bucket-level access (GCS rejects conditions
27
+ * otherwise) and policy version 3 — the read-modify-write here always
28
+ * requests/writes version 3.
18
29
  *
19
30
  * The read-modify-write on the shared bucket policy is member-scoped:
20
31
  * exactly one member is added/removed, every foreign role and member is
@@ -36,7 +47,38 @@ import type * as GCP from "../Providers.ts";
36
47
  * "principal://iam.googleapis.com/projects/864268824536/locations/global/workloadIdentityPools/micro-research-cluster-a.svc.id.goog/subject/ns/collab-srl/sa/default",
37
48
  * });
38
49
  * ```
50
+ *
51
+ * @section Prefix-scoped read on a customer bucket
52
+ * @example Conditional grant limited to one object prefix (+ bucket-level list)
53
+ * ```typescript
54
+ * yield* GCP.StorageBucketIamMember("QaDatasetRead", {
55
+ * bucket: "golden-zone-prod-770927",
56
+ * role: "roles/storage.objectViewer",
57
+ * member: "principal://iam.googleapis.com/…/subject/ns/collab-jeffrey-coworking/sa/default",
58
+ * condition: {
59
+ * title: "collab-jeffrey-coworking",
60
+ * expression:
61
+ * 'resource.name.startsWith("projects/_/buckets/golden-zone-prod-770927/objects/qa/") || resource.name == "projects/_/buckets/golden-zone-prod-770927"',
62
+ * },
63
+ * });
64
+ * ```
39
65
  */
66
+ export type StorageBucketIamMemberCondition = {
67
+ /**
68
+ * Binding title — create-time metadata only. NOT identity: a live
69
+ * binding with the same expression but another title is adopted, not
70
+ * retitled/replaced.
71
+ */
72
+ title: string;
73
+ /** Optional human note on the binding. Create-time metadata only. */
74
+ description?: string;
75
+ /**
76
+ * CEL condition expression. Part of the resource identity — compared
77
+ * byte-for-byte against live bindings' expressions, so keep the
78
+ * rendering deterministic. Immutable — replace.
79
+ */
80
+ expression: string;
81
+ };
40
82
  export type StorageBucketIamMemberProps = {
41
83
  /**
42
84
  * Name of the (pre-existing) GCS bucket to grant on. The bucket is
@@ -51,6 +93,14 @@ export type StorageBucketIamMemberProps = {
51
93
  * `group:…`, …). Immutable — replace.
52
94
  */
53
95
  member: string;
96
+ /**
97
+ * Optional IAM Condition scoping the grant (e.g. to an object
98
+ * prefix). Absent → the member joins the role's UNCONDITIONAL
99
+ * binding. The condition **expression** is identity (immutable —
100
+ * replace); title/description are create-time metadata. Requires
101
+ * uniform bucket-level access on the bucket.
102
+ */
103
+ condition?: StorageBucketIamMemberCondition;
54
104
  };
55
105
  export type StorageBucketIamMemberAttributes = {
56
106
  /** Bucket name, threaded through from props. */
@@ -59,6 +109,8 @@ export type StorageBucketIamMemberAttributes = {
59
109
  role: string;
60
110
  /** IAM member, threaded through from props. */
61
111
  member: string;
112
+ /** IAM Condition, threaded through from props (absent = unconditional). */
113
+ condition?: StorageBucketIamMemberCondition;
62
114
  };
63
115
  export type StorageBucketIamMember = Resource<"GCP.StorageBucketIamMember", StorageBucketIamMemberProps, StorageBucketIamMemberAttributes, never, GCP.Providers>;
64
116
  export declare const StorageBucketIamMember: import("alchemy").ResourceClass<StorageBucketIamMember>;
@@ -1 +1 @@
1
- {"version":3,"file":"StorageBucketIamMember.d.ts","sourceRoot":"","sources":["../../src/Storage/StorageBucketIamMember.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAI7C,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,gCAAgC,GAAG;IAC7C,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAC3C,4BAA4B,EAC5B,2BAA2B,EAC3B,gCAAgC,EAChC,KAAK,EACL,GAAG,CAAC,SAAS,CACd,CAAC;AAEF,eAAO,MAAM,sBAAsB,yDAElC,CAAC;AAEF,eAAO,MAAM,8BAA8B,yLAgKxC,CAAC"}
1
+ {"version":3,"file":"StorageBucketIamMember.d.ts","sourceRoot":"","sources":["../../src/Storage/StorageBucketIamMember.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAI7C,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,+BAA+B,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,gCAAgC,GAAG;IAC7C,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,SAAS,CAAC,EAAE,+BAA+B,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAC3C,4BAA4B,EAC5B,2BAA2B,EAC3B,gCAAgC,EAChC,KAAK,EACL,GAAG,CAAC,SAAS,CACd,CAAC;AAEF,eAAO,MAAM,sBAAsB,yDAElC,CAAC;AAEF,eAAO,MAAM,8BAA8B,yLA0NxC,CAAC"}
@@ -19,12 +19,20 @@ export const StorageBucketIamMemberProvider = () => Provider.effect(StorageBucke
19
19
  while: (e) => e?._tag !== "ConfigError",
20
20
  schedule: Schedule.exponential(Duration.seconds(2)).pipe(Schedule.both(Schedule.recurs(8))),
21
21
  }));
22
- // Membership check scoped to the unconditional binding for `role`
23
- // conditional bindings are someone else's and never touched.
24
- const hasMember = (policy, role, member) => (policy.bindings ?? []).some((b) => b.role === role && !b.condition && (b.members ?? []).includes(member));
22
+ // Binding selector: with no condition, ONLY the unconditional
23
+ // binding for `role` (conditional bindings are someone else's);
24
+ // with a condition, the binding whose expression matches
25
+ // byte-for-byte — title/description deliberately ignored so
26
+ // hand-applied grants with the same expression are adopted.
27
+ const bindingMatches = (b, role, condition) => b.role === role &&
28
+ (condition
29
+ ? b.condition?.expression === condition.expression
30
+ : !b.condition);
31
+ const hasMember = (policy, role, member, condition) => (policy.bindings ?? []).some((b) => bindingMatches(b, role, condition) &&
32
+ (b.members ?? []).includes(member));
25
33
  return {
26
- // Identity IS the triple; all three are static strings.
27
- stables: ["bucket", "role", "member"],
34
+ // Identity IS the tuple; all fields are static values.
35
+ stables: ["bucket", "role", "member", "condition"],
28
36
  diff: Effect.fn(function* ({ news, olds = {}, output }) {
29
37
  if (!isResolved(news))
30
38
  return undefined;
@@ -44,6 +52,17 @@ export const StorageBucketIamMemberProvider = () => Provider.effect(StorageBucke
44
52
  (priorMember && priorMember !== news.member)) {
45
53
  return { action: "replace" };
46
54
  }
55
+ // Condition expression is identity too — but only when a prior
56
+ // identity exists at all (a partially-persisted record with no
57
+ // bucket names no grant to revoke). Absent condition compares
58
+ // as "" so unconditional↔conditional flips replace, while a
59
+ // 0.10.x record (no condition attribute) vs. unconditional
60
+ // props stays a no-op.
61
+ const priorCond = output?.condition?.expression ?? olds.condition?.expression ?? "";
62
+ const newsCond = news.condition?.expression ?? "";
63
+ if (priorBucket && priorCond !== newsCond) {
64
+ return { action: "replace" };
65
+ }
47
66
  return undefined;
48
67
  }),
49
68
  reconcile: Effect.fn(function* ({ news }) {
@@ -54,25 +73,45 @@ export const StorageBucketIamMemberProvider = () => Provider.effect(StorageBucke
54
73
  }).pipe(Effect.catchTag("NotFound", () => Effect.fail(new ConfigError({
55
74
  message: `Bucket ${news.bucket} does not exist — StorageBucketIamMember grants on pre-existing buckets only.`,
56
75
  }))));
57
- if (hasMember(current, news.role, news.member))
76
+ if (hasMember(current, news.role, news.member, news.condition)) {
58
77
  return;
78
+ }
59
79
  const bindings = (current.bindings ?? []).map((b) => ({
60
80
  ...b,
61
81
  members: [...(b.members ?? [])],
62
82
  }));
63
- const existing = bindings.find((b) => b.role === news.role && !b.condition);
83
+ const existing = bindings.find((b) => bindingMatches(b, news.role, news.condition));
64
84
  if (existing) {
65
85
  existing.members = [...(existing.members ?? []), news.member];
66
86
  }
67
87
  else {
68
- bindings.push({ role: news.role, members: [news.member] });
88
+ bindings.push({
89
+ role: news.role,
90
+ members: [news.member],
91
+ ...(news.condition
92
+ ? {
93
+ condition: {
94
+ title: news.condition.title,
95
+ ...(news.condition.description
96
+ ? { description: news.condition.description }
97
+ : {}),
98
+ expression: news.condition.expression,
99
+ },
100
+ }
101
+ : {}),
102
+ });
69
103
  }
70
104
  yield* setIamPolicyBuckets({
71
105
  bucket: news.bucket,
72
106
  body: { ...current, bindings, version: 3 },
73
107
  });
74
108
  }));
75
- return { bucket: news.bucket, role: news.role, member: news.member };
109
+ return {
110
+ bucket: news.bucket,
111
+ role: news.role,
112
+ member: news.member,
113
+ ...(news.condition ? { condition: news.condition } : {}),
114
+ };
76
115
  }),
77
116
  delete: Effect.fn(function* ({ output }) {
78
117
  // Partially-persisted attributes (empty fields) name no real
@@ -87,14 +126,15 @@ export const StorageBucketIamMemberProvider = () => Provider.effect(StorageBucke
87
126
  // Bucket gone (or unreadable because gone) — the grant
88
127
  // went with it; idempotent success.
89
128
  Effect.catchTag("NotFound", () => Effect.succeed(undefined)));
90
- if (!current || !hasMember(current, output.role, output.member)) {
129
+ if (!current ||
130
+ !hasMember(current, output.role, output.member, output.condition)) {
91
131
  return;
92
132
  }
93
- // Remove exactly our member from the unconditional binding;
133
+ // Remove exactly our member from the matched binding;
94
134
  // drop the binding entirely if that empties it (GCS rejects
95
135
  // bindings with zero members).
96
136
  const bindings = (current.bindings ?? [])
97
- .map((b) => b.role === output.role && !b.condition
137
+ .map((b) => bindingMatches(b, output.role, output.condition)
98
138
  ? {
99
139
  ...b,
100
140
  members: (b.members ?? []).filter((m) => m !== output.member),
@@ -111,6 +151,7 @@ export const StorageBucketIamMemberProvider = () => Provider.effect(StorageBucke
111
151
  const bucket = output?.bucket ?? olds?.bucket;
112
152
  const role = output?.role ?? olds?.role;
113
153
  const member = output?.member ?? olds?.member;
154
+ const condition = output?.condition ?? olds?.condition;
114
155
  if (!bucket || !role || !member)
115
156
  return undefined;
116
157
  const current = yield* getIamPolicyBuckets({
@@ -121,9 +162,14 @@ export const StorageBucketIamMemberProvider = () => Provider.effect(StorageBucke
121
162
  return undefined;
122
163
  // Absent member → undefined: the engine treats that as drift
123
164
  // and the next plan re-grants.
124
- if (!hasMember(current, role, member))
165
+ if (!hasMember(current, role, member, condition))
125
166
  return undefined;
126
- return { bucket, role, member };
167
+ return {
168
+ bucket,
169
+ role,
170
+ member,
171
+ ...(condition ? { condition } : {}),
172
+ };
127
173
  }),
128
174
  };
129
175
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"StorageBucketIamMember.js","sourceRoot":"","sources":["../../src/Storage/StorageBucketIamMember.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"StorageBucketIamMember.js","sourceRoot":"","sources":["../../src/Storage/StorageBucketIamMember.ts"],"names":[],"mappings":"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"}
@@ -2,5 +2,5 @@ export { StorageBucket, StorageBucketProvider, } from "./Bucket.ts";
2
2
  export type { StorageBucketProps, StorageBucketIamBinding, StorageBucketBindingContract, } from "./Bucket.ts";
3
3
  export * from "./BucketIamMember.ts";
4
4
  export { StorageBucketIamMember, StorageBucketIamMemberProvider, } from "./StorageBucketIamMember.ts";
5
- export type { StorageBucketIamMemberProps, StorageBucketIamMemberAttributes, } from "./StorageBucketIamMember.ts";
5
+ export type { StorageBucketIamMemberProps, StorageBucketIamMemberAttributes, StorageBucketIamMemberCondition, } from "./StorageBucketIamMember.ts";
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,kBAAkB,EAClB,uBAAuB,EACvB,4BAA4B,GAC7B,MAAM,aAAa,CAAC;AACrB,cAAc,sBAAsB,CAAC;AACrC,OAAO,EACL,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,2BAA2B,EAC3B,gCAAgC,GACjC,MAAM,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,kBAAkB,EAClB,uBAAuB,EACvB,4BAA4B,GAC7B,MAAM,aAAa,CAAC;AACrB,cAAc,sBAAsB,CAAC;AACrC,OAAO,EACL,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,2BAA2B,EAC3B,gCAAgC,EAChC,+BAA+B,GAChC,MAAM,6BAA6B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microagi/alchemy-gcp",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "GCP provider for Alchemy v2 (Effect-based IaC). Resources for Project, ServiceAccount, Cluster, NodePool, Compute, ManagedLustre, ServiceUsage, ServiceNetworking, Cloud Run (Service + Job + IAM), Cloud SQL (Instance + Database + User with IAM database authn), Artifact Registry (Docker repositories, standard + remote pull-through caches), Kubernetes (typed Secret + generic SSA Manifest + Helm release), with ADC-backed credentials and target-side IAM bindings.",
5
5
  "keywords": [
6
6
  "alchemy",
@@ -19,9 +19,20 @@ import type * as GCP from "../Providers.ts";
19
19
  * cannot do — **removes it again on delete**, so grants revoke when the
20
20
  * declaring resource leaves the stack.
21
21
  *
22
- * Identity is the `(bucket, role, member)` triple; all three are
23
- * immutable — changing any replaces (the old triple is revoked, the new
24
- * one granted).
22
+ * Identity is the `(bucket, role, member, condition.expression)` tuple;
23
+ * all are immutable — changing any replaces (the old grant is revoked,
24
+ * the new one granted).
25
+ *
26
+ * With a `condition`, the member lands in the binding whose condition
27
+ * **expression** matches (CEL, compared byte-for-byte) — the binding is
28
+ * created with the given title/description if absent. Title and
29
+ * description are create-time metadata only: an existing binding with
30
+ * the same expression but a different title is adopted as-is, never
31
+ * retitled (that lets hand-applied conditional grants converge into the
32
+ * stack without a duplicate binding). Conditional bindings require the
33
+ * bucket to have uniform bucket-level access (GCS rejects conditions
34
+ * otherwise) and policy version 3 — the read-modify-write here always
35
+ * requests/writes version 3.
25
36
  *
26
37
  * The read-modify-write on the shared bucket policy is member-scoped:
27
38
  * exactly one member is added/removed, every foreign role and member is
@@ -43,7 +54,39 @@ import type * as GCP from "../Providers.ts";
43
54
  * "principal://iam.googleapis.com/projects/864268824536/locations/global/workloadIdentityPools/micro-research-cluster-a.svc.id.goog/subject/ns/collab-srl/sa/default",
44
55
  * });
45
56
  * ```
57
+ *
58
+ * @section Prefix-scoped read on a customer bucket
59
+ * @example Conditional grant limited to one object prefix (+ bucket-level list)
60
+ * ```typescript
61
+ * yield* GCP.StorageBucketIamMember("QaDatasetRead", {
62
+ * bucket: "golden-zone-prod-770927",
63
+ * role: "roles/storage.objectViewer",
64
+ * member: "principal://iam.googleapis.com/…/subject/ns/collab-jeffrey-coworking/sa/default",
65
+ * condition: {
66
+ * title: "collab-jeffrey-coworking",
67
+ * expression:
68
+ * 'resource.name.startsWith("projects/_/buckets/golden-zone-prod-770927/objects/qa/") || resource.name == "projects/_/buckets/golden-zone-prod-770927"',
69
+ * },
70
+ * });
71
+ * ```
46
72
  */
73
+ export type StorageBucketIamMemberCondition = {
74
+ /**
75
+ * Binding title — create-time metadata only. NOT identity: a live
76
+ * binding with the same expression but another title is adopted, not
77
+ * retitled/replaced.
78
+ */
79
+ title: string;
80
+ /** Optional human note on the binding. Create-time metadata only. */
81
+ description?: string;
82
+ /**
83
+ * CEL condition expression. Part of the resource identity — compared
84
+ * byte-for-byte against live bindings' expressions, so keep the
85
+ * rendering deterministic. Immutable — replace.
86
+ */
87
+ expression: string;
88
+ };
89
+
47
90
  export type StorageBucketIamMemberProps = {
48
91
  /**
49
92
  * Name of the (pre-existing) GCS bucket to grant on. The bucket is
@@ -58,6 +101,14 @@ export type StorageBucketIamMemberProps = {
58
101
  * `group:…`, …). Immutable — replace.
59
102
  */
60
103
  member: string;
104
+ /**
105
+ * Optional IAM Condition scoping the grant (e.g. to an object
106
+ * prefix). Absent → the member joins the role's UNCONDITIONAL
107
+ * binding. The condition **expression** is identity (immutable —
108
+ * replace); title/description are create-time metadata. Requires
109
+ * uniform bucket-level access on the bucket.
110
+ */
111
+ condition?: StorageBucketIamMemberCondition;
61
112
  };
62
113
 
63
114
  export type StorageBucketIamMemberAttributes = {
@@ -67,6 +118,8 @@ export type StorageBucketIamMemberAttributes = {
67
118
  role: string;
68
119
  /** IAM member, threaded through from props. */
69
120
  member: string;
121
+ /** IAM Condition, threaded through from props (absent = unconditional). */
122
+ condition?: StorageBucketIamMemberCondition;
70
123
  };
71
124
 
72
125
  export type StorageBucketIamMember = Resource<
@@ -103,20 +156,36 @@ export const StorageBucketIamMemberProvider = () =>
103
156
  }),
104
157
  );
105
158
 
106
- // Membership check scoped to the unconditional binding for `role`
107
- // conditional bindings are someone else's and never touched.
159
+ // Binding selector: with no condition, ONLY the unconditional
160
+ // binding for `role` (conditional bindings are someone else's);
161
+ // with a condition, the binding whose expression matches
162
+ // byte-for-byte — title/description deliberately ignored so
163
+ // hand-applied grants with the same expression are adopted.
164
+ const bindingMatches = (
165
+ b: { role?: string; condition?: { expression?: string } },
166
+ role: string,
167
+ condition?: StorageBucketIamMemberCondition,
168
+ ) =>
169
+ b.role === role &&
170
+ (condition
171
+ ? b.condition?.expression === condition.expression
172
+ : !b.condition);
173
+
108
174
  const hasMember = (
109
175
  policy: storage.Policy,
110
176
  role: string,
111
177
  member: string,
178
+ condition?: StorageBucketIamMemberCondition,
112
179
  ) =>
113
180
  (policy.bindings ?? []).some(
114
- (b) => b.role === role && !b.condition && (b.members ?? []).includes(member),
181
+ (b) =>
182
+ bindingMatches(b, role, condition) &&
183
+ (b.members ?? []).includes(member),
115
184
  );
116
185
 
117
186
  return {
118
- // Identity IS the triple; all three are static strings.
119
- stables: ["bucket", "role", "member"],
187
+ // Identity IS the tuple; all fields are static values.
188
+ stables: ["bucket", "role", "member", "condition"],
120
189
  diff: Effect.fn(function* ({ news, olds = {}, output }) {
121
190
  if (!isResolved(news)) return undefined;
122
191
  // Prior identity from persisted attributes first, then olds —
@@ -137,6 +206,18 @@ export const StorageBucketIamMemberProvider = () =>
137
206
  ) {
138
207
  return { action: "replace" } as const;
139
208
  }
209
+ // Condition expression is identity too — but only when a prior
210
+ // identity exists at all (a partially-persisted record with no
211
+ // bucket names no grant to revoke). Absent condition compares
212
+ // as "" so unconditional↔conditional flips replace, while a
213
+ // 0.10.x record (no condition attribute) vs. unconditional
214
+ // props stays a no-op.
215
+ const priorCond =
216
+ output?.condition?.expression ?? olds.condition?.expression ?? "";
217
+ const newsCond = news.condition?.expression ?? "";
218
+ if (priorBucket && priorCond !== newsCond) {
219
+ return { action: "replace" } as const;
220
+ }
140
221
  return undefined;
141
222
  }),
142
223
  reconcile: Effect.fn(function* ({ news }) {
@@ -154,19 +235,35 @@ export const StorageBucketIamMemberProvider = () =>
154
235
  ),
155
236
  ),
156
237
  );
157
- if (hasMember(current, news.role, news.member)) return;
238
+ if (hasMember(current, news.role, news.member, news.condition)) {
239
+ return;
240
+ }
158
241
 
159
242
  const bindings = (current.bindings ?? []).map((b) => ({
160
243
  ...b,
161
244
  members: [...(b.members ?? [])],
162
245
  }));
163
- const existing = bindings.find(
164
- (b) => b.role === news.role && !b.condition,
246
+ const existing = bindings.find((b) =>
247
+ bindingMatches(b, news.role, news.condition),
165
248
  );
166
249
  if (existing) {
167
250
  existing.members = [...(existing.members ?? []), news.member];
168
251
  } else {
169
- bindings.push({ role: news.role, members: [news.member] });
252
+ bindings.push({
253
+ role: news.role,
254
+ members: [news.member],
255
+ ...(news.condition
256
+ ? {
257
+ condition: {
258
+ title: news.condition.title,
259
+ ...(news.condition.description
260
+ ? { description: news.condition.description }
261
+ : {}),
262
+ expression: news.condition.expression,
263
+ },
264
+ }
265
+ : {}),
266
+ });
170
267
  }
171
268
  yield* setIamPolicyBuckets({
172
269
  bucket: news.bucket,
@@ -174,7 +271,12 @@ export const StorageBucketIamMemberProvider = () =>
174
271
  });
175
272
  }),
176
273
  );
177
- return { bucket: news.bucket, role: news.role, member: news.member };
274
+ return {
275
+ bucket: news.bucket,
276
+ role: news.role,
277
+ member: news.member,
278
+ ...(news.condition ? { condition: news.condition } : {}),
279
+ };
178
280
  }),
179
281
  delete: Effect.fn(function* ({ output }) {
180
282
  // Partially-persisted attributes (empty fields) name no real
@@ -192,15 +294,18 @@ export const StorageBucketIamMemberProvider = () =>
192
294
  Effect.succeed(undefined as storage.Policy | undefined),
193
295
  ),
194
296
  );
195
- if (!current || !hasMember(current, output.role, output.member)) {
297
+ if (
298
+ !current ||
299
+ !hasMember(current, output.role, output.member, output.condition)
300
+ ) {
196
301
  return;
197
302
  }
198
- // Remove exactly our member from the unconditional binding;
303
+ // Remove exactly our member from the matched binding;
199
304
  // drop the binding entirely if that empties it (GCS rejects
200
305
  // bindings with zero members).
201
306
  const bindings = (current.bindings ?? [])
202
307
  .map((b) =>
203
- b.role === output.role && !b.condition
308
+ bindingMatches(b, output.role, output.condition)
204
309
  ? {
205
310
  ...b,
206
311
  members: (b.members ?? []).filter(
@@ -221,6 +326,7 @@ export const StorageBucketIamMemberProvider = () =>
221
326
  const bucket = output?.bucket ?? olds?.bucket;
222
327
  const role = output?.role ?? olds?.role;
223
328
  const member = output?.member ?? olds?.member;
329
+ const condition = output?.condition ?? olds?.condition;
224
330
  if (!bucket || !role || !member) return undefined;
225
331
  const current = yield* getIamPolicyBuckets({
226
332
  bucket,
@@ -236,8 +342,13 @@ export const StorageBucketIamMemberProvider = () =>
236
342
  if (!current) return undefined;
237
343
  // Absent member → undefined: the engine treats that as drift
238
344
  // and the next plan re-grants.
239
- if (!hasMember(current, role, member)) return undefined;
240
- return { bucket, role, member };
345
+ if (!hasMember(current, role, member, condition)) return undefined;
346
+ return {
347
+ bucket,
348
+ role,
349
+ member,
350
+ ...(condition ? { condition } : {}),
351
+ };
241
352
  }),
242
353
  };
243
354
  }),
@@ -15,4 +15,5 @@ export {
15
15
  export type {
16
16
  StorageBucketIamMemberProps,
17
17
  StorageBucketIamMemberAttributes,
18
+ StorageBucketIamMemberCondition,
18
19
  } from "./StorageBucketIamMember.ts";