@veraxhq/verax 0.3.0 → 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 +28 -20
- package/bin/verax.js +11 -18
- package/package.json +28 -7
- package/src/cli/commands/baseline.js +1 -2
- package/src/cli/commands/default.js +72 -81
- package/src/cli/commands/doctor.js +29 -0
- package/src/cli/commands/ga.js +3 -0
- package/src/cli/commands/gates.js +1 -1
- package/src/cli/commands/inspect.js +6 -133
- package/src/cli/commands/release-check.js +2 -0
- package/src/cli/commands/run.js +74 -246
- package/src/cli/commands/security-check.js +2 -1
- package/src/cli/commands/truth.js +0 -1
- package/src/cli/entry.js +82 -309
- package/src/cli/util/angular-component-extractor.js +2 -2
- package/src/cli/util/angular-navigation-detector.js +2 -2
- package/src/cli/util/ast-interactive-detector.js +4 -6
- package/src/cli/util/ast-network-detector.js +3 -3
- package/src/cli/util/ast-promise-extractor.js +581 -0
- package/src/cli/util/ast-usestate-detector.js +3 -3
- package/src/cli/util/atomic-write.js +12 -1
- 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 +2 -1
- package/src/cli/util/determinism-writer.js +1 -1
- package/src/cli/util/digest-engine.js +359 -0
- package/src/cli/util/dom-diff.js +226 -0
- package/src/cli/util/env-url.js +0 -4
- package/src/cli/util/evidence-engine.js +287 -0
- package/src/cli/util/expectation-extractor.js +217 -367
- package/src/cli/util/findings-writer.js +19 -126
- 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 -2
- 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 -2
- package/src/cli/util/paths.js +12 -3
- package/src/cli/util/project-discovery.js +284 -3
- package/src/cli/util/project-writer.js +2 -2
- package/src/cli/util/run-id.js +23 -27
- package/src/cli/util/run-result.js +778 -0
- package/src/cli/util/selector-resolver.js +235 -0
- package/src/cli/util/summary-writer.js +2 -1
- package/src/cli/util/svelte-navigation-detector.js +3 -3
- package/src/cli/util/svelte-sfc-extractor.js +0 -1
- package/src/cli/util/svelte-state-detector.js +1 -2
- 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 +4 -3
- package/src/cli/util/vue-sfc-extractor.js +1 -2
- package/src/cli/util/vue-state-detector.js +1 -1
- 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/finding-explainer.js +3 -56
- package/src/verax/cli/init.js +4 -18
- package/src/verax/core/action-classifier.js +4 -3
- package/src/verax/core/artifacts/registry.js +0 -15
- package/src/verax/core/artifacts/verifier.js +18 -8
- package/src/verax/core/baseline/baseline.snapshot.js +2 -0
- package/src/verax/core/capabilities/gates.js +7 -1
- package/src/verax/core/confidence/confidence-compute.js +14 -7
- package/src/verax/core/confidence/confidence.loader.js +1 -0
- package/src/verax/core/confidence-engine-refactor.js +8 -3
- package/src/verax/core/confidence-engine.js +162 -23
- package/src/verax/core/contracts/types.js +1 -0
- package/src/verax/core/contracts/validators.js +79 -4
- package/src/verax/core/decision-snapshot.js +3 -30
- package/src/verax/core/decisions/decision.trace.js +2 -0
- package/src/verax/core/determinism/contract-writer.js +2 -2
- package/src/verax/core/determinism/contract.js +1 -1
- package/src/verax/core/determinism/diff.js +42 -1
- package/src/verax/core/determinism/engine.js +7 -6
- package/src/verax/core/determinism/finding-identity.js +3 -2
- package/src/verax/core/determinism/normalize.js +32 -4
- package/src/verax/core/determinism/report-writer.js +1 -0
- package/src/verax/core/determinism/run-fingerprint.js +7 -2
- package/src/verax/core/dynamic-route-intelligence.js +8 -7
- package/src/verax/core/evidence/evidence-capture-service.js +1 -0
- package/src/verax/core/evidence/evidence-intent-ledger.js +2 -1
- package/src/verax/core/evidence-builder.js +2 -2
- package/src/verax/core/execution-mode-context.js +1 -1
- package/src/verax/core/execution-mode-detector.js +5 -3
- package/src/verax/core/failures/exit-codes.js +39 -37
- package/src/verax/core/failures/failure-summary.js +1 -1
- package/src/verax/core/failures/failure.factory.js +3 -3
- package/src/verax/core/failures/failure.ledger.js +3 -2
- package/src/verax/core/ga/ga.artifact.js +1 -1
- package/src/verax/core/ga/ga.contract.js +3 -2
- package/src/verax/core/ga/ga.enforcer.js +1 -0
- package/src/verax/core/guardrails/policy.loader.js +1 -0
- package/src/verax/core/guardrails/truth-reconciliation.js +1 -1
- package/src/verax/core/guardrails-engine.js +2 -2
- 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 +2 -0
- package/src/verax/core/perf/perf.report.js +2 -0
- package/src/verax/core/pipeline-tracker.js +5 -0
- package/src/verax/core/release/provenance.builder.js +73 -214
- package/src/verax/core/release/release.enforcer.js +14 -9
- package/src/verax/core/release/reproducibility.check.js +1 -0
- package/src/verax/core/release/sbom.builder.js +32 -23
- 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 +6 -3
- package/src/verax/core/report/human-summary.js +141 -1
- package/src/verax/core/route-intelligence.js +4 -3
- 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 +10 -7
- package/src/verax/core/security/security.enforcer.js +4 -0
- package/src/verax/core/security/supplychain.policy.js +9 -1
- package/src/verax/core/security/vuln.scan.js +2 -2
- package/src/verax/core/truth/truth.certificate.js +3 -1
- package/src/verax/core/ui-feedback-intelligence.js +12 -46
- package/src/verax/detect/conditional-ui-silent-failure.js +84 -0
- package/src/verax/detect/confidence-engine.js +100 -660
- package/src/verax/detect/confidence-helper.js +1 -0
- package/src/verax/detect/detection-engine.js +1 -18
- package/src/verax/detect/dynamic-route-findings.js +17 -14
- package/src/verax/detect/expectation-chain-detector.js +1 -1
- package/src/verax/detect/expectation-model.js +3 -5
- package/src/verax/detect/failure-cause-inference.js +293 -0
- package/src/verax/detect/findings-writer.js +126 -166
- 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 +51 -234
- package/src/verax/detect/invariants-enforcer.js +147 -0
- package/src/verax/detect/journey-stall-detector.js +4 -4
- 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 +7 -6
- 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 +18 -18
- package/src/verax/detect/verdict-engine.js +3 -57
- package/src/verax/detect/view-switch-correlator.js +2 -2
- package/src/verax/flow/flow-engine.js +2 -1
- package/src/verax/flow/flow-spec.js +0 -6
- package/src/verax/index.js +48 -412
- 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 +67 -682
- 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/route-validator.js +1 -4
- 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 +735 -84
- package/src/verax/observe/interaction-executor.js +192 -0
- package/src/verax/observe/interaction-runner.js +782 -530
- 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 +1 -1
- package/src/verax/observe/observe-helpers.js +2 -1
- package/src/verax/observe/observe-runner.js +28 -24
- package/src/verax/observe/observers/budget-observer.js +3 -3
- package/src/verax/observe/observers/console-observer.js +4 -4
- package/src/verax/observe/observers/coverage-observer.js +4 -4
- package/src/verax/observe/observers/interaction-observer.js +3 -3
- package/src/verax/observe/observers/navigation-observer.js +4 -4
- package/src/verax/observe/observers/network-observer.js +4 -4
- package/src/verax/observe/observers/safety-observer.js +1 -1
- package/src/verax/observe/observers/ui-feedback-observer.js +4 -4
- package/src/verax/observe/page-traversal.js +138 -0
- package/src/verax/observe/snapshot-ops.js +94 -0
- package/src/verax/observe/ui-signal-sensor.js +2 -148
- package/src/verax/scan-summary-writer.js +10 -42
- package/src/verax/shared/artifact-manager.js +30 -13
- package/src/verax/shared/caching.js +1 -0
- package/src/verax/shared/expectation-tracker.js +1 -0
- package/src/verax/shared/zip-artifacts.js +6 -0
- package/src/verax/core/confidence-engine.js.backup +0 -471
- package/src/verax/shared/config-loader.js +0 -169
- /package/src/verax/shared/{expectation-proof.js → expectation-validation.js} +0 -0
|
@@ -59,6 +59,34 @@ export function normalizeArtifact(artifactName, json) {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
function normalizeDeterminismContract(artifact) {
|
|
63
|
+
return normalizeGeneric(artifact);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function normalizeRunMeta(artifact) {
|
|
67
|
+
return normalizeGeneric(artifact);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function normalizeTraces(artifact) {
|
|
71
|
+
return normalizeGeneric(artifact);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function normalizePerformanceReport(artifact) {
|
|
75
|
+
return normalizeGeneric(artifact);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function normalizeSecurityReport(artifact) {
|
|
79
|
+
return normalizeGeneric(artifact);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function normalizeGAReport(artifact) {
|
|
83
|
+
return normalizeGeneric(artifact);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function normalizeReleaseReport(artifact) {
|
|
87
|
+
return normalizeGeneric(artifact);
|
|
88
|
+
}
|
|
89
|
+
|
|
62
90
|
/**
|
|
63
91
|
* Normalize findings artifact
|
|
64
92
|
*/
|
|
@@ -414,11 +442,11 @@ function normalizePath(path) {
|
|
|
414
442
|
if (!path || typeof path !== 'string') return path;
|
|
415
443
|
let normalized = path.replace(/\\/g, '/');
|
|
416
444
|
// Remove absolute path prefixes
|
|
417
|
-
normalized = normalized.replace(/^[A-Z]:\/[
|
|
418
|
-
normalized = normalized.replace(/^\/[
|
|
445
|
+
normalized = normalized.replace(/^[A-Z]:\/[^/]+/, '');
|
|
446
|
+
normalized = normalized.replace(/^\/[^/]+/, '');
|
|
419
447
|
// Remove temp dirs
|
|
420
|
-
normalized = normalized.replace(/\/tmp\/[
|
|
421
|
-
normalized = normalized.replace(/\/\.verax\/runs\/[
|
|
448
|
+
normalized = normalized.replace(/\/tmp\/[^/]+/g, '/tmp/...');
|
|
449
|
+
normalized = normalized.replace(/\/\.verax\/runs\/[^/]+/g, '/.verax/runs/...');
|
|
422
450
|
return normalized;
|
|
423
451
|
}
|
|
424
452
|
|
|
@@ -63,6 +63,7 @@ export function writeDeterminismReportFromFile(runDir) {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
try {
|
|
66
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
66
67
|
const decisionsData = JSON.parse(readFileSync(decisionsPath, 'utf-8'));
|
|
67
68
|
const decisionRecorder = DecisionRecorder.fromExport(decisionsData);
|
|
68
69
|
return writeDeterminismReport(runDir, decisionRecorder);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { createHash } from 'crypto';
|
|
9
9
|
import { readFileSync, existsSync } from 'fs';
|
|
10
|
-
import { resolve, dirname } from 'path';
|
|
10
|
+
import { resolve, dirname as _dirname } from 'path';
|
|
11
11
|
import { getVeraxVersion } from '../run-id.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -25,7 +25,8 @@ export function computeRunFingerprint(params) {
|
|
|
25
25
|
const {
|
|
26
26
|
url,
|
|
27
27
|
projectDir,
|
|
28
|
-
|
|
28
|
+
// @ts-expect-error - Private field documented but not in type
|
|
29
|
+
_manifestPath = null,
|
|
29
30
|
policyHash = null,
|
|
30
31
|
fixtureId = null
|
|
31
32
|
} = params;
|
|
@@ -52,6 +53,7 @@ export function computeRunFingerprint(params) {
|
|
|
52
53
|
const configString = JSON.stringify(fingerprintInput, Object.keys(fingerprintInput).sort());
|
|
53
54
|
const hash = createHash('sha256').update(configString).digest('hex');
|
|
54
55
|
|
|
56
|
+
// @ts-expect-error - digest returns string
|
|
55
57
|
return hash.substring(0, 32); // 32 chars for readability
|
|
56
58
|
}
|
|
57
59
|
|
|
@@ -65,6 +67,7 @@ function computeSourceHash(projectDir) {
|
|
|
65
67
|
const packagePath = resolve(projectDir, 'package.json');
|
|
66
68
|
if (existsSync(packagePath)) {
|
|
67
69
|
const pkgContent = readFileSync(packagePath, 'utf-8');
|
|
70
|
+
// @ts-expect-error - digest returns string
|
|
68
71
|
return createHash('sha256').update(pkgContent).digest('hex').substring(0, 16);
|
|
69
72
|
}
|
|
70
73
|
return 'no-source';
|
|
@@ -88,11 +91,13 @@ function computePolicyHash(projectDir) {
|
|
|
88
91
|
for (const path of policyPaths) {
|
|
89
92
|
if (existsSync(path)) {
|
|
90
93
|
const content = readFileSync(path, 'utf-8');
|
|
94
|
+
// @ts-expect-error - digest returns string
|
|
91
95
|
hashes.push(createHash('sha256').update(content).digest('hex').substring(0, 8));
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
if (hashes.length > 0) {
|
|
100
|
+
// @ts-expect-error - digest returns string
|
|
96
101
|
return createHash('sha256').update(hashes.join('|')).digest('hex').substring(0, 16);
|
|
97
102
|
}
|
|
98
103
|
|
|
@@ -66,6 +66,7 @@ export function classifyDynamicRoute(routeModel, trace = null) {
|
|
|
66
66
|
const isAuthGated = isAuthGatedRoute(routeModel, trace);
|
|
67
67
|
const isSSROnly = isSSROnlyRoute(routeModel, trace);
|
|
68
68
|
const isRuntimeOnly = isRuntimeOnlyRoute(routeModel, trace);
|
|
69
|
+
// @ts-expect-error - Function hoisting
|
|
69
70
|
const hasObservableSignals = hasObservableSignals(routeModel, trace);
|
|
70
71
|
|
|
71
72
|
// UNVERIFIABLE: Auth-gated, SSR-only, or runtime-only without observable signals
|
|
@@ -107,7 +108,7 @@ export function classifyDynamicRoute(routeModel, trace = null) {
|
|
|
107
108
|
/**
|
|
108
109
|
* Check if route is auth-gated
|
|
109
110
|
*/
|
|
110
|
-
function isAuthGatedRoute(routeModel,
|
|
111
|
+
function isAuthGatedRoute(routeModel, _trace) {
|
|
111
112
|
// Check route path patterns
|
|
112
113
|
const path = routeModel.path || '';
|
|
113
114
|
const authPatterns = ['/admin', '/dashboard', '/account', '/settings', '/profile', '/user'];
|
|
@@ -117,8 +118,8 @@ function isAuthGatedRoute(routeModel, trace) {
|
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
// Check trace for auth-related signals
|
|
120
|
-
if (
|
|
121
|
-
const sensors =
|
|
121
|
+
if (_trace) {
|
|
122
|
+
const sensors = _trace.sensors || {};
|
|
122
123
|
const navSensor = sensors.navigation || {};
|
|
123
124
|
|
|
124
125
|
// If navigation was blocked or redirected to login
|
|
@@ -133,7 +134,7 @@ function isAuthGatedRoute(routeModel, trace) {
|
|
|
133
134
|
/**
|
|
134
135
|
* Check if route is SSR-only
|
|
135
136
|
*/
|
|
136
|
-
function isSSROnlyRoute(routeModel,
|
|
137
|
+
function isSSROnlyRoute(routeModel, _trace) {
|
|
137
138
|
// Next.js app router with dynamic segments might be SSR-only
|
|
138
139
|
if (routeModel.framework === 'next-app' && routeModel.isDynamic) {
|
|
139
140
|
// Check if route has getServerSideProps or similar indicators
|
|
@@ -147,7 +148,7 @@ function isSSROnlyRoute(routeModel, trace) {
|
|
|
147
148
|
/**
|
|
148
149
|
* Check if route is runtime-only (no static analysis possible)
|
|
149
150
|
*/
|
|
150
|
-
function isRuntimeOnlyRoute(routeModel,
|
|
151
|
+
function isRuntimeOnlyRoute(routeModel, _trace) {
|
|
151
152
|
// Routes with complex template literals or runtime variables
|
|
152
153
|
const originalPattern = routeModel.originalPattern || '';
|
|
153
154
|
|
|
@@ -162,7 +163,7 @@ function isRuntimeOnlyRoute(routeModel, trace) {
|
|
|
162
163
|
/**
|
|
163
164
|
* Check if route has observable signals
|
|
164
165
|
*/
|
|
165
|
-
function
|
|
166
|
+
function _hasObservableSignals(routeModel, trace) {
|
|
166
167
|
if (!trace) return false;
|
|
167
168
|
|
|
168
169
|
const sensors = trace.sensors || {};
|
|
@@ -336,7 +337,7 @@ export function correlateDynamicRouteNavigation(expectation, routeModel, trace)
|
|
|
336
337
|
|
|
337
338
|
// Get route evaluation from route intelligence
|
|
338
339
|
const correlation = correlateNavigationWithRoute(navigationTarget, [routeModel]);
|
|
339
|
-
const
|
|
340
|
+
const _routeEvaluation = correlation ? evaluateRouteNavigation(correlation, trace, trace.before?.url || '', trace.after?.url || '') : null;
|
|
340
341
|
|
|
341
342
|
// Get UI feedback score
|
|
342
343
|
const uiSignals = detectUIFeedbackSignals(trace);
|
|
@@ -120,6 +120,7 @@ export async function captureScreenshotWithRetry(page, filepath, options = {}) {
|
|
|
120
120
|
export async function captureDomSignatureSafe(page) {
|
|
121
121
|
try {
|
|
122
122
|
const domSignature = await captureDomSignature(page);
|
|
123
|
+
// @ts-expect-error - digest returns string
|
|
123
124
|
return { success: true, domSignature, failure: null };
|
|
124
125
|
} catch (error) {
|
|
125
126
|
const failure = new EvidenceCaptureFailure(
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { writeFileSync, readFileSync, existsSync } from 'fs';
|
|
10
10
|
import { resolve } from 'path';
|
|
11
|
-
import { EVIDENCE_CAPTURE_STAGE, EVIDENCE_CAPTURE_FAILURE_CODES } from './evidence-capture-service.js';
|
|
11
|
+
import { EVIDENCE_CAPTURE_STAGE, EVIDENCE_CAPTURE_FAILURE_CODES as _EVIDENCE_CAPTURE_FAILURE_CODES } from './evidence-capture-service.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Required evidence fields for CONFIRMED findings (stable)
|
|
@@ -157,6 +157,7 @@ export function readEvidenceIntentLedger(runDir) {
|
|
|
157
157
|
|
|
158
158
|
try {
|
|
159
159
|
const content = readFileSync(intentPath, 'utf-8');
|
|
160
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
160
161
|
return JSON.parse(content);
|
|
161
162
|
} catch (error) {
|
|
162
163
|
return null;
|
|
@@ -279,8 +279,8 @@ function buildJustification(expectation, trace, confidence) {
|
|
|
279
279
|
};
|
|
280
280
|
|
|
281
281
|
if (confidence) {
|
|
282
|
-
justification.confidenceReasons = confidence.reasons || [];
|
|
283
|
-
justification.confidenceScore = confidence.score || null;
|
|
282
|
+
justification.confidenceReasons = confidence.topReasons || confidence.reasons || [];
|
|
283
|
+
justification.confidenceScore = confidence.score01 || confidence.score || null; // Contract v1: score01 canonical
|
|
284
284
|
justification.confidenceLevel = confidence.level || null;
|
|
285
285
|
}
|
|
286
286
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - Injecting mode explanations into output
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { detectExecutionMode, applyConfidenceCeiling, CONFIDENCE_CEILINGS } from './execution-mode-detector.js';
|
|
12
|
+
import { detectExecutionMode, applyConfidenceCeiling, CONFIDENCE_CEILINGS as _CONFIDENCE_CEILINGS } from './execution-mode-detector.js';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Execution mode context object
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { existsSync, readdirSync, statSync } from 'fs';
|
|
20
|
-
import { join } from 'path';
|
|
20
|
+
import { join as _join } from 'path';
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Execution mode constants
|
|
@@ -38,10 +38,11 @@ export const CONFIDENCE_CEILINGS = {
|
|
|
38
38
|
/**
|
|
39
39
|
* Detect execution mode based on available inputs
|
|
40
40
|
* @param {string} srcPath - Path to source code directory
|
|
41
|
-
* @param {string}
|
|
41
|
+
* @param {string} _url - Target URL
|
|
42
|
+
* @ts-expect-error - JSDoc param documented but unused
|
|
42
43
|
* @returns {Object} - { mode, ceiling, explanation }
|
|
43
44
|
*/
|
|
44
|
-
export function detectExecutionMode(srcPath,
|
|
45
|
+
export function detectExecutionMode(srcPath, _url) {
|
|
45
46
|
// Check if source code is available and viable
|
|
46
47
|
const hasSourceCode = isSourceCodeAvailable(srcPath);
|
|
47
48
|
|
|
@@ -171,6 +172,7 @@ export function generateModeExplanation(mode, ceiling) {
|
|
|
171
172
|
return `Running in PROJECT_SCAN mode. Full analysis enabled with source code available.`;
|
|
172
173
|
|
|
173
174
|
case EXECUTION_MODES.WEB_SCAN_LIMITED:
|
|
175
|
+
// @ts-expect-error - Arithmetic on constant
|
|
174
176
|
return `Running in WEB_SCAN_LIMITED mode. No source code available; analysis limited to runtime observation. Confidence capped at ${Math.round(ceiling * 100)}%.`;
|
|
175
177
|
|
|
176
178
|
default:
|
|
@@ -1,68 +1,71 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Exit Codes Contract v1
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Exit codes with explicit precedence (highest wins):
|
|
5
|
+
* - 64: USAGE ERROR (invalid CLI usage)
|
|
6
|
+
* - 2: TOOL FAILURE (crash, invariant, runtime error)
|
|
7
|
+
* - 20: FAILURE (any CONFIRMED finding)
|
|
8
|
+
* - 10: WARNING (only SUSPECTED/INFORMATIONAL findings)
|
|
9
|
+
* - 0: OK (no CONFIRMED findings)
|
|
6
10
|
*/
|
|
7
11
|
|
|
8
|
-
import { FAILURE_SEVERITY } from './failure.types.js';
|
|
12
|
+
import { FAILURE_SEVERITY as _FAILURE_SEVERITY } from './failure.types.js';
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
|
-
* Exit Code
|
|
15
|
+
* Exit Code Constants (Contract v1)
|
|
12
16
|
*/
|
|
13
17
|
export const EXIT_CODE = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
INTERNAL_CORRUPTION: 70 // Internal corruption / invariant violation
|
|
18
|
+
OK: 0, // No CONFIRMED findings
|
|
19
|
+
WARNING: 10, // Only SUSPECTED/INFORMATIONAL
|
|
20
|
+
FAILURE: 20, // Any CONFIRMED finding
|
|
21
|
+
TOOL_FAILURE: 2, // Crash, invariant, runtime error
|
|
22
|
+
USAGE_ERROR: 64 // Invalid CLI usage
|
|
20
23
|
};
|
|
21
24
|
|
|
22
25
|
/**
|
|
23
|
-
* Determine exit code
|
|
26
|
+
* Determine exit code with precedence (highest wins)
|
|
27
|
+
* Precedence: 64 > 2 > 20 > 10 > 0
|
|
24
28
|
*
|
|
25
29
|
* @param {Object} ledgerSummary - Failure ledger summary
|
|
26
|
-
* @param {string}
|
|
30
|
+
* @param {string} _determinismVerdict - Determinism verdict
|
|
31
|
+
* @ts-expect-error - JSDoc param documented but unused
|
|
27
32
|
* @param {boolean} evidenceLawViolated - Whether Evidence Law was violated
|
|
28
33
|
* @param {boolean} policyInvalid - Whether policy was invalid
|
|
29
34
|
* @returns {number} Exit code
|
|
30
35
|
*/
|
|
31
|
-
export function determineExitCode(ledgerSummary,
|
|
32
|
-
//
|
|
36
|
+
export function determineExitCode(ledgerSummary, _determinismVerdict = null, evidenceLawViolated = false, policyInvalid = false) {
|
|
37
|
+
// Precedence 1: USAGE ERROR (64)
|
|
33
38
|
if (policyInvalid) {
|
|
34
|
-
return EXIT_CODE.
|
|
39
|
+
return EXIT_CODE.USAGE_ERROR;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
// Internal corruption
|
|
42
|
+
// Precedence 2: TOOL FAILURE (2) - Internal corruption or contract violations
|
|
38
43
|
const hasInternalCorruption = ledgerSummary.byCategory?.INTERNAL > 0 ||
|
|
39
44
|
ledgerSummary.byCategory?.CONTRACT > 0;
|
|
40
45
|
if (hasInternalCorruption) {
|
|
41
|
-
return EXIT_CODE.
|
|
46
|
+
return EXIT_CODE.TOOL_FAILURE;
|
|
42
47
|
}
|
|
43
48
|
|
|
44
|
-
// BLOCKING failures
|
|
49
|
+
// Precedence 2: TOOL FAILURE (2) - BLOCKING failures
|
|
45
50
|
if (ledgerSummary.bySeverity?.BLOCKING > 0) {
|
|
46
|
-
return EXIT_CODE.
|
|
51
|
+
return EXIT_CODE.TOOL_FAILURE;
|
|
47
52
|
}
|
|
48
53
|
|
|
49
|
-
//
|
|
54
|
+
// Precedence 2: TOOL FAILURE (2) - DEGRADED failures
|
|
50
55
|
if (ledgerSummary.bySeverity?.DEGRADED > 0) {
|
|
51
|
-
return EXIT_CODE.
|
|
56
|
+
return EXIT_CODE.TOOL_FAILURE;
|
|
52
57
|
}
|
|
53
58
|
|
|
54
|
-
//
|
|
55
|
-
if (ledgerSummary.bySeverity?.WARNING > 0) {
|
|
56
|
-
return EXIT_CODE.WARNINGS;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Evidence Law violation → 3 (BLOCKING)
|
|
59
|
+
// Precedence 2: TOOL FAILURE (2) - Evidence Law violation
|
|
60
60
|
if (evidenceLawViolated) {
|
|
61
|
-
return EXIT_CODE.
|
|
61
|
+
return EXIT_CODE.TOOL_FAILURE;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
//
|
|
65
|
-
|
|
64
|
+
// Note: Precedence 3-5 (FAILURE/WARNING/OK) handled by run-result.js
|
|
65
|
+
// This function handles system failures only
|
|
66
|
+
|
|
67
|
+
// No system failures → delegate to findings-based logic
|
|
68
|
+
return EXIT_CODE.OK;
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
/**
|
|
@@ -73,12 +76,11 @@ export function determineExitCode(ledgerSummary, determinismVerdict = null, evid
|
|
|
73
76
|
*/
|
|
74
77
|
export function getExitCodeMeaning(exitCode) {
|
|
75
78
|
const meanings = {
|
|
76
|
-
[EXIT_CODE.
|
|
77
|
-
[EXIT_CODE.
|
|
78
|
-
[EXIT_CODE.
|
|
79
|
-
[EXIT_CODE.
|
|
80
|
-
[EXIT_CODE.
|
|
81
|
-
[EXIT_CODE.INTERNAL_CORRUPTION]: 'Internal corruption / invariant violation'
|
|
79
|
+
[EXIT_CODE.OK]: 'OK (no CONFIRMED findings)',
|
|
80
|
+
[EXIT_CODE.WARNING]: 'WARNING (only SUSPECTED/INFORMATIONAL findings)',
|
|
81
|
+
[EXIT_CODE.FAILURE]: 'FAILURE (CONFIRMED finding detected)',
|
|
82
|
+
[EXIT_CODE.TOOL_FAILURE]: 'TOOL FAILURE (crash, invariant, or runtime error)',
|
|
83
|
+
[EXIT_CODE.USAGE_ERROR]: 'USAGE ERROR (invalid CLI usage)'
|
|
82
84
|
};
|
|
83
85
|
|
|
84
86
|
return meanings[exitCode] || `Unknown exit code: ${exitCode}`;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Formats failure summaries for CLI output.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { determineExitCode, getExitCodeMeaning } from './exit-codes.js';
|
|
7
|
+
import { determineExitCode, getExitCodeMeaning as _getExitCodeMeaning } from './exit-codes.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Format failure summary for CLI
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* No ad-hoc error creation allowed.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { FAILURE_CODE, FAILURE_CATEGORY, FAILURE_SEVERITY, EXECUTION_PHASE, validateFailure } from './failure.types.js';
|
|
8
|
+
import { FAILURE_CODE as _FAILURE_CODE, FAILURE_CATEGORY, FAILURE_SEVERITY, EXECUTION_PHASE, validateFailure } from './failure.types.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Create a failure object
|
|
@@ -22,7 +22,7 @@ import { FAILURE_CODE, FAILURE_CATEGORY, FAILURE_SEVERITY, EXECUTION_PHASE, vali
|
|
|
22
22
|
* @param {string} [params.stack] - Stack trace
|
|
23
23
|
* @param {string} [params.recoveryAction] - Recovery action
|
|
24
24
|
* @param {string} [params.impact] - Impact description
|
|
25
|
-
* @returns {
|
|
25
|
+
* @returns {Object} Validated failure object
|
|
26
26
|
*/
|
|
27
27
|
export function createFailure(params) {
|
|
28
28
|
const {
|
|
@@ -202,7 +202,7 @@ export function createInternalFailure(code, message, component, context = {}, st
|
|
|
202
202
|
* @param {string} phase - Execution phase
|
|
203
203
|
* @param {string} component - Component name
|
|
204
204
|
* @param {Object} context - Additional context
|
|
205
|
-
* @returns {
|
|
205
|
+
* @returns {Object} Failure object
|
|
206
206
|
*/
|
|
207
207
|
export function errorToFailure(error, code, category, phase, component, context = {}) {
|
|
208
208
|
return createFailure({
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { writeFileSync, mkdirSync } from 'fs';
|
|
9
|
-
import { resolve, dirname } from 'path';
|
|
9
|
+
import { resolve, dirname as _dirname } from 'path';
|
|
10
10
|
import { validateFailure } from './failure.types.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -25,7 +25,8 @@ export class FailureLedger {
|
|
|
25
25
|
/**
|
|
26
26
|
* Record a failure
|
|
27
27
|
*
|
|
28
|
-
* @param {
|
|
28
|
+
* @param {Object} failure - Failure object
|
|
29
|
+
* @ts-expect-error - Failure type not imported
|
|
29
30
|
*/
|
|
30
31
|
record(failure) {
|
|
31
32
|
validateFailure(failure);
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { evaluateAllCapabilityGates, buildGateContext } from '../capabilities/gates.js';
|
|
9
|
-
import { CAPABILITY_MATURITY } from '../capabilities/gates.js';
|
|
9
|
+
import { CAPABILITY_MATURITY as _CAPABILITY_MATURITY } from '../capabilities/gates.js';
|
|
10
10
|
import { verifyRun } from '../artifacts/verifier.js';
|
|
11
11
|
import { checkSecurityStatus } from '../security/security.enforcer.js';
|
|
12
12
|
import { readFileSync, existsSync } from 'fs';
|
|
13
13
|
import { resolve } from 'path';
|
|
14
|
-
import { isBaselineFrozen, enforceBaseline } from '../baseline/baseline.enforcer.js';
|
|
14
|
+
import { isBaselineFrozen as _isBaselineFrozen, enforceBaseline as _enforceBaseline } from '../baseline/baseline.enforcer.js';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* GA Blocker Codes
|
|
@@ -80,6 +80,7 @@ function loadDeterminismAcceptancePolicy(projectDir) {
|
|
|
80
80
|
|
|
81
81
|
try {
|
|
82
82
|
const content = readFileSync(policyPath, 'utf-8');
|
|
83
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
83
84
|
const policy = JSON.parse(content);
|
|
84
85
|
|
|
85
86
|
// Validate policy structure
|
|
@@ -36,6 +36,7 @@ export function loadGuardrailsPolicy(policyPath = null, projectDir = null) {
|
|
|
36
36
|
let policy;
|
|
37
37
|
try {
|
|
38
38
|
const policyContent = readFileSync(resolvedPath, 'utf-8');
|
|
39
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
39
40
|
policy = JSON.parse(policyContent);
|
|
40
41
|
} catch (error) {
|
|
41
42
|
throw new Error(`Failed to load guardrails policy: ${error.message}`);
|
|
@@ -52,8 +52,8 @@ function getGuardrailsPolicy(policyPath = null, projectDir = null) {
|
|
|
52
52
|
export function applyGuardrails(finding, context = {}, options = {}) {
|
|
53
53
|
const evidencePackage = context.evidencePackage || finding.evidencePackage || {};
|
|
54
54
|
const signals = context.signals || evidencePackage.signals || {};
|
|
55
|
-
const
|
|
56
|
-
const
|
|
55
|
+
const _confidenceReasons = context.confidenceReasons || finding.confidenceReasons || [];
|
|
56
|
+
const _promiseType = context.promiseType || finding.expectation?.type || finding.promise?.type || null;
|
|
57
57
|
|
|
58
58
|
// Load policy
|
|
59
59
|
const policy = getGuardrailsPolicy(options.policyPath, options.projectDir);
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 6A: Hard Budget Enforcement
|
|
3
|
+
*
|
|
4
|
+
* Enforces performance budgets as HARD limits with immediate termination.
|
|
5
|
+
* No warnings, no soft limits - budget exceeded = ANALYSIS_INCOMPLETE.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { SKIP_REASON } from '../../../cli/util/types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Check if budget is exceeded and enforce hard limit
|
|
12
|
+
*
|
|
13
|
+
* @param {Object} budget - Budget configuration
|
|
14
|
+
* @param {Object} metrics - Current metrics
|
|
15
|
+
* @param {Function} recordSkip - Function to record skip
|
|
16
|
+
* @param {Function} markIncomplete - Function to mark analysis incomplete
|
|
17
|
+
* @returns {{ exceeded: boolean, phase?: string, limit?: number, actual?: number }} Result
|
|
18
|
+
*/
|
|
19
|
+
export function enforceBudget(budget, metrics, recordSkip, markIncomplete) {
|
|
20
|
+
// Check observe budget
|
|
21
|
+
if (budget.observeMaxMs && metrics.observeMs >= budget.observeMaxMs) {
|
|
22
|
+
recordSkip(SKIP_REASON.TIMEOUT_OBSERVE, 1);
|
|
23
|
+
markIncomplete('observe', budget.observeMaxMs, metrics.observeMs);
|
|
24
|
+
return {
|
|
25
|
+
exceeded: true,
|
|
26
|
+
phase: 'observe',
|
|
27
|
+
limit: budget.observeMaxMs,
|
|
28
|
+
actual: metrics.observeMs,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Check detect budget
|
|
33
|
+
if (budget.detectMaxMs && metrics.detectMs >= budget.detectMaxMs) {
|
|
34
|
+
recordSkip(SKIP_REASON.TIMEOUT_DETECT, 1);
|
|
35
|
+
markIncomplete('detect', budget.detectMaxMs, metrics.detectMs);
|
|
36
|
+
return {
|
|
37
|
+
exceeded: true,
|
|
38
|
+
phase: 'detect',
|
|
39
|
+
limit: budget.detectMaxMs,
|
|
40
|
+
actual: metrics.detectMs,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Check total budget
|
|
45
|
+
if (budget.totalMaxMs && metrics.totalMs >= budget.totalMaxMs) {
|
|
46
|
+
recordSkip(SKIP_REASON.TIMEOUT_TOTAL, 1);
|
|
47
|
+
markIncomplete('total', budget.totalMaxMs, metrics.totalMs);
|
|
48
|
+
return {
|
|
49
|
+
exceeded: true,
|
|
50
|
+
phase: 'total',
|
|
51
|
+
limit: budget.totalMaxMs,
|
|
52
|
+
actual: metrics.totalMs,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Check expectations budget
|
|
57
|
+
if (budget.maxExpectations && metrics.expectationsAnalyzed >= budget.maxExpectations) {
|
|
58
|
+
const skippedCount = metrics.expectationsDiscovered - budget.maxExpectations;
|
|
59
|
+
if (skippedCount > 0) {
|
|
60
|
+
recordSkip(SKIP_REASON.BUDGET_EXCEEDED, skippedCount);
|
|
61
|
+
markIncomplete('expectations', budget.maxExpectations, metrics.expectationsAnalyzed);
|
|
62
|
+
return {
|
|
63
|
+
exceeded: true,
|
|
64
|
+
phase: 'expectations',
|
|
65
|
+
limit: budget.maxExpectations,
|
|
66
|
+
actual: metrics.expectationsAnalyzed,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return { exceeded: false };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Create budget guard that throws on budget exceeded
|
|
76
|
+
*
|
|
77
|
+
* @param {Object} budget - Budget configuration
|
|
78
|
+
* @param {Object} metrics - Metrics object (will be updated)
|
|
79
|
+
* @returns {Function} Guard function to check budget
|
|
80
|
+
*/
|
|
81
|
+
export function createBudgetGuard(budget, metrics) {
|
|
82
|
+
return (phase) => {
|
|
83
|
+
const check = enforceBudget(
|
|
84
|
+
budget,
|
|
85
|
+
metrics,
|
|
86
|
+
() => {}, // Skip recording handled elsewhere
|
|
87
|
+
() => {} // Marking handled elsewhere
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (check.exceeded) {
|
|
91
|
+
const error = new Error(
|
|
92
|
+
`Budget exceeded: ${phase} phase (limit: ${check.limit}ms, actual: ${check.actual}ms)`
|
|
93
|
+
);
|
|
94
|
+
error.name = 'BudgetExceededError';
|
|
95
|
+
// @ts-expect-error - Dynamic error properties
|
|
96
|
+
error.code = 'BUDGET_EXCEEDED';
|
|
97
|
+
// @ts-expect-error - Dynamic error properties
|
|
98
|
+
error.phase = phase;
|
|
99
|
+
// @ts-expect-error - Dynamic error properties
|
|
100
|
+
error.limit = check.limit;
|
|
101
|
+
// @ts-expect-error - Dynamic error properties
|
|
102
|
+
error.actual = check.actual;
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Wrap async operation with budget enforcement
|
|
110
|
+
*
|
|
111
|
+
* @param {Promise} operation - Async operation
|
|
112
|
+
* @param {Function} budgetGuard - Budget guard function
|
|
113
|
+
* @param {string} phase - Phase name
|
|
114
|
+
* @param {Function} onCheck - Called periodically to check budget
|
|
115
|
+
* @returns {Promise} Operation result or throws on budget exceeded
|
|
116
|
+
*/
|
|
117
|
+
export async function withBudgetEnforcement(operation, budgetGuard, phase, onCheck) {
|
|
118
|
+
const checkInterval = setInterval(() => {
|
|
119
|
+
try {
|
|
120
|
+
budgetGuard(phase);
|
|
121
|
+
if (onCheck) {
|
|
122
|
+
onCheck();
|
|
123
|
+
}
|
|
124
|
+
} catch (error) {
|
|
125
|
+
clearInterval(checkInterval);
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}, 1000); // Check every second
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
const result = await operation;
|
|
132
|
+
clearInterval(checkInterval);
|
|
133
|
+
return result;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
clearInterval(checkInterval);
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
}
|