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
14 changes: 7 additions & 7 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ jobs:
run:
working-directory: plugins/plugin-eval
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false

- name: Install uv
uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
enable-cache: true

Expand Down Expand Up @@ -70,12 +70,12 @@ jobs:
name: Markdown (markdownlint-cli2)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false

- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: '24'

Expand All @@ -86,7 +86,7 @@ jobs:
# to spec, but lint enforcement happens at the plugin-author layer, not at
# the framework PR layer.
# Config in .markdownlint.json keeps the ruleset narrow and pragmatic.
uses: DavidAnson/markdownlint-cli2-action@eb5ca3ab411449c66620fe7f1b3c9e10547144b0 # v18
uses: DavidAnson/markdownlint-cli2-action@eb5ca3ab411449c66620fe7f1b3c9e10547144b0 # v18.0.0
with:
globs: |
*.md
Expand All @@ -97,12 +97,12 @@ jobs:
name: JSON / TOML / YAML syntax
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false

- name: Install uv
uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
enable-cache: true

Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/eval-report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ jobs:
DEPTH: ${{ inputs.depth || 'quick' }}
ONLY_CHANGED: ${{ inputs.only_changed || '' }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
enable-cache: true

Expand Down Expand Up @@ -66,7 +68,7 @@ jobs:

- name: Upload reports artifact
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: eval-reports-${{ env.DEPTH }}-${{ github.run_id }}
path: eval-reports/
Expand Down
31 changes: 16 additions & 15 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
name: Validate JSON files
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false

Expand Down Expand Up @@ -112,12 +112,12 @@ jobs:
run:
working-directory: plugins/plugin-eval
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false

- name: Install uv
uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
enable-cache: true

Expand All @@ -137,12 +137,12 @@ jobs:
run:
working-directory: plugins/plugin-eval
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false

- name: Install uv
uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
enable-cache: true

Expand All @@ -159,12 +159,12 @@ jobs:
name: Cross-harness generation + validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false

- name: Install uv
uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
enable-cache: true

Expand Down Expand Up @@ -201,7 +201,7 @@ jobs:

- name: Upload generated artifacts for inspection
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: multi-harness-output
path: |
Expand All @@ -223,17 +223,17 @@ jobs:
# generated artifacts to catch issues that pure-Python parsing misses (CLI
# version drift, schema-loader surprises, plugin discovery bugs).
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false

- name: Set up Node.js (for Gemini CLI)
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: '24'

- name: Set up Bun (for OpenCode CLI)
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: latest

Expand All @@ -243,17 +243,18 @@ jobs:
echo "$HOME/.opencode/bin" >> "$GITHUB_PATH"

- name: Install Gemini CLI
# Pinned to the released line we developed against; bump alongside any
# gemini-extension.json schema changes.
run: npm install -g @google/gemini-cli@latest
# Deliberately @latest: this is a real-CLI smoke test and should track
# the current release. No lockfile exists to install from, so zizmor's
# adhoc-packages finding is accepted here (decision 2026-09-08, #20).
run: npm install -g @google/gemini-cli@latest # zizmor: ignore[adhoc-packages]

- name: Verify CLI versions
run: |
opencode --version
gemini --version

- name: Install uv
uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
enable-cache: true

Expand Down
24 changes: 24 additions & 0 deletions .markdownlint-cli2.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// markdownlint-cli2 configuration.
//
// Scope: this repo lints its own top-level and `docs/` Markdown. Per-plugin
// documentation under `plugins/` is owned by the plugin authors, which is the
// same scope the repo's own `markdownlint` CI job already applies -- it runs
// `markdownlint-cli2 "*.md" "docs/*.md"` and does not walk `plugins/`.
//
// This file exists so that tooling which discovers Markdown itself (the
// fleet-wide `standards-check` workflow, pre-commit hooks) applies that same
// scope, instead of reporting several hundred findings in vendored plugin
// docs that this repo does not own.
//
// Rules live in `.markdownlint.json` and are extended here rather than
// duplicated, so the two configs cannot drift. The repo's own CI action reads
// `.markdownlint.json` directly.
{
"config": {
"extends": ".markdownlint.json"
},
"ignores": [
"plugins/**",
"node_modules/**"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ INTERVAL="${1:-30}"
LOGFILE="${2:-thermal.log}"
PIDFILE="${LOGFILE}.pid"

if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then
echo "Stopping existing sampler (pid $(cat "$PIDFILE"))"
kill "$(cat "$PIDFILE")"
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE" || true)" 2>/dev/null; then
echo "Stopping existing sampler (pid $(cat "$PIDFILE" || true))"
kill "$(cat "$PIDFILE" || true)"
fi

echo "timestamp,temperature.gpu,power.draw" > "$LOGFILE"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ fi
TARGET=$(printf '%s' "$TARGET" | tr '[:upper:]' '[:lower:]' | sed 's/^\.//')
case "$TARGET" in
*[!a-z0-9]*|'') echo "error: invalid target format: '$2' (use a plain extension like pdf, mp3, docx)" >&2; exit 2 ;;
*) ;; # valid plain format token; nothing to do
esac
BASENAME=$(basename "$IN")
SRC=$(printf '%s' "${BASENAME##*.}" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9')
Expand All @@ -37,6 +38,7 @@ SRC=$(printf '%s' "${BASENAME##*.}" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-
if [ -n "$OUT" ]; then
case "$OUT" in
/*|~*|*../*|*/..|..) echo "error: output path must be relative and must not contain '..': $OUT" >&2; exit 2 ;;
*) ;; # relative, non-traversing path; nothing to do
esac
fi
[ -z "$OUT" ] && OUT="${IN%.*}.${TARGET}"
Expand All @@ -63,7 +65,7 @@ else
# printf is a shell builtin, so the large payload here is not subject to argv
# limits; read it back from the encoded file.
B64=$(cat "$B64_FILE")
SAFE_FN=$(printf '%s' "$BASENAME" | tr -d '"\\' | LC_ALL=C tr -cd '[:print:]')
SAFE_FN=$(printf '%s' "$BASENAME" | tr -d '"'"\\\\" | LC_ALL=C tr -cd '[:print:]')
printf '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"convert_file","arguments":{"base64_content":"%s","source_format":"%s","target_format":"%s","filename":"%s"}}}' \
"$B64" "$SRC" "$TARGET" "$SAFE_FN" > "$REQ_FILE"
fi
Expand All @@ -72,15 +74,15 @@ HTTP_CODE=$(curl -sS --max-time 300 -o "$RESP_FILE" -w "%{http_code}" \
-X POST "$ENDPOINT" -H "Content-Type: application/json" --data-binary "@$REQ_FILE")

if [ "$HTTP_CODE" != "200" ]; then
echo "error: conversion service returned HTTP $HTTP_CODE: $(head -c 300 "$RESP_FILE")" >&2
echo "error: conversion service returned HTTP $HTTP_CODE: $(head -c 300 "$RESP_FILE" || true)" >&2
exit 4
fi

DOWNLOAD_URL=$(grep -o 'https://changethisfile.com/v1/jobs/download/[A-Za-z0-9_-]*' "$RESP_FILE" | head -1 || true)
if [ -z "$DOWNLOAD_URL" ]; then
# Surface the tool's error text (rate limit, unsupported route, etc.)
ERR=$(sed 's/\\n/ /g' "$RESP_FILE" | grep -o '"text":"[^"]*"' | head -1 | sed 's/^"text":"//; s/"$//')
echo "error: ${ERR:-unexpected response: $(head -c 300 "$RESP_FILE")}" >&2
echo "error: ${ERR:-unexpected response: $(head -c 300 "$RESP_FILE" || true)}" >&2
exit 5
fi

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ echo ""

# 3. Check Chart.yaml
echo "3️⃣ Validating Chart.yaml..."
CHART_NAME=$(grep "^name:" "$CHART_DIR/Chart.yaml" | awk '{print $2}')
CHART_VERSION=$(grep "^version:" "$CHART_DIR/Chart.yaml" | awk '{print $2}')
APP_VERSION=$(grep "^appVersion:" "$CHART_DIR/Chart.yaml" | awk '{print $2}' | tr -d '"')
CHART_NAME=$(grep "^name:" "$CHART_DIR/Chart.yaml" | awk '{print $2}' || true)
CHART_VERSION=$(grep "^version:" "$CHART_DIR/Chart.yaml" | awk '{print $2}' || true)
APP_VERSION=$(grep "^appVersion:" "$CHART_DIR/Chart.yaml" | awk '{print $2}' | tr -d '"' || true)

if [ -z "$CHART_NAME" ]; then
error "Chart name not found"
Expand Down
18 changes: 9 additions & 9 deletions plugins/protect-mcp/test/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
set -uo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
cd "$SCRIPT_DIR" || exit 1

# --- Preflight ---------------------------------------------------------------

Expand Down Expand Up @@ -57,8 +57,8 @@ echo "=== Test 1: PreToolUse permit on Read ==="
INPUT=fixtures/pretool-allow-read.json
npx --yes protect-mcp@0.7.4 evaluate \
--policy fixtures/test-policy.cedar \
--tool "$(extract "$INPUT" tool_name)" \
--input "$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1]))["tool_input"]))' "$INPUT")" \
--tool "$(extract "$INPUT" tool_name || true)" \
--input "$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1]))["tool_input"]))' "$INPUT" || true)" \
--fail-on-missing-policy false >/dev/null 2>&1
check_exit $? 0 "Read is permitted by test-policy.cedar"

Expand All @@ -68,8 +68,8 @@ echo "=== Test 2: PreToolUse permit on Bash git ==="
INPUT=fixtures/pretool-allow-bash-safe.json
npx --yes protect-mcp@0.7.4 evaluate \
--policy fixtures/test-policy.cedar \
--tool "$(extract "$INPUT" tool_name)" \
--input "$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1]))["tool_input"]))' "$INPUT")" \
--tool "$(extract "$INPUT" tool_name || true)" \
--input "$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1]))["tool_input"]))' "$INPUT" || true)" \
--fail-on-missing-policy false >/dev/null 2>&1
check_exit $? 0 "Bash 'git status' is permitted"

Expand All @@ -79,8 +79,8 @@ echo "=== Test 3: PreToolUse forbid on Bash rm -rf ==="
INPUT=fixtures/pretool-deny-bash-destructive.json
npx --yes protect-mcp@0.7.4 evaluate \
--policy fixtures/test-policy.cedar \
--tool "$(extract "$INPUT" tool_name)" \
--input "$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1]))["tool_input"]))' "$INPUT")" \
--tool "$(extract "$INPUT" tool_name || true)" \
--input "$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1]))["tool_input"]))' "$INPUT" || true)" \
--fail-on-missing-policy false >/dev/null 2>&1
check_exit $? 2 "Bash 'rm -rf /' is denied with exit 2"

Expand All @@ -90,8 +90,8 @@ echo "=== Test 4: PreToolUse forbid on Write ==="
INPUT=fixtures/pretool-deny-write.json
npx --yes protect-mcp@0.7.4 evaluate \
--policy fixtures/test-policy.cedar \
--tool "$(extract "$INPUT" tool_name)" \
--input "$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1]))["tool_input"]))' "$INPUT")" \
--tool "$(extract "$INPUT" tool_name || true)" \
--input "$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1]))["tool_input"]))' "$INPUT" || true)" \
--fail-on-missing-policy false >/dev/null 2>&1
check_exit $? 2 "Write is denied with exit 2"

Expand Down
2 changes: 1 addition & 1 deletion plugins/protect-mcp/test/verify-fixtures.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
cd "$SCRIPT_DIR" || exit 1

command -v python3 >/dev/null 2>&1 || { echo "SKIP: python3 required"; exit 77; }

Expand Down
Loading
Loading