Files
story/internal/identity/repository_integration_test.go
T

62 lines
2.3 KiB
Go
Raw Normal View History

2026-08-26 06:41:07 +08:00
package identity
import (
"context"
"errors"
"os"
"testing"
"github.com/jackc/pgx/v5/pgxpool"
)
const (
localIssuer = "http://localhost:58180/realms/voice-local"
ownerSubject = "00000000-0000-0000-0000-000000000101"
outsiderSubject = "00000000-0000-0000-0000-000000000103"
firstHouseholdID = "10000000-0000-0000-0000-000000000211"
secondHouseholdID = "20000000-0000-0000-0000-000000000211"
)
func TestRepositoryEnforcesTenantAndRoleBoundaries(t *testing.T) {
databaseURL := os.Getenv("TEST_DATABASE_URL")
if databaseURL == "" {
t.Skip("TEST_DATABASE_URL is not set")
}
ctx := context.Background()
pool, err := pgxpool.New(ctx, databaseURL)
if err != nil {
t.Fatalf("connect integration database: %v", err)
}
defer pool.Close()
repository := NewRepository(pool)
owner := Principal{Issuer: localIssuer, Subject: ownerSubject}
currentUser, err := repository.CurrentUser(ctx, owner)
if err != nil {
t.Fatalf("load owner: %v", err)
}
if len(currentUser.Accounts) != 1 || len(currentUser.Accounts[0].Memberships) != 1 {
t.Fatalf("unexpected owner account: %#v", currentUser)
}
if currentUser.Accounts[0].Memberships[0].Role != RoleOwner {
t.Fatalf("owner role not resolved: %#v", currentUser.Accounts[0].Memberships[0])
}
if _, err := repository.RequireHouseholdCapability(ctx, owner, firstHouseholdID, CapabilityHouseholdManage); err != nil {
t.Fatalf("owner should manage own household: %v", err)
}
outsider := Principal{Issuer: localIssuer, Subject: outsiderSubject}
if _, err := repository.RequireHouseholdCapability(ctx, outsider, firstHouseholdID, CapabilityHouseholdRead); !errors.Is(err, ErrAccessDenied) {
t.Fatalf("cross-tenant access error = %v, want ErrAccessDenied", err)
}
if _, err := repository.RequireHouseholdCapability(ctx, outsider, secondHouseholdID, CapabilityHouseholdRead); err != nil {
t.Fatalf("viewer should read own household: %v", err)
}
if _, err := repository.RequireHouseholdCapability(ctx, outsider, secondHouseholdID, CapabilityHouseholdManage); !errors.Is(err, ErrAccessDenied) {
t.Fatalf("viewer manage error = %v, want ErrAccessDenied", err)
}
if _, err := repository.RequireHouseholdCapability(ctx, owner, firstHouseholdID, CapabilityRecordingPlay); !errors.Is(err, ErrAccessDenied) {
t.Fatalf("owner recording access error = %v, want ErrAccessDenied", err)
}
}