POC: Local Quick Start — one-click local DocumentDB provisioning & management#756
Draft
guanzhousongmicrosoft wants to merge 38 commits into
Draft
POC: Local Quick Start — one-click local DocumentDB provisioning & management#756guanzhousongmicrosoft wants to merge 38 commits into
guanzhousongmicrosoft wants to merge 38 commits into
Conversation
Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com>
- Add local-quickstart-v2.md: simplified design that removes the dedicated local connection subtree, uses a webview for container creation, gates TLS exceptions in the regular connection wizard, and migrates legacy emulator connections on first launch. - Mark local-quickstart.md as iteration 1 with a forward reference.
…decision note - terminal-first create progress for v1.0 (staged in-webview card deferred to v1.1) - adopt @microsoft/vscode-container-client (Docker+Podman) as the runtime layer - port fallback only for the default port; read the bound port from docker inspect - distinguish create-vs-start failure; pre-check connection name AND container name - scope prereq checks v1.0/v1.1; add section 18.1 PostgreSQL source-benchmark learnings - add docs/ai-and-plans/PRs/653-local-quickstart-design/description.md decision note Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…-agent review Adds a demo-focused proof-of-concept plan for Local Quick Start under docs/ai-and-plans/PRs/local-quickstart-poc/: - description.md: POC goal, scope (focus vs leave-out), deliberate deviations, reuse strategy, real-world image findings - poc-implementation-plan.md: process contract, architecture map, 14 decisions, 9 work items (Core WI-0..6 + Stretch WI-7..8), risks, demo script - review-and-resolutions.md: two rounds of 5-agent review (design/manager/impl/scope/risk) with every finding and resolution; consensus reached at rev. 3 No shipping code; planning only. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add @microsoft/vscode-container-client dependency (validates OPEN-3: post-image args supported via runContainer command[]) - ContainerRuntime: isDockerReady/isPortFree/pullImage/createAndRunContainer/inspect/start/stop/remove/listByLabel/followLogs - Masked, line-buffered OutputChannel writes so the generated password never leaks (D14), incl. split-chunk safety - quickStartTypes: image/port/label constants, InstanceState, StageEvent, InstanceMetadata - Unit tests for masking (8 passing) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Standalone service (documented deviation from D13 Task-composition: Task is single-use + numeric-notification progress, ill-fitting the in-webview stage checklist + Retry; D13 permits standalone) - provision() async generator yields StageEvents (checking/pulling/creating/starting/waiting/done); per-attempt AbortSignal; cleanup in finally (pull-cancel removes nothing; create/start-cancel removes by id, D12) - wire-protocol readiness probe via connectToClient (TLS-allow-invalid), 180s + backoff (D7) - credentials: URL-safe alphabet, percent-encoded conn string (D6); stored in SecretStorage - activation reconcile(): adopt labelled container if creds stored, else clean-remove - unit tests for credentials/conn-string (16 passing total) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- localQuickStartController (extends WebviewControllerBase; closePanel via this.panel.dispose, not this.dispose) - localQuickStartRouter: getDockerStatus/getStatus queries, startQuickStart subscription (mirrors ctx.signal to cancel provisioning + docker), closePanel mutation; imports tRPC primitives from ./trpc - mounted localQuickStart in appRouter; registered LocalQuickStart in WebviewRegistry (auto-bundled) - openLocalQuickStart command + registration; attach QuickStartService (reconcile + dispose) at activation - minimal React entry calling getDockerStatus (full UI in WI-3/WI-4) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Review: 4 metric cards (Docker/Port/Data=Ephemeral(POC)/Security) + What-we-do summary + Start - Docker-not-ready variant with Retry (opt-in; never auto-starts Docker) - Progress: lightweight staged checklist (D3) driven by startQuickStart subscription + elapsed timer + spinner; Cancel unsubscribes - Failure: inline error + Retry; View Docker output reveals the channel - Success: brief card then auto-close via closePanel (panel.dispose) -> tree handoff - added showOutput mutation; moved DockerStatusResult to pure types module (no router runtime in webview bundle) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…-5, WI-6) - LocalQuickStartItem root node: rocket empty-state row (opens webview) when NotInstalled; inline DocumentDBClusterItem when Running/Stopped (expand to browse); Provisioning/Error rows - QuickStartClusterItem subclass stamps a static 'Running . localhost:port' description (D2 design review) - QuickStartService pre-populates CredentialCache (setAuthCredentials) on success + reconcile so the inline item browses without a re-prompt - ConnectionsBranchDataProvider: render the node UNCONDITIONALLY incl. the zero-connections empty state (mandated option A); prepend in normal path; fix savedConnections telemetry count - refresh the tree on QuickStartService status change Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- ClustersExtension: refresh Connections tree on QuickStartService status change (WI-6 wiring) - prettier formatting; eslint-disable for initial-load setState-in-effect (matches DocumentView) - record standalone-service deviation from D13 + -dt/customOptions note in the plan Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Functional/security/tree/webview/design review fixes: - D14: followLogs now line-buffered via MaskingLineBuffer (split-secret safety) - stop followLogs on success: cts.cancel() in finally (was leaking docker logs -f) - orphan sweep if cancelled during create window (createAttempted + label sweep) - clear stale ClustersClient on fresh provision so re-run browses with new creds - webview: emit terminal error when busy + onComplete handler (no stuck 'provisioning'); unsubscribe-before-resubscribe + null-on-terminal (no double-click leak); review-screen Cancel button - readiness probe: direct MongoClient w/ 3s serverSelectionTimeout (Cancel responsive); remove redundant -t (detached already adds --tty) - optional sample-doc seed so the tree isn't empty to browse - Learn more... row; savedConnections telemetry counts real connections/folders Gates: lint, jest 2055, build, webview bundle all pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…utions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… Windows
Root cause: ShellStreamCommandRunnerFactory without a shellProvider drops each arg's quoting metadata and sets windowsVerbatimArguments on Windows, splitting Go-template args like '--format {{json .}}' on the space. This made 'docker info' (and inspect/list) fail, so isDockerReady reported the daemon unreachable even when Docker was running.
Fix: provide a platform shell provider (Cmd on Windows, Bash elsewhere) to every runner; switch makeRunner to strict:false (non-zero exit still rejects; harmless stderr warnings don't). Add @microsoft/vscode-processutils dependency.
Verified live on Windows: info, run (with credential args + labels), inspect (bound port), listByLabel, remove all succeed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s shell-provider) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adopt the image's native sample-data mechanism (documentdb-local --init-data true / INIT_DATA=true) instead of a bespoke driver-side seed — matches design 8.4 (use the image's standard init-script convention; portable, identical to running the image by hand). - pass '--init-data true' as post-image args alongside --username/--password - loads the rich sampledb (users/products/orders/analytics) vs the prior single doc - remove seedSampleData() driver hack - add capped, non-fatal waitForSampleData() so the tree reliably shows data on first expand (sample data loads just after gateway readiness) Verified live on Windows: --init-data true populates sampledb. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…shell provider) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Missing badge Turns the provision-and-browse POC into a managed instance (design §6.2/§11). - States: add Starting/Stopping; Stopped now reachable; Missing badge (§6.1) when metadata exists but Docker has no container - Service: start/stop/restart/deleteContainer/refreshLiveState; all destructive ops verify the quickstart label before acting (§9/§13.1); lifecycleBusy guard - Tree: state-aware rows with a Quick-Start-specific contextValue (treeItem_quickStartInstance + state token) so the instance shows Quick Start actions, not generic cluster menus; live-refresh on expand (cheap multi-window/external-change freshness, §12) - Commands: Start/Stop/Restart/Delete Container/Copy Connection String/Copy Password/View Logs (inline + context menu, gated by state) - Delete uses a one-line modal confirm (§11); password masked in View Logs (D14) Verified live on Windows: run/stop(exited)/start(running)/remove + label check. Gates: lint, jest 2055, build, webpack-prod all pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ocker exec) Baked '--init-data true' re-ran the image's sample-data init on every docker start, hit a duplicate-key error, and crashed the container (set -e); start() also inspected too early and falsely reported Running. Now run with only credentials and seed the built-in sampledb once after readiness via the image's native init script (docker exec), and require the container to stay running (confirmStaysRunning) before declaring Running. Verified live: stop->start stays running and sample data persists. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ased-cryptographic-random) Use rejection sampling so every URL-safe alphabet character is equally likely; a plain byte % 62 over-represented the first 8 characters. Flagged high-severity by CodeQL on PR #756. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Collaborator
|
🚀 amazing! |
…tance, ownership-bounded) Production v1 design decision for the multiple-instance / existing-container edge case raised by German Eichberger: Quick Start manages exactly one labelled instance it created; users attach their own containers via the regular wizard; multi-instance/adopt/auto-discovery deferred to v1.2 (labels keep the model forward-compatible). Identifies unlabelled name/port collision safety as the one concrete v1 hardening item. No code changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… Docker diagnosis P0: persistent named volume at /data (data survives recreate; Missing->recreate reuses stored creds+volume; idempotent sample seeding; explicit Delete drops the volume). Credentials now pass via a temp --env-file (mode 600, deleted in finally) as USERNAME/PASSWORD instead of CLI args (verified the image authenticates via env). Port-conflict fallback band [10260,10360) with bound-port readback. P1: DockerReadiness gains host arch/platformSupported; Docker-not-ready view rebuilt into per-check cards + Start Docker Desktop action + Install/Troubleshooting links; review Data card now 'Persistent volume'. Verified live + gates (lint/jest 2055/build/webpack/l10n). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
P1-3: success card adds Open Connection (focuses Connections view) + Copy Connection String, with a longer auto-close so the buttons are usable. P3-2: start/stop/restart re-check live Docker state via liveStateGuard before acting and inform the user if another window already changed it (design §12). P3-1: documentDB.quickstart.provision telemetry (result/reused/portFallback/provisionMs), getDockerStatus reports dockerReadiness+platformSupported, lifecycle commands tag action; no names/ports/creds sent (§14). Gates: l10n/prettier/lint/jest 2055/build/webpack-prod. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e coupling) 5-agent rubber-duck review (GPT-5.4/5.5 + Opus 4.8 REJECT; Opus 4.6/4.7 missed it) found a release blocker: emulatorConfiguration.isEmulator is overloaded as both the storage-zone selector and the TLS-allow-invalid trigger, so an emulator connection cannot be moved into the Clusters zone correctly. Reverted the migration cut. Recorded the prerequisite P2-0 (decouple storage-zone from isEmulator, the §7 work) which P2-1 and P2-2 both depend on. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…lator migration (§4, §7) P2-0: add explicit storageZone to ConnectionClusterModel + resolveStorageZone(cluster) helper (prefers the explicit zone, falls back to the old isEmulator inference). Stamp storageZone at the 3 construction sites and route every zone decision through it (DocumentDBClusterItem x3, removeConnection, moveItems, rename/updateCredentials/updateConnectionString wizards). isEmulator is kept only for behavior (TLS/timeouts/icons). +resolveStorageZone unit tests. P2-1: one-time migration copies each Emulators-zone connection into a 'Local Connections (Legacy)' folder in the Clusters zone (creds/auth/emulatorConfiguration preserved; isEmulator normalized so TLS still works; routed correctly via the new storageZone). Keeps the Emulators zone as read-only rollback; retires LocalEmulatorsItem once complete; one-time toast. create-if-missing (never overwrites user edits) + a reconciliation re-scan before the completion flag (closes the activation-window race) + isFolder guard + telemetry. Validated by a 3-round 5-agent rubber-duck review (GPT-5.4/5.5, Opus 4.6/4.7/4.8): the original isEmulator/zone blocker is resolved, the migration is data-safe/idempotent, TLS preserved, no regression. Pre-existing folder-aware deep-link reveal limitation documented as a follow-up. Gates: build/lint/jest 2058/l10n/prettier. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ort 10260 (§13.5) The manual local-connection wizard defaulted the DocumentDB emulator to 10255; the canonical DocumentDB local port is 10260 (matches Quick Start + the image). The Cosmos DB Mongo (RU) emulator legitimately keeps 10255. PromptPortStep's default/placeholder is now experience-aware. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…wizard (§7) Replaces the emulator-only TLS handling with a gated TLS-exception step in the regular new-connection wizard, per design §7. - Decouple TLS-allow-invalid from `isEmulator`: it now keys off `emulatorConfiguration.disableEmulatorSecurity` alone, so a regular local connection can accept a self-signed cert without being treated as an emulator (all 5 MongoClient option builders). - Gated wizard step (`PromptTlsExceptionStep`): offered only when every seed host is local/private; defaults to "Enable TLS". - Host classifier (`hostClassification.ts`): loopback/RFC1918/link-local/ULA/ `.local`/single-word, IDNA-normalized so a Unicode-dot homograph (`example。com`) cannot masquerade as a local host. - Write-time canonicalizer (`tlsException.ts`) is the security boundary: it strips every TLS-bypass URL param (cert/hostname/tlsInsecure/rejectUnauthorized) from the stored connection string and host-gates the exception, so the wizard, deep links and connection-string edits can never create an allow-invalid exception for a public host. - Hybrid runtime policy (`resolveAllowInvalidCertificates`): the stored flag is honored only for local/private hosts; on a public host a bare orphaned flag is inert (no allow-invalid, fail-fast timeout, local error copy, or tree badge), while an explicit URL param the user deliberately set is still honored. - Shell `isEmulator` now derives from credentials (not the timeout proxy); `updateConnectionString` host-gates both flags against the edited hosts. Verified across 8 five-agent review rounds (GPT-5.4/5.5, Opus 4.6/4.7/4.8) to unanimous consensus. The §7.3 connection-edit dialog remains a separate issue. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…nning Manual-testing UX feedback: - Success page no longer auto-closes after provisioning. The 4s auto-dismiss is removed and `Open Connection` no longer closes the panel — only the new explicit `Close` button dismisses it. Added a `Next steps` block (reusing the in-view successBox/Card pattern) and wired the shared Announcer for a11y. - `Delete Container…` is now offered while the instance is Running (menu gate += state_running). The confirmation is a stronger, state-aware data-loss warning (all data, logs and credentials are permanently lost; the running container is stopped first). deleteContainer() already force-removes (docker rm -f) and drops the data volume, so no backend change was needed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ample-data) Adds a collapsible Advanced panel to the Quick Start review screen for a custom host port, credentials, image tag, and a sample-data toggle (design §5.2), with security and data-safety hardening from a 4-round 5-agent review. Security (credentials off the host shell, §8.2): - Seed sample data by referencing $USERNAME/$PASSWORD from the container's OWN environment inside a ShellQuoting.Strong-quoted `sh -c`, so credentials never reach the host argv / process list on either bash or cmd. Credentials are now validated control-char-only (the env-file newline-injection vector stays blocked at zod + writeEnvFile; a `%` password round-trips safely). Data safety: - The reuse decision is keyed on stored credentials existing (live SecretStorage), not the in-memory Missing flag, so re-running setup can never silently wipe a reusable data volume; a fresh, volume-wiping provision is strictly the explicit Delete-then-recreate path. Recreate fidelity: - Persist the instance's image ref (metadata + a durable globalState record, backfilled on reconcile/adopt, cleared on Delete) so a recreate — even across a window reload — reuses the original image, not `latest`. - Surface a `willReuse` flag computed from the same predicate provision() uses; the webview hides the credential/image inputs and relabels the summary exactly when the service will reuse. Also: server-side both-or-neither credential refine (parity with the client); whitespace trim consistent client/zod/service; custom port preserved in the success message + connection string via a chosenPort inspect fallback; telemetry stays booleans-only (customPort/customCreds/customImage/sampleData). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… (v1.1)
Makes the provisioning flow usable with a keyboard and screen reader (WCAG 2.4.3,
3.3.1, 1.1.1, 4.1.3), reviewed by a 3-agent cross-model pass.
- Per-field validation: the Advanced inputs now surface errors via FluentUI
`Field` validationState/validationMessage (programmatically associated,
aria-invalid + role="alert") instead of one detached bottom message; credential
and image-tag checks are skipped while reusing an existing instance (those inputs
are hidden), and the offending field is highlighted.
- Progress announcements: a polite live region streams the current provisioning
stage; the failed and Docker-not-ready states are announced; the existing
success announcement is unchanged. The failure announcer is polite so it does not
clip the focus move, and the progress message is suppressed once a stage errors.
- Stage rows: the list is exposed as role="list"/"listitem" with a natural
row aria-label ("Pulling official image, done"); decorative icons are hidden. On
failure the active stage flips to the error state so it no longer reads/looks like
"in progress".
- Focus management: focus moves to the primary result action (Open Connection /
Retry) when provisioning ends, so keyboard/screen-reader users are not stranded on
<body> when the Cancel button unmounts.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Logs / Start over (v1.1) Implements §9.1: a wire-protocol readiness timeout no longer tears the container down. It is kept running (it may just be slow to initialize) and the webview offers Wait longer, View Docker output, and Start over, reviewed across 3 rounds by 5 agents. - Wait longer: re-probes the SAME retained container for another readiness window via a new `resumeReadiness` generator + `waitLonger` subscription — no re-pull, keeping the already-completed stages visible and streaming live logs. - Start over: `discardTimedOutInstance` removes the container and wipes the volume ONLY for a fresh (non-reusing) attempt; a reusing attempt's real data is always kept. - Reopen-safe: a `canResumeReadiness` status flag (gated on !busy) rehydrates the recovery actions when the panel is reopened instead of stranding the container. Data-safety / correctness: - Refactored the provision try/catch/finally to extract a shared, non-yielding `finalizeReadyInstance`, preserving the setStatus(Running)->success ordering so an unsubscribe after the terminal event can never tear down a healthy container. - Terminal events (timeout and hard error) are buffered and yielded AFTER `finally`, so provisioning/lifecycleBusy are clear before the webview shows Wait longer / Retry — no fast-click race with the "already in progress" guard. - `reconcile()` only removes an orphaned container, never its volume (a missing secret does not prove the volume is disposable — avoids irreversible data loss). - A webview stream-generation guard ignores trailing callbacks from a superseded or cancelled stream. Resume emits booleans/enum-only telemetry. Known limitation (v1.2): after a reload, reconcile adopts a reusing timed-out container as Running without re-probing; recoverable via Restart/Delete, no data loss. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.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.
One-sentence goal
What the POC does (demo narrative)
@microsoft/vscode-container-client(Docker).docker pull% streaming).ping, up to 180s) confirms the DB actually accepts connections ("running ≠ ready").sampledb(users / products / orders / analytics).Lifecycle management (v1.0 management layer)
The inline instance row is a full control surface, state-gated:
Missingbadge when the extension holds metadata but Docker has no matching container.vscode.documentdb.quickstartlabel on the container before acting; Delete uses a modal confirm; the generated password is masked in all Output-channel writes.Key technical decisions
QuickStartService(async-generator of stage events + per-attemptAbortSignal) instead of the single-useTaskbase class — fits cancellation + retry + the in-webview checklist model. (Deviation D13, logged.)--username/--password; the image's built-insampledbis seeded once after readiness by running the image's native init script viadocker exec. We deliberately do not bake--init-data trueinto the run args — that re-runs on everydocker start, hits a duplicate-key error, and crashes the container.start()/restart()also confirm the container stays running before declaring Running.Cmd/Bashshell provider so Go-template--formatargs quote correctly on Windows (otherwiseinfo/inspect/listbreak).DocumentDBClusterItemwithemulatorConfiguration = { isEmulator: true, disableEmulatorSecurity: true }→ TLS-allow-invalid + full browse via the existing tree, appearing only under the Quick Start node.Image:
ghcr.io/documentdb/documentdb/documentdb-local:latest· port10260· conn stringmongodb://<U>:<P>@localhost:10260/?tls=true&tlsAllowInvalidCertificates=true.Out of scope (deferred — POC, not production)
Legacy emulator migration (§4) · TLS-exception wizard (§7) · full action matrix details (§6) · port-fallback random band (§8.3, POC pre-checks 10260 and errors clearly) · container adoption / label-conflict (§10) · multi-window coordination / Docker events (§12) · advanced panel custom creds/image (§5.2) · categorized Docker diagnosis (§9) · telemetry (§14) · data-volume persistence (ephemeral by design). A short list of v1.0 readiness polish (platform check, Start-Docker-Desktop action, success-card buttons) is tracked in
review-and-resolutions.md.Verification
npm run build✅ ·npm run lint✅ ·npx jest --no-coverage(2055/2055) ✅ ·npm run webpack-prod✅. 16 new unit tests for output-masking + credential composition.How to test
See the step-by-step checklist in
docs/ai-and-plans/PRs/local-quickstart-poc/review-and-resolutions.md. In short:npm run webpack-prod→ launch with--extensionDevelopmentPath=dist→ Quick Start – Install & try → expand & browse → exercise Stop / Start / Restart / Delete.Process record (for reviewers & future agents)
description.md— decisions, scope, deviations, open questions.poc-implementation-plan.md— work breakdown & acceptance checks.review-and-resolutions.md— 5-agent reviews, every resolution, manual-test fixes, the v1.0 management layer, and the restart-safe fix.🤖 Generated with GitHub Copilot CLI