1
0
forked from baron/baron-sso

chore: consolidate local integration changes

This commit is contained in:
2026-06-09 21:03:05 +09:00
parent aa2848c3b6
commit 1341f07ef9
158 changed files with 10995 additions and 1490 deletions

View File

@@ -64,6 +64,28 @@ func TestWorksmobileHTTPClientCreateUserPostsDirectoryAdminPasswordPayload(t *te
require.Len(t, passwordConfig["password"], 16)
}
func TestNewWorksmobileUserPatchPayloadNormalizesMalformedKoreanCellPhone(t *testing.T) {
payload := NewWorksmobileUserPatchPayload(WorksmobileUserPayload{
DomainID: 1001,
Email: "phone-canonical@samaneng.com",
CellPhone: "+82+821062836786",
UserName: WorksmobileUserName{LastName: "Phone Canonical User"},
})
require.Equal(t, "+821062836786", payload.CellPhone)
}
func TestNewWorksmobileSCIMUserPayloadNormalizesMalformedKoreanCellPhone(t *testing.T) {
payload := NewWorksmobileSCIMUserPayload(WorksmobileUserPayload{
Email: "phone-canonical@samaneng.com",
CellPhone: "+82+821062836786",
UserName: WorksmobileUserName{LastName: "Phone Canonical User"},
})
require.Len(t, payload.PhoneNumbers, 1)
require.Equal(t, "+821062836786", payload.PhoneNumbers[0].Value)
}
func TestWorksmobileHTTPClientUpsertUserPatchesOnCreateConflictWithoutPasswordOrPrivateEmail(t *testing.T) {
transport := &captureRoundTripper{
responses: []captureResponse{
@@ -155,6 +177,7 @@ func TestWorksmobileHTTPClientResetUserPasswordPatchesPasswordConfig(t *testing.
passwordConfig := payload["passwordConfig"].(map[string]any)
require.Equal(t, "ADMIN", passwordConfig["passwordCreationType"])
require.Equal(t, "Aa1!Aa1!Aa1!Aa1!", passwordConfig["password"])
require.Equal(t, true, passwordConfig["changePasswordAtNextLogin"])
}
func TestWorksmobileHTTPClientCreateUserRequiresDirectoryToken(t *testing.T) {
@@ -225,6 +248,84 @@ func TestWorksmobileHTTPClientRequestsJWTBearerAccessToken(t *testing.T) {
require.Equal(t, float64(1710003600), payload["exp"])
}
func TestWorksmobileHTTPClientAppliesRateLimitBeforeDirectoryAPICalls(t *testing.T) {
transport := &captureRoundTripper{
statusCode: http.StatusCreated,
body: `{}`,
}
limiter := &captureWorksmobileRateLimiter{}
client := &WorksmobileHTTPClient{
BaseURL: "https://works.example.test",
DirectoryToken: "directory-token-1",
HTTPClient: &http.Client{Transport: transport},
RateLimiter: limiter,
}
err := client.CreateUser(context.Background(), WorksmobileUserPayload{
Email: "tester@samaneng.com",
PasswordConfig: WorksmobilePasswordConfig{PasswordCreationType: "ADMIN", Password: "Aa1!Aa1!Aa1!Aa1!"},
})
require.NoError(t, err)
require.Equal(t, []string{"POST /v1.0/users"}, limiter.keys)
require.Len(t, transport.requests, 1)
}
func TestWorksmobileHTTPClientAppliesRateLimitBeforeOAuthTokenCalls(t *testing.T) {
privateKey := testRSAPrivateKeyPEM(t)
transport := &captureRoundTripper{
statusCode: http.StatusOK,
body: `{"access_token":"directory-token-from-jwt","token_type":"Bearer","expires_in":3600}`,
}
limiter := &captureWorksmobileRateLimiter{}
client := &WorksmobileHTTPClient{
HTTPClient: &http.Client{Transport: transport},
RateLimiter: limiter,
now: func() time.Time { return time.Unix(1710000000, 0) },
OAuthConfig: WorksmobileOAuthConfig{
ClientID: "client-id-1",
ClientSecret: "client-secret-1",
ServiceAccount: "service-account-1",
PrivateKey: privateKey,
Scope: "directory",
TokenURL: "https://auth.example.test/oauth2/v2.0/token",
},
}
_, _, err := client.requestDirectoryAccessToken(context.Background(), time.Unix(1710000000, 0))
require.NoError(t, err)
require.Equal(t, []string{"POST /oauth2/v2.0/token"}, limiter.keys)
require.Len(t, transport.requests, 1)
}
func TestWorksmobileHTTPClientRateLimitKeyNormalizesResourceIDsAndDropsQuery(t *testing.T) {
parsedURL, err := url.Parse("https://works.example.test/v1.0/users/user%40example.com/alias-emails/alias%40example.com?domainId=1")
require.NoError(t, err)
require.Equal(
t,
"POST /v1.0/users/{id}/alias-emails/{id}",
worksmobileRateLimitKey(http.MethodPost, parsedURL),
)
parsedURL, err = url.Parse("https://works.example.test/scim/v2/Users/works-user-1")
require.NoError(t, err)
require.Equal(t, "PATCH /scim/v2/Users/{id}", worksmobileRateLimitKey(http.MethodPatch, parsedURL))
}
func TestNewWorksmobileHTTPClientDoesNotInstallRateLimiterByDefault(t *testing.T) {
client := NewWorksmobileHTTPClientWithAuth("directory-token", "scim-token", WorksmobileOAuthConfig{})
require.Nil(t, client.RateLimiter)
}
func TestNewWorksmobileAPIRateLimiterCreatesLimiterForWorkerUse(t *testing.T) {
limiter := NewWorksmobileAPIRateLimiter(240, time.Minute)
require.NotNil(t, limiter)
}
func TestWorksmobileHTTPClientRequiresConfiguredAPIBaseURL(t *testing.T) {
client := &WorksmobileHTTPClient{
DirectoryToken: "directory-token-1",
@@ -608,6 +709,18 @@ func TestWorksmobileRelayWorkerProcessesUserSuspendAndMarksProcessed(t *testing.
require.Equal(t, []string{"tester@samaneng.com"}, client.suspendedUsers)
}
func TestWorksmobileRelayWorkerProcessOnceRecoversPanic(t *testing.T) {
repo := &fakeWorksmobileOutboxRepo{listReadyPanic: "list ready crashed"}
client := &fakeWorksmobileDirectoryClient{}
worker := NewWorksmobileRelayWorker(repo, client)
err := worker.ProcessOnce(context.Background())
require.Error(t, err)
require.Contains(t, err.Error(), "worksmobile relay panic")
require.Contains(t, err.Error(), "list ready crashed")
}
func TestWorksmobileRelayWorkerProcessesActiveUserUpsertAndReactivates(t *testing.T) {
repo := &fakeWorksmobileOutboxRepo{
ready: []domain.WorksmobileOutbox{
@@ -736,6 +849,65 @@ func TestWorksmobileRelayWorkerSkipsDispatchWhenJobClaimFails(t *testing.T) {
require.Empty(t, client.createdOrgUnits)
}
func TestWorksmobileRelayWorkerSkipsProcessingWhenLeaderLockIsNotHeld(t *testing.T) {
repo := &fakeWorksmobileOutboxRepo{
ready: []domain.WorksmobileOutbox{
{
ID: "job-1",
ResourceType: domain.WorksmobileResourceUser,
ResourceID: "user-1",
Action: domain.WorksmobileActionUpsert,
Status: domain.WorksmobileOutboxStatusPending,
Payload: worksmobileUserOutboxPayload("root-1", WorksmobileUserPayload{
Email: "tester@samaneng.com",
UserExternalKey: "user-1",
}),
},
},
}
client := &fakeWorksmobileDirectoryClient{}
worker := NewWorksmobileRelayWorker(repo, client)
worker.SetLeaderLock(&fakeWorksmobileRelayLeaderLock{held: false})
err := worker.ProcessOnce(context.Background())
require.NoError(t, err)
require.Zero(t, repo.listReadyCalls)
require.Empty(t, repo.processingIDs)
require.Empty(t, repo.processedIDs)
require.Empty(t, client.createdUsers)
}
func TestWorksmobileRelayWorkerProcessesWhenLeaderLockIsHeld(t *testing.T) {
repo := &fakeWorksmobileOutboxRepo{
ready: []domain.WorksmobileOutbox{
{
ID: "job-1",
ResourceType: domain.WorksmobileResourceUser,
ResourceID: "user-1",
Action: domain.WorksmobileActionUpsert,
Status: domain.WorksmobileOutboxStatusPending,
Payload: worksmobileUserOutboxPayload("root-1", WorksmobileUserPayload{
Email: "tester@samaneng.com",
UserExternalKey: "user-1",
}),
},
},
}
client := &fakeWorksmobileDirectoryClient{}
lock := &fakeWorksmobileRelayLeaderLock{held: true}
worker := NewWorksmobileRelayWorker(repo, client)
worker.SetLeaderLock(lock)
err := worker.ProcessOnce(context.Background())
require.NoError(t, err)
require.Equal(t, 1, lock.ensureCalls)
require.Equal(t, 1, repo.listReadyCalls)
require.Equal(t, []string{"job-1"}, repo.processedIDs)
require.Equal(t, "tester@samaneng.com", client.createdUsers[0].Email)
}
func TestRedactWorksmobileOutboxPayloadsRemovesInitialPasswordFromOverview(t *testing.T) {
jobs := []domain.WorksmobileOutbox{
{
@@ -1179,6 +1351,8 @@ type fakeWorksmobileOutboxRepo struct {
payloadUpdates []domain.JSONMap
deletedPendingTenantRootID string
deletedPendingCount int
listReadyCalls int
listReadyPanic any
markProcessingClaims map[string]bool
processingIDs []string
processedIDs []string
@@ -1224,6 +1398,10 @@ func (f *fakeWorksmobileOutboxRepo) DeletePendingByTenantRoot(ctx context.Contex
}
func (f *fakeWorksmobileOutboxRepo) ListReady(ctx context.Context, limit int) ([]domain.WorksmobileOutbox, error) {
f.listReadyCalls++
if f.listReadyPanic != nil {
panic(f.listReadyPanic)
}
return f.ready, nil
}
@@ -1282,6 +1460,25 @@ type captureResponse struct {
body string
}
type captureWorksmobileRateLimiter struct {
keys []string
}
func (l *captureWorksmobileRateLimiter) Wait(ctx context.Context, key string) error {
l.keys = append(l.keys, key)
return ctx.Err()
}
type fakeWorksmobileRelayLeaderLock struct {
held bool
ensureCalls int
}
func (l *fakeWorksmobileRelayLeaderLock) EnsureLeadership(ctx context.Context) (bool, error) {
l.ensureCalls++
return l.held, ctx.Err()
}
func (t *captureRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
t.request = req
t.requests = append(t.requests, req)