Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 184 additions & 28 deletions lola-module/skills/secdevai-tool/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,46 @@ Run external security analysis tools inside isolated, read-only containers. Invo
| scorecard | https://github.com/ossf/scorecard | `gcr.io/openssf/scorecard:stable` | All |
| semgrep | https://github.com/semgrep/semgrep | `local/semgrep` (built locally) | Multi-language |

```yaml
tool_resolution:
python:
tools:
- bandit
- semgrep
- scorecard

go:
tools:
- gosec
- semgrep
- scorecard

java:
tools:
- semgrep
- scorecard

javascript:
tools:
- semgrep
- scorecard

rust:
tools:
- semgrep
- scorecard
```

## Prerequisites

Tools run exclusively inside containers for isolation and reproducibility. A container runtime is required:

- **Podman** (recommended): `brew install podman` / `dnf install podman` / `apt install podman`
- **Docker**: https://docs.docker.com/get-docker/

The helper script `scripts/container-run.sh` auto-detects podman or docker at runtime, runs containers with hardened defaults (all capabilities dropped, no-new-privileges, network disabled, resource limits), and prints installation guidance if neither runtime is found.
The helper script `scripts/container-run.sh` auto-detects `podman` or `docker` at runtime, runs containers with hardened defaults (all capabilities dropped, no-new-privileges, network disabled, resource limits), and prints installation guidance if neither runtime is found.

Note: All scripts are under the BASE directory (e.g.: `.claude/` or `.cursor/`).
**Note**: All scripts are under the `${BASE_DIR}` directory (e.g.: `.claude/` or `.cursor/`).

## Expected Response

Expand All @@ -50,54 +80,180 @@ When this skill is invoked, follow these steps:
- Show usage examples
- Do NOT run any tool automatically — wait for user input

```yaml
input_schema:
tool:
- bandit
- gosec
- scorecard
- semgrep
- all
```

### Step 2: Run Tool

Use `scripts/container-run.sh` to run the container image for the chosen tool. The script auto-detects podman/docker, mounts the current directory read-only at `/src`, and forwards any extra arguments to the container entrypoint.
Use `${BASE_DIR}/scripts/container-run.sh` to run the container image for the chosen tool. The script auto-detects podman/docker, mounts the current directory read-only at `/src`, and forwards any extra arguments to the container entrypoint.

```bash
```sh
# Usage: scripts/container-run.sh [--env K=V]... <image> [args...]
# Network is always disabled (--network=none).
```

#### Tool: Bandit

**Usage:**
```sh
# bandit (Python)
scripts/container-run.sh ghcr.io/pycqa/bandit/bandit -r . -f json -q
${BASE_DIR}/scripts/container-run.sh ghcr.io/pycqa/bandit/bandit -r . -f json -q
```

#### Tool: GoSec

**Usage:**
```sh
# gosec (Go)
scripts/container-run.sh ghcr.io/securego/gosec:latest -fmt=sarif ./...
${BASE_DIR}/scripts/container-run.sh ghcr.io/securego/gosec:latest -fmt=sarif ./...
```

# scorecard (local-only, filesystem checks only — no GitHub API access)
scripts/container-run.sh gcr.io/openssf/scorecard:stable --local . --format json
#### Tool: Scorecard

# semgrep — requires a locally built image (see build instructions below)
scripts/container-run.sh --env HOME=/tmp local/semgrep scan /src --config /sgrules/<lang> --sarif --metrics off --disable-version-check
**Usage:**
```sh
# scorecard (local-only, filesystem checks only — no GitHub API access)
${BASE_DIR}/scripts/container-run.sh gcr.io/openssf/scorecard:stable --local . --format json
```

**Scorecard**: Runs in `--local` mode only (no network, no GitHub token). Filesystem-based checks work (pinned dependencies, SECURITY.md, dangerous workflows); checks requiring the GitHub API (branch protection, CI/CD status) are skipped.

**Semgrep**: Uses a locally built image (`local/semgrep`) that bundles two offline rule sets:
#### Tool: semgrep

**Semgrep**: Uses a locally built image (`secdevai/semgrep:local`) that bundles two offline rule sets:
- `/sgrules` — [semgrep/semgrep-rules](https://github.com/semgrep/semgrep-rules) (community rules)
- `/sgrules-trail` — [trailofbits/semgrep-rules](https://github.com/trailofbits/semgrep-rules) (security-focused, AGPL-3.0)

Because the rules are baked into the image, the container runs with `--network=none` like all other tools. `--env HOME=/tmp` is required because semgrep writes cache state to `$HOME` and the container filesystem is read-only (only `/tmp` is writable).
**Build Semgrep container**: (`secdevai/semgrep:local`)
```sh
${BASE_DIR}/scripts/build-semgrep.sh
```

Build the image once from the project root (network required at build time only). Determine `<platform-dir>` from the deployment context (`.cursor`, `.claude`, or `.gemini`):
**Semgrep config resolution**
```yaml
semgrep_config_resolution:
python:
configs:
- /sgrules/python

