@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
package/README.md
CHANGED
|
@@ -153,17 +153,29 @@ Initialize agent security system.
|
|
|
153
153
|
|
|
154
154
|
**Options:**
|
|
155
155
|
- `--risk-level <level>` - Set risk level: `minimal`, `moderate`, or `aggressive` (default: `moderate`)
|
|
156
|
-
- `--
|
|
156
|
+
- `--with-openclaw` - Install OpenClaw integration
|
|
157
|
+
- `--with-claude-code` - Install Claude Code integration
|
|
158
|
+
- `--with-codex` - Install Codex CLI integration
|
|
159
|
+
- `--with-gemini` - Install Gemini CLI integration
|
|
160
|
+
- `--with-aider` - Install Aider integration
|
|
161
|
+
- `--with-cursor` - Install Cursor integration
|
|
162
|
+
- `--with-windsurf` - Install Windsurf integration
|
|
163
|
+
- `--with-continue` - Install Continue.dev integration
|
|
164
|
+
- `--with-gitleaks` - Download and install Gitleaks binary
|
|
165
|
+
- `--all` - Install all detected integrations and download Gitleaks
|
|
157
166
|
|
|
158
167
|
**What it does:**
|
|
159
168
|
- Creates `~/.rafter/config.json` configuration
|
|
160
169
|
- Initializes directory structure
|
|
161
|
-
- Detects
|
|
170
|
+
- Detects available agent environments
|
|
171
|
+
- Installs opted-in integrations (skills, hooks, MCP servers)
|
|
162
172
|
- Sets up audit logging
|
|
163
173
|
|
|
164
174
|
**Example:**
|
|
165
175
|
```bash
|
|
166
|
-
rafter agent init
|
|
176
|
+
rafter agent init # Config only, detect environments
|
|
177
|
+
rafter agent init --all # Install all detected integrations
|
|
178
|
+
rafter agent init --with-claude-code # Install Claude Code integration only
|
|
167
179
|
rafter agent init --risk-level aggressive
|
|
168
180
|
```
|
|
169
181
|
|
|
@@ -18,7 +18,7 @@ async function auditSkill(skillPath, opts) {
|
|
|
18
18
|
// Validate skill file exists
|
|
19
19
|
if (!fs.existsSync(skillPath)) {
|
|
20
20
|
console.error(`Error: Skill file not found: ${skillPath}`);
|
|
21
|
-
process.exit(
|
|
21
|
+
process.exit(2);
|
|
22
22
|
}
|
|
23
23
|
const absolutePath = path.resolve(skillPath);
|
|
24
24
|
const skillContent = fs.readFileSync(absolutePath, "utf-8");
|
|
@@ -143,7 +143,7 @@ function displayQuickScan(scan, skillName) {
|
|
|
143
143
|
else {
|
|
144
144
|
console.log(`⚠️ Secrets: ${scan.secrets} found`);
|
|
145
145
|
console.log(" → API keys, tokens, or credentials detected");
|
|
146
|
-
console.log(" → Run: rafter
|
|
146
|
+
console.log(" → Run: rafter scan local <path> for details");
|
|
147
147
|
}
|
|
148
148
|
// URLs
|
|
149
149
|
if (scan.urls.length === 0) {
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import { createHash } from "crypto";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
1
5
|
import { Command } from "commander";
|
|
2
6
|
import { AuditLogger } from "../../core/audit-logger.js";
|
|
7
|
+
import { ConfigManager } from "../../core/config-manager.js";
|
|
3
8
|
import { isAgentMode } from "../../utils/formatter.js";
|
|
4
9
|
export function createAuditCommand() {
|
|
5
10
|
return new Command("audit")
|
|
@@ -8,7 +13,12 @@ export function createAuditCommand() {
|
|
|
8
13
|
.option("--event <type>", "Filter by event type")
|
|
9
14
|
.option("--agent <type>", "Filter by agent type (openclaw, claude-code)")
|
|
10
15
|
.option("--since <date>", "Show entries since date (YYYY-MM-DD)")
|
|
16
|
+
.option("--share", "Generate a redacted excerpt for issue reports")
|
|
11
17
|
.action((opts) => {
|
|
18
|
+
if (opts.share) {
|
|
19
|
+
generateShareExcerpt();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
12
22
|
const logger = new AuditLogger();
|
|
13
23
|
const filter = {
|
|
14
24
|
limit: parseInt(opts.last, 10)
|
|
@@ -53,6 +63,92 @@ export function createAuditCommand() {
|
|
|
53
63
|
}
|
|
54
64
|
});
|
|
55
65
|
}
|
|
66
|
+
export function generateShareExcerpt() {
|
|
67
|
+
const version = getPkgVersion();
|
|
68
|
+
const os = `${process.platform}/${process.arch}`;
|
|
69
|
+
const timestamp = new Date().toISOString();
|
|
70
|
+
const config = new ConfigManager().loadWithPolicy();
|
|
71
|
+
const policyHash = computePolicyHash(config);
|
|
72
|
+
const riskLevel = getRiskLevel(config);
|
|
73
|
+
const logger = new AuditLogger();
|
|
74
|
+
const entries = logger.read({ limit: 5 });
|
|
75
|
+
const lines = [
|
|
76
|
+
"Rafter Audit Excerpt",
|
|
77
|
+
`Generated: ${timestamp}`,
|
|
78
|
+
"",
|
|
79
|
+
"Environment:",
|
|
80
|
+
` CLI: ${version}`,
|
|
81
|
+
` OS: ${os}`,
|
|
82
|
+
` Policy: sha256:${policyHash} (${riskLevel})`,
|
|
83
|
+
"",
|
|
84
|
+
"Recent events (last 5):",
|
|
85
|
+
];
|
|
86
|
+
if (entries.length === 0) {
|
|
87
|
+
lines.push(" (no entries)");
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
for (const entry of entries) {
|
|
91
|
+
const ts = entry.timestamp.replace("T", " ").replace(/\.\d+Z$/, "Z");
|
|
92
|
+
const eventPad = entry.eventType.padEnd(20);
|
|
93
|
+
const riskRaw = entry.action?.riskLevel ?? "low";
|
|
94
|
+
const riskPad = riskRaw.toUpperCase().padEnd(8);
|
|
95
|
+
const detail = formatShareDetail(entry);
|
|
96
|
+
lines.push(` ${ts} ${eventPad} ${riskPad} ${detail}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
lines.push("");
|
|
100
|
+
lines.push("Share this excerpt when reporting issues at https://github.com/Raftersecurity/rafter-cli/issues");
|
|
101
|
+
console.log(lines.join("\n"));
|
|
102
|
+
}
|
|
103
|
+
export function getPkgVersion() {
|
|
104
|
+
try {
|
|
105
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
106
|
+
const __dirname = path.dirname(__filename);
|
|
107
|
+
// Walk up from dist/commands/agent/ to find package.json
|
|
108
|
+
let dir = __dirname;
|
|
109
|
+
for (let i = 0; i < 6; i++) {
|
|
110
|
+
const candidate = path.join(dir, "package.json");
|
|
111
|
+
if (fs.existsSync(candidate)) {
|
|
112
|
+
const pkg = JSON.parse(fs.readFileSync(candidate, "utf-8"));
|
|
113
|
+
if (pkg.version)
|
|
114
|
+
return pkg.version;
|
|
115
|
+
}
|
|
116
|
+
dir = path.dirname(dir);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// fall through
|
|
121
|
+
}
|
|
122
|
+
return "unknown";
|
|
123
|
+
}
|
|
124
|
+
export function computePolicyHash(config) {
|
|
125
|
+
const patterns = config?.agent?.commandPolicy?.requireApproval ?? [];
|
|
126
|
+
const payload = JSON.stringify(patterns.slice().sort());
|
|
127
|
+
return createHash("sha256").update(payload).digest("hex").slice(0, 16);
|
|
128
|
+
}
|
|
129
|
+
export function getRiskLevel(config) {
|
|
130
|
+
return config?.agent?.riskLevel ?? "moderate";
|
|
131
|
+
}
|
|
132
|
+
export function formatShareDetail(entry) {
|
|
133
|
+
const action = entry.resolution.actionTaken;
|
|
134
|
+
const suffix = `[${action}]`;
|
|
135
|
+
if (entry.eventType === "secret_detected") {
|
|
136
|
+
const reason = entry.securityCheck.reason ?? "";
|
|
137
|
+
return `${reason} ${suffix}`;
|
|
138
|
+
}
|
|
139
|
+
if (entry.action?.command) {
|
|
140
|
+
return `${truncateCommand(entry.action.command, 60)} ${suffix}`;
|
|
141
|
+
}
|
|
142
|
+
if (entry.securityCheck.reason) {
|
|
143
|
+
return `${entry.securityCheck.reason} ${suffix}`;
|
|
144
|
+
}
|
|
145
|
+
return suffix;
|
|
146
|
+
}
|
|
147
|
+
export function truncateCommand(cmd, maxLen = 60) {
|
|
148
|
+
if (cmd.length <= maxLen)
|
|
149
|
+
return cmd;
|
|
150
|
+
return cmd.slice(0, maxLen) + "...";
|
|
151
|
+
}
|
|
56
152
|
function getEventIndicator(eventType) {
|
|
57
153
|
if (isAgentMode()) {
|
|
58
154
|
const tagMap = {
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { fmt } from "../../utils/formatter.js";
|
|
6
|
+
import { RegexScanner } from "../../scanners/regex-scanner.js";
|
|
7
|
+
import { GitleaksScanner } from "../../scanners/gitleaks.js";
|
|
8
|
+
import { ConfigManager } from "../../core/config-manager.js";
|
|
9
|
+
const BASELINE_PATH = path.join(os.homedir(), ".rafter", "baseline.json");
|
|
10
|
+
function loadBaseline() {
|
|
11
|
+
if (!fs.existsSync(BASELINE_PATH)) {
|
|
12
|
+
return { version: 1, created: "", updated: "", entries: [] };
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(fs.readFileSync(BASELINE_PATH, "utf-8"));
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return { version: 1, created: "", updated: "", entries: [] };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function saveBaseline(baseline) {
|
|
22
|
+
const dir = path.dirname(BASELINE_PATH);
|
|
23
|
+
if (!fs.existsSync(dir)) {
|
|
24
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
fs.writeFileSync(BASELINE_PATH, JSON.stringify(baseline, null, 2), "utf-8");
|
|
27
|
+
}
|
|
28
|
+
export function createBaselineCommand() {
|
|
29
|
+
const baseline = new Command("baseline")
|
|
30
|
+
.description("Manage the findings baseline (allowlist for known findings)");
|
|
31
|
+
baseline.addCommand(createBaselineCreateCommand());
|
|
32
|
+
baseline.addCommand(createBaselineShowCommand());
|
|
33
|
+
baseline.addCommand(createBaselineClearCommand());
|
|
34
|
+
baseline.addCommand(createBaselineAddCommand());
|
|
35
|
+
return baseline;
|
|
36
|
+
}
|
|
37
|
+
function createBaselineCreateCommand() {
|
|
38
|
+
return new Command("create")
|
|
39
|
+
.description("Scan and save all current findings as the baseline")
|
|
40
|
+
.argument("[path]", "Path to scan", ".")
|
|
41
|
+
.option("--engine <engine>", "Scan engine: gitleaks or patterns", "auto")
|
|
42
|
+
.action(async (scanPath, opts) => {
|
|
43
|
+
const validEngines = ["auto", "gitleaks", "patterns"];
|
|
44
|
+
const engineValue = opts.engine || "auto";
|
|
45
|
+
if (!validEngines.includes(engineValue)) {
|
|
46
|
+
console.error(`Invalid engine: ${engineValue}. Valid values: ${validEngines.join(", ")}`);
|
|
47
|
+
process.exit(2);
|
|
48
|
+
}
|
|
49
|
+
const resolvedPath = path.resolve(scanPath);
|
|
50
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
51
|
+
console.error(`Error: Path not found: ${resolvedPath}`);
|
|
52
|
+
process.exit(2);
|
|
53
|
+
}
|
|
54
|
+
const manager = new ConfigManager();
|
|
55
|
+
const cfg = manager.loadWithPolicy();
|
|
56
|
+
const scanCfg = cfg.agent?.scan;
|
|
57
|
+
console.error(`Scanning ${resolvedPath} to build baseline...`);
|
|
58
|
+
const engine = await selectEngine(opts.engine || "auto");
|
|
59
|
+
let results;
|
|
60
|
+
if (fs.statSync(resolvedPath).isDirectory()) {
|
|
61
|
+
results = await scanDirectory(resolvedPath, engine, scanCfg);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
results = await scanFile(resolvedPath, engine);
|
|
65
|
+
}
|
|
66
|
+
const now = new Date().toISOString();
|
|
67
|
+
const entries = [];
|
|
68
|
+
for (const r of results) {
|
|
69
|
+
for (const m of r.matches) {
|
|
70
|
+
entries.push({
|
|
71
|
+
file: r.file,
|
|
72
|
+
line: m.line ?? null,
|
|
73
|
+
pattern: m.pattern.name,
|
|
74
|
+
addedAt: now,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const existing = loadBaseline();
|
|
79
|
+
const baseline = {
|
|
80
|
+
version: 1,
|
|
81
|
+
created: existing.created || now,
|
|
82
|
+
updated: now,
|
|
83
|
+
entries,
|
|
84
|
+
};
|
|
85
|
+
saveBaseline(baseline);
|
|
86
|
+
if (entries.length === 0) {
|
|
87
|
+
console.log(fmt.success("No findings — baseline is empty (all clean)"));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
console.log(fmt.success(`Baseline saved: ${entries.length} finding(s) recorded`));
|
|
91
|
+
console.log(` Location: ${BASELINE_PATH}`);
|
|
92
|
+
console.log();
|
|
93
|
+
console.log("Future scans with --baseline will suppress these findings.");
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function createBaselineShowCommand() {
|
|
98
|
+
return new Command("show")
|
|
99
|
+
.description("Show current baseline entries")
|
|
100
|
+
.option("--json", "Output as JSON")
|
|
101
|
+
.action((opts) => {
|
|
102
|
+
const baseline = loadBaseline();
|
|
103
|
+
if (opts.json) {
|
|
104
|
+
console.log(JSON.stringify(baseline, null, 2));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (baseline.entries.length === 0) {
|
|
108
|
+
console.log("Baseline is empty. Run: rafter agent baseline create");
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
console.log(`Baseline: ${baseline.entries.length} entries`);
|
|
112
|
+
if (baseline.updated) {
|
|
113
|
+
console.log(`Updated: ${baseline.updated}`);
|
|
114
|
+
}
|
|
115
|
+
console.log();
|
|
116
|
+
// Group by file
|
|
117
|
+
const byFile = new Map();
|
|
118
|
+
for (const entry of baseline.entries) {
|
|
119
|
+
const list = byFile.get(entry.file) || [];
|
|
120
|
+
list.push(entry);
|
|
121
|
+
byFile.set(entry.file, list);
|
|
122
|
+
}
|
|
123
|
+
for (const [file, entries] of byFile) {
|
|
124
|
+
console.log(fmt.info(file));
|
|
125
|
+
for (const e of entries) {
|
|
126
|
+
const loc = e.line != null ? `line ${e.line}` : "unknown location";
|
|
127
|
+
console.log(` ${e.pattern} (${loc})`);
|
|
128
|
+
}
|
|
129
|
+
console.log();
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function createBaselineClearCommand() {
|
|
134
|
+
return new Command("clear")
|
|
135
|
+
.description("Remove all baseline entries")
|
|
136
|
+
.action(() => {
|
|
137
|
+
if (!fs.existsSync(BASELINE_PATH)) {
|
|
138
|
+
console.log("No baseline file found — nothing to clear.");
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
fs.unlinkSync(BASELINE_PATH);
|
|
142
|
+
console.log(fmt.success("Baseline cleared"));
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
function createBaselineAddCommand() {
|
|
146
|
+
return new Command("add")
|
|
147
|
+
.description("Manually add a finding to the baseline")
|
|
148
|
+
.requiredOption("--file <path>", "File path")
|
|
149
|
+
.requiredOption("--pattern <name>", "Pattern name (e.g. 'AWS Access Key')")
|
|
150
|
+
.option("--line <number>", "Line number")
|
|
151
|
+
.action((opts) => {
|
|
152
|
+
const baseline = loadBaseline();
|
|
153
|
+
const now = new Date().toISOString();
|
|
154
|
+
const entry = {
|
|
155
|
+
file: path.resolve(opts.file),
|
|
156
|
+
line: opts.line != null ? parseInt(opts.line, 10) : null,
|
|
157
|
+
pattern: opts.pattern,
|
|
158
|
+
addedAt: now,
|
|
159
|
+
};
|
|
160
|
+
baseline.entries.push(entry);
|
|
161
|
+
baseline.updated = now;
|
|
162
|
+
if (!baseline.created)
|
|
163
|
+
baseline.created = now;
|
|
164
|
+
saveBaseline(baseline);
|
|
165
|
+
console.log(fmt.success(`Added to baseline: ${opts.pattern} in ${opts.file}`));
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
// ── helpers ─────────────────────────────────────────────────────────
|
|
169
|
+
async function selectEngine(preference) {
|
|
170
|
+
if (preference === "patterns")
|
|
171
|
+
return "patterns";
|
|
172
|
+
if (preference === "gitleaks") {
|
|
173
|
+
const g = new GitleaksScanner();
|
|
174
|
+
return (await g.isAvailable()) ? "gitleaks" : "patterns";
|
|
175
|
+
}
|
|
176
|
+
if (preference !== "auto") {
|
|
177
|
+
console.error(`Invalid engine: ${preference}. Valid values: auto, gitleaks, patterns`);
|
|
178
|
+
process.exit(2);
|
|
179
|
+
}
|
|
180
|
+
const g = new GitleaksScanner();
|
|
181
|
+
return (await g.isAvailable()) ? "gitleaks" : "patterns";
|
|
182
|
+
}
|
|
183
|
+
async function scanFile(filePath, engine) {
|
|
184
|
+
if (engine === "gitleaks") {
|
|
185
|
+
try {
|
|
186
|
+
const g = new GitleaksScanner();
|
|
187
|
+
const r = await g.scanFile(filePath);
|
|
188
|
+
return r.matches.length > 0 ? [r] : [];
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
const s = new RegexScanner();
|
|
192
|
+
const r = s.scanFile(filePath);
|
|
193
|
+
return r.matches.length > 0 ? [r] : [];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const s = new RegexScanner();
|
|
197
|
+
const r = s.scanFile(filePath);
|
|
198
|
+
return r.matches.length > 0 ? [r] : [];
|
|
199
|
+
}
|
|
200
|
+
async function scanDirectory(dirPath, engine, scanCfg) {
|
|
201
|
+
if (engine === "gitleaks") {
|
|
202
|
+
try {
|
|
203
|
+
const g = new GitleaksScanner();
|
|
204
|
+
return await g.scanDirectory(dirPath);
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
const s = new RegexScanner();
|
|
208
|
+
return s.scanDirectory(dirPath, { excludePaths: scanCfg?.excludePaths });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const s = new RegexScanner();
|
|
212
|
+
return s.scanDirectory(dirPath, { excludePaths: scanCfg?.excludePaths });
|
|
213
|
+
}
|
|
@@ -29,7 +29,7 @@ export function createExecCommand() {
|
|
|
29
29
|
if (scanResult.secretsFound) {
|
|
30
30
|
console.error(`\n${fmt.warning("Secrets detected in staged files!")}\n`);
|
|
31
31
|
console.error(`Found ${scanResult.count} secret(s) in ${scanResult.files} file(s)`);
|
|
32
|
-
console.error(`\nRun 'rafter
|
|
32
|
+
console.error(`\nRun 'rafter scan local' for details.\n`);
|
|
33
33
|
interceptor.logEvaluation(evaluation, "blocked");
|
|
34
34
|
process.exit(1);
|
|
35
35
|
}
|
|
@@ -8,6 +8,8 @@ import { createAuditSkillCommand } from "./audit-skill.js";
|
|
|
8
8
|
import { createInstallHookCommand } from "./install-hook.js";
|
|
9
9
|
import { createVerifyCommand } from "./verify.js";
|
|
10
10
|
import { createStatusCommand } from "./status.js";
|
|
11
|
+
import { createUpdateGitleaksCommand } from "./update-gitleaks.js";
|
|
12
|
+
import { createBaselineCommand } from "./baseline.js";
|
|
11
13
|
export function createAgentCommand() {
|
|
12
14
|
const agent = new Command("agent")
|
|
13
15
|
.description("Agent security features");
|
|
@@ -21,5 +23,7 @@ export function createAgentCommand() {
|
|
|
21
23
|
agent.addCommand(createInstallHookCommand());
|
|
22
24
|
agent.addCommand(createVerifyCommand());
|
|
23
25
|
agent.addCommand(createStatusCommand());
|
|
26
|
+
agent.addCommand(createUpdateGitleaksCommand());
|
|
27
|
+
agent.addCommand(createBaselineCommand());
|
|
24
28
|
return agent;
|
|
25
29
|
}
|