9e6c2098b1
Co-authored-by: nova28 <17953305+nova28@users.noreply.github.com> Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
88 lines
3.4 KiB
Go
88 lines
3.4 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 "no GitHub or GitLab service
|
|
// available" return); the client itself is never exercised by this
|
|
// test. GitLab is left nil — this test only covers the shared
|
|
// authorization wiring, which applies regardless of provider.
|
|
githubSvc := github.NewService(nil, github.AuthMethodNone, nil, nil, nil, log)
|
|
|
|
svc := initWorkflowSyncService(db.NewPool(sqlxDB, sqlxDB), githubSvc, nil, 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)
|
|
}
|
|
}
|