codeant-cli 0.3.4 → 0.3.6
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/package.json +3 -2
- package/src/commands/login.js +2 -2
- package/src/commands/logout.js +2 -2
- package/src/commands/review.js +1 -1
- package/src/commands/secrets.js +6 -47
- package/src/reviewHeadless.js +2 -2
- package/src/rules/secrets.toml +4994 -0
- package/src/utils/analytics.js +1 -1
- package/src/utils/fetchApi.js +1 -1
- package/src/utils/secretsDetector.js +210 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeant-cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "Code review CLI tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"minimatch": "^10.1.1",
|
|
41
41
|
"open": "^10.1.0",
|
|
42
42
|
"posthog-node": "^5.28.5",
|
|
43
|
-
"react": "^18.3.1"
|
|
43
|
+
"react": "^18.3.1",
|
|
44
|
+
"smol-toml": "^1.6.1"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"vitest": "^1.6.1"
|
package/src/commands/login.js
CHANGED
|
@@ -14,7 +14,7 @@ export default function Login() {
|
|
|
14
14
|
|
|
15
15
|
useEffect(() => {
|
|
16
16
|
// Check if already logged in
|
|
17
|
-
const existingToken = getConfigValue('
|
|
17
|
+
const existingToken = getConfigValue('apiKeyV2');
|
|
18
18
|
if (existingToken) {
|
|
19
19
|
setStatus('already_logged_in');
|
|
20
20
|
setTimeout(() => exit(), 100);
|
|
@@ -48,7 +48,7 @@ export default function Login() {
|
|
|
48
48
|
clearTimeout(timeoutId);
|
|
49
49
|
|
|
50
50
|
// Save the API key
|
|
51
|
-
setConfigValue('
|
|
51
|
+
setConfigValue('apiKeyV2', token);
|
|
52
52
|
|
|
53
53
|
setStatus('success');
|
|
54
54
|
setTimeout(() => exit(), 100);
|
package/src/commands/logout.js
CHANGED
|
@@ -5,11 +5,11 @@ import { getConfigValue, setConfigValue } from '../utils/config.js';
|
|
|
5
5
|
export default function Logout() {
|
|
6
6
|
const { exit } = useApp();
|
|
7
7
|
|
|
8
|
-
const wasLoggedIn = !!getConfigValue('
|
|
8
|
+
const wasLoggedIn = !!getConfigValue('apiKeyV2');
|
|
9
9
|
|
|
10
10
|
useEffect(() => {
|
|
11
11
|
if (wasLoggedIn) {
|
|
12
|
-
setConfigValue('
|
|
12
|
+
setConfigValue('apiKeyV2', null);
|
|
13
13
|
}
|
|
14
14
|
exit();
|
|
15
15
|
}, []);
|
package/src/commands/review.js
CHANGED
|
@@ -31,7 +31,7 @@ export default function Review({ scanType = 'all', lastNCommits = 1, failOn = 'C
|
|
|
31
31
|
const [fileCount, setFileCount] = useState(0);
|
|
32
32
|
const [reviewMeta, setReviewMeta] = useState(null);
|
|
33
33
|
|
|
34
|
-
const apiKey = getConfigValue('
|
|
34
|
+
const apiKey = getConfigValue('apiKeyV2');
|
|
35
35
|
|
|
36
36
|
useEffect(() => {
|
|
37
37
|
if (!apiKey) {
|
package/src/commands/secrets.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react';
|
|
2
2
|
import { useApp } from 'ink';
|
|
3
|
-
import { getConfigValue } from '../utils/config.js';
|
|
4
|
-
import { fetchApi } from '../utils/fetchApi.js';
|
|
5
3
|
import SecretsApiHelper from '../utils/secretsApiHelper.js';
|
|
4
|
+
import { detectSecrets } from '../utils/secretsDetector.js';
|
|
6
5
|
import {
|
|
7
6
|
renderInitializing,
|
|
8
7
|
renderFetchingDiff,
|
|
9
8
|
renderScanning,
|
|
10
9
|
renderNoFiles,
|
|
11
10
|
renderError,
|
|
12
|
-
renderNotLoggedIn,
|
|
13
11
|
renderDone,
|
|
14
12
|
} from '../components/SecretsUI.js';
|
|
15
13
|
|
|
@@ -22,30 +20,12 @@ export default function Secrets({ scanType = 'all', failOn = 'CRITICAL', include
|
|
|
22
20
|
const [scanMeta, setScanMeta] = useState(null);
|
|
23
21
|
const [startTime] = useState(() => Date.now());
|
|
24
22
|
|
|
25
|
-
const apiKey = getConfigValue('apiKey');
|
|
26
|
-
|
|
27
|
-
// Handle not logged in state
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
if (!apiKey) {
|
|
30
|
-
if (process.stdin.isTTY) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
const id = setTimeout(() => exit(new Error('Not logged in')), 0);
|
|
34
|
-
return () => clearTimeout(id);
|
|
35
|
-
}
|
|
36
|
-
}, [apiKey, exit]);
|
|
37
|
-
|
|
38
|
-
if (!apiKey) {
|
|
39
|
-
return renderNotLoggedIn();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Helper to check if a secret should cause failure based on failOn level
|
|
43
23
|
const shouldFailOn = (confidenceScore) => {
|
|
44
24
|
const score = confidenceScore?.toUpperCase();
|
|
45
25
|
if (score === 'FALSE_POSITIVE') return false;
|
|
46
26
|
if (failOn === 'HIGH') return score === 'HIGH';
|
|
47
27
|
if (failOn === 'MEDIUM') return score === 'HIGH' || score === 'MEDIUM';
|
|
48
|
-
return true;
|
|
28
|
+
return true;
|
|
49
29
|
};
|
|
50
30
|
|
|
51
31
|
useEffect(() => {
|
|
@@ -56,7 +36,6 @@ export default function Secrets({ scanType = 'all', failOn = 'CRITICAL', include
|
|
|
56
36
|
if (cancelled) return;
|
|
57
37
|
setStatus('fetching_diff');
|
|
58
38
|
|
|
59
|
-
// Initialize git helper and get files
|
|
60
39
|
const helper = new SecretsApiHelper(process.cwd());
|
|
61
40
|
await helper.init();
|
|
62
41
|
|
|
@@ -66,8 +45,6 @@ export default function Secrets({ scanType = 'all', failOn = 'CRITICAL', include
|
|
|
66
45
|
|
|
67
46
|
const meta = requestBody._meta || null;
|
|
68
47
|
setScanMeta(meta);
|
|
69
|
-
|
|
70
|
-
// Strip _meta before sending to API
|
|
71
48
|
delete requestBody._meta;
|
|
72
49
|
|
|
73
50
|
if (requestBody.files.length === 0) {
|
|
@@ -78,17 +55,10 @@ export default function Secrets({ scanType = 'all', failOn = 'CRITICAL', include
|
|
|
78
55
|
setFileCount(requestBody.files.length);
|
|
79
56
|
setStatus('scanning');
|
|
80
57
|
|
|
81
|
-
//
|
|
82
|
-
const
|
|
83
|
-
'/extension/pr-review/secrets-detection',
|
|
84
|
-
'POST',
|
|
85
|
-
requestBody
|
|
86
|
-
);
|
|
58
|
+
// Local detection — no API call needed
|
|
59
|
+
const detectedSecrets = detectSecrets(requestBody.files);
|
|
87
60
|
|
|
88
61
|
if (cancelled) return;
|
|
89
|
-
const detectedSecrets = response.secretsDetected || [];
|
|
90
|
-
|
|
91
|
-
// Filter to only include files with actual secrets
|
|
92
62
|
const filesWithSecrets = detectedSecrets.filter(
|
|
93
63
|
file => file.secrets && file.secrets.length > 0
|
|
94
64
|
);
|
|
@@ -106,25 +76,16 @@ export default function Secrets({ scanType = 'all', failOn = 'CRITICAL', include
|
|
|
106
76
|
}
|
|
107
77
|
|
|
108
78
|
scanSecrets();
|
|
109
|
-
|
|
110
|
-
return () => {
|
|
111
|
-
cancelled = true;
|
|
112
|
-
};
|
|
79
|
+
return () => { cancelled = true; };
|
|
113
80
|
}, [scanType, include, exclude, lastNCommits, baseBranch, baseCommit]);
|
|
114
81
|
|
|
115
|
-
// Handle exit after status changes
|
|
116
82
|
useEffect(() => {
|
|
117
83
|
if (status === 'done') {
|
|
118
|
-
// Check if any secrets should cause failure based on failOn level
|
|
119
84
|
const hasBlockingSecrets = secrets.some(file =>
|
|
120
85
|
file.secrets.some(secret => shouldFailOn(secret.confidence_score))
|
|
121
86
|
);
|
|
122
|
-
|
|
123
87
|
if (hasBlockingSecrets) {
|
|
124
|
-
setTimeout(() => {
|
|
125
|
-
process.exitCode = 1;
|
|
126
|
-
exit(new Error('Secrets detected'));
|
|
127
|
-
}, 100);
|
|
88
|
+
setTimeout(() => { process.exitCode = 1; exit(new Error('Secrets detected')); }, 100);
|
|
128
89
|
} else {
|
|
129
90
|
setTimeout(() => exit(), 100);
|
|
130
91
|
}
|
|
@@ -135,8 +96,6 @@ export default function Secrets({ scanType = 'all', failOn = 'CRITICAL', include
|
|
|
135
96
|
}
|
|
136
97
|
}, [status, secrets]);
|
|
137
98
|
|
|
138
|
-
// ── Renders ──────────────────────────────────────────────────────────────
|
|
139
|
-
|
|
140
99
|
if (status === 'initializing') return renderInitializing(startTime);
|
|
141
100
|
if (status === 'fetching_diff') return renderFetchingDiff(startTime);
|
|
142
101
|
if (status === 'scanning') return renderScanning(startTime, fileCount, scanMeta);
|
package/src/reviewHeadless.js
CHANGED
|
@@ -87,8 +87,8 @@ export async function runReviewHeadless(options = {}) {
|
|
|
87
87
|
} = options;
|
|
88
88
|
|
|
89
89
|
// If the CLI config doesn't have an apiKey but the extension passed one, persist it
|
|
90
|
-
if (apiKey && !getConfigValue('
|
|
91
|
-
setConfigValue('
|
|
90
|
+
if (apiKey && !getConfigValue('apiKeyV2')) {
|
|
91
|
+
setConfigValue('apiKeyV2', apiKey);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
// Temporarily set env vars so fetchApi picks them up
|