Skip to content

Commit 22dc7be

Browse files
committed
Merge branch 'main' of https://github.com/coder/coder into bq/refactor-provisioners
2 parents 4f9030f + d52d239 commit 22dc7be

35 files changed

+708
-166
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ provisioner/terraform/testdata/version:
809809
.PHONY: provisioner/terraform/testdata/version
810810

811811
test:
812-
$(GIT_FLAGS) gotestsum --format standard-quiet -- -v -short -count=1 ./...
812+
$(GIT_FLAGS) gotestsum --format standard-quiet -- -v -short -count=1 ./... $(if $(RUN),-run $(RUN))
813813
.PHONY: test
814814

815815
test-cli:

cli/agent.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ func (r *RootCmd) workspaceAgent() *serpent.Command {
475475
},
476476
{
477477
Flag: "devcontainers-enable",
478-
Default: "true",
478+
Default: "false",
479479
Env: "CODER_AGENT_DEVCONTAINERS_ENABLE",
480480
Description: "Allow the agent to automatically detect running devcontainers.",
481481
Value: serpent.BoolOf(&devcontainersEnabled),

cli/testdata/coder_agent_--help.golden

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ OPTIONS:
3333
--debug-address string, $CODER_AGENT_DEBUG_ADDRESS (default: 127.0.0.1:2113)
3434
The bind address to serve a debug HTTP server.
3535

36-
--devcontainers-enable bool, $CODER_AGENT_DEVCONTAINERS_ENABLE (default: true)
36+
--devcontainers-enable bool, $CODER_AGENT_DEVCONTAINERS_ENABLE (default: false)
3737
Allow the agent to automatically detect running devcontainers.
3838

3939
--log-dir string, $CODER_AGENT_LOG_DIR (default: /tmp)

cli/testdata/coder_tokens_remove_--help.golden

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
coder v0.0.0-devel
22

33
USAGE:
4-
coder tokens remove <name>
4+
coder tokens remove <name|id|token>
55

66
Delete a token
77

cli/tokens.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cli
33
import (
44
"fmt"
55
"os"
6+
"strings"
67
"time"
78

89
"golang.org/x/exp/slices"
@@ -223,7 +224,7 @@ func (r *RootCmd) listTokens() *serpent.Command {
223224
func (r *RootCmd) removeToken() *serpent.Command {
224225
client := new(codersdk.Client)
225226
cmd := &serpent.Command{
226-
Use: "remove <name>",
227+
Use: "remove <name|id|token>",
227228
Aliases: []string{"delete"},
228229
Short: "Delete a token",
229230
Middleware: serpent.Chain(
@@ -233,7 +234,12 @@ func (r *RootCmd) removeToken() *serpent.Command {
233234
Handler: func(inv *serpent.Invocation) error {
234235
token, err := client.APIKeyByName(inv.Context(), codersdk.Me, inv.Args[0])
235236
if err != nil {
236-
return xerrors.Errorf("fetch api key by name %s: %w", inv.Args[0], err)
237+
// If it's a token, we need to extract the ID
238+
maybeID := strings.Split(inv.Args[0], "-")[0]
239+
token, err = client.APIKeyByID(inv.Context(), codersdk.Me, maybeID)
240+
if err != nil {
241+
return xerrors.Errorf("fetch api key by name or id: %w", err)
242+
}
237243
}
238244

239245
err = client.DeleteAPIKey(inv.Context(), codersdk.Me, token.ID)

cli/tokens_test.go

+35-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func TestTokens(t *testing.T) {
9393
require.Contains(t, res, secondTokenID)
9494

9595
// Test creating a token for third user from second user's (non-admin) session
96-
inv, root = clitest.New(t, "tokens", "create", "--name", "token-two", "--user", thirdUser.ID.String())
96+
inv, root = clitest.New(t, "tokens", "create", "--name", "failed-token", "--user", thirdUser.ID.String())
9797
clitest.SetupConfig(t, secondUserClient, root)
9898
buf = new(bytes.Buffer)
9999
inv.Stdout = buf
@@ -113,6 +113,7 @@ func TestTokens(t *testing.T) {
113113
require.Len(t, tokens, 1)
114114
require.Equal(t, id, tokens[0].ID)
115115

116+
// Delete by name
116117
inv, root = clitest.New(t, "tokens", "rm", "token-one")
117118
clitest.SetupConfig(t, client, root)
118119
buf = new(bytes.Buffer)
@@ -122,4 +123,37 @@ func TestTokens(t *testing.T) {
122123
res = buf.String()
123124
require.NotEmpty(t, res)
124125
require.Contains(t, res, "deleted")
126+
127+
// Delete by ID
128+
inv, root = clitest.New(t, "tokens", "rm", secondTokenID)
129+
clitest.SetupConfig(t, client, root)
130+
buf = new(bytes.Buffer)
131+
inv.Stdout = buf
132+
err = inv.WithContext(ctx).Run()
133+
require.NoError(t, err)
134+
res = buf.String()
135+
require.NotEmpty(t, res)
136+
require.Contains(t, res, "deleted")
137+
138+
// Create third token
139+
inv, root = clitest.New(t, "tokens", "create", "--name", "token-three")
140+
clitest.SetupConfig(t, client, root)
141+
buf = new(bytes.Buffer)
142+
inv.Stdout = buf
143+
err = inv.WithContext(ctx).Run()
144+
require.NoError(t, err)
145+
res = buf.String()
146+
require.NotEmpty(t, res)
147+
fourthToken := res
148+
149+
// Delete by token
150+
inv, root = clitest.New(t, "tokens", "rm", fourthToken)
151+
clitest.SetupConfig(t, client, root)
152+
buf = new(bytes.Buffer)
153+
inv.Stdout = buf
154+
err = inv.WithContext(ctx).Run()
155+
require.NoError(t, err)
156+
res = buf.String()
157+
require.NotEmpty(t, res)
158+
require.Contains(t, res, "deleted")
125159
}

coderd/apidoc/docs.go

+66
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

+62
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/coderd.go

+30
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,7 @@ func New(options *Options) *API {
788788
httpmw.AttachRequestID,
789789
httpmw.ExtractRealIP(api.RealIPConfig),
790790
httpmw.Logger(api.Logger),
791+
singleSlashMW,
791792
rolestore.CustomRoleMW,
792793
prometheusMW,
793794
// Build-Version is helpful for debugging.
@@ -1057,6 +1058,7 @@ func New(options *Options) *API {
10571058
r.Get("/rich-parameters", api.templateVersionRichParameters)
10581059
r.Get("/external-auth", api.templateVersionExternalAuth)
10591060
r.Get("/variables", api.templateVersionVariables)
1061+
r.Get("/presets", api.templateVersionPresets)
10601062
r.Get("/resources", api.templateVersionResources)
10611063
r.Get("/logs", api.templateVersionLogs)
10621064
r.Route("/dry-run", func(r chi.Router) {
@@ -1731,3 +1733,31 @@ func ReadExperiments(log slog.Logger, raw []string) codersdk.Experiments {
17311733
}
17321734
return exps
17331735
}
1736+
1737+
var multipleSlashesRe = regexp.MustCompile(`/+`)
1738+
1739+
func singleSlashMW(next http.Handler) http.Handler {
1740+
fn := func(w http.ResponseWriter, r *http.Request) {
1741+
var path string
1742+
rctx := chi.RouteContext(r.Context())
1743+
if rctx != nil && rctx.RoutePath != "" {
1744+
path = rctx.RoutePath
1745+
} else {
1746+
path = r.URL.Path
1747+
}
1748+
1749+
// Normalize multiple slashes to a single slash
1750+
newPath := multipleSlashesRe.ReplaceAllString(path, "/")
1751+
1752+
// Apply the cleaned path
1753+
// The approach is consistent with: https://github.com/go-chi/chi/blob/e846b8304c769c4f1a51c9de06bebfaa4576bd88/middleware/strip.go#L24-L28
1754+
if rctx != nil {
1755+
rctx.RoutePath = newPath
1756+
} else {
1757+
r.URL.Path = newPath
1758+
}
1759+
1760+
next.ServeHTTP(w, r)
1761+
}
1762+
return http.HandlerFunc(fn)
1763+
}

coderd/coderd_internal_test.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package coderd
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"net/http/httptest"
7+
"testing"
8+
9+
"github.com/go-chi/chi/v5"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestStripSlashesMW(t *testing.T) {
14+
t.Parallel()
15+
16+
tests := []struct {
17+
name string
18+
inputPath string
19+
wantPath string
20+
}{
21+
{"No changes", "/api/v1/buildinfo", "/api/v1/buildinfo"},
22+
{"Double slashes", "/api//v2//buildinfo", "/api/v2/buildinfo"},
23+
{"Triple slashes", "/api///v2///buildinfo", "/api/v2/buildinfo"},
24+
{"Leading slashes", "///api/v2/buildinfo", "/api/v2/buildinfo"},
25+
{"Root path", "/", "/"},
26+
{"Double slashes root", "//", "/"},
27+
{"Only slashes", "/////", "/"},
28+
}
29+
30+
handler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
31+
w.WriteHeader(http.StatusOK)
32+
})
33+
34+
for _, tt := range tests {
35+
tt := tt
36+
37+
t.Run("chi/"+tt.name, func(t *testing.T) {
38+
t.Parallel()
39+
req := httptest.NewRequest("GET", tt.inputPath, nil)
40+
rec := httptest.NewRecorder()
41+
42+
// given
43+
rctx := chi.NewRouteContext()
44+
rctx.RoutePath = tt.inputPath
45+
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx))
46+
47+
// when
48+
singleSlashMW(handler).ServeHTTP(rec, req)
49+
updatedCtx := chi.RouteContext(req.Context())
50+
51+
// then
52+
assert.Equal(t, tt.inputPath, req.URL.Path)
53+
assert.Equal(t, tt.wantPath, updatedCtx.RoutePath)
54+
})
55+
56+
t.Run("stdlib/"+tt.name, func(t *testing.T) {
57+
t.Parallel()
58+
req := httptest.NewRequest("GET", tt.inputPath, nil)
59+
rec := httptest.NewRecorder()
60+
61+
// when
62+
singleSlashMW(handler).ServeHTTP(rec, req)
63+
64+
// then
65+
assert.Equal(t, tt.wantPath, req.URL.Path)
66+
assert.Nil(t, chi.RouteContext(req.Context()))
67+
})
68+
}
69+
}

0 commit comments

Comments
 (0)