Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit81adc67

Browse files
committed
chore: add OAuth2 device flow test scripts
Change-Id: Ic232851727e683ab3d8b7ce970c505588da2f827Signed-off-by: Thomas Kosiewski <tk@coder.com>
1 parentab9db37 commit81adc67

File tree

46 files changed

+1369
-807
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1369
-807
lines changed

‎.claude/scripts/format.sh‎

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,30 +101,36 @@ fi
101101
# Get the file extension to determine the appropriate formatter
102102
file_ext="${file_path##*.}"
103103

104+
# Helper function to run formatter and handle errors
105+
run_formatter() {
106+
local target="$1"
107+
local file_type="$2"
108+
109+
if! make FILE="$file_path""$target";then
110+
echo"Error: Failed to format$file_type file:$file_path">&2
111+
exit 2
112+
fi
113+
echo"✓ Formatted$file_type file:$file_path"
114+
}
104115
# Change to the project root directory (where the Makefile is located)
105116
cd"$(dirname"$0")/../.."
106117

107118
# Call the appropriate Makefile target based on file extension
108119
case"$file_ext"in
109120
go)
110-
make fmt/go FILE="$file_path"
111-
echo"✓ Formatted Go file:$file_path"
121+
run_formatter"fmt/go""Go"
112122
;;
113123
js | jsx | ts | tsx)
114-
make fmt/ts FILE="$file_path"
115-
echo"✓ Formatted TypeScript/JavaScript file:$file_path"
124+
run_formatter"fmt/ts""TypeScript/JavaScript"
116125
;;
117126
tf | tfvars)
118-
make fmt/terraform FILE="$file_path"
119-
echo"✓ Formatted Terraform file:$file_path"
127+
run_formatter"fmt/terraform""Terraform"
120128
;;
121129
sh)
122-
make fmt/shfmt FILE="$file_path"
123-
echo"✓ Formatted shell script:$file_path"
130+
run_formatter"fmt/shfmt""shell script"
124131
;;
125132
md)
126-
make fmt/markdown FILE="$file_path"
127-
echo"✓ Formatted Markdown file:$file_path"
133+
run_formatter"fmt/markdown""Markdown"
128134
;;
129135
*)
130136
echo"No formatter available for file extension:$file_ext"