go:
configs:
- /sgrules/go
- /sgrules-trail/go

javascript:
configs:
- /sgrules/javascript

typescript:
configs:
- /sgrules/typescript

java:
configs:
- /sgrules/java

ruby:
configs:
- /sgrules/ruby
- /sgrules-trail/ruby

rust:
configs:
- /sgrules/rust
- /sgrules-trail/rs

all:
configs:
- /sgrules
- /sgrules-trail
```

**Language detection:**
```yaml
language_detection:
python:
files:
- pyproject.toml
- requirements.txt
- setup.py
- Pipfile
- poetry.lock
- "*.py"

go:
files:
- go.mod
- go.sum
- "*.go"

typescript:
files:
- tsconfig.json
- "*.ts"
- "*.tsx"

javascript:
files:
- package.json
- "*.js"
- "*.jsx"

java:
files:
- pom.xml
- build.gradle
- build.gradle.kts
- "*.java"

ruby:
files:
- Gemfile
- Gemfile.lock
- "*.rb"

rust:
files:
- Cargo.toml
- Cargo.lock
- "*.rs"
```

Select `--config` based on the detected project language.

**Usage:**
```sh
${BASE_DIR}/scripts/container-run.sh \
--env HOME=/tmp \
secdevai/semgrep:local \
scan /src \
--config /sgrules/<lang> \
--sarif \
--metrics off \
--disable-version-check
```

```bash
docker buildx build . -t local/semgrep \
-f <platform-dir>/lola-module/skills/secdevai-tool/scripts/Dockerfile.semgrep
**Example resolution for Golang:**
```sh
${BASE_DIR}/scripts/container-run.sh \
--env HOME=/tmp \
secdevai/semgrep:local \
scan /src \
--config /sgrules/go \
--config /sgrules-trail/go \
--sarif \
--metrics off \
--disable-version-check
```

Select `--config` based on the detected project language:

| Language | `--config` flags |
|----------|-----------------|
| Python | `--config /sgrules/python` |
| Go | `--config /sgrules/go --config /sgrules-trail/go` |
| JavaScript | `--config /sgrules/javascript` |
| TypeScript | `--config /sgrules/typescript` |
| Java | `--config /sgrules/java` |
| Ruby | `--config /sgrules/ruby --config /sgrules-trail/ruby` |
| Rust | `--config /sgrules/rust --config /sgrules-trail/rs` |
| All | `--config /sgrules --config /sgrules-trail` |
#### Tool: all

**If `all` is specified**: detect the project language and run each relevant(see Available Tools) tool sequentially, collecting all JSON output.

Expand Down
40 changes: 40 additions & 0 deletions lola-module/skills/secdevai-tool/scripts/build-semgrep.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/bash

set -euo pipefail

detect_runtime() {
if command -v podman &>/dev/null; then
echo "podman"
elif command -v docker &>/dev/null; then
echo "docker"
else
cat >&2 <<'MSG'
Error: No container runtime found.

SecDevAI requires podman or docker to run security tools in isolated,
read-only containers. Please install one of the following:

Podman (recommended):
macOS : brew install podman && podman machine init && podman machine start
Fedora : sudo dnf install podman
Ubuntu : sudo apt install podman

Docker:
All OS : https://docs.docker.com/get-docker/

After installing, re-run this command.
MSG
exit 1
fi
}

runtime="$(detect_runtime)"
echo "Using runtime: ${runtime}" >&2

BASE_DIR="$(dirname "$0")"
IMAGE_TAG="secdevai/semgrep:local"

exec "$runtime" build \
-t "${IMAGE_TAG}" \
-f "${BASE_DIR}/Dockerfile.semgrep" \
${BASE_DIR}