Skip to content

Commit a56220a

Browse files
committed
Add tests for standalone provisionerd
1 parent 940f458 commit a56220a

File tree

4 files changed

+119
-4
lines changed

4 files changed

+119
-4
lines changed

cli/provisionercreate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func provisionerCreate() *cobra.Command {
3333
}
3434
tokenArg := provisionerDaemon.AuthToken.String()
3535

36-
_, _ = fmt.Fprintln(cmd.ErrOrStderr(), `A new provisioner daemon has been registered.
36+
_, _ = fmt.Fprintln(cmd.OutOrStderr(), `A new provisioner daemon has been registered.
3737
3838
Start the provisioner daemon with the following command:
3939

cli/provisionercreate_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package cli_test
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"context"
7+
"strings"
8+
"testing"
9+
10+
"github.com/coder/coder/cli/clitest"
11+
"github.com/coder/coder/coderd/coderdtest"
12+
"github.com/google/uuid"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
func TestProvisionerCreate(t *testing.T) {
17+
t.Parallel()
18+
19+
t.Run("OK", func(t *testing.T) {
20+
t.Parallel()
21+
client := coderdtest.New(t, nil)
22+
_ = coderdtest.CreateFirstUser(t, client)
23+
cmd, root := clitest.New(t, "provisioners", "create", "foobar")
24+
clitest.SetupConfig(t, client, root)
25+
buf := new(bytes.Buffer)
26+
cmd.SetOut(buf)
27+
err := cmd.Execute()
28+
require.NoError(t, err)
29+
30+
var token *uuid.UUID
31+
const tokenPrefix = "coder provisioners run --token "
32+
s := bufio.NewScanner(buf)
33+
for s.Scan() {
34+
line := s.Text()
35+
if strings.HasPrefix(line, tokenPrefix) {
36+
tokenString := strings.TrimPrefix(line, tokenPrefix)
37+
parsedToken, err := uuid.Parse(tokenString)
38+
require.NoError(t, err, "provisioner token has invalid format")
39+
token = &parsedToken
40+
}
41+
}
42+
require.NotNil(t, token, "provisioner token not generated in output")
43+
44+
provisioners, err := client.ProvisionerDaemons(context.Background())
45+
require.NoError(t, err)
46+
tokensByName := make(map[string]*uuid.UUID)
47+
for _, p := range provisioners {
48+
tokensByName[p.Name] = p.AuthToken
49+
}
50+
require.Equal(t, token, tokensByName["foobar"])
51+
})
52+
53+
t.Run("Unprivileged", func(t *testing.T) {
54+
t.Parallel()
55+
adminClient := coderdtest.New(t, nil)
56+
admin := coderdtest.CreateFirstUser(t, adminClient)
57+
otherClient := coderdtest.CreateAnotherUser(t, adminClient, admin.OrganizationID)
58+
cmd, root := clitest.New(t, "provisioners", "create", "foobar")
59+
clitest.SetupConfig(t, otherClient, root)
60+
err := cmd.Execute()
61+
require.Error(t, err, "unprivileged user was allowed to create provisioner")
62+
})
63+
}

cli/provisionerrun_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package cli_test
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/coder/coder/cli/clitest"
8+
"github.com/coder/coder/coderd/coderdtest"
9+
"github.com/coder/coder/codersdk"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestProvisionerRun(t *testing.T) {
14+
t.Parallel()
15+
t.Run("Provisioner", func(t *testing.T) {
16+
t.Parallel()
17+
client := coderdtest.New(t, nil)
18+
_ = coderdtest.CreateFirstUser(t, client)
19+
provisionerResponse, err := client.CreateProvisionerDaemon(context.Background(),
20+
codersdk.CreateProvisionerDaemonRequest{
21+
Name: "foobar",
22+
},
23+
)
24+
require.NoError(t, err)
25+
token := provisionerResponse.AuthToken
26+
require.NotNil(t, token)
27+
28+
doneCh := make(chan error)
29+
defer func() {
30+
err := <-doneCh
31+
require.ErrorIs(t, err, context.Canceled, "provisioner command terminated with error")
32+
}()
33+
34+
ctx, cancelFunc := context.WithCancel(context.Background())
35+
defer cancelFunc()
36+
37+
cmd, root := clitest.New(t, "provisioners", "run", "--token", token.String())
38+
// command should only have access to provisioner auth token, not user credentials
39+
err = root.URL().Write(client.URL.String())
40+
require.NoError(t, err)
41+
42+
go func() {
43+
defer close(doneCh)
44+
doneCh <- cmd.ExecuteContext(ctx)
45+
}()
46+
})
47+
}

coderd/coderdtest/authtest.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,6 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
178178
"POST:/api/v2/csp/reports": {NoAuthorize: true},
179179
"GET:/api/v2/entitlements": {NoAuthorize: true},
180180

181-
// TODO needs authorization test
182-
"GET:/api/v2/provisionerdaemons/me/listen": {NoAuthorize: true},
183-
184181
"GET:/%40{user}/{workspacename}/apps/{workspaceapp}/*": {
185182
AssertAction: rbac.ActionCreate,
186183
AssertObject: workspaceExecObj,
@@ -209,6 +206,9 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
209206
"GET:/api/v2/workspaceagents/{workspaceagent}/iceservers": {NoAuthorize: true},
210207
"GET:/api/v2/workspaceagents/{workspaceagent}/derp": {NoAuthorize: true},
211208

209+
// Provisioner daemon endpoint does not use RBAC
210+
"GET:/api/v2/provisionerdaemons/me/listen": {NoAuthorize: true},
211+
212212
// These endpoints have more assertions. This is good, add more endpoints to assert if you can!
213213
"GET:/api/v2/organizations/{organization}": {AssertObject: rbac.ResourceOrganization.InOrg(a.Admin.OrganizationID)},
214214
"GET:/api/v2/users/{user}/organizations": {StatusCode: http.StatusOK, AssertObject: rbac.ResourceOrganization},
@@ -366,6 +366,11 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
366366
},
367367
"GET:/api/v2/provisionerdaemons": {
368368
StatusCode: http.StatusOK,
369+
AssertAction: rbac.ActionRead,
370+
AssertObject: rbac.ResourceProvisionerDaemon,
371+
},
372+
"POST:/api/v2/provisionerdaemons": {
373+
AssertAction: rbac.ActionCreate,
369374
AssertObject: rbac.ResourceProvisionerDaemon,
370375
},
371376

0 commit comments

Comments
 (0)