Skip to content

Enable Microsoft Entra ID sign-in for Private Marketplace access - #4

Closed
mcumming wants to merge 5596 commits into
mainfrom
mcumming-entra-id-vss-marketplace-review
Closed

Enable Microsoft Entra ID sign-in for Private Marketplace access#4
mcumming wants to merge 5596 commits into
mainfrom
mcumming-entra-id-vss-marketplace-review

Conversation

@mcumming

Copy link
Copy Markdown
Owner

Refactor commits addressing reviewer feedback on the Entra ID Private Marketplace work:

  • Break the account -> auth DI cycle via orchestrator wiring (connectAuthentication init API + AfterRestored contribution).
  • Rename the misnamed ExtensionGalleryServiceIndexService helper to ExtensionGalleryServiceIndexFetcher (owner-scoped createInstance helper, not a DI-registered service), per reviewer request to either register or rename.
  • Move the Microsoft (Entra) marketplace eligibility check client-side, matching the GitHub path.

Lee Murray and others added 30 commits August 6, 2026 15:19
…rosoft#329424)

style: add border to modified side-by-side diff editor

Co-authored-by: mrleemurray <mrleemurray@users.noreply.github.com>
`FindInput` and `ReplaceInput` each carried their own copy of the
arrow-key/escape handling used to move focus between the toggles of a
find input. The two blocks were identical apart from how the toggle
elements are collected.

Extract the block into `navigateToggles` in findInputToggles.ts and call
it from both widgets. The toggles are passed as a callback so that they
keep being resolved only once one of the handled keys is pressed, as
`FindInput` did before.

