@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.
- package/bin/cli.js +45 -4
- package/config/bootstrap-stack.json +14 -0
- package/infra/ci-harness/package-lock.json +22 -9
- package/package.json +7 -8
- package/servers/base-image-picker/index.js +3 -3
- package/servers/base-image-picker/manifest.json +4 -2
- package/servers/instance-sizer/index.js +564 -0
- package/servers/instance-sizer/lib/instance-ranker.js +270 -0
- package/servers/instance-sizer/lib/model-resolver.js +269 -0
- package/servers/instance-sizer/lib/vram-estimator.js +177 -0
- package/servers/instance-sizer/manifest.json +17 -0
- package/servers/instance-sizer/package.json +15 -0
- package/servers/{instance-recommender → lib}/catalogs/instances.json +136 -34
- package/servers/{base-image-picker → lib}/catalogs/model-servers.json +302 -254
- package/servers/lib/catalogs/model-sizes.json +131 -0
- package/servers/lib/catalogs/models.json +632 -0
- package/servers/{model-picker → lib}/catalogs/popular-diffusors.json +32 -10
- package/servers/{model-picker → lib}/catalogs/popular-transformers.json +59 -26
- package/servers/{base-image-picker → lib}/catalogs/python-slim.json +12 -12
- package/servers/lib/schemas/image-catalog.schema.json +6 -12
- package/servers/lib/schemas/instances.schema.json +29 -0
- package/servers/lib/schemas/model-catalog.schema.json +12 -10
- package/servers/lib/schemas/unified-model-catalog.schema.json +129 -0
- package/servers/model-picker/index.js +4 -4
- package/servers/model-picker/manifest.json +2 -3
- package/servers/region-picker/index.js +1 -1
- package/servers/region-picker/manifest.json +1 -1
- package/src/app.js +36 -0
- package/src/lib/architecture-sync.js +171 -0
- package/src/lib/arn-detection.js +22 -0
- package/src/lib/bootstrap-command-handler.js +120 -0
- package/src/lib/cli-handler.js +3 -3
- package/src/lib/config-manager.js +47 -1
- package/src/lib/configuration-manager.js +2 -2
- package/src/lib/cross-cutting-checker.js +460 -0
- package/src/lib/deployment-entry-schema.js +1 -2
- package/src/lib/dry-run-validator.js +78 -0
- package/src/lib/generation-validator.js +102 -0
- package/src/lib/mcp-validator-config.js +89 -0
- package/src/lib/payload-builder.js +153 -0
- package/src/lib/prompt-runner.js +866 -149
- package/src/lib/prompts.js +2 -2
- package/src/lib/registry-command-handler.js +236 -0
- package/src/lib/registry-loader.js +5 -5
- package/src/lib/schema-sync.js +203 -0
- package/src/lib/schema-validation-engine.js +195 -0
- package/src/lib/secret-classification.js +56 -0
- package/src/lib/secrets-command-handler.js +550 -0
- package/src/lib/service-model-parser.js +102 -0
- package/src/lib/validate-runner.js +216 -0
- package/src/lib/validation-report.js +140 -0
- package/src/lib/validators/base-validator.js +36 -0
- package/src/lib/validators/catalog-validator.js +177 -0
- package/src/lib/validators/enum-validator.js +120 -0
- package/src/lib/validators/required-field-validator.js +150 -0
- package/src/lib/validators/type-validator.js +313 -0
- package/src/prompt-adapter.js +3 -2
- package/templates/Dockerfile +1 -1
- package/templates/do/build +37 -5
- package/templates/do/config +15 -3
- package/templates/do/deploy +60 -5
- package/templates/do/logs +18 -3
- package/templates/do/run +15 -1
- package/templates/do/validate +61 -0
- package/servers/instance-recommender/LICENSE +0 -202
- package/servers/instance-recommender/index.js +0 -284
- package/servers/instance-recommender/manifest.json +0 -16
- package/servers/instance-recommender/package.json +0 -15
- /package/servers/{model-picker → lib}/catalogs/jumpstart-public.json +0 -0
- /package/servers/{region-picker → lib}/catalogs/regions.json +0 -0
- /package/servers/{base-image-picker → lib}/catalogs/triton-backends.json +0 -0
- /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
|
+
}
|