Skip to content
Merged
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
4 changes: 4 additions & 0 deletions .agents/skills/verify-tooltrust-scanner/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,7 @@ If launch itself fails, invoke the same cleanup command and preserve build error
`.github/workflows/verification.yml` runs `all`, `gaps` and `osv` for every pull request (including stacked bases) and pushes to main/master/dev. Each drive validates fingerprints first. Cleanup and evidence upload run even after failures; evidence is retained for 14 days. Build steps may download Go dependencies; runtime OSV requests use only the owned local fixture. No npm packages are downloaded and no user configuration is modified.

Keep this skill and its feature map aligned with changes using `/maintain-verification-skill`.

## Releases

Use [features/release.md](features/release.md) before every version bump/tag/npm publication. `--feature release` runs packaging/version checks using an owned local binary; the separate `--published` recipe tests real release downloads and checksums. Node.js 22+ and npm are required. These tests use isolated caches and never publish packages themselves.
1 change: 1 addition & 0 deletions .agents/skills/verify-tooltrust-scanner/features/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Launch and doctor using the parent SKILL.md. Use a fresh, owned run directory an
| mcp | [Use ToolTrust from an MCP client](mcp.md) | initialize, list, raw JSON scan, rules catalog |
| gate | [Scan before adding a server](gate.md) | dry-run, policy block, forced project-config install |
| osv | [Vulnerability service failures](osv.md) | Local HTTP success/error/timeout, partial failure, CLI and MCP propagation |
| release | [Release packaging](release.md) | Version alignment, packed npm install, MCP/error/cache behavior; published assets tested separately |

## Proof and gaps

Expand Down
7 changes: 7 additions & 0 deletions .agents/skills/verify-tooltrust-scanner/features/release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Release verification

Before tagging, run `verify.py drive --run "$TT_VERIFY_RUN" --feature release` after launch. Node.js 22+, npm and Go are required. It checks VERSION, npm package version/binary pin and server.json, packs the actual npm tarball, enforces its file allowlist, installs it with scripts disabled into owned scratch state, and tests the packaged wrapper with the release-version binary. Assert initialization/tool listing, empty scan errors, OSV 503 errors, cache reuse and a failing exit for an invalid cached executable. The preflight seeds a freshly built binary and does not claim a real release download.

After GitHub release assets exist, run `node scripts/verify-npm-release.js --published --run /absolute/fresh/owned/path`. This tests a cold download of the exact pinned release, checks both MCP/CLI SHA256 against platform checksum assets, verifies binary versions and CLI empty-input failure, then repeats wrapper/cache/error assertions. Release CI runs it on Linux, macOS and Windows. It needs GitHub network access. Evidence stays under the owned run's evidence directory; caches/install files are isolated by TOOLTRUST_CACHE_DIR and npm config/cache flags.

Only publish npm after the exact release asset tests pass. Verify npm registry metadata/tarball after publication. Update Homebrew version/checksum only once the tag archive exists, and validate the formula PR. Release notes must explain changed exit semantics. Registry publication to the MCP catalog, real Claude installation and signing/provenance guarantees are NOT established by these checks.
10 changes: 8 additions & 2 deletions .agents/skills/verify-tooltrust-scanner/scripts/verify.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def source_digest():
).decode().split("\0")
h = hashlib.sha256()
for name in sorted(set(names)):
if name.endswith(".go") or name in ("go.mod", "go.sum", "VERSION"):
if name.endswith(".go") or name in ("go.mod", "go.sum", "VERSION", "npm/package.json", "npm/bin/run.js", "server.json", "scripts/verify-npm-release.js"):
path = ROOT / name
h.update(name.encode())
h.update(path.read_bytes() if path.exists() else b"DELETED")
Expand Down Expand Up @@ -414,6 +414,12 @@ def do_POST(self):
worker.join(timeout=5)
save(self.evidence / "osv.http-requests.json", requests)

def release(self):
# npm uses owned config/cache; Go downloads are allowed during the build.
self.command("release-preflight", [shutil.which("node"), ROOT / "scripts/verify-npm-release.js",
"--run", self.runtime / "release", "--evidence", self.evidence / "release"],
env=os.environ.copy(), cwd=ROOT, timeout=300)

