How to test the Unbound Cursor plugin on your local machine before marketplace submission.
- Cursor IDE installed (with hooks support)
- Python 3.8+
Clone the repo and run the installer:
git clone https://github.com/websentry-ai/cursor-extension.git
cd cursor-extension
./install.shThis does everything:
- Opens your browser for Unbound authentication
- Saves
UNBOUND_CURSOR_API_KEYto your shell RC file - Restarts Cursor
Hooks are bundled with the plugin and work immediately — no separate download needed.
Run /unbound-setup in any Cursor conversation. The AI will walk you through the setup flow.
./uninstall.shRemoves the API key and log files. Restart Cursor after.
The plugin bundles two files (sourced from websentry-ai/setup):
hooks/hooks.json— registers 9 hooks for Cursor's lifecycle eventshooks/unbound.py— single script that handles all hook events
All hooks point to this single unbound.py script via ${CURSOR_PLUGIN_ROOT}. It reads the UNBOUND_CURSOR_API_KEY env var to authenticate with the Unbound API.
Test A.1: Allow (no policy violation)
- Ask the AI to run a safe command: "list files in the current directory"
- Expected: Command runs normally
Test A.2: Block (policy violation)
- In your Unbound dashboard (https://app.getunbound.ai), create a BLOCK rule for
rm -rf - Ask the AI: "run rm -rf /tmp/test"
- Expected: The command is blocked. Cursor should show the block reason
Test A.3: Fail open (API unreachable)
- Temporarily set an invalid key:
export UNBOUND_CURSOR_API_KEY="invalid-key-12345"
- Restart Cursor, ask the AI to run
ls - Expected: Command runs normally (fail open). Check error log:
cat ~/.cursor/hooks/error.log
Test B.1: Clean prompt
- Type a normal prompt: "What is 2 + 2?"
- Expected: Prompt goes through normally
Test B.2: DLP block
- In your Unbound dashboard, enable DLP guardrails
- Type a prompt containing a fake SSN: "My SSN is 123-45-6789"
- Expected: Prompt is blocked with exit code 2. Cursor should show "PII detected" or similar
Test C.1: Events are logged
- Have a conversation with tool use (shell commands, file reads)
- Check the audit log:
tail -5 ~/.cursor/hooks/agent-audit.log | python3 -m json.tool
- Expected: Entries for
afterShellExecution,afterFileEdit,beforeReadFile,afterAgentResponse
Test D.1: Successful exchange
- Have a short conversation, let the AI use tools
- Close the conversation (triggers
stopevent) - Check the Unbound dashboard — the session should appear
- Check that audit log was cleaned up:
cat ~/.cursor/hooks/agent-audit.log
Test D.2: Offline fallback
- Set an invalid key to simulate API failure
- Restart Cursor, have a conversation, close it
- Expected: Exchange data saved to offline log
Test E.1: Single-command install
- Run:
./install.sh
- Expected: Browser opens for auth, key saved, Cursor restarts. Hooks are bundled and active immediately.
Test E.2: Uninstall
- Run:
./uninstall.sh
- Expected:
UNBOUND_CURSOR_API_KEYcleared, logs cleaned
| File | What to check |
|---|---|
~/.cursor/hooks/agent-audit.log |
Audit trail — verify events are being logged |
~/.cursor/hooks/error.log |
API errors — check for connectivity issues |
You can test the bundled unbound.py directly by piping JSON to it:
# Test beforeShellExecution
echo '{"hook_event_name":"beforeShellExecution","conversation_id":"test-123","command":"ls","model":"gpt-4"}' | \
UNBOUND_CURSOR_API_KEY="your-key" python3 hooks/unbound.py
# Test beforeSubmitPrompt
echo '{"hook_event_name":"beforeSubmitPrompt","conversation_id":"test-123","prompt":"hello world","model":"gpt-4"}' | \
UNBOUND_CURSOR_API_KEY="your-key" python3 hooks/unbound.pyrm -f ~/.cursor/hooks/agent-audit.log
rm -f ~/.cursor/hooks/error.logRun the unit test suite (no Cursor or API key needed):
pip install pytest
python3 -m pytest tests/ -v| # | Test | Status |
|---|---|---|
| A.1 | beforeShellExecution — safe command allowed | |
| A.2 | beforeShellExecution — blocked command denied | |
| A.3 | beforeShellExecution — fail open on API error | |
| B.1 | beforeSubmitPrompt — clean prompt allowed | |
| B.2 | beforeSubmitPrompt — DLP blocks PII | |
| C.1 | Audit — events logged to agent-audit.log | |
| D.1 | stop — exchange sent to dashboard | |
| D.2 | stop — offline fallback on failure | |
| E.1 | Install — single-command setup | |
| E.2 | Uninstall — clean removal |