Skip to content

chat: fail closed on forced managed settings refresh - #332388

Open
joshspicer wants to merge 8 commits into
mainfrom
agents/e2e-forceremotesettingsrefresh-fail-closed-2354d926
Open

chat: fail closed on forced managed settings refresh#332388
joshspicer wants to merge 8 commits into
mainfrom
agents/e2e-forceremotesettingsrefresh-fail-closed-2354d926

Conversation

@joshspicer

@joshspicer joshspicer commented Aug 24, 2026

Copy link
Copy Markdown
Member

Summary

Makes forceRemoteSettingsRefresh a true fail-closed freshness control in VS Code.

When the control is effective from native MDM, a cached server response, or the managed settings file, VS Code now keeps AI features unavailable until /copilot_internal/managed_settings returns a fresh successful response for the current account, authentication provider, and endpoint. Cached settings may preserve existing restrictions and self-perpetuate the flag, but they cannot satisfy freshness.

What changed

  • Adds one typed freshness state machine shared by fetch, gate, diagnostics, and tests: notRequired, pending, satisfied, and categorized blocked states.
  • Resolves the control through the existing native MDM > server > file precedence, awaiting initial native/file snapshots before the cache decision.
  • Scopes satisfaction to account + provider + endpoint and closes the gate again on sign-out.
  • Treats network, rate-limit, HTTP, malformed-response, missing-endpoint, missing-token, and update-required outcomes consistently as blocked when freshness is required.
  • Composes freshness into the existing Account Policy gate so editor Chat and the Agents window withhold agent functionality before session creation.
  • Keeps authentication and explicit retry recovery available, with failure-specific notification/Agents-window UX.
  • Extends Policy Diagnostics with freshness state, source, scope, attempt time, retry timing, and failure category.
  • Documents that default delivery remains fail-open while this opt-in control is fail-closed.\n- Adds mock-policy-server presets for HTTP 500, malformed JSON, immediate disconnect, and client timeout so every fail-closed category is easy to exercise end to end.

Runtime alignment

This is the VS Code host implementation. It does not duplicate runtime schema parsing or policy matching. It aligns the host gate with the runtime behavior landed in github/copilot-agent-runtime#16384 while preserving VS Code-owned account, workbench, and Agents-window lifecycle behavior.

Validation

  • npm run transpile-client
  • Focused Node unit tests: 100 passing across managed-settings normalization/freshness/file delivery, default-account fetch behavior, Account Policy enforcement, and recovery UX.
  • npm run valid-layers-check
  • git diff --check
  • npm run typecheck-client reports only the unrelated pre-existing AgentService constructor error at src/vs/platform/agentHost/test/node/agentService.test.ts:9986 (the changed files type-check cleanly).
  • Electron unit runner is unavailable in this environment because chrome-sandbox is not configured setuid-root; the equivalent focused Node runner was used.
  • Three-model review council inspected every hunk. It found no consensus blockers and no removable hunks that preserved the requested behavior. Two concrete single-reviewer UX lifecycle findings were fixed and re-reviewed on the current head.

Related to microsoft/vscode-internalbacklog#8825.