def cleanup(self):
self.require_owned()
artifacts = sorted(str(p.relative_to(self.evidence)) for p in self.evidence.rglob("*") if p.is_file())
Expand All @@ -429,7 +435,7 @@ def main():
p = argparse.ArgumentParser(description=__doc__)
p.add_argument("action", choices=["launch", "doctor", "drive", "cleanup"])
p.add_argument("--run", required=True)
p.add_argument("--feature", choices=["static", "live", "source", "mcp", "gate", "all", "gaps", "osv"], default="all")
p.add_argument("--feature", choices=["static", "live", "source", "mcp", "gate", "all", "gaps", "osv", "release"], default="all")
args = p.parse_args()
run = Run(args.run)
if args.action != "drive":
Expand Down
25 changes: 18 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ jobs:
go-version: "1.26.9"
cache: true
- run: go test -race -count=1 ./...
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Verify release versions and packed npm wrapper
run: node scripts/verify-npm-release.js --run "$RUNNER_TEMP/release-preflight"

# ── 2. Cross-compile binaries for all target platforms ────────────────────
build:
Expand Down Expand Up @@ -126,6 +131,7 @@ jobs:
needs: [build]

steps:
- uses: actions/checkout@v4
- name: Download all binary artifacts
uses: actions/download-artifact@v4
with:
Expand All @@ -140,6 +146,7 @@ jobs:
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
body_path: docs/releases/${{ github.ref_name }}.md
files: |
dist/tooltrust-scanner_*
dist/tooltrust-mcp_*
Expand Down Expand Up @@ -260,17 +267,21 @@ jobs:
# Send a basic initialize request and check if it replies without crashing
echo '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "test", "version": "1.0.0"}}}' | $BIN_PATH

- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20

- name: Test NPM Wrapper
node-version: 22
- name: Verify exact packaged wrapper and released assets
shell: bash
run: |
# Use npx to download and run the wrapper. We must use tooltrust-mcp
# Note: Since the release was just created, the binary is already available on GitHub.
npx -y tooltrust-mcp@latest --help
run: node scripts/verify-npm-release.js --published --run "$RUNNER_TEMP/release-distribution"
- name: Upload distribution evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: distribution-${{ matrix.goos }}-${{ matrix.goarch }}
path: ${{ runner.temp }}/release-distribution/evidence/
retention-days: 14

# ── 6. Update Homebrew Formula ─────────────────────────────────────────────
update-formula:
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/verification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Select owned run directory
run: echo "TT_VERIFY_RUN=$RUNNER_TEMP/tooltrust-verification" >> "$GITHUB_ENV"
- name: Build owned binaries and record fingerprints
Expand All @@ -42,6 +45,9 @@ jobs:
- name: Verify vulnerability service failure handling
if: ${{ always() && steps.launch.outcome == 'success' }}
run: python3 "$TT_VERIFY_SCRIPT" drive --run "$TT_VERIFY_RUN" --feature osv
- name: Verify release packaging and versions
if: ${{ always() && steps.launch.outcome == 'success' }}
run: python3 "$TT_VERIFY_SCRIPT" drive --run "$TT_VERIFY_RUN" --feature release
- name: Clean owned runtime and retain evidence
if: ${{ always() }}
run: |
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,25 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

---

## [0.3.20] - 2026-10-12

### Added
- Detect Rust MCP server presence for rmcp ServerHandler implementations and handwritten serde_json tools/list handlers. Ignore comments and string examples. This is presence detection, not complete Rust schema extraction.
- Run CLI/MCP user-path verification in CI, including pagination, empty discovery, OSV failures and release packaging checks.
- Refresh reviewed malicious-package intelligence accumulated since v0.3.19.

### Fixed
- Empty tool manifests and live discovery now fail explicitly instead of receiving a clean A. Gate cannot bypass missing discovery with --force.
- Failed OSV lookups, invalid responses, timeouts and partial dependency lookup failures now report scan incomplete. MCP returns tool errors and gate refuses installation.
- Update the Go toolchain to 1.26.9 and golang.org/x/text for security fixes.
- Preserve npm wrapper failure exits when a cached binary cannot start, and support an isolated cache via TOOLTRUST_CACHE_DIR.
- Align npm tooltrust-mcp 1.1.13 and registry metadata with scanner v0.3.20; the previous npm wrapper still selected v0.3.17.

### Upgrade notes
- Scripts must handle nonzero exit when discovery is empty or OSV is unavailable. No success report is produced for these incomplete scans; a pre-existing output file is not evidence of a successful new run.
- TOOLTRUST_OSV_URL can select a trusted OSV-compatible endpoint (HTTPS, or numeric loopback HTTP for testing). Dependency names and versions are sent to that endpoint.
- MCP HTTP transport, full Rust schema extraction and Cargo dependency scanning remain outside this release.

## [0.3.19] - 2026-06-20

### Added
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.3.19
0.3.20
18 changes: 18 additions & 0 deletions docs/releases/v0.3.20.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# ToolTrust Scanner v0.3.20 / npm tooltrust-mcp 1.1.13

