@gradientedge/cdk-utils-azure 2.47.0 → 2.49.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.
@@ -3,8 +3,36 @@ import { Output } from '@pulumi/pulumi';
3
3
  import { AzureFunctionApp } from '../function-app/index.js';
4
4
  import { AzureEventHandlerProps, EventHandlerEventGridSubscription, EventHandlerServiceBus } from './types.js';
5
5
  /**
6
- * Provides a construct to create and deploy an Azure EventGrid Event Handler with Service Bus integration
6
+ * Provides a construct to create and deploy an Azure EventGrid Event Handler with Service Bus integration.
7
+ *
8
+ * ## Service Bus configuration
9
+ *
10
+ * The construct manages a Service Bus namespace and queue. Each can independently be created by the
11
+ * construct or resolved from existing Azure resources via the `namespace.useExisting` and
12
+ * `queue.useExisting` flags on {@link EventHandlerServiceBusProps}:
13
+ *
14
+ * | `namespace.useExisting` | `queue.useExisting` | Behaviour |
15
+ * |---|---|---|
16
+ * | `false` | `false` | Create both — the default. Used by single-purpose stacks that own the whole Service Bus surface. |
17
+ * | `true` | `false` | Look up the namespace, create a new queue under it. Use this when one namespace is provisioned by a shared infrastructure stack and multiple event-handler stacks each provision their own queue under it. |
18
+ * | `true` | `true` | Look up both. Cross-stack pattern where the producer/owner of the queue is a different stack (e.g. `WebhookEventHandler` consuming a queue created by `WebhookGateway`). |
19
+ * | `false` | `true` | **Invalid** — construct-time error. You cannot resolve an existing queue under a namespace the construct is creating. |
20
+ *
21
+ * The top-level `serviceBus.useExisting` flag is retained as a deprecated alias that sets both
22
+ * per-resource flags to the same value, so existing callers continue to work unchanged.
23
+ *
24
+ * ## Authorization and the `EVENT_INGEST_SERVICE_BUS` connection string
25
+ *
26
+ * When the construct owns the queue (`queue.useExisting=false`), it provisions a per-queue
27
+ * authorization rule named `listen-send` (scoped to the queue) with `Listen + Send` rights, and the function app's
28
+ * `EVENT_INGEST_SERVICE_BUS` connection string is sourced from that rule. This avoids granting the
29
+ * function app access to sibling queues when the namespace is shared.
30
+ *
31
+ * When the queue is external (`queue.useExisting=true`) the construct does not own auth rules on it
32
+ * and falls back to reading the namespace-level `RootManageSharedAccessKey` for the connection string.
33
+ *
7
34
  * @example
35
+ * // Minimal subclass (defaults — both namespace and queue created by the construct):
8
36
  * import { AzureEventHandler, AzureEventHandlerProps } from '@gradientedge/cdk-utils'
9
37
  *
10
38
  * class CustomConstruct extends AzureEventHandler {
@@ -15,6 +43,30 @@ import { AzureEventHandlerProps, EventHandlerEventGridSubscription, EventHandler
15
43
  * this.initResources()
16
44
  * }
17
45
  * }
46
+ *
47
+ * @example
48
+ * // Shared-namespace pattern — reuse a namespace provisioned by another stack, create a new
49
+ * // queue under it. Useful when multiple event handlers should share a single Service Bus namespace.
50
+ * import * as pulumi from '@pulumi/pulumi'
51
+ *
52
+ * const sharedInfraStack = new pulumi.StackReference('shared-infra')
53
+ * const sharedNamespace = sharedInfraStack.getOutput('serviceBusNamespace')
54
+ *
55
+ * new CustomConstruct('my-event-handler', {
56
+ * ...baseProps,
57
+ * serviceBus: {
58
+ * namespace: {
59
+ * useExisting: true,
60
+ * namespaceName: sharedNamespace.apply((ns) => ns.name),
61
+ * resourceGroupName: sharedNamespace.apply((ns) => ns.resourceGroupName),
62
+ * },
63
+ * queue: {
64
+ * useExisting: false,
65
+ * queueName: 'my-event-queue',
66
+ * },
67
+ * },
68
+ * })
69
+ *
18
70
  * @category Construct
19
71
  */
20
72
  export declare class AzureEventHandler extends AzureFunctionApp {
@@ -44,6 +96,18 @@ export declare class AzureEventHandler extends AzureFunctionApp {
44
96
  * @summary Method to create the dead-letter queue storage container for EventGrid subscriptions
45
97
  */
46
98
  protected createEventGridSubscriptionDlqStorageContainer(): void;
99
+ /**
100
+ * @summary Resolve effective `useExisting` flags for the Service Bus namespace and queue.
101
+ *
102
+ * Per-resource flags (`namespace.useExisting`, `queue.useExisting`) take precedence over the
103
+ * deprecated top-level `serviceBus.useExisting`, which is treated as an alias that sets both.
104
+ * Throws if the invalid combination (namespace.useExisting=false + queue.useExisting=true) is
105
+ * requested — a queue cannot be looked up under a namespace the construct is about to create.
106
+ */
107
+ protected resolveServiceBusUseExisting(): {
108
+ namespace: boolean;
109
+ queue: boolean;
110
+ };
47
111
  /**
48
112
  * @summary Method to create the Service Bus namespace
49
113
  */
@@ -52,16 +116,37 @@ export declare class AzureEventHandler extends AzureFunctionApp {
52
116
  * @summary Method to create the Service Bus queue
53
117
  */
54
118
  protected createServiceBusQueue(): void;
119
+ /**
120
+ * @summary Provision a per-queue Listen+Send authorization rule.
121
+ *
122
+ * Skipped when the construct does not own the queue (`queue.useExisting=true`) — in that case
123
+ * the producer/owner of the queue is responsible for its auth rules and the function app's
124
+ * connection string falls back to the namespace-level root rule in {@link createFunctionAppSiteConfig}.
125
+ *
126
+ * Replaces the previous reliance on `RootManageSharedAccessKey`, which grants Listen+Send+Manage
127
+ * on every queue in the namespace. The new rule narrows the scope to this one queue while keeping
128
+ * Listen+Send so existing function code can both consume and publish through it (Manage is
129
+ * intentionally dropped — a runtime app should not create or delete queues).
130
+ */
131
+ protected createServiceBusQueueAuthorizationRule(): void;
55
132
  /**
56
133
  * @summary Method to create or resolve an existing EventGrid topic
57
134
  */
58
135
  protected createEventGrid(): void;
59
136
  /**
60
- * @summary Method to create the EventGrid event subscription with Service Bus queue destination
137
+ * @summary Method to create the EventGrid event subscription with Service Bus queue destination.
138
+ *
139
+ * Skipped when the construct is reusing an existing queue (the producer/owner of that queue owns
140
+ * the subscription). When the construct creates a new queue — including the case where the queue
141
+ * is new but the parent namespace is externally-managed — the subscription is wired here.
61
142
  */
62
143
  protected createEventGridEventSubscription(): void;
63
144
  /**
64
- * @summary Method to create diagnostic log settings for the Service Bus namespace
145
+ * @summary Method to create diagnostic log settings for the Service Bus namespace.
146
+ *
147
+ * Diagnostic settings live on the namespace, so the construct only registers them when it owns
148
+ * the namespace. When the namespace is external (e.g. provisioned by a shared infrastructure
149
+ * stack), its owner is responsible for diagnostic settings — registering again here would conflict.
65
150
  */
66
151
  protected createServiceBusDiagnosticLog(): void;
67
152
  /**
@@ -72,6 +157,17 @@ export declare class AzureEventHandler extends AzureFunctionApp {
72
157
  * @summary Override to extend the function app site config with service bus connection strings
73
158
  */
74
159
  protected createFunctionAppSiteConfig(): void;
160
+ /**
161
+ * @summary Resolve the connection string injected as `EVENT_INGEST_SERVICE_BUS` on the function app.
162
+ *
163
+ * - When the construct provisioned the queue itself, read from the per-queue Listen-scoped
164
+ * authorization rule created in {@link createServiceBusQueueAuthorizationRule}. Scope is
165
+ * limited to this one queue, which is correct for a shared (per-domain) namespace.
166
+ * - When the queue is external (legacy `WebhookEventHandler` cross-stack pattern), fall back to
167
+ * the namespace-level `RootManageSharedAccessKey` — preserves pre-existing behaviour for that
168
+ * caller shape since the construct does not own the queue and cannot provision a rule on it.
169
+ */
170
+ protected resolveServiceBusConnectionString(): Output<string>;
75
171
  /**
76
172
  * @summary Override to extend the dashboard variables with service bus and event grid specifics
77
173
  */
@@ -1,10 +1,39 @@
1
1
  import { Provider } from '@pulumi/azure-native';
2
2
  import { getTopicOutput } from '@pulumi/azure-native/eventgrid/index.js';
3
- import { getNamespaceOutput, getQueueOutput, listNamespaceKeysOutput } from '@pulumi/azure-native/servicebus/index.js';
3
+ import { getNamespaceOutput, getQueueOutput, listNamespaceKeysOutput, listQueueKeysOutput, } from '@pulumi/azure-native/servicebus/index.js';
4
+ import { AccessRights } from '@pulumi/azure-native/types/enums/servicebus/index.js';
4
5
  import { AzureFunctionApp } from '../function-app/index.js';
5
6
  /**
6
- * Provides a construct to create and deploy an Azure EventGrid Event Handler with Service Bus integration
7
+ * Provides a construct to create and deploy an Azure EventGrid Event Handler with Service Bus integration.
8
+ *
9
+ * ## Service Bus configuration
10
+ *
11
+ * The construct manages a Service Bus namespace and queue. Each can independently be created by the
12
+ * construct or resolved from existing Azure resources via the `namespace.useExisting` and
13
+ * `queue.useExisting` flags on {@link EventHandlerServiceBusProps}:
14
+ *
15
+ * | `namespace.useExisting` | `queue.useExisting` | Behaviour |
16
+ * |---|---|---|
17
+ * | `false` | `false` | Create both — the default. Used by single-purpose stacks that own the whole Service Bus surface. |
18
+ * | `true` | `false` | Look up the namespace, create a new queue under it. Use this when one namespace is provisioned by a shared infrastructure stack and multiple event-handler stacks each provision their own queue under it. |
19
+ * | `true` | `true` | Look up both. Cross-stack pattern where the producer/owner of the queue is a different stack (e.g. `WebhookEventHandler` consuming a queue created by `WebhookGateway`). |
20
+ * | `false` | `true` | **Invalid** — construct-time error. You cannot resolve an existing queue under a namespace the construct is creating. |
21
+ *
22
+ * The top-level `serviceBus.useExisting` flag is retained as a deprecated alias that sets both
23
+ * per-resource flags to the same value, so existing callers continue to work unchanged.
24
+ *
25
+ * ## Authorization and the `EVENT_INGEST_SERVICE_BUS` connection string
26
+ *
27
+ * When the construct owns the queue (`queue.useExisting=false`), it provisions a per-queue
28
+ * authorization rule named `listen-send` (scoped to the queue) with `Listen + Send` rights, and the function app's
29
+ * `EVENT_INGEST_SERVICE_BUS` connection string is sourced from that rule. This avoids granting the
30
+ * function app access to sibling queues when the namespace is shared.
31
+ *
32
+ * When the queue is external (`queue.useExisting=true`) the construct does not own auth rules on it
33
+ * and falls back to reading the namespace-level `RootManageSharedAccessKey` for the connection string.
34
+ *
7
35
  * @example
36
+ * // Minimal subclass (defaults — both namespace and queue created by the construct):
8
37
  * import { AzureEventHandler, AzureEventHandlerProps } from '@gradientedge/cdk-utils'
9
38
  *
10
39
  * class CustomConstruct extends AzureEventHandler {
@@ -15,6 +44,30 @@ import { AzureFunctionApp } from '../function-app/index.js';
15
44
  * this.initResources()
16
45
  * }
17
46
  * }
47
+ *
48
+ * @example
49
+ * // Shared-namespace pattern — reuse a namespace provisioned by another stack, create a new
50
+ * // queue under it. Useful when multiple event handlers should share a single Service Bus namespace.
51
+ * import * as pulumi from '@pulumi/pulumi'
52
+ *
53
+ * const sharedInfraStack = new pulumi.StackReference('shared-infra')
54
+ * const sharedNamespace = sharedInfraStack.getOutput('serviceBusNamespace')
55
+ *
56
+ * new CustomConstruct('my-event-handler', {
57
+ * ...baseProps,
58
+ * serviceBus: {
59
+ * namespace: {
60
+ * useExisting: true,
61
+ * namespaceName: sharedNamespace.apply((ns) => ns.name),
62
+ * resourceGroupName: sharedNamespace.apply((ns) => ns.resourceGroupName),
63
+ * },
64
+ * queue: {
65
+ * useExisting: false,
66
+ * queueName: 'my-event-queue',
67
+ * },
68
+ * },
69
+ * })
70
+ *
18
71
  * @category Construct
19
72
  */
20
73
  export class AzureEventHandler extends AzureFunctionApp {
@@ -49,6 +102,7 @@ export class AzureEventHandler extends AzureFunctionApp {
49
102
  this.createEventGridSubscriptionDlqStorageContainer();
50
103
  this.createServiceBusNamespace();
51
104
  this.createServiceBusQueue();
105
+ this.createServiceBusQueueAuthorizationRule();
52
106
  this.createEventGrid();
53
107
  this.createEventGridEventSubscription();
54
108
  this.createServiceBusDiagnosticLog();
@@ -80,11 +134,35 @@ export class AzureEventHandler extends AzureFunctionApp {
80
134
  resourceGroupName: this.resourceGroup.name,
81
135
  });
82
136
  }
137
+ /**
138
+ * @summary Resolve effective `useExisting` flags for the Service Bus namespace and queue.
139
+ *
140
+ * Per-resource flags (`namespace.useExisting`, `queue.useExisting`) take precedence over the
141
+ * deprecated top-level `serviceBus.useExisting`, which is treated as an alias that sets both.
142
+ * Throws if the invalid combination (namespace.useExisting=false + queue.useExisting=true) is
143
+ * requested — a queue cannot be looked up under a namespace the construct is about to create.
144
+ */
145
+ resolveServiceBusUseExisting() {
146
+ // TODO: remove `deprecatedServiceBusUseExisting` and the `?? deprecatedServiceBusUseExisting`
147
+ // fallbacks once all callers have migrated to the per-resource flags
148
+ // (see EventHandlerServiceBusProps.useExisting in types.ts).
149
+ const deprecatedServiceBusUseExisting = this.props.serviceBus?.useExisting;
150
+ const namespaceUseExisting = this.props.serviceBus?.namespace?.useExisting;
151
+ const queueUseExisting = this.props.serviceBus?.queue?.useExisting;
152
+ const namespace = namespaceUseExisting ?? deprecatedServiceBusUseExisting ?? false;
153
+ const queue = queueUseExisting ?? deprecatedServiceBusUseExisting ?? false;
154
+ if (!namespace && queue) {
155
+ throw new Error(`[${this.id}] invalid serviceBus configuration: queue.useExisting=true requires namespace.useExisting=true ` +
156
+ `(cannot resolve an existing queue under a namespace the construct is creating).`);
157
+ }
158
+ return { namespace, queue };
159
+ }
83
160
  /**
84
161
  * @summary Method to create the Service Bus namespace
85
162
  */
86
163
  createServiceBusNamespace() {
87
- if (this.props.serviceBus?.useExisting && this.props.serviceBus?.namespace?.namespaceName) {
164
+ const useExistingFlags = this.resolveServiceBusUseExisting();
165
+ if (useExistingFlags.namespace && this.props.serviceBus?.namespace?.namespaceName) {
88
166
  this.serviceBus.namespace = getNamespaceOutput({
89
167
  namespaceName: this.props.serviceBus.namespace.namespaceName,
90
168
  resourceGroupName: this.props.serviceBus.namespace.resourceGroupName,
@@ -105,7 +183,8 @@ export class AzureEventHandler extends AzureFunctionApp {
105
183
  * @summary Method to create the Service Bus queue
106
184
  */
107
185
  createServiceBusQueue() {
108
- if (this.props.serviceBus?.useExisting &&
186
+ const useExistingFlags = this.resolveServiceBusUseExisting();
187
+ if (useExistingFlags.queue &&
109
188
  this.props.serviceBus?.namespace?.namespaceName &&
110
189
  this.props.serviceBus?.queue?.queueName) {
111
190
  this.serviceBus.queue = getQueueOutput({
@@ -115,11 +194,17 @@ export class AzureEventHandler extends AzureFunctionApp {
115
194
  });
116
195
  }
117
196
  else {
197
+ // Azure requires the queue's resource group to match its parent namespace's resource group.
198
+ // When the namespace is external, use the namespace's resource group from props;
199
+ // otherwise the construct is creating the namespace alongside the queue in the consumer stack's own resource group.
200
+ const namespaceResourceGroupName = useExistingFlags.namespace
201
+ ? (this.props.serviceBus?.namespace?.resourceGroupName ?? this.resourceGroup.name)
202
+ : this.resourceGroup.name;
118
203
  this.serviceBus.queue = this.serviceBusManager.createServiceBusQueue(this.id, this, {
119
204
  ...this.props.serviceBus?.queue,
120
205
  queueName: this.props.serviceBus?.queue?.queueName ?? this.id,
121
206
  namespaceName: this.serviceBus.namespace.name,
122
- resourceGroupName: this.resourceGroup.name,
207
+ resourceGroupName: namespaceResourceGroupName,
123
208
  });
124
209
  }
125
210
  this.registerOutputs({
@@ -127,6 +212,39 @@ export class AzureEventHandler extends AzureFunctionApp {
127
212
  serviceBusQueueName: this.serviceBus.queue.name,
128
213
  });
129
214
  }
215
+ /**
216
+ * @summary Provision a per-queue Listen+Send authorization rule.
217
+ *
218
+ * Skipped when the construct does not own the queue (`queue.useExisting=true`) — in that case
219
+ * the producer/owner of the queue is responsible for its auth rules and the function app's
220
+ * connection string falls back to the namespace-level root rule in {@link createFunctionAppSiteConfig}.
221
+ *
222
+ * Replaces the previous reliance on `RootManageSharedAccessKey`, which grants Listen+Send+Manage
223
+ * on every queue in the namespace. The new rule narrows the scope to this one queue while keeping
224
+ * Listen+Send so existing function code can both consume and publish through it (Manage is
225
+ * intentionally dropped — a runtime app should not create or delete queues).
226
+ */
227
+ createServiceBusQueueAuthorizationRule() {
228
+ const useExistingFlags = this.resolveServiceBusUseExisting();
229
+ if (useExistingFlags.queue)
230
+ return;
231
+ const namespaceResourceGroupName = useExistingFlags.namespace
232
+ ? (this.props.serviceBus?.namespace?.resourceGroupName ?? this.resourceGroup.name)
233
+ : this.resourceGroup.name;
234
+ // Azure caps `authorizationRuleName` at 50 chars. The rule's scope is the queue itself
235
+ // (`…/namespaces/<ns>/queues/<queue>/authorizationRules/<rule>`), so a literal name is
236
+ // unambiguous and avoids hitting the cap on long stack ids.
237
+ this.serviceBus.queueAuthorizationRule = this.serviceBusManager.createServiceBusQueueAuthorizationRule(this.id, this, {
238
+ authorizationRuleName: 'listen-send',
239
+ namespaceName: this.serviceBus.namespace.name,
240
+ queueName: this.serviceBus.queue.name,
241
+ resourceGroupName: namespaceResourceGroupName,
242
+ rights: [AccessRights.Listen, AccessRights.Send],
243
+ });
244
+ this.registerOutputs({
245
+ serviceBusQueueAuthorizationRuleId: this.serviceBus.queueAuthorizationRule.id,
246
+ });
247
+ }
130
248
  /**
131
249
  * @summary Method to create or resolve an existing EventGrid topic
132
250
  */
@@ -157,10 +275,15 @@ export class AzureEventHandler extends AzureFunctionApp {
157
275
  }
158
276
  }
159
277
  /**
160
- * @summary Method to create the EventGrid event subscription with Service Bus queue destination
278
+ * @summary Method to create the EventGrid event subscription with Service Bus queue destination.
279
+ *
280
+ * Skipped when the construct is reusing an existing queue (the producer/owner of that queue owns
281
+ * the subscription). When the construct creates a new queue — including the case where the queue
282
+ * is new but the parent namespace is externally-managed — the subscription is wired here.
161
283
  */
162
284
  createEventGridEventSubscription() {
163
- if (this.props.serviceBus?.useExisting || !this.eventGridEventSubscription.dlqStorageAccount)
285
+ const useExistingFlags = this.resolveServiceBusUseExisting();
286
+ if (useExistingFlags.queue || !this.eventGridEventSubscription.dlqStorageAccount)
164
287
  return;
165
288
  this.eventGridEventSubscription.eventSubscription = this.eventgridManager.createEventgridSubscription(this.id, this, {
166
289
  ...this.props.eventGridEventSubscription,
@@ -178,10 +301,15 @@ export class AzureEventHandler extends AzureFunctionApp {
178
301
  });
179
302
  }
180
303
  /**
181
- * @summary Method to create diagnostic log settings for the Service Bus namespace
304
+ * @summary Method to create diagnostic log settings for the Service Bus namespace.
305
+ *
306
+ * Diagnostic settings live on the namespace, so the construct only registers them when it owns
307
+ * the namespace. When the namespace is external (e.g. provisioned by a shared infrastructure
308
+ * stack), its owner is responsible for diagnostic settings — registering again here would conflict.
182
309
  */
183
310
  createServiceBusDiagnosticLog() {
184
- if (this.props.serviceBus?.useExisting)
311
+ const useExistingFlags = this.resolveServiceBusUseExisting();
312
+ if (useExistingFlags.namespace)
185
313
  return;
186
314
  this.monitorManager.createMonitorDiagnosticSettings(this.id, this, {
187
315
  name: `${this.id}-servicebus`,
@@ -230,15 +358,40 @@ export class AzureEventHandler extends AzureFunctionApp {
230
358
  this.appConnectionStrings = [
231
359
  {
232
360
  name: 'EVENT_INGEST_SERVICE_BUS',
233
- value: listNamespaceKeysOutput({
234
- resourceGroupName: this.props.serviceBus?.namespace?.resourceGroupName ?? this.resourceGroup.name,
235
- namespaceName: this.serviceBus.namespace.name,
236
- authorizationRuleName: 'RootManageSharedAccessKey',
237
- }).primaryConnectionString,
361
+ value: this.resolveServiceBusConnectionString(),
238
362
  type: 'ServiceBus',
239
363
  },
240
364
  ];
241
365
  }
366
+ /**
367
+ * @summary Resolve the connection string injected as `EVENT_INGEST_SERVICE_BUS` on the function app.
368
+ *
369
+ * - When the construct provisioned the queue itself, read from the per-queue Listen-scoped
370
+ * authorization rule created in {@link createServiceBusQueueAuthorizationRule}. Scope is
371
+ * limited to this one queue, which is correct for a shared (per-domain) namespace.
372
+ * - When the queue is external (legacy `WebhookEventHandler` cross-stack pattern), fall back to
373
+ * the namespace-level `RootManageSharedAccessKey` — preserves pre-existing behaviour for that
374
+ * caller shape since the construct does not own the queue and cannot provision a rule on it.
375
+ */
376
+ resolveServiceBusConnectionString() {
377
+ if (this.serviceBus.queueAuthorizationRule) {
378
+ const useExistingFlags = this.resolveServiceBusUseExisting();
379
+ const namespaceResourceGroupName = useExistingFlags.namespace
380
+ ? (this.props.serviceBus?.namespace?.resourceGroupName ?? this.resourceGroup.name)
381
+ : this.resourceGroup.name;
382
+ return listQueueKeysOutput({
383
+ resourceGroupName: namespaceResourceGroupName,
384
+ namespaceName: this.serviceBus.namespace.name,
385
+ queueName: this.serviceBus.queue.name,
386
+ authorizationRuleName: this.serviceBus.queueAuthorizationRule.name,
387
+ }).primaryConnectionString;
388
+ }
389
+ return listNamespaceKeysOutput({
390
+ resourceGroupName: this.props.serviceBus?.namespace?.resourceGroupName ?? this.resourceGroup.name,
391
+ namespaceName: this.serviceBus.namespace.name,
392
+ authorizationRuleName: 'RootManageSharedAccessKey',
393
+ }).primaryConnectionString;
394
+ }
242
395
  /**
243
396
  * @summary Override to extend the dashboard variables with service bus and event grid specifics
244
397
  */
@@ -1,5 +1,5 @@
1
1
  import { EventSubscription } from '@pulumi/azure-native/eventgrid/index.js';
2
- import { GetNamespaceResult, GetQueueResult, Namespace, Queue } from '@pulumi/azure-native/servicebus/index.js';
2
+ import { GetNamespaceResult, GetQueueResult, Namespace, Queue, QueueAuthorizationRule } from '@pulumi/azure-native/servicebus/index.js';
3
3
  import { BlobContainer, StorageAccount } from '@pulumi/azure-native/storage/index.js';
4
4
  import { Input, Output } from '@pulumi/pulumi';
5
5
  import { DefenderForStorageProps, EventgridEventSubscriptionProps, EventgridTopicProps, ServiceBusNamespaceProps, ServiceBusQueueProps, StorageAccountProps, StorageContainerProps } from '../../services/index.js';
@@ -27,15 +27,47 @@ export interface EventHandlerEventGridSubscription {
27
27
  eventSubscription?: EventSubscription;
28
28
  }
29
29
  /**
30
- * Properties for configuring the Service Bus integration in the event handler
30
+ * Properties for configuring the Service Bus namespace inside the event handler.
31
+ * Wraps {@link ServiceBusNamespaceProps} with a `useExisting` flag controlling
32
+ * whether the construct creates the namespace or resolves an existing one.
33
+ * @category Interface
34
+ */
35
+ export interface EventHandlerServiceBusNamespaceProps extends ServiceBusNamespaceProps {
36
+ /** When true, resolves an existing namespace via getNamespaceOutput instead of creating one */
37
+ useExisting?: boolean;
38
+ }
39
+ /**
40
+ * Properties for configuring the Service Bus queue inside the event handler.
41
+ * Wraps {@link ServiceBusQueueProps} with a `useExisting` flag controlling
42
+ * whether the construct creates the queue or resolves an existing one.
43
+ * @category Interface
44
+ */
45
+ export interface EventHandlerServiceBusQueueProps extends ServiceBusQueueProps {
46
+ /** When true, resolves an existing queue via getQueueOutput instead of creating one */
47
+ useExisting?: boolean;
48
+ }
49
+ /**
50
+ * Properties for configuring the Service Bus integration in the event handler.
51
+ *
52
+ * `namespace.useExisting` and `queue.useExisting` are independent. The supported combinations are:
53
+ * - `namespace.useExisting=false, queue.useExisting=false` — create both (default)
54
+ * - `namespace.useExisting=true, queue.useExisting=false` — reuse an existing (e.g. shared) namespace, create a new queue under it
55
+ * - `namespace.useExisting=true, queue.useExisting=true` — reuse both (cross-stack reference to a queue someone else owns)
56
+ * - `namespace.useExisting=false, queue.useExisting=true` — invalid; construct throws at construct-time
31
57
  * @category Interface
32
58
  */
33
59
  export interface EventHandlerServiceBusProps {
34
- /** Service Bus namespace properties */
35
- namespace?: ServiceBusNamespaceProps;
36
- /** Service Bus queue properties */
37
- queue?: ServiceBusQueueProps;
38
- /** When true, resolves an existing Service Bus instead of creating a new one */
60
+ /** Service Bus namespace properties (extends {@link ServiceBusNamespaceProps} with `useExisting`) */
61
+ namespace?: EventHandlerServiceBusNamespaceProps;
62
+ /** Service Bus queue properties (extends {@link ServiceBusQueueProps} with `useExisting`) */
63
+ queue?: EventHandlerServiceBusQueueProps;
64
+ /**
65
+ * Convenience alias that sets both `namespace.useExisting` and `queue.useExisting` to the same value.
66
+ * @deprecated Prefer `namespace.useExisting` and `queue.useExisting` individually. Retained as an alias
67
+ * so existing callers (e.g. WebhookEventHandler) continue to compile unchanged.
68
+ * TODO: remove once all callers have migrated to the per-resource flags. Also remove the
69
+ * resolution fallback in `resolveServiceBusUseExisting()` in main.ts.
70
+ */
39
71
  useExisting?: boolean;
40
72
  }
41
73
  /**
@@ -47,6 +79,13 @@ export interface EventHandlerServiceBus {
47
79
  namespace: Namespace | Output<GetNamespaceResult>;
48
80
  /** The provisioned or resolved Service Bus queue */
49
81
  queue: Queue | Output<GetQueueResult>;
82
+ /**
83
+ * Per-queue authorization rule (Listen+Send) used to build the function app's
84
+ * `EVENT_INGEST_SERVICE_BUS` connection string. Provisioned only when the
85
+ * construct owns the queue (`queue.useExisting=false`); undefined when the
86
+ * queue is external and the connection string falls back to the namespace-level rule.
87
+ */
88
+ queueAuthorizationRule?: QueueAuthorizationRule;
50
89
  }
51
90
  /**
52
91
  * Properties for configuring the EventGrid topic in the event handler
@@ -17,5 +17,7 @@ export declare enum RoleDefinitionId {
17
17
  /** Read, write, and delete Azure Storage blob data */
18
18
  STORAGE_BLOB_DATA_CONTRIBUTOR = "/providers/Microsoft.Authorization/roleDefinitions/ba92f5b4-2d11-453d-a403-e96b0029c9fe",
19
19
  /** Read, write, and delete Azure Storage table data */
20
- STORAGE_TABLE_DATA_CONTRIBUTOR = "/providers/Microsoft.Authorization/roleDefinitions/0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3"
20
+ STORAGE_TABLE_DATA_CONTRIBUTOR = "/providers/Microsoft.Authorization/roleDefinitions/0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3",
21
+ /** Full data-plane + management access on Service Bus namespaces (create queues/topics, listKeys on auth rules, send/receive) */
22
+ AZURE_SERVICE_BUS_DATA_OWNER = "/providers/Microsoft.Authorization/roleDefinitions/090c5cfd-751d-490a-894a-3ce6f1109419"
21
23
  }
@@ -19,4 +19,6 @@ export var RoleDefinitionId;
19
19
  RoleDefinitionId["STORAGE_BLOB_DATA_CONTRIBUTOR"] = "/providers/Microsoft.Authorization/roleDefinitions/ba92f5b4-2d11-453d-a403-e96b0029c9fe";
20
20
  /** Read, write, and delete Azure Storage table data */
21
21
  RoleDefinitionId["STORAGE_TABLE_DATA_CONTRIBUTOR"] = "/providers/Microsoft.Authorization/roleDefinitions/0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3";
22
+ /** Full data-plane + management access on Service Bus namespaces (create queues/topics, listKeys on auth rules, send/receive) */
23
+ RoleDefinitionId["AZURE_SERVICE_BUS_DATA_OWNER"] = "/providers/Microsoft.Authorization/roleDefinitions/090c5cfd-751d-490a-894a-3ce6f1109419";
22
24
  })(RoleDefinitionId || (RoleDefinitionId = {}));
@@ -1,6 +1,6 @@
1
1
  import { ResourceOptions } from '@pulumi/pulumi';
2
2
  import { CommonAzureConstruct } from '../../common/index.js';
3
- import { ResolveServicebusQueueProps, ServiceBusNamespaceProps, ServiceBusQueueProps, ServiceBusSubscriptionProps, ServiceBusTopicProps } from './types.js';
3
+ import { ResolveServicebusQueueProps, ServiceBusNamespaceProps, ServiceBusQueueAuthorizationRuleProps, ServiceBusQueueProps, ServiceBusSubscriptionProps, ServiceBusTopicProps } from './types.js';
4
4
  /**
5
5
  * Provides operations on Azure Servicebus using Pulumi
6
6
  * - A new instance of this class is injected into {@link CommonAzureConstruct} constructor.
@@ -47,6 +47,15 @@ export declare class AzureServiceBusManager {
47
47
  * @see [Pulumi Azure Native Service Bus Queue]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/service bus/queue/}
48
48
  */
49
49
  createServiceBusQueue(id: string, scope: CommonAzureConstruct, props: ServiceBusQueueProps, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/servicebus/queue.js").Queue;
50
+ /**
51
+ * @summary Method to create a new service bus queue authorization rule
52
+ * @param id scoped id of the resource
53
+ * @param scope scope in which this resource is defined
54
+ * @param props service bus queue authorization rule properties
55
+ * @param resourceOptions Optional settings to control resource behaviour
56
+ * @see [Pulumi Azure Native Service Bus Queue Authorization Rule]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/servicebus/queueauthorizationrule/}
57
+ */
58
+ createServiceBusQueueAuthorizationRule(id: string, scope: CommonAzureConstruct, props: ServiceBusQueueAuthorizationRuleProps, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/servicebus/queueAuthorizationRule.js").QueueAuthorizationRule;
50
59
  /**
51
60
  * @summary Method to create a new service bus subscription
52
61
  * @param id scoped id of the resource
@@ -1,4 +1,4 @@
1
- import { getQueueOutput, ManagedServiceIdentityType, Namespace, Queue, SkuName, Subscription, Topic, } from '@pulumi/azure-native/servicebus/index.js';
1
+ import { getQueueOutput, ManagedServiceIdentityType, Namespace, Queue, QueueAuthorizationRule, SkuName, Subscription, Topic, } from '@pulumi/azure-native/servicebus/index.js';
2
2
  /**
3
3
  * Provides operations on Azure Servicebus using Pulumi
4
4
  * - A new instance of this class is injected into {@link CommonAzureConstruct} constructor.
@@ -87,6 +87,19 @@ export class AzureServiceBusManager {
87
87
  enablePartitioning: props.enablePartitioning ?? false,
88
88
  }, { parent: scope, ...resourceOptions });
89
89
  }
90
+ /**
91
+ * @summary Method to create a new service bus queue authorization rule
92
+ * @param id scoped id of the resource
93
+ * @param scope scope in which this resource is defined
94
+ * @param props service bus queue authorization rule properties
95
+ * @param resourceOptions Optional settings to control resource behaviour
96
+ * @see [Pulumi Azure Native Service Bus Queue Authorization Rule]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/servicebus/queueauthorizationrule/}
97
+ */
98
+ createServiceBusQueueAuthorizationRule(id, scope, props, resourceOptions) {
99
+ if (!props)
100
+ throw new Error(`Props undefined for ${id}`);
101
+ return new QueueAuthorizationRule(`${id}-sqar`, { ...props }, { parent: scope, ...resourceOptions });
102
+ }
90
103
  /**
91
104
  * @summary Method to create a new service bus subscription
92
105
  * @param id scoped id of the resource
@@ -1,4 +1,4 @@
1
- import { GetQueueOutputArgs, NamespaceArgs, QueueArgs, SubscriptionArgs, TopicArgs } from '@pulumi/azure-native/servicebus/index.js';
1
+ import { GetQueueOutputArgs, NamespaceArgs, QueueArgs, QueueAuthorizationRuleArgs, SubscriptionArgs, TopicArgs } from '@pulumi/azure-native/servicebus/index.js';
2
2
  /**
3
3
  * Properties for creating a Service Bus namespace
4
4
  * @see [Pulumi Azure Native Service Bus Namespace]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/servicebus/namespace/}
@@ -20,6 +20,13 @@ export interface ServiceBusTopicProps extends TopicArgs {
20
20
  */
21
21
  export interface ServiceBusQueueProps extends QueueArgs {
22
22
  }
23
+ /**
24
+ * Properties for creating a Service Bus queue authorization rule
25
+ * @see [Pulumi Azure Native Service Bus Queue Authorization Rule]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/servicebus/queueauthorizationrule/}
26
+ * @category Interface
27
+ */
28
+ export interface ServiceBusQueueAuthorizationRuleProps extends QueueAuthorizationRuleArgs {
29
+ }
23
30
  /**
24
31
  * Properties for creating a Service Bus subscription
25
32
  * @see [Pulumi Azure Native Service Bus Subscription]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/servicebus/subscription/}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradientedge/cdk-utils-azure",
3
- "version": "2.47.0",
3
+ "version": "2.49.0",
4
4
  "description": "Azure Pulumi utilities for @gradientedge/cdk-utils",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",