3.5 KiB
3.5 KiB
id, title, status, wave, depends_on, plan, spec
| id | title | status | wave | depends_on | plan | spec |
|---|---|---|---|---|---|---|
| 01-service-authorization | Service-layer workspace authorization | pending | 1 | plan.md | ../../specs/tasks/requirements/workflow-sync-workspace-authz.md |
Task 01: Service-layer workspace authorization
Add the workspaceAuthorizer boundary to workflowsync.Service and wire it at app boot, following
the exact pattern already used by internal/github, internal/jira, internal/linear,
internal/slack, internal/azuredevops, and internal/automation.
Changes
apps/backend/internal/workflowsync/service.go:- Add
workspaceAuthorizer func(context.Context, string) errorfield toService. - Add
SetWorkspaceAuthorizer(nil-safe ons) andauthorizeWorkspaceAccess(nil-safe onsand the field) methods — copy the shape frominternal/github/service.go:169-181. - Call
s.authorizeWorkspaceAccess(ctx, workspaceID)first inGetConfigForWorkspace,SetConfigForWorkspace,DeleteConfigForWorkspace,SyncWorkspace, returning the error immediately (before touchings.storeors.applier).
- Add
apps/backend/internal/backendapp/services.go: ininitWorkflowSyncService, afterworkflowsync.Providesucceeds, callsvc.SetWorkspaceAuthorizer(taskSvc.AuthorizeWorkspaceAccess)before returningsvc.
Acceptance
- A caller whose identity does not own the target workspace gets
repoerrors.ErrWorkspaceNotFoundfrom all fourServicemethods, and no store read/write or applier call happens for that call. - A caller with no identity in context, or a synthetic identity, or a
Servicewith no authorizer wired, behaves exactly as before this change (fully unscoped, no denial). go vet/ build clean; no new lint findings under the changed-file thresholds inapps/backend/.golangci.yml.
Verification
cd apps/backend && go test ./internal/workflowsync/... -run 'Authoriz|SyncWorkspace|ConfigForWorkspace' -v
cd apps/backend && go build ./...
cd apps/backend && golangci-lint run ./internal/workflowsync/... ./internal/backendapp/... --new-from-rev=main --timeout=5m
Results
- Status: done.
go test ./internal/workflowsync/... -run 'Authoriz|DeniesForeign|SucceedWhenNoAuthorizer|SucceedWhenAuthorizerAllows' -v: 6/6 pass (TestGetConfigForWorkspace_DeniesForeignWorkspace,TestSetConfigForWorkspace_DeniesForeignWorkspaceAndLeavesConfigUnchanged,TestDeleteConfigForWorkspace_DeniesForeignWorkspaceAndLeavesConfigInPlace,TestSyncWorkspace_DeniesForeignWorkspaceAndNeverApplies,TestServiceMethods_SucceedWhenNoAuthorizerWired,TestServiceMethods_SucceedWhenAuthorizerAllows).go build ./...: clean.go test -race ./internal/workflowsync/... ./internal/backendapp/...: bothok.golangci-lint run ./internal/workflowsync/... ./internal/backendapp/... --new-from-rev=main --timeout=5m: 0 issues.- Codex review finding (blocker, fixed): the initial service-layer tests only ever installed a
hand-written fake authorizer, so a regression removing the real
svc.SetWorkspaceAuthorizer(taskSvc.AuthorizeWorkspaceAccess)wiring line ininitWorkflowSyncServicewould leave every test green. Addedapps/backend/internal/backendapp/workflowsync_wiring_test.go(TestInitWorkflowSyncService_WiresRealWorkspaceAuthorization), which callsinitWorkflowSyncServiceitself with a realtaskservice.Servicebacked by SQLite. Verified by temporarily commenting out the wiring line: the new test failed for the expected reason; restoring the line made it pass again (confirmed viago build/full suite afterward).