### Added
- Detect Rust MCP server presence for rmcp ServerHandler implementations and handwritten serde_json tools/list handlers. Ignore comments and string examples. This is presence detection, not complete Rust schema extraction.
- Run CLI/MCP user-path verification in CI, including pagination, empty discovery, OSV failures and release packaging checks.
- Refresh reviewed malicious-package intelligence accumulated since v0.3.19.

### Fixed
- Empty tool manifests and live discovery now fail explicitly instead of receiving a clean A. Gate cannot bypass missing discovery with --force.
- Failed OSV lookups, invalid responses, timeouts and partial dependency lookup failures now report scan incomplete. MCP returns tool errors and gate refuses installation.
- Update the Go toolchain to 1.26.9 and golang.org/x/text for security fixes.
- Preserve npm wrapper failure exits when a cached binary cannot start, and support an isolated cache via TOOLTRUST_CACHE_DIR.
- Align npm tooltrust-mcp 1.1.13 and registry metadata with scanner v0.3.20; the previous npm wrapper still selected v0.3.17.

### Upgrade notes
- Scripts must handle nonzero exit when discovery is empty or OSV is unavailable. No success report is produced for these incomplete scans; a pre-existing output file is not evidence of a successful new run.
- TOOLTRUST_OSV_URL can select a trusted OSV-compatible endpoint (HTTPS, or numeric loopback HTTP for testing). Dependency names and versions are sent to that endpoint.
- MCP HTTP transport, full Rust schema extraction and Cargo dependency scanning remain outside this release.
4 changes: 4 additions & 0 deletions npm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,7 @@ Flagged Tools:
- **Glama:** https://glama.ai/mcp/servers/AgentSafe-AI/tooltrust-scanner
- **Directory:** https://www.tooltrust.dev/
- **Rules:** https://github.com/AgentSafe-AI/tooltrust-scanner/blob/main/docs/RULES.md

## 1.1.13

Uses scanner v0.3.20, including Rust MCP presence detection and explicit failures for empty discovery or unavailable vulnerability checks. See the [release notes](https://github.com/AgentSafe-AI/tooltrust-scanner/releases/tag/v0.3.20). Set `TOOLTRUST_CACHE_DIR` to choose an isolated binary cache; by default it remains `~/.tooltrust-mcp/bin/`.
9 changes: 5 additions & 4 deletions npm/bin/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ function runBinary(binPath, args) {
const child = spawn(binPath, args, { stdio: 'inherit' });
child.on('error', (err) => {
console.error(`Failed to start subprocess: ${err}`);
process.exitCode = 1;
});
child.on('exit', (code) => {
process.exit(code || 0);
child.on('exit', (code, signal) => {
process.exit(code === null || signal ? 1 : code);
});
}

Expand All @@ -73,7 +74,7 @@ async function main() {
const binaryVersion = pkg.tooltrustBinaryVersion || 'latest';
const cacheBinName = `${binaryVersion}_${releaseBinName}`;
const downloadUrl = `https://github.com/AgentSafe-AI/tooltrust-scanner/releases/download/${binaryVersion}/${releaseBinName}`;
const cacheDir = path.join(os.homedir(), '.tooltrust-mcp', 'bin');
const cacheDir = process.env.TOOLTRUST_CACHE_DIR || path.join(os.homedir(), '.tooltrust-mcp', 'bin');
const binPath = path.join(cacheDir, cacheBinName);

// --version is the only flag handled by the wrapper (shows npm package version).
Expand All @@ -90,7 +91,7 @@ async function main() {
await downloadFile(downloadUrl, binPath);
} catch (e) {
console.error(`Error downloading binary: ${e.message}`);
console.error("Failed to download binary. If you are behind a proxy, try setting NODE_TLS_REJECT_UNAUTHORIZED=0 or download the binary manually from GitHub Releases.");
console.error("Failed to download binary. Check your network/proxy settings or download the binary manually from GitHub Releases.");
process.exit(1);
}
}
Expand Down
7 changes: 5 additions & 2 deletions npm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tooltrust-mcp",
"version": "1.1.12",
"version": "1.1.13",
"description": "MCP server that scans other MCP servers for prompt injection, data exfiltration, and privilege escalation. Add to your .mcp.json and let your AI agent audit its own tools.",
"keywords": [
"mcp",
Expand All @@ -21,5 +21,8 @@
"tooltrust-mcp": "bin/run.js"
},
"mcpName": "io.github.AgentSafe-AI/tooltrust-scanner",
"tooltrustBinaryVersion": "v0.3.17"
"tooltrustBinaryVersion": "v0.3.20",
"files": [
"bin/run.js"
]
}
Loading
Loading