‎coderd/apidoc/docs.go‎

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/apidoc/swagger.json‎

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/audit/diff.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type Auditable interface {
2424
database.NotificationsSettings|
2525
database.OAuth2ProviderApp|
2626
database.OAuth2ProviderAppSecret|
27+
database.OAuth2ProviderDeviceCode|
2728
database.PrebuildsSettings|
2829
database.CustomRole|
2930
database.AuditableOrganizationMember|

‎coderd/audit/request.go‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ func ResourceTarget[T Auditable](tgt T) string {
117117
returntyped.Name
118118
case database.OAuth2ProviderAppSecret:
119119
returntyped.DisplaySecret
120+
case database.OAuth2ProviderDeviceCode:
121+
returntyped.UserCode
120122
case database.CustomRole:
121123
returntyped.Name
122124
case database.AuditableOrganizationMember:
@@ -179,6 +181,8 @@ func ResourceID[T Auditable](tgt T) uuid.UUID {
179181
returntyped.ID
180182
case database.OAuth2ProviderAppSecret:
181183
returntyped.ID
184+
case database.OAuth2ProviderDeviceCode:
185+
returntyped.ID
182186
case database.CustomRole:
183187
returntyped.ID
184188
case database.AuditableOrganizationMember:
@@ -232,6 +236,8 @@ func ResourceType[T Auditable](tgt T) database.ResourceType {
232236
returndatabase.ResourceTypeOauth2ProviderApp
233237
case database.OAuth2ProviderAppSecret:
234238
returndatabase.ResourceTypeOauth2ProviderAppSecret
239+
case database.OAuth2ProviderDeviceCode:
240+
returndatabase.ResourceTypeOauth2ProviderDeviceCode
235241
case database.CustomRole:
236242
returndatabase.ResourceTypeCustomRole
237243
case database.AuditableOrganizationMember:
@@ -288,6 +294,8 @@ func ResourceRequiresOrgID[T Auditable]() bool {
288294
returnfalse
289295
case database.OAuth2ProviderAppSecret:
290296
returnfalse
297+
case database.OAuth2ProviderDeviceCode:
298+
returnfalse
291299
case database.CustomRole:
292300
returntrue
293301
case database.AuditableOrganizationMember:

‎coderd/coderd.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,7 @@ func New(options *Options) *API {
10051005
r.Route("/device",func(r chi.Router) {
10061006
r.Post("/",api.postOAuth2DeviceAuthorization())// RFC 8628 compliant endpoint
10071007
r.Route("/verify",func(r chi.Router) {
1008-
r.Use(apiKeyMiddleware)
1008+
r.Use(apiKeyMiddlewareRedirect)
10091009
r.Get("/",api.getOAuth2DeviceVerification())
10101010
r.Post("/",api.postOAuth2DeviceVerification())
10111011
})

‎coderd/database/check_constraint.go‎

Lines changed: 11 additions & 9 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/dbauthz/dbauthz.go‎

Lines changed: 76 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,35 @@ var (
436436
rbac.ResourceProvisionerJobs.Type: {policy.ActionRead,policy.ActionUpdate,policy.ActionCreate},
437437
rbac.ResourceOauth2App.Type: {policy.ActionCreate,policy.ActionRead,policy.ActionUpdate,policy.ActionDelete},
438438
rbac.ResourceOauth2AppSecret.Type: {policy.ActionCreate,policy.ActionRead,policy.ActionUpdate,policy.ActionDelete},
439+
rbac.ResourceOauth2AppCodeToken.Type: {policy.ActionCreate,policy.ActionRead,policy.ActionUpdate,policy.ActionDelete},
440+
}),
441+
Org:map[string][]rbac.Permission{},
442+
User: []rbac.Permission{},
443+
},
444+
}),
445+
Scope:rbac.ScopeAll,
446+
}.WithCachedASTValue()
447+
448+
subjectSystemOAuth2= rbac.Subject{
449+
Type:rbac.SubjectTypeSystemRestricted,
450+
FriendlyName:"System OAuth2",
451+
ID:uuid.Nil.String(),
452+
Roles:rbac.Roles([]rbac.Role{
453+
{
454+
Identifier: rbac.RoleIdentifier{Name:"system-oauth2"},
455+
DisplayName:"System OAuth2",
456+
Site:rbac.Permissions(map[string][]policy.Action{
457+
// OAuth2 resources - full CRUD permissions
458+
rbac.ResourceOauth2App.Type:rbac.ResourceOauth2App.AvailableActions(),
459+
rbac.ResourceOauth2AppSecret.Type:rbac.ResourceOauth2AppSecret.AvailableActions(),
460+
rbac.ResourceOauth2AppCodeToken.Type:rbac.ResourceOauth2AppCodeToken.AvailableActions(),
461+
462+
// API key permissions needed for OAuth2 token revocation
463+
rbac.ResourceApiKey.Type: {policy.ActionRead,policy.ActionDelete},
464+
465+
// Minimal read permissions that might be needed for OAuth2 operations
466+
rbac.ResourceUser.Type: {policy.ActionRead},
467+
rbac.ResourceOrganization.Type: {policy.ActionRead},
439468
}),
440469
User: []rbac.Permission{},
441470
ByOrgID:map[string]rbac.OrgPermissions{},
@@ -641,6 +670,12 @@ func AsSystemRestricted(ctx context.Context) context.Context {
641670
returnAs(ctx,subjectSystemRestricted)
642671
}
643672

673+
// AsSystemOAuth2 returns a context with an actor that has permissions
674+
// required for OAuth2 provider operations (token revocation, device codes, registration).
675+
funcAsSystemOAuth2(ctx context.Context) context.Context {
676+
returnAs(ctx,subjectSystemOAuth2)
677+
}
678+
644679
// AsSystemReadProvisionerDaemons returns a context with an actor that has permissions
645680
// to read provisioner daemons.
646681
funcAsSystemReadProvisionerDaemons(ctx context.Context) context.Context {
@@ -1434,6 +1469,14 @@ func (q *querier) CleanTailnetTunnels(ctx context.Context) error {
14341469
returnq.db.CleanTailnetTunnels(ctx)
14351470
}
14361471

1472+
func (q*querier)ConsumeOAuth2ProviderAppCodeByPrefix(ctx context.Context,secretPrefix []byte) (database.OAuth2ProviderAppCode,error) {
1473+
returnupdateWithReturn(q.log,q.auth,q.db.GetOAuth2ProviderAppCodeByPrefix,q.db.ConsumeOAuth2ProviderAppCodeByPrefix)(ctx,secretPrefix)
1474+
}
1475+
1476+
func (q*querier)ConsumeOAuth2ProviderDeviceCodeByPrefix(ctx context.Context,deviceCodePrefixstring) (database.OAuth2ProviderDeviceCode,error) {
1477+
returnupdateWithReturn(q.log,q.auth,q.db.GetOAuth2ProviderDeviceCodeByPrefix,q.db.ConsumeOAuth2ProviderDeviceCodeByPrefix)(ctx,deviceCodePrefix)
1478+
}
1479+
14371480
func (q*querier)CountAuditLogs(ctx context.Context,arg database.CountAuditLogsParams) (int64,error) {
14381481
// Shortcut if the user is an owner. The SQL filter is noticeable,
14391482
// and this is an easy win for owners. Which is the common case.
@@ -1577,7 +1620,7 @@ func (q *querier) DeleteExpiredOAuth2ProviderDeviceCodes(ctx context.Context) er
15771620
func (q*querier)DeleteExternalAuthLink(ctx context.Context,arg database.DeleteExternalAuthLinkParams)error {
15781621
returnfetchAndExec(q.log,q.auth,policy.ActionUpdatePersonal,func(ctx context.Context,arg database.DeleteExternalAuthLinkParams) (database.ExternalAuthLink,error) {
15791622
//nolint:gosimple
1580-
returnq.db.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{UserID:arg.UserID,ProviderID:arg.ProviderID})
1623+
returnq.db.GetExternalAuthLink(ctx,database.GetExternalAuthLinkParams(arg))
15811624
},q.db.DeleteExternalAuthLink)(ctx,arg)
15821625
}
15831626

@@ -1656,27 +1699,30 @@ func (q *querier) DeleteOAuth2ProviderAppTokensByAppAndUserID(ctx context.Contex
16561699
returnq.db.DeleteOAuth2ProviderAppTokensByAppAndUserID(ctx,arg)
16571700
}
16581701

1659-
func (q*querier)DeleteOldAuditLogConnectionEvents(ctx context.Context,threshold database.DeleteOldAuditLogConnectionEventsParams)error {
1660-
// `ResourceSystem` is deprecated, but it doesn't make sense to add
1661-
// `policy.ActionDelete` to `ResourceAuditLog`, since this is the one and
1662-
// only time we'll be deleting from the audit log.
1663-
iferr:=q.authorizeContext(ctx,policy.ActionDelete,rbac.ResourceSystem);err!=nil {
1664-
returnerr
1665-
}
1666-
returnq.db.DeleteOldAuditLogConnectionEvents(ctx,threshold)
1667-
}
1668-
16691702
func (q*querier)DeleteOAuth2ProviderDeviceCodeByID(ctx context.Context,id uuid.UUID)error {
16701703
// Fetch the device code first to check authorization
16711704
deviceCode,err:=q.db.GetOAuth2ProviderDeviceCodeByID(ctx,id)
16721705
iferr!=nil {
1673-
returnerr
1706+
returnxerrors.Errorf("get oauth2 provider device code: %w",err)
16741707
}
16751708
iferr:=q.authorizeContext(ctx,policy.ActionDelete,deviceCode);err!=nil {
1676-
returnerr
1709+
returnxerrors.Errorf("authorize oauth2 provider device code deletion: %w",err)
1710+
}
1711+
1712+
iferr:=q.db.DeleteOAuth2ProviderDeviceCodeByID(ctx,id);err!=nil {
1713+
returnxerrors.Errorf("delete oauth2 provider device code: %w",err)
16771714
}
1715+
returnnil
1716+
}
16781717

1679-
returnq.db.DeleteOAuth2ProviderDeviceCodeByID(ctx,id)
1718+
func (q*querier)DeleteOldAuditLogConnectionEvents(ctx context.Context,threshold database.DeleteOldAuditLogConnectionEventsParams)error {
1719+
// `ResourceSystem` is deprecated, but it doesn't make sense to add
1720+
// `policy.ActionDelete` to `ResourceAuditLog`, since this is the one and
1721+
// only time we'll be deleting from the audit log.
1722+
iferr:=q.authorizeContext(ctx,policy.ActionDelete,rbac.ResourceSystem);err!=nil {
1723+
returnerr
1724+
}
1725+
returnq.db.DeleteOldAuditLogConnectionEvents(ctx,threshold)
16801726
}
16811727

16821728
func (q*querier)DeleteOldNotificationMessages(ctx context.Context)error {
@@ -1708,7 +1754,7 @@ func (q *querier) DeleteOldWorkspaceAgentStats(ctx context.Context) error {
17081754
}
17091755

17101756
func (q*querier)DeleteOrganizationMember(ctx context.Context,arg database.DeleteOrganizationMemberParams)error {
1711-
returndeleteQ[database.OrganizationMember](q.log,q.auth,func(ctx context.Context,arg database.DeleteOrganizationMemberParams) (database.OrganizationMember,error) {
1757+
returndeleteQ(q.log,q.auth,func(ctx context.Context,arg database.DeleteOrganizationMemberParams) (database.OrganizationMember,error) {
17121758
member,err:=database.ExpectOne(q.OrganizationMembers(ctx, database.OrganizationMembersParams{
17131759
OrganizationID:arg.OrganizationID,
17141760
UserID:arg.UserID,
@@ -2371,7 +2417,7 @@ func (q *querier) GetLicenseByID(ctx context.Context, id int32) (database.Licens
23712417
}
23722418

23732419
func (q*querier)GetLicenses(ctx context.Context) ([]database.License,error) {
2374-
fetch:=func(ctx context.Context,_interface{}) ([]database.License,error) {
2420+
fetch:=func(ctx context.Context,_any) ([]database.License,error) {
23752421
returnq.db.GetLicenses(ctx)
23762422
}
23772423
returnfetchWithPostFilter(q.auth,policy.ActionRead,fetch)(ctx,nil)
@@ -2527,8 +2573,8 @@ func (q *querier) GetOAuth2ProviderDeviceCodeByUserCode(ctx context.Context, use
25272573
}
25282574

25292575
func (q*querier)GetOAuth2ProviderDeviceCodesByClientID(ctx context.Context,clientID uuid.UUID) ([]database.OAuth2ProviderDeviceCode,error) {
2530-
// This requires access to readtheOAuth2 app
2531-
iferr:=q.authorizeContext(ctx,policy.ActionRead,rbac.ResourceOauth2App);err!=nil {
2576+
// This requires access to read OAuth2 app code tokens
2577+
iferr:=q.authorizeContext(ctx,policy.ActionRead,rbac.ResourceOauth2AppCodeToken);err!=nil {
25322578
return []database.OAuth2ProviderDeviceCode{},err
25332579
}
25342580
returnq.db.GetOAuth2ProviderDeviceCodesByClientID(ctx,clientID)
@@ -2585,7 +2631,7 @@ func (q *querier) GetOrganizationResourceCountByID(ctx context.Context, organiza
25852631
}
25862632

25872633
func (q*querier)GetOrganizations(ctx context.Context,args database.GetOrganizationsParams) ([]database.Organization,error) {
2588-
fetch:=func(ctx context.Context,_interface{}) ([]database.Organization,error) {
2634+
fetch:=func(ctx context.Context,_any) ([]database.Organization,error) {
25892635
returnq.db.GetOrganizations(ctx,args)
25902636
}
25912637
returnfetchWithPostFilter(q.auth,policy.ActionRead,fetch)(ctx,nil)
@@ -2713,7 +2759,7 @@ func (q *querier) GetPreviousTemplateVersion(ctx context.Context, arg database.G
27132759
}
27142760

27152761
func (q*querier)GetProvisionerDaemons(ctx context.Context) ([]database.ProvisionerDaemon,error) {
2716-
fetch:=func(ctx context.Context,_interface{}) ([]database.ProvisionerDaemon,error) {
2762+
fetch:=func(ctx context.Context,_any) ([]database.ProvisionerDaemon,error) {
27172763
returnq.db.GetProvisionerDaemons(ctx)
27182764
}
27192765
returnfetchWithPostFilter(q.auth,policy.ActionRead,fetch)(ctx,nil)
@@ -3741,7 +3787,7 @@ func (q *querier) GetWorkspaceModulesCreatedAfter(ctx context.Context, createdAt
37413787
}
37423788

37433789
func (q*querier)GetWorkspaceProxies(ctx context.Context) ([]database.WorkspaceProxy,error) {
3744-
returnfetchWithPostFilter(q.auth,policy.ActionRead,func(ctx context.Context,_interface{}) ([]database.WorkspaceProxy,error) {
3790+
returnfetchWithPostFilter(q.auth,policy.ActionRead,func(ctx context.Context,_any) ([]database.WorkspaceProxy,error) {
37453791
returnq.db.GetWorkspaceProxies(ctx)
37463792
})(ctx,nil)
37473793
}
@@ -4071,8 +4117,8 @@ func (q *querier) InsertOAuth2ProviderAppToken(ctx context.Context, arg database
40714117
}
40724118

40734119
func (q*querier)InsertOAuth2ProviderDeviceCode(ctx context.Context,arg database.InsertOAuth2ProviderDeviceCodeParams) (database.OAuth2ProviderDeviceCode,error) {
4074-
// Creating device codes requires OAuth2 app access
4075-
iferr:=q.authorizeContext(ctx,policy.ActionCreate,rbac.ResourceOauth2App);err!=nil {
4120+
// Creating device codes requires OAuth2 appcode token creationaccess
4121+
iferr:=q.authorizeContext(ctx,policy.ActionCreate,rbac.ResourceOauth2AppCodeToken);err!=nil {
40764122
return database.OAuth2ProviderDeviceCode{},err
40774123
}
40784124
returnq.db.InsertOAuth2ProviderDeviceCode(ctx,arg)
@@ -4386,10 +4432,11 @@ func (q *querier) InsertWorkspaceBuild(ctx context.Context, arg database.InsertW
43864432
returnxerrors.Errorf("get workspace by id: %w",err)
43874433
}
43884434

4389-
varaction policy.Action=policy.ActionWorkspaceStart
4390-
ifarg.Transition==database.WorkspaceTransitionDelete {
4435+
action:=policy.ActionWorkspaceStart
4436+
switcharg.Transition {
4437+
casedatabase.WorkspaceTransitionDelete:
43914438
action=policy.ActionDelete
4392-
}elseifarg.Transition==database.WorkspaceTransitionStop {
4439+
casedatabase.WorkspaceTransitionStop:
43934440
action=policy.ActionWorkspaceStop
43944441
}
43954442

@@ -4813,13 +4860,10 @@ func (q *querier) UpdateOAuth2ProviderAppSecretByID(ctx context.Context, arg dat
48134860
}
48144861

48154862
func (q*querier)UpdateOAuth2ProviderDeviceCodeAuthorization(ctx context.Context,arg database.UpdateOAuth2ProviderDeviceCodeAuthorizationParams) (database.OAuth2ProviderDeviceCode,error) {
4816-
// Verify the user is authenticated for device code authorization
4817-
_,ok:=ActorFromContext(ctx)
4818-
if!ok {
4819-
return database.OAuth2ProviderDeviceCode{},ErrNoActor
4863+
fetch:=func(ctx context.Context,arg database.UpdateOAuth2ProviderDeviceCodeAuthorizationParams) (database.OAuth2ProviderDeviceCode,error) {
4864+
returnq.db.GetOAuth2ProviderDeviceCodeByID(ctx,arg.ID)
48204865
}
4821-
4822-
returnq.db.UpdateOAuth2ProviderDeviceCodeAuthorization(ctx,arg)
4866+
returnupdateWithReturn(q.log,q.auth,fetch,q.db.UpdateOAuth2ProviderDeviceCodeAuthorization)(ctx,arg)
48234867
}
48244868

48254869
func (q*querier)UpdateOrganization(ctx context.Context,arg database.UpdateOrganizationParams) (database.Organization,error) {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp