Skip to content

Commit 85aa0fe

Browse files
committed
Merge remote-tracking branch 'origin/main' into stevenmasley/clean_codersdk
2 parents db536c0 + eb8f371 commit 85aa0fe

25 files changed

+475
-161
lines changed

.goreleaser.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ docker_manifests:
153153

154154
release:
155155
ids: [coder-linux, coder-darwin, coder-windows, packages]
156+
footer: |
157+
## Container Image
158+
- `docker pull ghcr.io/coder/coder:{{ .Tag }}`
156159
157160
signs:
158161
- ids: [coder-darwin]

cli/cliui/parameter.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
"github.com/coder/coder/codersdk"
1111
)
1212

13-
func ParameterSchema(cmd *cobra.Command, parameterSchema codersdk.TemplateVersionParameterSchema) (string, error) {
13+
func ParameterSchema(cmd *cobra.Command, parameterSchema codersdk.ParameterSchema) (string, error) {
1414
_, _ = fmt.Fprintln(cmd.OutOrStdout(), Styles.Bold.Render("var."+parameterSchema.Name))
1515
if parameterSchema.Description != "" {
1616
_, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+strings.TrimSpace(strings.Join(strings.Split(parameterSchema.Description, "\n"), "\n "))+"\n")
@@ -30,16 +30,32 @@ func ParameterSchema(cmd *cobra.Command, parameterSchema codersdk.TemplateVersio
3030
_, _ = fmt.Fprint(cmd.OutOrStdout(), "\033[1A")
3131
value, err = Select(cmd, SelectOptions{
3232
Options: options,
33+
Default: parameterSchema.DefaultSourceValue,
3334
HideSearch: true,
3435
})
3536
if err == nil {
3637
_, _ = fmt.Fprintln(cmd.OutOrStdout())
3738
_, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+Styles.Prompt.String()+Styles.Field.Render(value))
3839
}
3940
} else {
41+
text := "Enter a value"
42+
if parameterSchema.DefaultSourceValue != "" {
43+
text += fmt.Sprintf(" (default: %q)", parameterSchema.DefaultSourceValue)
44+
}
45+
text += ":"
46+
4047
value, err = Prompt(cmd, PromptOptions{
41-
Text: Styles.Bold.Render("Enter a value:"),
48+
Text: Styles.Bold.Render(text),
4249
})
4350
}
44-
return value, err
51+
if err != nil {
52+
return "", err
53+
}
54+
55+
// If they didn't specify anything, use the default value if set.
56+
if len(options) == 0 && value == "" {
57+
value = parameterSchema.DefaultSourceValue
58+
}
59+
60+
return value, nil
4561
}

cli/cliui/select.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ func init() {
3535
}
3636

