@superblocksteam/shared 0.9603.3 → 0.9604.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.
Files changed (136) hide show
  1. package/dist/database-lifecycle/capacityPolicy.d.ts +51 -0
  2. package/dist/database-lifecycle/capacityPolicy.d.ts.map +1 -0
  3. package/dist/database-lifecycle/capacityPolicy.js +159 -0
  4. package/dist/database-lifecycle/capacityPolicy.js.map +1 -0
  5. package/dist/database-lifecycle/capacityPolicy.test.d.ts +2 -0
  6. package/dist/database-lifecycle/capacityPolicy.test.d.ts.map +1 -0
  7. package/dist/database-lifecycle/capacityPolicy.test.js +159 -0
  8. package/dist/database-lifecycle/capacityPolicy.test.js.map +1 -0
  9. package/dist/database-lifecycle/edit-lifecycle-capability.d.ts +18 -0
  10. package/dist/database-lifecycle/edit-lifecycle-capability.d.ts.map +1 -0
  11. package/dist/database-lifecycle/edit-lifecycle-capability.js +32 -0
  12. package/dist/database-lifecycle/edit-lifecycle-capability.js.map +1 -0
  13. package/dist/database-lifecycle/edit-lifecycle-capability.test.d.ts +2 -0
  14. package/dist/database-lifecycle/edit-lifecycle-capability.test.d.ts.map +1 -0
  15. package/dist/database-lifecycle/edit-lifecycle-capability.test.js +91 -0
  16. package/dist/database-lifecycle/edit-lifecycle-capability.test.js.map +1 -0
  17. package/dist/database-lifecycle/index.d.ts +50 -27
  18. package/dist/database-lifecycle/index.d.ts.map +1 -1
  19. package/dist/database-lifecycle/index.js +78 -54
  20. package/dist/database-lifecycle/index.js.map +1 -1
  21. package/dist/database-lifecycle/index.test.js +120 -77
  22. package/dist/database-lifecycle/index.test.js.map +1 -1
  23. package/dist/database-lifecycle/physicalPoolIdentity.d.ts +29 -0
  24. package/dist/database-lifecycle/physicalPoolIdentity.d.ts.map +1 -0
  25. package/dist/database-lifecycle/physicalPoolIdentity.js +64 -0
  26. package/dist/database-lifecycle/physicalPoolIdentity.js.map +1 -0
  27. package/dist/database-lifecycle/physicalPoolIdentity.test.d.ts +2 -0
  28. package/dist/database-lifecycle/physicalPoolIdentity.test.d.ts.map +1 -0
  29. package/dist/database-lifecycle/physicalPoolIdentity.test.js +51 -0
  30. package/dist/database-lifecycle/physicalPoolIdentity.test.js.map +1 -0
  31. package/dist/index.d.ts +1 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +1 -0
  34. package/dist/index.js.map +1 -1
  35. package/dist/types/audit/ocsf.d.ts +60 -6
  36. package/dist/types/audit/ocsf.d.ts.map +1 -1
  37. package/dist/types/audit/ocsf.js +12 -1
  38. package/dist/types/audit/ocsf.js.map +1 -1
  39. package/dist/types/deployment/deployQueueStatus.d.ts +13 -0
  40. package/dist/types/deployment/deployQueueStatus.d.ts.map +1 -1
  41. package/dist/types/deployment/index.d.ts +1 -1
  42. package/dist/types/deployment/index.d.ts.map +1 -1
  43. package/dist/types/deployment/index.js.map +1 -1
  44. package/dist/types/policyGate/index.d.ts +5 -0
  45. package/dist/types/policyGate/index.d.ts.map +1 -1
  46. package/dist/types/policyGate/index.js +5 -1
  47. package/dist/types/policyGate/index.js.map +1 -1
  48. package/dist/types/publishPipeline/plan.js +1 -1
  49. package/dist/types/publishPipeline/plan.js.map +1 -1
  50. package/dist/types/publishPipeline/plan.test.js +3 -3
  51. package/dist/types/publishPipeline/plan.test.js.map +1 -1
  52. package/dist/types/rbac/index.d.ts +2 -0
  53. package/dist/types/rbac/index.d.ts.map +1 -1
  54. package/dist/types/rbac/index.js +3 -1
  55. package/dist/types/rbac/index.js.map +1 -1
  56. package/dist/types/reviewPolicy/index.d.ts +30 -4
  57. package/dist/types/reviewPolicy/index.d.ts.map +1 -1
  58. package/dist/types/reviewPolicy/index.js +8 -1
  59. package/dist/types/reviewPolicy/index.js.map +1 -1
  60. package/dist-esm/database-lifecycle/capacityPolicy.d.ts +51 -0
  61. package/dist-esm/database-lifecycle/capacityPolicy.d.ts.map +1 -0
  62. package/dist-esm/database-lifecycle/capacityPolicy.js +150 -0
  63. package/dist-esm/database-lifecycle/capacityPolicy.js.map +1 -0
  64. package/dist-esm/database-lifecycle/capacityPolicy.test.d.ts +2 -0
  65. package/dist-esm/database-lifecycle/capacityPolicy.test.d.ts.map +1 -0
  66. package/dist-esm/database-lifecycle/capacityPolicy.test.js +157 -0
  67. package/dist-esm/database-lifecycle/capacityPolicy.test.js.map +1 -0
  68. package/dist-esm/database-lifecycle/edit-lifecycle-capability.d.ts +18 -0
  69. package/dist-esm/database-lifecycle/edit-lifecycle-capability.d.ts.map +1 -0
  70. package/dist-esm/database-lifecycle/edit-lifecycle-capability.js +29 -0
  71. package/dist-esm/database-lifecycle/edit-lifecycle-capability.js.map +1 -0
  72. package/dist-esm/database-lifecycle/edit-lifecycle-capability.test.d.ts +2 -0
  73. package/dist-esm/database-lifecycle/edit-lifecycle-capability.test.d.ts.map +1 -0
  74. package/dist-esm/database-lifecycle/edit-lifecycle-capability.test.js +89 -0
  75. package/dist-esm/database-lifecycle/edit-lifecycle-capability.test.js.map +1 -0
  76. package/dist-esm/database-lifecycle/index.d.ts +50 -27
  77. package/dist-esm/database-lifecycle/index.d.ts.map +1 -1
  78. package/dist-esm/database-lifecycle/index.js +62 -51
  79. package/dist-esm/database-lifecycle/index.js.map +1 -1
  80. package/dist-esm/database-lifecycle/index.test.js +90 -47
  81. package/dist-esm/database-lifecycle/index.test.js.map +1 -1
  82. package/dist-esm/database-lifecycle/physicalPoolIdentity.d.ts +29 -0
  83. package/dist-esm/database-lifecycle/physicalPoolIdentity.d.ts.map +1 -0
  84. package/dist-esm/database-lifecycle/physicalPoolIdentity.js +59 -0
  85. package/dist-esm/database-lifecycle/physicalPoolIdentity.js.map +1 -0
  86. package/dist-esm/database-lifecycle/physicalPoolIdentity.test.d.ts +2 -0
  87. package/dist-esm/database-lifecycle/physicalPoolIdentity.test.d.ts.map +1 -0
  88. package/dist-esm/database-lifecycle/physicalPoolIdentity.test.js +49 -0
  89. package/dist-esm/database-lifecycle/physicalPoolIdentity.test.js.map +1 -0
  90. package/dist-esm/index.d.ts +1 -0
  91. package/dist-esm/index.d.ts.map +1 -1
  92. package/dist-esm/index.js +1 -0
  93. package/dist-esm/index.js.map +1 -1
  94. package/dist-esm/types/audit/ocsf.d.ts +60 -6
  95. package/dist-esm/types/audit/ocsf.d.ts.map +1 -1
  96. package/dist-esm/types/audit/ocsf.js +12 -1
  97. package/dist-esm/types/audit/ocsf.js.map +1 -1
  98. package/dist-esm/types/deployment/deployQueueStatus.d.ts +13 -0
  99. package/dist-esm/types/deployment/deployQueueStatus.d.ts.map +1 -1
  100. package/dist-esm/types/deployment/index.d.ts +1 -1
  101. package/dist-esm/types/deployment/index.d.ts.map +1 -1
  102. package/dist-esm/types/deployment/index.js.map +1 -1
  103. package/dist-esm/types/policyGate/index.d.ts +5 -0
  104. package/dist-esm/types/policyGate/index.d.ts.map +1 -1
  105. package/dist-esm/types/policyGate/index.js +5 -1
  106. package/dist-esm/types/policyGate/index.js.map +1 -1
  107. package/dist-esm/types/publishPipeline/plan.js +1 -1
  108. package/dist-esm/types/publishPipeline/plan.js.map +1 -1
  109. package/dist-esm/types/publishPipeline/plan.test.js +3 -3
  110. package/dist-esm/types/publishPipeline/plan.test.js.map +1 -1
  111. package/dist-esm/types/rbac/index.d.ts +2 -0
  112. package/dist-esm/types/rbac/index.d.ts.map +1 -1
  113. package/dist-esm/types/rbac/index.js +3 -1
  114. package/dist-esm/types/rbac/index.js.map +1 -1
  115. package/dist-esm/types/reviewPolicy/index.d.ts +30 -4
  116. package/dist-esm/types/reviewPolicy/index.d.ts.map +1 -1
  117. package/dist-esm/types/reviewPolicy/index.js +7 -0
  118. package/dist-esm/types/reviewPolicy/index.js.map +1 -1
  119. package/package.json +1 -1
  120. package/src/database-lifecycle/capacityPolicy.test.ts +209 -0
  121. package/src/database-lifecycle/capacityPolicy.ts +197 -0
  122. package/src/database-lifecycle/edit-lifecycle-capability.test.ts +116 -0
  123. package/src/database-lifecycle/edit-lifecycle-capability.ts +34 -0
  124. package/src/database-lifecycle/index.test.ts +105 -48
  125. package/src/database-lifecycle/index.ts +157 -90
  126. package/src/database-lifecycle/physicalPoolIdentity.test.ts +64 -0
  127. package/src/database-lifecycle/physicalPoolIdentity.ts +75 -0
  128. package/src/index.ts +1 -0
  129. package/src/types/audit/ocsf.ts +73 -7
  130. package/src/types/deployment/deployQueueStatus.ts +14 -0
  131. package/src/types/deployment/index.ts +2 -1
  132. package/src/types/policyGate/index.ts +5 -1
  133. package/src/types/publishPipeline/plan.test.ts +3 -3
  134. package/src/types/publishPipeline/plan.ts +1 -1
  135. package/src/types/rbac/index.ts +3 -1
  136. package/src/types/reviewPolicy/index.ts +44 -5
