@empire-builder-kit/nx 1.0.0-rc.44 → 1.0.0-rc.46

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 (100) hide show
  1. package/package.json +3 -3
  2. package/src/blueprints/external-sandbox.d.ts +1 -1
  3. package/src/cli/main.d.ts +11 -5
  4. package/src/cli/main.js +88 -29
  5. package/src/container-images.d.ts +1 -1
  6. package/src/container-images.js +1 -1
  7. package/src/developer-agent/generator-planning.js +10 -3
  8. package/src/developer-agent/operation-registry.js +1 -1
  9. package/src/executors/deployment-plan/deployment-plan.js +5 -1
  10. package/src/executors/deployment-plan/schema.json +1 -1
  11. package/src/executors/fleet/fleet.js +4 -0
  12. package/src/executors/fleet/schema.json +1 -1
  13. package/src/executors/github-bootstrap/github-bootstrap.d.ts +3 -0
  14. package/src/executors/github-bootstrap/github-bootstrap.js +28 -0
  15. package/src/executors/github-bootstrap/schema.json +14 -0
  16. package/src/executors/local-deploy/federated-credential-transport.d.ts +4 -3
  17. package/src/executors/local-deploy/federated-credential-transport.js +15 -5
  18. package/src/foundation/cost-estimate.d.ts +8 -3
  19. package/src/foundation/cost-estimate.js +42 -19
  20. package/src/foundation/index.d.ts +1 -0
  21. package/src/foundation/index.js +1 -0
  22. package/src/foundation/local-private-smoke-access.js +6 -0
  23. package/src/foundation/logging.d.ts +3 -1
  24. package/src/foundation/logging.js +8 -1
  25. package/src/foundation/observability.d.ts +42 -0
  26. package/src/foundation/observability.js +181 -0
  27. package/src/foundation/preflight.js +1 -1
  28. package/src/generators/function/function.js +5 -2
  29. package/src/generators/observability-infrastructure.d.ts +2 -0
  30. package/src/generators/observability-infrastructure.js +31 -0
  31. package/src/generators/observability-policy.d.ts +4 -0
  32. package/src/generators/observability-policy.js +23 -0
  33. package/src/generators/preset/dependency-overrides.d.ts +17 -6
  34. package/src/generators/preset/dependency-overrides.js +17 -6
  35. package/src/generators/preset/tool-versions.d.ts +2 -2
  36. package/src/generators/preset/tool-versions.js +2 -2
  37. package/src/generators/preset/workspace-files-adopter-skills.js +28 -17
  38. package/src/generators/preset/workspace-files-agent-development.d.ts +9 -0
  39. package/src/generators/preset/workspace-files-agent-development.js +42 -0
  40. package/src/generators/preset/workspace-files-thin-deploy.js +17 -4
  41. package/src/generators/preset/workspace-files-thin-docs.js +10 -22
  42. package/src/generators/preset/workspace-files.d.ts +1 -0
  43. package/src/generators/preset/workspace-files.js +120 -35
  44. package/src/generators/slice/built-in-plan-alarm-identity.d.ts +173 -0
  45. package/src/generators/slice/built-in-plan-alarm-identity.js +202 -0
  46. package/src/generators/slice/built-in-plan-api-contract-files.js +136 -0
  47. package/src/generators/slice/built-in-plan-data-files.js +10 -3
  48. package/src/generators/slice/built-in-plan-database-lifecycle-files.js +1 -1
  49. package/src/generators/slice/built-in-plan-event-contract-literal.d.ts +6 -0
  50. package/src/generators/slice/built-in-plan-event-contract-literal.js +52 -0
  51. package/src/generators/slice/built-in-plan-infrastructure-files.js +304 -144
  52. package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.js +2 -2
  53. package/src/generators/slice/built-in-plan-metadata-files.js +37 -2
  54. package/src/generators/slice/built-in-plan-operations-files.js +106 -6
  55. package/src/generators/slice/built-in-plan-project-files.js +1 -0
  56. package/src/generators/slice/built-in-plan-release-files.js +2 -44
  57. package/src/generators/slice/built-in-plan-reliability-files.js +222 -236
  58. package/src/generators/slice/built-in-plan-shared.d.ts +29 -3
  59. package/src/generators/slice/built-in-plan-shared.js +29 -2
  60. package/src/generators/slice/built-in-plan-verification-files.js +0 -1
  61. package/src/generators/slice/built-in-plan-web-files.js +22 -6
  62. package/src/generators/slice/built-in-plan.js +2 -2
  63. package/src/generators/slice/slice.js +2 -0
  64. package/src/generators/upgrade/upgrade.d.ts +4 -3
  65. package/src/generators/upgrade/upgrade.js +139 -29
  66. package/src/generators/workload/frozen-container.d.ts +1 -1
  67. package/src/generators/workload/reliability-registration.d.ts +1 -1
  68. package/src/generators/workload/reliability-registration.js +9 -9
  69. package/src/generators/workload/workload.d.ts +1 -1
  70. package/src/generators/workload/workload.js +32 -10
  71. package/src/git-policy/github-bootstrap.d.ts +18 -0
  72. package/src/git-policy/github-bootstrap.js +99 -6
  73. package/src/local-dev/dev-command-core.d.ts +24 -3
  74. package/src/local-dev/dev-command-core.js +124 -12
  75. package/src/local-dev/errors.d.ts +19 -1
  76. package/src/local-dev/errors.js +18 -1
  77. package/src/local-dev/fleet-client.d.ts +64 -6
  78. package/src/local-dev/fleet-client.js +189 -15
  79. package/src/local-dev/fleet-process.d.ts +47 -2
  80. package/src/local-dev/fleet-process.js +248 -31
  81. package/src/local-dev/fleet-runtime.d.ts +37 -0
  82. package/src/local-dev/fleet-runtime.js +127 -69
  83. package/src/local-dev/fleet-session.d.ts +1 -0
  84. package/src/local-dev/fleet-session.js +83 -7
  85. package/src/local-dev/fleet-state.d.ts +5 -0
  86. package/src/local-dev/fleet-state.js +11 -2
  87. package/src/local-dev/fleet-supervisor-daemon.js +1 -5
  88. package/src/local-dev/fleet-supervisor.d.ts +7 -0
  89. package/src/local-dev/fleet-supervisor.js +83 -12
  90. package/src/local-dev/slice-runner.d.ts +19 -1
  91. package/src/local-dev/slice-runner.js +290 -91
  92. package/src/repository-policy/deployment-plan.d.ts +1 -1
  93. package/src/repository-policy/deployment-plan.js +16 -1
  94. package/src/secrets/generated-aws-control-plane.d.ts +11 -1
  95. package/src/secrets/generated-aws-control-plane.js +92 -29
  96. package/src/secrets/operator.d.ts +3 -2
  97. package/src/secrets/operator.js +27 -5
  98. package/src/supply-chain/blueprint-verification-authority.js +24 -3
  99. package/src/supply-chain/generated-files.js +9 -0
  100. package/src/supply-chain/sbom.js +74 -12
