@aws/ml-container-creator 0.2.5 → 0.3.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 (72) hide show
  1. package/bin/cli.js +45 -4
  2. package/config/bootstrap-stack.json +14 -0
  3. package/infra/ci-harness/package-lock.json +22 -9
  4. package/package.json +7 -8
  5. package/servers/base-image-picker/index.js +3 -3
  6. package/servers/base-image-picker/manifest.json +4 -2
  7. package/servers/instance-sizer/index.js +564 -0
  8. package/servers/instance-sizer/lib/instance-ranker.js +270 -0
  9. package/servers/instance-sizer/lib/model-resolver.js +269 -0
  10. package/servers/instance-sizer/lib/vram-estimator.js +177 -0
  11. package/servers/instance-sizer/manifest.json +17 -0
  12. package/servers/instance-sizer/package.json +15 -0
  13. package/servers/{instance-recommender → lib}/catalogs/instances.json +136 -34
  14. package/servers/{base-image-picker → lib}/catalogs/model-servers.json +302 -254
  15. package/servers/lib/catalogs/model-sizes.json +131 -0
  16. package/servers/lib/catalogs/models.json +632 -0
  17. package/servers/{model-picker → lib}/catalogs/popular-diffusors.json +32 -10
  18. package/servers/{model-picker → lib}/catalogs/popular-transformers.json +59 -26
  19. package/servers/{base-image-picker → lib}/catalogs/python-slim.json +12 -12
  20. package/servers/lib/schemas/image-catalog.schema.json +6 -12
  21. package/servers/lib/schemas/instances.schema.json +29 -0
  22. package/servers/lib/schemas/model-catalog.schema.json +12 -10
  23. package/servers/lib/schemas/unified-model-catalog.schema.json +129 -0
  24. package/servers/model-picker/index.js +4 -4
  25. package/servers/model-picker/manifest.json +2 -3
  26. package/servers/region-picker/index.js +1 -1
  27. package/servers/region-picker/manifest.json +1 -1
  28. package/src/app.js +36 -0
  29. package/src/lib/architecture-sync.js +171 -0
  30. package/src/lib/arn-detection.js +22 -0
  31. package/src/lib/bootstrap-command-handler.js +120 -0
  32. package/src/lib/cli-handler.js +3 -3
  33. package/src/lib/config-manager.js +47 -1
  34. package/src/lib/configuration-manager.js +2 -2
  35. package/src/lib/cross-cutting-checker.js +460 -0
  36. package/src/lib/deployment-entry-schema.js +1 -2
  37. package/src/lib/dry-run-validator.js +78 -0
  38. package/src/lib/generation-validator.js +102 -0
  39. package/src/lib/mcp-validator-config.js +89 -0
  40. package/src/lib/payload-builder.js +153 -0
  41. package/src/lib/prompt-runner.js +866 -149
  42. package/src/lib/prompts.js +2 -2
  43. package/src/lib/registry-command-handler.js +236 -0
  44. package/src/lib/registry-loader.js +5 -5
  45. package/src/lib/schema-sync.js +203 -0
  46. package/src/lib/schema-validation-engine.js +195 -0
  47. package/src/lib/secret-classification.js +56 -0
  48. package/src/lib/secrets-command-handler.js +550 -0
  49. package/src/lib/service-model-parser.js +102 -0
  50. package/src/lib/validate-runner.js +216 -0
  51. package/src/lib/validation-report.js +140 -0
  52. package/src/lib/validators/base-validator.js +36 -0
  53. package/src/lib/validators/catalog-validator.js +177 -0
  54. package/src/lib/validators/enum-validator.js +120 -0
  55. package/src/lib/validators/required-field-validator.js +150 -0
  56. package/src/lib/validators/type-validator.js +313 -0
  57. package/src/prompt-adapter.js +3 -2
  58. package/templates/Dockerfile +1 -1
  59. package/templates/do/build +37 -5
  60. package/templates/do/config +15 -3
  61. package/templates/do/deploy +60 -5
  62. package/templates/do/logs +18 -3
  63. package/templates/do/run +15 -1
  64. package/templates/do/validate +61 -0
  65. package/servers/instance-recommender/LICENSE +0 -202
  66. package/servers/instance-recommender/index.js +0 -284
  67. package/servers/instance-recommender/manifest.json +0 -16
  68. package/servers/instance-recommender/package.json +0 -15
  69. /package/servers/{model-picker → lib}/catalogs/jumpstart-public.json +0 -0
  70. /package/servers/{region-picker → lib}/catalogs/regions.json +0 -0
  71. /package/servers/{base-image-picker → lib}/catalogs/triton-backends.json +0 -0
  72. /package/servers/{base-image-picker → lib}/catalogs/triton.json +0 -0
