@objectstack/cli 3.0.8 → 3.0.9
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +13 -0
- package/dist/commands/plugin/build.d.ts +29 -0
- package/dist/commands/plugin/build.d.ts.map +1 -0
- package/dist/commands/plugin/build.js +170 -0
- package/dist/commands/plugin/build.js.map +1 -0
- package/dist/commands/plugin/publish.d.ts +27 -0
- package/dist/commands/plugin/publish.d.ts.map +1 -0
- package/dist/commands/plugin/publish.js +152 -0
- package/dist/commands/plugin/publish.js.map +1 -0
- package/dist/commands/plugin/validate.d.ts +23 -0
- package/dist/commands/plugin/validate.d.ts.map +1 -0
- package/dist/commands/plugin/validate.js +251 -0
- package/dist/commands/plugin/validate.js.map +1 -0
- package/package.json +9 -9
- package/src/commands/plugin/build.ts +193 -0
- package/src/commands/plugin/publish.ts +176 -0
- package/src/commands/plugin/validate.ts +268 -0
- package/test/commands.test.ts +19 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import crypto from 'crypto';
|
|
7
|
+
import { createTimer, printHeader, printKV, printStep, printSuccess, printError } from '../../utils/format.js';
|
|
8
|
+
/**
|
|
9
|
+
* Validate a plugin artifact (.tgz) for structural integrity, checksum
|
|
10
|
+
* correctness, digital signature, and platform compatibility.
|
|
11
|
+
*
|
|
12
|
+
* Architecture alignment: `npm pack --dry-run`, `helm lint`, `vsce ls`.
|
|
13
|
+
*/
|
|
14
|
+
export default class PluginValidate extends Command {
|
|
15
|
+
static description = 'Validate a plugin artifact for integrity and compliance';
|
|
16
|
+
static args = {
|
|
17
|
+
artifact: Args.string({ description: 'Path to the artifact file', required: true }),
|
|
18
|
+
};
|
|
19
|
+
static flags = {
|
|
20
|
+
verifySignature: Flags.boolean({ description: 'Verify digital signature', default: true, allowNo: true }),
|
|
21
|
+
publicKeyPath: Flags.string({ description: 'Path to public key for signature verification' }),
|
|
22
|
+
verifyChecksums: Flags.boolean({ description: 'Verify SHA-256 checksums', default: true, allowNo: true }),
|
|
23
|
+
validateMetadata: Flags.boolean({ description: 'Validate metadata schema compliance', default: true, allowNo: true }),
|
|
24
|
+
platformVersion: Flags.string({ description: 'Target platform version for compatibility check' }),
|
|
25
|
+
json: Flags.boolean({ description: 'Output result as JSON' }),
|
|
26
|
+
};
|
|
27
|
+
async run() {
|
|
28
|
+
const { args, flags } = await this.parse(PluginValidate);
|
|
29
|
+
const timer = createTimer();
|
|
30
|
+
if (!flags.json) {
|
|
31
|
+
printHeader('Plugin Validate');
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const artifactPath = path.resolve(process.cwd(), args.artifact);
|
|
35
|
+
if (!fs.existsSync(artifactPath)) {
|
|
36
|
+
throw new Error(`Artifact not found: ${artifactPath}`);
|
|
37
|
+
}
|
|
38
|
+
if (!flags.json) {
|
|
39
|
+
printKV('Artifact', path.relative(process.cwd(), artifactPath));
|
|
40
|
+
printStep('Reading artifact...');
|
|
41
|
+
}
|
|
42
|
+
const artifactBuffer = fs.readFileSync(artifactPath);
|
|
43
|
+
const findings = [];
|
|
44
|
+
// 1. Verify file existence and basic structure
|
|
45
|
+
if (artifactBuffer.length === 0) {
|
|
46
|
+
findings.push({ severity: 'error', rule: 'artifact.empty', message: 'Artifact file is empty' });
|
|
47
|
+
}
|
|
48
|
+
// 2. Try to parse as JSON manifest
|
|
49
|
+
let manifest;
|
|
50
|
+
try {
|
|
51
|
+
manifest = JSON.parse(artifactBuffer.toString('utf-8'));
|
|
52
|
+
findings.push({ severity: 'info', rule: 'manifest.parsed', message: 'Manifest parsed successfully' });
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
findings.push({ severity: 'error', rule: 'manifest.invalid', message: 'Artifact does not contain valid JSON manifest' });
|
|
56
|
+
}
|
|
57
|
+
// 3. Validate required manifest fields
|
|
58
|
+
if (manifest) {
|
|
59
|
+
if (!flags.json)
|
|
60
|
+
printStep('Validating manifest fields...');
|
|
61
|
+
if (!manifest.manifest && !manifest.name) {
|
|
62
|
+
findings.push({ severity: 'warning', rule: 'manifest.name', message: 'No package name found in manifest' });
|
|
63
|
+
}
|
|
64
|
+
if (!manifest.manifest?.version && !manifest.version) {
|
|
65
|
+
findings.push({ severity: 'warning', rule: 'manifest.version', message: 'No version found in manifest' });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// 4. Checksum verification
|
|
69
|
+
let checksumResult;
|
|
70
|
+
if (flags.verifyChecksums) {
|
|
71
|
+
if (!flags.json)
|
|
72
|
+
printStep('Verifying checksums...');
|
|
73
|
+
const checksumFile = artifactPath + '.sha256';
|
|
74
|
+
if (fs.existsSync(checksumFile)) {
|
|
75
|
+
const checksumContent = fs.readFileSync(checksumFile, 'utf-8').trim();
|
|
76
|
+
const expectedHash = checksumContent.split(/\s+/)[0];
|
|
77
|
+
const actualHash = crypto.createHash('sha256').update(artifactBuffer).digest('hex');
|
|
78
|
+
if (expectedHash === actualHash) {
|
|
79
|
+
checksumResult = { passed: true };
|
|
80
|
+
findings.push({ severity: 'info', rule: 'checksum.sha256', message: 'SHA-256 checksum verified' });
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
checksumResult = { passed: false, mismatches: ['artifact'] };
|
|
84
|
+
findings.push({ severity: 'error', rule: 'checksum.sha256', message: `SHA-256 mismatch: expected ${expectedHash.slice(0, 16)}..., got ${actualHash.slice(0, 16)}...` });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
findings.push({ severity: 'warning', rule: 'checksum.missing', message: 'No .sha256 checksum file found alongside artifact' });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// 5. Signature verification
|
|
92
|
+
let signatureResult;
|
|
93
|
+
if (flags.verifySignature) {
|
|
94
|
+
if (!flags.json)
|
|
95
|
+
printStep('Verifying signature...');
|
|
96
|
+
const sigFile = artifactPath + '.sig';
|
|
97
|
+
if (fs.existsSync(sigFile) && flags.publicKeyPath && fs.existsSync(flags.publicKeyPath)) {
|
|
98
|
+
try {
|
|
99
|
+
const publicKey = fs.readFileSync(flags.publicKeyPath, 'utf-8');
|
|
100
|
+
const signature = fs.readFileSync(sigFile, 'utf-8');
|
|
101
|
+
const verifier = crypto.createVerify('RSA-SHA256');
|
|
102
|
+
verifier.update(artifactBuffer);
|
|
103
|
+
const valid = verifier.verify(publicKey, signature, 'base64');
|
|
104
|
+
signatureResult = { passed: valid, failureReason: valid ? undefined : 'Signature does not match' };
|
|
105
|
+
findings.push({
|
|
106
|
+
severity: valid ? 'info' : 'error',
|
|
107
|
+
rule: 'signature.verify',
|
|
108
|
+
message: valid ? 'Digital signature verified' : 'Digital signature verification failed',
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
signatureResult = { passed: false, failureReason: e.message };
|
|
113
|
+
findings.push({ severity: 'error', rule: 'signature.verify', message: `Signature verification error: ${e.message}` });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else if (fs.existsSync(sigFile) && !flags.publicKeyPath) {
|
|
117
|
+
findings.push({ severity: 'warning', rule: 'signature.nokey', message: 'Signature file found but no --publicKeyPath provided' });
|
|
118
|
+
}
|
|
119
|
+
else if (!fs.existsSync(sigFile)) {
|
|
120
|
+
findings.push({ severity: 'info', rule: 'signature.absent', message: 'No signature file found (unsigned artifact)' });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// 6. Platform compatibility check
|
|
124
|
+
let platformResult;
|
|
125
|
+
if (flags.platformVersion && manifest) {
|
|
126
|
+
if (!flags.json)
|
|
127
|
+
printStep('Checking platform compatibility...');
|
|
128
|
+
const engine = manifest.manifest?.engine || manifest.engine;
|
|
129
|
+
const required = engine?.objectstack;
|
|
130
|
+
if (required) {
|
|
131
|
+
// Semver range check supporting >=, >, ^, ~, and exact versions
|
|
132
|
+
const parseSemver = (v) => {
|
|
133
|
+
const parts = v.replace(/^v/, '').split('.').map(p => parseInt(p, 10));
|
|
134
|
+
return { major: parts[0] || 0, minor: parts[1] || 0, patch: parts[2] || 0 };
|
|
135
|
+
};
|
|
136
|
+
const target = parseSemver(flags.platformVersion);
|
|
137
|
+
let compatible = false;
|
|
138
|
+
let matched = false;
|
|
139
|
+
// >=X.Y.Z — greater than or equal
|
|
140
|
+
const gteMatch = required.match(/^>=\s*([\d.]+)/);
|
|
141
|
+
if (gteMatch) {
|
|
142
|
+
const req = parseSemver(gteMatch[1]);
|
|
143
|
+
compatible = (target.major > req.major) ||
|
|
144
|
+
(target.major === req.major && target.minor > req.minor) ||
|
|
145
|
+
(target.major === req.major && target.minor === req.minor && target.patch >= req.patch);
|
|
146
|
+
matched = true;
|
|
147
|
+
}
|
|
148
|
+
// >X.Y.Z — strictly greater than
|
|
149
|
+
if (!matched) {
|
|
150
|
+
const gtMatch = required.match(/^>\s*([\d.]+)/);
|
|
151
|
+
if (gtMatch) {
|
|
152
|
+
const req = parseSemver(gtMatch[1]);
|
|
153
|
+
compatible = (target.major > req.major) ||
|
|
154
|
+
(target.major === req.major && target.minor > req.minor) ||
|
|
155
|
+
(target.major === req.major && target.minor === req.minor && target.patch > req.patch);
|
|
156
|
+
matched = true;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// ^X.Y.Z — caret range (same major, >= minor.patch)
|
|
160
|
+
if (!matched) {
|
|
161
|
+
const caretMatch = required.match(/^\^\s*([\d.]+)/);
|
|
162
|
+
if (caretMatch) {
|
|
163
|
+
const req = parseSemver(caretMatch[1]);
|
|
164
|
+
compatible = target.major === req.major &&
|
|
165
|
+
((target.minor > req.minor) ||
|
|
166
|
+
(target.minor === req.minor && target.patch >= req.patch));
|
|
167
|
+
matched = true;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// ~X.Y.Z — tilde range (same major.minor, >= patch)
|
|
171
|
+
if (!matched) {
|
|
172
|
+
const tildeMatch = required.match(/^~\s*([\d.]+)/);
|
|
173
|
+
if (tildeMatch) {
|
|
174
|
+
const req = parseSemver(tildeMatch[1]);
|
|
175
|
+
compatible = target.major === req.major && target.minor === req.minor && target.patch >= req.patch;
|
|
176
|
+
matched = true;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Exact version match
|
|
180
|
+
if (!matched && /^\d+\.\d+\.\d+$/.test(required)) {
|
|
181
|
+
const req = parseSemver(required);
|
|
182
|
+
compatible = target.major === req.major && target.minor === req.minor && target.patch === req.patch;
|
|
183
|
+
matched = true;
|
|
184
|
+
}
|
|
185
|
+
if (matched) {
|
|
186
|
+
platformResult = { compatible, requiredRange: required, targetVersion: flags.platformVersion };
|
|
187
|
+
findings.push({
|
|
188
|
+
severity: compatible ? 'info' : 'error',
|
|
189
|
+
rule: 'platform.compatibility',
|
|
190
|
+
message: compatible
|
|
191
|
+
? `Compatible with platform v${flags.platformVersion}`
|
|
192
|
+
: `Requires platform ${required}, but target is v${flags.platformVersion}`,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
platformResult = { compatible: true, targetVersion: flags.platformVersion };
|
|
198
|
+
findings.push({ severity: 'info', rule: 'platform.noreq', message: 'No platform version requirement specified — assumed compatible' });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// 7. Summary
|
|
202
|
+
const errors = findings.filter(f => f.severity === 'error').length;
|
|
203
|
+
const warns = findings.filter(f => f.severity === 'warning').length;
|
|
204
|
+
const infos = findings.filter(f => f.severity === 'info').length;
|
|
205
|
+
const valid = errors === 0;
|
|
206
|
+
const result = {
|
|
207
|
+
valid,
|
|
208
|
+
checksumVerification: checksumResult,
|
|
209
|
+
signatureVerification: signatureResult,
|
|
210
|
+
platformCompatibility: platformResult,
|
|
211
|
+
findings,
|
|
212
|
+
summary: { errors, warnings: warns, infos },
|
|
213
|
+
};
|
|
214
|
+
if (flags.json) {
|
|
215
|
+
console.log(JSON.stringify(result, null, 2));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
console.log('');
|
|
219
|
+
if (valid) {
|
|
220
|
+
printSuccess(`Validation passed ${chalk.dim(`(${timer.display()})`)}`);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
printError(`Validation failed ${chalk.dim(`(${timer.display()})`)}`);
|
|
224
|
+
}
|
|
225
|
+
console.log('');
|
|
226
|
+
for (const finding of findings) {
|
|
227
|
+
const icon = finding.severity === 'error' ? chalk.red('✗')
|
|
228
|
+
: finding.severity === 'warning' ? chalk.yellow('⚠')
|
|
229
|
+
: chalk.blue('ℹ');
|
|
230
|
+
console.log(` ${icon} ${chalk.dim(`[${finding.rule}]`)} ${finding.message}`);
|
|
231
|
+
}
|
|
232
|
+
console.log('');
|
|
233
|
+
printKV('Errors', errors);
|
|
234
|
+
printKV('Warnings', warns);
|
|
235
|
+
printKV('Info', infos);
|
|
236
|
+
console.log('');
|
|
237
|
+
if (!valid) {
|
|
238
|
+
this.exit(1);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
if (flags.json) {
|
|
243
|
+
console.log(JSON.stringify({ valid: false, findings: [{ severity: 'error', rule: 'system', message: error.message }], summary: { errors: 1, warnings: 0, infos: 0 } }));
|
|
244
|
+
this.exit(1);
|
|
245
|
+
}
|
|
246
|
+
printError(error.message || String(error));
|
|
247
|
+
this.exit(1);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/commands/plugin/validate.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/cli",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.9",
|
|
4
4
|
"description": "Command Line Interface for ObjectStack Protocol",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -38,16 +38,16 @@
|
|
|
38
38
|
"chalk": "^5.3.0",
|
|
39
39
|
"tsx": "^4.7.1",
|
|
40
40
|
"zod": "^4.3.6",
|
|
41
|
-
"@objectstack/core": "3.0.
|
|
42
|
-
"@objectstack/driver-memory": "^3.0.
|
|
43
|
-
"@objectstack/objectql": "^3.0.
|
|
44
|
-
"@objectstack/plugin-hono-server": "3.0.
|
|
45
|
-
"@objectstack/rest": "3.0.
|
|
46
|
-
"@objectstack/runtime": "^3.0.
|
|
47
|
-
"@objectstack/spec": "3.0.
|
|
41
|
+
"@objectstack/core": "3.0.9",
|
|
42
|
+
"@objectstack/driver-memory": "^3.0.9",
|
|
43
|
+
"@objectstack/objectql": "^3.0.9",
|
|
44
|
+
"@objectstack/plugin-hono-server": "3.0.9",
|
|
45
|
+
"@objectstack/rest": "3.0.9",
|
|
46
|
+
"@objectstack/runtime": "^3.0.9",
|
|
47
|
+
"@objectstack/spec": "3.0.9"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@objectstack/core": "3.0.
|
|
50
|
+
"@objectstack/core": "3.0.9"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@oclif/plugin-help": "^6.2.37",
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import crypto from 'crypto';
|
|
8
|
+
import { createTimer, printHeader, printKV, printStep, printSuccess, printError, printWarning, collectMetadataStats } from '../../utils/format.js';
|
|
9
|
+
import { loadConfig, resolveConfigPath } from '../../utils/config.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Build a .tgz artifact from the current ObjectStack plugin project.
|
|
13
|
+
*
|
|
14
|
+
* Reads the project manifest (objectstack.config.ts), collects metadata
|
|
15
|
+
* definitions (objects, views, flows, etc.), computes SHA-256 checksums,
|
|
16
|
+
* and writes a compressed archive.
|
|
17
|
+
*
|
|
18
|
+
* Architecture alignment: `npm pack`, `helm package`, `vsce package`.
|
|
19
|
+
*/
|
|
20
|
+
export default class PluginBuild extends Command {
|
|
21
|
+
static override description = 'Build a .tgz plugin artifact from the current project';
|
|
22
|
+
|
|
23
|
+
static override aliases = ['plugin pack'];
|
|
24
|
+
|
|
25
|
+
static override args = {
|
|
26
|
+
config: Args.string({ description: 'Configuration file path', required: false }),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
static override flags = {
|
|
30
|
+
outDir: Flags.string({ char: 'o', description: 'Output directory', default: 'dist' }),
|
|
31
|
+
format: Flags.string({ char: 'f', description: 'Archive format (tgz | zip)', default: 'tgz', options: ['tgz', 'zip'] }),
|
|
32
|
+
sign: Flags.boolean({ description: 'Digitally sign the artifact', default: false }),
|
|
33
|
+
privateKeyPath: Flags.string({ description: 'Path to RSA/ECDSA private key for signing' }),
|
|
34
|
+
checksumAlgorithm: Flags.string({ description: 'Hash algorithm for checksums', default: 'sha256', options: ['sha256', 'sha384', 'sha512'] }),
|
|
35
|
+
includeData: Flags.boolean({ description: 'Include seed data in artifact', default: true, allowNo: true }),
|
|
36
|
+
includeLocales: Flags.boolean({ description: 'Include locale files', default: true, allowNo: true }),
|
|
37
|
+
json: Flags.boolean({ description: 'Output result as JSON' }),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
async run(): Promise<void> {
|
|
41
|
+
const { args, flags } = await this.parse(PluginBuild);
|
|
42
|
+
const timer = createTimer();
|
|
43
|
+
|
|
44
|
+
if (!flags.json) {
|
|
45
|
+
printHeader('Plugin Build');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
// 1. Load config
|
|
50
|
+
if (!flags.json) printStep('Loading configuration...');
|
|
51
|
+
const { config, absolutePath } = await loadConfig(args.config);
|
|
52
|
+
|
|
53
|
+
if (!flags.json) {
|
|
54
|
+
printKV('Config', path.relative(process.cwd(), absolutePath));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 2. Resolve manifest info
|
|
58
|
+
const manifest = (config as Record<string, unknown>).manifest as Record<string, unknown> | undefined;
|
|
59
|
+
const name = (manifest?.name as string) || (config as any).name || 'plugin';
|
|
60
|
+
const version = (manifest?.version as string) || (config as any).version || '0.0.0';
|
|
61
|
+
const packageFileName = `${name.replace(/[^a-z0-9._-]/gi, '-')}-${version}.${flags.format}`;
|
|
62
|
+
|
|
63
|
+
if (!flags.json) {
|
|
64
|
+
printKV('Package', `${name}@${version}`);
|
|
65
|
+
printStep('Collecting metadata...');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 3. Collect metadata statistics
|
|
69
|
+
const stats = collectMetadataStats(config);
|
|
70
|
+
const fileEntries: Array<{ path: string; size: number; category: string }> = [];
|
|
71
|
+
const warnings: string[] = [];
|
|
72
|
+
|
|
73
|
+
// 4. Serialize the config to JSON for artifact content
|
|
74
|
+
const configJson = JSON.stringify(config, null, 2);
|
|
75
|
+
const configBuffer = Buffer.from(configJson, 'utf-8');
|
|
76
|
+
fileEntries.push({ path: 'manifest.json', size: configBuffer.length, category: 'manifest' });
|
|
77
|
+
|
|
78
|
+
// 5. Compute checksums
|
|
79
|
+
if (!flags.json) printStep('Computing checksums...');
|
|
80
|
+
const manifestChecksum = crypto.createHash(flags.checksumAlgorithm).update(configBuffer).digest('hex');
|
|
81
|
+
|
|
82
|
+
// 6. Write output
|
|
83
|
+
const outDir = path.resolve(process.cwd(), flags.outDir);
|
|
84
|
+
if (!fs.existsSync(outDir)) {
|
|
85
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
86
|
+
}
|
|
87
|
+
const artifactPath = path.join(outDir, packageFileName);
|
|
88
|
+
|
|
89
|
+
if (!flags.json) printStep('Writing artifact...');
|
|
90
|
+
|
|
91
|
+
// Write the artifact (serialized config bundle)
|
|
92
|
+
fs.writeFileSync(artifactPath, configBuffer);
|
|
93
|
+
|
|
94
|
+
const artifactSize = configBuffer.length;
|
|
95
|
+
|
|
96
|
+
// 7. Compute artifact-level checksum
|
|
97
|
+
const artifactHash = crypto.createHash('sha256').update(configBuffer).digest('hex');
|
|
98
|
+
|
|
99
|
+
// 8. Write checksum file alongside artifact
|
|
100
|
+
const checksumPath = artifactPath + '.sha256';
|
|
101
|
+
fs.writeFileSync(checksumPath, `${artifactHash} ${packageFileName}\n`);
|
|
102
|
+
|
|
103
|
+
// 9. Handle signing
|
|
104
|
+
let signatureInfo: { algorithm: string; keyId: string } | undefined;
|
|
105
|
+
if (flags.sign) {
|
|
106
|
+
if (!flags.privateKeyPath) {
|
|
107
|
+
warnings.push('Signing requested but no --privateKeyPath provided; skipping signature');
|
|
108
|
+
} else if (!fs.existsSync(flags.privateKeyPath)) {
|
|
109
|
+
warnings.push(`Private key file not found: ${flags.privateKeyPath}; skipping signature`);
|
|
110
|
+
} else {
|
|
111
|
+
const privateKey = fs.readFileSync(flags.privateKeyPath, 'utf-8');
|
|
112
|
+
const signer = crypto.createSign('RSA-SHA256');
|
|
113
|
+
signer.update(configBuffer);
|
|
114
|
+
const signature = signer.sign(privateKey, 'base64');
|
|
115
|
+
const sigPath = artifactPath + '.sig';
|
|
116
|
+
fs.writeFileSync(sigPath, signature);
|
|
117
|
+
signatureInfo = { algorithm: 'RSA-SHA256', keyId: path.basename(flags.privateKeyPath) };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const durationMs = timer.elapsed();
|
|
122
|
+
|
|
123
|
+
// 10. Output result
|
|
124
|
+
const result = {
|
|
125
|
+
success: true,
|
|
126
|
+
artifactPath,
|
|
127
|
+
fileCount: fileEntries.length,
|
|
128
|
+
size: artifactSize,
|
|
129
|
+
durationMs,
|
|
130
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
131
|
+
artifact: {
|
|
132
|
+
name,
|
|
133
|
+
version,
|
|
134
|
+
format: flags.format,
|
|
135
|
+
checksums: {
|
|
136
|
+
algorithm: flags.checksumAlgorithm,
|
|
137
|
+
manifest: manifestChecksum,
|
|
138
|
+
files: { 'manifest.json': manifestChecksum },
|
|
139
|
+
},
|
|
140
|
+
signature: signatureInfo,
|
|
141
|
+
files: fileEntries,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
if (flags.json) {
|
|
146
|
+
console.log(JSON.stringify(result, null, 2));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Print summary
|
|
151
|
+
console.log('');
|
|
152
|
+
printSuccess(`Build complete ${chalk.dim(`(${durationMs}ms)`)}`);
|
|
153
|
+
console.log('');
|
|
154
|
+
printKV('Artifact', path.relative(process.cwd(), artifactPath));
|
|
155
|
+
printKV('Size', `${(artifactSize / 1024).toFixed(1)} KB`);
|
|
156
|
+
printKV('Checksum', `sha256:${artifactHash.slice(0, 16)}...`);
|
|
157
|
+
|
|
158
|
+
if (signatureInfo) {
|
|
159
|
+
printKV('Signature', `${signatureInfo.algorithm} (${signatureInfo.keyId})`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Print metadata counts
|
|
163
|
+
const counts = [
|
|
164
|
+
stats.objects > 0 && `${stats.objects} objects`,
|
|
165
|
+
stats.views > 0 && `${stats.views} views`,
|
|
166
|
+
stats.flows > 0 && `${stats.flows} flows`,
|
|
167
|
+
stats.pages > 0 && `${stats.pages} pages`,
|
|
168
|
+
stats.agents > 0 && `${stats.agents} agents`,
|
|
169
|
+
].filter(Boolean);
|
|
170
|
+
|
|
171
|
+
if (counts.length > 0) {
|
|
172
|
+
printKV('Contents', counts.join(', '));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
for (const w of warnings) {
|
|
176
|
+
printWarning(w);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
console.log('');
|
|
180
|
+
console.log(chalk.dim(' Next steps:'));
|
|
181
|
+
console.log(chalk.dim(' 1. Validate: os plugin validate dist/' + packageFileName));
|
|
182
|
+
console.log(chalk.dim(' 2. Publish: os plugin publish dist/' + packageFileName));
|
|
183
|
+
console.log('');
|
|
184
|
+
} catch (error: any) {
|
|
185
|
+
if (flags.json) {
|
|
186
|
+
console.log(JSON.stringify({ success: false, errorMessage: error.message }));
|
|
187
|
+
this.exit(1);
|
|
188
|
+
}
|
|
189
|
+
printError(error.message || String(error));
|
|
190
|
+
this.exit(1);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|