qa360 1.0.4 → 1.1.1
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/dist/commands/history.js +1 -1
- package/dist/commands/pack.js +1 -1
- package/dist/commands/run.d.ts +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +1 -1
- package/dist/commands/secrets.js +1 -1
- package/dist/commands/serve.js +1 -1
- package/dist/commands/verify.js +1 -1
- package/dist/core/adapters/gitleaks-secrets.d.ts +115 -0
- package/dist/core/adapters/gitleaks-secrets.d.ts.map +1 -0
- package/dist/core/adapters/gitleaks-secrets.js +410 -0
- package/dist/core/adapters/k6-perf.d.ts +86 -0
- package/dist/core/adapters/k6-perf.d.ts.map +1 -0
- package/dist/core/adapters/k6-perf.js +398 -0
- package/dist/core/adapters/osv-deps.d.ts +124 -0
- package/dist/core/adapters/osv-deps.d.ts.map +1 -0
- package/dist/core/adapters/osv-deps.js +372 -0
- package/dist/core/adapters/playwright-api.d.ts +82 -0
- package/dist/core/adapters/playwright-api.d.ts.map +1 -0
- package/dist/core/adapters/playwright-api.js +252 -0
- package/dist/core/adapters/playwright-ui.d.ts +115 -0
- package/dist/core/adapters/playwright-ui.d.ts.map +1 -0
- package/dist/core/adapters/playwright-ui.js +346 -0
- package/dist/core/adapters/semgrep-sast.d.ts +100 -0
- package/dist/core/adapters/semgrep-sast.d.ts.map +1 -0
- package/dist/core/adapters/semgrep-sast.js +322 -0
- package/dist/core/adapters/zap-dast.d.ts +134 -0
- package/dist/core/adapters/zap-dast.d.ts.map +1 -0
- package/dist/core/adapters/zap-dast.js +424 -0
- package/dist/core/hooks/compose.d.ts +62 -0
- package/dist/core/hooks/compose.d.ts.map +1 -0
- package/dist/core/hooks/compose.js +225 -0
- package/dist/core/hooks/runner.d.ts +69 -0
- package/dist/core/hooks/runner.d.ts.map +1 -0
- package/dist/core/hooks/runner.js +303 -0
- package/dist/core/index.d.ts +74 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +39 -0
- package/dist/core/pack/migrator.d.ts +52 -0
- package/dist/core/pack/migrator.d.ts.map +1 -0
- package/dist/core/pack/migrator.js +304 -0
- package/dist/core/pack/validator.d.ts +43 -0
- package/dist/core/pack/validator.d.ts.map +1 -0
- package/dist/core/pack/validator.js +292 -0
- package/dist/core/proof/bundle.d.ts +138 -0
- package/dist/core/proof/bundle.d.ts.map +1 -0
- package/dist/core/proof/bundle.js +160 -0
- package/dist/core/proof/canonicalize.d.ts +48 -0
- package/dist/core/proof/canonicalize.d.ts.map +1 -0
- package/dist/core/proof/canonicalize.js +105 -0
- package/dist/core/proof/index.d.ts +14 -0
- package/dist/core/proof/index.d.ts.map +1 -0
- package/dist/core/proof/index.js +18 -0
- package/dist/core/proof/schema.d.ts +218 -0
- package/dist/core/proof/schema.d.ts.map +1 -0
- package/dist/core/proof/schema.js +263 -0
- package/dist/core/proof/signer.d.ts +112 -0
- package/dist/core/proof/signer.d.ts.map +1 -0
- package/dist/core/proof/signer.js +226 -0
- package/dist/core/proof/verifier.d.ts +98 -0
- package/dist/core/proof/verifier.d.ts.map +1 -0
- package/dist/core/proof/verifier.js +302 -0
- package/dist/core/runner/phase3-runner.d.ts +102 -0
- package/dist/core/runner/phase3-runner.d.ts.map +1 -0
- package/dist/core/runner/phase3-runner.js +471 -0
- package/dist/core/secrets/crypto.d.ts +76 -0
- package/dist/core/secrets/crypto.d.ts.map +1 -0
- package/dist/core/secrets/crypto.js +225 -0
- package/dist/core/secrets/manager.d.ts +77 -0
- package/dist/core/secrets/manager.d.ts.map +1 -0
- package/dist/core/secrets/manager.js +219 -0
- package/dist/core/security/redaction-patterns-extended.d.ts +28 -0
- package/dist/core/security/redaction-patterns-extended.d.ts.map +1 -0
- package/dist/core/security/redaction-patterns-extended.js +247 -0
- package/dist/core/security/redactor.d.ts +72 -0
- package/dist/core/security/redactor.d.ts.map +1 -0
- package/dist/core/security/redactor.js +279 -0
- package/dist/core/serve/diagnostics-collector.d.ts +33 -0
- package/dist/core/serve/diagnostics-collector.d.ts.map +1 -0
- package/dist/core/serve/diagnostics-collector.js +149 -0
- package/dist/core/serve/health-checker.d.ts +45 -0
- package/dist/core/serve/health-checker.d.ts.map +1 -0
- package/dist/core/serve/health-checker.js +219 -0
- package/dist/core/serve/index.d.ts +9 -0
- package/dist/core/serve/index.d.ts.map +1 -0
- package/dist/core/serve/index.js +8 -0
- package/dist/core/serve/metrics-collector.d.ts +25 -0
- package/dist/core/serve/metrics-collector.d.ts.map +1 -0
- package/dist/core/serve/metrics-collector.js +322 -0
- package/dist/core/serve/process-manager.d.ts +37 -0
- package/dist/core/serve/process-manager.d.ts.map +1 -0
- package/dist/core/serve/process-manager.js +213 -0
- package/dist/core/serve/server.d.ts +37 -0
- package/dist/core/serve/server.d.ts.map +1 -0
- package/dist/core/serve/server.js +191 -0
- package/dist/core/types/pack-v1.d.ts +162 -0
- package/dist/core/types/pack-v1.d.ts.map +1 -0
- package/dist/core/types/pack-v1.js +5 -0
- package/dist/core/types/trust-score.d.ts +70 -0
- package/dist/core/types/trust-score.d.ts.map +1 -0
- package/dist/core/types/trust-score.js +191 -0
- package/dist/core/vault/cas.d.ts +87 -0
- package/dist/core/vault/cas.d.ts.map +1 -0
- package/dist/core/vault/cas.js +255 -0
- package/dist/core/vault/index.d.ts +205 -0
- package/dist/core/vault/index.d.ts.map +1 -0
- package/dist/core/vault/index.js +631 -0
- package/package.json +13 -6
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Core Engine
|
|
3
|
+
*
|
|
4
|
+
* The heart of QA360 - handles proof generation, cryptographic signatures,
|
|
5
|
+
* and evidence vault for verifiable quality assurance.
|
|
6
|
+
*/
|
|
7
|
+
// Core classes (Phase 1+ implementation)
|
|
8
|
+
export class QA360Core {
|
|
9
|
+
constructor() {
|
|
10
|
+
// Phase 1 implementation coming soon
|
|
11
|
+
}
|
|
12
|
+
async generateProof(pack, results) {
|
|
13
|
+
throw new Error('Phase 1 implementation coming soon');
|
|
14
|
+
}
|
|
15
|
+
async verifyProof(proof) {
|
|
16
|
+
throw new Error('Phase 1 implementation coming soon');
|
|
17
|
+
}
|
|
18
|
+
async calculateTrustScore(results) {
|
|
19
|
+
throw new Error('Phase 1 implementation coming soon');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Export version
|
|
23
|
+
export const VERSION = '0.9.0-core';
|
|
24
|
+
// Proof Bundle System (Phase 2)
|
|
25
|
+
export * from './proof/index.js';
|
|
26
|
+
// Vault & Evidence System
|
|
27
|
+
export { EvidenceVault } from './vault/index.js';
|
|
28
|
+
// Security & Redaction
|
|
29
|
+
export { SecurityRedactor } from './security/redactor.js';
|
|
30
|
+
// Secrets Management
|
|
31
|
+
export { SecretsManager } from './secrets/manager.js';
|
|
32
|
+
export { SecretsCrypto } from './secrets/crypto.js';
|
|
33
|
+
// Pack Validation & Migration
|
|
34
|
+
export { PackValidator } from './pack/validator.js';
|
|
35
|
+
export { PackMigrator } from './pack/migrator.js';
|
|
36
|
+
// Server & Observability
|
|
37
|
+
export { QA360Server } from './serve/server.js';
|
|
38
|
+
// Runner
|
|
39
|
+
export { Phase3Runner } from './runner/phase3-runner.js';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Pack Migrator
|
|
3
|
+
* Migrates legacy pack configurations to v1 format
|
|
4
|
+
*/
|
|
5
|
+
import { LegacyPackConfig, PackMigrationResult } from '../types/pack-v1.js';
|
|
6
|
+
export declare class PackMigrator {
|
|
7
|
+
/**
|
|
8
|
+
* Migrate legacy pack to v1 format
|
|
9
|
+
*/
|
|
10
|
+
migrate(legacyPack: LegacyPackConfig): PackMigrationResult;
|
|
11
|
+
/**
|
|
12
|
+
* Migrate pack name to v1 format
|
|
13
|
+
*/
|
|
14
|
+
private migrateName;
|
|
15
|
+
/**
|
|
16
|
+
* Migrate adapters and tests to quality gates
|
|
17
|
+
*/
|
|
18
|
+
private migrateGates;
|
|
19
|
+
/**
|
|
20
|
+
* Map legacy adapter names to quality gates
|
|
21
|
+
*/
|
|
22
|
+
private mapAdapterToGates;
|
|
23
|
+
/**
|
|
24
|
+
* Migrate targets from legacy configuration
|
|
25
|
+
*/
|
|
26
|
+
private migrateTargets;
|
|
27
|
+
/**
|
|
28
|
+
* Extract API URL from legacy configuration
|
|
29
|
+
*/
|
|
30
|
+
private extractApiUrl;
|
|
31
|
+
/**
|
|
32
|
+
* Extract Web URL from legacy configuration
|
|
33
|
+
*/
|
|
34
|
+
private extractWebUrl;
|
|
35
|
+
/**
|
|
36
|
+
* Validate URL format
|
|
37
|
+
*/
|
|
38
|
+
private isValidUrl;
|
|
39
|
+
/**
|
|
40
|
+
* Migrate environment variables
|
|
41
|
+
*/
|
|
42
|
+
private migrateEnvironment;
|
|
43
|
+
/**
|
|
44
|
+
* Migrate hooks from legacy format
|
|
45
|
+
*/
|
|
46
|
+
private migrateHooks;
|
|
47
|
+
/**
|
|
48
|
+
* Check if a value looks like a secret
|
|
49
|
+
*/
|
|
50
|
+
private looksLikeSecret;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=migrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrator.d.ts","sourceRoot":"","sources":["../../../src/core/pack/migrator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAgB,gBAAgB,EAAE,mBAAmB,EAAoC,MAAM,qBAAqB,CAAC;AAE5H,qBAAa,YAAY;IAEvB;;OAEG;IACH,OAAO,CAAC,UAAU,EAAE,gBAAgB,GAAG,mBAAmB;IA6E1D;;OAEG;IACH,OAAO,CAAC,WAAW;IAiBnB;;OAEG;IACH,OAAO,CAAC,YAAY;IAqCpB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAgBzB;;OAEG;IACH,OAAO,CAAC,cAAc;IAsCtB;;OAEG;IACH,OAAO,CAAC,aAAa;IA2BrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAerB;;OAEG;IACH,OAAO,CAAC,UAAU;IASlB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA4B1B;;OAEG;IACH,OAAO,CAAC,YAAY;IAoCpB;;OAEG;IACH,OAAO,CAAC,eAAe;CAUxB"}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Pack Migrator
|
|
3
|
+
* Migrates legacy pack configurations to v1 format
|
|
4
|
+
*/
|
|
5
|
+
export class PackMigrator {
|
|
6
|
+
/**
|
|
7
|
+
* Migrate legacy pack to v1 format
|
|
8
|
+
*/
|
|
9
|
+
migrate(legacyPack) {
|
|
10
|
+
const changes = [];
|
|
11
|
+
const warnings = [];
|
|
12
|
+
try {
|
|
13
|
+
const v1Pack = {
|
|
14
|
+
version: 1,
|
|
15
|
+
name: this.migrateName(legacyPack.name, changes),
|
|
16
|
+
gates: this.migrateGates(legacyPack, changes, warnings),
|
|
17
|
+
};
|
|
18
|
+
// Optional fields
|
|
19
|
+
if (legacyPack.description) {
|
|
20
|
+
v1Pack.description = legacyPack.description;
|
|
21
|
+
}
|
|
22
|
+
// Migrate targets from adapters and tests
|
|
23
|
+
const targets = this.migrateTargets(legacyPack, changes, warnings);
|
|
24
|
+
if (Object.keys(targets).length > 0) {
|
|
25
|
+
v1Pack.targets = targets;
|
|
26
|
+
}
|
|
27
|
+
// Migrate environment
|
|
28
|
+
if (legacyPack.environment) {
|
|
29
|
+
v1Pack.environment = this.migrateEnvironment(legacyPack.environment, changes, warnings);
|
|
30
|
+
}
|
|
31
|
+
// Migrate hooks
|
|
32
|
+
if (legacyPack.hooks) {
|
|
33
|
+
v1Pack.hooks = this.migrateHooks(legacyPack.hooks, changes);
|
|
34
|
+
}
|
|
35
|
+
// Add default execution settings
|
|
36
|
+
v1Pack.execution = {
|
|
37
|
+
retry_on: ['ECONNRESET', '502'],
|
|
38
|
+
max_retries: 1,
|
|
39
|
+
fail_on_readiness: true,
|
|
40
|
+
timeout: 30000
|
|
41
|
+
};
|
|
42
|
+
changes.push({
|
|
43
|
+
type: 'added',
|
|
44
|
+
path: 'execution',
|
|
45
|
+
newValue: v1Pack.execution,
|
|
46
|
+
reason: 'Added default execution configuration for v1'
|
|
47
|
+
});
|
|
48
|
+
// Add default observability
|
|
49
|
+
v1Pack.observability = {
|
|
50
|
+
metrics: true,
|
|
51
|
+
trace: 'basic'
|
|
52
|
+
};
|
|
53
|
+
changes.push({
|
|
54
|
+
type: 'added',
|
|
55
|
+
path: 'observability',
|
|
56
|
+
newValue: v1Pack.observability,
|
|
57
|
+
reason: 'Added default observability configuration for v1'
|
|
58
|
+
});
|
|
59
|
+
return {
|
|
60
|
+
success: true,
|
|
61
|
+
fromVersion: legacyPack.version || '0.9.x',
|
|
62
|
+
toVersion: '1',
|
|
63
|
+
changes,
|
|
64
|
+
warnings
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
fromVersion: legacyPack.version || '0.9.x',
|
|
71
|
+
toVersion: '1',
|
|
72
|
+
changes,
|
|
73
|
+
warnings: [...warnings, `Migration failed: ${error instanceof Error ? error.message : 'Unknown error'}`]
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Migrate pack name to v1 format
|
|
79
|
+
*/
|
|
80
|
+
migrateName(name, changes) {
|
|
81
|
+
// Sanitize name for v1 requirements (alphanumeric, underscore, hyphen only)
|
|
82
|
+
const sanitized = name.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
83
|
+
if (sanitized !== name) {
|
|
84
|
+
changes.push({
|
|
85
|
+
type: 'modified',
|
|
86
|
+
path: 'name',
|
|
87
|
+
oldValue: name,
|
|
88
|
+
newValue: sanitized,
|
|
89
|
+
reason: 'Sanitized name to match v1 pattern requirements'
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return sanitized;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Migrate adapters and tests to quality gates
|
|
96
|
+
*/
|
|
97
|
+
migrateGates(legacyPack, changes, warnings) {
|
|
98
|
+
const gates = new Set();
|
|
99
|
+
// Map adapters to gates
|
|
100
|
+
if (legacyPack.adapters) {
|
|
101
|
+
for (const adapter of legacyPack.adapters) {
|
|
102
|
+
const mappedGates = this.mapAdapterToGates(adapter);
|
|
103
|
+
mappedGates.forEach(gate => gates.add(gate));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Map tests to gates
|
|
107
|
+
if (legacyPack.tests) {
|
|
108
|
+
for (const test of legacyPack.tests) {
|
|
109
|
+
const mappedGates = this.mapAdapterToGates(test.adapter);
|
|
110
|
+
mappedGates.forEach(gate => gates.add(gate));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Default to api_smoke if no gates detected
|
|
114
|
+
if (gates.size === 0) {
|
|
115
|
+
gates.add('api_smoke');
|
|
116
|
+
warnings.push('No recognizable adapters found, defaulting to api_smoke gate');
|
|
117
|
+
}
|
|
118
|
+
const gateArray = Array.from(gates);
|
|
119
|
+
changes.push({
|
|
120
|
+
type: 'added',
|
|
121
|
+
path: 'gates',
|
|
122
|
+
newValue: gateArray,
|
|
123
|
+
reason: `Mapped adapters [${legacyPack.adapters?.join(', ') || 'none'}] to quality gates`
|
|
124
|
+
});
|
|
125
|
+
return gateArray;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Map legacy adapter names to quality gates
|
|
129
|
+
*/
|
|
130
|
+
mapAdapterToGates(adapter) {
|
|
131
|
+
const mapping = {
|
|
132
|
+
'playwright': ['api_smoke', 'ui'],
|
|
133
|
+
'k6': ['perf'],
|
|
134
|
+
'lighthouse': ['perf', 'a11y'],
|
|
135
|
+
'semgrep': ['sast'],
|
|
136
|
+
'zap': ['dast'],
|
|
137
|
+
'axe': ['a11y'],
|
|
138
|
+
'jest': ['api_smoke'],
|
|
139
|
+
'cypress': ['ui'],
|
|
140
|
+
'puppeteer': ['ui']
|
|
141
|
+
};
|
|
142
|
+
return mapping[adapter.toLowerCase()] || ['api_smoke'];
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Migrate targets from legacy configuration
|
|
146
|
+
*/
|
|
147
|
+
migrateTargets(legacyPack, changes, warnings) {
|
|
148
|
+
const targets = {};
|
|
149
|
+
// Try to extract API target from environment or tests
|
|
150
|
+
const apiUrl = this.extractApiUrl(legacyPack);
|
|
151
|
+
if (apiUrl) {
|
|
152
|
+
targets.api = {
|
|
153
|
+
baseUrl: apiUrl,
|
|
154
|
+
smoke: ['GET /health -> 200'] // Default smoke test
|
|
155
|
+
};
|
|
156
|
+
changes.push({
|
|
157
|
+
type: 'added',
|
|
158
|
+
path: 'targets.api',
|
|
159
|
+
newValue: targets.api,
|
|
160
|
+
reason: `Extracted API target from configuration`
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
// Try to extract Web target
|
|
164
|
+
const webUrl = this.extractWebUrl(legacyPack);
|
|
165
|
+
if (webUrl && webUrl !== apiUrl) {
|
|
166
|
+
targets.web = {
|
|
167
|
+
baseUrl: webUrl,
|
|
168
|
+
pages: ['/'] // Default to homepage
|
|
169
|
+
};
|
|
170
|
+
changes.push({
|
|
171
|
+
type: 'added',
|
|
172
|
+
path: 'targets.web',
|
|
173
|
+
newValue: targets.web,
|
|
174
|
+
reason: `Extracted web target from configuration`
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
return targets;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Extract API URL from legacy configuration
|
|
181
|
+
*/
|
|
182
|
+
extractApiUrl(legacyPack) {
|
|
183
|
+
// Check environment variables
|
|
184
|
+
if (legacyPack.environment) {
|
|
185
|
+
const candidates = ['API_URL', 'BASE_URL', 'TARGET_URL', 'SERVER_URL'];
|
|
186
|
+
for (const candidate of candidates) {
|
|
187
|
+
const url = legacyPack.environment[candidate];
|
|
188
|
+
if (url && this.isValidUrl(url)) {
|
|
189
|
+
return url;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Check test configurations
|
|
194
|
+
if (legacyPack.tests) {
|
|
195
|
+
for (const test of legacyPack.tests) {
|
|
196
|
+
if (test.config?.baseURL && this.isValidUrl(test.config.baseURL)) {
|
|
197
|
+
return test.config.baseURL;
|
|
198
|
+
}
|
|
199
|
+
if (test.config?.url && this.isValidUrl(test.config.url)) {
|
|
200
|
+
return test.config.url;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Extract Web URL from legacy configuration
|
|
208
|
+
*/
|
|
209
|
+
extractWebUrl(legacyPack) {
|
|
210
|
+
// Similar logic to API URL but looking for web-specific patterns
|
|
211
|
+
if (legacyPack.environment) {
|
|
212
|
+
const candidates = ['WEB_URL', 'FRONTEND_URL', 'UI_URL', 'APP_URL'];
|
|
213
|
+
for (const candidate of candidates) {
|
|
214
|
+
const url = legacyPack.environment[candidate];
|
|
215
|
+
if (url && this.isValidUrl(url)) {
|
|
216
|
+
return url;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Validate URL format
|
|
224
|
+
*/
|
|
225
|
+
isValidUrl(url) {
|
|
226
|
+
try {
|
|
227
|
+
new URL(url);
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Migrate environment variables
|
|
236
|
+
*/
|
|
237
|
+
migrateEnvironment(env, changes, warnings) {
|
|
238
|
+
const migratedEnv = {};
|
|
239
|
+
for (const [key, value] of Object.entries(env)) {
|
|
240
|
+
// Convert to uppercase with underscores (v1 requirement)
|
|
241
|
+
const normalizedKey = key.toUpperCase().replace(/[^A-Z0-9_]/g, '_');
|
|
242
|
+
if (normalizedKey !== key) {
|
|
243
|
+
changes.push({
|
|
244
|
+
type: 'renamed',
|
|
245
|
+
path: `environment.${key}`,
|
|
246
|
+
oldValue: key,
|
|
247
|
+
newValue: normalizedKey,
|
|
248
|
+
reason: 'Normalized environment variable name for v1 requirements'
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
// Check for potential secrets
|
|
252
|
+
if (this.looksLikeSecret(value)) {
|
|
253
|
+
warnings.push(`Environment variable ${normalizedKey} appears to contain a secret. Consider using: \${{ secrets.${normalizedKey} }}`);
|
|
254
|
+
}
|
|
255
|
+
migratedEnv[normalizedKey] = value;
|
|
256
|
+
}
|
|
257
|
+
return migratedEnv;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Migrate hooks from legacy format
|
|
261
|
+
*/
|
|
262
|
+
migrateHooks(hooks, changes) {
|
|
263
|
+
const migratedHooks = {};
|
|
264
|
+
if (hooks.beforeAll) {
|
|
265
|
+
migratedHooks.beforeAll = hooks.beforeAll.map((cmd) => ({
|
|
266
|
+
run: cmd,
|
|
267
|
+
timeout: 30000
|
|
268
|
+
}));
|
|
269
|
+
changes.push({
|
|
270
|
+
type: 'modified',
|
|
271
|
+
path: 'hooks.beforeAll',
|
|
272
|
+
oldValue: hooks.beforeAll,
|
|
273
|
+
newValue: migratedHooks.beforeAll,
|
|
274
|
+
reason: 'Converted string commands to v1 hook object format'
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
if (hooks.afterAll) {
|
|
278
|
+
migratedHooks.afterAll = hooks.afterAll.map((cmd) => ({
|
|
279
|
+
run: cmd,
|
|
280
|
+
timeout: 30000
|
|
281
|
+
}));
|
|
282
|
+
changes.push({
|
|
283
|
+
type: 'modified',
|
|
284
|
+
path: 'hooks.afterAll',
|
|
285
|
+
oldValue: hooks.afterAll,
|
|
286
|
+
newValue: migratedHooks.afterAll,
|
|
287
|
+
reason: 'Converted string commands to v1 hook object format'
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
return migratedHooks;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Check if a value looks like a secret
|
|
294
|
+
*/
|
|
295
|
+
looksLikeSecret(value) {
|
|
296
|
+
const secretPatterns = [
|
|
297
|
+
/^[A-Za-z0-9+/]{20,}={0,2}$/, // Base64-like
|
|
298
|
+
/^[a-f0-9]{32,}$/i, // Hex tokens
|
|
299
|
+
/^sk-[a-zA-Z0-9]{32,}$/, // API keys
|
|
300
|
+
/^ghp_[a-zA-Z0-9]{36}$/, // GitHub tokens
|
|
301
|
+
];
|
|
302
|
+
return secretPatterns.some(pattern => pattern.test(value));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Pack v1 Validator
|
|
3
|
+
* Validates pack.yml files against the official schema
|
|
4
|
+
*/
|
|
5
|
+
import { PackValidationResult } from '../types/pack-v1.js';
|
|
6
|
+
export declare class PackValidator {
|
|
7
|
+
private ajv;
|
|
8
|
+
private schema;
|
|
9
|
+
constructor();
|
|
10
|
+
/**
|
|
11
|
+
* Validate a pack configuration
|
|
12
|
+
*/
|
|
13
|
+
validate(pack: any): PackValidationResult;
|
|
14
|
+
/**
|
|
15
|
+
* Validate business rules beyond schema
|
|
16
|
+
*/
|
|
17
|
+
private validateBusinessRules;
|
|
18
|
+
/**
|
|
19
|
+
* Check if a value looks like a secret
|
|
20
|
+
*/
|
|
21
|
+
private looksLikeSecret;
|
|
22
|
+
/**
|
|
23
|
+
* Check if a value is a secret reference
|
|
24
|
+
*/
|
|
25
|
+
private isSecretReference;
|
|
26
|
+
/**
|
|
27
|
+
* Validate hook commands for security issues
|
|
28
|
+
*/
|
|
29
|
+
private validateHookSecurity;
|
|
30
|
+
/**
|
|
31
|
+
* Get error code from AJV error
|
|
32
|
+
*/
|
|
33
|
+
private getErrorCode;
|
|
34
|
+
/**
|
|
35
|
+
* Format error message for better UX
|
|
36
|
+
*/
|
|
37
|
+
private formatErrorMessage;
|
|
38
|
+
/**
|
|
39
|
+
* Get suggestion for fixing error
|
|
40
|
+
*/
|
|
41
|
+
private getSuggestion;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../src/core/pack/validator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAAgB,oBAAoB,EAA8C,MAAM,qBAAqB,CAAC;AAErH,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,MAAM,CAAM;;IAkBpB;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,GAAG,GAAG,oBAAoB;IAgCzC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA0G7B;;OAEG;IACH,OAAO,CAAC,eAAe;IAYvB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA2B5B;;OAEG;IACH,OAAO,CAAC,YAAY;IAoBpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAmC1B;;OAEG;IACH,OAAO,CAAC,aAAa;CAiCtB"}
|