Add toolbar pinning for uploaded Chromium extensions#281
Open
rgarcia wants to merge 2 commits into
Open
Conversation
Accept an optional per-extension `pinned` flag on the extension upload and configure endpoints and translate it into ExtensionSettings.toolbar_pin in the managed enterprise policy. For force-installed extensions the pin is set on the real Chrome extension ID. For --load-extension extensions, which Chrome assigns an ID derived from the install path, compute that ID (SHA-256 of the resolved path mapped into the a-p alphabet) and key toolbar_pin by it, since a name-keyed entry is ignored by Chrome. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Unpin leaves stale policy entry
- For --load-extension updates we now clear any existing computed-ID toolbar_pin when pinned=false so stale force_pinned policy does not persist.
Or push these changes by commenting:
@cursor push 9b59b1530d
Preview (9b59b1530d)
diff --git a/server/lib/policy/policy.go b/server/lib/policy/policy.go
--- a/server/lib/policy/policy.go
+++ b/server/lib/policy/policy.go
@@ -242,12 +242,16 @@
// Extensions on this path are loaded via --load-extension, where Chrome
// assigns an ID derived from the install path rather than extensionName.
- // toolbar_pin is keyed by that real ID, so pin under the computed ID.
+ // toolbar_pin is keyed by that real ID.
+ pinnedID := UnpackedExtensionID(extensionPath)
if pinned {
- pinnedID := UnpackedExtensionID(extensionPath)
pinnedSetting := current.ExtensionSettings[pinnedID]
pinnedSetting.ToolbarPin = forcePinned
current.ExtensionSettings[pinnedID] = pinnedSetting
+ } else if pinnedSetting, exists := current.ExtensionSettings[pinnedID]; exists {
+ // Explicitly clear stale force_pinned when callers unpin.
+ pinnedSetting.ToolbarPin = ""
+ current.ExtensionSettings[pinnedID] = pinnedSetting
}
}You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit 49a7abe. Configure here.
…sing Address review feedback: - AddExtension reconciles the --load-extension toolbar_pin entry with the pinned flag (deletes the computed-ID entry when not pinned) so re-adding an extension unpinned cannot leave a stale force_pinned behind. - Both multipart parsers group extension fields lazily (a repeated field type starts a new group) instead of finalizing eagerly and back-patching the last finalized item, so the optional extensions.pinned field stays attached to its own extension regardless of position in the group. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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
pinnedfield to/chromium/upload-extensions-and-restartand/configure. When set, the extension is force-pinned to the toolbar via the managedExtensionSettings.toolbar_pinpolicy.toolbar_pin: force_pinnedon their real Chrome extension ID.--load-extensionextensions are assigned an ID by Chrome derived from the install path, so a newUnpackedExtensionIDhelper computes that ID (SHA-256 of the resolved path mapped into the a-p alphabet) and keystoolbar_pinby it. A name-keyedExtensionSettingsentry is ignored by Chrome, so this is required for pinning to actually take effect.ExtensionSettingsstays kernel-managed and blocked from raw user policy override; pinning is exposed as a typed flag and merged into the existing managed entries rather than unblocking the whole policy.This is the browser-VM half. Wiring the public API/SDK/dashboard to send
pinnedper extension is a separate follow-up.Testing
ExtensionSettingtoolbar_pin JSON marshaling, both multipart parsers, andparseExtensionPinned.go build ./...,go vet, andgo test ./lib/...pass locally.e2e_extension_pin_test.go): uploads an extension withpinned=trueand asserts thetoolbar_pinpolicy key equals the ID Chrome reports onchrome://extensions. This settles the two open questions — pin keyed by the real ID, and our computed ID matches Chrome's. Not run locally (requires Docker + prebuilt images); runs in CI.Test plan
TestPinnedExtensionInstallationpasses on headless + headfulNote
Medium Risk
Changes extension upload parsing and managed
policy.json(ExtensionSettings, install paths); incorrect ID or pin logic could mis-apply toolbar policy, but behavior is covered by unit and e2e tests.Overview
Adds optional
extensions.pinnedon extension upload (upload-extensions-and-restart) and/configure, so each extension can be force-pinned to the toolbar via managedExtensionSettings.toolbar_pin(force_pinned).Multipart parsing now groups
zip_file,name, and optionalpinnedper extension (field order within a group is flexible; repeating a field starts a new group).policy.AddExtensiontakespinned: force-installed extensions gettoolbar_pinon the real Chrome ID;--load-extensionpaths use a newUnpackedExtensionIDhelper (path-derived ID) so pinning keys match what Chrome applies. Re-uploading unpinned clears stale pin entries for load-extension installs.OpenAPI/generated types document
pinned. Unit tests cover parsers, ID helper, and policy JSON; a new e2e test uploads withpinned=trueand checkspolicy.jsonandchrome://extensionsIDs align.Reviewed by Cursor Bugbot for commit dad7682. Bugbot is set up for automated code reviews on this repo. Configure here.