@veraxhq/verax 0.2.1 → 0.4.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 +10 -6
- package/bin/verax.js +11 -11
- package/package.json +29 -8
- package/src/cli/commands/baseline.js +103 -0
- package/src/cli/commands/default.js +51 -6
- package/src/cli/commands/doctor.js +29 -0
- package/src/cli/commands/ga.js +246 -0
- package/src/cli/commands/gates.js +95 -0
- package/src/cli/commands/inspect.js +4 -2
- package/src/cli/commands/release-check.js +215 -0
- package/src/cli/commands/run.js +45 -6
- package/src/cli/commands/security-check.js +212 -0
- package/src/cli/commands/truth.js +113 -0
- package/src/cli/entry.js +30 -20
- 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 +544 -0
- package/src/cli/util/ast-network-detector.js +603 -0
- package/src/cli/util/ast-promise-extractor.js +581 -0
- package/src/cli/util/ast-usestate-detector.js +602 -0
- package/src/cli/util/atomic-write.js +12 -1
- package/src/cli/util/bootstrap-guard.js +86 -0
- package/src/cli/util/console-reporter.js +72 -0
- package/src/cli/util/detection-engine.js +105 -41
- package/src/cli/util/determinism-runner.js +124 -0
- package/src/cli/util/determinism-writer.js +129 -0
- package/src/cli/util/digest-engine.js +359 -0
- package/src/cli/util/dom-diff.js +226 -0
- package/src/cli/util/evidence-engine.js +287 -0
- package/src/cli/util/expectation-extractor.js +151 -5
- package/src/cli/util/findings-writer.js +3 -0
- package/src/cli/util/framework-detector.js +572 -0
- package/src/cli/util/idgen.js +1 -1
- package/src/cli/util/interaction-planner.js +529 -0
- package/src/cli/util/learn-writer.js +2 -0
- package/src/cli/util/ledger-writer.js +110 -0
- package/src/cli/util/monorepo-resolver.js +162 -0
- package/src/cli/util/observation-engine.js +127 -278
- package/src/cli/util/observe-writer.js +2 -0
- package/src/cli/util/project-discovery.js +284 -0
- package/src/cli/util/project-writer.js +2 -0
- package/src/cli/util/run-id.js +23 -27
- package/src/cli/util/run-resolver.js +64 -0
- package/src/cli/util/run-result.js +778 -0
- package/src/cli/util/selector-resolver.js +235 -0
- package/src/cli/util/source-requirement.js +55 -0
- package/src/cli/util/summary-writer.js +2 -0
- 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 +146 -0
- package/src/cli/util/svelte-state-detector.js +242 -0
- package/src/cli/util/trust-activation-integration.js +496 -0
- package/src/cli/util/trust-activation-wrapper.js +85 -0
- package/src/cli/util/trust-integration-hooks.js +164 -0
- package/src/cli/util/types.js +153 -0
- package/src/cli/util/url-validation.js +40 -0
- package/src/cli/util/vue-navigation-detector.js +178 -0
- package/src/cli/util/vue-sfc-extractor.js +161 -0
- package/src/cli/util/vue-state-detector.js +215 -0
- package/src/types/fs-augment.d.ts +23 -0
- package/src/types/global.d.ts +137 -0
- package/src/types/internal-types.d.ts +35 -0
- package/src/verax/cli/init.js +4 -18
- package/src/verax/core/action-classifier.js +4 -3
- package/src/verax/core/artifacts/registry.js +139 -0
- package/src/verax/core/artifacts/verifier.js +990 -0
- package/src/verax/core/baseline/baseline.enforcer.js +137 -0
- package/src/verax/core/baseline/baseline.snapshot.js +233 -0
- package/src/verax/core/capabilities/gates.js +505 -0
- package/src/verax/core/capabilities/registry.js +475 -0
- package/src/verax/core/confidence/confidence-compute.js +144 -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 +80 -0
- package/src/verax/core/confidence/confidence.schema.js +94 -0
- package/src/verax/core/confidence-engine-refactor.js +489 -0
- package/src/verax/core/confidence-engine.js +625 -0
- package/src/verax/core/contracts/index.js +29 -0
- package/src/verax/core/contracts/types.js +186 -0
- package/src/verax/core/contracts/validators.js +456 -0
- package/src/verax/core/decisions/decision.trace.js +278 -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 +405 -0
- package/src/verax/core/determinism/engine.js +222 -0
- package/src/verax/core/determinism/finding-identity.js +149 -0
- package/src/verax/core/determinism/normalize.js +466 -0
- package/src/verax/core/determinism/report-writer.js +93 -0
- package/src/verax/core/determinism/run-fingerprint.js +123 -0
- package/src/verax/core/dynamic-route-intelligence.js +529 -0
- package/src/verax/core/evidence/evidence-capture-service.js +308 -0
- package/src/verax/core/evidence/evidence-intent-ledger.js +166 -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 +192 -0
- package/src/verax/core/failures/exit-codes.js +88 -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 +133 -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 +435 -0
- package/src/verax/core/ga/ga.enforcer.js +87 -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 +84 -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 +1 -0
- package/src/verax/core/integrity/budget.js +138 -0
- package/src/verax/core/integrity/determinism.js +342 -0
- package/src/verax/core/integrity/integrity.js +208 -0
- package/src/verax/core/integrity/poisoning.js +108 -0
- package/src/verax/core/integrity/transaction.js +140 -0
- package/src/verax/core/observe/run-timeline.js +318 -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 +200 -0
- package/src/verax/core/pipeline-tracker.js +243 -0
- package/src/verax/core/product-definition.js +127 -0
- package/src/verax/core/release/provenance.builder.js +130 -0
- package/src/verax/core/release/release-report-writer.js +40 -0
- package/src/verax/core/release/release.enforcer.js +164 -0
- package/src/verax/core/release/reproducibility.check.js +222 -0
- package/src/verax/core/release/sbom.builder.js +292 -0
- package/src/verax/core/replay-validator.js +2 -0
- package/src/verax/core/replay.js +4 -0
- package/src/verax/core/report/cross-index.js +195 -0
- package/src/verax/core/report/human-summary.js +362 -0
- package/src/verax/core/route-intelligence.js +420 -0
- package/src/verax/core/run-id.js +6 -3
- package/src/verax/core/run-manifest.js +4 -3
- package/src/verax/core/security/secrets.scan.js +329 -0
- package/src/verax/core/security/security-report.js +50 -0
- package/src/verax/core/security/security.enforcer.js +128 -0
- package/src/verax/core/security/supplychain.defaults.json +38 -0
- package/src/verax/core/security/supplychain.policy.js +334 -0
- package/src/verax/core/security/vuln.scan.js +265 -0
- package/src/verax/core/truth/truth.certificate.js +252 -0
- package/src/verax/core/ui-feedback-intelligence.js +481 -0
- package/src/verax/detect/conditional-ui-silent-failure.js +84 -0
- package/src/verax/detect/confidence-engine.js +62 -34
- package/src/verax/detect/confidence-helper.js +34 -0
- package/src/verax/detect/dynamic-route-findings.js +338 -0
- package/src/verax/detect/expectation-chain-detector.js +417 -0
- package/src/verax/detect/expectation-model.js +2 -2
- package/src/verax/detect/failure-cause-inference.js +293 -0
- package/src/verax/detect/findings-writer.js +131 -35
- package/src/verax/detect/flow-detector.js +2 -2
- package/src/verax/detect/form-silent-failure.js +98 -0
- package/src/verax/detect/index.js +46 -5
- package/src/verax/detect/invariants-enforcer.js +147 -0
- package/src/verax/detect/journey-stall-detector.js +558 -0
- package/src/verax/detect/navigation-silent-failure.js +82 -0
- package/src/verax/detect/problem-aggregator.js +361 -0
- package/src/verax/detect/route-findings.js +219 -0
- package/src/verax/detect/summary-writer.js +477 -0
- package/src/verax/detect/test-failure-cause-inference.js +314 -0
- package/src/verax/detect/ui-feedback-findings.js +207 -0
- package/src/verax/detect/view-switch-correlator.js +242 -0
- package/src/verax/flow/flow-engine.js +2 -1
- package/src/verax/flow/flow-spec.js +0 -6
- package/src/verax/index.js +4 -0
- package/src/verax/intel/ts-program.js +1 -0
- package/src/verax/intel/vue-navigation-extractor.js +3 -0
- package/src/verax/learn/action-contract-extractor.js +3 -0
- package/src/verax/learn/ast-contract-extractor.js +1 -1
- package/src/verax/learn/flow-extractor.js +1 -0
- package/src/verax/learn/project-detector.js +5 -0
- package/src/verax/learn/react-router-extractor.js +2 -0
- package/src/verax/learn/source-instrumenter.js +1 -0
- package/src/verax/learn/state-extractor.js +2 -1
- package/src/verax/learn/static-extractor.js +1 -0
- package/src/verax/observe/coverage-gaps.js +132 -0
- package/src/verax/observe/expectation-handler.js +126 -0
- package/src/verax/observe/incremental-skip.js +46 -0
- package/src/verax/observe/index.js +51 -155
- package/src/verax/observe/interaction-executor.js +192 -0
- package/src/verax/observe/interaction-runner.js +782 -513
- package/src/verax/observe/network-firewall.js +86 -0
- package/src/verax/observe/observation-builder.js +169 -0
- package/src/verax/observe/observe-context.js +205 -0
- package/src/verax/observe/observe-helpers.js +192 -0
- package/src/verax/observe/observe-runner.js +230 -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/page-traversal.js +138 -0
- package/src/verax/observe/snapshot-ops.js +94 -0
- package/src/verax/observe/ui-feedback-detector.js +742 -0
- package/src/verax/scan-summary-writer.js +2 -0
- package/src/verax/shared/artifact-manager.js +25 -5
- package/src/verax/shared/caching.js +1 -0
- package/src/verax/shared/css-spinner-rules.js +204 -0
- package/src/verax/shared/expectation-tracker.js +1 -0
- package/src/verax/shared/view-switch-rules.js +208 -0
- package/src/verax/shared/zip-artifacts.js +6 -0
- package/src/verax/shared/config-loader.js +0 -169
- /package/src/verax/shared/{expectation-proof.js → expectation-validation.js} +0 -0
|
@@ -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 = { json: false, verbose: false }) {
|
|
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
|
+
|
|
@@ -37,13 +37,15 @@ export async function inspectCommand(runPath, options = {}) {
|
|
|
37
37
|
let summary, findings;
|
|
38
38
|
|
|
39
39
|
try {
|
|
40
|
-
|
|
40
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
41
|
+
summary = JSON.parse(readFileSync(`${fullPath}/summary.json`, 'utf-8'));
|
|
41
42
|
} catch (error) {
|
|
42
43
|
throw new DataError(`Failed to parse summary.json: ${error.message}`);
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
try {
|
|
46
|
-
|
|
47
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
48
|
+
findings = JSON.parse(readFileSync(`${fullPath}/findings.json`, 'utf-8'));
|
|
47
49
|
} catch (error) {
|
|
48
50
|
throw new DataError(`Failed to parse findings.json: ${error.message}`);
|
|
49
51
|
}
|
|
@@ -0,0 +1,215 @@
|
|
|
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
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
57
|
+
const provenance = JSON.parse(readFileSync(provenancePath, 'utf-8'));
|
|
58
|
+
|
|
59
|
+
// Validate provenance structure
|
|
60
|
+
if (!provenance.version || !provenance.git || !provenance.env) {
|
|
61
|
+
status.provenance.blockers.push('Invalid provenance structure');
|
|
62
|
+
} else if (provenance.git.dirty) {
|
|
63
|
+
status.provenance.blockers.push('Provenance indicates dirty git repository');
|
|
64
|
+
} else if (provenance.gaStatus !== 'GA-READY') {
|
|
65
|
+
status.provenance.blockers.push(`GA status is ${provenance.gaStatus}, not GA-READY`);
|
|
66
|
+
} else {
|
|
67
|
+
status.provenance.ok = true;
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
// Try to build it
|
|
71
|
+
try {
|
|
72
|
+
const provenance = await buildProvenance(projectDir);
|
|
73
|
+
writeProvenance(projectDir, provenance);
|
|
74
|
+
status.provenance.exists = true;
|
|
75
|
+
status.provenance.ok = true;
|
|
76
|
+
} catch (error) {
|
|
77
|
+
status.provenance.blockers.push(`Cannot build provenance: ${error.message}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
status.provenance.blockers.push(`Provenance check failed: ${error.message}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 3. Check SBOM
|
|
85
|
+
try {
|
|
86
|
+
const sbomPath = resolve(projectDir, 'release', 'sbom.json');
|
|
87
|
+
if (existsSync(sbomPath)) {
|
|
88
|
+
status.sbom.exists = true;
|
|
89
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
90
|
+
const sbom = JSON.parse(readFileSync(sbomPath, 'utf-8'));
|
|
91
|
+
|
|
92
|
+
// Validate SBOM structure
|
|
93
|
+
if (!sbom.bomFormat || !sbom.components || !Array.isArray(sbom.components)) {
|
|
94
|
+
status.sbom.blockers.push('Invalid SBOM structure');
|
|
95
|
+
} else if (sbom.components.length === 0) {
|
|
96
|
+
status.sbom.blockers.push('SBOM has no components');
|
|
97
|
+
} else {
|
|
98
|
+
status.sbom.ok = true;
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
// Try to build it
|
|
102
|
+
try {
|
|
103
|
+
const sbom = await buildSBOM(projectDir);
|
|
104
|
+
writeSBOM(projectDir, sbom);
|
|
105
|
+
status.sbom.exists = true;
|
|
106
|
+
status.sbom.ok = true;
|
|
107
|
+
} catch (error) {
|
|
108
|
+
status.sbom.blockers.push(`Cannot build SBOM: ${error.message}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch (error) {
|
|
112
|
+
status.sbom.blockers.push(`SBOM check failed: ${error.message}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 4. Check Reproducibility
|
|
116
|
+
try {
|
|
117
|
+
const report = await checkReproducibility(projectDir);
|
|
118
|
+
writeReproducibilityReport(projectDir, report);
|
|
119
|
+
|
|
120
|
+
if (report.verdict === 'REPRODUCIBLE') {
|
|
121
|
+
status.reproducibility.ok = true;
|
|
122
|
+
status.reproducibility.verdict = 'REPRODUCIBLE';
|
|
123
|
+
} else {
|
|
124
|
+
status.reproducibility.verdict = 'NON_REPRODUCIBLE';
|
|
125
|
+
if (report.differences && report.differences.length > 0) {
|
|
126
|
+
status.reproducibility.blockers = report.differences.map(d => d.message);
|
|
127
|
+
} else {
|
|
128
|
+
status.reproducibility.blockers.push('Build is not reproducible');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
status.reproducibility.blockers.push(`Reproducibility check failed: ${error.message}`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Determine overall status
|
|
136
|
+
const allOk = status.ga.ok && status.provenance.ok && status.sbom.ok && status.reproducibility.ok;
|
|
137
|
+
const hasInternalCorruption =
|
|
138
|
+
status.ga.blockers.some(b => b.includes('corruption') || b.includes('INTERNAL')) ||
|
|
139
|
+
status.provenance.blockers.some(b => b.includes('corruption')) ||
|
|
140
|
+
status.sbom.blockers.some(b => b.includes('corruption'));
|
|
141
|
+
|
|
142
|
+
// Write release report
|
|
143
|
+
const releaseStatus = {
|
|
144
|
+
releaseReady: allOk,
|
|
145
|
+
status,
|
|
146
|
+
summary: {
|
|
147
|
+
ga: status.ga.ok ? 'OK' : 'BLOCKED',
|
|
148
|
+
provenance: status.provenance.ok ? 'OK' : 'BLOCKED',
|
|
149
|
+
sbom: status.sbom.ok ? 'OK' : 'BLOCKED',
|
|
150
|
+
reproducibility: status.reproducibility.ok ? 'OK' : 'BLOCKED'
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
const releaseReportPath = writeReleaseReport(projectDir, releaseStatus);
|
|
154
|
+
|
|
155
|
+
// Output
|
|
156
|
+
if (json) {
|
|
157
|
+
console.log(JSON.stringify({
|
|
158
|
+
releaseReady: allOk,
|
|
159
|
+
status,
|
|
160
|
+
summary: {
|
|
161
|
+
ga: status.ga.ok ? 'OK' : 'BLOCKED',
|
|
162
|
+
provenance: status.provenance.ok ? 'OK' : 'BLOCKED',
|
|
163
|
+
sbom: status.sbom.ok ? 'OK' : 'BLOCKED',
|
|
164
|
+
reproducibility: status.reproducibility.ok ? 'OK' : 'BLOCKED'
|
|
165
|
+
},
|
|
166
|
+
reportPath: releaseReportPath
|
|
167
|
+
}, null, 2));
|
|
168
|
+
} else {
|
|
169
|
+
console.log('\n' + '='.repeat(80));
|
|
170
|
+
console.log('RELEASE READINESS CHECK');
|
|
171
|
+
console.log('='.repeat(80));
|
|
172
|
+
|
|
173
|
+
console.log(`\nGA Status: ${status.ga.ok ? '✅ READY' : '❌ BLOCKED'}`);
|
|
174
|
+
if (status.ga.blockers.length > 0) {
|
|
175
|
+
for (const blocker of status.ga.blockers) {
|
|
176
|
+
console.log(` - ${blocker}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
console.log(`\nProvenance: ${status.provenance.ok ? '✅ OK' : '❌ BLOCKED'}`);
|
|
181
|
+
if (status.provenance.blockers.length > 0) {
|
|
182
|
+
for (const blocker of status.provenance.blockers) {
|
|
183
|
+
console.log(` - ${blocker}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
console.log(`\nSBOM: ${status.sbom.ok ? '✅ OK' : '❌ BLOCKED'}`);
|
|
188
|
+
if (status.sbom.blockers.length > 0) {
|
|
189
|
+
for (const blocker of status.sbom.blockers) {
|
|
190
|
+
console.log(` - ${blocker}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
console.log(`\nReproducibility: ${status.reproducibility.ok ? '✅ REPRODUCIBLE' : '❌ NON_REPRODUCIBLE'}`);
|
|
195
|
+
if (status.reproducibility.blockers.length > 0) {
|
|
196
|
+
for (const blocker of status.reproducibility.blockers) {
|
|
197
|
+
console.log(` - ${blocker}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
console.log(`\nOverall: ${allOk ? '✅ RELEASE-READY' : '❌ RELEASE-BLOCKED'}`);
|
|
202
|
+
console.log(`\nSee report: ${releaseReportPath}`);
|
|
203
|
+
console.log('='.repeat(80) + '\n');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Exit codes: 0 = RELEASE-READY, 2 = RELEASE-BLOCKED, 70 = Internal corruption
|
|
207
|
+
if (allOk) {
|
|
208
|
+
process.exit(0);
|
|
209
|
+
} else if (hasInternalCorruption) {
|
|
210
|
+
process.exit(70);
|
|
211
|
+
} else {
|
|
212
|
+
process.exit(2);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
package/src/cli/commands/run.js
CHANGED
|
@@ -17,6 +17,8 @@ import { detectFindings } from '../util/detection-engine.js';
|
|
|
17
17
|
import { writeFindingsJson } from '../util/findings-writer.js';
|
|
18
18
|
import { writeSummaryJson } from '../util/summary-writer.js';
|
|
19
19
|
import { computeRuntimeBudget, withTimeout } from '../util/runtime-budget.js';
|
|
20
|
+
import { saveDigest } from '../util/digest-engine.js';
|
|
21
|
+
import { ARTIFACT_REGISTRY, getArtifactVersions } from '../../verax/core/artifacts/registry.js';
|
|
20
22
|
|
|
21
23
|
const __filename = fileURLToPath(import.meta.url);
|
|
22
24
|
const __dirname = dirname(__filename);
|
|
@@ -24,7 +26,8 @@ const __dirname = dirname(__filename);
|
|
|
24
26
|
function getVersion() {
|
|
25
27
|
try {
|
|
26
28
|
const pkgPath = resolve(__dirname, '../../../package.json');
|
|
27
|
-
|
|
29
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
30
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
28
31
|
return pkg.version;
|
|
29
32
|
} catch {
|
|
30
33
|
return '0.2.0';
|
|
@@ -92,6 +95,8 @@ export async function runCommand(options) {
|
|
|
92
95
|
try {
|
|
93
96
|
const failedAt = new Date().toISOString();
|
|
94
97
|
atomicWriteJson(paths.runStatusJson, {
|
|
98
|
+
contractVersion: 1,
|
|
99
|
+
artifactVersions: getArtifactVersions(),
|
|
95
100
|
status: 'FAILED',
|
|
96
101
|
runId,
|
|
97
102
|
startedAt,
|
|
@@ -100,6 +105,7 @@ export async function runCommand(options) {
|
|
|
100
105
|
});
|
|
101
106
|
|
|
102
107
|
atomicWriteJson(paths.runMetaJson, {
|
|
108
|
+
contractVersion: ARTIFACT_REGISTRY.runMeta.contractVersion,
|
|
103
109
|
veraxVersion: getVersion(),
|
|
104
110
|
nodeVersion: process.version,
|
|
105
111
|
platform: process.platform,
|
|
@@ -147,7 +153,7 @@ export async function runCommand(options) {
|
|
|
147
153
|
|
|
148
154
|
try {
|
|
149
155
|
// Generate run ID
|
|
150
|
-
runId = generateRunId();
|
|
156
|
+
runId = generateRunId(url);
|
|
151
157
|
if (verbose && !json) console.log(`Run ID: ${runId}`);
|
|
152
158
|
|
|
153
159
|
paths = getRunPaths(projectRoot, out, runId);
|
|
@@ -197,6 +203,8 @@ export async function runCommand(options) {
|
|
|
197
203
|
startedAt = now.toISOString();
|
|
198
204
|
|
|
199
205
|
atomicWriteJson(paths.runStatusJson, {
|
|
206
|
+
contractVersion: 1,
|
|
207
|
+
artifactVersions: getArtifactVersions(),
|
|
200
208
|
status: 'RUNNING',
|
|
201
209
|
runId,
|
|
202
210
|
startedAt,
|
|
@@ -204,6 +212,7 @@ export async function runCommand(options) {
|
|
|
204
212
|
|
|
205
213
|
// Write metadata
|
|
206
214
|
atomicWriteJson(paths.runMetaJson, {
|
|
215
|
+
contractVersion: ARTIFACT_REGISTRY.runMeta.contractVersion,
|
|
207
216
|
veraxVersion: getVersion(),
|
|
208
217
|
nodeVersion: process.version,
|
|
209
218
|
platform: process.platform,
|
|
@@ -291,7 +300,8 @@ export async function runCommand(options) {
|
|
|
291
300
|
paths.evidenceDir,
|
|
292
301
|
(progress) => {
|
|
293
302
|
events.emit(progress.event, progress);
|
|
294
|
-
}
|
|
303
|
+
},
|
|
304
|
+
{}
|
|
295
305
|
),
|
|
296
306
|
'Observe'
|
|
297
307
|
);
|
|
@@ -404,6 +414,8 @@ export async function runCommand(options) {
|
|
|
404
414
|
|
|
405
415
|
// Write completed status
|
|
406
416
|
atomicWriteJson(paths.runStatusJson, {
|
|
417
|
+
contractVersion: 1,
|
|
418
|
+
artifactVersions: getArtifactVersions(),
|
|
407
419
|
status: 'COMPLETE',
|
|
408
420
|
runId,
|
|
409
421
|
startedAt,
|
|
@@ -412,6 +424,7 @@ export async function runCommand(options) {
|
|
|
412
424
|
|
|
413
425
|
// Update metadata with completion time
|
|
414
426
|
atomicWriteJson(paths.runMetaJson, {
|
|
427
|
+
contractVersion: ARTIFACT_REGISTRY.runMeta.contractVersion,
|
|
415
428
|
veraxVersion: getVersion(),
|
|
416
429
|
nodeVersion: process.version,
|
|
417
430
|
platform: process.platform,
|
|
@@ -481,6 +494,11 @@ export async function runCommand(options) {
|
|
|
481
494
|
// Write observe results
|
|
482
495
|
writeObserveJson(paths.baseDir, observeData);
|
|
483
496
|
|
|
497
|
+
// H5: Write deterministic digest for reproducibility proof
|
|
498
|
+
if (observeData && observeData.digest) {
|
|
499
|
+
saveDigest(resolve(paths.baseDir, 'run.digest.json'), observeData.digest);
|
|
500
|
+
}
|
|
501
|
+
|
|
484
502
|
events.emit('phase:completed', {
|
|
485
503
|
phase: 'Finalize Artifacts',
|
|
486
504
|
message: 'Run artifacts written',
|
|
@@ -508,9 +526,27 @@ export async function runCommand(options) {
|
|
|
508
526
|
|
|
509
527
|
// Print summary if not JSON mode
|
|
510
528
|
if (!json) {
|
|
511
|
-
|
|
512
|
-
console.log(
|
|
513
|
-
console.log(
|
|
529
|
+
const relativePath = paths.baseDir.replace(/\\/g, '/').split('/').slice(-1)[0];
|
|
530
|
+
console.log('');
|
|
531
|
+
console.log('VERAX — Silent Failure Detection');
|
|
532
|
+
console.log('');
|
|
533
|
+
console.log(`✔ URL: ${url}`);
|
|
534
|
+
console.log('');
|
|
535
|
+
console.log('Learn phase:');
|
|
536
|
+
console.log(` → Extracted ${expectations.length} promises`);
|
|
537
|
+
console.log('');
|
|
538
|
+
console.log('Observe phase:');
|
|
539
|
+
console.log(` → Executed ${observeData.stats?.attempted || 0} interactions`);
|
|
540
|
+
console.log(` → Observed: ${observeData.stats?.observed || 0}/${observeData.stats?.attempted || 0}`);
|
|
541
|
+
console.log('');
|
|
542
|
+
console.log('Detect phase:');
|
|
543
|
+
console.log(` → Silent failures: ${detectData.stats?.silentFailures || 0}`);
|
|
544
|
+
console.log(` → Unproven: ${detectData.stats?.unproven || 0}`);
|
|
545
|
+
console.log(` → Coverage gaps: ${detectData.stats?.coverageGaps || 0}`);
|
|
546
|
+
console.log('');
|
|
547
|
+
console.log('Artifacts written to:');
|
|
548
|
+
console.log(` .verax/runs/${relativePath}/`);
|
|
549
|
+
console.log('');
|
|
514
550
|
}
|
|
515
551
|
|
|
516
552
|
return { runId, paths, success: true };
|
|
@@ -528,6 +564,8 @@ export async function runCommand(options) {
|
|
|
528
564
|
try {
|
|
529
565
|
const failedAt = new Date().toISOString();
|
|
530
566
|
atomicWriteJson(paths.runStatusJson, {
|
|
567
|
+
contractVersion: 1,
|
|
568
|
+
artifactVersions: getArtifactVersions(),
|
|
531
569
|
status: 'FAILED',
|
|
532
570
|
runId,
|
|
533
571
|
startedAt,
|
|
@@ -537,6 +575,7 @@ export async function runCommand(options) {
|
|
|
537
575
|
|
|
538
576
|
// Update metadata
|
|
539
577
|
atomicWriteJson(paths.runMetaJson, {
|
|
578
|
+
contractVersion: ARTIFACT_REGISTRY.runMeta.contractVersion,
|
|
540
579
|
veraxVersion: getVersion(),
|
|
541
580
|
nodeVersion: process.version,
|
|
542
581
|
platform: process.platform,
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.8 — Security Check CLI Command
|
|
3
|
+
*
|
|
4
|
+
* Checks security baseline: secrets, vulnerabilities, supply-chain.
|
|
5
|
+
* Exit codes: 0 = SECURITY-OK, 6 = SECURITY-BLOCKED, 70 = Internal corruption
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { scanSecrets, writeSecretsReport } from '../../verax/core/security/secrets.scan.js';
|
|
9
|
+
import { scanVulnerabilities, writeVulnReport } from '../../verax/core/security/vuln.scan.js';
|
|
10
|
+
import { evaluateSupplyChainPolicy, writeSupplyChainReport } from '../../verax/core/security/supplychain.policy.js';
|
|
11
|
+
import { writeSecurityReport } from '../../verax/core/security/security-report.js';
|
|
12
|
+
import { resolve } from 'path';
|
|
13
|
+
import { mkdirSync as _mkdirSync, existsSync } from 'fs';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Security check command
|
|
17
|
+
*
|
|
18
|
+
* @param {Object} options - Options
|
|
19
|
+
* @param {boolean} [options.json] - Output as JSON
|
|
20
|
+
*/
|
|
21
|
+
export async function securityCheckCommand(options = {}) {
|
|
22
|
+
const { json = false } = options;
|
|
23
|
+
const projectDir = resolve(process.cwd());
|
|
24
|
+
|
|
25
|
+
const status = {
|
|
26
|
+
secrets: { ok: false, hasSecrets: false, blockers: [], tool: 'VERAX_SECRETS_SCANNER' },
|
|
27
|
+
vulnerabilities: { ok: false, blocking: false, blockers: [], warnings: [], tool: null, availability: 'UNKNOWN' },
|
|
28
|
+
supplychain: { ok: false, violations: [], blockers: [], tool: 'VERAX_SUPPLYCHAIN_POLICY' }
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// 1. Scan for secrets
|
|
32
|
+
try {
|
|
33
|
+
const secretsResult = await scanSecrets(projectDir);
|
|
34
|
+
writeSecretsReport(projectDir, secretsResult);
|
|
35
|
+
|
|
36
|
+
status.secrets.ok = secretsResult.ok;
|
|
37
|
+
status.secrets.hasSecrets = secretsResult.hasSecrets;
|
|
38
|
+
|
|
39
|
+
if (secretsResult.hasSecrets) {
|
|
40
|
+
const critical = secretsResult.findings.filter(f => f.severity === 'CRITICAL');
|
|
41
|
+
const high = secretsResult.findings.filter(f => f.severity === 'HIGH');
|
|
42
|
+
|
|
43
|
+
if (critical.length > 0) {
|
|
44
|
+
status.secrets.blockers.push(`${critical.length} CRITICAL secret(s) detected`);
|
|
45
|
+
}
|
|
46
|
+
if (high.length > 0) {
|
|
47
|
+
status.secrets.blockers.push(`${high.length} HIGH severity secret(s) detected`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Add sample findings (first 3)
|
|
51
|
+
const sampleFindings = secretsResult.findings.slice(0, 3).map(f =>
|
|
52
|
+
`${f.type} in ${f.file}:${f.line}`
|
|
53
|
+
);
|
|
54
|
+
status.secrets.blockers.push(`Sample findings: ${sampleFindings.join(', ')}`);
|
|
55
|
+
}
|
|
56
|
+
} catch (error) {
|
|
57
|
+
status.secrets.blockers.push(`Secrets scan failed: ${error.message}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 2. Scan vulnerabilities
|
|
61
|
+
let vulnResult = null;
|
|
62
|
+
try {
|
|
63
|
+
vulnResult = await scanVulnerabilities(projectDir);
|
|
64
|
+
writeVulnReport(projectDir, vulnResult);
|
|
65
|
+
|
|
66
|
+
status.vulnerabilities.ok = !vulnResult.blocking;
|
|
67
|
+
status.vulnerabilities.blocking = vulnResult.blocking;
|
|
68
|
+
status.vulnerabilities.tool = vulnResult.tool || null;
|
|
69
|
+
status.vulnerabilities.availability = vulnResult.availability || 'UNKNOWN';
|
|
70
|
+
status.vulnerabilities.osvAvailable = vulnResult.osvAvailable || false;
|
|
71
|
+
|
|
72
|
+
if (vulnResult.availability === 'NOT_AVAILABLE') {
|
|
73
|
+
status.vulnerabilities.warnings.push('OSV scanner not available, using npm audit fallback');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (vulnResult.blocking) {
|
|
77
|
+
if (vulnResult.summary.critical > 0) {
|
|
78
|
+
status.vulnerabilities.blockers.push(`${vulnResult.summary.critical} CRITICAL vulnerability/vulnerabilities`);
|
|
79
|
+
}
|
|
80
|
+
if (vulnResult.summary.high > 0) {
|
|
81
|
+
status.vulnerabilities.blockers.push(`${vulnResult.summary.high} HIGH severity vulnerability/vulnerabilities`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (vulnResult.summary.medium > 0 && !vulnResult.blocking) {
|
|
86
|
+
status.vulnerabilities.warnings.push(`${vulnResult.summary.medium} MEDIUM severity vulnerability/vulnerabilities (non-blocking)`);
|
|
87
|
+
}
|
|
88
|
+
} catch (error) {
|
|
89
|
+
status.vulnerabilities.blockers.push(`Vulnerability scan failed: ${error.message}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 3. Check supply-chain policy
|
|
93
|
+
let supplyChainResult = null;
|
|
94
|
+
try {
|
|
95
|
+
supplyChainResult = await evaluateSupplyChainPolicy(projectDir);
|
|
96
|
+
writeSupplyChainReport(projectDir, supplyChainResult);
|
|
97
|
+
|
|
98
|
+
status.supplychain.ok = supplyChainResult.ok;
|
|
99
|
+
status.supplychain.violations = supplyChainResult.violations;
|
|
100
|
+
|
|
101
|
+
if (!supplyChainResult.ok) {
|
|
102
|
+
for (const violation of supplyChainResult.violations) {
|
|
103
|
+
status.supplychain.blockers.push(violation.message);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
} catch (error) {
|
|
107
|
+
status.supplychain.blockers.push(`Supply-chain check failed: ${error.message}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Determine overall status
|
|
111
|
+
const allOk = status.secrets.ok && status.vulnerabilities.ok && status.supplychain.ok;
|
|
112
|
+
|
|
113
|
+
// Write unified security report
|
|
114
|
+
let secretsReport = null;
|
|
115
|
+
try {
|
|
116
|
+
const secretsPath = resolve(projectDir, 'release', 'security.secrets.report.json');
|
|
117
|
+
if (existsSync(secretsPath)) {
|
|
118
|
+
const { readFileSync } = await import('fs');
|
|
119
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
120
|
+
secretsReport = JSON.parse(readFileSync(secretsPath, 'utf-8'));
|
|
121
|
+
}
|
|
122
|
+
} catch {
|
|
123
|
+
// Ignore
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
let vulnReportData = vulnResult;
|
|
127
|
+
let supplyChainReportData = supplyChainResult;
|
|
128
|
+
|
|
129
|
+
const unifiedReport = {
|
|
130
|
+
securityOk: allOk,
|
|
131
|
+
status,
|
|
132
|
+
summary: {
|
|
133
|
+
secrets: status.secrets.ok ? 'OK' : 'BLOCKED',
|
|
134
|
+
vulnerabilities: status.vulnerabilities.ok ? 'OK' : (status.vulnerabilities.blocking ? 'BLOCKED' : (status.vulnerabilities.availability === 'NOT_AVAILABLE' ? 'NOT_AVAILABLE' : 'WARN')),
|
|
135
|
+
supplychain: status.supplychain.ok ? 'OK' : 'BLOCKED'
|
|
136
|
+
},
|
|
137
|
+
secretsReport,
|
|
138
|
+
vulnReport: vulnReportData,
|
|
139
|
+
supplyChainReport: supplyChainReportData
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const unifiedReportPath = writeSecurityReport(projectDir, unifiedReport);
|
|
143
|
+
const hasInternalCorruption =
|
|
144
|
+
status.secrets.blockers.some(b => b.includes('corruption') || b.includes('Internal')) ||
|
|
145
|
+
status.vulnerabilities.blockers.some(b => b.includes('corruption')) ||
|
|
146
|
+
status.supplychain.blockers.some(b => b.includes('corruption'));
|
|
147
|
+
|
|
148
|
+
// Output
|
|
149
|
+
if (json) {
|
|
150
|
+
console.log(JSON.stringify({
|
|
151
|
+
securityOk: allOk,
|
|
152
|
+
status,
|
|
153
|
+
summary: {
|
|
154
|
+
secrets: status.secrets.ok ? 'OK' : 'BLOCKED',
|
|
155
|
+
vulnerabilities: status.vulnerabilities.ok ? 'OK' : (status.vulnerabilities.blocking ? 'BLOCKED' : (status.vulnerabilities.availability === 'NOT_AVAILABLE' ? 'NOT_AVAILABLE' : 'WARN')),
|
|
156
|
+
supplychain: status.supplychain.ok ? 'OK' : 'BLOCKED'
|
|
157
|
+
},
|
|
158
|
+
unifiedReportPath: unifiedReportPath
|
|
159
|
+
}, null, 2));
|
|
160
|
+
} else {
|
|
161
|
+
console.log('\n' + '='.repeat(80));
|
|
162
|
+
console.log('SECURITY BASELINE CHECK');
|
|
163
|
+
console.log('='.repeat(80));
|
|
164
|
+
|
|
165
|
+
console.log(`\nSecrets: ${status.secrets.ok ? '✅ OK' : '❌ BLOCKED'}`);
|
|
166
|
+
if (status.secrets.blockers.length > 0) {
|
|
167
|
+
for (const blocker of status.secrets.blockers) {
|
|
168
|
+
console.log(` - ${blocker}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
console.log(`\nVulnerabilities: ${status.vulnerabilities.ok ? '✅ OK' : (status.vulnerabilities.blocking ? '❌ BLOCKED' : '⚠️ WARN')}`);
|
|
173
|
+
if (status.vulnerabilities.blockers.length > 0) {
|
|
174
|
+
for (const blocker of status.vulnerabilities.blockers) {
|
|
175
|
+
console.log(` - ${blocker}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (status.vulnerabilities.warnings.length > 0) {
|
|
179
|
+
for (const warning of status.vulnerabilities.warnings) {
|
|
180
|
+
console.log(` ⚠️ ${warning}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log(`\nSupply-chain: ${status.supplychain.ok ? '✅ OK' : '❌ BLOCKED'}`);
|
|
185
|
+
if (status.supplychain.blockers.length > 0) {
|
|
186
|
+
for (const blocker of status.supplychain.blockers) {
|
|
187
|
+
console.log(` - ${blocker}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
console.log(`\nOverall: ${allOk ? '✅ SECURITY-OK' : '❌ SECURITY-BLOCKED'}`);
|
|
192
|
+
console.log(`\nSee unified report: ${unifiedReportPath}`);
|
|
193
|
+
console.log('='.repeat(80) + '\n');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Exit codes: 0 = SECURITY-OK, 6 = SECURITY-BLOCKED, 70 = Internal corruption
|
|
197
|
+
// NOT_AVAILABLE tools exit 0 only if policy allows (strict mode would exit 2)
|
|
198
|
+
const hasNotAvailable = status.vulnerabilities.availability === 'NOT_AVAILABLE';
|
|
199
|
+
const strictMode = process.env.VERAX_SECURITY_STRICT === '1';
|
|
200
|
+
|
|
201
|
+
if (allOk) {
|
|
202
|
+
process.exit(0);
|
|
203
|
+
} else if (hasNotAvailable && !strictMode) {
|
|
204
|
+
// NOT_AVAILABLE is not a blocker unless strict mode
|
|
205
|
+
process.exit(0);
|
|
206
|
+
} else if (hasInternalCorruption) {
|
|
207
|
+
process.exit(70);
|
|
208
|
+
} else {
|
|
209
|
+
process.exit(6);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|