mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
chore: Add workspace proxy enterprise cli commands (#7176)
* feat: Add workspace proxy enterprise cli commands * chore: Handle custom workspace proxy options. Remove excess * chore: Add endpoint to register workspace proxies
This commit is contained in:
Generated
+98
@@ -5067,6 +5067,83 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/workspaceproxies/me/register": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Enterprise"
|
||||
],
|
||||
"summary": "Register workspace proxy",
|
||||
"operationId": "register-workspace-proxy",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Issue signed app token request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/wsproxysdk.RegisterWorkspaceProxyRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/wsproxysdk.RegisterWorkspaceProxyResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/workspaceproxies/{workspaceproxy}": {
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Enterprise"
|
||||
],
|
||||
"summary": "Delete workspace proxy",
|
||||
"operationId": "delete-workspace-proxy",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Proxy ID or name",
|
||||
"name": "workspaceproxy",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/workspaces": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -10213,6 +10290,27 @@ const docTemplate = `{
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"wsproxysdk.RegisterWorkspaceProxyRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"access_url": {
|
||||
"description": "AccessURL that hits the workspace proxy api.",
|
||||
"type": "string"
|
||||
},
|
||||
"wildcard_hostname": {
|
||||
"description": "WildcardHostname that the workspace proxy api is serving for subdomain apps.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"wsproxysdk.RegisterWorkspaceProxyResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"app_security_key": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
|
||||
Generated
+88
@@ -4459,6 +4459,73 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/workspaceproxies/me/register": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Enterprise"],
|
||||
"summary": "Register workspace proxy",
|
||||
"operationId": "register-workspace-proxy",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Issue signed app token request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/wsproxysdk.RegisterWorkspaceProxyRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/wsproxysdk.RegisterWorkspaceProxyResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/workspaceproxies/{workspaceproxy}": {
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Enterprise"],
|
||||
"summary": "Delete workspace proxy",
|
||||
"operationId": "delete-workspace-proxy",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Proxy ID or name",
|
||||
"name": "workspaceproxy",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/workspaces": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -9272,6 +9339,27 @@
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"wsproxysdk.RegisterWorkspaceProxyRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"access_url": {
|
||||
"description": "AccessURL that hits the workspace proxy api.",
|
||||
"type": "string"
|
||||
},
|
||||
"wildcard_hostname": {
|
||||
"description": "WildcardHostname that the workspace proxy api is serving for subdomain apps.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"wsproxysdk.RegisterWorkspaceProxyResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"app_security_key": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
|
||||
@@ -181,6 +181,7 @@ var (
|
||||
rbac.ResourceUserData.Type: {rbac.ActionCreate, rbac.ActionUpdate},
|
||||
rbac.ResourceWorkspace.Type: {rbac.ActionUpdate},
|
||||
rbac.ResourceWorkspaceExecution.Type: {rbac.ActionCreate},
|
||||
rbac.ResourceWorkspaceProxy.Type: {rbac.ActionCreate, rbac.ActionUpdate, rbac.ActionDelete},
|
||||
}),
|
||||
Org: map[string][]rbac.Permission{},
|
||||
User: []rbac.Permission{},
|
||||
|
||||
@@ -1697,6 +1697,10 @@ func (q *querier) GetWorkspaceProxyByID(ctx context.Context, id uuid.UUID) (data
|
||||
return fetch(q.log, q.auth, q.db.GetWorkspaceProxyByID)(ctx, id)
|
||||
}
|
||||
|
||||
func (q *querier) GetWorkspaceProxyByName(ctx context.Context, name string) (database.WorkspaceProxy, error) {
|
||||
return fetch(q.log, q.auth, q.db.GetWorkspaceProxyByName)(ctx, name)
|
||||
}
|
||||
|
||||
func (q *querier) GetWorkspaceProxyByHostname(ctx context.Context, hostname string) (database.WorkspaceProxy, error) {
|
||||
return fetch(q.log, q.auth, q.db.GetWorkspaceProxyByHostname)(ctx, hostname)
|
||||
}
|
||||
@@ -1705,11 +1709,11 @@ func (q *querier) InsertWorkspaceProxy(ctx context.Context, arg database.InsertW
|
||||
return insert(q.log, q.auth, rbac.ResourceWorkspaceProxy, q.db.InsertWorkspaceProxy)(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateWorkspaceProxy(ctx context.Context, arg database.UpdateWorkspaceProxyParams) (database.WorkspaceProxy, error) {
|
||||
fetch := func(ctx context.Context, arg database.UpdateWorkspaceProxyParams) (database.WorkspaceProxy, error) {
|
||||
func (q *querier) RegisterWorkspaceProxy(ctx context.Context, arg database.RegisterWorkspaceProxyParams) (database.WorkspaceProxy, error) {
|
||||
fetch := func(ctx context.Context, arg database.RegisterWorkspaceProxyParams) (database.WorkspaceProxy, error) {
|
||||
return q.db.GetWorkspaceProxyByID(ctx, arg.ID)
|
||||
}
|
||||
return updateWithReturn(q.log, q.auth, fetch, q.db.UpdateWorkspaceProxy)(ctx, arg)
|
||||
return updateWithReturn(q.log, q.auth, fetch, q.db.RegisterWorkspaceProxy)(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateWorkspaceProxyDeleted(ctx context.Context, arg database.UpdateWorkspaceProxyDeletedParams) error {
|
||||
|
||||
@@ -444,9 +444,9 @@ func (s *MethodTestSuite) TestWorkspaceProxy() {
|
||||
ID: uuid.New(),
|
||||
}).Asserts(rbac.ResourceWorkspaceProxy, rbac.ActionCreate)
|
||||
}))
|
||||
s.Run("UpdateWorkspaceProxy", s.Subtest(func(db database.Store, check *expects) {
|
||||
s.Run("RegisterWorkspaceProxy", s.Subtest(func(db database.Store, check *expects) {
|
||||
p, _ := dbgen.WorkspaceProxy(s.T(), db, database.WorkspaceProxy{})
|
||||
check.Args(database.UpdateWorkspaceProxyParams{
|
||||
check.Args(database.RegisterWorkspaceProxyParams{
|
||||
ID: p.ID,
|
||||
}).Asserts(p, rbac.ActionUpdate)
|
||||
}))
|
||||
|
||||
@@ -5127,6 +5127,21 @@ func (q *fakeQuerier) GetWorkspaceProxyByID(_ context.Context, id uuid.UUID) (da
|
||||
return database.WorkspaceProxy{}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) GetWorkspaceProxyByName(_ context.Context, name string) (database.WorkspaceProxy, error) {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
for _, proxy := range q.workspaceProxies {
|
||||
if proxy.Deleted {
|
||||
continue
|
||||
}
|
||||
if proxy.Name == name {
|
||||
return proxy, nil
|
||||
}
|
||||
}
|
||||
return database.WorkspaceProxy{}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) GetWorkspaceProxyByHostname(_ context.Context, hostname string) (database.WorkspaceProxy, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
@@ -5187,14 +5202,12 @@ func (q *fakeQuerier) InsertWorkspaceProxy(_ context.Context, arg database.Inser
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) UpdateWorkspaceProxy(_ context.Context, arg database.UpdateWorkspaceProxyParams) (database.WorkspaceProxy, error) {
|
||||
func (q *fakeQuerier) RegisterWorkspaceProxy(_ context.Context, arg database.RegisterWorkspaceProxyParams) (database.WorkspaceProxy, error) {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
for i, p := range q.workspaceProxies {
|
||||
if p.ID == arg.ID {
|
||||
p.Name = arg.Name
|
||||
p.Icon = arg.Icon
|
||||
p.Url = arg.Url
|
||||
p.WildcardHostname = arg.WildcardHostname
|
||||
p.UpdatedAt = database.Now()
|
||||
|
||||
@@ -158,6 +158,7 @@ type sqlcQuerier interface {
|
||||
//
|
||||
GetWorkspaceProxyByHostname(ctx context.Context, hostname string) (WorkspaceProxy, error)
|
||||
GetWorkspaceProxyByID(ctx context.Context, id uuid.UUID) (WorkspaceProxy, error)
|
||||
GetWorkspaceProxyByName(ctx context.Context, name string) (WorkspaceProxy, error)
|
||||
GetWorkspaceResourceByID(ctx context.Context, id uuid.UUID) (WorkspaceResource, error)
|
||||
GetWorkspaceResourceMetadataByResourceIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceResourceMetadatum, error)
|
||||
GetWorkspaceResourceMetadataCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceResourceMetadatum, error)
|
||||
@@ -209,6 +210,7 @@ type sqlcQuerier interface {
|
||||
InsertWorkspaceResourceMetadata(ctx context.Context, arg InsertWorkspaceResourceMetadataParams) ([]WorkspaceResourceMetadatum, error)
|
||||
ParameterValue(ctx context.Context, id uuid.UUID) (ParameterValue, error)
|
||||
ParameterValues(ctx context.Context, arg ParameterValuesParams) ([]ParameterValue, error)
|
||||
RegisterWorkspaceProxy(ctx context.Context, arg RegisterWorkspaceProxyParams) (WorkspaceProxy, error)
|
||||
// Non blocking lock. Returns true if the lock was acquired, false otherwise.
|
||||
//
|
||||
// This must be called from within a transaction. The lock will be automatically
|
||||
@@ -253,7 +255,6 @@ type sqlcQuerier interface {
|
||||
UpdateWorkspaceBuildCostByID(ctx context.Context, arg UpdateWorkspaceBuildCostByIDParams) (WorkspaceBuild, error)
|
||||
UpdateWorkspaceDeletedByID(ctx context.Context, arg UpdateWorkspaceDeletedByIDParams) error
|
||||
UpdateWorkspaceLastUsedAt(ctx context.Context, arg UpdateWorkspaceLastUsedAtParams) error
|
||||
UpdateWorkspaceProxy(ctx context.Context, arg UpdateWorkspaceProxyParams) (WorkspaceProxy, error)
|
||||
UpdateWorkspaceProxyDeleted(ctx context.Context, arg UpdateWorkspaceProxyDeletedParams) error
|
||||
UpdateWorkspaceTTL(ctx context.Context, arg UpdateWorkspaceTTLParams) error
|
||||
UpdateWorkspaceTTLToBeWithinTemplateMax(ctx context.Context, arg UpdateWorkspaceTTLToBeWithinTemplateMaxParams) error
|
||||
|
||||
@@ -2937,6 +2937,36 @@ func (q *sqlQuerier) GetWorkspaceProxyByID(ctx context.Context, id uuid.UUID) (W
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getWorkspaceProxyByName = `-- name: GetWorkspaceProxyByName :one
|
||||
SELECT
|
||||
id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret
|
||||
FROM
|
||||
workspace_proxies
|
||||
WHERE
|
||||
name = $1
|
||||
AND deleted = false
|
||||
LIMIT
|
||||
1
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetWorkspaceProxyByName(ctx context.Context, name string) (WorkspaceProxy, error) {
|
||||
row := q.db.QueryRowContext(ctx, getWorkspaceProxyByName, name)
|
||||
var i WorkspaceProxy
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Name,
|
||||
&i.DisplayName,
|
||||
&i.Icon,
|
||||
&i.Url,
|
||||
&i.WildcardHostname,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Deleted,
|
||||
&i.TokenHashedSecret,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const insertWorkspaceProxy = `-- name: InsertWorkspaceProxy :one
|
||||
INSERT INTO
|
||||
workspace_proxies (
|
||||
@@ -2995,39 +3025,26 @@ func (q *sqlQuerier) InsertWorkspaceProxy(ctx context.Context, arg InsertWorkspa
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateWorkspaceProxy = `-- name: UpdateWorkspaceProxy :one
|
||||
const registerWorkspaceProxy = `-- name: RegisterWorkspaceProxy :one
|
||||
UPDATE
|
||||
workspace_proxies
|
||||
SET
|
||||
name = $1,
|
||||
display_name = $2,
|
||||
url = $3,
|
||||
wildcard_hostname = $4,
|
||||
icon = $5,
|
||||
url = $1,
|
||||
wildcard_hostname = $2,
|
||||
updated_at = Now()
|
||||
WHERE
|
||||
id = $6
|
||||
id = $3
|
||||
RETURNING id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret
|
||||
`
|
||||
|
||||
type UpdateWorkspaceProxyParams struct {
|
||||
Name string `db:"name" json:"name"`
|
||||
DisplayName string `db:"display_name" json:"display_name"`
|
||||
type RegisterWorkspaceProxyParams struct {
|
||||
Url string `db:"url" json:"url"`
|
||||
WildcardHostname string `db:"wildcard_hostname" json:"wildcard_hostname"`
|
||||
Icon string `db:"icon" json:"icon"`
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateWorkspaceProxy(ctx context.Context, arg UpdateWorkspaceProxyParams) (WorkspaceProxy, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateWorkspaceProxy,
|
||||
arg.Name,
|
||||
arg.DisplayName,
|
||||
arg.Url,
|
||||
arg.WildcardHostname,
|
||||
arg.Icon,
|
||||
arg.ID,
|
||||
)
|
||||
func (q *sqlQuerier) RegisterWorkspaceProxy(ctx context.Context, arg RegisterWorkspaceProxyParams) (WorkspaceProxy, error) {
|
||||
row := q.db.QueryRowContext(ctx, registerWorkspaceProxy, arg.Url, arg.WildcardHostname, arg.ID)
|
||||
var i WorkspaceProxy
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
|
||||
@@ -15,15 +15,12 @@ INSERT INTO
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, false) RETURNING *;
|
||||
|
||||
-- name: UpdateWorkspaceProxy :one
|
||||
-- name: RegisterWorkspaceProxy :one
|
||||
UPDATE
|
||||
workspace_proxies
|
||||
SET
|
||||
name = @name,
|
||||
display_name = @display_name,
|
||||
url = @url,
|
||||
wildcard_hostname = @wildcard_hostname,
|
||||
icon = @icon,
|
||||
updated_at = Now()
|
||||
WHERE
|
||||
id = @id
|
||||
@@ -49,6 +46,17 @@ WHERE
|
||||
LIMIT
|
||||
1;
|
||||
|
||||
-- name: GetWorkspaceProxyByName :one
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
workspace_proxies
|
||||
WHERE
|
||||
name = $1
|
||||
AND deleted = false
|
||||
LIMIT
|
||||
1;
|
||||
|
||||
-- Finds a workspace proxy that has an access URL or app hostname that matches
|
||||
-- the provided hostname. This is to check if a hostname matches any workspace
|
||||
-- proxy.
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -156,3 +157,53 @@ func ExtractWorkspaceProxy(opts ExtractWorkspaceProxyConfig) func(http.Handler)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type workspaceProxyParamContextKey struct{}
|
||||
|
||||
// WorkspaceProxyParam returns the worksace proxy from the ExtractWorkspaceProxyParam handler.
|
||||
func WorkspaceProxyParam(r *http.Request) database.WorkspaceProxy {
|
||||
user, ok := r.Context().Value(workspaceProxyParamContextKey{}).(database.WorkspaceProxy)
|
||||
if !ok {
|
||||
panic("developer error: workspace proxy parameter middleware not provided")
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
// ExtractWorkspaceProxyParam extracts a workspace proxy from an ID/name in the {workspaceproxy} URL
|
||||
// parameter.
|
||||
//
|
||||
//nolint:revive
|
||||
func ExtractWorkspaceProxyParam(db database.Store) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
proxyQuery := chi.URLParam(r, "workspaceproxy")
|
||||
if proxyQuery == "" {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "\"workspaceproxy\" must be provided.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var proxy database.WorkspaceProxy
|
||||
var dbErr error
|
||||
if proxyID, err := uuid.Parse(proxyQuery); err == nil {
|
||||
proxy, dbErr = db.GetWorkspaceProxyByID(ctx, proxyID)
|
||||
} else {
|
||||
proxy, dbErr = db.GetWorkspaceProxyByName(ctx, proxyQuery)
|
||||
}
|
||||
if httpapi.Is404Error(dbErr) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
if dbErr != nil {
|
||||
httpapi.InternalServerError(rw, dbErr)
|
||||
return
|
||||
}
|
||||
|
||||
ctx = context.WithValue(ctx, workspaceProxyParamContextKey{}, proxy)
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -160,4 +161,106 @@ func TestExtractWorkspaceProxy(t *testing.T) {
|
||||
defer res.Body.Close()
|
||||
require.Equal(t, http.StatusOK, res.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("Deleted", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var (
|
||||
db = dbfake.New()
|
||||
r = httptest.NewRequest("GET", "/", nil)
|
||||
rw = httptest.NewRecorder()
|
||||
|
||||
proxy, secret = dbgen.WorkspaceProxy(t, db, database.WorkspaceProxy{})
|
||||
)
|
||||
err := db.UpdateWorkspaceProxyDeleted(context.Background(), database.UpdateWorkspaceProxyDeletedParams{
|
||||
ID: proxy.ID,
|
||||
Deleted: true,
|
||||
})
|
||||
require.NoError(t, err, "failed to delete workspace proxy")
|
||||
|
||||
r.Header.Set(httpmw.WorkspaceProxyAuthTokenHeader, fmt.Sprintf("%s:%s", proxy.ID.String(), secret))
|
||||
|
||||
httpmw.ExtractWorkspaceProxy(httpmw.ExtractWorkspaceProxyConfig{
|
||||
DB: db,
|
||||
})(successHandler).ServeHTTP(rw, r)
|
||||
res := rw.Result()
|
||||
defer res.Body.Close()
|
||||
require.Equal(t, http.StatusUnauthorized, res.StatusCode)
|
||||
})
|
||||
}
|
||||
|
||||
func TestExtractWorkspaceProxyParam(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
successHandler := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
// Only called if the API key passes through the handler.
|
||||
httpapi.Write(context.Background(), rw, http.StatusOK, codersdk.Response{
|
||||
Message: "It worked!",
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("OKName", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var (
|
||||
db = dbfake.New()
|
||||
r = httptest.NewRequest("GET", "/", nil)
|
||||
rw = httptest.NewRecorder()
|
||||
|
||||
proxy, _ = dbgen.WorkspaceProxy(t, db, database.WorkspaceProxy{})
|
||||
)
|
||||
|
||||
routeContext := chi.NewRouteContext()
|
||||
routeContext.URLParams.Add("workspaceproxy", proxy.Name)
|
||||
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, routeContext))
|
||||
|
||||
httpmw.ExtractWorkspaceProxyParam(db)(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
// Checks that it exists on the context!
|
||||
_ = httpmw.WorkspaceProxyParam(request)
|
||||
successHandler.ServeHTTP(writer, request)
|
||||
})).ServeHTTP(rw, r)
|
||||
res := rw.Result()
|
||||
defer res.Body.Close()
|
||||
require.Equal(t, http.StatusOK, res.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("OKID", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var (
|
||||
db = dbfake.New()
|
||||
r = httptest.NewRequest("GET", "/", nil)
|
||||
rw = httptest.NewRecorder()
|
||||
|
||||
proxy, _ = dbgen.WorkspaceProxy(t, db, database.WorkspaceProxy{})
|
||||
)
|
||||
|
||||
routeContext := chi.NewRouteContext()
|
||||
routeContext.URLParams.Add("workspaceproxy", proxy.ID.String())
|
||||
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, routeContext))
|
||||
|
||||
httpmw.ExtractWorkspaceProxyParam(db)(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
// Checks that it exists on the context!
|
||||
_ = httpmw.WorkspaceProxyParam(request)
|
||||
successHandler.ServeHTTP(writer, request)
|
||||
})).ServeHTTP(rw, r)
|
||||
res := rw.Result()
|
||||
defer res.Body.Close()
|
||||
require.Equal(t, http.StatusOK, res.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("NotFound", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var (
|
||||
db = dbfake.New()
|
||||
r = httptest.NewRequest("GET", "/", nil)
|
||||
rw = httptest.NewRecorder()
|
||||
)
|
||||
|
||||
routeContext := chi.NewRouteContext()
|
||||
routeContext.URLParams.Add("workspaceproxy", uuid.NewString())
|
||||
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, routeContext))
|
||||
|
||||
httpmw.ExtractWorkspaceProxyParam(db)(successHandler).ServeHTTP(rw, r)
|
||||
res := rw.Result()
|
||||
defer res.Body.Close()
|
||||
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -54,6 +54,10 @@ func (t SignedToken) MatchesRequest(req Request) bool {
|
||||
// two keys.
|
||||
type SecurityKey [96]byte
|
||||
|
||||
func (k SecurityKey) String() string {
|
||||
return hex.EncodeToString(k[:])
|
||||
}
|
||||
|
||||
func (k SecurityKey) signingKey() []byte {
|
||||
return k[:64]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user