fix(provision): share Docker+SaaS prepare path so both mint workspace secrets (RFC #2312) - #2366
Merged
Merged
Conversation
… secrets (RFC #2312) Root cause of 2026-04-30 silent-503 chat-upload bug: provisionWorkspaceCP (SaaS) skipped issueAndInjectInboundSecret while provisionWorkspaceOpts (Docker) called it. Every prod SaaS workspace provisioned with NULL platform_inbound_secret → upload returned 503 with the v2-enrollment message on every attempt. Structural fix: - Extract prepareProvisionContext (secrets load, env mutators, preflight, cfg build), mintWorkspaceSecrets (auth_token + platform_inbound_secret), markProvisionFailed (broadcast + DB update) into workspace_provision_shared.go - Refactor both provision modes to call the shared helpers - Add provisionAbort struct so the missing-env failure class can carry its structured "missing" payload through the shared abort path - Unify last_sample_error: previously the decrypt-fail path skipped it while others set it; users now see every failure class in the UI Drift prevention: - AST gate TestProvisionFunctions_AllCallMintWorkspaceSecrets asserts every function in the provisionFunctions set calls mintWorkspaceSecrets at least once (same shape as the audit-coverage gate from #335). New provision paths must either call mint or be added to provisionExemptFunctions with a one-line justification - Behavioral test TestMintWorkspaceSecrets_PersistsInboundSecretInSaaSMode pins the contract: SaaS mode MUST persist platform_inbound_secret to the DB column even though it skips file injection Existing-workspace recovery (chat_files.go lazy-heal): - Upload + Download handlers detect NULL platform_inbound_secret and call IssuePlatformInboundSecret inline, returning 503 with retry_after_seconds=30 - Self-heals workspaces that were provisioned before this fix without requiring destructive reprovision Tests: full handlers + workspace-server module green; AST gate verified to fire red on deliberate violation (commented-out mint call surfaces the exact function name + actionable remediation message). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
HongmingWang-Rabbit
requested a review
from hongmingwang-moleculeai
as a code owner
April 30, 2026 09:18
HongmingWang-Rabbit
enabled auto-merge
April 30, 2026 09:19
5 tasks
HongmingWang-Rabbit
pushed a commit
that referenced
this pull request
Apr 30, 2026
…#2367) Closes #2367. TeamHandler.Expand provisioned child workspaces by directly calling h.provisioner.Start, skipping mintWorkspaceSecrets and every other preflight (secrets load, env mutators, identity injection, missing-env, empty-config-volume auto-recover). Children shipped with NULL platform_inbound_secret + never-issued auth_token — same drift class as the SaaS bug just fixed in PR #2366, found while exercising a stronger gate against this package. Fix: - TeamHandler now holds *WorkspaceHandler. Expand delegates each child provision to wh.provisionWorkspace, picking up the shared prepare/mint/preflight pipeline automatically. Future provision-time steps go in ONE place and team-expand inherits them. - prepareProvisionContext gains PARENT_ID env injection sourced from payload.ParentID (which Expand now populates). This preserves the signal workspace/coordinator.py reads on startup, without threading env through provisioner.WorkspaceConfig manually. - NewTeamHandler signature gains *WorkspaceHandler; router passes it. Gate upgrade: - TestProvisionFunctions_AllCallMintWorkspaceSecrets is now behavior-based: it walks every FuncDecl in the package and flags any function that calls h.provisioner.Start or h.cpProv.Start without also calling mintWorkspaceSecrets. Drift-resistant by construction — a future provision function with any name still trips the gate. - Replaces the name-list version from PR #2366. The name list missed Expand precisely because Expand wasn't named provision*; the behavior-based detector caught it spontaneously when prototyped. Tests: full workspace-server module green; gate previously verified to fire red on Expand pre-fix and on deliberate mintWorkspaceSecrets removal. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced Apr 30, 2026
Closed
HongmingWang-Rabbit
pushed a commit
that referenced
this pull request
Jun 12, 2026
…2366/#588) The merge queue used hard-coded limit=50 on list endpoints, silently truncating enumeration when more than 50 open PRs or status checks exist. This meant newer PRs could be invisible to the queue, and PRs with >50 status contexts would have incomplete check evaluation. Changes: - Add api_paginated() helper that loops through pages until a partial page is returned (indicating end of collection). - list_queued_issues() and list_candidate_issues() now use pagination to enumerate ALL open PRs, not just the first 50. - get_combined_status() /statuses enrichment now paginates to capture all status checks beyond the 50-entry cap. All 52 gitea-merge-queue tests pass. Refs: molecule-core#2366/#588, PM dispatch 01eaa317.
HongmingWang-Rabbit
pushed a commit
that referenced
this pull request
Jun 12, 2026
Serialized merge by gitea-merge-queue after current-main, genuine approvals, and required CI checks were green.
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
Root cause of 2026-04-30 silent-503 chat-upload bug:
provisionWorkspaceCP(SaaS) skippedissueAndInjectInboundSecretwhileprovisionWorkspaceOpts(Docker) called it. Every prod SaaS workspace shipped withNULL platform_inbound_secret→ upload returned 503 with the v2-enrollment message on every attempt.Structural fix — extract the mode-agnostic prepare/mint/markFailed helpers into
workspace_provision_shared.goso both modes call exactly the same prelude. Adding a future provision-time setup step now goes in ONE place and both modes pick it up automatically.What's shared
prepareProvisionContext— secrets load (global+workspace), env mutators, identity injection, missing-env preflight, cfg buildmintWorkspaceSecrets—auth_token+platform_inbound_secret(load-bearing for chat upload + every/internalendpoint)markProvisionFailed— broadcastWORKSPACE_PROVISION_FAILED+ persistlast_sample_errorWhat stays mode-specific
provisioner.Startwith local Docker, thenWriteFilesToContainerfor the/configsvolumecpProv.Start(CP launches EC2), persist returnedinstance_id, defer.auth_token+.platform_inbound_secretdelivery to the workspace's first/registry/registerresponseDrift prevention
TestProvisionFunctions_AllCallMintWorkspaceSecrets— AST gate that walks everyprovision*function in the package and asserts it callsmintWorkspaceSecrets. Same shape as the audit-coverage gate from fix(security): scope PausePollersForToken to requesting workspace (#329) #335. New provision paths must call mint or be added toprovisionExemptFunctionswith a one-line justificationTestMintWorkspaceSecrets_PersistsInboundSecretInSaaSMode— behavioral test that pins the contract: SaaS mode MUST persistplatform_inbound_secretto the DB column even though it skips Docker file injectionExisting-workspace recovery (lazy-heal)
chat_files.goUpload + Download handlers detectNULL platform_inbound_secretand callIssuePlatformInboundSecretinline, returning 503 withretry_after_seconds=30. Self-heals workspaces that were provisioned before this fix without requiring a destructive reprovision.Test plan
go build ./...cleango test ./...all green (full workspace-server module)TestProvisionWorkspace_NoInternalErrorsInBroadcastandTestProvisionWorkspaceCP_NoInternalErrorsInBroadcaststill pin the F1086/[QA] err.Error() leaks in workspace_provision.go and plugins_install_pipeline.go #1206 redaction invariantplatform_inbound_secretrow is NOT NULL, confirm chat upload returns 200🤖 Generated with Claude Code