feat: add endpoint for fetching workspace proxy keys (#14789)

This commit is contained in:
Jon Ayers
2024-09-26 21:01:49 +01:00
committed by GitHub
parent 5c977c6be7
commit 3fdeaf7b24
17 changed files with 547 additions and 0 deletions
+72
View File
@@ -7540,6 +7540,34 @@ const docTemplate = `{
}
}
},
"/workspaceproxies/me/crypto-keys": {
"get": {
"security": [
{
"CoderSessionToken": []
}
],
"produces": [
"application/json"
],
"tags": [
"Enterprise"
],
"summary": "Get workspace proxy crypto keys",
"operationId": "get-workspace-proxy-crypto-keys",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/wsproxysdk.CryptoKeysResponse"
}
}
},
"x-apidocgen": {
"skip": true
}
}
},
"/workspaceproxies/me/deregister": {
"post": {
"security": [
@@ -15955,6 +15983,50 @@ const docTemplate = `{
}
}
},
"wsproxysdk.CryptoKey": {
"type": "object",
"properties": {
"deletes_at": {
"type": "string"
},
"feature": {
"$ref": "#/definitions/wsproxysdk.CryptoKeyFeature"
},
"secret": {
"type": "string"
},
"sequence": {
"type": "integer"
},
"starts_at": {
"type": "string"
}
}
},
"wsproxysdk.CryptoKeyFeature": {
"type": "string",
"enum": [
"workspace_apps",
"oidc_convert",
"tailnet_resume"
],
"x-enum-varnames": [
"CryptoKeyFeatureWorkspaceApp",
"CryptoKeyFeatureOIDCConvert",
"CryptoKeyFeatureTailnetResume"
]
},
"wsproxysdk.CryptoKeysResponse": {
"type": "object",
"properties": {
"crypto_keys": {
"type": "array",
"items": {
"$ref": "#/definitions/wsproxysdk.CryptoKey"
}
}
}
},
"wsproxysdk.DeregisterWorkspaceProxyRequest": {
"type": "object",
"properties": {
+64
View File
@@ -6668,6 +6668,30 @@
}
}
},
"/workspaceproxies/me/crypto-keys": {
"get": {
"security": [
{
"CoderSessionToken": []
}
],
"produces": ["application/json"],
"tags": ["Enterprise"],
"summary": "Get workspace proxy crypto keys",
"operationId": "get-workspace-proxy-crypto-keys",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/wsproxysdk.CryptoKeysResponse"
}
}
},
"x-apidocgen": {
"skip": true
}
}
},
"/workspaceproxies/me/deregister": {
"post": {
"security": [
@@ -14590,6 +14614,46 @@
}
}
},
"wsproxysdk.CryptoKey": {
"type": "object",
"properties": {
"deletes_at": {
"type": "string"
},
"feature": {
"$ref": "#/definitions/wsproxysdk.CryptoKeyFeature"
},
"secret": {
"type": "string"
},
"sequence": {
"type": "integer"
},
"starts_at": {
"type": "string"
}
}
},
"wsproxysdk.CryptoKeyFeature": {
"type": "string",
"enum": ["workspace_apps", "oidc_convert", "tailnet_resume"],
"x-enum-varnames": [
"CryptoKeyFeatureWorkspaceApp",
"CryptoKeyFeatureOIDCConvert",
"CryptoKeyFeatureTailnetResume"
]
},
"wsproxysdk.CryptoKeysResponse": {
"type": "object",
"properties": {
"crypto_keys": {
"type": "array",
"items": {
"$ref": "#/definitions/wsproxysdk.CryptoKey"
}
}
}
},
"wsproxysdk.DeregisterWorkspaceProxyRequest": {
"type": "object",
"properties": {
+7
View File
@@ -1405,6 +1405,13 @@ func (q *querier) GetCryptoKeys(ctx context.Context) ([]database.CryptoKey, erro
return q.db.GetCryptoKeys(ctx)
}
func (q *querier) GetCryptoKeysByFeature(ctx context.Context, feature database.CryptoKeyFeature) ([]database.CryptoKey, error) {
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceCryptoKey); err != nil {
return nil, err
}
return q.db.GetCryptoKeysByFeature(ctx, feature)
}
func (q *querier) GetDBCryptKeys(ctx context.Context) ([]database.DBCryptKey, error) {
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
return nil, err
+4
View File
@@ -2302,6 +2302,10 @@ func (s *MethodTestSuite) TestCryptoKeys() {
DeletesAt: sql.NullTime{Time: time.Now(), Valid: true},
}).Asserts(rbac.ResourceCryptoKey, policy.ActionUpdate)
}))
s.Run("GetCryptoKeysByFeature", s.Subtest(func(db database.Store, check *expects) {
check.Args(database.CryptoKeyFeatureWorkspaceApps).
Asserts(rbac.ResourceCryptoKey, policy.ActionRead)
}))
}
func (s *MethodTestSuite) TestSystemFunctions() {
+17
View File
@@ -2429,6 +2429,23 @@ func (q *FakeQuerier) GetCryptoKeys(_ context.Context) ([]database.CryptoKey, er
return keys, nil
}
func (q *FakeQuerier) GetCryptoKeysByFeature(_ context.Context, feature database.CryptoKeyFeature) ([]database.CryptoKey, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
keys := make([]database.CryptoKey, 0)
for _, key := range q.cryptoKeys {
if key.Feature == feature && key.Secret.Valid {
keys = append(keys, key)
}
}
// We want to return the highest sequence number first.
slices.SortFunc(keys, func(i, j database.CryptoKey) int {
return int(j.Sequence - i.Sequence)
})
return keys, nil
}
func (q *FakeQuerier) GetDBCryptKeys(_ context.Context) ([]database.DBCryptKey, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
+7
View File
@@ -564,6 +564,13 @@ func (m metricsStore) GetCryptoKeys(ctx context.Context) ([]database.CryptoKey,
return r0, r1
}
func (m metricsStore) GetCryptoKeysByFeature(ctx context.Context, feature database.CryptoKeyFeature) ([]database.CryptoKey, error) {
start := time.Now()
r0, r1 := m.s.GetCryptoKeysByFeature(ctx, feature)
m.queryLatencies.WithLabelValues("GetCryptoKeysByFeature").Observe(time.Since(start).Seconds())
return r0, r1
}
func (m metricsStore) GetDBCryptKeys(ctx context.Context) ([]database.DBCryptKey, error) {
start := time.Now()
r0, r1 := m.s.GetDBCryptKeys(ctx)
+15
View File
@@ -1103,6 +1103,21 @@ func (mr *MockStoreMockRecorder) GetCryptoKeys(arg0 any) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCryptoKeys", reflect.TypeOf((*MockStore)(nil).GetCryptoKeys), arg0)
}
// GetCryptoKeysByFeature mocks base method.
func (m *MockStore) GetCryptoKeysByFeature(arg0 context.Context, arg1 database.CryptoKeyFeature) ([]database.CryptoKey, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetCryptoKeysByFeature", arg0, arg1)
ret0, _ := ret[0].([]database.CryptoKey)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetCryptoKeysByFeature indicates an expected call of GetCryptoKeysByFeature.
func (mr *MockStoreMockRecorder) GetCryptoKeysByFeature(arg0, arg1 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCryptoKeysByFeature", reflect.TypeOf((*MockStore)(nil).GetCryptoKeysByFeature), arg0, arg1)
}
// GetDBCryptKeys mocks base method.
func (m *MockStore) GetDBCryptKeys(arg0 context.Context) ([]database.DBCryptKey, error) {
m.ctrl.T.Helper()
+1
View File
@@ -134,6 +134,7 @@ type sqlcQuerier interface {
GetCoordinatorResumeTokenSigningKey(ctx context.Context) (string, error)
GetCryptoKeyByFeatureAndSequence(ctx context.Context, arg GetCryptoKeyByFeatureAndSequenceParams) (CryptoKey, error)
GetCryptoKeys(ctx context.Context) ([]CryptoKey, error)
GetCryptoKeysByFeature(ctx context.Context, feature CryptoKeyFeature) ([]CryptoKey, error)
GetDBCryptKeys(ctx context.Context) ([]DBCryptKey, error)
GetDERPMeshKey(ctx context.Context) (string, error)
GetDefaultOrganization(ctx context.Context) (Organization, error)
+38
View File
@@ -849,6 +849,44 @@ func (q *sqlQuerier) GetCryptoKeys(ctx context.Context) ([]CryptoKey, error) {
return items, nil
}
const getCryptoKeysByFeature = `-- name: GetCryptoKeysByFeature :many
SELECT feature, sequence, secret, secret_key_id, starts_at, deletes_at
FROM crypto_keys
WHERE feature = $1
AND secret IS NOT NULL
ORDER BY sequence DESC
`
func (q *sqlQuerier) GetCryptoKeysByFeature(ctx context.Context, feature CryptoKeyFeature) ([]CryptoKey, error) {
rows, err := q.db.QueryContext(ctx, getCryptoKeysByFeature, feature)
if err != nil {
return nil, err
}
defer rows.Close()
var items []CryptoKey
for rows.Next() {
var i CryptoKey
if err := rows.Scan(
&i.Feature,
&i.Sequence,
&i.Secret,
&i.SecretKeyID,
&i.StartsAt,
&i.DeletesAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getLatestCryptoKeyByFeature = `-- name: GetLatestCryptoKeyByFeature :one
SELECT feature, sequence, secret, secret_key_id, starts_at, deletes_at
FROM crypto_keys
+7
View File
@@ -3,6 +3,13 @@ SELECT *
FROM crypto_keys
WHERE secret IS NOT NULL;
-- name: GetCryptoKeysByFeature :many
SELECT *
FROM crypto_keys
WHERE feature = $1
AND secret IS NOT NULL
ORDER BY sequence DESC;
-- name: GetLatestCryptoKeyByFeature :one
SELECT *
FROM crypto_keys