joshspicer and others added 3 commits August 24, 2026 16:33
Groundwork for making `forceRemoteSettingsRefresh` a real fail-closed
startup gate (microsoft/vscode-internalbacklog#8825). Contract only — no
behavior change, and nothing gates on freshness yet.

Adds `managedSettingsFreshness.ts`, declaring the state machine shared by
the fetch path, the policy gate and Policy Diagnostics so those consumers
cannot drift: `NotRequired` / `Pending` / `Satisfied` / `Blocked`, the
failure categories every inability-to-refresh maps to, and scoping by
account + provider + endpoint so satisfaction is never transferable
across accounts or GHE hosts.

Replaces `shouldForceRemoteSettingsRefresh` with
`resolveForceRemoteSettingsRefresh`, which resolves through
`pickManagedSettings` instead of re-implementing precedence. Two fixes
fall out: the file channel now participates (the old helper read only
native MDM and server, silently ignoring managed-file delivery), and an
explicit managed `false` is now distinguishable from an absent value,
which a later change needs in order to know when the requirement may be
cleared.

The old helper had no production caller — it was left orphaned when
661f18f reworked the managed-settings fetch — so this is inert.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address PR feedback: `IManagedSettingsFreshness` was a bag of optional
fields, so a consumer could construct `Blocked` with no failure,
`Satisfied` with no scope, or attach `httpStatus`/`retryAfter` to states
where they mean nothing — leaving the fetch, gate and diagnostics
consumers free to drift despite the type.

Models it as a discriminated union instead, so each active state requires
the fields its contract defines. `Blocked` is itself a union keyed on the
failure category, so a status code is required for an HTTP error, a
backoff deadline for rate limiting, and neither is accepted elsewhere.
`source` is now the shared `ManagedSettingsChannel` rather than `string`,
and is required on the effective states, which also encodes that it is
never `'none'` once a channel has supplied the control.

Adds `@ts-expect-error` coverage for the three rejected shapes: the
directives fail the build if any shape becomes constructible again.

`isSameManagedSettingsFreshnessScope` is now a private helper with
required arguments — the union guarantees a scope is present, so its
undefined-tolerance was unreachable, and nothing outside this module
used it.

Also trims two over-long comments flagged in review.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Require a fresh managed-settings response before enabling AI features when forceRemoteSettingsRefresh is effective. Preserve recovery through sign-in and retry, expose diagnostics, and cover native, server, file, failure, scope, and sign-out behavior.

Related to microsoft/vscode-internalbacklog#8825.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings August 24, 2026 18:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds fail-closed managed-settings freshness enforcement across account fetching, policy gates, diagnostics, and the Agents window.

Changes:

  • Introduces scoped freshness states and failure categories.
  • Integrates freshness enforcement and recovery UX.
  • Adds unit, fixture, and service initialization coverage.
Show a summary per file
File Description
.github/skills/policy-and-managed-settings/github-managed-settings.md Documents fail-closed behavior.
src/vs/editor/contrib/inlineCompletions/test/browser/utils.ts Updates account-service mock.
src/vs/editor/standalone/browser/standaloneServices.ts Adds default freshness state.
src/vs/platform/defaultAccount/common/defaultAccount.ts Exposes freshness API.
src/vs/platform/policy/common/copilotManagedSettings.ts Resolves control precedence.
src/vs/platform/policy/common/fileManagedSettingsIpc.ts Awaits initial file snapshots.
src/vs/platform/policy/common/fileManagedSettingsService.ts Adds initialization barrier.
src/vs/platform/policy/common/managedSettingsFreshness.ts Defines freshness state machine.
src/vs/platform/policy/test/common/copilotManagedSettings.test.ts Tests control precedence.
src/vs/platform/policy/test/common/fileManagedSettingsService.test.ts Tests initialization API.
src/vs/platform/policy/test/common/managedSettingsFreshness.test.ts Tests freshness invariants.
src/vs/sessions/contrib/policyBlocked/browser/policyBlocked.contribution.ts Routes freshness overlays.
src/vs/sessions/contrib/policyBlocked/browser/sessionsPolicyBlocked.ts Adds recovery UI.
src/vs/sessions/contrib/policyBlocked/test/browser/sessionsPolicyBlocked.fixture.ts Adds blocked-state fixture.
src/vs/sessions/test/web.test.ts Updates account-service mock.
src/vs/workbench/browser/actions/developerActions.ts Extends policy diagnostics.
src/vs/workbench/browser/web.main.ts Registers null file service.
src/vs/workbench/services/accounts/browser/defaultAccount.ts Implements freshness fetching and scope.
src/vs/workbench/services/accounts/test/browser/defaultAccount.test.ts Covers freshness outcomes.
src/vs/workbench/services/policies/browser/accountPolicyGateContribution.ts Adds notification recovery UX.
src/vs/workbench/services/policies/common/accountPolicyService.ts Composes freshness into policy gate.
src/vs/workbench/services/policies/test/browser/accountPolicyGateContribution.test.ts Tests notifications.
src/vs/workbench/services/policies/test/browser/accountPolicyService.test.ts Tests gate enforcement.
src/vs/workbench/services/policies/test/browser/multiplexPolicyService.test.ts Updates provider mock.
src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts Updates fixture services.

Review details

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 25/25 changed files
  • Comments generated: 6
  • Review effort level: Balanced

Comment thread src/vs/workbench/services/accounts/browser/defaultAccount.ts
Comment thread src/vs/workbench/services/accounts/browser/defaultAccount.ts Outdated
Comment thread src/vs/workbench/services/policies/browser/accountPolicyGateContribution.ts Outdated
Comment thread src/vs/sessions/contrib/policyBlocked/browser/sessionsPolicyBlocked.ts Outdated
Re-render the Agents window when freshness failure details change and preserve startup notification deferral.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Screenshot Changes

Base: b34a8ac0 Current: 3ebd67ba

Added (2)

sessions/sessionsPolicyBlocked/ManagedSettingsUnavailable/Dark

current

sessions/sessionsPolicyBlocked/ManagedSettingsUnavailable/Light

current

joshspicer and others added 2 commits August 24, 2026 18:45
Scope cached server controls before precedence, avoid expired rate-limit poll loops, and align update-required recovery guidance across workbench and Agents window UI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Classic web initialization intentionally skips the default-account fetch. Exercise the explicit refresh path before asserting the no-token fail-closed state so the browser suite observes the same lifecycle it is validating.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ensure managed-settings messages render Code - OSS instead of an undefined product label in component screenshots.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@joshspicer
joshspicer marked this pull request as ready for review August 24, 2026 21:50
Let the mock policy server return HTTP errors, malformed JSON, immediate disconnects, or no response until client timeout through presets, the GUI, and the control API.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

5 participants