@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.
Files changed (213) hide show
  1. package/README.md +10 -6
  2. package/bin/verax.js +11 -11
  3. package/package.json +29 -8
  4. package/src/cli/commands/baseline.js +103 -0
  5. package/src/cli/commands/default.js +51 -6
  6. package/src/cli/commands/doctor.js +29 -0
  7. package/src/cli/commands/ga.js +246 -0
  8. package/src/cli/commands/gates.js +95 -0
  9. package/src/cli/commands/inspect.js +4 -2
  10. package/src/cli/commands/release-check.js +215 -0
  11. package/src/cli/commands/run.js +45 -6
  12. package/src/cli/commands/security-check.js +212 -0
  13. package/src/cli/commands/truth.js +113 -0
  14. package/src/cli/entry.js +30 -20
  15. package/src/cli/util/angular-component-extractor.js +179 -0
  16. package/src/cli/util/angular-navigation-detector.js +141 -0
  17. package/src/cli/util/angular-network-detector.js +161 -0
  18. package/src/cli/util/angular-state-detector.js +162 -0
  19. package/src/cli/util/ast-interactive-detector.js +544 -0
  20. package/src/cli/util/ast-network-detector.js +603 -0
  21. package/src/cli/util/ast-promise-extractor.js +581 -0
  22. package/src/cli/util/ast-usestate-detector.js +602 -0
  23. package/src/cli/util/atomic-write.js +12 -1
  24. package/src/cli/util/bootstrap-guard.js +86 -0
  25. package/src/cli/util/console-reporter.js +72 -0
  26. package/src/cli/util/detection-engine.js +105 -41
  27. package/src/cli/util/determinism-runner.js +124 -0
  28. package/src/cli/util/determinism-writer.js +129 -0
  29. package/src/cli/util/digest-engine.js +359 -0
  30. package/src/cli/util/dom-diff.js +226 -0
  31. package/src/cli/util/evidence-engine.js +287 -0
  32. package/src/cli/util/expectation-extractor.js +151 -5
  33. package/src/cli/util/findings-writer.js +3 -0
  34. package/src/cli/util/framework-detector.js +572 -0
  35. package/src/cli/util/idgen.js +1 -1
  36. package/src/cli/util/interaction-planner.js +529 -0
  37. package/src/cli/util/learn-writer.js +2 -0
  38. package/src/cli/util/ledger-writer.js +110 -0
  39. package/src/cli/util/monorepo-resolver.js +162 -0
  40. package/src/cli/util/observation-engine.js +127 -278
  41. package/src/cli/util/observe-writer.js +2 -0
  42. package/src/cli/util/project-discovery.js +284 -0
  43. package/src/cli/util/project-writer.js +2 -0
  44. package/src/cli/util/run-id.js +23 -27
  45. package/src/cli/util/run-resolver.js +64 -0
  46. package/src/cli/util/run-result.js +778 -0
  47. package/src/cli/util/selector-resolver.js +235 -0
  48. package/src/cli/util/source-requirement.js +55 -0
  49. package/src/cli/util/summary-writer.js +2 -0
  50. package/src/cli/util/svelte-navigation-detector.js +163 -0
  51. package/src/cli/util/svelte-network-detector.js +80 -0
  52. package/src/cli/util/svelte-sfc-extractor.js +146 -0
  53. package/src/cli/util/svelte-state-detector.js +242 -0
  54. package/src/cli/util/trust-activation-integration.js +496 -0
  55. package/src/cli/util/trust-activation-wrapper.js +85 -0
  56. package/src/cli/util/trust-integration-hooks.js +164 -0
  57. package/src/cli/util/types.js +153 -0
  58. package/src/cli/util/url-validation.js +40 -0
  59. package/src/cli/util/vue-navigation-detector.js +178 -0
  60. package/src/cli/util/vue-sfc-extractor.js +161 -0
  61. package/src/cli/util/vue-state-detector.js +215 -0
  62. package/src/types/fs-augment.d.ts +23 -0
  63. package/src/types/global.d.ts +137 -0
  64. package/src/types/internal-types.d.ts +35 -0
  65. package/src/verax/cli/init.js +4 -18
  66. package/src/verax/core/action-classifier.js +4 -3
  67. package/src/verax/core/artifacts/registry.js +139 -0
  68. package/src/verax/core/artifacts/verifier.js +990 -0
  69. package/src/verax/core/baseline/baseline.enforcer.js +137 -0
  70. package/src/verax/core/baseline/baseline.snapshot.js +233 -0
  71. package/src/verax/core/capabilities/gates.js +505 -0
  72. package/src/verax/core/capabilities/registry.js +475 -0
  73. package/src/verax/core/confidence/confidence-compute.js +144 -0
  74. package/src/verax/core/confidence/confidence-invariants.js +234 -0
  75. package/src/verax/core/confidence/confidence-report-writer.js +112 -0
  76. package/src/verax/core/confidence/confidence-weights.js +44 -0
  77. package/src/verax/core/confidence/confidence.defaults.js +65 -0
  78. package/src/verax/core/confidence/confidence.loader.js +80 -0
  79. package/src/verax/core/confidence/confidence.schema.js +94 -0
  80. package/src/verax/core/confidence-engine-refactor.js +489 -0
  81. package/src/verax/core/confidence-engine.js +625 -0
  82. package/src/verax/core/contracts/index.js +29 -0
  83. package/src/verax/core/contracts/types.js +186 -0
  84. package/src/verax/core/contracts/validators.js +456 -0
  85. package/src/verax/core/decisions/decision.trace.js +278 -0
  86. package/src/verax/core/determinism/contract-writer.js +89 -0
  87. package/src/verax/core/determinism/contract.js +139 -0
  88. package/src/verax/core/determinism/diff.js +405 -0
  89. package/src/verax/core/determinism/engine.js +222 -0
  90. package/src/verax/core/determinism/finding-identity.js +149 -0
  91. package/src/verax/core/determinism/normalize.js +466 -0
  92. package/src/verax/core/determinism/report-writer.js +93 -0
  93. package/src/verax/core/determinism/run-fingerprint.js +123 -0
  94. package/src/verax/core/dynamic-route-intelligence.js +529 -0
  95. package/src/verax/core/evidence/evidence-capture-service.js +308 -0
  96. package/src/verax/core/evidence/evidence-intent-ledger.js +166 -0
  97. package/src/verax/core/evidence-builder.js +487 -0
  98. package/src/verax/core/execution-mode-context.js +77 -0
  99. package/src/verax/core/execution-mode-detector.js +192 -0
  100. package/src/verax/core/failures/exit-codes.js +88 -0
  101. package/src/verax/core/failures/failure-summary.js +76 -0
  102. package/src/verax/core/failures/failure.factory.js +225 -0
  103. package/src/verax/core/failures/failure.ledger.js +133 -0
  104. package/src/verax/core/failures/failure.types.js +196 -0
  105. package/src/verax/core/failures/index.js +10 -0
  106. package/src/verax/core/ga/ga-report-writer.js +43 -0
  107. package/src/verax/core/ga/ga.artifact.js +49 -0
  108. package/src/verax/core/ga/ga.contract.js +435 -0
  109. package/src/verax/core/ga/ga.enforcer.js +87 -0
  110. package/src/verax/core/guardrails/guardrails-report-writer.js +109 -0
  111. package/src/verax/core/guardrails/policy.defaults.js +210 -0
  112. package/src/verax/core/guardrails/policy.loader.js +84 -0
  113. package/src/verax/core/guardrails/policy.schema.js +110 -0
  114. package/src/verax/core/guardrails/truth-reconciliation.js +136 -0
  115. package/src/verax/core/guardrails-engine.js +505 -0
  116. package/src/verax/core/incremental-store.js +1 -0
  117. package/src/verax/core/integrity/budget.js +138 -0
  118. package/src/verax/core/integrity/determinism.js +342 -0
  119. package/src/verax/core/integrity/integrity.js +208 -0
  120. package/src/verax/core/integrity/poisoning.js +108 -0
  121. package/src/verax/core/integrity/transaction.js +140 -0
  122. package/src/verax/core/observe/run-timeline.js +318 -0
  123. package/src/verax/core/perf/perf.contract.js +186 -0
  124. package/src/verax/core/perf/perf.display.js +65 -0
  125. package/src/verax/core/perf/perf.enforcer.js +91 -0
  126. package/src/verax/core/perf/perf.monitor.js +209 -0
  127. package/src/verax/core/perf/perf.report.js +200 -0
  128. package/src/verax/core/pipeline-tracker.js +243 -0
  129. package/src/verax/core/product-definition.js +127 -0
  130. package/src/verax/core/release/provenance.builder.js +130 -0
  131. package/src/verax/core/release/release-report-writer.js +40 -0
  132. package/src/verax/core/release/release.enforcer.js +164 -0
  133. package/src/verax/core/release/reproducibility.check.js +222 -0
  134. package/src/verax/core/release/sbom.builder.js +292 -0
  135. package/src/verax/core/replay-validator.js +2 -0
  136. package/src/verax/core/replay.js +4 -0
  137. package/src/verax/core/report/cross-index.js +195 -0
  138. package/src/verax/core/report/human-summary.js +362 -0
  139. package/src/verax/core/route-intelligence.js +420 -0
  140. package/src/verax/core/run-id.js +6 -3
  141. package/src/verax/core/run-manifest.js +4 -3
  142. package/src/verax/core/security/secrets.scan.js +329 -0
  143. package/src/verax/core/security/security-report.js +50 -0
  144. package/src/verax/core/security/security.enforcer.js +128 -0
  145. package/src/verax/core/security/supplychain.defaults.json +38 -0
  146. package/src/verax/core/security/supplychain.policy.js +334 -0
  147. package/src/verax/core/security/vuln.scan.js +265 -0
  148. package/src/verax/core/truth/truth.certificate.js +252 -0
  149. package/src/verax/core/ui-feedback-intelligence.js +481 -0
  150. package/src/verax/detect/conditional-ui-silent-failure.js +84 -0
  151. package/src/verax/detect/confidence-engine.js +62 -34
  152. package/src/verax/detect/confidence-helper.js +34 -0
  153. package/src/verax/detect/dynamic-route-findings.js +338 -0
  154. package/src/verax/detect/expectation-chain-detector.js +417 -0
  155. package/src/verax/detect/expectation-model.js +2 -2
  156. package/src/verax/detect/failure-cause-inference.js +293 -0
  157. package/src/verax/detect/findings-writer.js +131 -35
  158. package/src/verax/detect/flow-detector.js +2 -2
  159. package/src/verax/detect/form-silent-failure.js +98 -0
  160. package/src/verax/detect/index.js +46 -5
  161. package/src/verax/detect/invariants-enforcer.js +147 -0
  162. package/src/verax/detect/journey-stall-detector.js +558 -0
  163. package/src/verax/detect/navigation-silent-failure.js +82 -0
  164. package/src/verax/detect/problem-aggregator.js +361 -0
  165. package/src/verax/detect/route-findings.js +219 -0
  166. package/src/verax/detect/summary-writer.js +477 -0
  167. package/src/verax/detect/test-failure-cause-inference.js +314 -0
  168. package/src/verax/detect/ui-feedback-findings.js +207 -0
  169. package/src/verax/detect/view-switch-correlator.js +242 -0
  170. package/src/verax/flow/flow-engine.js +2 -1
  171. package/src/verax/flow/flow-spec.js +0 -6
  172. package/src/verax/index.js +4 -0
  173. package/src/verax/intel/ts-program.js +1 -0
  174. package/src/verax/intel/vue-navigation-extractor.js +3 -0
  175. package/src/verax/learn/action-contract-extractor.js +3 -0
  176. package/src/verax/learn/ast-contract-extractor.js +1 -1
  177. package/src/verax/learn/flow-extractor.js +1 -0
  178. package/src/verax/learn/project-detector.js +5 -0
  179. package/src/verax/learn/react-router-extractor.js +2 -0
  180. package/src/verax/learn/source-instrumenter.js +1 -0
  181. package/src/verax/learn/state-extractor.js +2 -1
  182. package/src/verax/learn/static-extractor.js +1 -0
  183. package/src/verax/observe/coverage-gaps.js +132 -0
  184. package/src/verax/observe/expectation-handler.js +126 -0
  185. package/src/verax/observe/incremental-skip.js +46 -0
  186. package/src/verax/observe/index.js +51 -155
  187. package/src/verax/observe/interaction-executor.js +192 -0
  188. package/src/verax/observe/interaction-runner.js +782 -513
  189. package/src/verax/observe/network-firewall.js +86 -0
  190. package/src/verax/observe/observation-builder.js +169 -0
  191. package/src/verax/observe/observe-context.js +205 -0
  192. package/src/verax/observe/observe-helpers.js +192 -0
  193. package/src/verax/observe/observe-runner.js +230 -0
  194. package/src/verax/observe/observers/budget-observer.js +185 -0
  195. package/src/verax/observe/observers/console-observer.js +102 -0
  196. package/src/verax/observe/observers/coverage-observer.js +107 -0
  197. package/src/verax/observe/observers/interaction-observer.js +471 -0
  198. package/src/verax/observe/observers/navigation-observer.js +132 -0
  199. package/src/verax/observe/observers/network-observer.js +87 -0
  200. package/src/verax/observe/observers/safety-observer.js +82 -0
  201. package/src/verax/observe/observers/ui-feedback-observer.js +99 -0
  202. package/src/verax/observe/page-traversal.js +138 -0
  203. package/src/verax/observe/snapshot-ops.js +94 -0
  204. package/src/verax/observe/ui-feedback-detector.js +742 -0
  205. package/src/verax/scan-summary-writer.js +2 -0
  206. package/src/verax/shared/artifact-manager.js +25 -5
  207. package/src/verax/shared/caching.js +1 -0
  208. package/src/verax/shared/css-spinner-rules.js +204 -0
  209. package/src/verax/shared/expectation-tracker.js +1 -0
  210. package/src/verax/shared/view-switch-rules.js +208 -0
  211. package/src/verax/shared/zip-artifacts.js +6 -0
  212. package/src/verax/shared/config-loader.js +0 -169
  213. /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
+