@@ -1,16 +1,62 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AwsGeneratedSecretInitializationError = void 0;
4
+ exports.safeGeneratedSecretObservationDiagnostic = safeGeneratedSecretObservationDiagnostic;
4
5
  exports.createAwsGeneratedSecretInitializationControlPlane = createAwsGeneratedSecretInitializationControlPlane;
5
6
  const node_crypto_1 = require("node:crypto");
6
7
  const client_secrets_manager_1 = require("@aws-sdk/client-secrets-manager");
7
8
  const model_js_1 = require("./model.js");
9
+ const observationPhases = ['inspect', 'pre-create', 'post-create'];
10
+ const observationPredicates = [
11
+ 'response-record',
12
+ 'arn-type',
13
+ 'arn-name',
14
+ 'name',
15
+ 'description',
16
+ 'deleted-date',
17
+ 'rotation-enabled',
18
+ 'tags-shape',
19
+ 'tags-count',
20
+ 'tag-entry',
21
+ 'tag-duplicate',
22
+ 'tag-value',
23
+ 'version-state',
24
+ 'not-found',
25
+ ];
26
+ /** Copy only static labels; never invoke getters or retain provider detail. */
27
+ function safeGeneratedSecretObservationDiagnostic(value) {
28
+ try {
29
+ if (!isRecord(value))
30
+ return undefined;
31
+ const descriptors = Object.getOwnPropertyDescriptors(value);
32
+ if (Reflect.ownKeys(descriptors).length !== 2 ||
33
+ !Object.prototype.hasOwnProperty.call(descriptors.phase ?? {}, 'value') ||
34
+ !Object.prototype.hasOwnProperty.call(descriptors.predicate ?? {}, 'value')) {
35
+ return undefined;
36
+ }
37
+ const phase = descriptors.phase?.value;
38
+ const predicate = descriptors.predicate?.value;
39
+ if (!observationPhases.some((entry) => entry === phase) ||
40
+ !observationPredicates.some((entry) => entry === predicate)) {
41
+ return undefined;
42
+ }
43
+ return Object.freeze({
44
+ phase: phase,
45
+ predicate: predicate,
46
+ });
47
+ }
48
+ catch {
49
+ return undefined;
50
+ }
51
+ }
8
52
  class AwsGeneratedSecretInitializationError extends Error {
9
53
  code;
10
- constructor(code) {
54
+ observationDiagnostic;
55
+ constructor(code, observationDiagnostic) {
11
56
  super(`Generated secret initialization failed (${code}).`);
12
57
  this.name = 'AwsGeneratedSecretInitializationError';
13
58
  this.code = code;
59
+ this.observationDiagnostic = safeGeneratedSecretObservationDiagnostic(observationDiagnostic);
14
60
  }
15
61
  }
16
62
  exports.AwsGeneratedSecretInitializationError = AwsGeneratedSecretInitializationError;
@@ -71,21 +117,26 @@ function tagsToAws(tags) {
71
117
  .sort()
72
118
  .map((Key) => ({ Key, Value: tags[Key] }));
73
119
  }
74
- function exactTags(value, expected) {
75
- if (!Array.isArray(value) || value.length !== Object.keys(expected).length) {
76
- return false;
77
- }
120
+ function tagsDiagnostic(value, expected) {
121
+ if (!Array.isArray(value))
122
+ return 'tags-shape';
123
+ if (value.length !== Object.keys(expected).length)
124
+ return 'tags-count';
78
125
  const observed = {};
79
126
  for (const entry of value) {
80
127
  if (!isRecord(entry) ||
81
128
  typeof entry['Key'] !== 'string' ||
82
- typeof entry['Value'] !== 'string' ||
83
- Object.prototype.hasOwnProperty.call(observed, entry['Key'])) {
84
- return false;
129
+ typeof entry['Value'] !== 'string') {
130
+ return 'tag-entry';
131
+ }
132
+ if (Object.prototype.hasOwnProperty.call(observed, entry['Key'])) {
133
+ return 'tag-duplicate';
85
134
  }
86
135
  observed[entry['Key']] = entry['Value'];
87
136
  }
88
- return Object.entries(expected).every(([key, expectedValue]) => observed[key] === expectedValue);
137
+ return Object.entries(expected).every(([key, expectedValue]) => observed[key] === expectedValue)
138
+ ? undefined
139
+ : 'tag-value';
89
140
  }
90
141
  function arnMatchesName(arn, name) {
91
142
  if (!(0, model_js_1.isExactSecretArn)(arn))
@@ -108,20 +159,32 @@ function inspectVersionState(output, versionId) {
108
159
  ? 'current'
109
160
  : 'conflicting';
110
161
  }
111
- function requireDescribeOutput(value, input) {
112
- if (!isRecord(value) ||
113
- typeof value['ARN'] !== 'string' ||
114
- !arnMatchesName(value['ARN'], input.name) ||
115
- value['Name'] !== input.name ||
116
- value['Description'] !== input.description ||
117
- value['DeletedDate'] !== undefined ||
118
- value['RotationEnabled'] === true ||
119
- !exactTags(value['Tags'], input.tags)) {
120
- throw new AwsGeneratedSecretInitializationError('generated-secret-observation-invalid');
162
+ function requireDescribeOutput(value, input, phase) {
163
+ let predicate;
164
+ if (!isRecord(value))
165
+ predicate = 'response-record';
166
+ else if (typeof value['ARN'] !== 'string')
167
+ predicate = 'arn-type';
168
+ else if (!arnMatchesName(value['ARN'], input.name))
169
+ predicate = 'arn-name';
170
+ else if (value['Name'] !== input.name)
171
+ predicate = 'name';
172
+ else if (value['Description'] !== input.description)
173
+ predicate = 'description';
174
+ else if (value['DeletedDate'] !== undefined)
175
+ predicate = 'deleted-date';
176
+ else if (value['RotationEnabled'] === true)
177
+ predicate = 'rotation-enabled';
178
+ else
179
+ predicate = tagsDiagnostic(value['Tags'], input.tags);
180
+ if (predicate !== undefined) {
181
+ throw new AwsGeneratedSecretInitializationError('generated-secret-observation-invalid', { phase, predicate });
121
182
  }
183
+ // The branches above establish the same shape as the former compound check.
184
+ const output = value;
122
185
  return {
123
- arn: value['ARN'],
124
- state: inspectVersionState(value, expectedVersionId(input.name, input.generation)),
186
+ arn: output.ARN,
187
+ state: inspectVersionState(output, expectedVersionId(input.name, input.generation)),
125
188
  };
126
189
  }
127
190
  function requireCreateOutput(value, input, versionId) {
@@ -161,7 +224,7 @@ function createAwsGeneratedSecretInitializationControlPlane(options = {}) {
161
224
  const client = options.client ?? defaultClient(options.clientConfiguration ?? {});
162
225
  const generateBytes = options.randomBytes ?? node_crypto_1.randomBytes;
163
226
  const wait = options.wait ?? defaultWait;
164
- const inspectExact = async (input) => {
227
+ const inspectExact = async (input, phase) => {
165
228
  requireInput(input);
166
229
  let rawOutput;
167
230
  try {
@@ -172,13 +235,13 @@ function createAwsGeneratedSecretInitializationControlPlane(options = {}) {
172
235
  return { state: 'missing' };
173
236
  throw new AwsGeneratedSecretInitializationError('generated-secret-read-failed');
174
237
  }
175
- return requireDescribeOutput(rawOutput, input);
238
+ return requireDescribeOutput(rawOutput, input, phase);
176
239
  };
177
240
  const inspectAfterCreate = async (input) => {
178
241
  let finalInspection = { state: 'missing' };
179
242
  for (const delay of inspectionDelaysMilliseconds) {
180
243
  await wait(delay);
181
- finalInspection = await inspectExact(input);
244
+ finalInspection = await inspectExact(input, 'post-create');
182
245
  if (finalInspection.state !== 'missing')
183
246
  return finalInspection;
184
247
  }
@@ -186,15 +249,15 @@ function createAwsGeneratedSecretInitializationControlPlane(options = {}) {
186
249
  };
187
250
  return Object.freeze({
188
251
  async inspect(input) {
189
- return (await inspectExact(input)).state;
252
+ return (await inspectExact(input, 'inspect')).state;
190
253
  },
191
254
  async initializeGenerated(input) {
192
255
  requireInput(input);
193
- const initial = await inspectExact(input);
256
+ const initial = await inspectExact(input, 'pre-create');
194
257
  if (initial.state === 'current')
195
258
  return 'unchanged';
196
259
  if (initial.state !== 'missing') {
197
- throw new AwsGeneratedSecretInitializationError('generated-secret-state-conflicting');
260
+ throw new AwsGeneratedSecretInitializationError('generated-secret-state-conflicting', { phase: 'pre-create', predicate: 'version-state' });
198
261
  }
199
262
  let idBytes;
200
263
  let keyBytes;
@@ -248,11 +311,11 @@ function createAwsGeneratedSecretInitializationControlPlane(options = {}) {
248
311
  return responseAccepted ? 'applied' : 'unchanged';
249
312
  }
250
313
  if (finalInspection.state === 'conflicting') {
251
- throw new AwsGeneratedSecretInitializationError('generated-secret-state-conflicting');
314
+ throw new AwsGeneratedSecretInitializationError('generated-secret-state-conflicting', { phase: 'post-create', predicate: 'version-state' });
252
315
  }
253
316
  throw new AwsGeneratedSecretInitializationError(responseAccepted
254
317
  ? 'generated-secret-observation-invalid'
255
- : 'generated-secret-write-failed');
318
+ : 'generated-secret-write-failed', { phase: 'post-create', predicate: 'not-found' });
256
319
  },
257
320
  });
258
321
  }
@@ -1,4 +1,4 @@
1
- import { AwsGeneratedSecretInitializationError } from './generated-aws-control-plane.js';
1
+ import { AwsGeneratedSecretInitializationError, type GeneratedSecretObservationDiagnostic } from './generated-aws-control-plane.js';
2
2
  import { type SecretMetadataFinding, type SecretMetadataMutationIntent, type SecretMetadataPreflightResult, type SecretMetadataReconciliationResult } from './metadata.js';
3
3
  import { type ObservedSecretMetadata, type SecretManagementScope, type SecretMetadataDeclaration } from './model.js';
4
4
  export interface ListedSecretContainer {
@@ -84,8 +84,9 @@ export type SecretProtectedLifecycleAction = 'deploy' | 'recover' | 'remove' | '
84
84
  export declare class SecretOperatorControlPlaneError extends Error {
85
85
  readonly operation: 'create-empty' | 'describe' | 'inventory' | 'initialize-generated' | 'list' | 'recover' | 'retire' | 'tag';
86
86
  readonly diagnosticCode?: AwsGeneratedSecretInitializationError['code'];
87
+ readonly observationDiagnostic?: GeneratedSecretObservationDiagnostic;
87
88
  readonly code: 'secret-control-plane-apply-failed' | 'secret-control-plane-inventory-failed' | 'secret-control-plane-inventory-invalid' | 'secret-control-plane-protected-action-failed';
88
- constructor(code: SecretOperatorControlPlaneError['code'], operation: 'create-empty' | 'describe' | 'inventory' | 'initialize-generated' | 'list' | 'recover' | 'retire' | 'tag', diagnosticCode?: AwsGeneratedSecretInitializationError['code']);
89
+ constructor(code: SecretOperatorControlPlaneError['code'], operation: 'create-empty' | 'describe' | 'inventory' | 'initialize-generated' | 'list' | 'recover' | 'retire' | 'tag', diagnosticCode?: AwsGeneratedSecretInitializationError['code'], observationDiagnostic?: GeneratedSecretObservationDiagnostic);
89
90
  }
90
91
  export interface SecretMetadataOperatorResult {
91
92
  after?: SecretMetadataReconciliationResult;
@@ -13,14 +13,20 @@ const model_js_1 = require("./model.js");
13
13
  class SecretOperatorControlPlaneError extends Error {
14
14
  operation;
15
15
  diagnosticCode;
16
+ observationDiagnostic;
16
17
  code;
17
- constructor(code, operation, diagnosticCode) {
18
+ constructor(code, operation, diagnosticCode, observationDiagnostic) {
19
+ const safeObservation = (0, generated_aws_control_plane_js_1.safeGeneratedSecretObservationDiagnostic)(observationDiagnostic);
18
20
  super(`Secret metadata ${operation} failed (${code}).` +
19
- (diagnosticCode ? ` Reason: ${diagnosticCode}.` : ''));
21
+ (diagnosticCode ? ` Reason: ${diagnosticCode}.` : '') +
22
+ (safeObservation
23
+ ? ` Observation: ${safeObservation.phase}/${safeObservation.predicate}.`
24
+ : ''));
20
25
  this.operation = operation;
21
26
  this.diagnosticCode = diagnosticCode;
22
27
  this.name = 'SecretOperatorControlPlaneError';
23
28
  this.code = code;
29
+ this.observationDiagnostic = safeObservation;
24
30
  }
25
31
  }
26
32
  exports.SecretOperatorControlPlaneError = SecretOperatorControlPlaneError;
@@ -35,14 +41,30 @@ function safeControlPlaneError(error, code, operation) {
35
41
  // Preserve only our finite, value-blind diagnostic vocabulary. Never attach
36
42
  // the raw SDK error, message, stack, request or cause: they may hold values.
37
43
  if (error instanceof generated_aws_control_plane_js_1.AwsGeneratedSecretInitializationError) {
38
- const diagnosticCode = Object.getOwnPropertyDescriptor(error, 'code')?.value;
44
+ let diagnosticCode;
45
+ try {
46
+ diagnosticCode = Object.getOwnPropertyDescriptor(error, 'code')?.value;
47
+ }
48
+ catch {
49
+ // A descriptor trap must not replace the safe error with its own.
50
+ return new SecretOperatorControlPlaneError(code, operation);
51
+ }
39
52
  switch (diagnosticCode) {
40
53
  case 'generated-secret-input-invalid':
41
54
  case 'generated-secret-observation-invalid':
42
55
  case 'generated-secret-read-failed':
43
56
  case 'generated-secret-state-conflicting':
44
- case 'generated-secret-write-failed':
45
- return new SecretOperatorControlPlaneError(code, operation, diagnosticCode);
57
+ case 'generated-secret-write-failed': {
58
+ let observationDiagnostic;
59
+ try {
60
+ observationDiagnostic = (0, generated_aws_control_plane_js_1.safeGeneratedSecretObservationDiagnostic)(Object.getOwnPropertyDescriptor(error, 'observationDiagnostic')
61
+ ?.value);
62
+ }
63
+ catch {
64
+ // An optional descriptor trap is untrusted detail, not a new error.
65
+ }
66
+ return new SecretOperatorControlPlaneError(code, operation, diagnosticCode, observationDiagnostic);
67
+ }
46
68
  }
47
69
  }
48
70
  return new SecretOperatorControlPlaneError(code, operation);
@@ -439,6 +439,25 @@ function isBlueprintVerificationExecutionAuthorityPath(path) {
439
439
  /^(?:vite|vitest)\.config\.[a-z0-9]+$/u.test(name) ||
440
440
  /^packages\/[^/]+\/\.ebk\/ownership\.json$/u.test(normalized));
441
441
  }
442
+ function isNativeArtifactDependencyBoundary(workspaceRoot, path, candidate) {
443
+ const match = /^packages\/([a-z][a-z0-9]*(?:-[a-z0-9]+)*)\/\.sst\/artifacts\/[^/]+\/node_modules$/u.exec(path);
444
+ const slice = match?.[1];
445
+ if (!slice)
446
+ return false;
447
+ const dependencyRoot = (0, node_path_1.join)(workspaceRoot, 'packages', slice, 'node_modules');
448
+ try {
449
+ const metadata = (0, node_fs_1.lstatSync)(dependencyRoot);
450
+ return (metadata.isDirectory() &&
451
+ !metadata.isSymbolicLink() &&
452
+ (0, node_fs_1.realpathSync)(dependencyRoot) === dependencyRoot &&
453
+ (0, node_path_1.toNamespacedPath)((0, node_path_1.resolve)((0, node_path_1.dirname)(candidate), (0, node_fs_1.readlinkSync)(candidate))) ===
454
+ (0, node_path_1.toNamespacedPath)(dependencyRoot) &&
455
+ (0, node_fs_1.realpathSync)(candidate) === dependencyRoot);
456
+ }
457
+ catch {
458
+ return false;
459
+ }
460
+ }
442
461
  /**
443
462
  * Inventories every execution-loader configuration outside bounded generated,
444
463
  * dependency, cache, and evidence directories. Forbidden ambient config is
@@ -467,15 +486,17 @@ function assertNoMutableBlueprintVerificationConfiguration(workspace) {
467
486
  const path = directoryPath
468
487
  ? `${directoryPath}/${entry.name}`
469
488
  : entry.name;
470
- const skippedDirectory = entry.isDirectory() &&
471
- SKIPPED_CONFIGURATION_DIRECTORIES.has(entry.name.toLowerCase());
489
+ const candidate = (0, node_path_1.join)(directory, entry.name);
490
+ const skippedDirectory = (entry.isDirectory() &&
491
+ SKIPPED_CONFIGURATION_DIRECTORIES.has(entry.name.toLowerCase())) ||
492
+ (entry.isSymbolicLink() &&
493
+ isNativeArtifactDependencyBoundary(workspaceRoot, path, candidate));
472
494
  if (entry.isSymbolicLink() && !skippedDirectory) {
473
495
  throw new Error(`Blueprint verification configuration inventory refuses symbolic-link authority at ${path}.`);
474
496
  }
475
497
  if (forbiddenConfigurationName(entry.name)) {
476
498
  throw new Error(`Blueprint verification refuses mutable environment or package-manager configuration at ${path}.`);
477
499
  }
478
- const candidate = (0, node_path_1.join)(directory, entry.name);
479
500
  if (protectedConfigurationName(entry.name)) {
480
501
  const metadata = (0, node_fs_1.lstatSync)(candidate);
481
502
  const child = (0, node_path_1.relative)(workspaceRoot, candidate);
@@ -275,6 +275,15 @@ to generate the effective managed \`pnpm-workspace.yaml\`, then run
275
275
  Review the lockfile and rerun affected checks. Never edit the managed YAML or
276
276
  ownership hashes. Pins do not waive the existing supply-chain policies.
277
277
 
278
+ The Standard Slice owns an exact local \`@opennextjs/aws\` development dependency.
279
+ Its build wrapper refuses a missing or different local builder; it never invokes
280
+ npx or dlx. Fresh override defaults include the reviewed
281
+ \`@node-minify/core@9.0.2>glob@10.3.3: 10.5.0\` correction. Existing seeded
282
+ policy always wins: explicitly reconcile that entry in the editable JSON before
283
+ the supported workspace report/apply, preserving other decisions. The override
284
+ governs the managed builder tree; OpenNext's nested npm image install remains a
285
+ separate boundary checked by the generated Sharp metadata/native-target guard.
286
+
278
287
  The license lists are organization-owned policy, not legal conclusions.
279
288
  Unknown and changed licenses require review. Exceptions are exact-component,
280
289
  approved, expiring records with compensating controls and recheck triggers.
@@ -160,7 +160,8 @@ function createCycloneDxComponentsFromInventory(input) {
160
160
  }));
161
161
  }
162
162
  function canonicalTimestamp(value, path) {
163
- if (!Number.isFinite(Date.parse(value)) ||
163
+ if (typeof value !== 'string' ||
164
+ !Number.isFinite(Date.parse(value)) ||
164
165
  new Date(value).toISOString() !== value) {
165
166
  throw new errors_js_1.SupplyChainError('supply-chain-input-invalid', path, 'must be a canonical ISO-8601 timestamp');
166
167
  }
@@ -775,8 +776,11 @@ function bindingInput(value) {
775
776
  }
776
777
  function createSupplyChainReleaseBinding(input) {
777
778
  canonicalTimestamp(input.createdAt, 'createdAt');
778
- if (!common_js_1.SUPPLY_CHAIN_REFERENCE.test(input.releaseId) ||
779
- !common_js_1.SUPPLY_CHAIN_SHA256.test(input.releaseManifestDigest) ||
779
+ if (typeof input.releaseId !== 'string' ||
780
+ common_js_1.SUPPLY_CHAIN_REFERENCE.exec(input.releaseId)?.[0] !== input.releaseId ||
781
+ typeof input.releaseManifestDigest !== 'string' ||
782
+ common_js_1.SUPPLY_CHAIN_SHA256.exec(input.releaseManifestDigest)?.[0] !==
783
+ input.releaseManifestDigest ||
780
784
  input.artifacts.length === 0 ||
781
785
  (0, common_js_1.hasSensitiveSupplyChainShape)(input)) {
782
786
  throw new errors_js_1.SupplyChainError('supply-chain-input-invalid', 'releaseBinding', 'must bind at least one artifact to an exact release manifest');
@@ -785,11 +789,21 @@ function createSupplyChainReleaseBinding(input) {
785
789
  const artifacts = [...input.artifacts]
786
790
  .sort((left, right) => (0, deterministic_order_js_1.compareUtf16)(left.bindingId, right.bindingId))
787
791
  .map((artifact, index) => {
788
- if (!common_js_1.SUPPLY_CHAIN_REFERENCE.test(artifact.bindingId) ||
789
- !common_js_1.SUPPLY_CHAIN_SHA256.test(artifact.candidateDigest) ||
790
- !common_js_1.SUPPLY_CHAIN_SHA256.test(artifact.contentDigest) ||
791
- !common_js_1.SUPPLY_CHAIN_SHA256.test(artifact.sbomDigest) ||
792
- !/^urn:uuid:[a-f0-9-]{36}$/.test(artifact.sbomSerialNumber) ||
792
+ if (typeof artifact.bindingId !== 'string' ||
793
+ common_js_1.SUPPLY_CHAIN_REFERENCE.exec(artifact.bindingId)?.[0] !==
794
+ artifact.bindingId ||
795
+ typeof artifact.candidateDigest !== 'string' ||
796
+ common_js_1.SUPPLY_CHAIN_SHA256.exec(artifact.candidateDigest)?.[0] !==
797
+ artifact.candidateDigest ||
798
+ typeof artifact.contentDigest !== 'string' ||
799
+ common_js_1.SUPPLY_CHAIN_SHA256.exec(artifact.contentDigest)?.[0] !==
800
+ artifact.contentDigest ||
801
+ typeof artifact.sbomDigest !== 'string' ||
802
+ common_js_1.SUPPLY_CHAIN_SHA256.exec(artifact.sbomDigest)?.[0] !==
803
+ artifact.sbomDigest ||
804
+ typeof artifact.sbomSerialNumber !== 'string' ||
805
+ /^urn:uuid:[a-f0-9-]{36}$/.exec(artifact.sbomSerialNumber)?.[0] !==
806
+ artifact.sbomSerialNumber ||
793
807
  seen.has(artifact.bindingId)) {
794
808
  throw new errors_js_1.SupplyChainError('supply-chain-input-invalid', `releaseBinding.artifacts[${index}]`, 'must uniquely bind artifact and SBOM digests');
795
809
  }
@@ -810,14 +824,62 @@ function createSupplyChainReleaseBinding(input) {
810
824
  };
811
825
  }
812
826
  function validateSupplyChainReleaseBinding(value, expected) {
827
+ const exactKeys = (record, keys) => [Object.prototype, null].includes(Object.getPrototypeOf(record)) &&
828
+ Object.keys(record).sort(deterministic_order_js_1.compareUtf16).join('\0') ===
829
+ [...keys].sort(deterministic_order_js_1.compareUtf16).join('\0');
813
830
  if (!(0, validation_js_1.isRecord)(value) ||
831
+ !exactKeys(value, [
832
+ 'artifacts',
833
+ 'createdAt',
834
+ 'kind',
835
+ 'materialDigest',
836
+ 'releaseId',
837
+ 'releaseManifestDigest',
838
+ 'schemaVersion',
839
+ ]) ||
814
840
  value.kind !== exports.SUPPLY_CHAIN_RELEASE_BINDING_KIND ||
815
841
  value.schemaVersion !== exports.SUPPLY_CHAIN_SBOM_SCHEMA_VERSION ||
816
- !common_js_1.SUPPLY_CHAIN_SHA256.test(String(value.materialDigest)) ||
817
- !Array.isArray(value.artifacts)) {
818
- throw new errors_js_1.SupplyChainError('supply-chain-input-invalid', 'releaseBinding', 'must be an EBK supply-chain release binding v1');
842
+ typeof value.materialDigest !== 'string' ||
843
+ common_js_1.SUPPLY_CHAIN_SHA256.exec(value.materialDigest)?.[0] !==
844
+ value.materialDigest ||
845
+ typeof value.createdAt !== 'string' ||
846
+ typeof value.releaseId !== 'string' ||
847
+ typeof value.releaseManifestDigest !== 'string' ||
848
+ !Array.isArray(value.artifacts) ||
849
+ !value.artifacts.length) {
850
+ throw new errors_js_1.SupplyChainError('supply-chain-input-invalid', 'releaseBinding', 'must be an exact EBK supply-chain release binding v1');
851
+ }
852
+ const artifacts = [];
853
+ for (const artifact of value.artifacts) {
854
+ if (!(0, validation_js_1.isRecord)(artifact) ||
855
+ !exactKeys(artifact, [
856
+ 'bindingId',
857
+ 'candidateDigest',
858
+ 'contentDigest',
859
+ 'sbomDigest',
860
+ 'sbomSerialNumber',
861
+ ]) ||
862
+ typeof artifact.bindingId !== 'string' ||
863
+ typeof artifact.candidateDigest !== 'string' ||
864
+ typeof artifact.contentDigest !== 'string' ||
865
+ typeof artifact.sbomDigest !== 'string' ||
866
+ typeof artifact.sbomSerialNumber !== 'string') {
867
+ throw new errors_js_1.SupplyChainError('supply-chain-input-invalid', 'releaseBinding.artifacts', 'must contain exact string artifact fields');
868
+ }
869
+ artifacts.push({
870
+ bindingId: artifact.bindingId,
871
+ candidateDigest: artifact.candidateDigest,
872
+ contentDigest: artifact.contentDigest,
873
+ sbomDigest: artifact.sbomDigest,
874
+ sbomSerialNumber: artifact.sbomSerialNumber,
875
+ });
819
876
  }
820
- const recreated = createSupplyChainReleaseBinding(value);
877
+ const recreated = createSupplyChainReleaseBinding({
878
+ artifacts,
879
+ createdAt: value.createdAt,
880
+ releaseId: value.releaseId,
881
+ releaseManifestDigest: value.releaseManifestDigest,
882
+ });
821
883
  if (recreated.materialDigest !== value.materialDigest) {
822
884
  throw new errors_js_1.SupplyChainError('supply-chain-artifact-mismatch', 'releaseBinding.materialDigest', 'does not match the canonical binding bytes');
823
885
  }