Files
multica/server/internal/handler/file_test.go
devv-eve 8c0708bb5d fix(server): validate workspace membership for subscriptions and uploads (#935)
* fix(server): validate workspace membership for subscription targets and file uploads

Closes MED-1 (cross-workspace subscription injection) and MED-2 (file upload
missing workspace member validation) from the security audit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test(server): add negative tests for cross-workspace subscription and upload

Address PR review feedback:
- Add tests verifying cross-workspace user_id is rejected with 403 on
  subscribe and unsubscribe
- Add test verifying upload with foreign workspace_id is rejected with 403
- Make isWorkspaceEntity explicitly enumerate "member"/"agent" and reject
  unknown user types

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Devv <devv@Devvs-Mac-mini.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 20:22:03 -07:00

49 lines
1.4 KiB
Go

package handler
import (
"bytes"
"context"
"fmt"
"mime/multipart"
"net/http"
"net/http/httptest"
"testing"
)
type mockStorage struct{}
func (m *mockStorage) Upload(_ context.Context, key string, _ []byte, _ string, _ string) (string, error) {
return fmt.Sprintf("https://cdn.example.com/%s", key), nil
}
func (m *mockStorage) Delete(_ context.Context, _ string) {}
func (m *mockStorage) DeleteKeys(_ context.Context, _ []string) {}
func (m *mockStorage) KeyFromURL(rawURL string) string { return rawURL }
func TestUploadFileForeignWorkspace(t *testing.T) {
origStorage := testHandler.Storage
testHandler.Storage = &mockStorage{}
defer func() { testHandler.Storage = origStorage }()
var body bytes.Buffer
writer := multipart.NewWriter(&body)
part, err := writer.CreateFormFile("file", "test.txt")
if err != nil {
t.Fatal(err)
}
part.Write([]byte("hello world"))
writer.Close()
foreignWorkspaceID := "00000000-0000-0000-0000-000000000099"
req := httptest.NewRequest("POST", "/api/upload-file", &body)
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("X-User-ID", testUserID)
req.Header.Set("X-Workspace-ID", foreignWorkspaceID)
w := httptest.NewRecorder()
testHandler.UploadFile(w, req)
if w.Code != http.StatusForbidden {
t.Fatalf("UploadFile with foreign workspace: expected 403, got %d: %s", w.Code, w.Body.String())
}
}