@@ -0,0 +1,195 @@
1
+ import ValidationReport from './validation-report.js';
2
+ import EnumValidator from './validators/enum-validator.js';
3
+ import TypeValidator from './validators/type-validator.js';
4
+ import RequiredFieldValidator from './validators/required-field-validator.js';
5
+ import CrossCuttingChecker from './cross-cutting-checker.js';
6
+ import { existsSync, readFileSync } from 'node:fs';
7
+ import path from 'node:path';
8
+
9
+ /**
10
+ * Core validation orchestrator.
11
+ * Loads service models, runs static and smart validators, and produces a report.
12
+ *
13
+ * Requirements: 12.1, 12.2, 12.5, 15.4, 15.5
14
+ */
15
+ export default class SchemaValidationEngine {
16
+ /**
17
+ * @param {Object} options
18
+ * @param {string} options.registryPath - Path to schema registry
19
+ * @param {boolean} options.ignoreStaleness - Suppress staleness warnings
20
+ * @param {boolean} options.smartMode - Enable smart-mode validators
21
+ */
22
+ constructor(options = {}) {
23
+ this.registryPath = options.registryPath || null;
24
+ this.ignoreStaleness = options.ignoreStaleness || false;
25
+ this.smartMode = options.smartMode || false;
26
+ this.validators = [];
27
+ this.serviceModels = options.serviceModels || [];
28
+ this.instanceCatalog = options.instanceCatalog || null;
29
+ this.crossCuttingChecker = new CrossCuttingChecker();
30
+
31
+ // Auto-register built-in validators
32
+ this.registerValidator(new EnumValidator());
33
+ this.registerValidator(new TypeValidator());
34
+ this.registerValidator(new RequiredFieldValidator());
35
+ }
36
+
37
+ /**
38
+ * Run full validation pipeline.
39
+ * Orchestrate: load models → run static validators → run smart validators (if enabled) → return report.
40
+ * @param {Object} context - ValidationContext from PayloadBuilder
41
+ * @returns {Promise<ValidationReport>}
42
+ */
43
+ async validate(context) {
44
+ const report = new ValidationReport();
45
+
46
+ // Run static validators (mode === 'static' or 'both')
47
+ const staticValidators = this.validators.filter(
48
+ v => v.mode === 'static' || v.mode === 'both'
49
+ );
50
+
51
+ const priorFindings = [];
52
+
53
+ for (const validator of staticValidators) {
54
+ try {
55
+ const findings = await validator.validate(context, {
56
+ priorFindings: [...priorFindings],
57
+ serviceModels: this.serviceModels
58
+ });
59
+ for (const finding of findings) {
60
+ report.addFinding(finding);
61
+ priorFindings.push(finding);
62
+ }
63
+ } catch (err) {
64
+ report.warnings.push({
65
+ source: 'engine',
66
+ severity: 'warning',
67
+ operation: '',
68
+ fieldPath: '',
69
+ remediationHint: `Plugin "${validator.name}" threw an error: ${err.message}`
70
+ });
71
+ }
72
+ }
73
+
74
+ // Run cross-cutting checks after schema validators
75
+ if (this.instanceCatalog) {
76
+ try {
77
+ const crossCuttingFindings = this.crossCuttingChecker.check(context, this.instanceCatalog);
78
+ for (const finding of crossCuttingFindings) {
79
+ report.addFinding(finding);
80
+ priorFindings.push(finding);
81
+ }
82
+ } catch (err) {
83
+ report.warnings.push({
84
+ source: 'engine',
85
+ severity: 'warning',
86
+ operation: '',
87
+ fieldPath: '',
88
+ remediationHint: `Cross-cutting checker threw an error: ${err.message}`
89
+ });
90
+ }
91
+ }
92
+
93
+ // Run smart validators if enabled (mode === 'smart' or 'both')
94
+ if (this.smartMode) {
95
+ const smartValidators = this.validators.filter(
96
+ v => v.mode === 'smart' || v.mode === 'both'
97
+ );
98
+
99
+ for (const validator of smartValidators) {
100
+ // Skip validators already run in static pass (mode === 'both')
101
+ if (validator.mode === 'both' && staticValidators.includes(validator)) {
102
+ continue;
103
+ }
104
+
105
+ try {
106
+ const findings = await validator.validate(context, {
107
+ priorFindings: [...priorFindings],
108
+ serviceModels: this.serviceModels
109
+ });
110
+ for (const finding of findings) {
111
+ report.addFinding(finding);
112
+ priorFindings.push(finding);
113
+ }
114
+ } catch (err) {
115
+ report.warnings.push({
116
+ source: 'engine',
117
+ severity: 'warning',
118
+ operation: '',
119
+ fieldPath: '',
120
+ remediationHint: `Smart plugin "${validator.name}" threw an error: ${err.message}`
121
+ });
122
+ }
123
+ }
124
+ }
125
+
126
+ return report;
127
+ }
128
+
129
+ /**
130
+ * Register a custom validator plugin.
131
+ * @param {Object} validator - A BaseValidator instance
132
+ */
133
+ registerValidator(validator) {
134
+ this.validators.push(validator);
135
+ }
136
+
137
+ /**
138
+ * Check schema registry staleness.
139
+ * @returns {{ stale: boolean, lastSynced: string|null, daysSinceSync: number, registryMissing?: boolean }}
140
+ */
141
+ checkStaleness() {
142
+ if (!this.registryPath) {
143
+ return {
144
+ stale: false,
145
+ lastSynced: null,
146
+ daysSinceSync: 0,
147
+ registryMissing: true
148
+ };
149
+ }
150
+
151
+ let manifest;
152
+ try {
153
+ const manifestPath = path.join(this.registryPath, 'manifest.json');
154
+
155
+ if (!existsSync(manifestPath)) {
156
+ return {
157
+ stale: false,
158
+ lastSynced: null,
159
+ daysSinceSync: 0,
160
+ registryMissing: true
161
+ };
162
+ }
163
+
164
+ manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
165
+ } catch {
166
+ return {
167
+ stale: false,
168
+ lastSynced: null,
169
+ daysSinceSync: 0,
170
+ registryMissing: true
171
+ };
172
+ }
173
+
174
+ if (!manifest || !manifest.lastSynced) {
175
+ return {
176
+ stale: false,
177
+ lastSynced: null,
178
+ daysSinceSync: 0,
179
+ registryMissing: true
180
+ };
181
+ }
182
+
183
+ const lastSynced = manifest.lastSynced;
184
+ const syncDate = new Date(lastSynced);
185
+ const now = new Date();
186
+ const daysSinceSync = Math.floor((now - syncDate) / (1000 * 60 * 60 * 24));
187
+ const stale = daysSinceSync > 30;
188
+
189
+ if (stale && !this.ignoreStaleness) {
190
+ console.log(`⚠️ Schema registry is ${daysSinceSync} days old. Run \`ml-container-creator bootstrap sync-schemas\` to update.`);
191
+ }
192
+
193
+ return { stale, lastSynced, daysSinceSync };
194
+ }
195
+ }
@@ -0,0 +1,56 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ /**
5
+ * Secret Classification Registry
6
+ *
7
+ * Single source of truth for all secret type metadata. Each entry defines
8
+ * the identifier, display name, applicable stages, purpose, CLI flags,
9
+ * environment variable names, and prompt labels for a secret type.
10
+ *
11
+ * Adding a new secret type requires only adding a new entry to this array —
12
+ * the CLI, prompt flow, and do-script templates derive behavior from this registry.
13
+ */
14
+
15
+ export const SECRET_CLASSIFICATIONS = Object.freeze([
16
+ {
17
+ identifier: 'hf-token',
18
+ displayName: 'HuggingFace Token',
19
+ stages: ['build-time', 'runtime'],
20
+ purpose: 'Gated model download from HuggingFace Hub',
21
+ cliFlag: 'hf-token-arn',
22
+ cliFlagPlaintext: 'hf-token',
23
+ envVar: 'HF_TOKEN',
24
+ envVarArn: 'HF_TOKEN_ARN',
25
+ promptLabel: 'HuggingFace token'
26
+ },
27
+ {
28
+ identifier: 'ngc-token',
29
+ displayName: 'NVIDIA NGC Token',
30
+ stages: ['build-time'],
31
+ purpose: 'Pulling base images from NVIDIA NGC registry',
32
+ cliFlag: 'ngc-token-arn',
33
+ cliFlagPlaintext: 'ngc-token',
34
+ envVar: 'NGC_API_KEY',
35
+ envVarArn: 'NGC_API_KEY_ARN',
36
+ promptLabel: 'NVIDIA NGC API key'
37
+ }
38
+ ]);
39
+
40
+ /**
41
+ * Look up a classification entry by identifier.
42
+ * @param {string} identifier - e.g. 'hf-token'
43
+ * @returns {Object|undefined}
44
+ */
45
+ export function getClassification(identifier) {
46
+ return SECRET_CLASSIFICATIONS.find(c => c.identifier === identifier);
47
+ }
48
+
49
+ /**
50
+ * Get all classifications applicable to a given stage.
51
+ * @param {string} stage - 'build-time' or 'runtime'
52
+ * @returns {Object[]}
53
+ */
54
+ export function getClassificationsForStage(stage) {
55
+ return SECRET_CLASSIFICATIONS.filter(c => c.stages.includes(stage));
56
+ }