@rafter-security/cli 0.6.6 → 0.7.1
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 +29 -10
- package/dist/commands/agent/audit-skill.js +22 -20
- package/dist/commands/agent/audit.js +27 -0
- package/dist/commands/agent/components.js +800 -0
- package/dist/commands/agent/config.js +2 -1
- package/dist/commands/agent/disable.js +47 -0
- package/dist/commands/agent/enable.js +50 -0
- package/dist/commands/agent/exec.js +2 -0
- package/dist/commands/agent/index.js +6 -0
- package/dist/commands/agent/init.js +162 -163
- package/dist/commands/agent/install-hook.js +15 -14
- package/dist/commands/agent/list.js +72 -0
- package/dist/commands/agent/scan.js +4 -3
- package/dist/commands/agent/verify.js +1 -1
- package/dist/commands/backend/run.js +12 -3
- package/dist/commands/backend/scan-status.js +3 -2
- package/dist/commands/brief.js +22 -2
- package/dist/commands/ci/init.js +25 -21
- package/dist/commands/completion.js +4 -3
- package/dist/commands/docs/index.js +18 -0
- package/dist/commands/docs/list.js +37 -0
- package/dist/commands/docs/show.js +64 -0
- package/dist/commands/mcp/server.js +84 -0
- package/dist/commands/report.js +42 -41
- package/dist/commands/scan/index.js +7 -5
- package/dist/commands/skill/index.js +14 -0
- package/dist/commands/skill/install.js +89 -0
- package/dist/commands/skill/list.js +79 -0
- package/dist/commands/skill/registry.js +273 -0
- package/dist/commands/skill/remote.js +333 -0
- package/dist/commands/skill/review.js +975 -0
- package/dist/commands/skill/uninstall.js +65 -0
- package/dist/core/audit-logger.js +262 -21
- package/dist/core/config-manager.js +3 -0
- package/dist/core/docs-loader.js +148 -0
- package/dist/core/policy-loader.js +72 -1
- package/dist/core/risk-rules.js +16 -3
- package/dist/index.js +19 -9
- package/dist/scanners/gitleaks.js +6 -2
- package/package.json +1 -1
- package/resources/skills/rafter/SKILL.md +77 -97
- package/resources/skills/rafter/docs/backend.md +106 -0
- package/resources/skills/rafter/docs/cli-reference.md +199 -0
- package/resources/skills/rafter/docs/finding-triage.md +79 -0
- package/resources/skills/rafter/docs/guardrails.md +91 -0
- package/resources/skills/rafter/docs/shift-left.md +64 -0
- package/resources/skills/rafter-agent-security/SKILL.md +1 -1
- package/resources/skills/rafter-code-review/SKILL.md +91 -0
- package/resources/skills/rafter-code-review/docs/api.md +90 -0
- package/resources/skills/rafter-code-review/docs/asvs.md +120 -0
- package/resources/skills/rafter-code-review/docs/cwe-top25.md +78 -0
- package/resources/skills/rafter-code-review/docs/investigation-playbook.md +101 -0
- package/resources/skills/rafter-code-review/docs/llm.md +87 -0
- package/resources/skills/rafter-code-review/docs/web-app.md +84 -0
- package/resources/skills/rafter-secure-design/SKILL.md +103 -0
- package/resources/skills/rafter-secure-design/docs/api-design.md +97 -0
- package/resources/skills/rafter-secure-design/docs/auth.md +67 -0
- package/resources/skills/rafter-secure-design/docs/data-storage.md +90 -0
- package/resources/skills/rafter-secure-design/docs/dependencies.md +101 -0
- package/resources/skills/rafter-secure-design/docs/deployment.md +104 -0
- package/resources/skills/rafter-secure-design/docs/ingestion.md +98 -0
- package/resources/skills/rafter-secure-design/docs/standards-pointers.md +102 -0
- package/resources/skills/rafter-secure-design/docs/threat-modeling.md +128 -0
- package/resources/skills/rafter-skill-review/SKILL.md +106 -0
- package/resources/skills/rafter-skill-review/docs/authorship-provenance.md +82 -0
- package/resources/skills/rafter-skill-review/docs/changelog-review.md +99 -0
- package/resources/skills/rafter-skill-review/docs/data-practices.md +88 -0
- package/resources/skills/rafter-skill-review/docs/malware-indicators.md +79 -0
- package/resources/skills/rafter-skill-review/docs/prompt-injection.md +85 -0
- package/resources/skills/rafter-skill-review/docs/telemetry.md +78 -0
package/dist/core/risk-rules.js
CHANGED
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
* Centralized risk assessment rules.
|
|
3
3
|
* Single source of truth — imported by command-interceptor, audit-logger, and config-defaults.
|
|
4
4
|
*/
|
|
5
|
+
/** Directories where `rm -rf /<dir>` is catastrophic (data loss / unbootable). */
|
|
6
|
+
const CRITICAL_DIRS = "home|etc|usr|boot|root|sys|proc|lib|lib64|bin|sbin|opt";
|
|
5
7
|
export const CRITICAL_PATTERNS = [
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
// rm -rf / (root only, any flag order)
|
|
9
|
+
new RegExp(`rm\\s+(-[a-z]*r[a-z]*\\s+)*-[a-z]*f[a-z]*\\s+/(\\s|$)`),
|
|
10
|
+
new RegExp(`rm\\s+(-[a-z]*f[a-z]*\\s+)*-[a-z]*r[a-z]*\\s+/(\\s|$)`),
|
|
11
|
+
// rm -rf on critical top-level directories
|
|
12
|
+
new RegExp(`rm\\s+(-[a-z]*r[a-z]*\\s+)*-[a-z]*f[a-z]*\\s+/(${CRITICAL_DIRS})(/|\\s|$)`),
|
|
13
|
+
new RegExp(`rm\\s+(-[a-z]*f[a-z]*\\s+)*-[a-z]*r[a-z]*\\s+/(${CRITICAL_DIRS})(/|\\s|$)`),
|
|
8
14
|
/:\(\)\{\s*:\|:&\s*\};:/, // fork bomb
|
|
9
15
|
/dd\s+if=.*of=\/dev\/sd/,
|
|
10
16
|
/>\s*\/dev\/sd/,
|
|
@@ -55,11 +61,18 @@ export const DEFAULT_REQUIRE_APPROVAL = [
|
|
|
55
61
|
"git push --force-if-includes",
|
|
56
62
|
"git push .* \\+",
|
|
57
63
|
];
|
|
64
|
+
/** Read-only commands whose arguments should not trigger risk patterns. */
|
|
65
|
+
const SAFE_PREFIX = /^(grep|egrep|fgrep|rg|ag|ack|echo|printf)\s/;
|
|
66
|
+
/** Shell operators that chain independent commands. */
|
|
67
|
+
const CHAIN_OPERATORS = /[;|&]|&&|\|\|/;
|
|
58
68
|
/**
|
|
59
69
|
* Assess risk level of a command string.
|
|
60
70
|
*/
|
|
61
71
|
export function assessCommandRisk(command) {
|
|
62
|
-
const cmd = command.toLowerCase();
|
|
72
|
+
const cmd = command.toLowerCase().trim();
|
|
73
|
+
// Safe prefix only applies to simple (non-chained) commands
|
|
74
|
+
if (SAFE_PREFIX.test(cmd) && !CHAIN_OPERATORS.test(cmd))
|
|
75
|
+
return "low";
|
|
63
76
|
for (const pattern of CRITICAL_PATTERNS) {
|
|
64
77
|
if (pattern.test(cmd))
|
|
65
78
|
return "critical";
|
package/dist/index.js
CHANGED
|
@@ -6,11 +6,13 @@ import { createGetCommand } from "./commands/backend/get.js";
|
|
|
6
6
|
import { createUsageCommand } from "./commands/backend/usage.js";
|
|
7
7
|
import { createScanGroupCommand } from "./commands/scan/index.js";
|
|
8
8
|
import { createAgentCommand } from "./commands/agent/index.js";
|
|
9
|
+
import { createSkillCommand } from "./commands/skill/index.js";
|
|
9
10
|
import { createCiCommand } from "./commands/ci/index.js";
|
|
10
11
|
import { createHookCommand } from "./commands/hook/index.js";
|
|
11
12
|
import { createMcpCommand } from "./commands/mcp/index.js";
|
|
12
13
|
import { createPolicyCommand } from "./commands/policy/index.js";
|
|
13
14
|
import { createBriefCommand } from "./commands/brief.js";
|
|
15
|
+
import { createDocsCommand } from "./commands/docs/index.js";
|
|
14
16
|
import { createNotifyCommand } from "./commands/notify.js";
|
|
15
17
|
import { createCompletionCommand } from "./commands/completion.js";
|
|
16
18
|
import { createIssuesCommand } from "./commands/issues/index.js";
|
|
@@ -21,27 +23,27 @@ import { createRequire } from "module";
|
|
|
21
23
|
dotenv.config();
|
|
22
24
|
const require = createRequire(import.meta.url);
|
|
23
25
|
const { version: VERSION } = require("../package.json");
|
|
26
|
+
// Set agent mode early from argv — preAction hooks may not propagate to nested
|
|
27
|
+
// subcommands on Node 18, so we detect -a/--agent before Commander parses.
|
|
28
|
+
if (process.argv.includes("-a") || process.argv.includes("--agent")) {
|
|
29
|
+
setAgentMode(true);
|
|
30
|
+
}
|
|
24
31
|
const program = new Command()
|
|
25
32
|
.name("rafter")
|
|
26
33
|
.description("Rafter CLI — the default security agent for AI workflows. Free for individuals and open source. No account required.")
|
|
27
34
|
.version(VERSION)
|
|
28
35
|
.enablePositionalOptions()
|
|
29
36
|
.option("-a, --agent", "Plain output for AI agents (no colors/emoji)");
|
|
30
|
-
//
|
|
31
|
-
program.hook("preAction", (thisCommand) => {
|
|
32
|
-
const opts = thisCommand.opts();
|
|
33
|
-
if (opts.agent) {
|
|
34
|
-
setAgentMode(true);
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
// Backend commands
|
|
37
|
+
// Remote scan commands
|
|
38
38
|
program.addCommand(createRunCommand());
|
|
39
39
|
program.addCommand(createGetCommand());
|
|
40
40
|
program.addCommand(createUsageCommand());
|
|
41
|
-
// Scan command group (default: remote
|
|
41
|
+
// Scan command group (default: remote scan; subcommands: local, remote)
|
|
42
42
|
program.addCommand(createScanGroupCommand());
|
|
43
43
|
// Agent commands
|
|
44
44
|
program.addCommand(createAgentCommand());
|
|
45
|
+
// Skill commands (install / uninstall / list rafter-authored skills)
|
|
46
|
+
program.addCommand(createSkillCommand());
|
|
45
47
|
// CI commands
|
|
46
48
|
program.addCommand(createCiCommand());
|
|
47
49
|
// Hook commands (for agent platform integration)
|
|
@@ -50,6 +52,8 @@ program.addCommand(createHookCommand());
|
|
|
50
52
|
program.addCommand(createMcpCommand());
|
|
51
53
|
// Policy commands
|
|
52
54
|
program.addCommand(createPolicyCommand());
|
|
55
|
+
// Docs — repo-specific security docs from .rafter.yml
|
|
56
|
+
program.addCommand(createDocsCommand());
|
|
53
57
|
// GitHub Issues integration
|
|
54
58
|
program.addCommand(createIssuesCommand());
|
|
55
59
|
// Brief — agent-independent knowledge delivery
|
|
@@ -60,6 +64,12 @@ program.addCommand(createNotifyCommand());
|
|
|
60
64
|
program.addCommand(createReportCommand());
|
|
61
65
|
// Shell completions
|
|
62
66
|
program.addCommand(createCompletionCommand());
|
|
67
|
+
// Version subcommand (also available as --version)
|
|
68
|
+
program.addCommand(new Command("version")
|
|
69
|
+
.description("Print version and exit")
|
|
70
|
+
.action(() => {
|
|
71
|
+
console.log(VERSION);
|
|
72
|
+
}));
|
|
63
73
|
// Non-blocking update check — runs after command, prints to stderr
|
|
64
74
|
checkForUpdate(VERSION).then((notice) => {
|
|
65
75
|
if (notice)
|
|
@@ -82,15 +82,19 @@ export class GitleaksScanner {
|
|
|
82
82
|
/**
|
|
83
83
|
* Scan a directory
|
|
84
84
|
*/
|
|
85
|
-
async scanDirectory(dirPath) {
|
|
85
|
+
async scanDirectory(dirPath, opts) {
|
|
86
86
|
if (!await this.isAvailable()) {
|
|
87
87
|
throw new Error("Gitleaks not available");
|
|
88
88
|
}
|
|
89
89
|
const gitleaksPath = this.binaryManager.getGitleaksPath();
|
|
90
90
|
const tmpReport = path.join(os.tmpdir(), `gitleaks-${Date.now()}-${randomBytes(6).toString("hex")}.json`);
|
|
91
91
|
try {
|
|
92
|
+
const args = ["detect", "-f", "json", "-r", tmpReport, "-s", dirPath];
|
|
93
|
+
if (!opts?.useGit) {
|
|
94
|
+
args.splice(1, 0, "--no-git");
|
|
95
|
+
}
|
|
92
96
|
// Run gitleaks detect on directory
|
|
93
|
-
await execFileAsync(gitleaksPath,
|
|
97
|
+
await execFileAsync(gitleaksPath, args, { timeout: 60000 });
|
|
94
98
|
// No leaks found
|
|
95
99
|
if (!fs.existsSync(tmpReport)) {
|
|
96
100
|
return [];
|
package/package.json
CHANGED
|
@@ -1,138 +1,118 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: rafter
|
|
3
|
-
description: "Rafter — the security toolkit built for AI workflows.
|
|
4
|
-
version: 0.
|
|
5
|
-
allowed-tools: [Bash]
|
|
3
|
+
description: "Rafter — the security toolkit built for AI workflows. Router skill: pick your task below and Read the matching sub-doc. Covers (a) scanning code/repos, (b) evaluating a command before running, (c) auditing a plugin or skill, (d) understanding a finding, (e) writing secure code from scratch, (f) analyzing existing code for flaws. Local features are free, deterministic, and offline (no API key). Remote SAST/SCA via RAFTER_API_KEY when deeper analysis is needed. If RAFTER_API_KEY is missing, local still works — don't block on it."
|
|
4
|
+
version: 0.7.0
|
|
5
|
+
allowed-tools: [Bash, Read]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# Rafter Security Toolkit
|
|
8
|
+
# Rafter — Security Toolkit for AI Workflows
|
|
9
9
|
|
|
10
|
-
Rafter
|
|
10
|
+
Rafter ships three tiers of security tooling:
|
|
11
11
|
|
|
12
|
-
1. **Local
|
|
13
|
-
2. **Remote fast** —
|
|
14
|
-
3. **Remote plus** — agentic deep-dive analysis
|
|
12
|
+
1. **Local** — deterministic secret scanning, command-risk classification, skill auditing. Free, offline, no API key.
|
|
13
|
+
2. **Remote fast** (default) — SAST + SCA + deterministic secrets via the Rafter API.
|
|
14
|
+
3. **Remote plus** — agentic deep-dive analysis. Your code is deleted after the run.
|
|
15
15
|
|
|
16
|
-
Stable
|
|
16
|
+
Stable exit codes, stable JSON shapes, deterministic findings. Safe to chain in CI and in agent loops.
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
> **Platform setup**: Run `rafter brief setup/<platform>` for integration guides.
|
|
18
|
+
---
|
|
20
19
|
|
|
21
|
-
##
|
|
20
|
+
## Choose Your Adventure
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
Pick the branch that matches what you're trying to do. Each branch points at a sub-doc — `Read` only the one you need so you don't flood context.
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
rafter run [--repo org/repo] [--branch branch-name]
|
|
27
|
-
# or
|
|
28
|
-
rafter scan [--repo org/repo] [--branch branch-name]
|
|
29
|
-
```
|
|
24
|
+
### (a) I want to scan code or a repo for issues
|
|
30
25
|
|
|
31
|
-
|
|
26
|
+
Use this for: "Is this safe to push?", "Check for leaks", "Run a security scan", pre-merge / pre-deploy gating, post-dependency-update checks.
|
|
32
27
|
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
- After dependency updates
|
|
38
|
-
- User mentions: security audit, vulnerability scan, SAST, code analysis
|
|
39
|
-
- User asks: "Is this safe to merge?", "Are there vulnerabilities?", "Check this PR"
|
|
28
|
+
- Local secret scan (fast, no key): `rafter scan local .`
|
|
29
|
+
- Remote SAST/SCA (needs `RAFTER_API_KEY`): `rafter run` (alias `rafter scan`)
|
|
30
|
+
- **Read `docs/backend.md`** for fast-vs-plus modes, auth, latency, cost.
|
|
31
|
+
- **Read `docs/cli-reference.md`** §`scan` and §`run` for full flag matrix.
|
|
40
32
|
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
# In a git repo
|
|
44
|
-
rafter scan
|
|
33
|
+
### (b) I want to evaluate a command before running it
|
|
45
34
|
|
|
46
|
-
|
|
47
|
-
rafter scan --repo myorg/myrepo --branch main
|
|
48
|
-
```
|
|
35
|
+
Use this for: "Is `rm -rf $DIR` safe?", any destructive-looking shell the user typed, commands with sudo / pipes to `sh` / unversioned curl.
|
|
49
36
|
|
|
50
|
-
|
|
37
|
+
- One-shot: `rafter agent exec --dry-run -- <command>`
|
|
38
|
+
- Wrap execution: `rafter agent exec -- <command>` (blocks on critical, prompts on high)
|
|
39
|
+
- **Read `docs/guardrails.md`** for how PreToolUse hooks, risk tiers, and overrides work.
|
|
51
40
|
|
|
52
|
-
|
|
53
|
-
rafter get <scan-id>
|
|
54
|
-
```
|
|
41
|
+
### (c) I want to review a plugin, skill, or extension before installing
|
|
55
42
|
|
|
56
|
-
|
|
43
|
+
Use this for: installing an MCP server, adding a Claude skill, vetting an AI tool config.
|
|
57
44
|
|
|
58
|
-
**
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
45
|
+
- **Installing a new skill? → Read `rafter-skill-review/SKILL.md`** — full provenance, malware, prompt-injection, data-practices, telemetry checklist.
|
|
46
|
+
- Run the deterministic pass: `rafter skill review <path-or-url>` (emits JSON).
|
|
47
|
+
- Audit a directory: `rafter agent audit <path>` (still supported).
|
|
48
|
+
- **Read `docs/cli-reference.md`** §`skill review` / §`agent audit` for output shape and exit codes.
|
|
62
49
|
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
rafter get scan_abc123xyz
|
|
66
|
-
```
|
|
50
|
+
### (d) I want to understand a finding I already have
|
|
67
51
|
|
|
68
|
-
|
|
52
|
+
Use this for: "What does `HARDCODED_SECRET` mean?", "Is this a real issue or noise?", triaging a scan report.
|
|
69
53
|
|
|
70
|
-
|
|
71
|
-
rafter usage
|
|
72
|
-
```
|
|
54
|
+
- **Read `docs/finding-triage.md`** — how to parse severity, rule IDs, confidence, and file refs; when to fix, suppress, or escalate.
|
|
73
55
|
|
|
74
|
-
|
|
56
|
+
### (e) I want to write secure code from scratch
|
|
75
57
|
|
|
76
|
-
|
|
77
|
-
- User asks about remaining scans
|
|
78
|
-
- Before triggering a scan to confirm quota
|
|
79
|
-
- User mentions: quota, usage, limits, remaining scans
|
|
58
|
+
Use this for: designing a new feature, picking auth/crypto primitives, shaping APIs before they exist.
|
|
80
59
|
|
|
81
|
-
|
|
60
|
+
- **Read `docs/shift-left.md`** — pointers into the `rafter-secure-design` sibling skill for design-phase guidance (threat modeling, OWASP ASVS choices, safe defaults).
|
|
82
61
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
62
|
+
### (f) I want to analyze existing code for flaws
|
|
63
|
+
|
|
64
|
+
Use this for: code review, refactoring risky modules, OWASP / MITRE ATT&CK / ASVS walks.
|
|
65
|
+
|
|
66
|
+
- **Read `docs/shift-left.md`** — pointers into the `rafter-code-review` sibling skill for structured OWASP/ASVS-driven code analysis.
|
|
67
|
+
- For automated SAST findings first, see branch (a).
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Repo-Specific Security Rules
|
|
72
|
+
|
|
73
|
+
Projects can declare a `docs:` list in `.rafter.yml` pointing at repo-specific security guides, threat models, or compliance policies — files or URLs. **Before doing any security-relevant work (scanning, reviewing, writing auth/crypto/input-handling code), check for these docs:**
|
|
87
74
|
|
|
88
|
-
Or create `.env` file:
|
|
89
75
|
```bash
|
|
90
|
-
|
|
76
|
+
rafter docs list # enumerate available docs (no network)
|
|
77
|
+
rafter docs list --tag threat-model # filter by tag
|
|
78
|
+
rafter docs show secure-coding # read one by id (fetches + caches URLs)
|
|
79
|
+
rafter docs show owasp # id OR tag — if a tag matches, all tagged docs are concatenated
|
|
91
80
|
```
|
|
92
81
|
|
|
93
|
-
|
|
82
|
+
If docs exist, treat them as authoritative project rules: they override general guidance when they conflict. If no docs are configured (`exit 3` / "No docs configured"), fall back to the standard OWASP / ASVS advice.
|
|
94
83
|
|
|
95
|
-
|
|
96
|
-
1. Trigger scan: `rafter run`
|
|
97
|
-
2. Get results: `rafter get <scan-id>`
|
|
98
|
-
3. Review findings and suggest fixes
|
|
84
|
+
MCP-connected agents: the same surface is exposed as the `rafter://docs` resource plus `list_docs` / `get_doc` tools.
|
|
99
85
|
|
|
100
|
-
|
|
101
|
-
1. Check quota: `rafter usage`
|
|
102
|
-
2. Trigger scan on feature branch: `rafter run --branch feature-branch`
|
|
103
|
-
3. Review results before creating PR
|
|
86
|
+
## Fast Path (most common)
|
|
104
87
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
88
|
+
```bash
|
|
89
|
+
rafter scan local . # secrets, offline, exit 0/1/2
|
|
90
|
+
rafter run # remote SAST/SCA (auto-detects repo/branch)
|
|
91
|
+
rafter get <scan-id> # fetch results
|
|
92
|
+
rafter usage # check API quota
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- Exit `0` = clean / no findings
|
|
96
|
+
- Exit `1` = findings detected OR error
|
|
97
|
+
- Exit `2` = invalid input / scan not found
|
|
109
98
|
|
|
110
|
-
|
|
99
|
+
Full CLI tree: **Read `docs/cli-reference.md`**. Full digest: `rafter brief commands`.
|
|
111
100
|
|
|
112
|
-
|
|
113
|
-
- **Code security findings** - SAST issues, security anti-patterns, hardcoded credentials
|
|
114
|
-
- **Configuration issues** - Insecure settings, exposed secrets
|
|
115
|
-
- **Severity levels** - Each finding rated by risk impact
|
|
101
|
+
## Configuration
|
|
116
102
|
|
|
117
|
-
|
|
103
|
+
Remote scanning needs an API key:
|
|
118
104
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
4. **Actionable recommendations** - Provide specific fixes for each finding
|
|
123
|
-
5. **Graceful degradation** - If RAFTER_API_KEY is not set, use `rafter scan local` instead. Don't let a missing key block the workflow.
|
|
105
|
+
```bash
|
|
106
|
+
export RAFTER_API_KEY="..." # or put it in .env
|
|
107
|
+
```
|
|
124
108
|
|
|
125
|
-
|
|
109
|
+
Without a key, local scanning still works fully — do not block the workflow.
|
|
126
110
|
|
|
127
|
-
|
|
128
|
-
- Wait for scan completion or show scan ID for later retrieval
|
|
129
|
-
- Parse JSON output for structured analysis
|
|
130
|
-
- Link findings to specific files and lines when available
|
|
111
|
+
## Strengthen the Project
|
|
131
112
|
|
|
132
|
-
|
|
113
|
+
If this repo doesn't have Rafter wired in yet:
|
|
133
114
|
|
|
134
|
-
|
|
135
|
-
- `rafter
|
|
136
|
-
-
|
|
137
|
-
-
|
|
138
|
-
- `rafter brief setup/<platform>` — platform-specific integration guide
|
|
115
|
+
- `rafter agent install-hook` — pre-commit secret scan
|
|
116
|
+
- `rafter ci init` — CI workflow with scanning
|
|
117
|
+
- `.rafter.yml` — project-specific policy
|
|
118
|
+
- `rafter brief setup/<platform>` — per-agent integration guide
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Rafter Remote Backend — Fast vs Plus
|
|
2
|
+
|
|
3
|
+
When to reach for the Rafter API instead of (or in addition to) the local scanner, and what to expect in terms of depth, cost, and latency.
|
|
4
|
+
|
|
5
|
+
## Local vs Remote — Which First?
|
|
6
|
+
|
|
7
|
+
| Question | Answer |
|
|
8
|
+
|---|---|
|
|
9
|
+
| "Are there leaked secrets in this diff/repo?" | **Local first** (`rafter scan local .`). Deterministic, offline, sub-second. |
|
|
10
|
+
| "Any SAST issues — SQLi, XSS, insecure deserialization, weak crypto?" | **Remote** (`rafter run`). Needs the backend's analyzers. |
|
|
11
|
+
| "Are my dependencies vulnerable (CVEs)?" | **Remote** — SCA runs server-side. |
|
|
12
|
+
| "I'm in a CI pipeline without a `RAFTER_API_KEY`" | **Local only**. Don't fail the build on a missing key. |
|
|
13
|
+
| "I need a deep, agent-driven review with hypotheses and cross-file reasoning" | **Remote plus** (`--mode plus`). |
|
|
14
|
+
|
|
15
|
+
Rule of thumb: local is a guardrail; remote is a review.
|
|
16
|
+
|
|
17
|
+
## Setup
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
export RAFTER_API_KEY="..."
|
|
21
|
+
# or
|
|
22
|
+
echo "RAFTER_API_KEY=..." >> .env
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Private GitHub repos need `RAFTER_GITHUB_TOKEN` (or `--github-token`) so the backend can clone the ref.
|
|
26
|
+
|
|
27
|
+
Check quota with `rafter usage` before firing a batch of scans.
|
|
28
|
+
|
|
29
|
+
If the key is missing, `rafter run` exits with a clear error — **do not** prompt the user mid-flow; recommend `rafter scan local` and move on.
|
|
30
|
+
|
|
31
|
+
## Modes
|
|
32
|
+
|
|
33
|
+
### `--mode fast` (default)
|
|
34
|
+
|
|
35
|
+
Deterministic SAST + SCA + secret detection via the analyzer pipeline. Same input → same output. Good for CI gates and PR checks.
|
|
36
|
+
|
|
37
|
+
- **Latency**: typically seconds to a couple of minutes, depending on repo size.
|
|
38
|
+
- **Cost**: lowest per-scan. Free tier covers casual use. See `rafter brief pricing`.
|
|
39
|
+
- **Output**: stable JSON; findings carry `ruleId`, `severity`, `file`, `line`, `confidence`.
|
|
40
|
+
|
|
41
|
+
### `--mode plus`
|
|
42
|
+
|
|
43
|
+
Agentic deep-dive pass on top of fast mode: cross-file reasoning, data-flow hypotheses, design-level flags. Non-deterministic but reproducible in aggregate.
|
|
44
|
+
|
|
45
|
+
- **Latency**: minutes (larger repos can take longer).
|
|
46
|
+
- **Cost**: higher per-scan. Use when fast mode has flagged something worth triaging deeply, or on a release candidate.
|
|
47
|
+
- **Output**: same JSON shape as fast mode, plus narrative `notes` and higher-confidence chains.
|
|
48
|
+
|
|
49
|
+
Recommended flow:
|
|
50
|
+
1. `rafter scan local .` — secrets guardrail in dev loop.
|
|
51
|
+
2. `rafter run --mode fast` — every PR in CI.
|
|
52
|
+
3. `rafter run --mode plus` — before release, or when a fast-mode finding needs deeper context.
|
|
53
|
+
|
|
54
|
+
## Authentication & Data Handling
|
|
55
|
+
|
|
56
|
+
- The backend clones the specified ref, runs analysis, returns results, and **deletes the code**. No long-term retention of source.
|
|
57
|
+
- Scan artifacts (findings JSON, reports) are retained so `rafter get <scan-id>` works after the fact.
|
|
58
|
+
- Self-hosted / VPC deployments are an enterprise option; see rafter.so.
|
|
59
|
+
|
|
60
|
+
## Output Contract
|
|
61
|
+
|
|
62
|
+
Every remote scan returns:
|
|
63
|
+
|
|
64
|
+
```jsonc
|
|
65
|
+
{
|
|
66
|
+
"scanId": "scan_...",
|
|
67
|
+
"status": "completed" | "running" | "failed",
|
|
68
|
+
"mode": "fast" | "plus",
|
|
69
|
+
"findings": [
|
|
70
|
+
{ "ruleId": "...", "severity": "critical|high|medium|low|info",
|
|
71
|
+
"file": "...", "line": 42, "confidence": "high|medium|low",
|
|
72
|
+
"title": "...", "description": "...", "recommendation": "..." }
|
|
73
|
+
],
|
|
74
|
+
"summary": { "critical": 0, "high": 2, "medium": 5, "low": 3 }
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
See `shared-docs/CLI_SPEC.md` for the full schema. See `docs/finding-triage.md` for how to read a finding.
|
|
79
|
+
|
|
80
|
+
## Async / Non-Blocking Scans
|
|
81
|
+
|
|
82
|
+
`rafter run --skip-interactive` returns the `scan_id` immediately. Poll later:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
SCAN=$(rafter run --skip-interactive --format json | jq -r .scanId)
|
|
86
|
+
# ... do other work ...
|
|
87
|
+
rafter get "$SCAN" --format json
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
This is the pattern for long-running CI jobs and background agent loops.
|
|
91
|
+
|
|
92
|
+
## Latency & Cost Expectations (rule of thumb)
|
|
93
|
+
|
|
94
|
+
| Repo size | fast | plus |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| < 5k LOC | ~10–30s | ~1–3 min |
|
|
97
|
+
| 5k – 50k LOC | ~30s – 2 min | ~3–10 min |
|
|
98
|
+
| 50k+ LOC | minutes | tens of minutes |
|
|
99
|
+
|
|
100
|
+
Plus mode's latency scales with "how much there is to reason about", not strictly LOC. Don't block an agent turn on plus; use `--skip-interactive` and poll.
|
|
101
|
+
|
|
102
|
+
## When NOT to use the remote backend
|
|
103
|
+
|
|
104
|
+
- You're iterating locally on a tiny diff — local scan + lint is faster.
|
|
105
|
+
- You have no network / no API key — stay local.
|
|
106
|
+
- You've already run the same scan ten minutes ago with no code changes — cache the last result instead of re-scanning.
|