@veraxhq/verax 0.2.0 → 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/README.md +14 -18
- package/bin/verax.js +7 -0
- package/package.json +15 -5
- package/src/cli/commands/baseline.js +104 -0
- package/src/cli/commands/default.js +323 -111
- package/src/cli/commands/doctor.js +36 -4
- package/src/cli/commands/ga.js +243 -0
- package/src/cli/commands/gates.js +95 -0
- package/src/cli/commands/inspect.js +131 -2
- package/src/cli/commands/release-check.js +213 -0
- package/src/cli/commands/run.js +498 -103
- package/src/cli/commands/security-check.js +211 -0
- package/src/cli/commands/truth.js +114 -0
- package/src/cli/entry.js +305 -68
- package/src/cli/util/angular-component-extractor.js +179 -0
- package/src/cli/util/angular-navigation-detector.js +141 -0
- package/src/cli/util/angular-network-detector.js +161 -0
- package/src/cli/util/angular-state-detector.js +162 -0
- package/src/cli/util/ast-interactive-detector.js +546 -0
- package/src/cli/util/ast-network-detector.js +603 -0
- package/src/cli/util/ast-usestate-detector.js +602 -0
- package/src/cli/util/bootstrap-guard.js +86 -0
- package/src/cli/util/detection-engine.js +4 -3
- package/src/cli/util/determinism-runner.js +123 -0
- package/src/cli/util/determinism-writer.js +129 -0
- package/src/cli/util/env-url.js +4 -0
- package/src/cli/util/events.js +76 -0
- package/src/cli/util/expectation-extractor.js +380 -74
- package/src/cli/util/findings-writer.js +126 -15
- package/src/cli/util/learn-writer.js +3 -1
- package/src/cli/util/observation-engine.js +69 -23
- package/src/cli/util/observe-writer.js +3 -1
- package/src/cli/util/paths.js +6 -14
- package/src/cli/util/project-discovery.js +23 -0
- package/src/cli/util/project-writer.js +3 -1
- package/src/cli/util/redact.js +2 -2
- package/src/cli/util/run-resolver.js +64 -0
- package/src/cli/util/runtime-budget.js +147 -0
- package/src/cli/util/source-requirement.js +55 -0
- package/src/cli/util/summary-writer.js +13 -1
- package/src/cli/util/svelte-navigation-detector.js +163 -0
- package/src/cli/util/svelte-network-detector.js +80 -0
- package/src/cli/util/svelte-sfc-extractor.js +147 -0
- package/src/cli/util/svelte-state-detector.js +243 -0
- package/src/cli/util/vue-navigation-detector.js +177 -0
- package/src/cli/util/vue-sfc-extractor.js +162 -0
- package/src/cli/util/vue-state-detector.js +215 -0
- package/src/types/global.d.ts +28 -0
- package/src/types/ts-ast.d.ts +24 -0
- package/src/verax/cli/doctor.js +2 -2
- package/src/verax/cli/finding-explainer.js +56 -3
- package/src/verax/cli/init.js +1 -1
- package/src/verax/cli/url-safety.js +12 -2
- package/src/verax/cli/wizard.js +13 -2
- package/src/verax/core/artifacts/registry.js +154 -0
- package/src/verax/core/artifacts/verifier.js +980 -0
- package/src/verax/core/baseline/baseline.enforcer.js +137 -0
- package/src/verax/core/baseline/baseline.snapshot.js +231 -0
- package/src/verax/core/budget-engine.js +1 -1
- package/src/verax/core/capabilities/gates.js +499 -0
- package/src/verax/core/capabilities/registry.js +475 -0
- package/src/verax/core/confidence/confidence-compute.js +137 -0
- package/src/verax/core/confidence/confidence-invariants.js +234 -0
- package/src/verax/core/confidence/confidence-report-writer.js +112 -0
- package/src/verax/core/confidence/confidence-weights.js +44 -0
- package/src/verax/core/confidence/confidence.defaults.js +65 -0
- package/src/verax/core/confidence/confidence.loader.js +79 -0
- package/src/verax/core/confidence/confidence.schema.js +94 -0
- package/src/verax/core/confidence-engine-refactor.js +484 -0
- package/src/verax/core/confidence-engine.js +486 -0
- package/src/verax/core/confidence-engine.js.backup +471 -0
- package/src/verax/core/contracts/index.js +29 -0
- package/src/verax/core/contracts/types.js +185 -0
- package/src/verax/core/contracts/validators.js +381 -0
- package/src/verax/core/decision-snapshot.js +31 -4
- package/src/verax/core/decisions/decision.trace.js +276 -0
- package/src/verax/core/determinism/contract-writer.js +89 -0
- package/src/verax/core/determinism/contract.js +139 -0
- package/src/verax/core/determinism/diff.js +364 -0
- package/src/verax/core/determinism/engine.js +221 -0
- package/src/verax/core/determinism/finding-identity.js +148 -0
- package/src/verax/core/determinism/normalize.js +438 -0
- package/src/verax/core/determinism/report-writer.js +92 -0
- package/src/verax/core/determinism/run-fingerprint.js +118 -0
- package/src/verax/core/determinism-model.js +35 -6
- package/src/verax/core/dynamic-route-intelligence.js +528 -0
- package/src/verax/core/evidence/evidence-capture-service.js +307 -0
- package/src/verax/core/evidence/evidence-intent-ledger.js +165 -0
- package/src/verax/core/evidence-builder.js +487 -0
- package/src/verax/core/execution-mode-context.js +77 -0
- package/src/verax/core/execution-mode-detector.js +190 -0
- package/src/verax/core/failures/exit-codes.js +86 -0
- package/src/verax/core/failures/failure-summary.js +76 -0
- package/src/verax/core/failures/failure.factory.js +225 -0
- package/src/verax/core/failures/failure.ledger.js +132 -0
- package/src/verax/core/failures/failure.types.js +196 -0
- package/src/verax/core/failures/index.js +10 -0
- package/src/verax/core/ga/ga-report-writer.js +43 -0
- package/src/verax/core/ga/ga.artifact.js +49 -0
- package/src/verax/core/ga/ga.contract.js +434 -0
- package/src/verax/core/ga/ga.enforcer.js +86 -0
- package/src/verax/core/guardrails/guardrails-report-writer.js +109 -0
- package/src/verax/core/guardrails/policy.defaults.js +210 -0
- package/src/verax/core/guardrails/policy.loader.js +83 -0
- package/src/verax/core/guardrails/policy.schema.js +110 -0
- package/src/verax/core/guardrails/truth-reconciliation.js +136 -0
- package/src/verax/core/guardrails-engine.js +505 -0
- package/src/verax/core/incremental-store.js +15 -7
- package/src/verax/core/observe/run-timeline.js +316 -0
- package/src/verax/core/perf/perf.contract.js +186 -0
- package/src/verax/core/perf/perf.display.js +65 -0
- package/src/verax/core/perf/perf.enforcer.js +91 -0
- package/src/verax/core/perf/perf.monitor.js +209 -0
- package/src/verax/core/perf/perf.report.js +198 -0
- package/src/verax/core/pipeline-tracker.js +238 -0
- package/src/verax/core/product-definition.js +127 -0
- package/src/verax/core/release/provenance.builder.js +271 -0
- package/src/verax/core/release/release-report-writer.js +40 -0
- package/src/verax/core/release/release.enforcer.js +159 -0
- package/src/verax/core/release/reproducibility.check.js +221 -0
- package/src/verax/core/release/sbom.builder.js +283 -0
- package/src/verax/core/replay-validator.js +4 -4
- package/src/verax/core/replay.js +1 -1
- package/src/verax/core/report/cross-index.js +192 -0
- package/src/verax/core/report/human-summary.js +222 -0
- package/src/verax/core/route-intelligence.js +419 -0
- package/src/verax/core/security/secrets.scan.js +326 -0
- package/src/verax/core/security/security-report.js +50 -0
- package/src/verax/core/security/security.enforcer.js +124 -0
- package/src/verax/core/security/supplychain.defaults.json +38 -0
- package/src/verax/core/security/supplychain.policy.js +326 -0
- package/src/verax/core/security/vuln.scan.js +265 -0
- package/src/verax/core/silence-impact.js +1 -1
- package/src/verax/core/silence-model.js +9 -7
- package/src/verax/core/truth/truth.certificate.js +250 -0
- package/src/verax/core/ui-feedback-intelligence.js +515 -0
- package/src/verax/detect/comparison.js +8 -3
- package/src/verax/detect/confidence-engine.js +645 -57
- package/src/verax/detect/confidence-helper.js +33 -0
- package/src/verax/detect/detection-engine.js +19 -2
- package/src/verax/detect/dynamic-route-findings.js +335 -0
- package/src/verax/detect/evidence-index.js +15 -65
- package/src/verax/detect/expectation-chain-detector.js +417 -0
- package/src/verax/detect/expectation-model.js +56 -3
- package/src/verax/detect/explanation-helpers.js +1 -1
- package/src/verax/detect/finding-detector.js +2 -2
- package/src/verax/detect/findings-writer.js +149 -20
- package/src/verax/detect/flow-detector.js +4 -4
- package/src/verax/detect/index.js +265 -15
- package/src/verax/detect/interactive-findings.js +3 -4
- package/src/verax/detect/journey-stall-detector.js +558 -0
- package/src/verax/detect/route-findings.js +218 -0
- package/src/verax/detect/signal-mapper.js +2 -2
- package/src/verax/detect/skip-classifier.js +4 -4
- package/src/verax/detect/ui-feedback-findings.js +207 -0
- package/src/verax/detect/verdict-engine.js +61 -9
- package/src/verax/detect/view-switch-correlator.js +242 -0
- package/src/verax/flow/flow-engine.js +3 -2
- package/src/verax/flow/flow-spec.js +1 -2
- package/src/verax/index.js +413 -33
- package/src/verax/intel/effect-detector.js +1 -1
- package/src/verax/intel/index.js +2 -2
- package/src/verax/intel/route-extractor.js +3 -3
- package/src/verax/intel/vue-navigation-extractor.js +81 -18
- package/src/verax/intel/vue-router-extractor.js +4 -2
- package/src/verax/learn/action-contract-extractor.js +684 -66
- package/src/verax/learn/ast-contract-extractor.js +53 -1
- package/src/verax/learn/index.js +36 -2
- package/src/verax/learn/manifest-writer.js +28 -14
- package/src/verax/learn/route-extractor.js +1 -1
- package/src/verax/learn/route-validator.js +12 -8
- package/src/verax/learn/state-extractor.js +1 -1
- package/src/verax/learn/static-extractor-navigation.js +1 -1
- package/src/verax/learn/static-extractor-validation.js +2 -2
- package/src/verax/learn/static-extractor.js +8 -7
- package/src/verax/learn/ts-contract-resolver.js +14 -12
- package/src/verax/observe/browser.js +22 -3
- package/src/verax/observe/console-sensor.js +2 -2
- package/src/verax/observe/expectation-executor.js +2 -1
- package/src/verax/observe/focus-sensor.js +1 -1
- package/src/verax/observe/human-driver.js +29 -10
- package/src/verax/observe/index.js +92 -844
- package/src/verax/observe/interaction-discovery.js +27 -15
- package/src/verax/observe/interaction-runner.js +31 -14
- package/src/verax/observe/loading-sensor.js +6 -0
- package/src/verax/observe/navigation-sensor.js +1 -1
- package/src/verax/observe/observe-context.js +205 -0
- package/src/verax/observe/observe-helpers.js +191 -0
- package/src/verax/observe/observe-runner.js +226 -0
- package/src/verax/observe/observers/budget-observer.js +185 -0
- package/src/verax/observe/observers/console-observer.js +102 -0
- package/src/verax/observe/observers/coverage-observer.js +107 -0
- package/src/verax/observe/observers/interaction-observer.js +471 -0
- package/src/verax/observe/observers/navigation-observer.js +132 -0
- package/src/verax/observe/observers/network-observer.js +87 -0
- package/src/verax/observe/observers/safety-observer.js +82 -0
- package/src/verax/observe/observers/ui-feedback-observer.js +99 -0
- package/src/verax/observe/settle.js +1 -0
- package/src/verax/observe/state-sensor.js +8 -4
- package/src/verax/observe/state-ui-sensor.js +7 -1
- package/src/verax/observe/traces-writer.js +27 -16
- package/src/verax/observe/ui-feedback-detector.js +742 -0
- package/src/verax/observe/ui-signal-sensor.js +155 -2
- package/src/verax/scan-summary-writer.js +46 -9
- package/src/verax/shared/artifact-manager.js +9 -6
- package/src/verax/shared/budget-profiles.js +2 -2
- package/src/verax/shared/caching.js +1 -1
- package/src/verax/shared/config-loader.js +1 -2
- package/src/verax/shared/css-spinner-rules.js +204 -0
- package/src/verax/shared/dynamic-route-utils.js +12 -6
- package/src/verax/shared/retry-policy.js +1 -6
- package/src/verax/shared/root-artifacts.js +1 -1
- package/src/verax/shared/view-switch-rules.js +208 -0
- package/src/verax/shared/zip-artifacts.js +1 -0
- package/src/verax/validate/context-validator.js +1 -1
- package/src/verax/observe/index.js.backup +0 -1
- package/src/verax/validate/context-validator.js.bak +0 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.6 — GA Readiness CLI Command
|
|
3
|
+
*
|
|
4
|
+
* Pure inspection command. Evaluates GA readiness using existing artifacts only.
|
|
5
|
+
* No URL, no browser, no project execution.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { evaluateGAReadiness } from '../../verax/core/ga/ga.contract.js';
|
|
9
|
+
import { writeGAStatus } from '../../verax/core/ga/ga.artifact.js';
|
|
10
|
+
import { writeGAReport } from '../../verax/core/ga/ga-report-writer.js';
|
|
11
|
+
import { GA_BLOCKER_CODE } from '../../verax/core/ga/ga.contract.js';
|
|
12
|
+
import { resolve } from 'path';
|
|
13
|
+
import { readFileSync, existsSync } from 'fs';
|
|
14
|
+
import { findLatestRunId, validateRunId } from '../util/run-resolver.js';
|
|
15
|
+
import { UsageError } from '../util/errors.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Load failure ledger summary
|
|
19
|
+
*
|
|
20
|
+
* @param {string} projectDir - Project directory
|
|
21
|
+
* @param {string} runId - Run ID
|
|
22
|
+
* @returns {Object|null} Failure ledger summary or null
|
|
23
|
+
*/
|
|
24
|
+
function loadFailureLedger(projectDir, runId) {
|
|
25
|
+
const ledgerPath = resolve(projectDir, '.verax', 'runs', runId, 'failure.ledger.json');
|
|
26
|
+
if (!existsSync(ledgerPath)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const content = readFileSync(ledgerPath, 'utf-8');
|
|
32
|
+
const ledger = JSON.parse(content);
|
|
33
|
+
return ledger.summary || null;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Load determinism verdict
|
|
41
|
+
*
|
|
42
|
+
* @param {string} projectDir - Project directory
|
|
43
|
+
* @param {string} runId - Run ID
|
|
44
|
+
* @returns {Promise<string|null>} Determinism verdict or null
|
|
45
|
+
*/
|
|
46
|
+
async function loadDeterminismVerdict(projectDir, runId) {
|
|
47
|
+
const decisionsPath = resolve(projectDir, '.verax', 'runs', runId, 'decisions.json');
|
|
48
|
+
if (!existsSync(decisionsPath)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const decisions = JSON.parse(readFileSync(decisionsPath, 'utf-8'));
|
|
54
|
+
const { DecisionRecorder } = await import('../../verax/core/determinism-model.js');
|
|
55
|
+
const recorder = DecisionRecorder.fromExport(decisions);
|
|
56
|
+
const { computeDeterminismVerdict } = await import('../../verax/core/determinism/contract.js');
|
|
57
|
+
const verdict = computeDeterminismVerdict(recorder);
|
|
58
|
+
return verdict.verdict;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Check for Evidence Law violations
|
|
66
|
+
*
|
|
67
|
+
* @param {string} projectDir - Project directory
|
|
68
|
+
* @param {string} runId - Run ID
|
|
69
|
+
* @returns {boolean} Whether Evidence Law was violated
|
|
70
|
+
*/
|
|
71
|
+
function checkEvidenceLawViolations(projectDir, runId) {
|
|
72
|
+
const findingsPath = resolve(projectDir, '.verax', 'runs', runId, 'findings.json');
|
|
73
|
+
if (!existsSync(findingsPath)) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const content = readFileSync(findingsPath, 'utf-8');
|
|
79
|
+
const findings = JSON.parse(content);
|
|
80
|
+
|
|
81
|
+
if (!Array.isArray(findings.findings)) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Check for CONFIRMED findings with incomplete evidence
|
|
86
|
+
for (const finding of findings.findings) {
|
|
87
|
+
if ((finding.severity === 'CONFIRMED' || finding.status === 'CONFIRMED') &&
|
|
88
|
+
finding.evidencePackage && !finding.evidencePackage.isComplete) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return false;
|
|
94
|
+
} catch (error) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* PHASE 21.6.1: `verax ga` command
|
|
101
|
+
*
|
|
102
|
+
* Pure inspection command. No URL, no browser, no execution.
|
|
103
|
+
*
|
|
104
|
+
* @param {Object} options - Options
|
|
105
|
+
* @param {string} [options.runId] - Run ID (defaults to latest)
|
|
106
|
+
* @param {boolean} [options.json] - Output as JSON
|
|
107
|
+
*/
|
|
108
|
+
export async function gaCommand(options = {}) {
|
|
109
|
+
const { runId: providedRunId = null, json = false } = options;
|
|
110
|
+
|
|
111
|
+
const projectDir = resolve(process.cwd());
|
|
112
|
+
|
|
113
|
+
// Resolve run ID: use provided or find latest
|
|
114
|
+
let runId = providedRunId;
|
|
115
|
+
|
|
116
|
+
if (!runId) {
|
|
117
|
+
// Find latest run
|
|
118
|
+
runId = findLatestRunId(projectDir);
|
|
119
|
+
|
|
120
|
+
if (!runId) {
|
|
121
|
+
// No runs found - GA is BLOCKED
|
|
122
|
+
const gaResult = {
|
|
123
|
+
pass: false,
|
|
124
|
+
blockers: [{
|
|
125
|
+
code: GA_BLOCKER_CODE.NO_RUNS_FOUND || 'GA_NO_RUNS_FOUND',
|
|
126
|
+
message: 'No runs found in .verax/runs/. Run a scan first.',
|
|
127
|
+
context: {}
|
|
128
|
+
}],
|
|
129
|
+
warnings: [],
|
|
130
|
+
summary: {
|
|
131
|
+
pass: false,
|
|
132
|
+
blockersCount: 1,
|
|
133
|
+
warningsCount: 0,
|
|
134
|
+
checkedAt: new Date().toISOString()
|
|
135
|
+
},
|
|
136
|
+
inputs: {
|
|
137
|
+
gates: null,
|
|
138
|
+
determinism: null,
|
|
139
|
+
evidenceLaw: null,
|
|
140
|
+
failureLedger: null
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
if (json) {
|
|
145
|
+
console.log(JSON.stringify({
|
|
146
|
+
gaReady: false,
|
|
147
|
+
blockers: gaResult.blockers,
|
|
148
|
+
warnings: [],
|
|
149
|
+
summary: gaResult.summary
|
|
150
|
+
}, null, 2));
|
|
151
|
+
} else {
|
|
152
|
+
console.log('\n' + '='.repeat(80));
|
|
153
|
+
console.log('GA READINESS EVALUATION');
|
|
154
|
+
console.log('='.repeat(80));
|
|
155
|
+
console.log('\nGA STATUS: ❌ BLOCKED');
|
|
156
|
+
console.log('\nBlockers:');
|
|
157
|
+
console.log('- No runs found in .verax/runs/. Run a scan first.');
|
|
158
|
+
console.log('='.repeat(80) + '\n');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
process.exit(4);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
// Validate provided run ID
|
|
166
|
+
if (!validateRunId(projectDir, runId)) {
|
|
167
|
+
const error = new UsageError(`Run ID not found: ${runId}`);
|
|
168
|
+
// UsageError already has exit code 64
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Load context from artifacts (pure filesystem reads)
|
|
174
|
+
const failureLedger = loadFailureLedger(projectDir, runId);
|
|
175
|
+
const determinismVerdict = await loadDeterminismVerdict(projectDir, runId);
|
|
176
|
+
const evidenceLawViolated = checkEvidenceLawViolations(projectDir, runId);
|
|
177
|
+
|
|
178
|
+
// Evaluate GA readiness
|
|
179
|
+
const gaResult = await evaluateGAReadiness({
|
|
180
|
+
projectDir,
|
|
181
|
+
runId,
|
|
182
|
+
determinismVerdict,
|
|
183
|
+
evidenceLawViolated,
|
|
184
|
+
failureLedger
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Write status artifact
|
|
188
|
+
const artifactPath = writeGAStatus(projectDir, runId, gaResult);
|
|
189
|
+
|
|
190
|
+
// Write GA report
|
|
191
|
+
const reportPath = writeGAReport(projectDir, runId, gaResult);
|
|
192
|
+
|
|
193
|
+
// Output
|
|
194
|
+
if (json) {
|
|
195
|
+
console.log(JSON.stringify({
|
|
196
|
+
gaReady: gaResult.pass,
|
|
197
|
+
blockers: gaResult.blockers,
|
|
198
|
+
warnings: gaResult.warnings,
|
|
199
|
+
summary: gaResult.summary,
|
|
200
|
+
artifactPath,
|
|
201
|
+
reportPath
|
|
202
|
+
}, null, 2));
|
|
203
|
+
} else {
|
|
204
|
+
console.log('\n' + '='.repeat(80));
|
|
205
|
+
console.log('GA READINESS EVALUATION');
|
|
206
|
+
console.log('='.repeat(80));
|
|
207
|
+
console.log(`\nGA STATUS: ${gaResult.pass ? '✅ READY' : '❌ BLOCKED'}`);
|
|
208
|
+
|
|
209
|
+
if (gaResult.blockers.length > 0) {
|
|
210
|
+
console.log('\nBlockers:');
|
|
211
|
+
for (const blocker of gaResult.blockers) {
|
|
212
|
+
console.log(`- ${blocker.message}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (gaResult.warnings.length > 0) {
|
|
217
|
+
console.log('\nWarnings:');
|
|
218
|
+
for (const warning of gaResult.warnings) {
|
|
219
|
+
console.log(`- ${warning.message}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
console.log(`\nSee: ${artifactPath}`);
|
|
224
|
+
console.log(`Report: ${reportPath}`);
|
|
225
|
+
console.log('='.repeat(80) + '\n');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Exit codes: 0 = GA-READY, 2 = GA-BLOCKED, 70 = Internal corruption
|
|
229
|
+
if (!gaResult.pass) {
|
|
230
|
+
// Check if it's an internal corruption issue
|
|
231
|
+
const hasInternalBlocker = gaResult.blockers.some(b =>
|
|
232
|
+
b.code === 'GA_INTERNAL_FAILURES' ||
|
|
233
|
+
b.code === 'GA_CONTRACT_FAILURES'
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
if (hasInternalBlocker) {
|
|
237
|
+
process.exit(70);
|
|
238
|
+
} else {
|
|
239
|
+
process.exit(2);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 19 — Capability Gates CLI Command
|
|
3
|
+
*
|
|
4
|
+
* Evaluates all capability gates and reports PASS/FAIL.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
evaluateAllCapabilityGates,
|
|
9
|
+
buildGateContext,
|
|
10
|
+
} from '../../verax/core/capabilities/gates.js';
|
|
11
|
+
import { resolve } from 'path';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import { dirname } from 'path';
|
|
14
|
+
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = dirname(__filename);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* PHASE 19: `verax gates` command
|
|
20
|
+
*
|
|
21
|
+
* @param {Object} options - Options
|
|
22
|
+
* @param {boolean} options.json - Output as JSON
|
|
23
|
+
* @param {boolean} options.verbose - Verbose output
|
|
24
|
+
*/
|
|
25
|
+
export async function gatesCommand(options = {}) {
|
|
26
|
+
const { json = false, verbose = false } = options;
|
|
27
|
+
|
|
28
|
+
// Pass explicit project root to ensure correct path resolution
|
|
29
|
+
const projectRoot = resolve(__dirname, '../../..');
|
|
30
|
+
const context = await buildGateContext({ projectRoot });
|
|
31
|
+
const result = evaluateAllCapabilityGates(context);
|
|
32
|
+
|
|
33
|
+
if (json) {
|
|
34
|
+
console.log(JSON.stringify({
|
|
35
|
+
pass: result.pass,
|
|
36
|
+
summary: result.summary,
|
|
37
|
+
perCapability: result.perCapability,
|
|
38
|
+
}, null, 2));
|
|
39
|
+
} else {
|
|
40
|
+
// Human-readable output
|
|
41
|
+
console.log('\n' + '='.repeat(80));
|
|
42
|
+
console.log('CAPABILITY GATES EVALUATION');
|
|
43
|
+
console.log('='.repeat(80));
|
|
44
|
+
console.log(`\nStatus: ${result.pass ? '✅ PASS' : '❌ FAIL'}`);
|
|
45
|
+
console.log(`Total Capabilities: ${result.summary.total}`);
|
|
46
|
+
console.log(`Passing: ${result.summary.pass}`);
|
|
47
|
+
console.log(`Failing: ${result.summary.fail}`);
|
|
48
|
+
|
|
49
|
+
if (!result.pass) {
|
|
50
|
+
console.log('\n' + '-'.repeat(80));
|
|
51
|
+
console.log('FAILING CAPABILITIES:');
|
|
52
|
+
console.log('-'.repeat(80));
|
|
53
|
+
|
|
54
|
+
for (const failure of result.summary.allFailures) {
|
|
55
|
+
console.log(`\n❌ ${failure.capabilityId}`);
|
|
56
|
+
for (const gateFailure of failure.failures) {
|
|
57
|
+
console.log(` └─ ${gateFailure.reasonCode}: ${gateFailure.message}`);
|
|
58
|
+
}
|
|
59
|
+
if (failure.warnings && failure.warnings.length > 0) {
|
|
60
|
+
for (const warning of failure.warnings) {
|
|
61
|
+
console.log(` ⚠️ ${warning.reasonCode}: ${warning.message}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (verbose) {
|
|
67
|
+
console.log('\n' + '-'.repeat(80));
|
|
68
|
+
console.log('REQUIREMENTS BY MATURITY LEVEL:');
|
|
69
|
+
console.log('-'.repeat(80));
|
|
70
|
+
console.log('\nEXPERIMENTAL:');
|
|
71
|
+
console.log(' - Must exist in registry');
|
|
72
|
+
console.log(' - Must have at least 1 test matrix entry');
|
|
73
|
+
console.log('\nPARTIAL:');
|
|
74
|
+
console.log(' - All EXPERIMENTAL requirements');
|
|
75
|
+
console.log(' - Must have at least 1 realistic fixture mapping');
|
|
76
|
+
console.log(' - Must have documentation');
|
|
77
|
+
console.log('\nSTABLE:');
|
|
78
|
+
console.log(' - All PARTIAL requirements');
|
|
79
|
+
console.log(' - Must have determinism test coverage');
|
|
80
|
+
console.log(' - Must have artifact assertions in test matrix');
|
|
81
|
+
console.log(' - Must have guardrails coverage (if category requires it)');
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
console.log('\n✅ All capabilities meet their required gates!');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log('='.repeat(80) + '\n');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Exit code: 0 if PASS, 2 if FAIL
|
|
91
|
+
if (!result.pass) {
|
|
92
|
+
process.exit(2);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
@@ -1,13 +1,41 @@
|
|
|
1
|
-
import { resolve } from 'path';
|
|
1
|
+
import { resolve, dirname, basename } from 'path';
|
|
2
2
|
import { existsSync, readFileSync, readdirSync } from 'fs';
|
|
3
3
|
import { DataError } from '../util/errors.js';
|
|
4
|
+
import { displayPerformanceInInspect } from '../../verax/core/perf/perf.display.js';
|
|
5
|
+
import { loadRunTimeline } from '../../verax/core/observe/run-timeline.js';
|
|
6
|
+
import { loadDecisionTrace } from '../../verax/core/decisions/decision.trace.js';
|
|
7
|
+
import { loadCrossIndex } from '../../verax/core/report/cross-index.js';
|
|
8
|
+
import { generateHumanSummary, formatHumanSummary } from '../../verax/core/report/human-summary.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Extract runId from runPath
|
|
12
|
+
*/
|
|
13
|
+
function extractRunId(runPath) {
|
|
14
|
+
const fullPath = resolve(runPath);
|
|
15
|
+
const runDirBasename = basename(fullPath);
|
|
16
|
+
const parentDir = basename(dirname(fullPath));
|
|
17
|
+
|
|
18
|
+
// Check if path is .verax/runs/<runId>
|
|
19
|
+
if (parentDir === 'runs') {
|
|
20
|
+
return runDirBasename;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return runDirBasename;
|
|
24
|
+
}
|
|
4
25
|
|
|
5
26
|
/**
|
|
6
27
|
* `verax inspect` command
|
|
7
28
|
* Read an existing run folder and display summary
|
|
8
29
|
*/
|
|
9
30
|
export async function inspectCommand(runPath, options = {}) {
|
|
10
|
-
const {
|
|
31
|
+
const {
|
|
32
|
+
json = false,
|
|
33
|
+
timeline = false,
|
|
34
|
+
decisions = false,
|
|
35
|
+
failures = false,
|
|
36
|
+
performance = false,
|
|
37
|
+
evidence = false
|
|
38
|
+
} = options;
|
|
11
39
|
|
|
12
40
|
const fullPath = resolve(runPath);
|
|
13
41
|
|
|
@@ -102,7 +130,108 @@ export async function inspectCommand(runPath, options = {}) {
|
|
|
102
130
|
console.log(`Evidence: not found`);
|
|
103
131
|
}
|
|
104
132
|
|
|
133
|
+
// PHASE 21.9: Display performance metrics
|
|
134
|
+
const runId = output.runId;
|
|
135
|
+
const projectDir = resolve(process.cwd());
|
|
136
|
+
|
|
137
|
+
// PHASE 21.10: Handle specific flags
|
|
138
|
+
if (timeline) {
|
|
139
|
+
const timelineData = loadRunTimeline(projectDir, runId);
|
|
140
|
+
if (timelineData) {
|
|
141
|
+
if (json) {
|
|
142
|
+
console.log(JSON.stringify(timelineData, null, 2));
|
|
143
|
+
} else {
|
|
144
|
+
console.log('\n=== Timeline ===\n');
|
|
145
|
+
for (const event of timelineData.events) {
|
|
146
|
+
console.log(`${event.timestamp || 'N/A'} [${event.phase}] ${event.event}`);
|
|
147
|
+
if (event.data) {
|
|
148
|
+
console.log(` ${JSON.stringify(event.data)}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
console.log('');
|
|
152
|
+
}
|
|
153
|
+
return output;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (decisions) {
|
|
158
|
+
const decisionTrace = loadDecisionTrace(projectDir, runId);
|
|
159
|
+
if (decisionTrace) {
|
|
160
|
+
if (json) {
|
|
161
|
+
console.log(JSON.stringify(decisionTrace, null, 2));
|
|
162
|
+
} else {
|
|
163
|
+
console.log('\n=== Decision Trace ===\n');
|
|
164
|
+
for (const trace of decisionTrace.findings) {
|
|
165
|
+
console.log(`Finding: ${trace.findingId}`);
|
|
166
|
+
console.log(` Status: ${trace.status.value}`);
|
|
167
|
+
console.log(` Confidence: ${trace.confidence.level || 'UNKNOWN'}`);
|
|
168
|
+
console.log(` Why detected: ${trace.detection.why.map(w => w.reason).join('; ')}`);
|
|
169
|
+
console.log(` Why status: ${trace.status.why.map(w => w.reason).join('; ')}`);
|
|
170
|
+
console.log('');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return output;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (failures) {
|
|
178
|
+
const failureLedgerPath = resolve(fullPath, 'failure.ledger.json');
|
|
179
|
+
if (existsSync(failureLedgerPath)) {
|
|
180
|
+
const failureLedger = JSON.parse(readFileSync(failureLedgerPath, 'utf-8'));
|
|
181
|
+
if (json) {
|
|
182
|
+
console.log(JSON.stringify(failureLedger, null, 2));
|
|
183
|
+
} else {
|
|
184
|
+
console.log('\n=== Failures ===\n');
|
|
185
|
+
console.log(`Total: ${failureLedger.summary?.total || 0}`);
|
|
186
|
+
if (failureLedger.failures) {
|
|
187
|
+
for (const failure of failureLedger.failures) {
|
|
188
|
+
console.log(`[${failure.severity || 'UNKNOWN'}] ${failure.code}: ${failure.message}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
console.log('');
|
|
192
|
+
}
|
|
193
|
+
return output;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (performance) {
|
|
198
|
+
displayPerformanceInInspect(projectDir, runId);
|
|
105
199
|
console.log('');
|
|
200
|
+
return output;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (evidence) {
|
|
204
|
+
const crossIndex = loadCrossIndex(projectDir, runId);
|
|
205
|
+
if (crossIndex) {
|
|
206
|
+
if (json) {
|
|
207
|
+
console.log(JSON.stringify(crossIndex, null, 2));
|
|
208
|
+
} else {
|
|
209
|
+
console.log('\n=== Evidence Cross-Index ===\n');
|
|
210
|
+
for (const [findingId, entry] of Object.entries(crossIndex.findings)) {
|
|
211
|
+
console.log(`Finding: ${findingId}`);
|
|
212
|
+
console.log(` Evidence files: ${entry.evidence.files.length}`);
|
|
213
|
+
console.log(` Evidence complete: ${entry.evidence.isComplete}`);
|
|
214
|
+
console.log(` Confidence: ${entry.confidence.level || 'UNKNOWN'}`);
|
|
215
|
+
console.log(` Guardrails: ${entry.guardrails.applied.length} rule(s) applied`);
|
|
216
|
+
console.log('');
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return output;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Default: show summary + human summary
|
|
224
|
+
displayPerformanceInInspect(projectDir, runId);
|
|
225
|
+
|
|
226
|
+
// PHASE 21.10: Display human summary
|
|
227
|
+
const humanSummary = await generateHumanSummary(projectDir, runId);
|
|
228
|
+
if (humanSummary && !json) {
|
|
229
|
+
console.log(formatHumanSummary(humanSummary));
|
|
230
|
+
} else if (humanSummary && json) {
|
|
231
|
+
output.humanSummary = humanSummary;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
console.log('');
|
|
106
235
|
}
|
|
107
236
|
|
|
108
237
|
return output;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.7 — Release Check CLI Command
|
|
3
|
+
*
|
|
4
|
+
* Checks release readiness: GA status, Provenance, SBOM, Reproducibility.
|
|
5
|
+
* Exit codes: 0 = RELEASE-READY, 5 = RELEASE-BLOCKED, 70 = Internal corruption
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { buildProvenance, writeProvenance } from '../../verax/core/release/provenance.builder.js';
|
|
9
|
+
import { buildSBOM, writeSBOM } from '../../verax/core/release/sbom.builder.js';
|
|
10
|
+
import { checkReproducibility, writeReproducibilityReport } from '../../verax/core/release/reproducibility.check.js';
|
|
11
|
+
import { checkGAStatus } from '../../verax/core/ga/ga.enforcer.js';
|
|
12
|
+
import { writeReleaseReport } from '../../verax/core/release/release-report-writer.js';
|
|
13
|
+
import { findLatestRunId } from '../util/run-resolver.js';
|
|
14
|
+
import { resolve } from 'path';
|
|
15
|
+
import { existsSync, readFileSync } from 'fs';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Check release readiness
|
|
19
|
+
*
|
|
20
|
+
* @param {Object} options - Options
|
|
21
|
+
* @param {boolean} [options.json] - Output as JSON
|
|
22
|
+
*/
|
|
23
|
+
export async function releaseCheckCommand(options = {}) {
|
|
24
|
+
const { json = false } = options;
|
|
25
|
+
const projectDir = resolve(process.cwd());
|
|
26
|
+
|
|
27
|
+
const status = {
|
|
28
|
+
ga: { ok: false, status: 'UNKNOWN', blockers: [] },
|
|
29
|
+
provenance: { ok: false, exists: false, blockers: [] },
|
|
30
|
+
sbom: { ok: false, exists: false, blockers: [] },
|
|
31
|
+
reproducibility: { ok: false, verdict: 'UNKNOWN', blockers: [] }
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// 1. Check GA status
|
|
35
|
+
try {
|
|
36
|
+
const runId = findLatestRunId(projectDir);
|
|
37
|
+
if (runId) {
|
|
38
|
+
const gaCheck = checkGAStatus(projectDir, runId);
|
|
39
|
+
status.ga.ok = gaCheck.ready;
|
|
40
|
+
status.ga.status = gaCheck.ready ? 'GA-READY' : 'GA-BLOCKED';
|
|
41
|
+
if (!gaCheck.ready && gaCheck.status?.blockers) {
|
|
42
|
+
status.ga.blockers = gaCheck.status.blockers.map(b => b.message);
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
status.ga.blockers.push('No runs found. Run a scan first.');
|
|
46
|
+
}
|
|
47
|
+
} catch (error) {
|
|
48
|
+
status.ga.blockers.push(`GA check failed: ${error.message}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 2. Check Provenance
|
|
52
|
+
try {
|
|
53
|
+
const provenancePath = resolve(projectDir, 'release', 'release.provenance.json');
|
|
54
|
+
if (existsSync(provenancePath)) {
|
|
55
|
+
status.provenance.exists = true;
|
|
56
|
+
const provenance = JSON.parse(readFileSync(provenancePath, 'utf-8'));
|
|
57
|
+
|
|
58
|
+
// Validate provenance structure
|
|
59
|
+
if (!provenance.version || !provenance.git || !provenance.env) {
|
|
60
|
+
status.provenance.blockers.push('Invalid provenance structure');
|
|
61
|
+
} else if (provenance.git.dirty) {
|
|
62
|
+
status.provenance.blockers.push('Provenance indicates dirty git repository');
|
|
63
|
+
} else if (provenance.gaStatus !== 'GA-READY') {
|
|
64
|
+
status.provenance.blockers.push(`GA status is ${provenance.gaStatus}, not GA-READY`);
|
|
65
|
+
} else {
|
|
66
|
+
status.provenance.ok = true;
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
// Try to build it
|
|
70
|
+
try {
|
|
71
|
+
const provenance = await buildProvenance(projectDir);
|
|
72
|
+
writeProvenance(projectDir, provenance);
|
|
73
|
+
status.provenance.exists = true;
|
|
74
|
+
status.provenance.ok = true;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
status.provenance.blockers.push(`Cannot build provenance: ${error.message}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
status.provenance.blockers.push(`Provenance check failed: ${error.message}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 3. Check SBOM
|
|
84
|
+
try {
|
|
85
|
+
const sbomPath = resolve(projectDir, 'release', 'sbom.json');
|
|
86
|
+
if (existsSync(sbomPath)) {
|
|
87
|
+
status.sbom.exists = true;
|
|
88
|
+
const sbom = JSON.parse(readFileSync(sbomPath, 'utf-8'));
|
|
89
|
+
|
|
90
|
+
// Validate SBOM structure
|
|
91
|
+
if (!sbom.bomFormat || !sbom.components || !Array.isArray(sbom.components)) {
|
|
92
|
+
status.sbom.blockers.push('Invalid SBOM structure');
|
|
93
|
+
} else if (sbom.components.length === 0) {
|
|
94
|
+
status.sbom.blockers.push('SBOM has no components');
|
|
95
|
+
} else {
|
|
96
|
+
status.sbom.ok = true;
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
// Try to build it
|
|
100
|
+
try {
|
|
101
|
+
const sbom = await buildSBOM(projectDir);
|
|
102
|
+
writeSBOM(projectDir, sbom);
|
|
103
|
+
status.sbom.exists = true;
|
|
104
|
+
status.sbom.ok = true;
|
|
105
|
+
} catch (error) {
|
|
106
|
+
status.sbom.blockers.push(`Cannot build SBOM: ${error.message}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} catch (error) {
|
|
110
|
+
status.sbom.blockers.push(`SBOM check failed: ${error.message}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 4. Check Reproducibility
|
|
114
|
+
try {
|
|
115
|
+
const report = await checkReproducibility(projectDir);
|
|
116
|
+
writeReproducibilityReport(projectDir, report);
|
|
117
|
+
|
|
118
|
+
if (report.verdict === 'REPRODUCIBLE') {
|
|
119
|
+
status.reproducibility.ok = true;
|
|
120
|
+
status.reproducibility.verdict = 'REPRODUCIBLE';
|
|
121
|
+
} else {
|
|
122
|
+
status.reproducibility.verdict = 'NON_REPRODUCIBLE';
|
|
123
|
+
if (report.differences && report.differences.length > 0) {
|
|
124
|
+
status.reproducibility.blockers = report.differences.map(d => d.message);
|
|
125
|
+
} else {
|
|
126
|
+
status.reproducibility.blockers.push('Build is not reproducible');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
} catch (error) {
|
|
130
|
+
status.reproducibility.blockers.push(`Reproducibility check failed: ${error.message}`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Determine overall status
|
|
134
|
+
const allOk = status.ga.ok && status.provenance.ok && status.sbom.ok && status.reproducibility.ok;
|
|
135
|
+
const hasInternalCorruption =
|
|
136
|
+
status.ga.blockers.some(b => b.includes('corruption') || b.includes('INTERNAL')) ||
|
|
137
|
+
status.provenance.blockers.some(b => b.includes('corruption')) ||
|
|
138
|
+
status.sbom.blockers.some(b => b.includes('corruption'));
|
|
139
|
+
|
|
140
|
+
// Write release report
|
|
141
|
+
const releaseStatus = {
|
|
142
|
+
releaseReady: allOk,
|
|
143
|
+
status,
|
|
144
|
+
summary: {
|
|
145
|
+
ga: status.ga.ok ? 'OK' : 'BLOCKED',
|
|
146
|
+
provenance: status.provenance.ok ? 'OK' : 'BLOCKED',
|
|
147
|
+
sbom: status.sbom.ok ? 'OK' : 'BLOCKED',
|
|
148
|
+
reproducibility: status.reproducibility.ok ? 'OK' : 'BLOCKED'
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
const releaseReportPath = writeReleaseReport(projectDir, releaseStatus);
|
|
152
|
+
|
|
153
|
+
// Output
|
|
154
|
+
if (json) {
|
|
155
|
+
console.log(JSON.stringify({
|
|
156
|
+
releaseReady: allOk,
|
|
157
|
+
status,
|
|
158
|
+
summary: {
|
|
159
|
+
ga: status.ga.ok ? 'OK' : 'BLOCKED',
|
|
160
|
+
provenance: status.provenance.ok ? 'OK' : 'BLOCKED',
|
|
161
|
+
sbom: status.sbom.ok ? 'OK' : 'BLOCKED',
|
|
162
|
+
reproducibility: status.reproducibility.ok ? 'OK' : 'BLOCKED'
|
|
163
|
+
},
|
|
164
|
+
reportPath: releaseReportPath
|
|
165
|
+
}, null, 2));
|
|
166
|
+
} else {
|
|
167
|
+
console.log('\n' + '='.repeat(80));
|
|
168
|
+
console.log('RELEASE READINESS CHECK');
|
|
169
|
+
console.log('='.repeat(80));
|
|
170
|
+
|
|
171
|
+
console.log(`\nGA Status: ${status.ga.ok ? '✅ READY' : '❌ BLOCKED'}`);
|
|
172
|
+
if (status.ga.blockers.length > 0) {
|
|
173
|
+
for (const blocker of status.ga.blockers) {
|
|
174
|
+
console.log(` - ${blocker}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
console.log(`\nProvenance: ${status.provenance.ok ? '✅ OK' : '❌ BLOCKED'}`);
|
|
179
|
+
if (status.provenance.blockers.length > 0) {
|
|
180
|
+
for (const blocker of status.provenance.blockers) {
|
|
181
|
+
console.log(` - ${blocker}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
console.log(`\nSBOM: ${status.sbom.ok ? '✅ OK' : '❌ BLOCKED'}`);
|
|
186
|
+
if (status.sbom.blockers.length > 0) {
|
|
187
|
+
for (const blocker of status.sbom.blockers) {
|
|
188
|
+
console.log(` - ${blocker}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
console.log(`\nReproducibility: ${status.reproducibility.ok ? '✅ REPRODUCIBLE' : '❌ NON_REPRODUCIBLE'}`);
|
|
193
|
+
if (status.reproducibility.blockers.length > 0) {
|
|
194
|
+
for (const blocker of status.reproducibility.blockers) {
|
|
195
|
+
console.log(` - ${blocker}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
console.log(`\nOverall: ${allOk ? '✅ RELEASE-READY' : '❌ RELEASE-BLOCKED'}`);
|
|
200
|
+
console.log(`\nSee report: ${releaseReportPath}`);
|
|
201
|
+
console.log('='.repeat(80) + '\n');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Exit codes: 0 = RELEASE-READY, 2 = RELEASE-BLOCKED, 70 = Internal corruption
|
|
205
|
+
if (allOk) {
|
|
206
|
+
process.exit(0);
|
|
207
|
+
} else if (hasInternalCorruption) {
|
|
208
|
+
process.exit(70);
|
|
209
|
+
} else {
|
|
210
|
+
process.exit(2);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|