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

Commit29d804e

Browse files
authored
feat: add API key scopes and application_connect scope (#4067)
1 parentadad347 commit29d804e

File tree

42 files changed

+476
-88
lines changed

Some content is hidden

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

42 files changed

+476
-88
lines changed

‎cli/resetpassword.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/coder/coder/cli/cliflag"
1111
"github.com/coder/coder/cli/cliui"
1212
"github.com/coder/coder/coderd/database"
13+
"github.com/coder/coder/coderd/database/migrations"
1314
"github.com/coder/coder/coderd/userpassword"
1415
)
1516

@@ -35,7 +36,7 @@ func resetPassword() *cobra.Command {
3536
returnxerrors.Errorf("ping postgres: %w",err)
3637
}
3738

38-
err=database.EnsureClean(sqlDB)
39+
err=migrations.EnsureClean(sqlDB)
3940
iferr!=nil {
4041
returnxerrors.Errorf("database needs migration: %w",err)
4142
}

‎cli/server.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import (
5353
"github.com/coder/coder/coderd/autobuild/executor"
5454
"github.com/coder/coder/coderd/database"
5555
"github.com/coder/coder/coderd/database/databasefake"
56+
"github.com/coder/coder/coderd/database/migrations"
5657
"github.com/coder/coder/coderd/devtunnel"
5758
"github.com/coder/coder/coderd/gitsshkey"
5859
"github.com/coder/coder/coderd/prometheusmetrics"
@@ -430,7 +431,7 @@ func Server(newAPI func(*coderd.Options) *coderd.API) *cobra.Command {
430431
iferr!=nil {
431432
returnxerrors.Errorf("ping postgres: %w",err)
432433
}
433-
err=database.MigrateUp(sqlDB)
434+
err=migrations.Up(sqlDB)
434435
iferr!=nil {
435436
returnxerrors.Errorf("migrate up: %w",err)
436437
}

‎coderd/authorize.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ import (
1111
)
1212

1313
funcAuthorizeFilter[O rbac.Objecter](h*HTTPAuthorizer,r*http.Request,action rbac.Action,objects []O) ([]O,error) {
14-
roles:=httpmw.AuthorizationUserRoles(r)
15-
objects,err:=rbac.Filter(r.Context(),h.Authorizer,roles.ID.String(),roles.Roles,action,objects)
14+
roles:=httpmw.UserAuthorization(r)
15+
objects,err:=rbac.Filter(r.Context(),h.Authorizer,roles.ID.String(),roles.Roles,roles.Scope.ToRBAC(),action,objects)
1616
iferr!=nil {
1717
// Log the error as Filter should not be erroring.
1818
h.Logger.Error(r.Context(),"filter failed",
1919
slog.Error(err),
2020
slog.F("user_id",roles.ID),
2121
slog.F("username",roles.Username),
22+
slog.F("scope",roles.Scope),
2223
slog.F("route",r.URL.Path),
2324
slog.F("action",action),
2425
)
@@ -55,8 +56,8 @@ func (api *API) Authorize(r *http.Request, action rbac.Action, object rbac.Objec
5556
//return
5657
//}
5758
func (h*HTTPAuthorizer)Authorize(r*http.Request,action rbac.Action,object rbac.Objecter)bool {
58-
roles:=httpmw.AuthorizationUserRoles(r)
59-
err:=h.Authorizer.ByRoleName(r.Context(),roles.ID.String(),roles.Roles,action,object.RBACObject())
59+
roles:=httpmw.UserAuthorization(r)
60+
err:=h.Authorizer.ByRoleName(r.Context(),roles.ID.String(),roles.Roles,roles.Scope.ToRBAC(),action,object.RBACObject())
6061
iferr!=nil {
6162
// Log the errors for debugging
6263
internalError:=new(rbac.UnauthorizedError)
@@ -70,6 +71,7 @@ func (h *HTTPAuthorizer) Authorize(r *http.Request, action rbac.Action, object r
7071
slog.F("roles",roles.Roles),
7172
slog.F("user_id",roles.ID),
7273
slog.F("username",roles.Username),
74+
slog.F("scope",roles.Scope),
7375
slog.F("route",r.URL.Path),
7476
slog.F("action",action),
7577
slog.F("object",object),

‎coderd/coderdtest/authtest.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
163163
// Some quick reused objects
164164
workspaceRBACObj:=rbac.ResourceWorkspace.InOrg(a.Organization.ID).WithOwner(a.Workspace.OwnerID.String())
165165
workspaceExecObj:=rbac.ResourceWorkspaceExecution.InOrg(a.Organization.ID).WithOwner(a.Workspace.OwnerID.String())
166+
applicationConnectObj:=rbac.ResourceWorkspaceApplicationConnect.InOrg(a.Organization.ID).WithOwner(a.Workspace.OwnerID.String())
167+
166168
// skipRoutes allows skipping routes from being checked.
167169
skipRoutes:=map[string]string{
168170
"POST:/api/v2/users/logout":"Logging out deletes the API Key for other routes",
@@ -408,11 +410,11 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
408410

409411
assertAllHTTPMethods("/%40{user}/{workspace_and_agent}/apps/{workspaceapp}/*",RouteCheck{
410412
AssertAction:rbac.ActionCreate,
411-
AssertObject:workspaceExecObj,
413+
AssertObject:applicationConnectObj,
412414
})
413415
assertAllHTTPMethods("/@{user}/{workspace_and_agent}/apps/{workspaceapp}/*",RouteCheck{
414416
AssertAction:rbac.ActionCreate,
415-
AssertObject:workspaceExecObj,
417+
AssertObject:applicationConnectObj,
416418
})
417419

418420
returnskipRoutes,assertRoute
@@ -518,6 +520,7 @@ func (a *AuthTester) Test(ctx context.Context, assertRoute map[string]RouteCheck
518520
typeauthCallstruct {
519521
SubjectIDstring
520522
Roles []string
523+
Scope rbac.Scope
521524
Action rbac.Action
522525
Object rbac.Object
523526
}
@@ -527,21 +530,25 @@ type recordingAuthorizer struct {
527530
AlwaysReturnerror
528531
}
529532

530-
func (r*recordingAuthorizer)ByRoleName(_ context.Context,subjectIDstring,roleNames []string,action rbac.Action,object rbac.Object)error {
533+
var_ rbac.Authorizer= (*recordingAuthorizer)(nil)
534+
535+
func (r*recordingAuthorizer)ByRoleName(_ context.Context,subjectIDstring,roleNames []string,scope rbac.Scope,action rbac.Action,object rbac.Object)error {
531536
r.Called=&authCall{
532537
SubjectID:subjectID,
533538
Roles:roleNames,
539+
Scope:scope,
534540
Action:action,
535541
Object:object,
536542
}
537543
returnr.AlwaysReturn
538544
}
539545

540-
func (r*recordingAuthorizer)PrepareByRoleName(_ context.Context,subjectIDstring,roles []string,action rbac.Action,_string) (rbac.PreparedAuthorized,error) {
546+
func (r*recordingAuthorizer)PrepareByRoleName(_ context.Context,subjectIDstring,roles []string,scope rbac.Scope,action rbac.Action,_string) (rbac.PreparedAuthorized,error) {
541547
return&fakePreparedAuthorizer{
542548
Original:r,
543549
SubjectID:subjectID,
544550
Roles:roles,
551+
Scope:scope,
545552
Action:action,
546553
},nil
547554
}
@@ -554,9 +561,10 @@ type fakePreparedAuthorizer struct {
554561
Original*recordingAuthorizer
555562
SubjectIDstring
556563
Roles []string
564+
Scope rbac.Scope
557565
Action rbac.Action
558566
}
559567

560568
func (f*fakePreparedAuthorizer)Authorize(ctx context.Context,object rbac.Object)error {
561-
returnf.Original.ByRoleName(ctx,f.SubjectID,f.Roles,f.Action,object)
569+
returnf.Original.ByRoleName(ctx,f.SubjectID,f.Roles,f.Scope,f.Action,object)
562570
}

‎coderd/database/databasefake/databasefake.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,7 @@ func (q *fakeQuerier) InsertAPIKey(_ context.Context, arg database.InsertAPIKeyP
15881588
UpdatedAt:arg.UpdatedAt,
15891589
LastUsed:arg.LastUsed,
15901590
LoginType:arg.LoginType,
1591+
Scope:arg.Scope,
15911592
}
15921593
q.apiKeys=append(q.apiKeys,key)
15931594
returnkey,nil

‎coderd/database/db_test.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ package database_test
44

55
import (
66
"context"
7+
"database/sql"
78
"testing"
89

910
"github.com/google/uuid"
1011
"github.com/stretchr/testify/require"
1112

1213
"github.com/coder/coder/coderd/database"
14+
"github.com/coder/coder/coderd/database/migrations"
15+
"github.com/coder/coder/coderd/database/postgres"
1316
)
1417

1518
funcTestNestedInTx(t*testing.T) {
@@ -20,7 +23,7 @@ func TestNestedInTx(t *testing.T) {
2023

2124
uid:=uuid.New()
2225
sqlDB:=testSQLDB(t)
23-
err:=database.MigrateUp(sqlDB)
26+
err:=migrations.Up(sqlDB)
2427
require.NoError(t,err,"migrations")
2528

2629
db:=database.New(sqlDB)
@@ -48,3 +51,17 @@ func TestNestedInTx(t *testing.T) {
4851
require.NoError(t,err,"user exists")
4952
require.Equal(t,uid,user.ID,"user id expected")
5053
}
54+
55+
functestSQLDB(t testing.TB)*sql.DB {
56+
t.Helper()
57+
58+
connection,closeFn,err:=postgres.Open()
59+
require.NoError(t,err)
60+
t.Cleanup(closeFn)
61+
62+
db,err:=sql.Open("postgres",connection)
63+
require.NoError(t,err)
64+
t.Cleanup(func() {_=db.Close() })
65+
66+
returndb
67+
}

‎coderd/database/dump.sql

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/gen/dump/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"path/filepath"
1010
"runtime"
1111

12-
"github.com/coder/coder/coderd/database"
12+
"github.com/coder/coder/coderd/database/migrations"
1313
"github.com/coder/coder/coderd/database/postgres"
1414
)
1515

@@ -25,7 +25,7 @@ func main() {
2525
panic(err)
2626
}
2727

28-
err=database.MigrateUp(db)
28+
err=migrations.Up(db)
2929
iferr!=nil {
3030
panic(err)
3131
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- Avoid "upgrading" devurl keys to fully fledged API keys.
2+
DELETEFROM api_keysWHERE scope!='all';
3+
4+
ALTERTABLE api_keys DROP COLUMN scope;
5+
6+
DROPTYPE api_key_scope;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CREATETYPEapi_key_scopeAS ENUM (
2+
'all',
3+
'application_connect'
4+
);
5+
6+
ALTERTABLE api_keys ADD COLUMN scope api_key_scopeNOT NULL DEFAULT'all';

‎coderd/database/migrate.gorenamed to‎coderd/database/migrations/migrate.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
packagedatabase
1+
packagemigrations
22

33
import (
44
"context"
@@ -14,12 +14,12 @@ import (
1414
"golang.org/x/xerrors"
1515
)
1616

17-
//go:embedmigrations/*.sql
17+
//go:embed *.sql
1818
varmigrations embed.FS
1919

20-
funcmigrateSetup(db*sql.DB) (source.Driver,*migrate.Migrate,error) {
20+
funcsetup(db*sql.DB) (source.Driver,*migrate.Migrate,error) {
2121
ctx:=context.Background()
22-
sourceDriver,err:=iofs.New(migrations,"migrations")
22+
sourceDriver,err:=iofs.New(migrations,".")
2323
iferr!=nil {
2424
returnnil,nil,xerrors.Errorf("create iofs: %w",err)
2525
}
@@ -45,9 +45,9 @@ func migrateSetup(db *sql.DB) (source.Driver, *migrate.Migrate, error) {
4545
returnsourceDriver,m,nil
4646
}
4747

48-
//MigrateUp runs SQL migrations to ensure the database schema is up-to-date.
49-
funcMigrateUp(db*sql.DB) (retErrerror) {
50-
_,m,err:=migrateSetup(db)
48+
//Up runs SQL migrations to ensure the database schema is up-to-date.
49+
funcUp(db*sql.DB) (retErrerror) {
50+
_,m,err:=setup(db)
5151
iferr!=nil {
5252
returnxerrors.Errorf("migrate setup: %w",err)
5353
}
@@ -76,9 +76,9 @@ func MigrateUp(db *sql.DB) (retErr error) {
7676
returnnil
7777
}
7878

79-
//MigrateDown runs all down SQL migrations.
80-
funcMigrateDown(db*sql.DB)error {
81-
_,m,err:=migrateSetup(db)
79+
//Down runs all down SQL migrations.
80+
funcDown(db*sql.DB)error {
81+
_,m,err:=setup(db)
8282
iferr!=nil {
8383
returnxerrors.Errorf("migrate setup: %w",err)
8484
}
@@ -100,7 +100,7 @@ func MigrateDown(db *sql.DB) error {
100100
// applied, without making any changes to the database. If not, returns a
101101
// non-nil error.
102102
funcEnsureClean(db*sql.DB)error {
103-
sourceDriver,m,err:=migrateSetup(db)
103+
sourceDriver,m,err:=setup(db)
104104
iferr!=nil {
105105
returnxerrors.Errorf("migrate setup: %w",err)
106106
}

‎coderd/database/migrate_test.gorenamed to‎coderd/database/migrations/migrate_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//go:build linux
22

3-
packagedatabase_test
3+
packagemigrations_test
44

55
import (
66
"database/sql"
@@ -12,7 +12,7 @@ import (
1212
"github.com/stretchr/testify/require"
1313
"go.uber.org/goleak"
1414

15-
"github.com/coder/coder/coderd/database"
15+
"github.com/coder/coder/coderd/database/migrations"
1616
"github.com/coder/coder/coderd/database/postgres"
1717
)
1818

@@ -33,7 +33,7 @@ func TestMigrate(t *testing.T) {
3333

3434
db:=testSQLDB(t)
3535

36-
err:=database.MigrateUp(db)
36+
err:=migrations.Up(db)
3737
require.NoError(t,err)
3838
})
3939

@@ -42,10 +42,10 @@ func TestMigrate(t *testing.T) {
4242

4343
db:=testSQLDB(t)
4444

45-
err:=database.MigrateUp(db)
45+
err:=migrations.Up(db)
4646
require.NoError(t,err)
4747

48-
err=database.MigrateUp(db)
48+
err=migrations.Up(db)
4949
require.NoError(t,err)
5050
})
5151

@@ -54,13 +54,13 @@ func TestMigrate(t *testing.T) {
5454

5555
db:=testSQLDB(t)
5656

57-
err:=database.MigrateUp(db)
57+
err:=migrations.Up(db)
5858
require.NoError(t,err)
5959

60-
err=database.MigrateDown(db)
60+
err=migrations.Down(db)
6161
require.NoError(t,err)
6262

63-
err=database.MigrateUp(db)
63+
err=migrations.Up(db)
6464
require.NoError(t,err)
6565
})
6666
}
@@ -120,7 +120,7 @@ func TestCheckLatestVersion(t *testing.T) {
120120
})
121121
}
122122

123-
err:=database.CheckLatestVersion(driver,tc.currentVersion)
123+
err:=migrations.CheckLatestVersion(driver,tc.currentVersion)
124124
varerrMessagestring
125125
iferr!=nil {
126126
errMessage=err.Error()

‎coderd/database/modelmethods.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ import (
44
"github.com/coder/coder/coderd/rbac"
55
)
66

7+
func (sAPIKeyScope)ToRBAC() rbac.Scope {
8+
switchs {
9+
caseAPIKeyScopeAll:
10+
returnrbac.ScopeAll
11+
caseAPIKeyScopeApplicationConnect:
12+
returnrbac.ScopeApplicationConnect
13+
default:
14+
panic("developer error: unknown scope type "+string(s))
15+
}
16+
}
17+
718
func (tTemplate)RBACObject() rbac.Object {
819
returnrbac.ResourceTemplate.InOrg(t.OrganizationID)
920
}
@@ -21,6 +32,10 @@ func (w Workspace) ExecutionRBAC() rbac.Object {
2132
returnrbac.ResourceWorkspaceExecution.InOrg(w.OrganizationID).WithOwner(w.OwnerID.String())
2233
}
2334

35+
func (wWorkspace)ApplicationConnectRBAC() rbac.Object {
36+
returnrbac.ResourceWorkspaceApplicationConnect.InOrg(w.OrganizationID).WithOwner(w.OwnerID.String())
37+
}
38+
2439
func (mOrganizationMember)RBACObject() rbac.Object {
2540
returnrbac.ResourceOrganizationMember.InOrg(m.OrganizationID)
2641
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp