From 65c1dca85e3b6c8c8f2219190a8053df7a640e72 Mon Sep 17 00:00:00 2001 From: "Molecule AI Dev Engineer A (Kimi)" Date: Sat, 23 May 2026 06:04:45 +0000 Subject: [PATCH 1/3] fix(tests): make SSRF and admin-token tests hermetic against env vars Tests in mcp_test.go assumed strict (non-SaaS) SSRF mode but inherited MOLECULE_ORG_ID from the container environment, causing isSafeURL and isPrivateOrMetadataIP to allow RFC-1918 ranges and fail. Tests in admin_test_token_test.go assumed no ADMIN_TOKEN gate but inherited ADMIN_TOKEN from the environment, causing 401 instead of the expected 200/404. Add t.Setenv guards to both files so each test controls its own environment and passes regardless of ambient env vars. Co-Authored-By: Claude Opus 4.7 --- .../internal/handlers/admin_test_token_test.go | 3 +++ workspace-server/internal/handlers/mcp_test.go | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/workspace-server/internal/handlers/admin_test_token_test.go b/workspace-server/internal/handlers/admin_test_token_test.go index 62d3f2b6e..3097aea79 100644 --- a/workspace-server/internal/handlers/admin_test_token_test.go +++ b/workspace-server/internal/handlers/admin_test_token_test.go @@ -39,6 +39,7 @@ func TestAdminTestToken_EnabledViaFlagEvenInProd(t *testing.T) { mock := setupTestDB(t) t.Setenv("MOLECULE_ENV", "production") t.Setenv("MOLECULE_ENABLE_TEST_TOKENS", "1") + t.Setenv("ADMIN_TOKEN", "") mock.ExpectQuery("SELECT id FROM workspaces WHERE id ="). WithArgs("ws-1"). @@ -58,6 +59,7 @@ func TestAdminTestToken_EnabledViaFlagEvenInProd(t *testing.T) { func TestAdminTestToken_WorkspaceNotFound(t *testing.T) { mock := setupTestDB(t) t.Setenv("MOLECULE_ENV", "development") + t.Setenv("ADMIN_TOKEN", "") mock.ExpectQuery("SELECT id FROM workspaces WHERE id ="). WithArgs("missing"). @@ -75,6 +77,7 @@ func TestAdminTestToken_WorkspaceNotFound(t *testing.T) { func TestAdminTestToken_HappyPath_TokenValidates(t *testing.T) { mock := setupTestDB(t) t.Setenv("MOLECULE_ENV", "development") + t.Setenv("ADMIN_TOKEN", "") mock.ExpectQuery("SELECT id FROM workspaces WHERE id ="). WithArgs("ws-1"). diff --git a/workspace-server/internal/handlers/mcp_test.go b/workspace-server/internal/handlers/mcp_test.go index 3affb8e32..32843e92f 100644 --- a/workspace-server/internal/handlers/mcp_test.go +++ b/workspace-server/internal/handlers/mcp_test.go @@ -1141,6 +1141,8 @@ func TestIsSafeURL_Blocks169_254_Metadata(t *testing.T) { } func TestIsSafeURL_Blocks10xPrivate(t *testing.T) { + t.Setenv("MOLECULE_ORG_ID", "") + t.Setenv("MOLECULE_DEPLOY_MODE", "self-hosted") err := isSafeURL("http://10.0.0.1/agent") if err == nil { t.Errorf("isSafeURL: expected 10.x.x.x to be blocked, got nil") @@ -1148,6 +1150,8 @@ func TestIsSafeURL_Blocks10xPrivate(t *testing.T) { } func TestIsSafeURL_Blocks172Private(t *testing.T) { + t.Setenv("MOLECULE_ORG_ID", "") + t.Setenv("MOLECULE_DEPLOY_MODE", "self-hosted") err := isSafeURL("http://172.16.0.1/agent") if err == nil { t.Errorf("isSafeURL: expected 172.16.0.0/12 to be blocked, got nil") @@ -1155,6 +1159,8 @@ func TestIsSafeURL_Blocks172Private(t *testing.T) { } func TestIsSafeURL_Blocks192_168Private(t *testing.T) { + t.Setenv("MOLECULE_ORG_ID", "") + t.Setenv("MOLECULE_DEPLOY_MODE", "self-hosted") err := isSafeURL("http://192.168.1.100/agent") if err == nil { t.Errorf("isSafeURL: expected 192.168.x.x to be blocked, got nil") @@ -1178,6 +1184,8 @@ func TestIsSafeURL_BlocksInvalidURL(t *testing.T) { // ==================== SSRF Defence — isPrivateOrMetadataIP ==================== func TestIsPrivateOrMetadataIP_10Range(t *testing.T) { + t.Setenv("MOLECULE_ORG_ID", "") + t.Setenv("MOLECULE_DEPLOY_MODE", "self-hosted") tests := []string{"10.0.0.0", "10.255.255.255", "10.1.2.3"} for _, ip := range tests { if !isPrivateOrMetadataIP(net.ParseIP(ip)) { @@ -1187,6 +1195,8 @@ func TestIsPrivateOrMetadataIP_10Range(t *testing.T) { } func TestIsPrivateOrMetadataIP_172Range(t *testing.T) { + t.Setenv("MOLECULE_ORG_ID", "") + t.Setenv("MOLECULE_DEPLOY_MODE", "self-hosted") tests := []string{"172.16.0.0", "172.31.255.255", "172.20.1.1"} for _, ip := range tests { if !isPrivateOrMetadataIP(net.ParseIP(ip)) { @@ -1196,6 +1206,8 @@ func TestIsPrivateOrMetadataIP_172Range(t *testing.T) { } func TestIsPrivateOrMetadataIP_192_168Range(t *testing.T) { + t.Setenv("MOLECULE_ORG_ID", "") + t.Setenv("MOLECULE_DEPLOY_MODE", "self-hosted") tests := []string{"192.168.0.0", "192.168.255.255", "192.168.1.1"} for _, ip := range tests { if !isPrivateOrMetadataIP(net.ParseIP(ip)) { -- 2.52.0 From 5727ff4323802c39901a68b1ae392253a541ee28 Mon Sep 17 00:00:00 2001 From: "Molecule AI Dev Engineer A (Kimi)" Date: Sat, 23 May 2026 06:10:55 +0000 Subject: [PATCH 2/3] fix(tests): add env guards to registry, security, and provision tests Additional tests that inherited MOLECULE_ORG_ID or ADMIN_TOKEN from the container environment and failed: - registry_test.go: TestValidateAgentURL (strict RFC-1918 checks) - security_regression_685_686_687_688_test.go: fresh-install fail-open tests that need ADMIN_TOKEN unset to pass through the AdminAuth gate - workspace_provision_test.go: issueAndInjectToken tests that verify token injection into ConfigFiles (skipped in SaaS mode) Co-Authored-By: Claude Opus 4.7 --- workspace-server/internal/handlers/registry_test.go | 2 ++ .../handlers/security_regression_685_686_687_688_test.go | 2 ++ .../internal/handlers/workspace_provision_test.go | 8 ++++++++ 3 files changed, 12 insertions(+) diff --git a/workspace-server/internal/handlers/registry_test.go b/workspace-server/internal/handlers/registry_test.go index 7ad1dbbc6..7332279ec 100644 --- a/workspace-server/internal/handlers/registry_test.go +++ b/workspace-server/internal/handlers/registry_test.go @@ -712,6 +712,8 @@ func TestHeartbeat_SkipsRemovedRows(t *testing.T) { // ------------------------------------------------------------ func TestValidateAgentURL(t *testing.T) { + t.Setenv("MOLECULE_ORG_ID", "") + t.Setenv("MOLECULE_DEPLOY_MODE", "self-hosted") cases := []struct { name string url string diff --git a/workspace-server/internal/handlers/security_regression_685_686_687_688_test.go b/workspace-server/internal/handlers/security_regression_685_686_687_688_test.go index aa35a5172..a072ecee5 100644 --- a/workspace-server/internal/handlers/security_regression_685_686_687_688_test.go +++ b/workspace-server/internal/handlers/security_regression_685_686_687_688_test.go @@ -95,6 +95,7 @@ func TestSecurity_GetTemplates_NoAuth_Returns401(t *testing.T) { func TestSecurity_GetTemplates_FreshInstall_FailsOpen(t *testing.T) { setupTestDB(t) setupTestRedis(t) + t.Setenv("ADMIN_TOKEN", "") authDB, authMock := newFreshInstallAuthDB(t) tmpDir := t.TempDir() @@ -152,6 +153,7 @@ func TestSecurity_GetOrgTemplates_NoAuth_Returns401(t *testing.T) { func TestSecurity_GetOrgTemplates_FreshInstall_FailsOpen(t *testing.T) { setupTestDB(t) setupTestRedis(t) + t.Setenv("ADMIN_TOKEN", "") authDB, authMock := newFreshInstallAuthDB(t) tmpDir := t.TempDir() diff --git a/workspace-server/internal/handlers/workspace_provision_test.go b/workspace-server/internal/handlers/workspace_provision_test.go index a5e46d64a..7d81af849 100644 --- a/workspace-server/internal/handlers/workspace_provision_test.go +++ b/workspace-server/internal/handlers/workspace_provision_test.go @@ -788,6 +788,8 @@ func TestIssueAndInjectToken_HappyPath(t *testing.T) { mock := setupTestDB(t) broadcaster := newTestBroadcaster() handler := NewWorkspaceHandler(broadcaster, nil, "http://localhost:8080", t.TempDir()) + t.Setenv("MOLECULE_ORG_ID", "") + t.Setenv("MOLECULE_DEPLOY_MODE", "self-hosted") // RevokeAllForWorkspace UPDATE (0 rows — no prior tokens, still succeeds) mock.ExpectExec(`UPDATE workspace_auth_tokens SET revoked_at`). @@ -825,6 +827,8 @@ func TestIssueAndInjectToken_RotatesExistingToken(t *testing.T) { mock := setupTestDB(t) broadcaster := newTestBroadcaster() handler := NewWorkspaceHandler(broadcaster, nil, "http://localhost:8080", t.TempDir()) + t.Setenv("MOLECULE_ORG_ID", "") + t.Setenv("MOLECULE_DEPLOY_MODE", "self-hosted") // RevokeAllForWorkspace: 1 existing token revoked mock.ExpectExec(`UPDATE workspace_auth_tokens SET revoked_at`). @@ -891,6 +895,8 @@ func TestIssueAndInjectToken_IssueFailSkipsInjection(t *testing.T) { mock := setupTestDB(t) broadcaster := newTestBroadcaster() handler := NewWorkspaceHandler(broadcaster, nil, "http://localhost:8080", t.TempDir()) + t.Setenv("MOLECULE_ORG_ID", "") + t.Setenv("MOLECULE_DEPLOY_MODE", "self-hosted") mock.ExpectExec(`UPDATE workspace_auth_tokens SET revoked_at`). WithArgs("ws-418-issue-fail"). @@ -917,6 +923,8 @@ func TestIssueAndInjectToken_NilConfigFilesAllocated(t *testing.T) { mock := setupTestDB(t) broadcaster := newTestBroadcaster() handler := NewWorkspaceHandler(broadcaster, nil, "http://localhost:8080", t.TempDir()) + t.Setenv("MOLECULE_ORG_ID", "") + t.Setenv("MOLECULE_DEPLOY_MODE", "self-hosted") mock.ExpectExec(`UPDATE workspace_auth_tokens SET revoked_at`). WithArgs("ws-418-nil-cfg"). -- 2.52.0 From b4cc4e2e228fa040f733d84cc848554a31316ade Mon Sep 17 00:00:00 2001 From: "Molecule AI Dev Engineer A (Kimi)" Date: Sat, 23 May 2026 06:17:27 +0000 Subject: [PATCH 3/3] fix(tests): add ADMIN_TOKEN guards to middleware and router tests Additional environment-sensitive tests that inherited ADMIN_TOKEN: - wsauth_middleware_test.go: 6 AdminAuth tests that expect fail-open or bearer-token behavior without an ambient admin secret - admin_test_token_route_test.go: fresh-install fail-open test Co-Authored-By: Claude Opus 4.7 --- .../internal/middleware/wsauth_middleware_test.go | 6 ++++++ .../internal/router/admin_test_token_route_test.go | 1 + 2 files changed, 7 insertions(+) diff --git a/workspace-server/internal/middleware/wsauth_middleware_test.go b/workspace-server/internal/middleware/wsauth_middleware_test.go index b42209b3a..8371802c2 100644 --- a/workspace-server/internal/middleware/wsauth_middleware_test.go +++ b/workspace-server/internal/middleware/wsauth_middleware_test.go @@ -256,6 +256,7 @@ func TestWorkspaceAuth_WrongWorkspace_Returns401(t *testing.T) { // live tokens anywhere) the middleware must let the request through so existing // deployments keep working during the Phase-30 rollout. func TestAdminAuth_FailOpen_NoTokensGlobally(t *testing.T) { + t.Setenv("ADMIN_TOKEN", "") mockDB, mock, err := sqlmock.New() if err != nil { t.Fatalf("sqlmock.New: %v", err) @@ -375,6 +376,7 @@ func TestAdminAuth_C11_DeleteNoBearer_Returns401(t *testing.T) { // TestAdminAuth_ValidBearer_Passes — a valid bearer token (from any workspace) // must be accepted for admin routes. func TestAdminAuth_ValidBearer_Passes(t *testing.T) { + t.Setenv("ADMIN_TOKEN", "") mockDB, mock, err := sqlmock.New() if err != nil { t.Fatalf("sqlmock.New: %v", err) @@ -418,6 +420,7 @@ func TestAdminAuth_ValidBearer_Passes(t *testing.T) { // TestAdminAuth_InvalidBearer_Returns401 — wrong token must not grant admin access. func TestAdminAuth_InvalidBearer_Returns401(t *testing.T) { + t.Setenv("ADMIN_TOKEN", "") mockDB, mock, err := sqlmock.New() if err != nil { t.Fatalf("sqlmock.New: %v", err) @@ -700,6 +703,7 @@ func TestAdminAuth_Issue180_ApprovalsListing_NoBearer_Returns401(t *testing.T) { // fail-open contract: on a fresh install (no tokens anywhere), the middleware // must not block the canvas from polling /approvals/pending. func TestAdminAuth_Issue180_ApprovalsListing_FailOpen_NoTokens(t *testing.T) { + t.Setenv("ADMIN_TOKEN", "") mockDB, mock, err := sqlmock.New() if err != nil { t.Fatalf("sqlmock.New: %v", err) @@ -1098,6 +1102,7 @@ func TestCanvasOrBearer_TokensExist_CanvasOrigin_Passes(t *testing.T) { // issuing workspace has status='removed' must not grant admin access. // The JOIN in ValidateAnyToken filters the row out, resulting in ErrNoRows. func TestAdminAuth_RemovedWorkspaceToken_Returns401(t *testing.T) { + t.Setenv("ADMIN_TOKEN", "") mockDB, mock, err := sqlmock.New() if err != nil { t.Fatalf("sqlmock.New: %v", err) @@ -1251,6 +1256,7 @@ func TestAdminAuth_623_ForgedCORSOrigin_Returns401(t *testing.T) { // TestAdminAuth_623_ValidBearer_WithOrigin_Passes — bearer + matching Origin // should still work (the Origin is irrelevant once the bearer validates). func TestAdminAuth_623_ValidBearer_WithOrigin_Passes(t *testing.T) { + t.Setenv("ADMIN_TOKEN", "") mockDB, mock, err := sqlmock.New() if err != nil { t.Fatalf("sqlmock: %v", err) diff --git a/workspace-server/internal/router/admin_test_token_route_test.go b/workspace-server/internal/router/admin_test_token_route_test.go index 8f59250bd..6a6fc51ab 100644 --- a/workspace-server/internal/router/admin_test_token_route_test.go +++ b/workspace-server/internal/router/admin_test_token_route_test.go @@ -81,6 +81,7 @@ func TestTestTokenRoute_RequiresAdminAuth_WhenTokensExist(t *testing.T) { // bootstrap path still works before the first workspace has registered. func TestTestTokenRoute_FailOpenOnFreshInstall(t *testing.T) { t.Setenv("MOLECULE_ENV", "development") + t.Setenv("ADMIN_TOKEN", "") mock := setupRouterTestDB(t) // HasAnyLiveTokenGlobal: no tokens yet — fresh install. -- 2.52.0