codeproof 1.0.3 → 1.0.4

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/commands/run.js CHANGED
@@ -118,7 +118,7 @@ export async function runCli({ args = [], cwd }) {
118
118
  });
119
119
 
120
120
  if (features.reporting) {
121
- withFailOpenReporting(() => {
121
+ await withFailOpenReporting(async () => {
122
122
  const timestamp = new Date().toISOString();
123
123
  const reportId = randomUUID();
124
124
  const projectId = config.projectId || "";
@@ -138,62 +138,88 @@ export async function runCli({ args = [], cwd }) {
138
138
  aiReviewed,
139
139
  timestamp
140
140
  });
141
- // Reporting is fail-open: never block commits if logging fails.
141
+ // Report is saved to file and sent to server regardless of findings
142
+ logInfo("Saving report to file...");
142
143
  writeReport({ projectRoot: gitRoot, report });
144
+ logSuccess("Report saved locally.");
143
145
 
144
146
  const integration = config?.integration || {};
145
147
  const integrationEnabled = features.integration && Boolean(integration.enabled);
148
+
149
+ // Always send to server in pre-commit or manual mode
146
150
  if (integrationEnabled) {
147
- withFailOpenIntegration(() => {
151
+ logInfo("Syncing report to server...");
152
+ await withFailOpenIntegration(async () => {
148
153
  // Network calls are fail-open; never affect exit codes.
149
- sendReportToServer(report, {
154
+ return await sendReportToServer(report, {
150
155
  enabled: true,
151
156
  endpointUrl: integration.endpointUrl
152
157
  });
153
158
  });
159
+ logSuccess("Report synced to server.");
154
160
  } else {
155
161
  reportFeatureDisabled("Integration", verbose, logInfo);
156
162
  }
157
163
  }, () => {
158
- logWarn("Failed to write CodeProof report. Continuing without blocking.");
164
+ logWarn("Failed to process report. Continuing without blocking.");
159
165
  });
160
166
  } else {
161
167
  reportFeatureDisabled("Reporting", verbose, logInfo);
162
168
  }
163
169
 
164
170
  if (blockFindings.length > 0) {
165
- logError(`Baseline rule violations (${blockFindings.length}):`);
171
+ logError(`\n❌ CRITICAL ISSUES FOUND (${blockFindings.length}):\n`);
166
172
  for (const finding of blockFindings) {
167
173
  const relative = path.relative(gitRoot, finding.filePath) || finding.filePath;
168
- logError(
169
- `${finding.ruleId} [${finding.severity}/${finding.confidence}] ${relative}:${finding.line} ${finding.message}`
170
- );
171
- logError(` ${finding.snippet}`);
174
+ logError(` • ${finding.ruleId.toUpperCase()}`);
175
+ logError(` File: ${relative}:${finding.line}`);
176
+ logError(` Issue: ${finding.message}`);
177
+ // console.log(` Code: ${finding.snippet}`);
178
+ logError("");
172
179
  }
173
180
  }
174
181
 
175
182
  if (warnFindings.length > 0) {
176
- logWarn(`Baseline warnings (${warnFindings.length}):`);
177
- for (const finding of warnFindings) {
178
- const relative = path.relative(gitRoot, finding.filePath) || finding.filePath;
179
- logWarn(
180
- `${finding.ruleId} [${finding.severity}/${finding.confidence}] ${relative}:${finding.line} ${finding.message}`
181
- );
182
- logWarn(` ${finding.snippet}`);
183
+ // Filter to show only HIGH risk warnings
184
+ const highRiskWarnings = warnFindings.filter(f => f.confidence === "high");
185
+ if (highRiskWarnings.length > 0) {
186
+ logWarn(`\n⚠️ HIGH RISK WARNINGS (${highRiskWarnings.length}):\n`);
187
+ for (const finding of highRiskWarnings) {
188
+ const relative = path.relative(gitRoot, finding.filePath) || finding.filePath;
189
+ logWarn(` ${finding.ruleId.toUpperCase()}`);
190
+ logWarn(` File: ${relative}:${finding.line}`);
191
+ logWarn(` Issue: ${finding.message}`);
192
+ // console.log(` Code: ${finding.snippet}`);
193
+ logWarn("");
194
+ }
183
195
  }
196
+ // comment out low risk warnings
197
+ // const lowRiskWarnings = warnFindings.filter(f => f.confidence !== "high");
198
+ // if (lowRiskWarnings.length > 0) {
199
+ // logWarn(`Baseline warnings (${lowRiskWarnings.length}):`);
200
+ // for (const finding of lowRiskWarnings) {
201
+ // const relative = path.relative(gitRoot, finding.filePath) || finding.filePath;
202
+ // logWarn(
203
+ // `${finding.ruleId} [${finding.severity}/${finding.confidence}] ${relative}:${finding.line} ${finding.message}`
204
+ // );
205
+ // logWarn(` ${finding.snippet}`);
206
+ // }
207
+ // }
184
208
  }
185
209
 
186
210
  if (aiReviewed.length > 0) {
187
- logWarn(`AI-reviewed findings (${aiReviewed.length}):`);
211
+ logWarn(`\n🤖 AI-REVIEWED FINDINGS (${aiReviewed.length}):\n`);
188
212
  for (const entry of aiReviewed) {
189
213
  const { finding, decision } = entry;
190
214
  const relative = path.relative(gitRoot, finding.filePath) || finding.filePath;
191
- logWarn(
192
- `${finding.ruleId} [${decision.verdict}/${decision.confidence.toFixed(2)}] ${relative}:${finding.line} ${decision.explanation}`
193
- );
215
+ const verdict = decision.verdict === "block" ? "BLOCKED" : "WARNING";
216
+ logWarn(` • ${finding.ruleId.toUpperCase()} [${verdict}]`);
217
+ logWarn(` File: ${relative}:${finding.line}`);
218
+ logWarn(` Analysis: ${decision.explanation}`);
194
219
  if (decision.suggestedFix) {
195
- logWarn(` Suggested fix: ${decision.suggestedFix}`);
220
+ logWarn(` Fix: ${decision.suggestedFix}`);
196
221
  }
222
+ logWarn("");
197
223
  }
198
224
  }
199
225
 
@@ -18,9 +18,13 @@ export function reportFeatureDisabled(name, verbose, logInfo) {
18
18
  logInfo(`${name} disabled by feature flag.`);
19
19
  }
20
20
 
21
- export function withFailOpenReporting(action, onError) {
21
+ export async function withFailOpenReporting(action, onError) {
22
22
  try {
23
- return action();
23
+ const result = action();
24
+ if (result && typeof result.then === 'function') {
25
+ return await result;
26
+ }
27
+ return result;
24
28
  } catch {
25
29
  if (onError) {
26
30
  onError();
@@ -29,9 +33,12 @@ export function withFailOpenReporting(action, onError) {
29
33
  }
30
34
  }
31
35
 
32
- export function withFailOpenIntegration(action) {
36
+ export async function withFailOpenIntegration(action) {
33
37
  try {
34
- action();
38
+ const result = action();
39
+ if (result && typeof result.then === 'function') {
40
+ await result;
41
+ }
35
42
  } catch {
36
43
  // Integration failures are ignored to avoid affecting commits.
37
44
  }
@@ -25,7 +25,7 @@ function getHookBlock() {
25
25
  " exit 0",
26
26
  " fi",
27
27
  "fi",
28
- "CODEPROOF_PRECOMMIT=1 codeproof run --precommit",
28
+ "CODEPROOF_PRECOMMIT=1 npx codeproof run --precommit",
29
29
  "RESULT=$?",
30
30
  "if [ $RESULT -ne 0 ]; then",
31
31
  " echo \"CodeProof checks failed. Commit blocked.\"",
@@ -62,7 +62,7 @@ export function installPreCommitHook(gitRoot) {
62
62
  " exit 0",
63
63
  " fi",
64
64
  "fi",
65
- "CODEPROOF_PRECOMMIT=1 codeproof run --precommit",
65
+ "CODEPROOF_PRECOMMIT=1 npx codeproof run --precommit",
66
66
  "RESULT=$?",
67
67
  "if [ $RESULT -ne 0 ]; then",
68
68
  " echo \"CodeProof checks failed. Commit blocked.\"",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeproof",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "CodeProof CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -4,11 +4,17 @@ import https from "https";
4
4
  // Boundary: integration layer only. Must not import CLI, rule engine, or reporting.
5
5
  // Network calls are fail-open to avoid impacting commits or developer flow.
6
6
 
7
- const DEFAULT_ENDPOINT = "https://api.codeproof.dev/report";
7
+ const DEFAULT_ENDPOINT = "http://127.0.0.1:4000/api/reports";
8
8
 
9
- export function sendReportToServer(report, options = {}) {
9
+ export async function sendReportToServer(report, options = {}) {
10
10
  const enabled = Boolean(options.enabled);
11
+
12
+ // console.log("[API Client] sendReportToServer called");
13
+ // console.log("[API Client] enabled:", enabled);
14
+ // console.log("[API Client] options:", JSON.stringify(options, null, 2));
15
+
11
16
  if (!enabled) {
17
+ // console.log("[API Client] Integration disabled, skipping");
12
18
  return;
13
19
  }
14
20
 
@@ -16,41 +22,75 @@ export function sendReportToServer(report, options = {}) {
16
22
  ? options.endpointUrl.trim()
17
23
  : DEFAULT_ENDPOINT;
18
24
 
19
- try {
20
- const url = new URL(endpointUrl);
21
- const payload = JSON.stringify(report);
22
- const transport = url.protocol === "http:" ? http : https;
23
-
24
- const request = transport.request(
25
- {
26
- method: "POST",
27
- hostname: url.hostname,
28
- port: url.port || (url.protocol === "http:" ? 80 : 443),
29
- path: `${url.pathname}${url.search}`,
30
- headers: {
31
- "Content-Type": "application/json",
32
- "Content-Length": Buffer.byteLength(payload)
25
+ // console.log("[API Client] Target endpoint:", endpointUrl);
26
+ // console.log("[API Client] Report summary:", {
27
+ // projectId: report.projectId,
28
+ // clientId: report.clientId,
29
+ // findingsCount: report.findings?.length || 0
30
+ // });
31
+
32
+ return new Promise((resolve) => {
33
+ try {
34
+ const url = new URL(endpointUrl);
35
+ const payload = JSON.stringify(report);
36
+ const transport = url.protocol === "http:" ? http : https;
37
+
38
+ // console.log("[API Client] URL parsed - protocol:", url.protocol, "hostname:", url.hostname, "port:", url.port, "pathname:", url.pathname);
39
+ // console.log("[API Client] Payload size:", Buffer.byteLength(payload), "bytes");
40
+ // console.log("[API Client] Payload preview:", payload.substring(0, 200) + "...");
41
+
42
+ const portNumber = url.port ? parseInt(url.port, 10) : (url.protocol === "http:" ? 80 : 443);
43
+
44
+ // console.log("[API Client] Sending POST to:", `${url.protocol}//${url.hostname}:${portNumber}${url.pathname}`);
45
+
46
+ const request = transport.request(
47
+ {
48
+ method: "POST",
49
+ hostname: url.hostname,
50
+ port: portNumber,
51
+ path: `${url.pathname}${url.search}`,
52
+ headers: {
53
+ "Content-Type": "application/json",
54
+ "Content-Length": Buffer.byteLength(payload)
55
+ },
56
+ timeout: 5000
33
57
  },
34
- timeout: 2000
35
- },
36
- (res) => {
37
- // UX: fail-open integrations never read or store server responses.
38
- res.resume();
39
- }
40
- );
41
-
42
- request.on("timeout", () => {
43
- // Integrations are fail-open: timeout should not block or throw.
44
- request.destroy();
45
- });
46
-
47
- request.on("error", () => {
48
- // Integrations are fail-open: network errors are ignored silently.
49
- });
50
-
51
- request.write(payload);
52
- request.end();
53
- } catch {
54
- // Integrations are fail-open: invalid URLs or serialization issues are ignored silently.
55
- }
58
+ (res) => {
59
+ // console.log("[API Client] Response received:", res.statusCode);
60
+ let body = "";
61
+ res.on("data", (chunk) => {
62
+ body += chunk;
63
+ });
64
+ res.on("end", () => {
65
+ // console.log("[API Client] Response body:", body);
66
+ if (res.statusCode === 201) {
67
+ // Report sent successfully
68
+ } else {
69
+ console.error("[API Client] Server returned status:", res.statusCode);
70
+ }
71
+ resolve();
72
+ });
73
+ res.resume();
74
+ }
75
+ );
76
+
77
+ request.on("timeout", () => {
78
+ console.error("[API Client] Request timeout");
79
+ request.destroy();
80
+ resolve();
81
+ });
82
+
83
+ request.on("error", (err) => {
84
+ console.error("[API Client] Request error:", err.message);
85
+ resolve();
86
+ });
87
+
88
+ request.write(payload);
89
+ request.end();
90
+ // console.log("[API Client] Request sent");
91
+ } catch (err) {
92
+ console.error("[API Client] Exception:", err.message);
93
+ resolve();
94
+ }
95
+ });
56
96
  }