-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathaction.yml
More file actions
101 lines (85 loc) · 3.75 KB
/
action.yml
File metadata and controls
101 lines (85 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
name: 'ToolTrust MCP Security Scanner'
description: 'Scan MCP server tools for prompt injection, privilege escalation, and supply-chain attacks. Each tool gets a trust grade (A–F) and a gateway policy (ALLOW / REQUIRE_APPROVAL / BLOCK). Fail your CI if a server exceeds your risk threshold.'
author: 'AgentSafe-AI'
branding:
icon: 'shield'
color: 'blue'
inputs:
server:
description: 'The live MCP server command to scan (e.g., "npx -y @modelcontextprotocol/server-filesystem /tmp"). Mutually exclusive with input.'
required: false
input:
description: 'The path to a local tools.json file (mutually exclusive with server).'
required: false
fail-on:
description: 'The grade threshold to fail the CI. (allow | approval | block). Default is "approval" (fails on C, D, F).'
required: false
default: 'approval'
deep-scan:
description: 'Enable AI-based semantic analysis for deep prompt injection detection (~22MB model).'
required: false
default: 'false'
outputs:
grade:
description: "The overall scan grade (A, B, C, D, F)"
value: ${{ steps.scan.outputs.grade }}
score:
description: "The numeric risk score of the scan"
value: ${{ steps.scan.outputs.score }}
result:
description: "The full JSON output of the scan report"
value: ${{ steps.scan.outputs.result }}
runs:
using: 'composite'
steps:
- name: Download ToolTrust Scanner
shell: bash
run: |
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/')"
URL="https://github.com/AgentSafe-AI/tooltrust-scanner/releases/latest/download/tooltrust-scanner_${OS}_${ARCH}"
mkdir -p "$GITHUB_WORKSPACE/.tooltrust/bin"
curl -fsSL "$URL" -o "$GITHUB_WORKSPACE/.tooltrust/bin/tooltrust"
chmod +x "$GITHUB_WORKSPACE/.tooltrust/bin/tooltrust"
echo "$GITHUB_WORKSPACE/.tooltrust/bin" >> $GITHUB_PATH
- name: Run ToolTrust Scanner
id: scan
shell: bash
run: |
if [ -n "${{ inputs.server }}" ] && [ -n "${{ inputs.input }}" ]; then
echo "::error::Inputs 'server' and 'input' are mutually exclusive. Please provide exactly one."
exit 1
fi
REPORT_FILE="$(mktemp)"
# Turn off exit immediately so we can parse the JSON even if the scan fails
set +e
DEEP_SCAN_FLAG=""
if [ "${{ inputs.deep-scan }}" = "true" ]; then
DEEP_SCAN_FLAG="--deep-scan"
fi
if [ -n "${{ inputs.server }}" ]; then
tooltrust scan --server "${{ inputs.server }}" --fail-on "${{ inputs.fail-on }}" $DEEP_SCAN_FLAG --output json --file "$REPORT_FILE" >/dev/null
elif [ -n "${{ inputs.input }}" ]; then
tooltrust scan --input "${{ inputs.input }}" --fail-on "${{ inputs.fail-on }}" $DEEP_SCAN_FLAG --output json --file "$REPORT_FILE" >/dev/null
else
echo "::error::Either 'server' or 'input' must be provided."
exit 1
fi
SCAN_EXIT_CODE=$?
# Turn behavior back on
set -e
if [ -f "$REPORT_FILE" ]; then
GRADE=$(jq -r '.summary.avg_grade // empty' "$REPORT_FILE")
SCORE=$(jq -r '.summary.avg_score // empty' "$REPORT_FILE")
echo "grade=$GRADE" >> $GITHUB_OUTPUT
echo "score=$SCORE" >> $GITHUB_OUTPUT
# Multiline output for result
echo "result<<EOF" >> $GITHUB_OUTPUT
cat "$REPORT_FILE" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
# Print the report to stdout for Action logs
cat "$REPORT_FILE"
else
echo "::warning::Scan report was not generated."
fi
exit $SCAN_EXIT_CODE