$npx -y skills add Rune-kit/rune --skill sastStatic analysis tool runner. Wraps ESLint, Semgrep, Bandit, Clippy, and language-specific analyzers with unified severity output. Use when deeper code analysis needed beyond pattern matching.
| 1 | # sast |
| 2 | |
| 3 | ## Purpose |
| 4 | |
| 5 | Unified static analysis tool runner. While `sentinel` does regex-based security pattern matching and `verification` runs lint/type/test/build, SAST goes deeper — running dedicated static analysis tools that understand data flow, taint tracking, and language-specific vulnerability patterns. |
| 6 | |
| 7 | Sentinel catches obvious patterns (hardcoded secrets, SQL string concat). SAST catches subtle ones (tainted data flowing through 3 function calls to a sink, unsafe deserialization behind a wrapper). |
| 8 | |
| 9 | ## Triggers |
| 10 | |
| 11 | - Called by `sentinel` (L2) when deep analysis needed beyond pattern matching |
| 12 | - Called by `audit` (L2) during security dimension assessment |
| 13 | - Called by `cook` (L1) on security-sensitive code (auth, crypto, payments) |
| 14 | - `/rune sast` — manual static analysis scan |
| 15 | |
| 16 | ## Calls (outbound) |
| 17 | |
| 18 | None — pure runner using Bash for all tools. |
| 19 | |
| 20 | ## Called By (inbound) |
| 21 | |
| 22 | - `sentinel` (L2): deep analysis beyond regex patterns |
| 23 | - `audit` (L2): security dimension in full audit |
| 24 | - `cook` (L1): security-sensitive code paths |
| 25 | - `review` (L2): when security patterns detected in diff |
| 26 | |
| 27 | ## Execution |
| 28 | |
| 29 | ### Step 1 — Detect Language and Tools |
| 30 | |
| 31 | Use `Glob` to detect project language and available tools: |
| 32 | |
| 33 | | Indicator | Language | Primary Tool | Fallback | |
| 34 | |---|---|---|---| |
| 35 | | `package.json` | JavaScript/TypeScript | `npx eslint --ext .js,.ts,.tsx` | `npx oxlint` | |
| 36 | | `tsconfig.json` | TypeScript | `npx tsc --noEmit` + ESLint | — | |
| 37 | | `pyproject.toml` / `setup.py` | Python | `bandit -r . -f json` | `ruff check --select S .` | |
| 38 | | `Cargo.toml` | Rust | `cargo clippy -- -D warnings` | `cargo audit` | |
| 39 | | `go.mod` | Go | `govulncheck ./...` | `go vet ./...` | |
| 40 | | `.semgrep.yml` / any | Any | `semgrep --config auto` | — | |
| 41 | |
| 42 | Check tool availability: |
| 43 | ``` |
| 44 | Bash: command -v <tool> 2>/dev/null |
| 45 | → If not installed: mark as SKIP with install instruction |
| 46 | → If installed: proceed with scan |
| 47 | ``` |
| 48 | |
| 49 | ### Step 2 — Run Primary Analysis |
| 50 | |
| 51 | Run the detected primary tool on changed files (or full project if no diff): |
| 52 | |
| 53 | ``` |
| 54 | For each available tool: |
| 55 | Bash: <tool command> 2>&1 |
| 56 | → Capture stdout + stderr |
| 57 | → Parse output into unified format (see Step 4) |
| 58 | → Record: exit code, finding count, execution time |
| 59 | ``` |
| 60 | |
| 61 | **Tool-specific commands:** |
| 62 | |
| 63 | ```bash |
| 64 | # ESLint (JS/TS) — security-focused rules |
| 65 | npx eslint --no-eslintrc --rule '{"no-eval": "error", "no-implied-eval": "error"}' <files> |
| 66 | |
| 67 | # Bandit (Python) — security scanner |
| 68 | bandit -r <path> -f json -ll # medium+ severity only |
| 69 | |
| 70 | # Semgrep (any language) — pattern-based analysis |
| 71 | semgrep --config auto --json --severity ERROR --severity WARNING <path> |
| 72 | |
| 73 | # Clippy (Rust) — lint + security |
| 74 | cargo clippy --all-targets -- -D warnings -W clippy::unwrap_used |
| 75 | |
| 76 | # govulncheck (Go) — vulnerability check |
| 77 | govulncheck ./... |
| 78 | ``` |
| 79 | |
| 80 | ### Step 3 — Run Semgrep (If Available) |
| 81 | |
| 82 | Semgrep provides cross-language analysis with community rules. Run regardless of primary language tool: |
| 83 | |
| 84 | ``` |
| 85 | IF semgrep is installed: |
| 86 | Bash: semgrep --config auto --json <changed-files-or-project> |
| 87 | → Parse JSON output |
| 88 | → Map severity: error→BLOCK, warning→WARN, info→INFO |
| 89 | ``` |
| 90 | |
| 91 | If semgrep is NOT installed, log INFO: "semgrep not installed — install with `pip install semgrep` for deeper cross-language analysis." |
| 92 | |
| 93 | ### Step 4 — Normalize to Unified Format |
| 94 | |
| 95 | Map all tool outputs to unified severity: |
| 96 | |
| 97 | ``` |
| 98 | BLOCK (must fix): |
| 99 | - Bandit: HIGH confidence + HIGH severity |
| 100 | - ESLint: error-level security rules |
| 101 | - Semgrep: ERROR severity |
| 102 | - Clippy: deny-level warnings |
| 103 | - govulncheck: any known vulnerability |
| 104 | |
| 105 | WARN (should fix): |
| 106 | - Bandit: MEDIUM confidence or MEDIUM severity |
| 107 | - ESLint: warning-level rules |
| 108 | - Semgrep: WARNING severity |
| 109 | - Clippy: warn-level suggestions |
| 110 | |
| 111 | INFO (informational): |
| 112 | - Bandit: LOW severity |
| 113 | - Semgrep: INFO severity |
| 114 | - Style/convention suggestions |
| 115 | ``` |
| 116 | |
| 117 | ### Step 5 — Report |
| 118 | |
| 119 | ``` |
| 120 | ## SAST Report |
| 121 | - **Status**: PASS | WARN | BLOCK |
| 122 | - **Tools Run**: [list with versions] |
| 123 | - **Tools Skipped**: [list with install instructions] |
| 124 | - **Files Scanned**: [count] |
| 125 | - **Findings**: [count by severity] |
| 126 | |
| 127 | ### BLOCK (must fix) |
| 128 | - `path/to/file.py:42` — [tool] Possible SQL injection via string formatting (B608) |
| 129 | - `path/to/auth.ts:15` — [semgrep] JWT token not verified before use |
| 130 | |
| 131 | ### WARN (should fix) |
| 132 | - `path/to/utils.py:88` — [bandit] Use of `subprocess` with shell=True (B602) |
| 133 | |
| 134 | ### INFO |
| 135 | - `path/to/config.ts:10` — [eslint] Prefer `const` over `let` for unchanging variable |
| 136 | |
| 137 | ### Tool Coverage |
| 138 | | Tool | Status | Findings | Duration | |
| 139 | |------|--------|----------|----------| |
| 140 | | ESLint | RAN | 2 WARN | 1.2s | |
| 141 | | Semgrep | SKIPPED | — | — (not installed) | |
| 142 | | Bandit | N/A | — | — (not Python) | |
| 143 | ``` |
| 144 | |
| 145 | ## Output Format |
| 146 | |
| 147 | SAST Report with status (PASS/WARN/BLOCK), t |