@elizaos/skills 2.0.0-alpha.10
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.
- package/README.md +126 -0
- package/dist/formatter.d.ts +44 -0
- package/dist/formatter.d.ts.map +1 -0
- package/dist/formatter.js +182 -0
- package/dist/frontmatter.d.ts +39 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +105 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/loader.d.ts +33 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +362 -0
- package/dist/resolver.d.ts +18 -0
- package/dist/resolver.d.ts.map +1 -0
- package/dist/resolver.js +90 -0
- package/dist/types.d.ts +201 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +57 -0
- package/skills/1password/SKILL.md +70 -0
- package/skills/1password/references/cli-examples.md +29 -0
- package/skills/1password/references/get-started.md +17 -0
- package/skills/apple-notes/SKILL.md +77 -0
- package/skills/apple-reminders/SKILL.md +96 -0
- package/skills/bear-notes/SKILL.md +107 -0
- package/skills/bird/SKILL.md +224 -0
- package/skills/blogwatcher/SKILL.md +69 -0
- package/skills/blucli/SKILL.md +47 -0
- package/skills/bluebubbles/SKILL.md +131 -0
- package/skills/camsnap/SKILL.md +45 -0
- package/skills/canvas/SKILL.md +203 -0
- package/skills/clawhub/SKILL.md +77 -0
- package/skills/coding-agent/SKILL.md +284 -0
- package/skills/discord/SKILL.md +578 -0
- package/skills/eightctl/SKILL.md +50 -0
- package/skills/food-order/SKILL.md +48 -0
- package/skills/gemini/SKILL.md +43 -0
- package/skills/gifgrep/SKILL.md +79 -0
- package/skills/github/SKILL.md +77 -0
- package/skills/gog/SKILL.md +116 -0
- package/skills/goplaces/SKILL.md +52 -0
- package/skills/healthcheck/SKILL.md +245 -0
- package/skills/himalaya/SKILL.md +257 -0
- package/skills/himalaya/references/configuration.md +184 -0
- package/skills/himalaya/references/message-composition.md +199 -0
- package/skills/imsg/SKILL.md +74 -0
- package/skills/local-places/SERVER_README.md +101 -0
- package/skills/local-places/SKILL.md +102 -0
- package/skills/local-places/pyproject.toml +21 -0
- package/skills/local-places/src/local_places/__init__.py +2 -0
- package/skills/local-places/src/local_places/google_places.py +314 -0
- package/skills/local-places/src/local_places/main.py +65 -0
- package/skills/local-places/src/local_places/schemas.py +107 -0
- package/skills/mcporter/SKILL.md +61 -0
- package/skills/model-usage/SKILL.md +69 -0
- package/skills/model-usage/references/codexbar-cli.md +33 -0
- package/skills/model-usage/scripts/model_usage.py +310 -0
- package/skills/nano-banana-pro/SKILL.md +58 -0
- package/skills/nano-banana-pro/scripts/generate_image.py +184 -0
- package/skills/nano-pdf/SKILL.md +38 -0
- package/skills/notion/SKILL.md +172 -0
- package/skills/obsidian/SKILL.md +81 -0
- package/skills/openai-image-gen/SKILL.md +89 -0
- package/skills/openai-image-gen/scripts/gen.py +240 -0
- package/skills/openai-whisper/SKILL.md +38 -0
- package/skills/openai-whisper-api/SKILL.md +52 -0
- package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
- package/skills/openhue/SKILL.md +51 -0
- package/skills/oracle/SKILL.md +125 -0
- package/skills/ordercli/SKILL.md +78 -0
- package/skills/peekaboo/SKILL.md +190 -0
- package/skills/sag/SKILL.md +87 -0
- package/skills/security-ask-questions-if-underspecified/.claude-plugin/plugin.json +10 -0
- package/skills/security-ask-questions-if-underspecified/README.md +24 -0
- package/skills/security-ask-questions-if-underspecified/SKILL.md +85 -0
- package/skills/security-ask-questions-if-underspecified/skills/ask-questions-if-underspecified/SKILL.md +85 -0
- package/skills/security-audit-context-building/.claude-plugin/plugin.json +10 -0
- package/skills/security-audit-context-building/README.md +58 -0
- package/skills/security-audit-context-building/SKILL.md +297 -0
- package/skills/security-audit-context-building/commands/audit-context.md +21 -0
- package/skills/security-audit-context-building/skills/audit-context-building/SKILL.md +297 -0
- package/skills/security-audit-context-building/skills/audit-context-building/resources/COMPLETENESS_CHECKLIST.md +47 -0
- package/skills/security-audit-context-building/skills/audit-context-building/resources/FUNCTION_MICRO_ANALYSIS_EXAMPLE.md +355 -0
- package/skills/security-audit-context-building/skills/audit-context-building/resources/OUTPUT_REQUIREMENTS.md +71 -0
- package/skills/security-building-secure-contracts/.claude-plugin/plugin.json +10 -0
- package/skills/security-building-secure-contracts/README.md +241 -0
- package/skills/security-building-secure-contracts/SKILL.md +67 -0
- package/skills/security-building-secure-contracts/skills/algorand-vulnerability-scanner/SKILL.md +284 -0
- package/skills/security-building-secure-contracts/skills/algorand-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +405 -0
- package/skills/security-building-secure-contracts/skills/audit-prep-assistant/SKILL.md +409 -0
- package/skills/security-building-secure-contracts/skills/cairo-vulnerability-scanner/SKILL.md +329 -0
- package/skills/security-building-secure-contracts/skills/cairo-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +722 -0
- package/skills/security-building-secure-contracts/skills/code-maturity-assessor/SKILL.md +218 -0
- package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/ASSESSMENT_CRITERIA.md +355 -0
- package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/EXAMPLE_REPORT.md +248 -0
- package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/REPORT_FORMAT.md +33 -0
- package/skills/security-building-secure-contracts/skills/cosmos-vulnerability-scanner/SKILL.md +334 -0
- package/skills/security-building-secure-contracts/skills/cosmos-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +740 -0
- package/skills/security-building-secure-contracts/skills/guidelines-advisor/SKILL.md +252 -0
- package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/ASSESSMENT_AREAS.md +329 -0
- package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/DELIVERABLES.md +118 -0
- package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/EXAMPLE_REPORT.md +298 -0
- package/skills/security-building-secure-contracts/skills/secure-workflow-guide/SKILL.md +161 -0
- package/skills/security-building-secure-contracts/skills/secure-workflow-guide/resources/EXAMPLE_REPORT.md +279 -0
- package/skills/security-building-secure-contracts/skills/secure-workflow-guide/resources/WORKFLOW_STEPS.md +132 -0
- package/skills/security-building-secure-contracts/skills/solana-vulnerability-scanner/SKILL.md +389 -0
- package/skills/security-building-secure-contracts/skills/solana-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +669 -0
- package/skills/security-building-secure-contracts/skills/substrate-vulnerability-scanner/SKILL.md +298 -0
- package/skills/security-building-secure-contracts/skills/substrate-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +791 -0
- package/skills/security-building-secure-contracts/skills/token-integration-analyzer/SKILL.md +362 -0
- package/skills/security-building-secure-contracts/skills/token-integration-analyzer/resources/ASSESSMENT_CATEGORIES.md +571 -0
- package/skills/security-building-secure-contracts/skills/token-integration-analyzer/resources/REPORT_TEMPLATES.md +141 -0
- package/skills/security-building-secure-contracts/skills/ton-vulnerability-scanner/SKILL.md +388 -0
- package/skills/security-building-secure-contracts/skills/ton-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +595 -0
- package/skills/security-differential-review/.claude-plugin/plugin.json +10 -0
- package/skills/security-differential-review/README.md +109 -0
- package/skills/security-differential-review/SKILL.md +220 -0
- package/skills/security-differential-review/commands/diff-review.md +21 -0
- package/skills/security-differential-review/skills/differential-review/SKILL.md +220 -0
- package/skills/security-differential-review/skills/differential-review/adversarial.md +203 -0
- package/skills/security-differential-review/skills/differential-review/methodology.md +234 -0
- package/skills/security-differential-review/skills/differential-review/patterns.md +300 -0
- package/skills/security-differential-review/skills/differential-review/reporting.md +369 -0
- package/skills/security-entry-point-analyzer/.claude-plugin/plugin.json +10 -0
- package/skills/security-entry-point-analyzer/README.md +74 -0
- package/skills/security-entry-point-analyzer/SKILL.md +251 -0
- package/skills/security-entry-point-analyzer/commands/entry-points.md +18 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/SKILL.md +251 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/cosmwasm.md +182 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/move-aptos.md +107 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/move-sui.md +87 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/solana.md +155 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/solidity.md +135 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/ton.md +185 -0
- package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/vyper.md +141 -0
- package/skills/security-fix-review/.claude-plugin/plugin.json +13 -0
- package/skills/security-fix-review/README.md +118 -0
- package/skills/security-fix-review/SKILL.md +264 -0
- package/skills/security-fix-review/commands/fix-review.md +24 -0
- package/skills/security-fix-review/skills/fix-review/SKILL.md +264 -0
- package/skills/security-fix-review/skills/fix-review/references/bug-detection.md +408 -0
- package/skills/security-fix-review/skills/fix-review/references/finding-matching.md +298 -0
- package/skills/security-fix-review/skills/fix-review/references/report-parsing.md +398 -0
- package/skills/security-insecure-defaults/.claude-plugin/plugin.json +10 -0
- package/skills/security-insecure-defaults/README.md +45 -0
- package/skills/security-insecure-defaults/SKILL.md +117 -0
- package/skills/security-insecure-defaults/skills/insecure-defaults/SKILL.md +117 -0
- package/skills/security-insecure-defaults/skills/insecure-defaults/references/examples.md +409 -0
- package/skills/security-modern-python/.claude-plugin/plugin.json +10 -0
- package/skills/security-modern-python/README.md +58 -0
- package/skills/security-modern-python/SKILL.md +333 -0
- package/skills/security-modern-python/hooks/hooks.json +16 -0
- package/skills/security-modern-python/hooks/intercept-legacy-python.bats +388 -0
- package/skills/security-modern-python/hooks/intercept-legacy-python.sh +109 -0
- package/skills/security-modern-python/hooks/test_helper.bash +75 -0
- package/skills/security-modern-python/skills/modern-python/SKILL.md +333 -0
- package/skills/security-modern-python/skills/modern-python/references/dependabot.md +43 -0
- package/skills/security-modern-python/skills/modern-python/references/migration-checklist.md +141 -0
- package/skills/security-modern-python/skills/modern-python/references/pep723-scripts.md +259 -0
- package/skills/security-modern-python/skills/modern-python/references/prek.md +211 -0
- package/skills/security-modern-python/skills/modern-python/references/pyproject.md +254 -0
- package/skills/security-modern-python/skills/modern-python/references/ruff-config.md +240 -0
- package/skills/security-modern-python/skills/modern-python/references/security-setup.md +255 -0
- package/skills/security-modern-python/skills/modern-python/references/testing.md +284 -0
- package/skills/security-modern-python/skills/modern-python/references/uv-commands.md +200 -0
- package/skills/security-modern-python/skills/modern-python/templates/dependabot.yml +36 -0
- package/skills/security-modern-python/skills/modern-python/templates/pre-commit-config.yaml +66 -0
- package/skills/security-property-based-testing/.claude-plugin/plugin.json +9 -0
- package/skills/security-property-based-testing/README.md +47 -0
- package/skills/security-property-based-testing/SKILL.md +109 -0
- package/skills/security-property-based-testing/skills/property-based-testing/README.md +88 -0
- package/skills/security-property-based-testing/skills/property-based-testing/SKILL.md +109 -0
- package/skills/security-property-based-testing/skills/property-based-testing/references/design.md +191 -0
- package/skills/security-property-based-testing/skills/property-based-testing/references/generating.md +200 -0
- package/skills/security-property-based-testing/skills/property-based-testing/references/libraries.md +130 -0
- package/skills/security-property-based-testing/skills/property-based-testing/references/refactoring.md +181 -0
- package/skills/security-property-based-testing/skills/property-based-testing/references/reviewing.md +209 -0
- package/skills/security-property-based-testing/skills/property-based-testing/references/strategies.md +124 -0
- package/skills/semgrep-rule-creator/.claude-plugin/plugin.json +8 -0
- package/skills/semgrep-rule-creator/README.md +43 -0
- package/skills/semgrep-rule-creator/SKILL.md +168 -0
- package/skills/semgrep-rule-creator/commands/semgrep-rule.md +26 -0
- package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/SKILL.md +168 -0
- package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/references/quick-reference.md +203 -0
- package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/references/workflow.md +240 -0
- package/skills/session-logs/SKILL.md +115 -0
- package/skills/sharp-edges/.claude-plugin/plugin.json +10 -0
- package/skills/sharp-edges/README.md +48 -0
- package/skills/sharp-edges/SKILL.md +292 -0
- package/skills/sharp-edges/skills/sharp-edges/SKILL.md +292 -0
- package/skills/sharp-edges/skills/sharp-edges/references/auth-patterns.md +252 -0
- package/skills/sharp-edges/skills/sharp-edges/references/case-studies.md +274 -0
- package/skills/sharp-edges/skills/sharp-edges/references/config-patterns.md +333 -0
- package/skills/sharp-edges/skills/sharp-edges/references/crypto-apis.md +190 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-c.md +205 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-csharp.md +285 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-go.md +270 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-java.md +263 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-javascript.md +269 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-kotlin.md +265 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-php.md +245 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-python.md +274 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-ruby.md +273 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-rust.md +272 -0
- package/skills/sharp-edges/skills/sharp-edges/references/lang-swift.md +287 -0
- package/skills/sharp-edges/skills/sharp-edges/references/language-specific.md +588 -0
- package/skills/sherpa-onnx-tts/SKILL.md +103 -0
- package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +178 -0
- package/skills/skill-creator/SKILL.md +370 -0
- package/skills/skill-creator/license.txt +202 -0
- package/skills/skill-creator/scripts/init_skill.py +378 -0
- package/skills/skill-creator/scripts/package_skill.py +111 -0
- package/skills/skill-creator/scripts/quick_validate.py +101 -0
- package/skills/slack/SKILL.md +144 -0
- package/skills/songsee/SKILL.md +49 -0
- package/skills/sonoscli/SKILL.md +46 -0
- package/skills/spec-to-code-compliance/.claude-plugin/plugin.json +10 -0
- package/skills/spec-to-code-compliance/README.md +67 -0
- package/skills/spec-to-code-compliance/SKILL.md +349 -0
- package/skills/spec-to-code-compliance/commands/spec-compliance.md +22 -0
- package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/SKILL.md +349 -0
- package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/COMPLETENESS_CHECKLIST.md +69 -0
- package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/IR_EXAMPLES.md +417 -0
- package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/OUTPUT_REQUIREMENTS.md +105 -0
- package/skills/spotify-player/SKILL.md +64 -0
- package/skills/static-analysis/.claude-plugin/plugin.json +8 -0
- package/skills/static-analysis/README.md +59 -0
- package/skills/static-analysis/SKILL.md +91 -0
- package/skills/static-analysis/skills/codeql/SKILL.md +315 -0
- package/skills/static-analysis/skills/sarif-parsing/SKILL.md +479 -0
- package/skills/static-analysis/skills/sarif-parsing/resources/jq-queries.md +162 -0
- package/skills/static-analysis/skills/sarif-parsing/resources/sarif_helpers.py +331 -0
- package/skills/static-analysis/skills/semgrep/SKILL.md +337 -0
- package/skills/summarize/SKILL.md +87 -0
- package/skills/testing-handbook-skills/.claude-plugin/plugin.json +8 -0
- package/skills/testing-handbook-skills/README.md +241 -0
- package/skills/testing-handbook-skills/SKILL.md +104 -0
- package/skills/testing-handbook-skills/scripts/pyproject.toml +8 -0
- package/skills/testing-handbook-skills/scripts/validate-skills.py +657 -0
- package/skills/testing-handbook-skills/skills/address-sanitizer/SKILL.md +341 -0
- package/skills/testing-handbook-skills/skills/aflpp/SKILL.md +640 -0
- package/skills/testing-handbook-skills/skills/atheris/SKILL.md +515 -0
- package/skills/testing-handbook-skills/skills/cargo-fuzz/SKILL.md +454 -0
- package/skills/testing-handbook-skills/skills/codeql/SKILL.md +549 -0
- package/skills/testing-handbook-skills/skills/constant-time-testing/SKILL.md +507 -0
- package/skills/testing-handbook-skills/skills/coverage-analysis/SKILL.md +607 -0
- package/skills/testing-handbook-skills/skills/fuzzing-dictionary/SKILL.md +297 -0
- package/skills/testing-handbook-skills/skills/fuzzing-obstacles/SKILL.md +426 -0
- package/skills/testing-handbook-skills/skills/harness-writing/SKILL.md +614 -0
- package/skills/testing-handbook-skills/skills/libafl/SKILL.md +625 -0
- package/skills/testing-handbook-skills/skills/libfuzzer/SKILL.md +795 -0
- package/skills/testing-handbook-skills/skills/ossfuzz/SKILL.md +426 -0
- package/skills/testing-handbook-skills/skills/ruzzy/SKILL.md +443 -0
- package/skills/testing-handbook-skills/skills/semgrep/SKILL.md +601 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/SKILL.md +372 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/agent-prompt.md +280 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/discovery.md +452 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/domain-skill.md +504 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/fuzzer-skill.md +454 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/technique-skill.md +527 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/tool-skill.md +366 -0
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/testing.md +482 -0
- package/skills/testing-handbook-skills/skills/wycheproof/SKILL.md +533 -0
- package/skills/things-mac/SKILL.md +86 -0
- package/skills/tmux/SKILL.md +135 -0
- package/skills/tmux/scripts/find-sessions.sh +112 -0
- package/skills/tmux/scripts/wait-for-text.sh +83 -0
- package/skills/trello/SKILL.md +95 -0
- package/skills/variant-analysis/.claude-plugin/plugin.json +8 -0
- package/skills/variant-analysis/README.md +41 -0
- package/skills/variant-analysis/SKILL.md +142 -0
- package/skills/variant-analysis/commands/variants.md +23 -0
- package/skills/variant-analysis/skills/variant-analysis/METHODOLOGY.md +327 -0
- package/skills/variant-analysis/skills/variant-analysis/SKILL.md +142 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/codeql/cpp.ql +119 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/codeql/go.ql +69 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/codeql/java.ql +71 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/codeql/javascript.ql +63 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/codeql/python.ql +80 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/cpp.yaml +98 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/go.yaml +63 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/java.yaml +61 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/javascript.yaml +60 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/python.yaml +72 -0
- package/skills/variant-analysis/skills/variant-analysis/resources/variant-report-template.md +75 -0
- package/skills/video-frames/SKILL.md +46 -0
- package/skills/video-frames/scripts/frame.sh +81 -0
- package/skills/voice-call/SKILL.md +45 -0
- package/skills/wacli/SKILL.md +72 -0
- package/skills/weather/SKILL.md +54 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
# Tests for intercept-legacy-python.sh hook
|
|
3
|
+
|
|
4
|
+
load test_helper
|
|
5
|
+
|
|
6
|
+
# =============================================================================
|
|
7
|
+
# Early Exit Tests
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
@test "exits silently when uv is not available" {
|
|
11
|
+
# Run with restricted PATH that excludes uv
|
|
12
|
+
run_hook_no_uv "python script.py"
|
|
13
|
+
assert_allow
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@test "exits silently on invalid JSON input" {
|
|
17
|
+
run bash -c 'echo "not json" | '"'$HOOK_SCRIPT'"
|
|
18
|
+
assert_allow
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@test "exits silently on empty JSON" {
|
|
22
|
+
run bash -c 'echo "{}" | '"'$HOOK_SCRIPT'"
|
|
23
|
+
assert_allow
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@test "exits silently when command is empty string" {
|
|
27
|
+
run bash -c 'echo "{\"tool_input\":{\"command\":\"\"}}" | '"'$HOOK_SCRIPT'"
|
|
28
|
+
assert_allow
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@test "exits silently when command field is missing" {
|
|
32
|
+
run bash -c 'echo "{\"tool_input\":{}}" | '"'$HOOK_SCRIPT'"
|
|
33
|
+
assert_allow
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# =============================================================================
|
|
37
|
+
# Allow: uv run (proper usage)
|
|
38
|
+
# =============================================================================
|
|
39
|
+
|
|
40
|
+
@test "allows uv run python" {
|
|
41
|
+
run_hook "uv run python script.py"
|
|
42
|
+
assert_allow
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@test "allows uv run with script directly" {
|
|
46
|
+
run_hook "uv run script.py"
|
|
47
|
+
assert_allow
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@test "allows uv run python -m module" {
|
|
51
|
+
run_hook "uv run python -m pytest"
|
|
52
|
+
assert_allow
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@test "allows uv run after semicolon" {
|
|
56
|
+
run_hook "cd project; uv run python script.py"
|
|
57
|
+
assert_allow
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@test "allows uv run after &&" {
|
|
61
|
+
run_hook "cd project && uv run python script.py"
|
|
62
|
+
assert_allow
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# =============================================================================
|
|
66
|
+
# Allow: Diagnostic Commands
|
|
67
|
+
# =============================================================================
|
|
68
|
+
|
|
69
|
+
@test "allows which python" {
|
|
70
|
+
run_hook "which python"
|
|
71
|
+
assert_allow
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@test "allows which python3" {
|
|
75
|
+
run_hook "which python3"
|
|
76
|
+
assert_allow
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@test "allows which pip" {
|
|
80
|
+
run_hook "which pip"
|
|
81
|
+
assert_allow
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@test "allows which pip3" {
|
|
85
|
+
run_hook "which pip3"
|
|
86
|
+
assert_allow
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@test "allows type python" {
|
|
90
|
+
run_hook "type python"
|
|
91
|
+
assert_allow
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@test "allows type python3" {
|
|
95
|
+
run_hook "type python3"
|
|
96
|
+
assert_allow
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@test "allows whereis python" {
|
|
100
|
+
run_hook "whereis python"
|
|
101
|
+
assert_allow
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@test "allows whereis pip" {
|
|
105
|
+
run_hook "whereis pip"
|
|
106
|
+
assert_allow
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@test "allows command -v python" {
|
|
110
|
+
run_hook "command -v python"
|
|
111
|
+
assert_allow
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@test "allows command -v python3" {
|
|
115
|
+
run_hook "command -v python3"
|
|
116
|
+
assert_allow
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@test "allows command -v pip" {
|
|
120
|
+
run_hook "command -v pip"
|
|
121
|
+
assert_allow
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@test "allows command -v pip3" {
|
|
125
|
+
run_hook "command -v pip3"
|
|
126
|
+
assert_allow
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
# =============================================================================
|
|
130
|
+
# Allow: Search Tools (python as argument, not command)
|
|
131
|
+
# =============================================================================
|
|
132
|
+
|
|
133
|
+
@test "allows grep python file.txt" {
|
|
134
|
+
run_hook "grep python file.txt"
|
|
135
|
+
assert_allow
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@test "allows grep -r python src/" {
|
|
139
|
+
run_hook "grep -r python src/"
|
|
140
|
+
assert_allow
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@test "allows rg python src/" {
|
|
144
|
+
run_hook "rg python src/"
|
|
145
|
+
assert_allow
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@test "allows ag python ." {
|
|
149
|
+
run_hook "ag python ."
|
|
150
|
+
assert_allow
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@test "allows ack python" {
|
|
154
|
+
run_hook "ack python"
|
|
155
|
+
assert_allow
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@test "allows find with python in name pattern" {
|
|
159
|
+
run_hook "find . -name '*.py'"
|
|
160
|
+
assert_allow
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@test "allows find with python string pattern" {
|
|
164
|
+
run_hook "find . -name 'python*'"
|
|
165
|
+
assert_allow
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
@test "allows grep piped to non-python command" {
|
|
169
|
+
run_hook "grep -l TODO | xargs rm"
|
|
170
|
+
assert_allow
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
@test "allows find piped to grep" {
|
|
174
|
+
run_hook "find . -name '*.py' | grep test"
|
|
175
|
+
assert_allow
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
# =============================================================================
|
|
179
|
+
# Deny: Direct Python Execution
|
|
180
|
+
# =============================================================================
|
|
181
|
+
|
|
182
|
+
@test "denies python script.py" {
|
|
183
|
+
run_hook "python script.py"
|
|
184
|
+
assert_deny
|
|
185
|
+
assert_suggestion_contains "uv run python"
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@test "denies python3 script.py" {
|
|
189
|
+
run_hook "python3 script.py"
|
|
190
|
+
assert_deny
|
|
191
|
+
assert_suggestion_contains "uv run python"
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@test "denies python -c 'print(1)'" {
|
|
195
|
+
run_hook "python -c 'print(1)'"
|
|
196
|
+
assert_deny
|
|
197
|
+
assert_suggestion_contains "uv run python"
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@test "denies python3 -m pytest" {
|
|
201
|
+
run_hook "python3 -m pytest"
|
|
202
|
+
assert_deny
|
|
203
|
+
assert_suggestion_contains "uv run python -m module"
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
@test "denies python -m module" {
|
|
207
|
+
run_hook "python -m http.server"
|
|
208
|
+
assert_deny
|
|
209
|
+
assert_suggestion_contains "uv run python -m module"
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
@test "denies python -m pip install" {
|
|
213
|
+
run_hook "python -m pip install requests"
|
|
214
|
+
assert_deny
|
|
215
|
+
assert_suggestion_contains "uv add"
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@test "denies python3 -m pip install" {
|
|
219
|
+
run_hook "python3 -m pip install requests"
|
|
220
|
+
assert_deny
|
|
221
|
+
assert_suggestion_contains "uv add"
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
# =============================================================================
|
|
225
|
+
# Deny: Pip Commands
|
|
226
|
+
# =============================================================================
|
|
227
|
+
|
|
228
|
+
@test "denies pip install" {
|
|
229
|
+
run_hook "pip install requests"
|
|
230
|
+
assert_deny
|
|
231
|
+
assert_suggestion_contains "uv add"
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
@test "denies pip3 install" {
|
|
235
|
+
run_hook "pip3 install requests"
|
|
236
|
+
assert_deny
|
|
237
|
+
assert_suggestion_contains "uv add"
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@test "denies pip uninstall" {
|
|
241
|
+
run_hook "pip uninstall requests"
|
|
242
|
+
assert_deny
|
|
243
|
+
assert_suggestion_contains "uv remove"
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@test "denies pip3 uninstall" {
|
|
247
|
+
run_hook "pip3 uninstall foo"
|
|
248
|
+
assert_deny
|
|
249
|
+
assert_suggestion_contains "uv remove"
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
@test "denies pip freeze" {
|
|
253
|
+
run_hook "pip freeze"
|
|
254
|
+
assert_deny
|
|
255
|
+
assert_suggestion_contains "uv export"
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
@test "denies pip3 freeze" {
|
|
259
|
+
run_hook "pip3 freeze"
|
|
260
|
+
assert_deny
|
|
261
|
+
assert_suggestion_contains "uv export"
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
@test "denies pip list" {
|
|
265
|
+
run_hook "pip list"
|
|
266
|
+
assert_deny
|
|
267
|
+
assert_suggestion_contains "uv"
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
@test "denies pip show" {
|
|
271
|
+
run_hook "pip show requests"
|
|
272
|
+
assert_deny
|
|
273
|
+
assert_suggestion_contains "uv"
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
# =============================================================================
|
|
277
|
+
# Deny: uv pip (legacy interface)
|
|
278
|
+
# =============================================================================
|
|
279
|
+
|
|
280
|
+
@test "denies uv pip install" {
|
|
281
|
+
run_hook "uv pip install requests"
|
|
282
|
+
assert_deny
|
|
283
|
+
assert_suggestion_contains "uv pip"
|
|
284
|
+
assert_suggestion_contains "legacy"
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@test "denies uv pip sync" {
|
|
288
|
+
run_hook "uv pip sync requirements.txt"
|
|
289
|
+
assert_deny
|
|
290
|
+
assert_suggestion_contains "uv pip"
|
|
291
|
+
assert_suggestion_contains "legacy"
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
@test "denies uv pip compile" {
|
|
295
|
+
run_hook "uv pip compile requirements.in"
|
|
296
|
+
assert_deny
|
|
297
|
+
assert_suggestion_contains "uv pip"
|
|
298
|
+
assert_suggestion_contains "legacy"
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
@test "denies uv pip freeze" {
|
|
302
|
+
run_hook "uv pip freeze"
|
|
303
|
+
assert_deny
|
|
304
|
+
assert_suggestion_contains "uv pip"
|
|
305
|
+
assert_suggestion_contains "legacy"
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
# =============================================================================
|
|
309
|
+
# Deny: Piped Commands with Python Execution
|
|
310
|
+
# =============================================================================
|
|
311
|
+
|
|
312
|
+
@test "denies python3 script.py | grep foo" {
|
|
313
|
+
run_hook "python3 script.py | grep foo"
|
|
314
|
+
assert_deny
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
@test "denies python script.py | head" {
|
|
318
|
+
run_hook "python script.py | head"
|
|
319
|
+
assert_deny
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
@test "denies find | xargs python3" {
|
|
323
|
+
run_hook "find . -name '*.py' | xargs python3"
|
|
324
|
+
assert_deny
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
@test "denies grep | xargs python script.py" {
|
|
328
|
+
run_hook "grep -l test | xargs python script.py"
|
|
329
|
+
assert_deny
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
@test "denies cat file | python3" {
|
|
333
|
+
run_hook "cat file.txt | python3"
|
|
334
|
+
assert_deny
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
@test "denies echo | python -c" {
|
|
338
|
+
run_hook "echo 'data' | python -c 'import sys; print(sys.stdin.read())'"
|
|
339
|
+
assert_deny
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
# =============================================================================
|
|
343
|
+
# Deny: Compound Commands
|
|
344
|
+
# =============================================================================
|
|
345
|
+
|
|
346
|
+
@test "denies python after semicolon" {
|
|
347
|
+
run_hook "cd project; python script.py"
|
|
348
|
+
assert_deny
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
@test "denies python after &&" {
|
|
352
|
+
run_hook "cd project && python script.py"
|
|
353
|
+
assert_deny
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
@test "denies python in subshell" {
|
|
357
|
+
run_hook "output=\$(python script.py)"
|
|
358
|
+
assert_deny
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
@test "denies pip after semicolon" {
|
|
362
|
+
run_hook "cd project; pip install requests"
|
|
363
|
+
assert_deny
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
# =============================================================================
|
|
367
|
+
# Edge Cases
|
|
368
|
+
# =============================================================================
|
|
369
|
+
|
|
370
|
+
@test "allows command with python in path component" {
|
|
371
|
+
run_hook "cat /usr/bin/python3"
|
|
372
|
+
assert_allow
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@test "allows ls of python directory" {
|
|
376
|
+
run_hook "ls ~/.python_history"
|
|
377
|
+
assert_allow
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
@test "denies bare python with no args" {
|
|
381
|
+
run_hook "python"
|
|
382
|
+
assert_deny
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
@test "denies bare python3 with no args" {
|
|
386
|
+
run_hook "python3"
|
|
387
|
+
assert_deny
|
|
388
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Fast exit if uv not available
|
|
5
|
+
command -v uv &>/dev/null || exit 0
|
|
6
|
+
|
|
7
|
+
# Parse JSON input
|
|
8
|
+
input_command=$(jq -r '.tool_input.command // empty' 2>/dev/null) || exit 0
|
|
9
|
+
[[ -z "$input_command" ]] && exit 0
|
|
10
|
+
|
|
11
|
+
suggestion=""
|
|
12
|
+
|
|
13
|
+
# Skip if the command uses uv run (the proper way)
|
|
14
|
+
# This handles: uv run python, uv run script.py, etc.
|
|
15
|
+
if [[ $input_command =~ (^|[[:space:];|&])uv[[:space:]]+run[[:space:]] ]]; then
|
|
16
|
+
exit 0
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# Skip diagnostic commands (checking python location, not executing it)
|
|
20
|
+
if [[ $input_command =~ (^|[[:space:];|&])(which|type|whereis)[[:space:]]+(python3?|pip3?)([[:space:]]|$) ]]; then
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
if [[ $input_command =~ command[[:space:]]+-v[[:space:]]+(python3?|pip3?)([[:space:]]|$) ]]; then
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Skip search tools when python/pip is NOT being executed
|
|
28
|
+
# Handles: grep python (OK), python | grep (DENY), find | xargs python (DENY)
|
|
29
|
+
if [[ $input_command =~ (^|[[:space:];|&])(grep|rg|ag|ack|find)[[:space:]] ]]; then
|
|
30
|
+
# Check for python/pip at COMMAND position before any pipe
|
|
31
|
+
# Command position: start of string (with optional whitespace) or after ; or &
|
|
32
|
+
before_pipe="${input_command%%|*}"
|
|
33
|
+
py_at_start='^[[:space:]]*(python3?|pip3?)([[:space:]]|$)'
|
|
34
|
+
py_after_sep='[;&][[:space:]]*(python3?|pip3?)([[:space:]]|$)'
|
|
35
|
+
if [[ $before_pipe =~ $py_at_start ]] || [[ $before_pipe =~ $py_after_sep ]]; then
|
|
36
|
+
: # Python executes before pipe - fall through to deny
|
|
37
|
+
# Check for xargs/parallel invoking python/pip after pipe
|
|
38
|
+
elif [[ $input_command == *"|"* ]]; then
|
|
39
|
+
after_pipe="${input_command#*|}"
|
|
40
|
+
if [[ $after_pipe =~ (xargs|parallel)[[:space:]] ]] &&
|
|
41
|
+
[[ $after_pipe =~ (python3?|pip3?)([[:space:]]|$) ]]; then
|
|
42
|
+
: # xargs/parallel invokes python - fall through to deny
|
|
43
|
+
else
|
|
44
|
+
exit 0 # No python execution found
|
|
45
|
+
fi
|
|
46
|
+
else
|
|
47
|
+
exit 0 # No pipe, search tool only - python is just an argument
|
|
48
|
+
fi
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Pattern matching for legacy commands
|
|
52
|
+
# Match at: start of line, after ; && || | $( or whitespace
|
|
53
|
+
# Captures the matched command (python/python3/pip/pip3) in group 2
|
|
54
|
+
legacy_pattern='(^|[;&|]|\$\(|[[:space:]])(python3?|pip3?)([[:space:]]|$)'
|
|
55
|
+
|
|
56
|
+
if [[ $input_command =~ $legacy_pattern ]]; then
|
|
57
|
+
matched="${BASH_REMATCH[2]}"
|
|
58
|
+
|
|
59
|
+
# Determine suggestion based on what was matched
|
|
60
|
+
# Build patterns using the matched command
|
|
61
|
+
# shellcheck disable=SC2016
|
|
62
|
+
case "$matched" in
|
|
63
|
+
python | python3)
|
|
64
|
+
pip_pattern="${matched}[[:space:]]+-m[[:space:]]+pip"
|
|
65
|
+
module_pattern="${matched}[[:space:]]+-m[[:space:]]"
|
|
66
|
+
if [[ $input_command =~ $pip_pattern ]]; then
|
|
67
|
+
suggestion='`python -m pip` -> `uv add`/`uv remove`'
|
|
68
|
+
elif [[ $input_command =~ $module_pattern ]]; then
|
|
69
|
+
suggestion='`python -m module` -> `uv run python -m module`'
|
|
70
|
+
else
|
|
71
|
+
suggestion='`python` -> `uv run python`'
|
|
72
|
+
fi
|
|
73
|
+
;;
|
|
74
|
+
pip | pip3)
|
|
75
|
+
install_pattern="${matched}[[:space:]]+install"
|
|
76
|
+
uninstall_pattern="${matched}[[:space:]]+uninstall"
|
|
77
|
+
freeze_pattern="${matched}[[:space:]]+freeze"
|
|
78
|
+
if [[ $input_command =~ $install_pattern ]]; then
|
|
79
|
+
suggestion='`pip install` -> `uv add` or `uv run --with pkg`'
|
|
80
|
+
elif [[ $input_command =~ $uninstall_pattern ]]; then
|
|
81
|
+
suggestion='`pip uninstall` -> `uv remove`'
|
|
82
|
+
elif [[ $input_command =~ $freeze_pattern ]]; then
|
|
83
|
+
suggestion='`pip freeze` -> `uv export`'
|
|
84
|
+
else
|
|
85
|
+
suggestion='`pip` -> use `uv` commands instead'
|
|
86
|
+
fi
|
|
87
|
+
;;
|
|
88
|
+
esac
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# Also check for `uv pip` (legacy interface)
|
|
92
|
+
uv_pip_pattern='(^|[[:space:];|&])uv[[:space:]]+pip([[:space:]]|$)'
|
|
93
|
+
if [[ $input_command =~ $uv_pip_pattern ]]; then
|
|
94
|
+
# shellcheck disable=SC2016
|
|
95
|
+
suggestion='`uv pip` is legacy. Use: `uv add`, `uv remove`, `uv sync`'
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
[[ -z "$suggestion" ]] && exit 0
|
|
99
|
+
|
|
100
|
+
# Output denial with suggestion
|
|
101
|
+
cat <<EOF
|
|
102
|
+
{
|
|
103
|
+
"hookSpecificOutput": {
|
|
104
|
+
"hookEventName": "PreToolUse",
|
|
105
|
+
"permissionDecision": "deny",
|
|
106
|
+
"permissionDecisionReason": "Use uv instead: ${suggestion}"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
EOF
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Test helper functions for intercept-legacy-python.sh BATS tests
|
|
3
|
+
# shellcheck disable=SC2154 # status/output are BATS-provided variables
|
|
4
|
+
# shellcheck disable=SC2016 # Single quotes for jq filter are intentional
|
|
5
|
+
|
|
6
|
+
# Path to the hook script under test
|
|
7
|
+
HOOK_SCRIPT="${BATS_TEST_DIRNAME}/intercept-legacy-python.sh"
|
|
8
|
+
|
|
9
|
+
# Run the hook with a bash command
|
|
10
|
+
# Usage: run_hook "python script.py"
|
|
11
|
+
# Uses jq to properly escape the command string for JSON
|
|
12
|
+
run_hook() {
|
|
13
|
+
local cmd="$1"
|
|
14
|
+
# Use jq to create properly escaped JSON, pipe directly to script
|
|
15
|
+
run bash -c 'jq -n --arg cmd "$1" '"'"'{"tool_input":{"command":$cmd}}'"'"' | "$2"' _ "$cmd" "$HOOK_SCRIPT"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# Run hook without uv available (for testing early exit)
|
|
19
|
+
# Usage: run_hook_no_uv "python script.py"
|
|
20
|
+
run_hook_no_uv() {
|
|
21
|
+
local cmd="$1"
|
|
22
|
+
# Create a subshell with restricted PATH that excludes uv
|
|
23
|
+
# Suppress stderr to ignore jq's "Broken pipe" when script exits early
|
|
24
|
+
run env PATH=/usr/bin:/bin bash -c 'jq -n --arg cmd "$1" '"'"'{"tool_input":{"command":$cmd}}'"'"' 2>/dev/null | "$2"' _ "$cmd" "$HOOK_SCRIPT"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# Assert the hook allowed the command (exit 0, no output)
|
|
28
|
+
assert_allow() {
|
|
29
|
+
if [[ $status -ne 0 ]]; then
|
|
30
|
+
echo "Expected exit 0 (allow), got exit $status"
|
|
31
|
+
echo "Output: $output"
|
|
32
|
+
return 1
|
|
33
|
+
fi
|
|
34
|
+
if [[ -n "$output" ]]; then
|
|
35
|
+
echo "Expected no output (allow), got:"
|
|
36
|
+
echo "$output"
|
|
37
|
+
return 1
|
|
38
|
+
fi
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Assert the hook denied the command (JSON output with deny decision)
|
|
42
|
+
assert_deny() {
|
|
43
|
+
if [[ $status -ne 0 ]]; then
|
|
44
|
+
echo "Expected exit 0 with deny JSON, got exit $status"
|
|
45
|
+
echo "Output: $output"
|
|
46
|
+
return 1
|
|
47
|
+
fi
|
|
48
|
+
if [[ -z "$output" ]]; then
|
|
49
|
+
echo "Expected deny JSON output, got empty"
|
|
50
|
+
return 1
|
|
51
|
+
fi
|
|
52
|
+
if ! echo "$output" | jq -e '.hookSpecificOutput.permissionDecision == "deny"' >/dev/null 2>&1; then
|
|
53
|
+
echo "Expected permissionDecision: deny"
|
|
54
|
+
echo "Output: $output"
|
|
55
|
+
return 1
|
|
56
|
+
fi
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Assert the suggestion contains expected text
|
|
60
|
+
# Usage: assert_suggestion_contains "uv run python"
|
|
61
|
+
assert_suggestion_contains() {
|
|
62
|
+
local expected="$1"
|
|
63
|
+
local reason
|
|
64
|
+
reason=$(echo "$output" | jq -r '.hookSpecificOutput.permissionDecisionReason // empty' 2>/dev/null)
|
|
65
|
+
if [[ -z "$reason" ]]; then
|
|
66
|
+
echo "No permissionDecisionReason found in output"
|
|
67
|
+
echo "Output: $output"
|
|
68
|
+
return 1
|
|
69
|
+
fi
|
|
70
|
+
if [[ "$reason" != *"$expected"* ]]; then
|
|
71
|
+
echo "Expected suggestion to contain: $expected"
|
|
72
|
+
echo "Got: $reason"
|
|
73
|
+
return 1
|
|
74
|
+
fi
|
|
75
|
+
}
|