qa360 1.0.3 → 1.1.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/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 +12 -6
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Canonicalization for deterministic hashing
|
|
3
|
+
*
|
|
4
|
+
* Implements RFC 8785-like canonicalization:
|
|
5
|
+
* - Alphabetically sorted keys (recursive)
|
|
6
|
+
* - UTF-8 NFC normalization
|
|
7
|
+
* - No whitespace (compact)
|
|
8
|
+
* - Deterministic across platforms
|
|
9
|
+
*
|
|
10
|
+
* @see docs/rfc/proof-bundle-v1.md#4-canonicalization
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Canonicalize a JavaScript object into deterministic JSON string
|
|
14
|
+
*
|
|
15
|
+
* @param obj - Object to canonicalize
|
|
16
|
+
* @returns Canonical JSON string (compact, sorted keys, UTF-8 NFC)
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const obj = { b: 2, a: 1 };
|
|
21
|
+
* const canonical = canonicalize(obj);
|
|
22
|
+
* // Returns: '{"a":1,"b":2}\n'
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function canonicalize(obj) {
|
|
26
|
+
// Handle primitives
|
|
27
|
+
if (obj === null)
|
|
28
|
+
return 'null';
|
|
29
|
+
if (obj === undefined)
|
|
30
|
+
return 'null'; // Treat undefined as null
|
|
31
|
+
const type = typeof obj;
|
|
32
|
+
if (type === 'boolean')
|
|
33
|
+
return obj ? 'true' : 'false';
|
|
34
|
+
if (type === 'number') {
|
|
35
|
+
// Ensure decimal notation (no scientific notation)
|
|
36
|
+
if (!isFinite(obj)) {
|
|
37
|
+
throw new Error('Cannot canonicalize non-finite number');
|
|
38
|
+
}
|
|
39
|
+
return String(obj);
|
|
40
|
+
}
|
|
41
|
+
if (type === 'string') {
|
|
42
|
+
// Unicode NFC normalization
|
|
43
|
+
const normalized = obj.normalize('NFC');
|
|
44
|
+
// JSON.stringify handles escaping
|
|
45
|
+
return JSON.stringify(normalized);
|
|
46
|
+
}
|
|
47
|
+
// Handle arrays
|
|
48
|
+
if (Array.isArray(obj)) {
|
|
49
|
+
const items = obj.map(item => canonicalize(item));
|
|
50
|
+
return `[${items.join(',')}]`;
|
|
51
|
+
}
|
|
52
|
+
// Handle objects
|
|
53
|
+
if (type === 'object') {
|
|
54
|
+
// Get keys and sort alphabetically
|
|
55
|
+
const keys = Object.keys(obj).sort();
|
|
56
|
+
// Build key-value pairs
|
|
57
|
+
const pairs = keys.map(key => {
|
|
58
|
+
const value = obj[key];
|
|
59
|
+
const canonicalKey = canonicalize(key);
|
|
60
|
+
const canonicalValue = canonicalize(value);
|
|
61
|
+
return `${canonicalKey}:${canonicalValue}`;
|
|
62
|
+
});
|
|
63
|
+
return `{${pairs.join(',')}}`;
|
|
64
|
+
}
|
|
65
|
+
throw new Error(`Cannot canonicalize type: ${type}`);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Canonicalize and append newline (standard format)
|
|
69
|
+
*
|
|
70
|
+
* @param obj - Object to canonicalize
|
|
71
|
+
* @returns Canonical JSON string with trailing newline
|
|
72
|
+
*/
|
|
73
|
+
export function canonicalizeWithNewline(obj) {
|
|
74
|
+
return canonicalize(obj) + '\n';
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Remove signature field and canonicalize
|
|
78
|
+
* Used for signature verification
|
|
79
|
+
*
|
|
80
|
+
* @param bundle - Proof bundle (may contain signature field)
|
|
81
|
+
* @returns Canonical JSON without signature field
|
|
82
|
+
*/
|
|
83
|
+
export function canonicalizeForSigning(bundle) {
|
|
84
|
+
// Clone to avoid mutating original
|
|
85
|
+
const clone = JSON.parse(JSON.stringify(bundle));
|
|
86
|
+
// Remove signature field
|
|
87
|
+
delete clone.signature;
|
|
88
|
+
return canonicalizeWithNewline(clone);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Verify canonicalization is deterministic
|
|
92
|
+
*
|
|
93
|
+
* @param obj - Object to test
|
|
94
|
+
* @returns true if canonicalization is stable
|
|
95
|
+
*/
|
|
96
|
+
export function isCanonicalStable(obj) {
|
|
97
|
+
try {
|
|
98
|
+
const first = canonicalize(obj);
|
|
99
|
+
const second = canonicalize(obj);
|
|
100
|
+
return first === second;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Proof Bundle System
|
|
3
|
+
*
|
|
4
|
+
* Cryptographically signed, verifiable proof bundles for test results.
|
|
5
|
+
*
|
|
6
|
+
* @module @qa360/core/proof
|
|
7
|
+
* @see docs/rfc/proof-bundle-v1.md
|
|
8
|
+
*/
|
|
9
|
+
export { canonicalize, canonicalizeWithNewline, canonicalizeForSigning, isCanonicalStable, } from './canonicalize.js';
|
|
10
|
+
export { generateKeys, saveKeys, loadKeys, keysExist, initializeKeys, ensureProofKeys, sha256, sign, verify, testRoundtrip, getKeyDirectory, getKeyPaths, type KeyPair, type KeyPaths, } from './signer.js';
|
|
11
|
+
export { validateProofBundle, getSchema, patterns, type ValidationResult, } from './schema.js';
|
|
12
|
+
export { createProofBundle, createProofBundleFromPack, computeSHA256, type ProofBundle, type RunMetadata, type Environment, type CIContext, type Artifact, type TestResults, type Gate, type SigningMetadata, type TimestampInfo, type IdentityInfo, type ProofBundleParams, } from './bundle.js';
|
|
13
|
+
export { verifyProofBundle, verifyArtifact, verifyArtifacts, verifyComplete, verifyProofFile, verifyPhase3Proof, VerificationCode, type VerificationResult, type VerificationDetails, type ArtifactVerificationOptions, } from './verifier.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/proof/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,cAAc,EACd,eAAe,EACf,MAAM,EACN,IAAI,EACJ,MAAM,EACN,aAAa,EACb,eAAe,EACf,WAAW,EACX,KAAK,OAAO,EACZ,KAAK,QAAQ,GACd,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,mBAAmB,EACnB,SAAS,EACT,QAAQ,EACR,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,aAAa,EACb,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,IAAI,EACT,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,2BAA2B,GACjC,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Proof Bundle System
|
|
3
|
+
*
|
|
4
|
+
* Cryptographically signed, verifiable proof bundles for test results.
|
|
5
|
+
*
|
|
6
|
+
* @module @qa360/core/proof
|
|
7
|
+
* @see docs/rfc/proof-bundle-v1.md
|
|
8
|
+
*/
|
|
9
|
+
// Canonicalization
|
|
10
|
+
export { canonicalize, canonicalizeWithNewline, canonicalizeForSigning, isCanonicalStable, } from './canonicalize.js';
|
|
11
|
+
// Signing
|
|
12
|
+
export { generateKeys, saveKeys, loadKeys, keysExist, initializeKeys, ensureProofKeys, sha256, sign, verify, testRoundtrip, getKeyDirectory, getKeyPaths, } from './signer.js';
|
|
13
|
+
// Schema validation
|
|
14
|
+
export { validateProofBundle, getSchema, patterns, } from './schema.js';
|
|
15
|
+
// Bundle creation
|
|
16
|
+
export { createProofBundle, createProofBundleFromPack, computeSHA256, } from './bundle.js';
|
|
17
|
+
// Verification
|
|
18
|
+
export { verifyProofBundle, verifyArtifact, verifyArtifacts, verifyComplete, verifyProofFile, verifyPhase3Proof, VerificationCode, } from './verifier.js';
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Schema Validation for Proof Bundles
|
|
3
|
+
*
|
|
4
|
+
* Validates proof bundles against the v1 schema using AJV.
|
|
5
|
+
*
|
|
6
|
+
* @see docs/rfc/proof-bundle-v1.md#7-json-schema
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Validation result
|
|
10
|
+
*/
|
|
11
|
+
export interface ValidationResult {
|
|
12
|
+
valid: boolean;
|
|
13
|
+
errors?: string[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Validate proof bundle against schema
|
|
17
|
+
*
|
|
18
|
+
* @param bundle - Proof bundle to validate
|
|
19
|
+
* @returns Validation result with errors if invalid
|
|
20
|
+
*/
|
|
21
|
+
export declare function validateProofBundle(bundle: any): ValidationResult;
|
|
22
|
+
/**
|
|
23
|
+
* Get the JSON Schema object
|
|
24
|
+
*
|
|
25
|
+
* @returns Proof Bundle v1 schema
|
|
26
|
+
*/
|
|
27
|
+
export declare function getSchema(): {
|
|
28
|
+
$schema: string;
|
|
29
|
+
$id: string;
|
|
30
|
+
title: string;
|
|
31
|
+
type: string;
|
|
32
|
+
required: string[];
|
|
33
|
+
additionalProperties: boolean;
|
|
34
|
+
properties: {
|
|
35
|
+
spec: {
|
|
36
|
+
type: string;
|
|
37
|
+
const: string;
|
|
38
|
+
};
|
|
39
|
+
run: {
|
|
40
|
+
type: string;
|
|
41
|
+
required: string[];
|
|
42
|
+
additionalProperties: boolean;
|
|
43
|
+
properties: {
|
|
44
|
+
id: {
|
|
45
|
+
type: string;
|
|
46
|
+
format: string;
|
|
47
|
+
};
|
|
48
|
+
startedAt: {
|
|
49
|
+
type: string;
|
|
50
|
+
format: string;
|
|
51
|
+
};
|
|
52
|
+
finishedAt: {
|
|
53
|
+
type: string;
|
|
54
|
+
format: string;
|
|
55
|
+
};
|
|
56
|
+
environment: {
|
|
57
|
+
type: string;
|
|
58
|
+
required: string[];
|
|
59
|
+
additionalProperties: boolean;
|
|
60
|
+
properties: {
|
|
61
|
+
os: {
|
|
62
|
+
type: string;
|
|
63
|
+
enum: string[];
|
|
64
|
+
};
|
|
65
|
+
node: {
|
|
66
|
+
type: string;
|
|
67
|
+
pattern: string;
|
|
68
|
+
};
|
|
69
|
+
arch: {
|
|
70
|
+
type: string;
|
|
71
|
+
enum: string[];
|
|
72
|
+
};
|
|
73
|
+
ci: {
|
|
74
|
+
type: string;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
packHash: {
|
|
79
|
+
type: string;
|
|
80
|
+
pattern: string;
|
|
81
|
+
};
|
|
82
|
+
ciContext: {
|
|
83
|
+
type: string;
|
|
84
|
+
properties: {
|
|
85
|
+
provider: {
|
|
86
|
+
type: string[];
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
artifacts: {
|
|
93
|
+
type: string;
|
|
94
|
+
items: {
|
|
95
|
+
type: string;
|
|
96
|
+
required: string[];
|
|
97
|
+
additionalProperties: boolean;
|
|
98
|
+
properties: {
|
|
99
|
+
name: {
|
|
100
|
+
type: string;
|
|
101
|
+
minLength: number;
|
|
102
|
+
};
|
|
103
|
+
sha256: {
|
|
104
|
+
type: string;
|
|
105
|
+
pattern: string;
|
|
106
|
+
};
|
|
107
|
+
size: {
|
|
108
|
+
type: string;
|
|
109
|
+
minimum: number;
|
|
110
|
+
};
|
|
111
|
+
path: {
|
|
112
|
+
type: string;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
results: {
|
|
118
|
+
type: string;
|
|
119
|
+
required: string[];
|
|
120
|
+
additionalProperties: boolean;
|
|
121
|
+
properties: {
|
|
122
|
+
trustScore: {
|
|
123
|
+
type: string;
|
|
124
|
+
minimum: number;
|
|
125
|
+
maximum: number;
|
|
126
|
+
};
|
|
127
|
+
gates: {
|
|
128
|
+
type: string;
|
|
129
|
+
items: {
|
|
130
|
+
type: string;
|
|
131
|
+
required: string[];
|
|
132
|
+
additionalProperties: boolean;
|
|
133
|
+
properties: {
|
|
134
|
+
name: {
|
|
135
|
+
type: string;
|
|
136
|
+
minLength: number;
|
|
137
|
+
};
|
|
138
|
+
status: {
|
|
139
|
+
type: string;
|
|
140
|
+
enum: string[];
|
|
141
|
+
};
|
|
142
|
+
metrics: {
|
|
143
|
+
type: string;
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
signing: {
|
|
151
|
+
type: string;
|
|
152
|
+
required: string[];
|
|
153
|
+
additionalProperties: boolean;
|
|
154
|
+
properties: {
|
|
155
|
+
algo: {
|
|
156
|
+
type: string;
|
|
157
|
+
const: string;
|
|
158
|
+
};
|
|
159
|
+
signerId: {
|
|
160
|
+
type: string;
|
|
161
|
+
minLength: number;
|
|
162
|
+
};
|
|
163
|
+
timestamp: {
|
|
164
|
+
type: string;
|
|
165
|
+
required: string[];
|
|
166
|
+
properties: {
|
|
167
|
+
type: {
|
|
168
|
+
type: string;
|
|
169
|
+
enum: string[];
|
|
170
|
+
};
|
|
171
|
+
token: {
|
|
172
|
+
type: string[];
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
identity: {
|
|
177
|
+
type: string;
|
|
178
|
+
required: string[];
|
|
179
|
+
properties: {
|
|
180
|
+
type: {
|
|
181
|
+
type: string;
|
|
182
|
+
enum: string[];
|
|
183
|
+
};
|
|
184
|
+
evidence: {
|
|
185
|
+
type: string[];
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
signature: {
|
|
192
|
+
type: string;
|
|
193
|
+
pattern: string;
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* Validate specific field patterns
|
|
199
|
+
*/
|
|
200
|
+
export declare const patterns: {
|
|
201
|
+
/**
|
|
202
|
+
* Validate SHA-256 hash format
|
|
203
|
+
*/
|
|
204
|
+
sha256: (hash: string) => boolean;
|
|
205
|
+
/**
|
|
206
|
+
* Validate UUID v4 format
|
|
207
|
+
*/
|
|
208
|
+
uuid: (id: string) => boolean;
|
|
209
|
+
/**
|
|
210
|
+
* Validate Ed25519 signature format (base64, 88 chars)
|
|
211
|
+
*/
|
|
212
|
+
signature: (sig: string) => boolean;
|
|
213
|
+
/**
|
|
214
|
+
* Validate Node.js version format
|
|
215
|
+
*/
|
|
216
|
+
nodeVersion: (version: string) => boolean;
|
|
217
|
+
};
|
|
218
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/core/proof/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AA4MD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,GAAG,GAAG,gBAAgB,CAcjE;AAED;;;;GAIG;AACH,wBAAgB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAExB;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ;IACnB;;OAEG;mBACY,MAAM,KAAG,OAAO;IAI/B;;OAEG;eACQ,MAAM,KAAG,OAAO;IAI3B;;OAEG;qBACc,MAAM,KAAG,OAAO;IAIjC;;OAEG;2BACoB,MAAM,KAAG,OAAO;CAGxC,CAAC"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Schema Validation for Proof Bundles
|
|
3
|
+
*
|
|
4
|
+
* Validates proof bundles against the v1 schema using AJV.
|
|
5
|
+
*
|
|
6
|
+
* @see docs/rfc/proof-bundle-v1.md#7-json-schema
|
|
7
|
+
*/
|
|
8
|
+
import Ajv2020 from 'ajv/dist/2020.js';
|
|
9
|
+
import addFormats from 'ajv-formats';
|
|
10
|
+
/**
|
|
11
|
+
* Proof Bundle v1 JSON Schema (Draft 2020-12)
|
|
12
|
+
*
|
|
13
|
+
* Uses AJV 2020-12 for full JSON Schema 2020-12 support.
|
|
14
|
+
* This ensures compatibility with the RFC Proof Bundle v1 specification.
|
|
15
|
+
*/
|
|
16
|
+
const PROOF_BUNDLE_SCHEMA = {
|
|
17
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
18
|
+
$id: 'https://qa360.dev/schemas/proof-bundle-v1.json',
|
|
19
|
+
title: 'QA360 Proof Bundle v1',
|
|
20
|
+
type: 'object',
|
|
21
|
+
required: ['spec', 'run', 'artifacts', 'results', 'signing', 'signature'],
|
|
22
|
+
additionalProperties: false,
|
|
23
|
+
properties: {
|
|
24
|
+
spec: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
const: 'qa360.proof.v1',
|
|
27
|
+
},
|
|
28
|
+
run: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
required: ['id', 'startedAt', 'finishedAt', 'environment', 'packHash'],
|
|
31
|
+
additionalProperties: false,
|
|
32
|
+
properties: {
|
|
33
|
+
id: {
|
|
34
|
+
type: 'string',
|
|
35
|
+
format: 'uuid',
|
|
36
|
+
},
|
|
37
|
+
startedAt: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
format: 'date-time',
|
|
40
|
+
},
|
|
41
|
+
finishedAt: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
format: 'date-time',
|
|
44
|
+
},
|
|
45
|
+
environment: {
|
|
46
|
+
type: 'object',
|
|
47
|
+
required: ['os', 'node', 'arch', 'ci'],
|
|
48
|
+
additionalProperties: false,
|
|
49
|
+
properties: {
|
|
50
|
+
os: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
enum: ['windows', 'linux', 'darwin'],
|
|
53
|
+
},
|
|
54
|
+
node: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
pattern: '^\\d+\\.\\d+\\.\\d+$',
|
|
57
|
+
},
|
|
58
|
+
arch: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
enum: ['x64', 'arm64'],
|
|
61
|
+
},
|
|
62
|
+
ci: {
|
|
63
|
+
type: 'boolean',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
packHash: {
|
|
68
|
+
type: 'string',
|
|
69
|
+
pattern: '^sha256-[0-9a-f]{64}$',
|
|
70
|
+
},
|
|
71
|
+
ciContext: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: {
|
|
74
|
+
provider: {
|
|
75
|
+
type: ['string', 'null'],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
artifacts: {
|
|
82
|
+
type: 'array',
|
|
83
|
+
items: {
|
|
84
|
+
type: 'object',
|
|
85
|
+
required: ['name', 'sha256', 'size'],
|
|
86
|
+
additionalProperties: false,
|
|
87
|
+
properties: {
|
|
88
|
+
name: {
|
|
89
|
+
type: 'string',
|
|
90
|
+
minLength: 1,
|
|
91
|
+
},
|
|
92
|
+
sha256: {
|
|
93
|
+
type: 'string',
|
|
94
|
+
pattern: '^sha256-[0-9a-f]{64}$',
|
|
95
|
+
},
|
|
96
|
+
size: {
|
|
97
|
+
type: 'integer',
|
|
98
|
+
minimum: 0,
|
|
99
|
+
},
|
|
100
|
+
path: {
|
|
101
|
+
type: 'string',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
results: {
|
|
107
|
+
type: 'object',
|
|
108
|
+
required: ['trustScore', 'gates'],
|
|
109
|
+
additionalProperties: false,
|
|
110
|
+
properties: {
|
|
111
|
+
trustScore: {
|
|
112
|
+
type: 'integer',
|
|
113
|
+
minimum: 0,
|
|
114
|
+
maximum: 100,
|
|
115
|
+
},
|
|
116
|
+
gates: {
|
|
117
|
+
type: 'array',
|
|
118
|
+
items: {
|
|
119
|
+
type: 'object',
|
|
120
|
+
required: ['name', 'status'],
|
|
121
|
+
additionalProperties: false,
|
|
122
|
+
properties: {
|
|
123
|
+
name: {
|
|
124
|
+
type: 'string',
|
|
125
|
+
minLength: 1,
|
|
126
|
+
},
|
|
127
|
+
status: {
|
|
128
|
+
type: 'string',
|
|
129
|
+
enum: ['pass', 'fail', 'skip'],
|
|
130
|
+
},
|
|
131
|
+
metrics: {
|
|
132
|
+
type: 'object',
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
signing: {
|
|
140
|
+
type: 'object',
|
|
141
|
+
required: ['algo', 'signerId', 'timestamp', 'identity'],
|
|
142
|
+
additionalProperties: false,
|
|
143
|
+
properties: {
|
|
144
|
+
algo: {
|
|
145
|
+
type: 'string',
|
|
146
|
+
const: 'ed25519',
|
|
147
|
+
},
|
|
148
|
+
signerId: {
|
|
149
|
+
type: 'string',
|
|
150
|
+
minLength: 1,
|
|
151
|
+
},
|
|
152
|
+
timestamp: {
|
|
153
|
+
type: 'object',
|
|
154
|
+
required: ['type'],
|
|
155
|
+
properties: {
|
|
156
|
+
type: {
|
|
157
|
+
type: 'string',
|
|
158
|
+
enum: ['none', 'rfc3161'],
|
|
159
|
+
},
|
|
160
|
+
token: {
|
|
161
|
+
type: ['string', 'null'],
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
identity: {
|
|
166
|
+
type: 'object',
|
|
167
|
+
required: ['type'],
|
|
168
|
+
properties: {
|
|
169
|
+
type: {
|
|
170
|
+
type: 'string',
|
|
171
|
+
enum: ['none', 'did', 'sigstore'],
|
|
172
|
+
},
|
|
173
|
+
evidence: {
|
|
174
|
+
type: ['string', 'object', 'null'],
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
signature: {
|
|
181
|
+
type: 'string',
|
|
182
|
+
pattern: '^[A-Za-z0-9+/]{86}==$',
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Create AJV 2020-12 validator instance
|
|
188
|
+
*
|
|
189
|
+
* Configured with:
|
|
190
|
+
* - strict: true (enforce strict schema validation)
|
|
191
|
+
* - allErrors: true (collect all validation errors)
|
|
192
|
+
* - allowUnionTypes: true (support type unions like ['string', 'null'])
|
|
193
|
+
* - strictTypes: false (allow flexible type checking for edge cases)
|
|
194
|
+
*/
|
|
195
|
+
let validator = null;
|
|
196
|
+
function getValidator() {
|
|
197
|
+
if (!validator) {
|
|
198
|
+
const ajv = new Ajv2020({
|
|
199
|
+
strict: true,
|
|
200
|
+
allErrors: true,
|
|
201
|
+
allowUnionTypes: true,
|
|
202
|
+
strictTypes: false,
|
|
203
|
+
});
|
|
204
|
+
addFormats(ajv);
|
|
205
|
+
validator = ajv.compile(PROOF_BUNDLE_SCHEMA);
|
|
206
|
+
}
|
|
207
|
+
return validator;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Validate proof bundle against schema
|
|
211
|
+
*
|
|
212
|
+
* @param bundle - Proof bundle to validate
|
|
213
|
+
* @returns Validation result with errors if invalid
|
|
214
|
+
*/
|
|
215
|
+
export function validateProofBundle(bundle) {
|
|
216
|
+
const validate = getValidator();
|
|
217
|
+
const valid = validate(bundle);
|
|
218
|
+
if (valid) {
|
|
219
|
+
return { valid: true };
|
|
220
|
+
}
|
|
221
|
+
const errors = validate.errors?.map(err => {
|
|
222
|
+
const path = err.instancePath || 'root';
|
|
223
|
+
return `${path}: ${err.message}`;
|
|
224
|
+
}) || ['Unknown validation error'];
|
|
225
|
+
return { valid: false, errors };
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Get the JSON Schema object
|
|
229
|
+
*
|
|
230
|
+
* @returns Proof Bundle v1 schema
|
|
231
|
+
*/
|
|
232
|
+
export function getSchema() {
|
|
233
|
+
return PROOF_BUNDLE_SCHEMA;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Validate specific field patterns
|
|
237
|
+
*/
|
|
238
|
+
export const patterns = {
|
|
239
|
+
/**
|
|
240
|
+
* Validate SHA-256 hash format
|
|
241
|
+
*/
|
|
242
|
+
sha256: (hash) => {
|
|
243
|
+
return /^sha256-[0-9a-f]{64}$/.test(hash);
|
|
244
|
+
},
|
|
245
|
+
/**
|
|
246
|
+
* Validate UUID v4 format
|
|
247
|
+
*/
|
|
248
|
+
uuid: (id) => {
|
|
249
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(id);
|
|
250
|
+
},
|
|
251
|
+
/**
|
|
252
|
+
* Validate Ed25519 signature format (base64, 88 chars)
|
|
253
|
+
*/
|
|
254
|
+
signature: (sig) => {
|
|
255
|
+
return /^[A-Za-z0-9+/]{86}==$/.test(sig);
|
|
256
|
+
},
|
|
257
|
+
/**
|
|
258
|
+
* Validate Node.js version format
|
|
259
|
+
*/
|
|
260
|
+
nodeVersion: (version) => {
|
|
261
|
+
return /^\d+\.\d+\.\d+$/.test(version);
|
|
262
|
+
},
|
|
263
|
+
};
|