Fixes microsoft#199892

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Dmitriy Vasyura <dmitriv@microsoft.com>
…allback (microsoft#329433)

* sessions: Refine Show/Hide Editor placement, icons, and Browser-tab fallback

Follow-up to microsoft#329384 (merged), addressing feedback on that PR's
Show/Hide Editor Area actions:

- Moves Hide Editor / Show Editor from the full-width editor header's
  trailing layout group to the tab strip's editor-title layout cluster
  (`MenuId.EditorTitleLayout`), immediately after Maximize/Restore
  Editor Area (order 20 vs. 10). Toggle Details remains alone in the
  header's trailing group.
- Both actions now always render regardless of whether the active tab
  has a docked detail panel (drops the `HasDockedDetailsContext` gate),
  matching Maximize/Restore's own always-shown behavior in that
  cluster.
- Switches their icons to the existing `right-panel-hide` /
  `right-panel-show` codicons (previously `chevron-right` /
  `chevron-left`, which are already heavily reused elsewhere in this
  window for tree/list disclosure twisties).
- Hide Editor is always enabled (drops its `AuxiliaryBarVisibleContext`
  precondition) and unconditionally reveals the auxiliary bar in
  `run()`.
- Fixes a resulting regression: clicking Hide Editor while a Browser
  tab was active would immediately re-hide the just-revealed detail
  panel, since `SinglePaneDetailPanelStrategy`'s "Browser hides the
  detail" rule fired again right away. The strategy now only
  transiently hides the detail for a Browser tab while the editor area
  itself stays visible; once the editor area is hidden (e.g. via Hide
  Editor), the panel shows the same Changes/Files fallback a session
  with no active editor gets, since it would otherwise be the only
  thing left on screen. Revealing the editor area again (Show Editor)
  restores the normal transient-hide behavior.

Updates SINGLE_PANE_SCENARIOS.md and LAYOUT.md to document the new
placement, icons, always-enabled state, and Browser-tab fallback, and
adds/updates targeted tests covering the menu placement, the action's
unconditional reveal, and the strategy's Browser-tab fallback end to
end.

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

* sessions: Address PR review feedback on comments, tests, and docs

- Condenses several overly-verbose inline/JSDoc comments in
  editor.contribution.ts, singlePaneDetailPanelStrategy.ts, and both
  test files down to their non-obvious intent, since the detailed
  scenario catalog already lives in SINGLE_PANE_SCENARIOS.md.
- Adds icon assertions (Maximize/Restore/Hide/Show) to the
  layoutActions.test.ts menu-placement test, so it actually fails if
  Hide/Show Editor regress back to their old chevron icons — verified
  locally that the assertion catches the regression.
- Fixes a documentation contradiction in SINGLE_PANE_SCENARIOS.md's
  transition matrix: a Browser tab cannot remain in "Editor + Detail"
  while the editor area is visible (it always hides the detail), so
  Show Editor's result when Browser was last active is "Editor only",
  not "Editor + Detail". Scopes the earlier "any" row to the states
  where activating Browser is actually possible.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fix: update SVG paths in preview-dark and preview-light files for consistency

Co-authored-by: mrleemurray <mrleemurray@users.noreply.github.com>
…#322786)

* Add missing Azure SDK for Go modules to GoModulesToLookFor

Add 9 new client library modules from the Azure SDK releases page:
- sdk/batch/azbatch
- sdk/messaging/eventgrid/azeventgrid
- sdk/messaging/eventgrid/aznamespaces
- sdk/messaging/eventgrid/azsystemevents
- sdk/messaging/azwebpubsub
- sdk/monitor/ingestion/azlogs
- sdk/monitor/query/azlogs
- sdk/monitor/query/azmetrics
- sdk/azidentity/cache

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

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Fix formatting in workspaceTagsService.ts

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…te-loop-mcp-server-registration

Fix non-antisymmetric comparator in McpWorkbenchService.sort()
* chat: restore attached context completion ranking

- The inline attachment reference feature remained wired, but commit
  e746b00 (microsoft#328944) began assigning Agent Host completions an exact
  current-token filter score. Suggest ranking evaluates that fuzzy score
  before sortText, so host results displaced attached context despite its
  explicit priority.
- Pre-filter attached context with the same fuzzy matching behavior, then
  use the current token as filterText so matching attachments tie the Agent
  Host score and their priority sortText takes effect again.
- Mark attached context results incomplete so # and @ candidates refresh as
  the user continues typing, and cover bare, name, attachment-prefix, and
  unmatched queries.

Validation:
- 48 chat input completion tests pass.
- Changed files pass ESLint and git diff --check.

(Commit message generated by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e30098cd-04fb-4f03-bd73-bfc659d31831

* Apply remaining changes

Co-authored-by: justschen <54879025+justschen@users.noreply.github.com>

* chat: restore slash command relevance

- Preserve the actual filter text for slash commands, skills, chats, and
  other non-file Agent Host completions so Monaco can rank fuzzy matches
  such as /vscode-pet for /pet.
- Keep the common current-token filter score for file and folder results,
  where it is needed to retain deterministic multi-root host ordering.
- Add regression coverage for both the slash-command heuristic and the
  existing file-order behavior.

(Commit message generated by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e30098cd-04fb-4f03-bd73-bfc659d31831

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Copilot-Session: e30098cd-04fb-4f03-bd73-bfc659d31831
* nes: fix: compose complete workspace recording oracles

Compose raw workspace changes before applying the configurable disjoint-edit limit. Include accepted completion chains and omit targets that are later continued across recording, generated, idle, or cursor boundaries.

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

Copilot-Session: f23381fa-6246-44d2-a0a3-167c28272a57

* nes: fix: group nearby workspace recording edits

Treat cursor moves as soft oracle boundaries when user-intent edits continue nearby in the same document. Preserve distant and idle cursor boundaries so coherent multi-edit episodes remain grouped without crossing into unrelated work.

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

Copilot-Session: f23381fa-6246-44d2-a0a3-167c28272a57

* nes: fix: omit empty workspace oracles

Drop workspace-recording candidates whose collected operations compose to no net edit, such as typing and then deleting the same character.

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

Copilot-Session: f23381fa-6246-44d2-a0a3-167c28272a57

* nes: fix: share composed oracle policy across formats

Apply compose-before-limit oracle collection to alternative-action and continuous inputs, including idle and cursor locality boundaries, no-op filtering, restore handling, and parallel CLI propagation. Preserve workspace-specific source classification and end-of-recording rules.

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

Copilot-Session: f23381fa-6246-44d2-a0a3-167c28272a57

---------

Co-authored-by: Dmitriy Vasyura <dmitriv@microsoft.com>
Copilot-Session: f23381fa-6246-44d2-a0a3-167c28272a57
Agent Host session hydration installed a persistent state-change listener that refreshed the current active client whenever its in-memory payload differed from protocol state. Because wire serialization drops undefined properties, the echoed session/activeClientSet remained structurally unequal and immediately triggered another refresh. This produced a self-sustaining request/echo loop at roughly 1,800 messages and 33 MiB per second, saturating the Agents window renderer, driving repeated major garbage collections, and generating hundreds of megabytes of AHP traffic in seconds.\n\nMake the hydration reconciliation one-shot: wait until this client appears, dispose the listener before dispatching any refresh, and leave subsequent legitimate tool and customization updates to their existing observables. Add regression coverage that simulates the wire-normalized echo and verifies it cannot dispatch a second refresh.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chat: reduce agent session change retention

Persist aggregate change summaries in the renderer cache and avoid eagerly attaching cached file arrays when lazy loading is enabled. Add focused cache migration and provider resolution coverage. (Written by Copilot)

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

* chat: preserve change summaries on lazy refresh

Keep aggregate counts when a provider omits lazy changes, while demoting previously hydrated arrays to summaries. Add focused reconciliation coverage. (Written by Copilot)

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

---------

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

* Fix dictation cleanup timeout handling

Co-authored-by: meganrogge <29464607+meganrogge@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: meganrogge <29464607+meganrogge@users.noreply.github.com>
* Support Auto tiers

* Make auto tiers an exp driven thing

* Resolve comments
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Initial plan

* Fix voice playback when reopening chat sessions

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

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Read Copilot-specific components from the sanctioned com.github.copilot manifest namespace and extension directory while preserving portable Agent Plugin defaults and package containment.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Dmitriy Vasyura <dmitriv@microsoft.com>
sessions: keep managed tabs in aux-only view

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Classify effective policy telemetry sources

Preserve policyCount as the legacy effective total while adding administrator, account, and account-gate family counts. Track the winning source through account and multiplex policy services, including source-only transitions.

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

Copilot-Session: 2773b969-fe4a-4671-a0a1-1fc69b1968f3

* Remove aggregate policy count telemetry

Make administrator, account, and account-gate counts the canonical policy.applied schema. Values without explicit provenance are excluded instead of being attributed to administrators.

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

Copilot-Session: 2773b969-fe4a-4671-a0a1-1fc69b1968f3

* Split policy telemetry by delivery source

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

Copilot-Session: 2773b969-fe4a-4671-a0a1-1fc69b1968f3

* Refactor policy source state

Centralize policy value and source transitions in AbstractPolicyService and isolate account-specific source resolution.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1ced0d45-0ef0-4c69-843f-9951452d9b92

---------

Co-authored-by: Josh Spicer <23246594+joshspicer@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2773b969-fe4a-4671-a0a1-1fc69b1968f3
Copilot-Session: 1ced0d45-0ef0-4c69-843f-9951452d9b92
Michael Cummings and others added 27 commits August 10, 2026 12:12
Resolve the marketplace access strategy in the workbench gallery manifest
service: cache-first startup, provider-routed access handling, Microsoft
eligibility probing against the eligibility resource from the gallery
manifest, the GitHub DefaultAccount path, the marketplace auth-provider
context key, and access telemetry.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Surface a provider-aware sign-in prompt and access-denied state in the
extensions viewlet, driven by the marketplace auth-provider context key so
the correct identity provider is presented to the user.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Allow the built-in extensions gallery to silently use Microsoft (Entra ID)
authentication sessions for Private Marketplace access.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Cover provider selection, cache-first startup, Microsoft eligibility
handling, and the GitHub access path in the gallery manifest service.

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

Address rubber-duck review findings on the Entra ID marketplace path:

- Scope the cached access verdict to the marketplace it was computed against
  (authProvider + accountId + serviceUrl), rejecting stale caches on any mismatch.
- Guard cache application and background validation with a monotonic epoch so a
  session/account/config change mid-validation supersedes an in-flight result.
- Register session/account listeners before applying the cache, and the config
  listener before initial validation, closing startup TOCTOU windows.
- Route transient auth-service and marketplace-fetch failures to Unreachable
  instead of leaving a configured marketplace on a blank Unavailable view.
- Split 401 (missing/expired token -> RequiresSignIn, not cached) from 403
  (durable denial -> AccessDenied, cached ineligible).
- Never follow redirects on token-bearing requests; only send the Entra token to
  an HTTPS same-origin target; reject non-2xx and non-manifest 200 responses
  before parsing.
- Restore the galleryservice:custom:marketplace telemetry on the GitHub path and
  drop the unused server-provided eligibility reason from persisted cache.

Expand unit coverage to 45 tests across provider routing, eligibility, caching,
error classification, and the epoch race paths.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…g, resource validation, UX copy

- Policy: make the `extensions.gallery.authProvider` schema enum and enumDescriptions
  unconditional (`github`, `microsoft`). Gating the enum on the Entra product flag left the
  policy metadata exporting two enum descriptions against a single-value enum, which fails the
  policy-artifact generator's equal-length requirement on a clean export. The Entra gate is
  already enforced at runtime in getEffectiveAuthProvider(), and the setting is hidden
  (included: false), so this advertises nothing new in the UI.

- Cross-account authorization leak: on Microsoft session change and GitHub default-account
  change, revoke the active manifest (drop `Available`) before revalidating. Previously the
  active status stayed `Available`, so a transient index/eligibility failure on the new account
  preserved the prior account's access.

- Layering: move CONTEXT_MARKETPLACE_AUTH_PROVIDER down to the platform extensionGalleryManifest
  module so the workbench service no longer imports from a workbench/contrib module. The
  Extensions contribution re-exports it for existing consumers.

- Resource validation: reject a 200 service index whose `resources` entries are malformed
  (missing string `id`/`type`), not just a non-array `resources`. Endpoint discovery calls
  `resource.type.split()` outside the fetch try/catch, so an undefined `type` would crash
  initialization instead of surfacing `Unreachable`.

- UX: make the Microsoft AccessDenied welcome message generic. A bare 403 gives no typed reason,
  so asserting that an Entra ID account or Visual Studio Subscription is required could tell an
  already-signed-in user to obtain access they already have.

Adds a unit test covering the malformed-resources -> Unreachable path. All 47 gallery tests pass;
typecheck-client and valid-layers-check are clean.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replace the two `as any` casts flagged by the local/code-no-any-casts
ESLint rule that failed hygiene: complete the stubbed
IProductService.extensionsGallery so it satisfies Partial<IProductService>
without a cast, and cast the entitlements literal to IEntitlementsData.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Extract all eligibility/access-validation logic out of
WorkbenchExtensionGalleryManifestService into a dedicated, provider-agnostic
ExtensionGalleryAccessValidator, and split the GitHub-vs-Microsoft branching
into IExtensionGalleryAccessProvider strategy classes. This debloats the host
service (it now only builds a status sink and delegates) and isolates each
identity system's account resolution + eligibility check.

Replace the hand-rolled monotonic validationEpoch TOCTOU counter with a
CancellationTokenSource held in a MutableDisposable: assigning a new source
cancels/disposes the prior one, and each validation re-checks
token.isCancellationRequested immediately before mutating status/cache/manifest,
so a superseded in-flight validation cannot commit a stale verdict for an
account that is no longer current. Addresses reviewer feedback that the epoch
machinery bloated the service.

New files:
- extensionGalleryAccess.ts: shared leaf contracts (IExtensionGalleryAccessCore,
  IExtensionGalleryAccessProvider, IExtensionGalleryAccessSink, ICachedAccess,
  AccountResolution, ExtensionGalleryAccessProviderId, isSafeTokenTarget).
- extensionGalleryAccessProviders.ts: GitHub and Microsoft access providers.
- extensionGalleryAccessValidator.ts: provider-agnostic orchestrator.

Security invariants preserved: no microsoft->github fallback, cache scoped to
provider+serviceUrl, bearer only over HTTPS same-origin with followRedirects:0,
and the 401/403/transient status mappings are unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
…d-in Microsoft accounts

When a signed-in Microsoft account made an authenticated Marketplace request that
returned 401, the previous logic mapped it to RequiresSignIn, which re-prompted the
same account whose token had just been rejected - producing an infinite sign-in loop.
Map both Microsoft 401 branches (service-index and eligibility) to AccessDenied so the
condition is surfaced to the user, and do not cache the 401 verdict (unlike a durable
403 denial) so a later config/account/session change re-evaluates cleanly. Lower the
MarketplaceAuthRequiredError log level to trace. First-time no-session flows are
unchanged (still RequiresSignIn).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
Keep the extensions.gallery.authProvider setting while moving its policy declaration and generated catalog entry to a separate maintainer-authored change.\n\nCo-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>\nCopilot-Session: 449a6246-235a-4c42-8d6d-ef65fd83a190
Replace ExtensionGalleryAccessValidator and the provider/sink strategy
classes with two plain services and restore the manifest service toward
its upstream-main shape (minimal diff):

- ExtensionGalleryAccountService: mirrors IDefaultAccountService
  (getAccount/getCachedAccess/clearCache/onDidChangeAccount); owns
  GitHub + Microsoft account resolution, the eligibility check, and the
  ICachedAccess read/write/validate.
- ExtensionGalleryServiceIndexService: memoized service-index fetch.
- extensionGalleryManifestService: delegates all account/eligibility/
  index/cache work to the two services; keeps the added validation
  orchestration with a MutableDisposable<CancellationTokenSource> for
  the TOCTOU supersession guard.
- extensionGalleryAccess: trimmed leaf (removed orphaned sink/core
  interfaces), keeps shared helpers and error types.

The onDidChangeAccount subscription is registered before the initial
awaited validation so a sign-out mid-flight is observed. All 46
existing manifest-service tests pass unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
…che path, restore logs, trim comments

Continue the Private Marketplace access refactor on the extracted services:

- Thread CancellationToken through the account service's cache mutations
  (denyFromAuthError and the eligible fast-path), guarding every write with
  token.isCancellationRequested so a superseded validation can never restore or
  persist a verdict for an account that is no longer current (TOCTOU guard).
- Materialize the service index inside the account service's cached-access path
  and add invalidateServiceIndexCache(), so the host maps a verdict to status
  without any further fetching and each validation generation re-fetches cleanly.
- Restore the [Marketplace] debug log messages (sign-in / access / SKU /
  enterprise) for parity with main's observability.
- Trim branch-added comments to why-only, leaving main's pre-existing comments
  untouched.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
…olved provider

Replace the DI-service parameters on getEffectiveAuthProvider with plain
primitives (configured provider string + Entra product flag) so the helper
never reaches into a service, and cache the resolved provider in a field on
the manifest service to avoid resolving it twice.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
…e entry

The microsoft and github/default access-denied welcome blocks carried
near-identical messages and together covered every provider state, so
replace them with a single entry gated on the AccessDenied status alone.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
galleryservice:custom:marketplace was gated on the github provider, so
successful Microsoft/Entra marketplace access went uncounted. It now fires
for any successfully accessed serviceUrl-configured marketplace, restoring
its original meaning (custom-marketplace access, independent of provider).

The github-vs-microsoft distinction is instead tracked by
marketplace:auth:checked, which is now emitted from cacheAccess so every
definitive eligibility verdict reports its authProvider + eligible for both
providers (previously only the Microsoft 200 path emitted it).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
Add a dedicated extensionGalleryAccess.test.ts exercising the pure getEffectiveAuthProvider and isSafeTokenTarget helpers directly, and telemetry-assertion cases in the manifest service suite verifying galleryservice:custom:marketplace fires for both GitHub and Microsoft on eligible access, and marketplace:auth:checked reports the correct authProvider+eligible at each definitive verdict.

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

Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
Import the context key directly from the platform extensionGalleryManifest
module in extensionsViewlet.ts (its only consumer) instead of re-exporting
it from contrib/extensions/common/extensions.ts, so there is a single import
source. Addresses PR review feedback.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
Assign onDidChangeAccount directly via Event.signal over the provider-specific
source instead of relaying through a private Emitter with Event.map. Removes the
now-unused Emitter import. Addresses PR review feedback.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
Set the default for the marketplace auth-provider setting to 'github' instead
of the empty string, so the default is a member of the declared enum. Both
readers treat any non-'microsoft' value as the GitHub path, so behavior is
unchanged. Addresses PR review feedback.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
Drop the empty 'microsoft': [] placeholder from trustedExtensionAuthAccess in
product.json. It granted no silent access (no-op) and was local scaffolding for
the Entra path. Addresses PR review feedback.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
Replace the lazy `galleryAccountService: | undefined` field and its
`createInstance` in the manifest service with a proper
`InstantiationType.Delayed` singleton behind a new
`IExtensionGalleryAccountService` decorator, injected into the ctor.

The Delayed proxy makes ctor-time injection and the `onDidChangeAccount`
subscription non-instantiating, so the account service (and its
transitively-cyclic `IAuthenticationService` dependency) only materializes
on first non-event access. A `galleryAccountServiceActive` flag guards the
config-change handler so an unrelated config change never force-instantiates
the resolver when no private marketplace was configured. The ctor microtask
is kept: it defers the eager bootstrap's first access past ctor return so
the re-entry resolves the cached instance instead of throwing
"RECURSIVELY instantiating".

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
The Microsoft auth provider returns one session per signed-in account, so
picking sessions[0] was arbitrary when several accounts are signed in.

Persist a provider-scoped account slot (marketplace.account = { authProvider,
id }) and add a single getMicrosoftSession() selector that both the live check
and cache validation use: prefer the remembered account, adopt-and-persist a
lone account, and refuse to guess (require sign-in) when several accounts are
signed in with no remembered choice or the remembered one is gone.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
Address PR review: the Microsoft sign-in action no longer blindly
creates a session. When multiple Microsoft accounts are signed in, a
quick pick lets the user choose one (with a "different account" escape
hatch); a single account is bound directly, and no accounts falls
through to interactive sign-in. The chosen account is persisted so
selection stays grounded across restarts.

The browser-layer sign-in action delegates to a command registered in
the electron-browser account service (mirroring the GitHub branch's
DEFAULT_ACCOUNT_SIGN_IN_COMMAND delegation), respecting the layer
boundary. Binding uses createSession({ account }) so an already
signed-in account is bound without a fresh login while still firing the
session-change event that drives marketplace re-validation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
Address PR review: the two methods read as similar. Add JSDoc on each
contrasting it with the other so the distinct responsibilities are clear
at the call site: getAccount is the heavier public eligibility verdict
(may hit the network), while resolveCurrentAccount is an identity-only
silent resolution used solely for cache validation. The overlapping
"current account" selection logic was already unified into the single
getMicrosoftSession() selector.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
Decide Private Marketplace eligibility locally from the account's ID-token
tenant (`tid`) claim instead of round-tripping to a server-side
EligibilityService endpoint, mirroring how the GitHub path already gates
locally. A work/school (Entra) tenant is eligible; a personal Microsoft
Account (MSA) is not. The check runs before any index fetch, so an ineligible
account never touches the (possibly auth-gated) index, and fails closed on an
undecodable/opaque token or a token with no `tid`.

Removes the EligibilityService resource type, its URL discovery, the
same-origin token-target guard for it, and the IRequestService dependency and
POST round-trip in ExtensionGalleryAccountService. Adds an optional `tid`
claim to IAuthorizationJWTClaims and rewrites the surrounding docs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
ExtensionGalleryAccountService injected IAuthenticationService, forming a
service DI cycle (account -> auth -> extensionService -> extensionGalleryService
-> manifest -> account) that the instantiation graph walker detects and aborts
startup on. `Delayed` does not help: the cycle graph is a static walk over the
@iService constructor decorators.

Remove the @IAuthenticationService constructor dependency and supply it
post-startup through a new connectAuthentication() init API, wired by a small
ExtensionGalleryAccountAuthenticationContribution at WorkbenchPhase.AfterRestored
(orchestrator wiring, per reviewer guidance - not a service-locator lookup).
Until connected the Microsoft path reports "no account"; connecting re-signals
onDidChangeAccount once so any verdict resolved in that window is re-validated.

Update the manifest service test to play the orchestrator role by calling
connectAuthentication after constructing the account service.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
The class carried a "Service" suffix but is a plain createInstance helper
owned by ExtensionGalleryAccountService (an owner-scoped memo cache), not a
DI-registered service. Rename the class to ExtensionGalleryServiceIndexFetcher
and the field indexService -> serviceIndexFetcher so the name no longer implies
a service registration it does not have, per reviewer feedback (either register
it properly or rename it).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fe244b45-6362-4563-880d-fa3d9a27a07c
@mcumming

ghost commented Aug 13, 2026

Copy link
Copy Markdown
Owner Author

Closing: opened by mistake. The tracked PR for this branch is microsoft#325331.

@mcumming mcumming closed this Aug 13, 2026
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.