skillscan-trace 0.1.0__tar.gz
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.
- skillscan_trace-0.1.0/.dockerignore +17 -0
- skillscan_trace-0.1.0/.github/workflows/ci.yml +46 -0
- skillscan_trace-0.1.0/.github/workflows/codeql.yml +29 -0
- skillscan_trace-0.1.0/.github/workflows/release-pypi.yml +51 -0
- skillscan_trace-0.1.0/.gitignore +30 -0
- skillscan_trace-0.1.0/CONTRIBUTING.md +71 -0
- skillscan_trace-0.1.0/Dockerfile +64 -0
- skillscan_trace-0.1.0/PKG-INFO +200 -0
- skillscan_trace-0.1.0/PRIVACY.md +95 -0
- skillscan_trace-0.1.0/README.md +162 -0
- skillscan_trace-0.1.0/ROADMAP.md +80 -0
- skillscan_trace-0.1.0/docker-compose.yml +45 -0
- skillscan_trace-0.1.0/pyproject.toml +67 -0
- skillscan_trace-0.1.0/skillscan-trace.example.yaml +76 -0
- skillscan_trace-0.1.0/skillscan_trace/__init__.py +7 -0
- skillscan_trace-0.1.0/skillscan_trace/canary/__init__.py +14 -0
- skillscan_trace-0.1.0/skillscan_trace/canary/bash_ast.py +383 -0
- skillscan_trace-0.1.0/skillscan_trace/canary/detectors.py +712 -0
- skillscan_trace-0.1.0/skillscan_trace/canary/server.py +1187 -0
- skillscan_trace-0.1.0/skillscan_trace/cli.py +721 -0
- skillscan_trace-0.1.0/skillscan_trace/config.py +209 -0
- skillscan_trace-0.1.0/skillscan_trace/formatters.py +268 -0
- skillscan_trace-0.1.0/skillscan_trace/harness.py +314 -0
- skillscan_trace-0.1.0/skillscan_trace/input_gen.py +152 -0
- skillscan_trace-0.1.0/skillscan_trace/judge/__init__.py +17 -0
- skillscan_trace-0.1.0/skillscan_trace/judge/judges.py +290 -0
- skillscan_trace-0.1.0/skillscan_trace/judge/models.py +90 -0
- skillscan_trace-0.1.0/skillscan_trace/judge/orchestrator.py +160 -0
- skillscan_trace-0.1.0/skillscan_trace/judge/prompt.py +159 -0
- skillscan_trace-0.1.0/skillscan_trace/models.py +153 -0
- skillscan_trace-0.1.0/skillscan_trace/resolver.py +265 -0
- skillscan_trace-0.1.0/skillscan_trace/serve.py +337 -0
- skillscan_trace-0.1.0/tests/__init__.py +1 -0
- skillscan_trace-0.1.0/tests/test_canary.py +722 -0
- skillscan_trace-0.1.0/tests/test_phase2.py +259 -0
- skillscan_trace-0.1.0/tests/test_phase3.py +383 -0
- skillscan_trace-0.1.0/tests/test_phase4.py +291 -0
- skillscan_trace-0.1.0/tests/test_phase5.py +380 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: Lint, type-check & test
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.11", "3.12"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: |
|
|
27
|
+
python -m pip install --upgrade pip
|
|
28
|
+
pip install -e ".[dev]"
|
|
29
|
+
|
|
30
|
+
- name: Format check (ruff)
|
|
31
|
+
if: matrix.python-version == '3.11'
|
|
32
|
+
run: ruff format --check .
|
|
33
|
+
|
|
34
|
+
- name: Lint (ruff)
|
|
35
|
+
if: matrix.python-version == '3.11'
|
|
36
|
+
run: ruff check .
|
|
37
|
+
|
|
38
|
+
- name: Type-check (mypy)
|
|
39
|
+
if: matrix.python-version == '3.11'
|
|
40
|
+
run: mypy skillscan_trace --ignore-missing-imports
|
|
41
|
+
|
|
42
|
+
- name: Run tests
|
|
43
|
+
run: pytest tests/ -q --tb=short
|
|
44
|
+
env:
|
|
45
|
+
# Tests use mock providers — no real API key needed
|
|
46
|
+
OPENAI_API_KEY: "sk-test-placeholder"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: CodeQL
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
pull_request:
|
|
5
|
+
schedule:
|
|
6
|
+
- cron: '21 4 * * 1'
|
|
7
|
+
jobs:
|
|
8
|
+
analyze:
|
|
9
|
+
name: Analyze (python)
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
actions: read
|
|
13
|
+
contents: read
|
|
14
|
+
security-events: write
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
language: [python]
|
|
19
|
+
steps:
|
|
20
|
+
- name: Checkout repository
|
|
21
|
+
uses: actions/checkout@v4
|
|
22
|
+
- name: Initialize CodeQL
|
|
23
|
+
uses: github/codeql-action/init@v3
|
|
24
|
+
with:
|
|
25
|
+
languages: ${{ matrix.language }}
|
|
26
|
+
- name: Autobuild
|
|
27
|
+
uses: github/codeql-action/autobuild@v3
|
|
28
|
+
- name: Perform CodeQL Analysis
|
|
29
|
+
uses: github/codeql-action/analyze@v3
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
name: Build distribution
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- name: Set up Python
|
|
15
|
+
uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.11"
|
|
18
|
+
|
|
19
|
+
- name: Install build tools
|
|
20
|
+
run: |
|
|
21
|
+
python -m pip install --upgrade pip
|
|
22
|
+
pip install build
|
|
23
|
+
|
|
24
|
+
- name: Build package
|
|
25
|
+
run: python -m build
|
|
26
|
+
|
|
27
|
+
- name: Upload distribution artifacts
|
|
28
|
+
uses: actions/upload-artifact@v4
|
|
29
|
+
with:
|
|
30
|
+
name: dist
|
|
31
|
+
path: dist/
|
|
32
|
+
|
|
33
|
+
publish:
|
|
34
|
+
name: Publish to PyPI
|
|
35
|
+
needs: build
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
environment:
|
|
38
|
+
name: pypi
|
|
39
|
+
url: https://pypi.org/project/skillscan-trace/
|
|
40
|
+
permissions:
|
|
41
|
+
id-token: write # required for OIDC trusted publisher
|
|
42
|
+
|
|
43
|
+
steps:
|
|
44
|
+
- name: Download distribution artifacts
|
|
45
|
+
uses: actions/download-artifact@v4
|
|
46
|
+
with:
|
|
47
|
+
name: dist
|
|
48
|
+
path: dist/
|
|
49
|
+
|
|
50
|
+
- name: Publish to PyPI
|
|
51
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
.venv/
|
|
8
|
+
.env
|
|
9
|
+
|
|
10
|
+
# Trace outputs
|
|
11
|
+
traces/
|
|
12
|
+
*.trace.json
|
|
13
|
+
|
|
14
|
+
# Canary state (never commit)
|
|
15
|
+
.canary_*/
|
|
16
|
+
.domain_state.json
|
|
17
|
+
|
|
18
|
+
# IDE
|
|
19
|
+
.vscode/
|
|
20
|
+
.idea/
|
|
21
|
+
*.swp
|
|
22
|
+
|
|
23
|
+
# OS
|
|
24
|
+
.DS_Store
|
|
25
|
+
Thumbs.db
|
|
26
|
+
|
|
27
|
+
# Test artifacts
|
|
28
|
+
.pytest_cache/
|
|
29
|
+
.coverage
|
|
30
|
+
htmlcov/
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Contributing to skillscan-trace
|
|
2
|
+
|
|
3
|
+
## Context
|
|
4
|
+
|
|
5
|
+
skillscan-trace is the behavioral execution engine in the SkillScan family. It is a sibling project to [skillscan-security](https://github.com/kurtpayne/skillscan-security), which contains the static analyzer, ML classifier, and skill corpus.
|
|
6
|
+
|
|
7
|
+
If you are picking up this project for the first time, read these documents in order:
|
|
8
|
+
|
|
9
|
+
1. [`README.md`](./README.md) — what the tool does and why
|
|
10
|
+
2. [`SPEC.md`](./SPEC.md) — the complete behavioral specification (authoritative)
|
|
11
|
+
3. [`ARCHITECTURE.md`](./ARCHITECTURE.md) — system design and component overview
|
|
12
|
+
4. [`IMPLEMENTATION_PLAN.md`](./IMPLEMENTATION_PLAN.md) — ordered build plan with acceptance criteria
|
|
13
|
+
5. [`skillscan-security/docs/TRACE_RESEARCH.md`](https://github.com/kurtpayne/skillscan-security/blob/main/docs/TRACE_RESEARCH.md) — research notes on prior art, canary taxonomy, and domain allowlist design
|
|
14
|
+
|
|
15
|
+
## Repository relationship
|
|
16
|
+
|
|
17
|
+
The two repos share artifacts. When working on skillscan-trace, you may need to reference or update:
|
|
18
|
+
|
|
19
|
+
| Artifact | Location | Notes |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| Canary taxonomy | `skillscan-security/docs/TRACE_RESEARCH.md` | Source of truth for what to detect |
|
|
22
|
+
| Domain allowlist | `skillscan-security/trace/domains/verified.yml` | Bundled into skillscan-trace at build time |
|
|
23
|
+
| Finding ID namespace | `skillscan-security/src/skillscan/rules/` | Finding IDs must not conflict |
|
|
24
|
+
| Skill corpus | `skillscan-security/corpus/` | Used for integration tests and batch tracing |
|
|
25
|
+
|
|
26
|
+
## Development setup
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
git clone https://github.com/kurtpayne/skillscan-trace
|
|
30
|
+
cd skillscan-trace
|
|
31
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
32
|
+
pip install -e ".[dev]"
|
|
33
|
+
|
|
34
|
+
# Verify Ollama is running
|
|
35
|
+
ollama serve &
|
|
36
|
+
ollama pull qwen2.5:7b
|
|
37
|
+
|
|
38
|
+
# Run tests
|
|
39
|
+
pytest
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Implementation guidance
|
|
43
|
+
|
|
44
|
+
The `IMPLEMENTATION_PLAN.md` defines 10 milestones in dependency order. Start with Milestone 1 (instrumented MCP server) — it is the novel component with no prior art and everything else depends on it.
|
|
45
|
+
|
|
46
|
+
The MCP server should be testable standalone before the agent harness exists. Write a simple test client that sends tool calls directly to the server and verifies the interceptor behavior. This avoids needing a running model for unit tests.
|
|
47
|
+
|
|
48
|
+
The agent harness uses the OpenAI-compatible API that Ollama exposes at `http://localhost:11434/v1`. The same harness code works with real OpenAI/Anthropic models by changing the `base_url`. Do not write model-specific integration code.
|
|
49
|
+
|
|
50
|
+
## Testing
|
|
51
|
+
|
|
52
|
+
Every interceptor must have unit tests. The integration test suite runs known-malicious and known-benign skills through the full pipeline. The skillscan-security corpus provides the test cases — clone it alongside this repo and set `SKILLSCAN_CORPUS_PATH` to point at it.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
export SKILLSCAN_CORPUS_PATH=../skillscan-security/corpus
|
|
56
|
+
pytest tests/integration/
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Design constraints
|
|
60
|
+
|
|
61
|
+
**No GPU required.** The default path must work on a laptop with 8GB RAM and no GPU. Do not add GPU-only dependencies to the core package.
|
|
62
|
+
|
|
63
|
+
**No API key required by default.** Ollama is the zero-friction path. API model support is a configuration option, not the default.
|
|
64
|
+
|
|
65
|
+
**Low compliance model.** The default model (`qwen2.5:7b`) is chosen for its low refusal rate, not its safety properties. This is intentional — see SPEC.md Section 4.1 for the rationale.
|
|
66
|
+
|
|
67
|
+
**Structured output first.** Every trace produces a machine-readable JSON report. Human-readable text is a formatting layer on top. Do not design the data model around the text output.
|
|
68
|
+
|
|
69
|
+
## Versioning
|
|
70
|
+
|
|
71
|
+
skillscan-trace follows semantic versioning. The v1.0 milestone is defined by the acceptance criteria in `IMPLEMENTATION_PLAN.md`. Breaking changes to the trace report schema require a major version bump.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# skillscan-trace Docker image
|
|
2
|
+
#
|
|
3
|
+
# Supports two modes:
|
|
4
|
+
#
|
|
5
|
+
# Single trace (default):
|
|
6
|
+
# docker run --rm \
|
|
7
|
+
# -e OPENAI_API_KEY=$OPENAI_API_KEY \
|
|
8
|
+
# -v $(pwd)/my-skill.md:/skill.md:ro \
|
|
9
|
+
# skillscan/trace run /skill.md
|
|
10
|
+
#
|
|
11
|
+
# Self-hosted server:
|
|
12
|
+
# docker run -p 8080:8080 \
|
|
13
|
+
# skillscan/trace serve
|
|
14
|
+
#
|
|
15
|
+
# OpenRouter:
|
|
16
|
+
# docker run --rm \
|
|
17
|
+
# -e OPENROUTER_API_KEY=$OPENROUTER_API_KEY \
|
|
18
|
+
# -v $(pwd)/my-skill.md:/skill.md:ro \
|
|
19
|
+
# skillscan/trace run /skill.md --provider openrouter
|
|
20
|
+
#
|
|
21
|
+
# Ollama (fully local, no API key):
|
|
22
|
+
# docker run --rm \
|
|
23
|
+
# --network host \
|
|
24
|
+
# -v $(pwd)/my-skill.md:/skill.md:ro \
|
|
25
|
+
# skillscan/trace run /skill.md --provider ollama
|
|
26
|
+
|
|
27
|
+
FROM python:3.11-slim
|
|
28
|
+
|
|
29
|
+
# Security: run as non-root
|
|
30
|
+
RUN groupadd --gid 1001 skillscan && \
|
|
31
|
+
useradd --uid 1001 --gid skillscan --shell /bin/bash --create-home skillscan
|
|
32
|
+
|
|
33
|
+
WORKDIR /app
|
|
34
|
+
|
|
35
|
+
# Install system dependencies
|
|
36
|
+
RUN apt-get update && \
|
|
37
|
+
apt-get install -y --no-install-recommends \
|
|
38
|
+
git \
|
|
39
|
+
curl \
|
|
40
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
41
|
+
|
|
42
|
+
# Copy project files
|
|
43
|
+
COPY pyproject.toml README.md ./
|
|
44
|
+
COPY skillscan_trace/ ./skillscan_trace/
|
|
45
|
+
|
|
46
|
+
# Install with serve extras
|
|
47
|
+
RUN pip install --no-cache-dir ".[serve]"
|
|
48
|
+
|
|
49
|
+
# Create directories with correct ownership
|
|
50
|
+
RUN mkdir -p /trace-output /trace-cache && \
|
|
51
|
+
chown -R skillscan:skillscan /app /trace-output /trace-cache
|
|
52
|
+
|
|
53
|
+
USER skillscan
|
|
54
|
+
|
|
55
|
+
# Default output and cache directories
|
|
56
|
+
VOLUME ["/trace-output", "/trace-cache"]
|
|
57
|
+
|
|
58
|
+
# Health check for serve mode
|
|
59
|
+
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
|
60
|
+
CMD curl -f http://localhost:8080/v1/health || exit 1
|
|
61
|
+
|
|
62
|
+
# Default: show help. Override with `run /skill.md` or `serve`
|
|
63
|
+
ENTRYPOINT ["skillscan-trace"]
|
|
64
|
+
CMD ["--help"]
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: skillscan-trace
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Behavioral execution engine for MCP-based AI agent skills
|
|
5
|
+
Project-URL: Repository, https://github.com/kurtpayne/skillscan-trace
|
|
6
|
+
Project-URL: Issues, https://github.com/kurtpayne/skillscan-trace/issues
|
|
7
|
+
Project-URL: skillscan-security, https://github.com/kurtpayne/skillscan-security
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: agents,ai,behavioral-analysis,mcp,security
|
|
10
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Topic :: Security
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Requires-Dist: bashlex>=0.18
|
|
17
|
+
Requires-Dist: click>=8.0
|
|
18
|
+
Requires-Dist: jsonschema>=4.0
|
|
19
|
+
Requires-Dist: mcp>=1.0
|
|
20
|
+
Requires-Dist: openai>=1.0
|
|
21
|
+
Requires-Dist: python-dotenv>=1.0
|
|
22
|
+
Requires-Dist: python-frontmatter>=1.0
|
|
23
|
+
Requires-Dist: pyyaml>=6.0
|
|
24
|
+
Requires-Dist: requests>=2.0
|
|
25
|
+
Requires-Dist: rich>=13.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
28
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
33
|
+
Provides-Extra: serve
|
|
34
|
+
Requires-Dist: fastapi>=0.110; extra == 'serve'
|
|
35
|
+
Requires-Dist: pydantic>=2.0; extra == 'serve'
|
|
36
|
+
Requires-Dist: uvicorn[standard]>=0.29; extra == 'serve'
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# skillscan-trace
|
|
40
|
+
|
|
41
|
+
[](https://github.com/kurtpayne/skillscan-trace/actions/workflows/ci.yml)
|
|
42
|
+
[](https://github.com/kurtpayne/skillscan-trace/actions/workflows/codeql.yml)
|
|
43
|
+
[](https://pypi.org/project/skillscan-trace/)
|
|
44
|
+
[](LICENSE)
|
|
45
|
+
[](pyproject.toml)
|
|
46
|
+
|
|
47
|
+
**Behavioral execution engine for MCP-based AI agent skills.**
|
|
48
|
+
|
|
49
|
+
skillscan-trace runs a skill against a real language model inside an instrumented, isolated environment and records everything the model does: every file it reads, every network request it makes, every environment variable it accesses, every binary it probes. The output is a structured, machine-readable trace report.
|
|
50
|
+
|
|
51
|
+
It is the dynamic analysis counterpart to [skillscan](https://github.com/kurtpayne/skillscan-security), which performs static analysis. Together they form two legs of the skillscan family:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
skillscan family
|
|
55
|
+
├── skillscan — static analysis (pattern matching, ML classifier)
|
|
56
|
+
├── skillscan-trace — behavioral execution engine ← this repo
|
|
57
|
+
└── skillscan-lint — schema and format validation (planned)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## What it does
|
|
63
|
+
|
|
64
|
+
A skill is a Markdown file that becomes a system prompt for an AI agent. Most skills are benign. Some are malicious — they instruct the agent to exfiltrate credentials, probe the filesystem, call attacker-controlled servers, or hijack the agent's behavior through prompt injection embedded in tool output.
|
|
65
|
+
|
|
66
|
+
Static analysis catches the obvious cases. Behavioral analysis catches the rest: conditional payloads that only activate in certain environments, obfuscated instructions that decode at runtime, and prompt injection delivered through external content the skill fetches.
|
|
67
|
+
|
|
68
|
+
skillscan-trace works by:
|
|
69
|
+
|
|
70
|
+
1. Loading the skill's `SKILL.md` as the system prompt for a local language model
|
|
71
|
+
2. Sending a realistic user prompt that exercises the skill's stated functionality
|
|
72
|
+
3. Driving the model's tool-use loop through an **instrumented MCP server** that intercepts every tool call
|
|
73
|
+
4. Checking each call against a canary taxonomy (credential files, wallet paths, ENV vars, binary probing, network destinations)
|
|
74
|
+
5. Emitting a structured trace report (JSON + SARIF) with every observed behavior and any findings
|
|
75
|
+
|
|
76
|
+
The model runs locally via [Ollama](https://ollama.com/) — no API key required, no cloud dependency. API providers (OpenAI, OpenRouter, Anthropic) are supported for users who prefer them or want access to more capable models.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Status
|
|
81
|
+
|
|
82
|
+
**v0.1.0 — core CLI complete.** Phases 1–5 are implemented and 144/144 tests pass. The tool is installable and usable today.
|
|
83
|
+
|
|
84
|
+
See [`SPEC.md`](./SPEC.md) for the full behavioral specification.
|
|
85
|
+
See [`ARCHITECTURE.md`](./ARCHITECTURE.md) for the system design.
|
|
86
|
+
See [`IMPLEMENTATION_PLAN.md`](./IMPLEMENTATION_PLAN.md) for the build plan and phase status.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Quick start
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Install from source
|
|
94
|
+
git clone https://github.com/kurtpayne/skillscan-trace
|
|
95
|
+
cd skillscan-trace
|
|
96
|
+
pip install -e .
|
|
97
|
+
|
|
98
|
+
# Run a trace with OpenAI
|
|
99
|
+
export OPENAI_API_KEY=sk-...
|
|
100
|
+
skillscan-trace run ./path/to/skill/
|
|
101
|
+
|
|
102
|
+
# Run with OpenRouter (200+ models via one key)
|
|
103
|
+
export OPENROUTER_API_KEY=sk-or-...
|
|
104
|
+
skillscan-trace run ./skill/ --provider openrouter --model mistralai/mistral-7b-instruct
|
|
105
|
+
|
|
106
|
+
# Run with a local Ollama model (no API key required)
|
|
107
|
+
skillscan-trace run ./skill/ --provider ollama --model qwen2.5:7b
|
|
108
|
+
|
|
109
|
+
# Run with explicit base URL (Azure, Mistral, etc.)
|
|
110
|
+
skillscan-trace run ./skill/ --base-url https://api.mistral.ai/v1 --api-key $MISTRAL_KEY
|
|
111
|
+
|
|
112
|
+
# Output formats
|
|
113
|
+
skillscan-trace run ./skill/ --format sarif # SARIF 2.1.0 for CI
|
|
114
|
+
skillscan-trace run ./skill/ --format json # native trace format
|
|
115
|
+
skillscan-trace run ./skill/ --format text # human-readable summary
|
|
116
|
+
|
|
117
|
+
# Verify connectivity
|
|
118
|
+
skillscan-trace check
|
|
119
|
+
skillscan-trace check --provider openrouter
|
|
120
|
+
skillscan-trace check --provider ollama
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Skill format support
|
|
126
|
+
|
|
127
|
+
skillscan-trace handles all skill formats found in the wild:
|
|
128
|
+
|
|
129
|
+
| Format | Description | Example |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| Single `SKILL.md` | Standard Claude Code / MCP skill | `./my-skill/SKILL.md` |
|
|
132
|
+
| Single `.md` file | Flat file, no directory | `./my-skill.md` |
|
|
133
|
+
| Directory with `SKILL.md` | Standard with supporting files | `./my-skill/` |
|
|
134
|
+
| Frontmatter + body | YAML frontmatter + Markdown body | `name:`, `allowed-tools:` |
|
|
135
|
+
| Plain Markdown | No frontmatter | Any `.md` file |
|
|
136
|
+
| Multi-file skill | Directory with multiple `.md` files | Loaded in alphabetical order |
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Output: Trace Report
|
|
141
|
+
|
|
142
|
+
Every trace produces a JSON trace report and optionally a SARIF report.
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"schema_version": "1.0.0",
|
|
147
|
+
"trace_id": "trc_20260320_abc123",
|
|
148
|
+
"skill": {
|
|
149
|
+
"path": "./my-skill/SKILL.md",
|
|
150
|
+
"name": "git-helper",
|
|
151
|
+
"sha256": "a1b2c3..."
|
|
152
|
+
},
|
|
153
|
+
"model": {
|
|
154
|
+
"provider": "ollama",
|
|
155
|
+
"model": "qwen2.5:7b",
|
|
156
|
+
"version": "..."
|
|
157
|
+
},
|
|
158
|
+
"prompt": "Help me commit my changes",
|
|
159
|
+
"duration_ms": 4823,
|
|
160
|
+
"tool_calls": [...],
|
|
161
|
+
"findings": [...],
|
|
162
|
+
"summary": {
|
|
163
|
+
"total_tool_calls": 7,
|
|
164
|
+
"finding_count": 1,
|
|
165
|
+
"severity_max": "HIGH",
|
|
166
|
+
"clean": false
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Relationship to skillscan-security
|
|
174
|
+
|
|
175
|
+
skillscan-trace is a sibling project to [skillscan-security](https://github.com/kurtpayne/skillscan-security). The two projects share:
|
|
176
|
+
|
|
177
|
+
- **Finding schema**: The same finding IDs (`EXF-001`, `MAL-001`, `IOC-001`, etc.) and severity levels
|
|
178
|
+
- **Canary taxonomy**: The same list of high-value target paths and ENV var names
|
|
179
|
+
- **Domain allowlist**: `trace/domains/verified.yml` from skillscan-security is the source of truth; skillscan-trace consumes it
|
|
180
|
+
- **Corpus feedback loop**: Traces that produce findings can be reviewed and added to the skillscan-security corpus as `sandbox_verified/` examples, improving the ML classifier's recall on behavioral patterns that static analysis misses
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Privacy & Key Handling
|
|
185
|
+
|
|
186
|
+
Your API key goes directly to the LLM provider you chose. The canary server runs in-process on your machine. Nothing leaves your network except the LLM API calls you explicitly authorize. SkillScan has no server-side component in local mode.
|
|
187
|
+
|
|
188
|
+
See [`PRIVACY.md`](./PRIVACY.md) for the full data flow explanation.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Contributing
|
|
193
|
+
|
|
194
|
+
See [`CONTRIBUTING.md`](./CONTRIBUTING.md).
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
MIT
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Privacy & Key Handling
|
|
2
|
+
|
|
3
|
+
skillscan-trace is a local tool. **Your skill files, API keys, and trace results never leave your machine** except for the LLM API calls you explicitly authorize.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What happens during a trace
|
|
8
|
+
|
|
9
|
+
When you run `skillscan-trace run ./skill.md`, the following happens entirely on your machine:
|
|
10
|
+
|
|
11
|
+
1. **Skill loading.** The skill file is read from your local filesystem. It is not uploaded anywhere.
|
|
12
|
+
2. **Canary environment setup.** A temporary directory is created in-process with synthetic credential files, wallet paths, and environment variables. These are randomly generated per run and have no real value.
|
|
13
|
+
3. **LLM API call.** The skill's content is sent to the LLM provider you configured (`--provider openai`, `--provider openrouter`, or `--provider ollama`). This is the only network request skillscan-trace makes. The request goes directly from your machine to the provider — it does not pass through any SkillScan server.
|
|
14
|
+
4. **Canary server.** The instrumented MCP server runs in-process. It intercepts every tool call the model makes and checks it against the canary taxonomy. No subprocess is spawned; no data is written to disk except the trace report you explicitly request.
|
|
15
|
+
5. **Report output.** The trace report is written to your local `./trace-output/` directory (or the path you specify with `--output-dir`). It is not uploaded anywhere.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Your API key
|
|
20
|
+
|
|
21
|
+
Your API key is passed directly to the LLM provider you chose. It is not:
|
|
22
|
+
|
|
23
|
+
- Stored by skillscan-trace (it is read from your `.env` file, environment variable, or `--api-key` flag and used only for the duration of the run)
|
|
24
|
+
- Transmitted to any SkillScan server (there is no SkillScan server in local mode)
|
|
25
|
+
- Logged to disk (the trace report does not include your API key)
|
|
26
|
+
- Shared with any third party other than the LLM provider you selected
|
|
27
|
+
|
|
28
|
+
If you use `--provider openrouter`, your key goes to [OpenRouter](https://openrouter.ai). If you use `--provider openai`, it goes to [OpenAI](https://openai.com). If you use `--provider ollama`, no key is required and no network request is made to any external service.
|
|
29
|
+
|
|
30
|
+
### Storing keys in .env
|
|
31
|
+
|
|
32
|
+
skillscan-trace reads a `.env` file automatically from the current directory and all parent directories (nearest file wins). This is the recommended way to store API keys:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
# .env — add this file to .gitignore, never commit it
|
|
36
|
+
OPENAI_API_KEY=sk-...
|
|
37
|
+
OPENROUTER_API_KEY=sk-or-...
|
|
38
|
+
ANTHROPIC_API_KEY=sk-ant-... # only needed when --judge is enabled
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Priority order (highest wins):
|
|
42
|
+
1. `--api-key` CLI flag
|
|
43
|
+
2. Shell environment variable (`export OPENAI_API_KEY=...`)
|
|
44
|
+
3. `.env` file in the current or nearest ancestor directory
|
|
45
|
+
4. `skillscan-trace.yaml` config file (API keys are **not** supported here — use `.env` instead)
|
|
46
|
+
|
|
47
|
+
The `.env` file is loaded with `override=False`, meaning shell variables you have already exported always take precedence over `.env` values. If no `.env` file is found, skillscan-trace falls back to the shell environment silently.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## What is sent to the LLM provider
|
|
52
|
+
|
|
53
|
+
The LLM API call contains:
|
|
54
|
+
|
|
55
|
+
- The skill's `SKILL.md` content (as the system prompt)
|
|
56
|
+
- A generated user message that exercises the skill's stated functionality
|
|
57
|
+
- The canary tool definitions (the list of tools the model can call)
|
|
58
|
+
|
|
59
|
+
The canary tool definitions describe the tool interface (names, parameter schemas) but do not contain any real credential values. The canary values (fake AWS keys, fake wallet seeds, etc.) are only present in the tool *responses* that the canary server returns when the model calls a tool — those responses stay on your machine and are never sent back to the LLM provider in a way that would expose them.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Ollama (fully local)
|
|
64
|
+
|
|
65
|
+
If you use `--provider ollama`, the entire trace runs on your machine with no external network requests. The model runs locally via [Ollama](https://ollama.com/). No API key is required. No data leaves your machine.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Trace reports
|
|
70
|
+
|
|
71
|
+
Trace reports (JSON, SARIF, text) are written to your local filesystem only. They contain:
|
|
72
|
+
|
|
73
|
+
- The skill path and SHA-256 hash of the skill content
|
|
74
|
+
- The model and provider used
|
|
75
|
+
- All tool calls the model made (tool name, arguments, canary server response)
|
|
76
|
+
- Any findings (rule ID, severity, description)
|
|
77
|
+
- Token usage for the run
|
|
78
|
+
|
|
79
|
+
They do not contain your API key, your system's real credential files, or any data from outside the canary environment.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Summary
|
|
84
|
+
|
|
85
|
+
| Data | Where it goes |
|
|
86
|
+
|---|---|
|
|
87
|
+
| Skill file content | LLM provider (as system prompt) |
|
|
88
|
+
| API key | LLM provider only (never stored or logged) |
|
|
89
|
+
| Canary tool definitions | LLM provider (tool schemas, no real values) |
|
|
90
|
+
| Canary credential values | Your machine only (in-process canary server) |
|
|
91
|
+
| Trace report | Your local filesystem only |
|
|
92
|
+
| Your real credential files | Not accessed (canary uses synthetic files) |
|
|
93
|
+
| `.env` file contents | Your machine only (never transmitted) |
|
|
94
|
+
|
|
95
|
+
If you have questions or concerns about data handling, open an issue at [github.com/kurtpayne/skillscan-trace](https://github.com/kurtpayne/skillscan-trace/issues).
|