Files
Bruno ClermontandBruno Clermont 7d95e4ae01 fix: resolve duplicated tenant-path segment in team shared-workspace resolution (#1322)
Root cause: internal/agent/loop_context.go re-applied tenant scoping
(TenantLayer/TenantID) on top of l.dataDir, which was already
tenant-scoped upstream in internal/agent/resolver.go, producing paths
like /app/workspace/tenants/<slug>/tenants/<slug>/teams/<teamID>
instead of the correct /app/workspace/tenants/<slug>/teams/<teamID>.

Also consolidates all previously-duplicated tenant-path-joining logic
(config.TenantDataDir, config.TenantWorkspace, tools.TenantLayer,
workspace.tenantPath) into a single canonical config.TenantScopedDir
function in internal/config/tenant_paths.go, with all other
implementations now delegating to it.

Co-authored-by: Bruno Clermont <bruno.clermont@gmail.com>
2026-07-02 04:58:45 +07:00

79 lines
2.5 KiB
Go

package config
import (
"path/filepath"
"testing"
"github.com/google/uuid"
)
func TestTenantScopedDir_MasterTenant(t *testing.T) {
got := TenantScopedDir("/data", masterTenantID.String(), "master")
if got != "/data" {
t.Errorf("master tenant should be no-op, got %s", got)
}
}
func TestTenantScopedDir_EmptyTenantID(t *testing.T) {
got := TenantScopedDir("/data", "", "acme")
if got != "/data" {
t.Errorf("empty tenantID should be no-op, got %s", got)
}
}
func TestTenantScopedDir_UsesSlug(t *testing.T) {
tid := uuid.MustParse("0193b000-0000-7000-8000-000000000002")
got := TenantScopedDir("/data", tid.String(), "acme")
want := filepath.Join("/data", "tenants", "acme")
if got != want {
t.Errorf("got %s, want %s", got, want)
}
}
func TestTenantScopedDir_EmptySlugFallsBackToID(t *testing.T) {
tid := uuid.MustParse("0193b000-0000-7000-8000-000000000002")
got := TenantScopedDir("/data", tid.String(), "")
want := filepath.Join("/data", "tenants", tid.String())
if got != want {
t.Errorf("got %s, want %s", got, want)
}
}
func TestTenantScopedDir_TraversalDefense(t *testing.T) {
tid := uuid.MustParse("0193b000-0000-7000-8000-000000000002")
got := TenantScopedDir("/data", tid.String(), "../../etc")
want := filepath.Join("/data", "tenants", tid.String())
if got != want {
t.Errorf("malicious slug should fall back to ID-based path, got %s, want %s", got, want)
}
}
// TestTenantDataDir_TenantWorkspace_DelegateToCanonical pins that both
// exported wrappers produce identical output shapes via the single
// canonical TenantScopedDir implementation — no independent join logic.
func TestTenantDataDir_TenantWorkspace_DelegateToCanonical(t *testing.T) {
tid := uuid.MustParse("0193b000-0000-7000-8000-000000000002")
dataDir := TenantDataDir("/data", tid, "acme")
wantDataDir := filepath.Join("/data", "tenants", "acme")
if dataDir != wantDataDir {
t.Errorf("TenantDataDir = %s, want %s", dataDir, wantDataDir)
}
workspace := TenantWorkspace("/ws", tid, "acme")
wantWorkspace := filepath.Join("/ws", "tenants", "acme")
if workspace != wantWorkspace {
t.Errorf("TenantWorkspace = %s, want %s", workspace, wantWorkspace)
}
}
func TestTenantTeamDir(t *testing.T) {
tid := uuid.MustParse("0193b000-0000-7000-8000-000000000002")
teamID := uuid.MustParse("0193c000-0000-7000-8000-000000000003")
got := TenantTeamDir("/data", tid, "acme", teamID)
want := filepath.Join("/data", "tenants", "acme", "teams", teamID.String())
if got != want {
t.Errorf("got %s, want %s", got, want)
}
}