Add opt-in telemetry reporting#4
Open
rishiy15 wants to merge 1 commit into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds opt-in, no-PII telemetry to the plugin so 1Password can measure plugin adoption and the prevalence of common validation outcomes (allow/deny, missing vs. disabled mounts). Events are written as JSON lines to a file that the 1Password desktop app ingests and forwards to
1Password's telemetry pipeline. This brings the cursor-plugin to parity with the equivalent instrumentation in the agent-hooks repo so the two can be unioned on a single dashboard.
This is the producer half only — it writes event files. Ingestion/forwarding is handled by the 1Password desktop app; this PR has no network calls of its own.
What & why
The hook already knows, per invocation, whether it allowed or denied, why it denied, how it discovered env files, and how long it took. Capturing that (bucketed, de-identified) lets us answer "are people actually using the plugin, and where does validation commonly fail?" without
any code in the hot path that could affect a hook decision.
Changes
scripts/lib/telemetry.sh (new, sourced helper)
scripts/validate-mounted-env-files (+95)
Events emitted
Both under vendor com.1password.app:
Privacy & consent
Testing
Automated (library behavior)
Sandboxed exercise of scripts/lib/telemetry.sh under a throwaway $HOME (no writes to your real ~/.config/1Password): consent gating, JSON validity (incl. escaped quotes), null serialization for empty mode/mount_count, bucket_duration_ms boundaries, install-once dedup +
version-bump, and the 1 MB cap. All pass.
Manual end-to-end in Cursor
▎ The beforeShellExecution hook only fires for agent-run shell commands — commands the Cursor agent executes, not ones you type into the terminal yourself.
Prerequisites
Events are only written when the signal file exists. Either flip the in-app setting (Settings → Manage Account → Data Usage → enable product telemetry), or create it directly for a producer-only test:
touch ~/.config/1Password/telemetry-enabled
Create a .cursor/hooks.json in the workspace you'll test in, pointing the command at the absolute path of this checkout's script (so you exercise your working tree, not the installed marketplace copy):
mkdir -p .cursor
cat > .cursor/hooks.json <<'EOF'
{
"version": 1,
"hooks": {
"beforeShellExecution": [
{ "command": "/ABSOLUTE/PATH/TO/cursor-plugin/scripts/validate-mounted-env-files" }
]
}
}
EOF
Replace /ABSOLUTE/PATH/TO/cursor-plugin with your clone path. (User-level ~/.cursor/hooks.json works too; project-level is easiest to scope to one workspace.) If the marketplace 1Password plugin is installed, disable it (Settings → Plugins) so it doesn't also fire.
Reload Cursor so it picks up the hook: Cmd+Shift+P → Developer: Reload Window.
Trigger the allow path — ask the agent to run a shell command, e.g. "run echo hi in the terminal". Then confirm:
tail -5 /tmp/1password-cursor-hooks.log
cat ~/.config/1Password/data/hook-events/events.jsonl
Expect an agent_hook_execution line with "decision":"allow", the correct hook_version (from .cursor-plugin/plugin.json), client":"cursor", plus a one-time agent_hook_install line on the first run after install.
Trigger the deny path — point a mount at a missing file so validation denies. Easiest via TOML in the test workspace:
mkdir -p .1password
echo 'mount_paths = ["'"$PWD"'/.env.missing"]' > .1password/environments.toml
Re-trigger an agent command; expect a "decision":"deny" event with "deny_reason":"file_missing" and "mode":"configured". (Disable a mount in the app, or combine both, to see file_disabled / file_missing_and_disabled.)
Verify fail-open — confirm telemetry can't break the hook:
mv scripts/lib/telemetry.sh /tmp/telemetry.sh.bak # simulate missing lib
Re-trigger; the hook must still return its allow/deny decision normally (no telemetry written). Restore afterward:
mv /tmp/telemetry.sh.bak scripts/lib/telemetry.sh
Confirm ingestion (if running a desktop-app build with hook-event ingestion): after a trigger, events.jsonl is drained (deleted) within ~60s and the event appears in your telemetry backend (e.g. Snowplow). Without that build, step 4's cat confirms the producer side.
Cleanup: remove .cursor/hooks.json, .1password/environments.toml, and (if you created it for testing) ~/.config/1Password/telemetry-enabled.