Skip to content

feat(devicepolicy): enforce VS Code private marketplace URL#178

Open
raysubham wants to merge 3 commits into
step-security:mainfrom
raysubham:feat/vsc-private-markeplace-support
Open

feat(devicepolicy): enforce VS Code private marketplace URL#178
raysubham wants to merge 3 commits into
step-security:mainfrom
raysubham:feat/vsc-private-markeplace-support

Conversation

@raysubham

Copy link
Copy Markdown
Contributor

Summary

Folds an optional VS Code private-marketplace URL (extensions.gallery.serviceUrl) into the existing ide_extension#vscode reconciler, delivered through the same agent enforcement lane as the extension allowlist. The agent writes both keys into the user-scope settings.json in one atomic merge and tracks ownership of each independently.

Additive and regression-guarded: an allowlist-only policy compiles, writes, and records ownership exactly as before (byte-identical settings.json and cache record). No agent-version gating — marketplace-URL tenants run current agents, so the resolver always sends the URL and one hash covers it.

What changed (internal/devicepolicy/)

  • api: lift gallery_service_url from run-config into EffectivePolicy (no request change).
  • settings_writer: new managedSettingsWriter seam — ReadManaged / ApplyManaged / RestoreManaged over a set of keyed ops (one atomic load→patch→store). Single-key Write/Read/Clear retained for any single-key writer.
  • reconcile: ownership-gated set / remove / preserve for the gallery key; convergence over both keys before the idempotency short-circuit; drift over owned keys; per-key ownership-safe clear; atomic multi-key rollback on a post-write persist failure.
  • cache: additive WrittenSettings map[string]string (omitempty → an allowlist-only record is unchanged on disk).
  • probe: mdm_managed when an MDM owns AllowedExtensions or ExtensionGalleryServiceUrl (Windows / macOS / Linux).

Semantics

  • URL present → set authoritatively (overwrite whatever is there).
  • URL absent → remove only if the on-disk value is the one the agent wrote; a user-configured URL is preserved.
  • clear:true → remove each owned key independently; a tampered / foreign key is left in place.
  • VS Code adopts a changed gallery at next restart; the agent converges settings.json immediately (file state is the contract, as today).

Testing

  • go test ./internal/devicepolicy/ -race — writer goldens (allowlist-only bytes identical to the pre-feature Write, both-key, remove-tolerates-absence, preserve, presence flags, restore round-trip, refuse-unsalvageable, special-char round-trip), reconcile transitions (first / idempotent / gallery-only drift / allowlist drift / URL added / replaced / removed-when-owned / foreign-preserved / clear-owned-only / multi-key rollback / rollback-failure / readback-mismatch), cache round-trip + omitempty, probe either-key (darwin native; linux + windows fixtures).
  • Gates: gofmt -l clean · go vet (darwin/linux/windows) · cross-compile CGO_ENABLED=0 linux/amd64 + darwin/arm64 + windows/amd64 · go mod tidy no-diff · golangci-lint 0 issues · make smoke 44/44.

No version bump or CHANGELOG entry (handled at release cut).

Fold an optional extensions.gallery.serviceUrl into the existing
ide_extension#vscode reconciler, written into the user-scope
settings.json beside extensions.allowed via one atomic multi-key write.
The agent owns both keys: set is authoritative, removal is
ownership-gated (never deletes a user-configured value), and drift,
convergence, selective clear, and post-write rollback all cover both.

- api: lift gallery_service_url from run-config into EffectivePolicy
- settings_writer: managedSettingsWriter (ReadManaged / ApplyManaged /
  RestoreManaged) over a set of keyed ops; single-key Write/Read/Clear kept
- reconcile: ownership-gated set/remove/preserve for the gallery key;
  convergence over both keys before the idempotency short-circuit; drift
  over owned keys; atomic multi-key rollback; per-key ownership-safe clear
- cache: additive WrittenSettings map (omitempty; an allowlist-only
  record is unchanged on disk)
- probe: yield mdm_managed when an MDM owns AllowedExtensions OR
  ExtensionGalleryServiceUrl (Windows / macOS / Linux)

Additive and regression-guarded: an allowlist-only policy writes exactly
as before (byte-identical settings.json and ownership record).
…tings

Move the VS Code allowlist's ownership record from the scalar WrittenValue
into the WrittenSettings map alongside the gallery URL, so every managed key
is tracked uniformly by setting id. WrittenValue is now used only by the
single-key (npm) writer; adds omitempty so managed records no longer carry a
dead written_value field. No behavior change: ownership is read back from the
same values the agent writes.
… map)

The run-config policy payload is now a settings map (setting id → compiled value) instead of the bare extensions.allowed object plus a sibling gallery_service_url field; the hash covers the whole map.

enforce and clear are fully driven by the settings map and recorded ownership — no per-key special-casing — so a new managed setting rides through with no code change. Fetch now requires extensions.allowed to be present and a JSON object. Deleted managedKeys/managedGalleryValue; added compactSettings/sortedUnion/sortedKeys.

Breaking run-config wire change (pre-GA): requires agent-api to emit the settings-map shape.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant