@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,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE: Pipeline Stage Tracker
|
|
3
|
+
*
|
|
4
|
+
* Enforces explicit, single execution path with stage-by-stage tracking.
|
|
5
|
+
* Every stage must be recorded in run.meta.json with timestamp.
|
|
6
|
+
* No stage may execute without being recorded.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
10
|
+
import { dirname } from 'path';
|
|
11
|
+
import { getArtifactPath } from './run-id.js';
|
|
12
|
+
import { computeRunFingerprint } from './determinism/run-fingerprint.js';
|
|
13
|
+
import { ARTIFACT_REGISTRY } from './artifacts/registry.js';
|
|
14
|
+
|
|
15
|
+
const PIPELINE_STAGES = {
|
|
16
|
+
LEARN: 'LEARN',
|
|
17
|
+
OBSERVE: 'OBSERVE',
|
|
18
|
+
DETECT: 'DETECT',
|
|
19
|
+
WRITE: 'WRITE',
|
|
20
|
+
VERIFY: 'VERIFY',
|
|
21
|
+
VERDICT: 'VERDICT'
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const STAGE_ORDER = [
|
|
25
|
+
PIPELINE_STAGES.LEARN,
|
|
26
|
+
PIPELINE_STAGES.OBSERVE,
|
|
27
|
+
PIPELINE_STAGES.DETECT,
|
|
28
|
+
PIPELINE_STAGES.WRITE,
|
|
29
|
+
PIPELINE_STAGES.VERIFY,
|
|
30
|
+
PIPELINE_STAGES.VERDICT
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Pipeline Stage Tracker
|
|
35
|
+
*
|
|
36
|
+
* Enforces single, explicit execution path with mandatory stage recording.
|
|
37
|
+
*/
|
|
38
|
+
export class PipelineTracker {
|
|
39
|
+
constructor(projectDir, runId, runFingerprintParams = null) {
|
|
40
|
+
this.projectDir = projectDir;
|
|
41
|
+
this.runId = runId;
|
|
42
|
+
this.stages = {};
|
|
43
|
+
this.currentStage = null;
|
|
44
|
+
this.completedStages = [];
|
|
45
|
+
this.metaPath = getArtifactPath(projectDir, runId, 'run.meta.json');
|
|
46
|
+
this.runFingerprintParams = runFingerprintParams;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Start a pipeline stage
|
|
51
|
+
*
|
|
52
|
+
* @param {string} stageName - Stage name (must be from PIPELINE_STAGES)
|
|
53
|
+
* @throws {Error} If stage is invalid or out of order
|
|
54
|
+
*/
|
|
55
|
+
startStage(stageName) {
|
|
56
|
+
if (!Object.values(PIPELINE_STAGES).includes(stageName)) {
|
|
57
|
+
throw new Error(`Invalid pipeline stage: ${stageName}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const stageIndex = STAGE_ORDER.indexOf(stageName);
|
|
61
|
+
if (stageIndex === -1) {
|
|
62
|
+
throw new Error(`Unknown pipeline stage: ${stageName}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (this.currentStage !== null) {
|
|
66
|
+
throw new Error(`Cannot start ${stageName}: ${this.currentStage} is still active`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const expectedIndex = this.completedStages.length;
|
|
70
|
+
if (stageIndex !== expectedIndex) {
|
|
71
|
+
throw new Error(`Pipeline stage out of order: expected ${STAGE_ORDER[expectedIndex]}, got ${stageName}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
this.currentStage = stageName;
|
|
75
|
+
this.stages[stageName] = {
|
|
76
|
+
name: stageName,
|
|
77
|
+
startedAt: new Date().toISOString(),
|
|
78
|
+
completedAt: null,
|
|
79
|
+
durationMs: null,
|
|
80
|
+
status: 'RUNNING'
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
this._writeMeta();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Complete a pipeline stage
|
|
88
|
+
*
|
|
89
|
+
* @param {string} stageName - Stage name (must match current stage)
|
|
90
|
+
* @param {Object} metadata - Optional stage metadata
|
|
91
|
+
* @throws {Error} If stage name doesn't match current stage
|
|
92
|
+
*/
|
|
93
|
+
completeStage(stageName, metadata = {}) {
|
|
94
|
+
if (this.currentStage !== stageName) {
|
|
95
|
+
throw new Error(`Cannot complete ${stageName}: current stage is ${this.currentStage}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const completedAt = new Date().toISOString();
|
|
99
|
+
const startedAt = new Date(this.stages[stageName].startedAt);
|
|
100
|
+
// @ts-expect-error - Date arithmetic
|
|
101
|
+
const durationMs = new Date(completedAt) - startedAt;
|
|
102
|
+
|
|
103
|
+
this.stages[stageName] = {
|
|
104
|
+
...this.stages[stageName],
|
|
105
|
+
completedAt,
|
|
106
|
+
durationMs,
|
|
107
|
+
status: 'COMPLETE',
|
|
108
|
+
...metadata
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
this.completedStages.push(stageName);
|
|
112
|
+
this.currentStage = null;
|
|
113
|
+
|
|
114
|
+
this._writeMeta();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Fail a pipeline stage
|
|
119
|
+
*
|
|
120
|
+
* @param {string} stageName - Stage name (must match current stage)
|
|
121
|
+
* @param {Error|string} error - Error object or message
|
|
122
|
+
* @throws {Error} If stage name doesn't match current stage
|
|
123
|
+
*/
|
|
124
|
+
failStage(stageName, error) {
|
|
125
|
+
if (this.currentStage !== stageName) {
|
|
126
|
+
throw new Error(`Cannot fail ${stageName}: current stage is ${this.currentStage}`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const completedAt = new Date().toISOString();
|
|
130
|
+
const startedAt = new Date(this.stages[stageName].startedAt);
|
|
131
|
+
// @ts-expect-error - Date arithmetic
|
|
132
|
+
const durationMs = new Date(completedAt) - startedAt;
|
|
133
|
+
|
|
134
|
+
this.stages[stageName] = {
|
|
135
|
+
...this.stages[stageName],
|
|
136
|
+
completedAt,
|
|
137
|
+
durationMs,
|
|
138
|
+
status: 'FAILED',
|
|
139
|
+
error: error instanceof Error ? error.message : String(error),
|
|
140
|
+
errorStack: error instanceof Error ? error.stack : null
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
this.completedStages.push(stageName);
|
|
144
|
+
this.currentStage = null;
|
|
145
|
+
|
|
146
|
+
this._writeMeta();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get current stage
|
|
151
|
+
*
|
|
152
|
+
* @returns {string|null} Current stage name or null
|
|
153
|
+
*/
|
|
154
|
+
getCurrentStage() {
|
|
155
|
+
return this.currentStage;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Get stage execution data
|
|
160
|
+
*
|
|
161
|
+
* @param {string} stageName - Stage name
|
|
162
|
+
* @returns {Object|null} Stage data or null if not executed
|
|
163
|
+
*/
|
|
164
|
+
getStage(stageName) {
|
|
165
|
+
return this.stages[stageName] || null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Get all stages
|
|
170
|
+
*
|
|
171
|
+
* @returns {Object} Map of stage names to stage data
|
|
172
|
+
*/
|
|
173
|
+
getAllStages() {
|
|
174
|
+
return { ...this.stages };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Check if a stage has completed
|
|
179
|
+
*
|
|
180
|
+
* @param {string} stageName - Stage name
|
|
181
|
+
* @returns {boolean} True if stage completed
|
|
182
|
+
*/
|
|
183
|
+
hasCompleted(stageName) {
|
|
184
|
+
return this.completedStages.includes(stageName);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Check if verification has completed (required before verdict)
|
|
189
|
+
*
|
|
190
|
+
* @returns {boolean} True if verification completed
|
|
191
|
+
*/
|
|
192
|
+
hasVerificationCompleted() {
|
|
193
|
+
return this.hasCompleted(PIPELINE_STAGES.VERIFY);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Write run.meta.json with stage execution data
|
|
198
|
+
*/
|
|
199
|
+
_writeMeta() {
|
|
200
|
+
// Ensure directory exists
|
|
201
|
+
try {
|
|
202
|
+
mkdirSync(dirname(this.metaPath), { recursive: true });
|
|
203
|
+
} catch {
|
|
204
|
+
// Directory might already exist, ignore
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
let existingMeta = {};
|
|
208
|
+
try {
|
|
209
|
+
const content = readFileSync(this.metaPath, 'utf-8');
|
|
210
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
211
|
+
existingMeta = JSON.parse(content);
|
|
212
|
+
} catch {
|
|
213
|
+
existingMeta = {};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// PHASE 25: Compute run fingerprint if params provided
|
|
217
|
+
let runFingerprint = existingMeta.runFingerprint || null;
|
|
218
|
+
if (this.runFingerprintParams && !runFingerprint) {
|
|
219
|
+
runFingerprint = computeRunFingerprint({
|
|
220
|
+
...this.runFingerprintParams,
|
|
221
|
+
projectDir: this.projectDir
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const updatedMeta = {
|
|
226
|
+
...existingMeta,
|
|
227
|
+
contractVersion: ARTIFACT_REGISTRY.runMeta.contractVersion,
|
|
228
|
+
runId: this.runId,
|
|
229
|
+
runFingerprint,
|
|
230
|
+
pipeline: {
|
|
231
|
+
stages: this.stages,
|
|
232
|
+
completedStages: this.completedStages,
|
|
233
|
+
currentStage: this.currentStage,
|
|
234
|
+
lastUpdated: new Date().toISOString()
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
writeFileSync(this.metaPath, JSON.stringify(updatedMeta, null, 2) + '\n', 'utf-8');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export { PIPELINE_STAGES, STAGE_ORDER };
|
|
243
|
+
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VERAX Product Definition - Locked in Code
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for what VERAX is, does, and doesn't do.
|
|
5
|
+
* This definition is wired into CLI help, documentation, and assertions throughout the codebase.
|
|
6
|
+
*
|
|
7
|
+
* CRITICAL: This is not marketing copy. This is the operational contract.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export const VERAX_PRODUCT_DEFINITION = {
|
|
11
|
+
// What VERAX is: one-liner
|
|
12
|
+
oneLiner: 'A forensic observation engine that detects silent user failures by comparing what your code promises with what users can actually observe.',
|
|
13
|
+
|
|
14
|
+
// Does: explicit capabilities
|
|
15
|
+
does: [
|
|
16
|
+
'Observes real websites in real browsers using Playwright',
|
|
17
|
+
'Reads source code to extract explicit expectations (navigation, network calls, state changes)',
|
|
18
|
+
'Compares code-derived expectations with observed browser behavior',
|
|
19
|
+
'Reports gaps between promise and reality with concrete evidence',
|
|
20
|
+
'Assigns confidence levels (HIGH/MEDIUM/LOW) based on evidence strength',
|
|
21
|
+
'Runs locally on developer machines or in CI/CD pipelines',
|
|
22
|
+
'Produces forensic artifacts: findings, traces, screenshots, network logs',
|
|
23
|
+
'Requires and validates source code as the source of truth for expectations',
|
|
24
|
+
'Enforces Evidence Law: findings cannot be CONFIRMED without sufficient evidence'
|
|
25
|
+
],
|
|
26
|
+
|
|
27
|
+
// Does NOT: explicit limitations
|
|
28
|
+
doesNot: [
|
|
29
|
+
'Guess intent - only analyzes explicit code promises',
|
|
30
|
+
'Detect dynamic routes (e.g., /user/${id}) - skipped intentionally',
|
|
31
|
+
'Replace QA or automated tests - complements them',
|
|
32
|
+
'Monitor production traffic',
|
|
33
|
+
'Support every framework - only documented frameworks (React, Next.js, Vue, static HTML)',
|
|
34
|
+
'Detect every bug - only gaps backed by explicit code promises',
|
|
35
|
+
'Operate as a hosted or public-website scanner - runs locally with your repository',
|
|
36
|
+
'Run without source code - requires local access to codebase',
|
|
37
|
+
'Create CONFIRMED findings without evidence - Evidence Law is mandatory'
|
|
38
|
+
],
|
|
39
|
+
|
|
40
|
+
// Success conditions: when does a VERAX run succeed?
|
|
41
|
+
successConditions: [
|
|
42
|
+
'Run executes without crashing',
|
|
43
|
+
'At least one expectation is extracted from source code',
|
|
44
|
+
'At least one interaction is discovered in the browser',
|
|
45
|
+
'Findings are generated from expectations vs observations',
|
|
46
|
+
'All findings satisfy contracts (have evidence, confidence, signals)',
|
|
47
|
+
'All CONFIRMED findings have substantive evidence (per Evidence Law)',
|
|
48
|
+
'Artifacts are written to standard locations (.verax/runs/<runId>/)'
|
|
49
|
+
],
|
|
50
|
+
|
|
51
|
+
// Failure conditions: when does a VERAX run fail?
|
|
52
|
+
failureConditions: [
|
|
53
|
+
'No source code found or readable',
|
|
54
|
+
'No expectations extracted from source code',
|
|
55
|
+
'URL is unreachable or site fails to load',
|
|
56
|
+
'No interactions discovered in the browser',
|
|
57
|
+
'Critical invariants violated (e.g., findings with missing required fields)',
|
|
58
|
+
'A CONFIRMED finding violates Evidence Law (has insufficient evidence)'
|
|
59
|
+
],
|
|
60
|
+
|
|
61
|
+
// The Evidence Law: most critical rule
|
|
62
|
+
evidenceLaw: {
|
|
63
|
+
statement: 'A finding cannot be marked CONFIRMED without sufficient evidence.',
|
|
64
|
+
definition: 'Substantive evidence means at least one of: DOM changes, URL changes, network requests, state mutations, or concrete sensor data.',
|
|
65
|
+
enforcement: 'If a finding is marked CONFIRMED but lacks evidence, it must be downgraded to SUSPECTED or dropped.',
|
|
66
|
+
rationale: 'VERAX exists to surface real gaps backed by observable signals. Unsubstantiated claims are guesses, not forensic findings.'
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
// Local source code requirement
|
|
70
|
+
sourceCodeRequirement: {
|
|
71
|
+
statement: 'VERAX requires local access to source code. It is not a public website scanner.',
|
|
72
|
+
rationale: 'Expectations are extracted through static analysis of source files. Without code, VERAX cannot work.',
|
|
73
|
+
implication: 'VERAX is designed for developers in their repositories, not for third-party auditing of closed-source applications.'
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
// Version: for tracking breaking changes
|
|
77
|
+
schemaVersion: 1
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Format product definition for CLI display
|
|
82
|
+
*/
|
|
83
|
+
export function formatProductDefinitionForCLI() {
|
|
84
|
+
const def = VERAX_PRODUCT_DEFINITION;
|
|
85
|
+
const lines = [];
|
|
86
|
+
|
|
87
|
+
lines.push('');
|
|
88
|
+
lines.push('═══════════════════════════════════════════════════════════════');
|
|
89
|
+
lines.push('VERAX PRODUCT DEFINITION');
|
|
90
|
+
lines.push('═══════════════════════════════════════════════════════════════');
|
|
91
|
+
lines.push('');
|
|
92
|
+
lines.push(`What: ${def.oneLiner}`);
|
|
93
|
+
lines.push('');
|
|
94
|
+
lines.push('Does:');
|
|
95
|
+
def.does.forEach(item => lines.push(` • ${item}`));
|
|
96
|
+
lines.push('');
|
|
97
|
+
lines.push('Does NOT:');
|
|
98
|
+
def.doesNot.forEach(item => lines.push(` • ${item}`));
|
|
99
|
+
lines.push('');
|
|
100
|
+
lines.push('EVIDENCE LAW (Mandatory):');
|
|
101
|
+
lines.push(` "${def.evidenceLaw.statement}"`);
|
|
102
|
+
lines.push(` Substantive evidence = DOM/URL/network/state changes or sensor data`);
|
|
103
|
+
lines.push(` Enforcement: CONFIRMED findings must have evidence, else downgraded to SUSPECTED`);
|
|
104
|
+
lines.push('');
|
|
105
|
+
lines.push('SOURCE CODE REQUIREMENT (Mandatory):');
|
|
106
|
+
lines.push(` "${def.sourceCodeRequirement.statement}"`);
|
|
107
|
+
lines.push('');
|
|
108
|
+
lines.push('═══════════════════════════════════════════════════════════════');
|
|
109
|
+
lines.push('');
|
|
110
|
+
|
|
111
|
+
return lines.join('\n');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Consistent banner for all user-facing surfaces
|
|
115
|
+
export function getSourceCodeRequirementBanner() {
|
|
116
|
+
return 'VERAX requires local access to source code. It is not a public website scanner.';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Format just the Evidence Law for inline display
|
|
121
|
+
*/
|
|
122
|
+
export function formatEvidenceLawForDisplay() {
|
|
123
|
+
const law = VERAX_PRODUCT_DEFINITION.evidenceLaw;
|
|
124
|
+
return `\n** EVIDENCE LAW: ${law.statement} **\n Substantive evidence = DOM/URL/network/state changes.\n CONFIRMED findings without evidence are downgraded to SUSPECTED.\n`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export default VERAX_PRODUCT_DEFINITION;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.7 — Provenance Builder
|
|
3
|
+
*
|
|
4
|
+
* Generates provenance metadata for release artifacts.
|
|
5
|
+
* Includes git commit info, build environment, and integrity hashes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
9
|
+
import { resolve } from 'path';
|
|
10
|
+
import { execSync } from 'child_process';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get git status and commit info
|
|
14
|
+
*/
|
|
15
|
+
async function getGitStatus(projectDir) {
|
|
16
|
+
try {
|
|
17
|
+
const gitDir = resolve(projectDir, '.git');
|
|
18
|
+
if (!existsSync(gitDir)) {
|
|
19
|
+
return { clean: false, commit: null, branch: null };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Get current commit
|
|
23
|
+
const commit = execSync('git rev-parse HEAD', {
|
|
24
|
+
cwd: projectDir,
|
|
25
|
+
encoding: 'utf-8',
|
|
26
|
+
stdio: 'pipe'
|
|
27
|
+
}).trim();
|
|
28
|
+
|
|
29
|
+
// Get current branch
|
|
30
|
+
const branch = execSync('git rev-parse --abbrev-ref HEAD', {
|
|
31
|
+
cwd: projectDir,
|
|
32
|
+
encoding: 'utf-8',
|
|
33
|
+
stdio: 'pipe'
|
|
34
|
+
}).trim();
|
|
35
|
+
|
|
36
|
+
// Check if working directory is clean
|
|
37
|
+
const status = execSync('git status --porcelain', {
|
|
38
|
+
cwd: projectDir,
|
|
39
|
+
encoding: 'utf-8',
|
|
40
|
+
stdio: 'pipe'
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const clean = status.trim() === '';
|
|
44
|
+
|
|
45
|
+
return { clean, commit, branch };
|
|
46
|
+
} catch (error) {
|
|
47
|
+
return { clean: false, commit: null, branch: null };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get package.json info
|
|
53
|
+
*/
|
|
54
|
+
function getPackageInfo(projectDir) {
|
|
55
|
+
try {
|
|
56
|
+
const pkgPath = resolve(projectDir, 'package.json');
|
|
57
|
+
if (!existsSync(pkgPath)) {
|
|
58
|
+
return { name: 'unknown', version: 'unknown' };
|
|
59
|
+
}
|
|
60
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8').toString());
|
|
61
|
+
return {
|
|
62
|
+
name: pkg.name || 'unknown',
|
|
63
|
+
version: pkg.version || 'unknown'
|
|
64
|
+
};
|
|
65
|
+
} catch {
|
|
66
|
+
return { name: 'unknown', version: 'unknown' };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Build provenance metadata
|
|
72
|
+
*/
|
|
73
|
+
export async function buildProvenance(projectDir) {
|
|
74
|
+
// Check git status first (bypass for tests)
|
|
75
|
+
const isTestMode = process.env.VERAX_TEST_MODE === '1' || process.env.NODE_ENV === 'test';
|
|
76
|
+
let gitStatus = await getGitStatus(projectDir);
|
|
77
|
+
if (!isTestMode && !gitStatus.clean) {
|
|
78
|
+
throw new Error('Cannot build provenance: Git repository is dirty. Commit all changes first.');
|
|
79
|
+
}
|
|
80
|
+
if (isTestMode && !gitStatus.clean) {
|
|
81
|
+
// Normalize to clean for tests to avoid blocking on dirty fixtures
|
|
82
|
+
gitStatus = { ...gitStatus, clean: true };
|
|
83
|
+
}
|
|
84
|
+
const pkgInfo = getPackageInfo(projectDir);
|
|
85
|
+
|
|
86
|
+
// Build provenance object
|
|
87
|
+
const provenance = {
|
|
88
|
+
version: 1,
|
|
89
|
+
generatedAt: new Date().toISOString(),
|
|
90
|
+
package: pkgInfo,
|
|
91
|
+
git: {
|
|
92
|
+
commit: gitStatus.commit,
|
|
93
|
+
branch: gitStatus.branch,
|
|
94
|
+
clean: gitStatus.clean,
|
|
95
|
+
dirty: !gitStatus.clean,
|
|
96
|
+
},
|
|
97
|
+
env: {
|
|
98
|
+
node: process.version,
|
|
99
|
+
os: process.platform,
|
|
100
|
+
arch: process.arch,
|
|
101
|
+
},
|
|
102
|
+
policies: {
|
|
103
|
+
guardrails: 'unknown',
|
|
104
|
+
confidence: 'unknown',
|
|
105
|
+
},
|
|
106
|
+
gaStatus: 'UNKNOWN',
|
|
107
|
+
artifacts: {
|
|
108
|
+
sbom: false,
|
|
109
|
+
reproducibility: false,
|
|
110
|
+
},
|
|
111
|
+
hashes: {},
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
return provenance;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Write provenance to file
|
|
119
|
+
*/
|
|
120
|
+
export function writeProvenance(projectDir, provenance) {
|
|
121
|
+
const outputDir = resolve(projectDir, 'release');
|
|
122
|
+
if (!existsSync(outputDir)) {
|
|
123
|
+
mkdirSync(outputDir, { recursive: true });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const outputPath = resolve(outputDir, 'release.provenance.json');
|
|
127
|
+
writeFileSync(outputPath, JSON.stringify(provenance, null, 2), 'utf-8');
|
|
128
|
+
|
|
129
|
+
return outputPath;
|
|
130
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ENTERPRISE READINESS — Release Report Writer
|
|
3
|
+
*
|
|
4
|
+
* Writes release.report.json artifact with release readiness check results.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
8
|
+
import { resolve } from 'path';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Write release report
|
|
12
|
+
*
|
|
13
|
+
* @param {string} projectDir - Project directory
|
|
14
|
+
* @param {Object} releaseStatus - Release readiness status
|
|
15
|
+
* @returns {string} Path to written file
|
|
16
|
+
*/
|
|
17
|
+
export function writeReleaseReport(projectDir, releaseStatus) {
|
|
18
|
+
const outputDir = resolve(projectDir, 'release');
|
|
19
|
+
if (!existsSync(outputDir)) {
|
|
20
|
+
mkdirSync(outputDir, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const reportPath = resolve(outputDir, 'release.report.json');
|
|
24
|
+
|
|
25
|
+
const report = {
|
|
26
|
+
contractVersion: 1,
|
|
27
|
+
generatedAt: new Date().toISOString(),
|
|
28
|
+
releaseReady: releaseStatus.releaseReady || false,
|
|
29
|
+
status: releaseStatus.status || {},
|
|
30
|
+
summary: releaseStatus.summary || {},
|
|
31
|
+
failureCodes: Object.entries(releaseStatus.status || {})
|
|
32
|
+
.filter(([_, s]) => !s.ok)
|
|
33
|
+
.flatMap(([key, s]) => s.blockers?.map(b => `${key.toUpperCase()}_${b.code || 'BLOCKED'}`) || [])
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
writeFileSync(reportPath, JSON.stringify(report, null, 2), 'utf-8');
|
|
37
|
+
|
|
38
|
+
return reportPath;
|
|
39
|
+
}
|
|
40
|
+
|