Files
kandev/apps/backend/internal/backendapp/workflowsync_wiring_test.go
T

86 lines
3.3 KiB
Go

package backendapp
import (
"context"
"errors"
"path/filepath"
"testing"
"github.com/jmoiron/sqlx"
"github.com/kandev/kandev/internal/auth/authn"
"github.com/kandev/kandev/internal/common/logger"
"github.com/kandev/kandev/internal/db"
"github.com/kandev/kandev/internal/github"
"github.com/kandev/kandev/internal/task/repository/repoerrors"
taskservice "github.com/kandev/kandev/internal/task/service"
)
// TestInitWorkflowSyncService_WiresRealWorkspaceAuthorization calls the real
// initWorkflowSyncService boot function — not a hand-copied re-wiring — with a
// real taskservice.Service backed by SQLite, so a regression that removes or
// breaks the SetWorkspaceAuthorizer(taskSvc.AuthorizeWorkspaceAccess) line
// inside it fails this test. The workflowsync package's own tests only ever
// install a hand-written fake authorizer and cannot detect that class of
// regression.
func TestInitWorkflowSyncService_WiresRealWorkspaceAuthorization(t *testing.T) {
harness := newBootStateTestHarness(t)
ctx := context.Background()
ownerCtx := authn.WithIdentity(ctx, authn.Identity{UserID: "owner-1", Role: authn.RoleMember})
workspace, err := harness.taskSvc.CreateWorkspace(ownerCtx, &taskservice.CreateWorkspaceRequest{
Name: "victim workspace",
})
if err != nil {
t.Fatalf("create workspace: %v", err)
}
if workspace.OwnerID != "owner-1" {
t.Fatalf("workspace owner = %q, want owner-1 (authenticated caller owns what it creates)", workspace.OwnerID)
}
dbConn, err := db.OpenSQLite(filepath.Join(t.TempDir(), "workflowsync.db"))
if err != nil {
t.Fatalf("OpenSQLite: %v", err)
}
sqlxDB := sqlx.NewDb(dbConn, "sqlite3")
t.Cleanup(func() {
if err := sqlxDB.Close(); err != nil {
t.Errorf("close db: %v", err)
}
})
log, err := logger.NewLogger(logger.LoggingConfig{Level: "error", Format: "console"})
if err != nil {
t.Fatalf("logger: %v", err)
}
// A non-nil GitHub service is required for initWorkflowSyncService to
// wire anything at all (see its early "GitHub unavailable" return); the
// client itself is never exercised by this test.
githubSvc := github.NewService(nil, github.AuthMethodNone, nil, nil, nil, log)
svc := initWorkflowSyncService(db.NewPool(sqlxDB, sqlxDB), githubSvc, harness.workflowSvc, harness.taskSvc, log)
if svc == nil {
t.Fatal("initWorkflowSyncService returned nil")
}
if _, err := svc.GetConfigForWorkspace(ownerCtx, workspace.ID); err != nil {
t.Fatalf("owner GetConfigForWorkspace: %v", err)
}
foreignCtx := authn.WithIdentity(ctx, authn.Identity{UserID: "attacker-1", Role: authn.RoleMember})
_, err = svc.GetConfigForWorkspace(foreignCtx, workspace.ID)
if !errors.Is(err, repoerrors.ErrWorkspaceNotFound) {
t.Fatalf("foreign identity GetConfigForWorkspace err = %v, want ErrWorkspaceNotFound", err)
}
// Internal caller (no identity in context — matches the periodic poller)
// and the pre-auth synthetic identity are both unscoped.
if _, err := svc.GetConfigForWorkspace(ctx, workspace.ID); err != nil {
t.Fatalf("identity-free GetConfigForWorkspace: %v", err)
}
syntheticCtx := authn.WithIdentity(ctx, authn.Identity{UserID: "single-user", Role: authn.RoleAdmin, Synthetic: true})
if _, err := svc.GetConfigForWorkspace(syntheticCtx, workspace.ID); err != nil {
t.Fatalf("synthetic identity GetConfigForWorkspace: %v", err)
}
}