3737
type SelectOptions struct {
38-
Options []string
38+
Options []string
39+
// Default will be highlighted first if it's a valid option.
40+
Default string
3941
Size int
4042
HideSearch bool
4143
}
@@ -50,9 +52,16 @@ func Select(cmd *cobra.Command, opts SelectOptions) (string, error) {
5052
if flag.Lookup("test.v") != nil {
5153
return opts.Options[0], nil
5254
}
55+
56+
var defaultOption interface{}
57+
if opts.Default != "" {
58+
defaultOption = opts.Default
59+
}
60+
5361
var value string
5462
err := survey.AskOne(&survey.Select{
5563
Options: opts.Options,
64+
Default: defaultOption,
5665
PageSize: opts.Size,
5766
}, &value, survey.WithIcons(func(is *survey.IconSet) {
5867
is.Help.Text = "Type to search"

cli/create_test.go

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli_test
22

33
import (
4+
"fmt"
45
"testing"
56

67
"github.com/stretchr/testify/require"
@@ -44,6 +45,7 @@ func TestCreate(t *testing.T) {
4445
}
4546
<-doneChan
4647
})
48+
4749
t.Run("CreateFromList", func(t *testing.T) {
4850
t.Parallel()
4951
client := coderdtest.New(t, nil)
@@ -74,6 +76,7 @@ func TestCreate(t *testing.T) {
7476
}
7577
<-doneChan
7678
})
79+
7780
t.Run("FromNothing", func(t *testing.T) {
7881
t.Parallel()
7982
client := coderdtest.New(t, nil)
@@ -105,33 +108,52 @@ func TestCreate(t *testing.T) {
105108
}
106109
<-doneChan
107110
})
111+
108112
t.Run("WithParameter", func(t *testing.T) {
109113
t.Parallel()
110114
client := coderdtest.New(t, nil)
111115
user := coderdtest.CreateFirstUser(t, client)
112116
coderdtest.NewProvisionerDaemon(t, client)
117+
118+
defaultValue := "something"
113119
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
114120
Parse: []*proto.Parse_Response{{
115121
Type: &proto.Parse_Response_Complete{
116122
Complete: &proto.Parse_Complete{
117-
ParameterSchemas: []*proto.ParameterSchema{{
118-
AllowOverrideSource: true,
119-
Name: "region",
120-
Description: "description",
121-
DefaultSource: &proto.ParameterSource{
122-
Scheme: proto.ParameterSource_DATA,
123-
Value: "something",
123+
ParameterSchemas: []*proto.ParameterSchema{
124+
{
125+
AllowOverrideSource: true,
126+
Name: "region",
127+
Description: "description 1",
128+
DefaultSource: &proto.ParameterSource{
129+
Scheme: proto.ParameterSource_DATA,
130+
Value: defaultValue,
131+
},
132+
DefaultDestination: &proto.ParameterDestination{
133+
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
134+
},
124135
},
125-
DefaultDestination: &proto.ParameterDestination{
126-
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
136+
{
137+
AllowOverrideSource: true,
138+
Name: "username",
139+
Description: "description 2",
140+
DefaultSource: &proto.ParameterSource{
141+
Scheme: proto.ParameterSource_DATA,
142+
// No default value
143+
Value: "",
144+
},
145+
DefaultDestination: &proto.ParameterDestination{
146+
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
147+
},
127148
},
128-
}},
149+
},
129150
},
130151
},
131152
}},
132153
Provision: echo.ProvisionComplete,
133154
ProvisionDryRun: echo.ProvisionComplete,
134155
})
156+
135157
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
136158
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
137159
cmd, root := clitest.New(t, "create", "")
@@ -145,9 +167,11 @@ func TestCreate(t *testing.T) {
145167
err := cmd.Execute()
146168
require.NoError(t, err)
147169
}()
170+
148171
matches := []string{
149172
"Specify a name", "my-workspace",
150-
"Enter a value", "bananas",
173+
fmt.Sprintf("Enter a value (default: %q):", defaultValue), "bingo",
174+
"Enter a value:", "boingo",
151175
"Confirm create?", "yes",
152176
}
153177
for i := 0; i < len(matches); i += 2 {

cli/login.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ func login() *cobra.Command {
164164
cliui.Styles.Paragraph.Render(fmt.Sprintf("Welcome to Coder, %s! You're authenticated.", cliui.Styles.Keyword.Render(username)))+"\n")
165165

166166
_, _ = fmt.Fprintf(cmd.OutOrStdout(),
167-
cliui.Styles.Paragraph.Render("Get started by creating a template: "+cliui.Styles.Code.Render("coder templates create"))+"\n")
167+
cliui.Styles.Paragraph.Render("Get started by creating a template: "+cliui.Styles.Code.Render("coder templates init"))+"\n")
168168
return nil
169169
}
170170

cli/templatecreate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ func createValidTemplateVersion(cmd *cobra.Command, client *codersdk.Client, org
175175
sort.Slice(parameterSchemas, func(i, j int) bool {
176176
return parameterSchemas[i].Name < parameterSchemas[j].Name
177177
})
178-
missingSchemas := make([]codersdk.TemplateVersionParameterSchema, 0)
178+
missingSchemas := make([]codersdk.ParameterSchema, 0)
179179
for _, parameterSchema := range parameterSchemas {
180180
_, ok := valuesBySchemaID[parameterSchema.ID.String()]
181181
if ok {

coderd/coderd.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ func New(options *Options) (http.Handler, func()) {
149149
r.Get("/", api.workspacesByOrganization)
150150
r.Route("/{user}", func(r chi.Router) {
151151
r.Use(httpmw.ExtractUserParam(options.Database))
152-
r.Get("/{workspace}", api.workspaceByOwnerAndName)
152+
r.Get("/{workspacename}", api.workspaceByOwnerAndName)
153153
r.Get("/", api.workspacesByOwner)
154154
})
155155
})
@@ -237,8 +237,6 @@ func New(options *Options) (http.Handler, func()) {
237237
r.Route("/password", func(r chi.Router) {
238238
r.Put("/", api.putUserPassword)
239239
})
240-
r.Get("/organizations", api.organizationsByUser)
241-
r.Post("/organizations", api.postOrganizationsByUser)
242240
// These roles apply to the site wide permissions.
243241
r.Put("/roles", api.putUserRoles)
244242
r.Get("/roles", api.userRoles)
@@ -316,6 +314,7 @@ func New(options *Options) (http.Handler, func()) {
316314
r.Route("/workspacebuilds/{workspacebuild}", func(r chi.Router) {
317315
r.Use(
318316
apiKeyMiddleware,
317+
authRolesMiddleware,
319318
httpmw.ExtractWorkspaceBuildParam(options.Database),
320319
httpmw.ExtractWorkspaceParam(options.Database),
321320
)

coderd/coderd_test.go

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package coderd_test
22

33
import (
44
"context"
5+
"io"
56
"net/http"
67
"strings"
78
"testing"
@@ -48,13 +49,18 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
4849
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
4950
template := coderdtest.CreateTemplate(t, client, admin.OrganizationID, version.ID)
5051
workspace := coderdtest.CreateWorkspace(t, client, admin.OrganizationID, template.ID)
52+
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
5153

5254
// Always fail auth from this point forward
5355
authorizer.AlwaysReturn = rbac.ForbiddenWithInternal(xerrors.New("fake implementation"), nil, nil)
5456

57+
// Some quick reused objects
58+
workspaceRBACObj := rbac.ResourceWorkspace.InOrg(organization.ID).WithID(workspace.ID.String()).WithOwner(workspace.OwnerID.String())
59+
5560
// skipRoutes allows skipping routes from being checked.
5661
type routeCheck struct {
5762
NoAuthorize bool
63+
AssertAction rbac.Action
5864
AssertObject rbac.Object
5965
StatusCode int
6066
}
@@ -84,13 +90,7 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
8490
"GET:/api/v2/workspaceagents/{workspaceagent}/turn": {NoAuthorize: true},
8591

8692
// TODO: @emyrk these need to be fixed by adding authorize calls
87-
"GET:/api/v2/workspaceresources/{workspaceresource}": {NoAuthorize: true},
88-
"GET:/api/v2/workspacebuilds/{workspacebuild}": {NoAuthorize: true},
89-
"GET:/api/v2/workspacebuilds/{workspacebuild}/logs": {NoAuthorize: true},
90-
"GET:/api/v2/workspacebuilds/{workspacebuild}/resources": {NoAuthorize: true},
91-
"GET:/api/v2/workspacebuilds/{workspacebuild}/state": {NoAuthorize: true},
92-
"PATCH:/api/v2/workspacebuilds/{workspacebuild}/cancel": {NoAuthorize: true},
93-
"GET:/api/v2/workspaces/{workspace}/builds/{workspacebuildname}": {NoAuthorize: true},
93+
"GET:/api/v2/workspaceresources/{workspaceresource}": {NoAuthorize: true},
9494

9595
"GET:/api/v2/users/oauth2/github/callback": {NoAuthorize: true},
9696

@@ -123,15 +123,9 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
123123

124124
"POST:/api/v2/users/{user}/organizations": {NoAuthorize: true},
125125

126-
"GET:/api/v2/workspaces/{workspace}": {NoAuthorize: true},
127-
"PUT:/api/v2/workspaces/{workspace}/autostart": {NoAuthorize: true},
128-
"PUT:/api/v2/workspaces/{workspace}/autostop": {NoAuthorize: true},
129-
"GET:/api/v2/workspaces/{workspace}/builds": {NoAuthorize: true},
130-
"POST:/api/v2/workspaces/{workspace}/builds": {NoAuthorize: true},
131-
"GET:/api/v2/workspaces/{workspace}/watch": {NoAuthorize: true},
132-
133-
"POST:/api/v2/files": {NoAuthorize: true},
134-
"GET:/api/v2/files/{hash}": {NoAuthorize: true},
126+
"POST:/api/v2/files": {NoAuthorize: true},
127+
"GET:/api/v2/files/{hash}": {NoAuthorize: true},
128+
"GET:/api/v2/workspaces/{workspace}/watch": {NoAuthorize: true},
135129

136130
// These endpoints have more assertions. This is good, add more endpoints to assert if you can!
137131
"GET:/api/v2/organizations/{organization}": {AssertObject: rbac.ResourceOrganization.InOrg(admin.OrganizationID)},
@@ -141,11 +135,60 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
141135
"GET:/api/v2/organizations/{organization}/workspaces/{user}/{workspace}": {
142136
AssertObject: rbac.ResourceWorkspace.InOrg(organization.ID).WithID(workspace.ID.String()).WithOwner(workspace.OwnerID.String()),
143137
},
138+
"GET:/api/v2/workspaces/{workspace}/builds/{workspacebuildname}": {
139+
AssertAction: rbac.ActionRead,
140+
AssertObject: workspaceRBACObj,
141+
},
142+
"GET:/api/v2/organizations/{organization}/workspaces/{user}/{workspacename}": {
143+
AssertAction: rbac.ActionRead,
144+
AssertObject: workspaceRBACObj,
145+
},
144146
"GET:/api/v2/organizations/{organization}/workspaces": {StatusCode: http.StatusOK, AssertObject: rbac.ResourceWorkspace},
145-
"GET:/api/v2/workspaces": {StatusCode: http.StatusOK, AssertObject: rbac.ResourceWorkspace},
147+
"GET:/api/v2/workspacebuilds/{workspacebuild}": {
148+
AssertAction: rbac.ActionRead,
149+
AssertObject: workspaceRBACObj,
150+
},
151+
"GET:/api/v2/workspacebuilds/{workspacebuild}/logs": {
152+
AssertAction: rbac.ActionRead,
153+
AssertObject: workspaceRBACObj,
154+
},
155+
"GET:/api/v2/workspaces/{workspace}/builds": {
156+
AssertAction: rbac.ActionRead,
157+
AssertObject: workspaceRBACObj,
158+
},
159+
"GET:/api/v2/workspaces/{workspace}": {
160+
AssertAction: rbac.ActionRead,
161+
AssertObject: workspaceRBACObj,
162+
},
163+
"PUT:/api/v2/workspaces/{workspace}/autostart": {
164+
AssertAction: rbac.ActionUpdate,
165+
AssertObject: workspaceRBACObj,
166+
},
167+
"PUT:/api/v2/workspaces/{workspace}/autostop": {
168+
AssertAction: rbac.ActionUpdate,
169+
AssertObject: workspaceRBACObj,
170+
},
171+
"PATCH:/api/v2/workspacebuilds/{workspacebuild}/cancel": {
172+
AssertAction: rbac.ActionUpdate,
173+
AssertObject: workspaceRBACObj,
174+
},
175+
"GET:/api/v2/workspacebuilds/{workspacebuild}/resources": {
176+
AssertAction: rbac.ActionRead,
177+
AssertObject: workspaceRBACObj,
178+
},
179+
"GET:/api/v2/workspacebuilds/{workspacebuild}/state": {
180+
AssertAction: rbac.ActionRead,
181+
AssertObject: workspaceRBACObj,
182+
},
183+
"GET:/api/v2/workspaces/": {
184+
StatusCode: http.StatusOK,
185+
AssertAction: rbac.ActionRead,
186+
AssertObject: workspaceRBACObj,
187+
},
146188

147-
// These endpoints need payloads to get to the auth part.
148-
"PUT:/api/v2/users/{user}/roles": {StatusCode: http.StatusBadRequest, NoAuthorize: true},
189+
// These endpoints need payloads to get to the auth part. Payloads will be required
190+
"PUT:/api/v2/users/{user}/roles": {StatusCode: http.StatusBadRequest, NoAuthorize: true},
191+
"POST:/api/v2/workspaces/{workspace}/builds": {StatusCode: http.StatusBadRequest, NoAuthorize: true},
149192
}
150193

151194
for k, v := range assertRoute {
@@ -175,16 +218,24 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
175218
route = strings.ReplaceAll(route, "{organization}", admin.OrganizationID.String())
176219
route = strings.ReplaceAll(route, "{user}", admin.UserID.String())
177220
route = strings.ReplaceAll(route, "{organizationname}", organization.Name)
178-
route = strings.ReplaceAll(route, "{workspace}", workspace.Name)
221+
route = strings.ReplaceAll(route, "{workspace}", workspace.ID.String())
222+
route = strings.ReplaceAll(route, "{workspacebuild}", workspace.LatestBuild.ID.String())
223+
route = strings.ReplaceAll(route, "{workspacename}", workspace.Name)
224+
route = strings.ReplaceAll(route, "{workspacebuildname}", workspace.LatestBuild.Name)
179225

180226
resp, err := client.Request(context.Background(), method, route, nil)
181227
require.NoError(t, err, "do req")
228+
body, _ := io.ReadAll(resp.Body)
229+
t.Logf("Response Body: %q", string(body))
182230
_ = resp.Body.Close()
183231

184232
if !routeAssertions.NoAuthorize {
185233
assert.NotNil(t, authorizer.Called, "authorizer expected")
186234
assert.Equal(t, routeAssertions.StatusCode, resp.StatusCode, "expect unauthorized")
187235
if authorizer.Called != nil {
236+
if routeAssertions.AssertAction != "" {
237+
assert.Equal(t, routeAssertions.AssertAction, authorizer.Called.Action, "resource action")
238+
}
188239
if routeAssertions.AssertObject.Type != "" {
189240
assert.Equal(t, routeAssertions.AssertObject.Type, authorizer.Called.Object.Type, "resource type")
190241
}

0 commit comments

Comments
 (0)