@rafter-security/cli 0.5.3 → 0.5.9
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 +15 -3
- package/dist/commands/agent/audit-skill.js +2 -2
- package/dist/commands/agent/audit.js +96 -0
- package/dist/commands/agent/baseline.js +213 -0
- package/dist/commands/agent/exec.js +1 -1
- package/dist/commands/agent/index.js +4 -0
- package/dist/commands/agent/init.js +371 -29
- package/dist/commands/agent/install-hook.js +41 -47
- package/dist/commands/agent/scan.js +196 -23
- package/dist/commands/agent/status.js +65 -4
- package/dist/commands/agent/update-gitleaks.js +40 -0
- package/dist/commands/agent/verify.js +18 -4
- package/dist/commands/backend/run.js +69 -61
- package/dist/commands/ci/init.js +10 -3
- package/dist/commands/completion.js +320 -110
- package/dist/commands/hook/posttool.js +21 -7
- package/dist/commands/hook/pretool.js +50 -13
- package/dist/commands/issues/dedup.js +39 -0
- package/dist/commands/issues/from-scan.js +143 -0
- package/dist/commands/issues/from-text.js +185 -0
- package/dist/commands/issues/github-client.js +85 -0
- package/dist/commands/issues/index.js +25 -0
- package/dist/commands/issues/issue-builder.js +101 -0
- package/dist/commands/policy/export.js +7 -2
- package/dist/commands/scan/index.js +44 -0
- package/dist/core/audit-logger.js +41 -0
- package/dist/core/config-defaults.js +28 -0
- package/dist/core/config-manager.js +19 -2
- package/dist/core/pattern-engine.js +26 -1
- package/dist/core/risk-rules.js +5 -3
- package/dist/index.js +8 -2
- package/dist/scanners/gitleaks.js +5 -5
- package/dist/scanners/regex-scanner.js +12 -1
- package/dist/scanners/secret-patterns.js +3 -3
- package/dist/utils/binary-manager.js +59 -20
- package/dist/utils/skill-manager.js +5 -3
- package/package.json +2 -1
- package/resources/pre-commit-hook.sh +2 -2
- package/resources/pre-push-hook.sh +60 -0
- package/resources/rafter-security-skill.md +7 -11
|
@@ -4,23 +4,44 @@ import ora from "ora";
|
|
|
4
4
|
import { detectRepo } from "../../utils/git.js";
|
|
5
5
|
import { API, resolveKey, EXIT_GENERAL_ERROR, EXIT_QUOTA_EXHAUSTED } from "../../utils/api.js";
|
|
6
6
|
import { handleScanStatus } from "./scan-status.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Shared handler for the remote backend scan (used by both `rafter run` and `rafter scan` / `rafter scan remote`).
|
|
9
|
+
*/
|
|
10
|
+
export async function runRemoteScan(opts) {
|
|
11
|
+
const key = resolveKey(opts.apiKey);
|
|
12
|
+
let repo, branch;
|
|
13
|
+
try {
|
|
14
|
+
({ repo, branch } = detectRepo({ repo: opts.repo, branch: opts.branch, quiet: opts.quiet }));
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
if (e instanceof Error) {
|
|
18
|
+
console.error(e.message);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
console.error(e);
|
|
22
|
+
}
|
|
23
|
+
process.exit(EXIT_GENERAL_ERROR);
|
|
24
|
+
}
|
|
25
|
+
if (!opts.quiet) {
|
|
26
|
+
const spinner = ora("Submitting scan").start();
|
|
19
27
|
try {
|
|
20
|
-
|
|
28
|
+
const { data } = await axios.post(`${API}/static/scan`, { repository_name: repo, branch_name: branch }, { headers: { "x-api-key": key } });
|
|
29
|
+
spinner.succeed(`Scan ID: ${data.scan_id}`);
|
|
30
|
+
if (opts.skipInteractive)
|
|
31
|
+
return;
|
|
32
|
+
const exitCode = await handleScanStatus(data.scan_id, { "x-api-key": key }, opts.format ?? "md", opts.quiet);
|
|
33
|
+
process.exit(exitCode);
|
|
21
34
|
}
|
|
22
35
|
catch (e) {
|
|
23
|
-
|
|
36
|
+
spinner.fail("Request failed");
|
|
37
|
+
if (e.response?.status === 429) {
|
|
38
|
+
console.error("Quota exhausted");
|
|
39
|
+
process.exit(EXIT_QUOTA_EXHAUSTED);
|
|
40
|
+
}
|
|
41
|
+
else if (e.response?.data) {
|
|
42
|
+
console.error(e.response.data);
|
|
43
|
+
}
|
|
44
|
+
else if (e instanceof Error) {
|
|
24
45
|
console.error(e.message);
|
|
25
46
|
}
|
|
26
47
|
else {
|
|
@@ -28,57 +49,44 @@ export function createRunCommand() {
|
|
|
28
49
|
}
|
|
29
50
|
process.exit(EXIT_GENERAL_ERROR);
|
|
30
51
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
try {
|
|
55
|
+
const { data } = await axios.post(`${API}/static/scan`, { repository_name: repo, branch_name: branch }, { headers: { "x-api-key": key } });
|
|
56
|
+
if (opts.skipInteractive)
|
|
57
|
+
return;
|
|
58
|
+
const exitCode = await handleScanStatus(data.scan_id, { "x-api-key": key }, opts.format ?? "md", opts.quiet);
|
|
59
|
+
process.exit(exitCode);
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
if (e.response?.status === 429) {
|
|
63
|
+
process.exit(EXIT_QUOTA_EXHAUSTED);
|
|
40
64
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (e.response?.status === 429) {
|
|
44
|
-
console.error("Quota exhausted");
|
|
45
|
-
process.exit(EXIT_QUOTA_EXHAUSTED);
|
|
46
|
-
}
|
|
47
|
-
else if (e.response?.data) {
|
|
48
|
-
console.error(e.response.data);
|
|
49
|
-
}
|
|
50
|
-
else if (e instanceof Error) {
|
|
51
|
-
console.error(e.message);
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
console.error(e);
|
|
55
|
-
}
|
|
56
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
65
|
+
else if (e.response?.data) {
|
|
66
|
+
console.error(e.response.data);
|
|
57
67
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
try {
|
|
61
|
-
const { data } = await axios.post(`${API}/static/scan`, { repository_name: repo, branch_name: branch }, { headers: { "x-api-key": key } });
|
|
62
|
-
if (opts.skipInteractive)
|
|
63
|
-
return;
|
|
64
|
-
const exitCode = await handleScanStatus(data.scan_id, { "x-api-key": key }, opts.format, opts.quiet);
|
|
65
|
-
process.exit(exitCode);
|
|
68
|
+
else if (e instanceof Error) {
|
|
69
|
+
console.error(e.message);
|
|
66
70
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
process.exit(EXIT_QUOTA_EXHAUSTED);
|
|
70
|
-
}
|
|
71
|
-
else if (e.response?.data) {
|
|
72
|
-
console.error(e.response.data);
|
|
73
|
-
}
|
|
74
|
-
else if (e instanceof Error) {
|
|
75
|
-
console.error(e.message);
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
console.error(e);
|
|
79
|
-
}
|
|
80
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
71
|
+
else {
|
|
72
|
+
console.error(e);
|
|
81
73
|
}
|
|
74
|
+
process.exit(EXIT_GENERAL_ERROR);
|
|
82
75
|
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function addRunOptions(cmd) {
|
|
79
|
+
return cmd
|
|
80
|
+
.option("-r, --repo <repo>", "org/repo (default: current)")
|
|
81
|
+
.option("-b, --branch <branch>", "branch (default: current else main)")
|
|
82
|
+
.option("-k, --api-key <key>", "API key or RAFTER_API_KEY env var")
|
|
83
|
+
.option("-f, --format <format>", "json | md", "md")
|
|
84
|
+
.option("--skip-interactive", "do not wait for scan to complete")
|
|
85
|
+
.option("--quiet", "suppress status messages");
|
|
86
|
+
}
|
|
87
|
+
export function createRunCommand() {
|
|
88
|
+
return addRunOptions(new Command("run")
|
|
89
|
+
.description("Trigger a remote backend security scan")).action(async (opts) => {
|
|
90
|
+
await runRemoteScan(opts);
|
|
83
91
|
});
|
|
84
92
|
}
|
package/dist/commands/ci/init.js
CHANGED
|
@@ -44,6 +44,12 @@ export function createCiInitCommand() {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
console.log(` ${opts.withBackend ? "3" : "2"}. Commit and push to trigger the pipeline`);
|
|
47
|
+
if (platform === "github") {
|
|
48
|
+
console.log();
|
|
49
|
+
console.log("Alternatives:");
|
|
50
|
+
console.log(" - GitHub Action: uses: Raftersecurity/rafter-cli@v0");
|
|
51
|
+
console.log(" - Pre-commit: https://github.com/Raftersecurity/rafter-cli#pre-commit-framework");
|
|
52
|
+
}
|
|
47
53
|
console.log();
|
|
48
54
|
});
|
|
49
55
|
}
|
|
@@ -68,6 +74,7 @@ function generateTemplate(platform, withBackend) {
|
|
|
68
74
|
}
|
|
69
75
|
function githubTemplate(withBackend) {
|
|
70
76
|
let yaml = `# Generated by: rafter ci init
|
|
77
|
+
# Alternative: uses: Raftersecurity/rafter-cli@v0
|
|
71
78
|
name: Rafter Security
|
|
72
79
|
|
|
73
80
|
on:
|
|
@@ -89,7 +96,7 @@ jobs:
|
|
|
89
96
|
run: npm install -g @rafter-security/cli
|
|
90
97
|
|
|
91
98
|
- name: Scan for secrets
|
|
92
|
-
run: rafter
|
|
99
|
+
run: rafter scan local . --quiet
|
|
93
100
|
`;
|
|
94
101
|
if (withBackend) {
|
|
95
102
|
yaml += `
|
|
@@ -120,7 +127,7 @@ secret-scan:
|
|
|
120
127
|
image: node:20
|
|
121
128
|
script:
|
|
122
129
|
- npm install -g @rafter-security/cli
|
|
123
|
-
- rafter
|
|
130
|
+
- rafter scan local . --quiet
|
|
124
131
|
rules:
|
|
125
132
|
- if: $CI_PIPELINE_SOURCE == "push"
|
|
126
133
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
@@ -158,7 +165,7 @@ jobs:
|
|
|
158
165
|
command: npm install -g @rafter-security/cli
|
|
159
166
|
- run:
|
|
160
167
|
name: Scan for secrets
|
|
161
|
-
command: rafter
|
|
168
|
+
command: rafter scan local . --quiet
|
|
162
169
|
`;
|
|
163
170
|
if (withBackend) {
|
|
164
171
|
yaml += `
|