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

Commitb101a6f

Browse files
authored
POST license API endpoint (#3570)
* POST license APISigned-off-by: Spike Curtis <spike@coder.com>* Support interface{} types in generated TypescriptSigned-off-by: Spike Curtis <spike@coder.com>* Disable linting on empty interface anySigned-off-by: Spike Curtis <spike@coder.com>* Code review updatesSigned-off-by: Spike Curtis <spike@coder.com>* Enforce unique licensesSigned-off-by: Spike Curtis <spike@coder.com>* Renames from code reviewSigned-off-by: Spike Curtis <spike@coder.com>* Code review renames and commentsSigned-off-by: Spike Curtis <spike@coder.com>Signed-off-by: Spike Curtis <spike@coder.com>
1 parent85acfdf commitb101a6f

File tree

29 files changed

+666
-50
lines changed

29 files changed

+666
-50
lines changed

‎cli/clitest/clitest.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121
// New creates a CLI instance with a configuration pointed to a
2222
// temporary testing directory.
2323
funcNew(t*testing.T,args...string) (*cobra.Command, config.Root) {
24-
cmd:=cli.Root()
24+
cmd:=cli.Root(cli.AGPL())
2525
dir:=t.TempDir()
2626
root:=config.Root(dir)
2727
cmd.SetArgs(append([]string{"--global-config",dir},args...))

‎cli/root.go

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/coder/coder/cli/cliflag"
2121
"github.com/coder/coder/cli/cliui"
2222
"github.com/coder/coder/cli/config"
23+
"github.com/coder/coder/coderd"
2324
"github.com/coder/coder/codersdk"
2425
)
2526

@@ -58,7 +59,42 @@ func init() {
5859
cobra.AddTemplateFuncs(templateFunctions)
5960
}
6061

61-
funcRoot()*cobra.Command {
62+
funcCore() []*cobra.Command {
63+
return []*cobra.Command{
64+
configSSH(),
65+
create(),
66+
deleteWorkspace(),
67+
dotfiles(),
68+
gitssh(),
69+
list(),
70+
login(),
71+
logout(),
72+
parameters(),
73+
portForward(),
74+
publickey(),
75+
resetPassword(),
76+
schedules(),
77+
show(),
78+
ssh(),
79+
start(),
80+
state(),
81+
stop(),
82+
templates(),
83+
update(),
84+
users(),
85+
versionCmd(),
86+
wireguardPortForward(),
87+
workspaceAgent(),
88+
features(),
89+
}
90+
}
91+
92+
funcAGPL() []*cobra.Command {
93+
all:=append(Core(),Server(coderd.New))
94+
returnall
95+
}
96+
97+
funcRoot(subcommands []*cobra.Command)*cobra.Command {
6298
cmd:=&cobra.Command{
6399
Use:"coder",
64100
SilenceErrors:true,
@@ -109,34 +145,7 @@ func Root() *cobra.Command {
109145
),
110146
}
111147

112-
cmd.AddCommand(
113-
configSSH(),
114-
create(),
115-
deleteWorkspace(),
116-
dotfiles(),
117-
gitssh(),
118-
list(),
119-
login(),
120-
logout(),
121-
parameters(),
122-
portForward(),
123-
publickey(),
124-
resetPassword(),
125-
schedules(),
126-
server(),
127-
show(),
128-
ssh(),
129-
start(),
130-
state(),
131-
stop(),
132-
templates(),
133-
update(),
134-
users(),
135-
versionCmd(),
136-
wireguardPortForward(),
137-
workspaceAgent(),
138-
features(),
139-
)
148+
cmd.AddCommand(subcommands...)
140149

141150
cmd.SetUsageTemplate(usageTemplate())
142151

‎cli/server.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ import (
6868
)
6969

7070
// nolint:gocyclo
71-
funcserver()*cobra.Command {
71+
funcServer(newAPIfunc(*coderd.Options)*coderd.API)*cobra.Command {
7272
var (
7373
accessURLstring
7474
addressstring
@@ -434,7 +434,7 @@ func server() *cobra.Command {
434434
),promAddress,"prometheus")()
435435
}
436436

437-
coderAPI:=coderd.New(options)
437+
coderAPI:=newAPI(options)
438438
defercoderAPI.Close()
439439

440440
client:=codersdk.New(localURL)
@@ -886,16 +886,16 @@ func newProvisionerDaemon(ctx context.Context, coderAPI *coderd.API,
886886
// nolint: revive
887887
funcprintLogo(cmd*cobra.Command,spookybool) {
888888
ifspooky {
889-
_,_=fmt.Fprintf(cmd.OutOrStdout(),`▄████▄ ▒█████ ▓█████▄ ▓█████ ██▀███
889+
_,_=fmt.Fprintf(cmd.OutOrStdout(),`▄████▄ ▒█████ ▓█████▄ ▓█████ ██▀███
890890
▒██▀ ▀█ ▒██▒ ██▒▒██▀ ██▌▓█ ▀ ▓██ ▒ ██▒
891891
▒▓█ ▄ ▒██░ ██▒░██ █▌▒███ ▓██ ░▄█ ▒
892-
▒▓▓▄ ▄██▒▒██ ██░░▓█▄ ▌▒▓█ ▄ ▒██▀▀█▄
892+
▒▓▓▄ ▄██▒▒██ ██░░▓█▄ ▌▒▓█ ▄ ▒██▀▀█▄
893893
▒ ▓███▀ ░░ ████▓▒░░▒████▓ ░▒████▒░██▓ ▒██▒
894894
░ ░▒ ▒ ░░ ▒░▒░▒░ ▒▒▓ ▒ ░░ ▒░ ░░ ▒▓ ░▒▓░
895895
░ ▒ ░ ▒ ▒░ ░ ▒ ▒ ░ ░ ░ ░▒ ░ ▒░
896-
░ ░ ░ ░ ▒ ░ ░ ░ ░ ░░ ░
897-
░ ░ ░ ░ ░ ░ ░ ░
898-
░ ░
896+
░ ░ ░ ░ ▒ ░ ░ ░ ░ ░░ ░
897+
░ ░ ░ ░ ░ ░ ░ ░
898+
░ ░
899899
`)
900900
return
901901
}

‎cmd/coder/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
funcmain() {
1616
rand.Seed(time.Now().UnixMicro())
1717

18-
cmd,err:=cli.Root().ExecuteC()
18+
cmd,err:=cli.Root(cli.AGPL()).ExecuteC()
1919
iferr!=nil {
2020
iferrors.Is(err,cliui.Canceled) {
2121
os.Exit(1)

‎coderd/authorize.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ func AuthorizeFilter[O rbac.Objecter](api *API, r *http.Request, action rbac.Act
2727
returnobjects,nil
2828
}
2929

30+
typeHTTPAuthorizerstruct {
31+
Authorizer rbac.Authorizer
32+
Logger slog.Logger
33+
}
34+
3035
// Authorize will return false if the user is not authorized to do the action.
3136
// This function will log appropriately, but the caller must return an
3237
// error to the api client.
@@ -37,14 +42,26 @@ func AuthorizeFilter[O rbac.Objecter](api *API, r *http.Request, action rbac.Act
3742
//return
3843
//}
3944
func (api*API)Authorize(r*http.Request,action rbac.Action,object rbac.Objecter)bool {
45+
returnapi.httpAuth.Authorize(r,action,object)
46+
}
47+
48+
// Authorize will return false if the user is not authorized to do the action.
49+
// This function will log appropriately, but the caller must return an
50+
// error to the api client.
51+
// Eg:
52+
//if !h.Authorize(...) {
53+
//httpapi.Forbidden(rw)
54+
//return
55+
//}
56+
func (h*HTTPAuthorizer)Authorize(r*http.Request,action rbac.Action,object rbac.Objecter)bool {
4057
roles:=httpmw.AuthorizationUserRoles(r)
41-
err:=api.Authorizer.ByRoleName(r.Context(),roles.ID.String(),roles.Roles,action,object.RBACObject())
58+
err:=h.Authorizer.ByRoleName(r.Context(),roles.ID.String(),roles.Roles,action,object.RBACObject())
4259
iferr!=nil {
4360
// Log the errors for debugging
4461
internalError:=new(rbac.UnauthorizedError)
45-
logger:=api.Logger
62+
logger:=h.Logger
4663
ifxerrors.As(err,internalError) {
47-
logger=api.Logger.With(slog.F("internal",internalError.Internal()))
64+
logger=h.Logger.With(slog.F("internal",internalError.Internal()))
4865
}
4966
// Log information for debugging. This will be very helpful
5067
// in the early days

‎coderd/coderd.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ type Options struct {
6666
Telemetry telemetry.Reporter
6767
TURNServer*turnconn.Server
6868
TracerProvider*sdktrace.TracerProvider
69+
LicenseHandler http.Handler
6970
}
7071

7172
// New constructs a Coder API handler.
@@ -92,6 +93,9 @@ func New(options *Options) *API {
9293
ifoptions.PrometheusRegistry==nil {
9394
options.PrometheusRegistry=prometheus.NewRegistry()
9495
}
96+
ifoptions.LicenseHandler==nil {
97+
options.LicenseHandler=licenses()
98+
}
9599

96100
siteCacheDir:=options.CacheDir
97101
ifsiteCacheDir!="" {
@@ -107,6 +111,10 @@ func New(options *Options) *API {
107111
Options:options,
108112
Handler:r,
109113
siteHandler:site.Handler(site.FS(),binFS),
114+
httpAuth:&HTTPAuthorizer{
115+
Authorizer:options.Authorizer,
116+
Logger:options.Logger,
117+
},
110118
}
111119
api.workspaceAgentCache=wsconncache.New(api.dialWorkspaceAgent,0)
112120
oauthConfigs:=&httpmw.OAuth2Configs{
@@ -395,6 +403,10 @@ func New(options *Options) *API {
395403
r.Use(apiKeyMiddleware)
396404
r.Get("/",entitlements)
397405
})
406+
r.Route("/licenses",func(r chi.Router) {
407+
r.Use(apiKeyMiddleware)
408+
r.Mount("/",options.LicenseHandler)
409+
})
398410
})
399411

400412
r.NotFound(compressHandler(http.HandlerFunc(api.siteHandler.ServeHTTP)).ServeHTTP)
@@ -409,6 +421,7 @@ type API struct {
409421
websocketWaitMutex sync.Mutex
410422
websocketWaitGroup sync.WaitGroup
411423
workspaceAgentCache*wsconncache.Cache
424+
httpAuth*HTTPAuthorizer
412425
}
413426

414427
// Close waits for all WebSocket connections to drain before returning.

‎coderd/coderdtest/coderdtest.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ type Options struct {
7373

7474
// IncludeProvisionerD when true means to start an in-memory provisionerD
7575
IncludeProvisionerDbool
76+
APIBuilderfunc(*coderd.Options)*coderd.API
7677
}
7778

7879
// New constructs a codersdk client connected to an in-memory API instance.
@@ -122,6 +123,9 @@ func newWithCloser(t *testing.T, options *Options) (*codersdk.Client, io.Closer)
122123
close(options.AutobuildStats)
123124
})
124125
}
126+
ifoptions.APIBuilder==nil {
127+
options.APIBuilder=coderd.New
128+
}
125129

126130
// This can be hotswapped for a live database instance.
127131
db:=databasefake.New()
@@ -177,7 +181,7 @@ func newWithCloser(t *testing.T, options *Options) (*codersdk.Client, io.Closer)
177181
})
178182

179183
// We set the handler after server creation for the access URL.
180-
coderAPI:=coderd.New(&coderd.Options{
184+
coderAPI:=options.APIBuilder(&coderd.Options{
181185
AgentConnectionUpdateFrequency:150*time.Millisecond,
182186
// Force a long disconnection timeout to ensure
183187
// agents are not marked as disconnected during slow tests.

‎coderd/database/databasefake/databasefake.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func New() database.Store {
4242
workspaceBuilds:make([]database.WorkspaceBuild,0),
4343
workspaceApps:make([]database.WorkspaceApp,0),
4444
workspaces:make([]database.Workspace,0),
45+
licenses:make([]database.License,0),
4546
},
4647
}
4748
}
@@ -92,8 +93,10 @@ type data struct {
9293
workspaceBuilds []database.WorkspaceBuild
9394
workspaceApps []database.WorkspaceApp
9495
workspaces []database.Workspace
96+
licenses []database.License
9597

96-
deploymentIDstring
98+
deploymentIDstring
99+
lastLicenseIDint32
97100
}
98101

99102
// InTx doesn't rollback data properly for in-memory yet.
@@ -2277,6 +2280,22 @@ func (q *fakeQuerier) GetDeploymentID(_ context.Context) (string, error) {
22772280
returnq.deploymentID,nil
22782281
}
22792282

2283+
func (q*fakeQuerier)InsertLicense(
2284+
_ context.Context,arg database.InsertLicenseParams) (database.License,error) {
2285+
q.mutex.RLock()
2286+
deferq.mutex.RUnlock()
2287+
2288+
l:= database.License{
2289+
ID:q.lastLicenseID+1,
2290+
UploadedAt:arg.UploadedAt,
2291+
JWT:arg.JWT,
2292+
Exp:arg.Exp,
2293+
}
2294+
q.lastLicenseID=l.ID
2295+
q.licenses=append(q.licenses,l)
2296+
returnl,nil
2297+
}
2298+
22802299
func (q*fakeQuerier)GetUserLinkByLinkedID(_ context.Context,idstring) (database.UserLink,error) {
22812300
q.mutex.RLock()
22822301
deferq.mutex.RUnlock()

‎coderd/database/dump.sql

Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- Valid licenses don't fit into old format, so delete all data
2+
DELETEFROM licenses;
3+
ALTERTABLE licenses DROP COLUMN jwt;
4+
ALTERTABLE licenses RENAME COLUMN uploaded_at to created_at;
5+
ALTERTABLE licenses ADD COLUMN license jsonbNOT NULL;
6+
ALTERTABLE licenses DROP COLUMN exp;
7+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
-- No valid licenses should exist, but to be sure, drop all rows
2+
DELETEFROM licenses;
3+
ALTERTABLE licenses DROP COLUMN license;
4+
ALTERTABLE licenses RENAME COLUMN created_at to uploaded_at;
5+
ALTERTABLE licenses ADD COLUMN jwttextNOT NULL;
6+
-- prevent adding the same license more than once
7+
ALTERTABLE licenses ADDCONSTRAINT licenses_jwt_key UNIQUE (jwt);
8+
ALTERTABLE licenses ADD COLUMN exptimestamp with time zoneNOT NULL;
9+
COMMENT ON COLUMN licenses.exp IS'exp tracks the claim of the same name in the JWT, and we include it here so that we can easily query for licenses that have not yet expired.';
10+

‎coderd/database/models.go

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

‎coderd/database/querier.go

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp