mirror of
https://github.com/warmbly/warmbly.git
synced 2026-10-12 16:02:44 +00:00
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
155 lines
5.9 KiB
Go
155 lines
5.9 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/mail"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"github.com/warmbly/warmbly/internal/api/middleware"
|
|
"github.com/warmbly/warmbly/internal/app/organization"
|
|
"github.com/warmbly/warmbly/internal/errx"
|
|
"github.com/warmbly/warmbly/internal/models"
|
|
"github.com/warmbly/warmbly/internal/repository"
|
|
)
|
|
|
|
type testerUsers struct {
|
|
repository.UserRepository
|
|
userID uuid.UUID
|
|
until time.Time
|
|
}
|
|
|
|
func (r *testerUsers) GetUserByEmail(context.Context, string) (*models.User, error) { return nil, nil }
|
|
|
|
func (r *testerUsers) CreateExemptUser(_ context.Context, email *mail.Address, _, _ string, _ *uuid.UUID, until time.Time) (*models.User, error) {
|
|
r.until = until
|
|
return &models.User{ID: r.userID, Email: email.Address}, nil
|
|
}
|
|
|
|
type testerWorkspaces struct {
|
|
organization.OrganizationService
|
|
orgID, actor, roleID uuid.UUID
|
|
until time.Time
|
|
created, joined bool
|
|
}
|
|
|
|
func (s *testerWorkspaces) CreateTesterWorkspace(_ context.Context, _, actor uuid.UUID, _, _ string, until time.Time) (*models.Organization, *errx.Error) {
|
|
s.created, s.actor, s.until = true, actor, until
|
|
return &models.Organization{ID: s.orgID, Category: models.OrganizationCategoryTest}, nil
|
|
}
|
|
|
|
func (s *testerWorkspaces) AttachTester(_ context.Context, orgID, _, actor, roleID uuid.UUID) (*models.OrganizationMember, *errx.Error) {
|
|
s.joined, s.orgID, s.actor, s.roleID = true, orgID, actor, roleID
|
|
return &models.OrganizationMember{OrganizationID: orgID}, nil
|
|
}
|
|
|
|
func TestAdminCreateTesterOnlyGrantsDedicatedWorkspaces(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
for _, existing := range []bool{false, true} {
|
|
actor, orgID, roleID := uuid.New(), uuid.New(), uuid.New()
|
|
users := &testerUsers{userID: uuid.New()}
|
|
orgs := &testerWorkspaces{orgID: orgID}
|
|
h := &Handler{UserRepo: users, OrganizationService: orgs}
|
|
r := gin.New()
|
|
r.Use(func(c *gin.Context) { c.Set(middleware.AdminUserIDKey, actor) })
|
|
r.POST("/testers", h.AdminCreateTester)
|
|
req := adminCreateTesterRequest{Email: "reviewer@example.test", Reason: "OAuth review", PasswordDays: 7}
|
|
if existing {
|
|
req.OrgID, req.RoleID = &orgID, &roleID
|
|
}
|
|
raw, err := json.Marshal(req)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
w := httptest.NewRecorder()
|
|
r.ServeHTTP(w, httptest.NewRequest(http.MethodPost, "/testers", strings.NewReader(string(raw))))
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("create tester existing=%v: HTTP %d", existing, w.Code)
|
|
}
|
|
var response adminCreateTesterResponse
|
|
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if response.Joined != existing || orgs.created == existing || orgs.joined != existing || orgs.actor != actor {
|
|
t.Fatalf("wrong provisioning path for existing=%v", existing)
|
|
}
|
|
if existing && orgs.roleID != roleID {
|
|
t.Fatal("existing workspace role changed")
|
|
}
|
|
if !existing && !orgs.until.Equal(users.until) {
|
|
t.Fatal("test entitlement did not use the reviewer password expiry")
|
|
}
|
|
if !response.PasswordExpiresAt.Equal(users.until) || !strings.HasPrefix(response.Password, "Tester-") {
|
|
t.Fatal("reviewer credentials response is incomplete")
|
|
}
|
|
}
|
|
}
|
|
|
|
type testerSampleService struct {
|
|
organization.OrganizationService
|
|
orgID, actor uuid.UUID
|
|
ip, agent string
|
|
called bool
|
|
err *errx.Error
|
|
}
|
|
|
|
func (s *testerSampleService) SeedTesterWorkspace(_ context.Context, orgID, actor uuid.UUID, ip, agent string) (*models.TesterSampleData, *errx.Error) {
|
|
s.called, s.orgID, s.actor, s.ip, s.agent = true, orgID, actor, ip, agent
|
|
return &models.TesterSampleData{OrganizationID: orgID, Created: true, SeededAt: time.Now()}, s.err
|
|
}
|
|
|
|
func TestAdminSeedTesterWorkspaceRequiresAuthorityAndValidTarget(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
actor, orgID := uuid.New(), uuid.New()
|
|
for _, tc := range []struct {
|
|
name string
|
|
perms models.AdminPermission
|
|
actor bool
|
|
id string
|
|
missing bool
|
|
err *errx.Error
|
|
status int
|
|
called bool
|
|
}{
|
|
{name: "allowed", perms: models.AdminPermManageTesters, actor: true, id: orgID.String(), status: http.StatusOK, called: true},
|
|
{name: "view only", perms: models.AdminPermViewUsers, actor: true, id: orgID.String(), status: http.StatusForbidden},
|
|
{name: "no actor", perms: models.AdminPermManageTesters, id: orgID.String(), status: http.StatusUnauthorized},
|
|
{name: "invalid target", perms: models.AdminPermManageTesters, actor: true, id: "not-a-uuid", status: http.StatusBadRequest},
|
|
{name: "nil target", perms: models.AdminPermManageTesters, actor: true, id: uuid.Nil.String(), status: http.StatusBadRequest},
|
|
{name: "inactive workspace", perms: models.AdminPermManageTesters, actor: true, id: orgID.String(), err: errx.New(errx.BadRequest, "inactive"), status: http.StatusBadRequest, called: true},
|
|
{name: "unavailable", perms: models.AdminPermManageTesters, actor: true, id: orgID.String(), missing: true, status: http.StatusServiceUnavailable},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
s := &testerSampleService{err: tc.err}
|
|
h := &Handler{}
|
|
if !tc.missing {
|
|
h.OrganizationService = s
|
|
}
|
|
r := gin.New()
|
|
r.Use(func(c *gin.Context) {
|
|
c.Set(middleware.AdminPermissionsKey, tc.perms)
|
|
if tc.actor {
|
|
c.Set(middleware.AdminUserIDKey, actor)
|
|
}
|
|
})
|
|
r.POST("/organizations/:id/sample-data", middleware.RequireAdminPermission(models.AdminPermManageTesters), h.AdminSeedTesterWorkspace)
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodPost, "/organizations/"+tc.id+"/sample-data", nil)
|
|
req.Header.Set("User-Agent", "sample-review")
|
|
r.ServeHTTP(w, req)
|
|
if w.Code != tc.status || s.called != tc.called {
|
|
t.Fatalf("HTTP %d, called=%v: %s", w.Code, s.called, w.Body.String())
|
|
}
|
|
if s.called && (s.orgID != orgID || s.actor != actor || s.agent != "sample-review" || s.ip == "") {
|
|
t.Fatal("target or audit attribution changed")
|
|
}
|
|
})
|
|
}
|
|
}
|