@@ -1,13 +1,16 @@
1
1
  import { describe, expect, test } from 'vitest';
2
2
 
3
+ import { ApiTriggerType } from '../types/api/index.js';
3
4
  import {
5
+ DATABASE_LIFECYCLE_MANAGED_BY,
6
+ LIFECYCLE_OPERATIONS,
4
7
  computeBindingKey,
5
8
  computeDesiredSpecHash,
6
9
  computeNativeDbApplicationToken,
7
- computeNativeDbBindingToken,
8
- computeNativeDbDatabaseName,
10
+ computeNativeDbProfileToken,
9
11
  computeRequirementKey,
10
12
  containsCredentialMaterial,
13
+ isLifecycleManagedIntegrationAllowedForApiTrigger,
11
14
  isSecretKey,
12
15
  isTerminalLifecycleState,
13
16
  nativeDbIamSessionPolicy,
@@ -16,6 +19,21 @@ import {
16
19
  } from './index.js';
17
20
 
18
21
  describe('database lifecycle contracts', () => {
22
+ // Postgres `ALTER TYPE ... ADD VALUE` appends. TypeORM's entity-vs-schema
23
+ // check treats enum label order as part of the contract, so this array must
24
+ // match the live `lifecycle_operation_enum` order rather than alphabetical
25
+ // or semantic grouping.
26
+ test('lists lifecycle operations in Postgres enum order', () => {
27
+ expect(LIFECYCLE_OPERATIONS).toEqual(['ensure_database', 'migrate_schema', 'retire_database', 'ensure_physical_database_instance']);
28
+ });
29
+
30
+ test('allows lifecycle-managed integrations only in application APIs', () => {
31
+ expect(isLifecycleManagedIntegrationAllowedForApiTrigger(ApiTriggerType.UI, DATABASE_LIFECYCLE_MANAGED_BY)).toBe(true);
32
+ expect(isLifecycleManagedIntegrationAllowedForApiTrigger(ApiTriggerType.WORKFLOW, DATABASE_LIFECYCLE_MANAGED_BY)).toBe(false);
33
+ expect(isLifecycleManagedIntegrationAllowedForApiTrigger(ApiTriggerType.SCHEDULE, DATABASE_LIFECYCLE_MANAGED_BY)).toBe(false);
34
+ expect(isLifecycleManagedIntegrationAllowedForApiTrigger(ApiTriggerType.WORKFLOW, null)).toBe(true);
35
+ });
36
+
19
37
  test('computes stable requirement, binding, and desired spec identifiers', async () => {
20
38
  const requirement = {
21
39
  logicalName: 'Orders DB',
@@ -32,27 +50,28 @@ describe('database lifecycle contracts', () => {
32
50
  expect(computeRequirementKey({ logicalName: 'orders/db', engine: 'postgres' })).toBe('orders-db~orders%2Fdb:postgres');
33
51
  expect(computeRequirementKey({ logicalName: 'orders-db', engine: 'postgres' })).toBe('orders-db~orders-db:postgres');
34
52
  // binding_key excludes the logical name on purpose: one database per
35
- // (organization, application, environment, profile). Two different logical
36
- // names under the same profile resolve to the same binding_key.
53
+ // (organization, application, profile). Two different logical names under
54
+ // the same profile resolve to the same binding_key.
37
55
  expect(
38
56
  computeBindingKey({
39
57
  organizationId: 'org-1',
40
58
  applicationId: 'app-1',
41
- environment: 'edit',
42
59
  profile: 'Staging EU'
43
60
  })
44
- ).toBe('org-1:app-1:edit:staging-eu~Staging%20EU');
61
+ ).toBe('org-1:app-1:staging-eu~Staging%20EU');
45
62
  expect(
46
63
  computeBindingKey({
47
64
  organizationId: 'org-1',
48
65
  applicationId: 'app-1',
49
- environment: 'edit',
50
66
  profile: 'staging'
51
67
  })
52
- ).toBe('org-1:app-1:edit:staging~staging');
68
+ ).toBe('org-1:app-1:staging~staging');
53
69
 
54
70
  await expect(computeDesiredSpecHash(requirement)).resolves.toBe(
55
- await computeDesiredSpecHash({ ...requirement, extensions: ['uuid-ossp', 'pgcrypto'] })
71
+ await computeDesiredSpecHash({
72
+ ...requirement,
73
+ extensions: ['uuid-ossp', 'pgcrypto']
74
+ })
56
75
  );
57
76
  await expect(computeDesiredSpecHash(requirement)).resolves.toBe('QsCl6RVzJVEwf4Nuk0D27rRtycYe2vQZMxcXLt9WUkQ=');
58
77
  });
@@ -67,8 +86,14 @@ describe('database lifecycle contracts', () => {
67
86
  } as const;
68
87
 
69
88
  const withoutDirectory = await computeDesiredSpecHash(infrastructureSpec);
70
- const withDirectory = await computeDesiredSpecHash({ ...infrastructureSpec, migrationDirectory: 'db/migrations' });
71
- const withOtherDirectory = await computeDesiredSpecHash({ ...infrastructureSpec, migrationDirectory: 'db/other-migrations' });
89
+ const withDirectory = await computeDesiredSpecHash({
90
+ ...infrastructureSpec,
91
+ migrationDirectory: 'db/migrations'
92
+ });
93
+ const withOtherDirectory = await computeDesiredSpecHash({
94
+ ...infrastructureSpec,
95
+ migrationDirectory: 'db/other-migrations'
96
+ });
72
97
 
73
98
  // migrationDirectory only says where the SQL files live, not what
74
99
  // infrastructure to provision, so changing it must not look like drift.
@@ -91,7 +116,7 @@ describe('database lifecycle contracts', () => {
91
116
  expect(first).toBe(second);
92
117
  });
93
118
 
94
- test('redacts raw credential material while preserving credential refs', () => {
119
+ test('redacts raw credential material and generic credential refs while preserving physical masterCredentialRef', () => {
95
120
  const redacted = redactLifecycleSecrets({
96
121
  host: 'db.internal',
97
122
  password: 'raw-password',
@@ -108,6 +133,11 @@ describe('database lifecycle contracts', () => {
108
133
  ref: 'database/orders',
109
134
  field: 'password'
110
135
  }
136
+ },
137
+ masterCredentialRef: {
138
+ resolver: 'aws_secrets_manager',
139
+ ref: 'physical-instance/master',
140
+ field: 'password'
111
141
  }
112
142
  });
113
143
 
@@ -122,11 +152,12 @@ describe('database lifecycle contracts', () => {
122
152
  }
123
153
  },
124
154
  credential_refs: {
125
- password: {
126
- resolver: 'vault',
127
- ref: 'database/orders',
128
- field: 'password'
129
- }
155
+ password: '[REDACTED]'
156
+ },
157
+ masterCredentialRef: {
158
+ resolver: 'aws_secrets_manager',
159
+ ref: 'physical-instance/master',
160
+ field: 'password'
130
161
  }
131
162
  });
132
163
  });
@@ -158,17 +189,17 @@ describe('database lifecycle contracts', () => {
158
189
  test('builds a canonical session policy from a valid managed Postgres IAM descriptor', () => {
159
190
  const descriptor = parseNativeDbIamDescriptor({
160
191
  application_id: 'application-id',
161
- auth_descriptor_version: 1,
192
+ auth_descriptor_version: 3,
162
193
  auth_mode: 'aws_iam_role',
163
194
  aws_account_id: '123456789012',
164
195
  binding_id: 'binding-id',
165
196
  cluster_resource_id: 'cluster-ABC123DEF456EXAMPLE',
166
197
  connector_role_arn: 'arn:aws:iam::123456789012:role/superblocks-native-db-connector-prod',
167
- database: 'sbndb_abcdef123456_0123456789abcdef01234567',
198
+ database: 'sbndb_abcdef1234567890_0123456789abcdef01234567',
168
199
  host: 'native-db.cluster-example.us-west-2.rds.amazonaws.com',
169
200
  port: 5432,
170
201
  region: 'us-west-2',
171
- username: 'sbndb_abcdef123456_7bfeae1170db923274f1943f_runtime'
202
+ username: 'sbndb_abcdef1234567890_0123456789abcdef01234567_runtime'
172
203
  });
173
204
 
174
205
  expect(descriptor).toBeDefined();
@@ -176,57 +207,57 @@ describe('database lifecycle contracts', () => {
176
207
  throw new Error('Expected a valid IAM descriptor');
177
208
  }
178
209
  expect(nativeDbIamSessionPolicy(descriptor)).toBe(
179
- '{"Version":"2012-10-17","Statement":[{"Sid":"ConnectToThisNativeDatabaseUser","Effect":"Allow","Action":"rds-db:connect","Resource":"arn:aws:rds-db:us-west-2:123456789012:dbuser:cluster-ABC123DEF456EXAMPLE/sbndb_abcdef123456_7bfeae1170db923274f1943f_runtime"}]}'
210
+ '{"Version":"2012-10-17","Statement":[{"Sid":"ConnectToThisNativeDatabaseUser","Effect":"Allow","Action":"rds-db:connect","Resource":"arn:aws:rds-db:us-west-2:123456789012:dbuser:cluster-ABC123DEF456EXAMPLE/sbndb_abcdef1234567890_0123456789abcdef01234567_runtime"}]}'
180
211
  );
181
212
  });
182
213
 
183
- test('reads binding-scoped v2 managed Postgres IAM descriptors', () => {
214
+ test('reads managed Postgres IAM descriptors with auth_descriptor_version 3', () => {
184
215
  expect(
185
216
  parseNativeDbIamDescriptor({
186
217
  application_id: 'application-id',
187
- auth_descriptor_version: 2,
218
+ auth_descriptor_version: 3,
188
219
  auth_mode: 'aws_iam_role',
189
220
  aws_account_id: '123456789012',
190
221
  binding_id: 'binding-id',
191
222
  cluster_resource_id: 'cluster-ABC123DEF456EXAMPLE',
192
223
  connector_role_arn: 'arn:aws:iam::123456789012:role/superblocks-native-db-connector-prod',
193
- database: 'sbndb_abcdef123456_0123456789abcdef01234567',
224
+ database: 'sbndb_abcdef1234567890_0123456789abcdef01234567',
194
225
  host: 'native-db.cluster-example.us-west-2.rds.amazonaws.com',
195
226
  port: 5432,
196
227
  region: 'us-west-2',
197
- username: 'sbndb_abcdef123456_0123456789abcdef01234567_runtime'
228
+ username: 'sbndb_abcdef1234567890_0123456789abcdef01234567_runtime'
198
229
  })
199
230
  ).toEqual({
200
231
  application_id: 'application-id',
201
- auth_descriptor_version: 2,
232
+ auth_descriptor_version: 3,
202
233
  auth_mode: 'aws_iam_role',
203
234
  aws_account_id: '123456789012',
204
235
  binding_id: 'binding-id',
205
236
  cluster_resource_id: 'cluster-ABC123DEF456EXAMPLE',
206
237
  connector_role_arn: 'arn:aws:iam::123456789012:role/superblocks-native-db-connector-prod',
207
- database: 'sbndb_abcdef123456_0123456789abcdef01234567',
238
+ database: 'sbndb_abcdef1234567890_0123456789abcdef01234567',
208
239
  host: 'native-db.cluster-example.us-west-2.rds.amazonaws.com',
209
240
  port: 5432,
210
241
  region: 'us-west-2',
211
- username: 'sbndb_abcdef123456_0123456789abcdef01234567_runtime'
242
+ username: 'sbndb_abcdef1234567890_0123456789abcdef01234567_runtime'
212
243
  });
213
244
  });
214
245
 
215
- test('rejects v2 descriptors when database and runtime username use different binding tokens', () => {
246
+ test('rejects descriptors when database and runtime username do not match', () => {
216
247
  expect(
217
248
  parseNativeDbIamDescriptor({
218
249
  application_id: 'application-id',
219
- auth_descriptor_version: 2,
250
+ auth_descriptor_version: 3,
220
251
  auth_mode: 'aws_iam_role',
221
252
  aws_account_id: '123456789012',
222
253
  binding_id: 'binding-id',
223
254
  cluster_resource_id: 'cluster-ABC123DEF456EXAMPLE',
224
255
  connector_role_arn: 'arn:aws:iam::123456789012:role/superblocks-native-db-connector-prod',
225
- database: 'sbndb_abcdef123456_0123456789abcdef01234567',
256
+ database: 'sbndb_abcdef1234567890_0123456789abcdef01234567',
226
257
  host: 'native-db.cluster-example.us-west-2.rds.amazonaws.com',
227
258
  port: 5432,
228
259
  region: 'us-west-2',
229
- username: 'sbndb_abcdef123456_fedcba9876543210fedcba98_runtime'
260
+ username: 'sbndb_abcdef1234567890_fedcba9876543210fedcba98_runtime'
230
261
  })
231
262
  ).toBeUndefined();
232
263
  });
@@ -234,56 +265,82 @@ describe('database lifecycle contracts', () => {
234
265
  test('rejects malformed or non-commercial managed Postgres IAM descriptors', () => {
235
266
  const descriptor = {
236
267
  application_id: 'application-id',
237
- auth_descriptor_version: 1,
268
+ auth_descriptor_version: 3,
238
269
  auth_mode: 'aws_iam_role',
239
270
  aws_account_id: '123456789012',
240
271
  binding_id: 'binding-id',
241
272
  cluster_resource_id: 'cluster-ABC123DEF456EXAMPLE',
242
273
  connector_role_arn: 'arn:aws:iam::123456789012:role/superblocks-native-db-connector-prod',
243
- database: 'sbndb_abcdef123456_0123456789abcdef01234567',
274
+ database: 'sbndb_abcdef1234567890_0123456789abcdef01234567',
244
275
  host: 'native-db.cluster-example.us-west-2.rds.amazonaws.com',
245
276
  port: 5432,
246
277
  region: 'us-west-2',
247
- username: 'sbndb_abcdef123456_7bfeae1170db923274f1943f_runtime'
278
+ username: 'sbndb_abcdef1234567890_0123456789abcdef01234567_runtime'
248
279
  };
249
280
 
250
- expect(parseNativeDbIamDescriptor({ ...descriptor, auth_descriptor_version: 3 })).toBeUndefined();
251
- expect(parseNativeDbIamDescriptor({ ...descriptor, cluster_resource_id: 'not-an-rds-resource' })).toBeUndefined();
252
- expect(parseNativeDbIamDescriptor({ ...descriptor, connector_role_arn: 'arn:aws:iam::210987654321:role/other' })).toBeUndefined();
281
+ expect(parseNativeDbIamDescriptor({ ...descriptor, auth_descriptor_version: 1 })).toBeUndefined();
282
+ expect(parseNativeDbIamDescriptor({ ...descriptor, auth_descriptor_version: 2 })).toBeUndefined();
283
+ expect(
284
+ parseNativeDbIamDescriptor({
285
+ ...descriptor,
286
+ cluster_resource_id: 'not-an-rds-resource'
287
+ })
288
+ ).toBeUndefined();
289
+ expect(
290
+ parseNativeDbIamDescriptor({
291
+ ...descriptor,
292
+ connector_role_arn: 'arn:aws:iam::210987654321:role/other'
293
+ })
294
+ ).toBeUndefined();
253
295
  expect(parseNativeDbIamDescriptor({ ...descriptor, database: 'orders' })).toBeUndefined();
254
- expect(parseNativeDbIamDescriptor({ ...descriptor, host: descriptor.host.toUpperCase() })).toBeUndefined();
255
- expect(parseNativeDbIamDescriptor({ ...descriptor, host: 'native-db.cluster-example.us-east-1.rds.amazonaws.com' })).toBeUndefined();
296
+ expect(
297
+ parseNativeDbIamDescriptor({
298
+ ...descriptor,
299
+ host: descriptor.host.toUpperCase()
300
+ })
301
+ ).toBeUndefined();
302
+ expect(
303
+ parseNativeDbIamDescriptor({
304
+ ...descriptor,
305
+ host: 'native-db.cluster-example.us-east-1.rds.amazonaws.com'
306
+ })
307
+ ).toBeUndefined();
256
308
  expect(parseNativeDbIamDescriptor({ ...descriptor, port: 0 })).toBeUndefined();
257
309
  expect(parseNativeDbIamDescriptor({ ...descriptor, region: 'cn-north-1' })).toBeUndefined();
258
310
  expect(parseNativeDbIamDescriptor({ ...descriptor, region: 'us-gov-west-1' })).toBeUndefined();
259
- expect(parseNativeDbIamDescriptor({ ...descriptor, username: 'sbndb_000000000000_7bfeae1170db923274f1943f_runtime' })).toBeUndefined();
311
+ expect(
312
+ parseNativeDbIamDescriptor({
313
+ ...descriptor,
314
+ username: 'sbndb_0000000000000000_7bfeae1170db923274f1943f_runtime'
315
+ })
316
+ ).toBeUndefined();
260
317
  });
261
318
 
262
319
  test('accepts standalone RDS IAM resource IDs', () => {
263
320
  expect(
264
321
  parseNativeDbIamDescriptor({
265
322
  application_id: 'application-id',
266
- auth_descriptor_version: 1,
323
+ auth_descriptor_version: 3,
267
324
  auth_mode: 'aws_iam_role',
268
325
  aws_account_id: '123456789012',
269
326
  binding_id: 'binding-id',
270
327
  cluster_resource_id: 'db-ABCDEF0123456789-1',
271
328
  connector_role_arn: 'arn:aws:iam::123456789012:role/superblocks-native-db-connector-prod',
272
- database: 'sbndb_abcdef123456_0123456789abcdef01234567',
329
+ database: 'sbndb_abcdef1234567890_0123456789abcdef01234567',
273
330
  host: 'native-db.example.us-west-2.rds.amazonaws.com',
274
331
  port: 5432,
275
332
  region: 'us-west-2',
276
- username: 'sbndb_abcdef123456_7bfeae1170db923274f1943f_runtime'
333
+ username: 'sbndb_abcdef1234567890_0123456789abcdef01234567_runtime'
277
334
  })
278
335
  ).toBeDefined();
279
336
  });
280
337
 
281
- test('derives canonical IAM database and runtime-user identity tokens', async () => {
338
+ test('derives canonical IAM application token', async () => {
282
339
  await expect(computeNativeDbApplicationToken('application-id')).resolves.toBe('7bfeae1170db923274f1943f');
283
- await expect(computeNativeDbDatabaseName('abcdef123456', 'database-id')).resolves.toBe('sbndb_abcdef123456_dad72612f7a80580b028178f');
284
340
  });
285
341
 
286
- test('derives a stable binding identity token for v2 database and runtime-user names', async () => {
287
- await expect(computeNativeDbBindingToken('binding-id')).resolves.toBe('927968fc37b7b41be7e14cf9');
342
+ test('derives canonical IAM profile token', async () => {
343
+ await expect(computeNativeDbProfileToken('production')).resolves.toHaveLength(16);
344
+ await expect(computeNativeDbProfileToken('Production')).resolves.toBe(await computeNativeDbProfileToken('production'));
288
345
  });
289
346
  });