mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-13 13:18:56 +02:00
* 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>
49 lines
1.4 KiB
Go
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())
|
|
}
|
|
}
|