diff --git a/cli/server_internal_test.go b/cli/server_internal_test.go
index 3224059e1ec51..4adb85cc64a7d 100644
--- a/cli/server_internal_test.go
+++ b/cli/server_internal_test.go
@@ -254,7 +254,7 @@ func TestIsDERPPath(t *testing.T) {
//{
// path: "/derp",
// expected: true,
- //},
+ // },
{
path: "/derp/",
expected: true,
diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go
index 095f16d223f22..74537c0f7a483 100644
--- a/coderd/apidoc/docs.go
+++ b/coderd/apidoc/docs.go
@@ -11898,6 +11898,9 @@ const docTemplate = `{
"type": "string",
"format": "date-time"
},
+ "version": {
+ "type": "string"
+ },
"wildcard_hostname": {
"description": "WildcardHostname is the wildcard hostname for subdomain apps.\nE.g. *.us.example.com\nE.g. *--suffix.au.example.com\nOptional. Does not need to be on the same domain as PathAppURL.",
"type": "string"
diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json
index 927c9b32e3986..cf00313832900 100644
--- a/coderd/apidoc/swagger.json
+++ b/coderd/apidoc/swagger.json
@@ -10827,6 +10827,9 @@
"type": "string",
"format": "date-time"
},
+ "version": {
+ "type": "string"
+ },
"wildcard_hostname": {
"description": "WildcardHostname is the wildcard hostname for subdomain apps.\nE.g. *.us.example.com\nE.g. *--suffix.au.example.com\nOptional. Does not need to be on the same domain as PathAppURL.",
"type": "string"
diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go
index 1837c6f2588b5..aaf8914faa273 100644
--- a/coderd/database/dbmem/dbmem.go
+++ b/coderd/database/dbmem/dbmem.go
@@ -5563,6 +5563,7 @@ func (q *FakeQuerier) RegisterWorkspaceProxy(_ context.Context, arg database.Reg
p.WildcardHostname = arg.WildcardHostname
p.DerpEnabled = arg.DerpEnabled
p.DerpOnly = arg.DerpOnly
+ p.Version = arg.Version
p.UpdatedAt = dbtime.Now()
q.workspaceProxies[i] = p
return p, nil
diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql
index a475d82f3d805..73340b6f1371a 100644
--- a/coderd/database/dump.sql
+++ b/coderd/database/dump.sql
@@ -1127,7 +1127,8 @@ CREATE TABLE workspace_proxies (
token_hashed_secret bytea NOT NULL,
region_id integer NOT NULL,
derp_enabled boolean DEFAULT true NOT NULL,
- derp_only boolean DEFAULT false NOT NULL
+ derp_only boolean DEFAULT false NOT NULL,
+ version text DEFAULT ''::text NOT NULL
);
COMMENT ON COLUMN workspace_proxies.icon IS 'Expects an emoji character. (/emojis/1f1fa-1f1f8.png)';
diff --git a/coderd/database/migrations/000170_workspaceproxy_version.down.sql b/coderd/database/migrations/000170_workspaceproxy_version.down.sql
new file mode 100644
index 0000000000000..55810705b0152
--- /dev/null
+++ b/coderd/database/migrations/000170_workspaceproxy_version.down.sql
@@ -0,0 +1,3 @@
+BEGIN;
+ALTER TABLE workspace_proxies DROP COLUMN version;
+COMMIT;
diff --git a/coderd/database/migrations/000170_workspaceproxy_version.up.sql b/coderd/database/migrations/000170_workspaceproxy_version.up.sql
new file mode 100644
index 0000000000000..a7e3519126c2e
--- /dev/null
+++ b/coderd/database/migrations/000170_workspaceproxy_version.up.sql
@@ -0,0 +1,3 @@
+BEGIN;
+ALTER TABLE workspace_proxies ADD COLUMN version TEXT DEFAULT ''::TEXT NOT NULL;
+COMMIT;
diff --git a/coderd/database/models.go b/coderd/database/models.go
index 8ab3417dd6406..3170dc2562548 100644
--- a/coderd/database/models.go
+++ b/coderd/database/models.go
@@ -2364,7 +2364,8 @@ type WorkspaceProxy struct {
RegionID int32 `db:"region_id" json:"region_id"`
DerpEnabled bool `db:"derp_enabled" json:"derp_enabled"`
// Disables app/terminal proxying for this proxy and only acts as a DERP relay.
- DerpOnly bool `db:"derp_only" json:"derp_only"`
+ DerpOnly bool `db:"derp_only" json:"derp_only"`
+ Version string `db:"version" json:"version"`
}
type WorkspaceResource struct {
diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go
index 842b05380258e..09f36c69b848b 100644
--- a/coderd/database/queries.sql.go
+++ b/coderd/database/queries.sql.go
@@ -3667,7 +3667,7 @@ func (q *sqlQuerier) UpdateProvisionerJobWithCompleteByID(ctx context.Context, a
const getWorkspaceProxies = `-- name: GetWorkspaceProxies :many
SELECT
- id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only
+ id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version
FROM
workspace_proxies
WHERE
@@ -3697,6 +3697,7 @@ func (q *sqlQuerier) GetWorkspaceProxies(ctx context.Context) ([]WorkspaceProxy,
&i.RegionID,
&i.DerpEnabled,
&i.DerpOnly,
+ &i.Version,
); err != nil {
return nil, err
}
@@ -3713,7 +3714,7 @@ func (q *sqlQuerier) GetWorkspaceProxies(ctx context.Context) ([]WorkspaceProxy,
const getWorkspaceProxyByHostname = `-- name: GetWorkspaceProxyByHostname :one
SELECT
- id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only
+ id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version
FROM
workspace_proxies
WHERE
@@ -3772,13 +3773,14 @@ func (q *sqlQuerier) GetWorkspaceProxyByHostname(ctx context.Context, arg GetWor
&i.RegionID,
&i.DerpEnabled,
&i.DerpOnly,
+ &i.Version,
)
return i, err
}
const getWorkspaceProxyByID = `-- name: GetWorkspaceProxyByID :one
SELECT
- id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only
+ id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version
FROM
workspace_proxies
WHERE
@@ -3804,13 +3806,14 @@ func (q *sqlQuerier) GetWorkspaceProxyByID(ctx context.Context, id uuid.UUID) (W
&i.RegionID,
&i.DerpEnabled,
&i.DerpOnly,
+ &i.Version,
)
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, region_id, derp_enabled, derp_only
+ id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version
FROM
workspace_proxies
WHERE
@@ -3837,6 +3840,7 @@ func (q *sqlQuerier) GetWorkspaceProxyByName(ctx context.Context, name string) (
&i.RegionID,
&i.DerpEnabled,
&i.DerpOnly,
+ &i.Version,
)
return i, err
}
@@ -3858,7 +3862,7 @@ INSERT INTO
deleted
)
VALUES
- ($1, '', '', $2, $3, $4, $5, $6, $7, $8, $9, false) RETURNING id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only
+ ($1, '', '', $2, $3, $4, $5, $6, $7, $8, $9, false) RETURNING id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version
`
type InsertWorkspaceProxyParams struct {
@@ -3900,6 +3904,7 @@ func (q *sqlQuerier) InsertWorkspaceProxy(ctx context.Context, arg InsertWorkspa
&i.RegionID,
&i.DerpEnabled,
&i.DerpOnly,
+ &i.Version,
)
return i, err
}
@@ -3912,10 +3917,11 @@ SET
wildcard_hostname = $2 :: text,
derp_enabled = $3 :: boolean,
derp_only = $4 :: boolean,
+ version = $5 :: text,
updated_at = Now()
WHERE
- id = $5
-RETURNING id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only
+ id = $6
+RETURNING id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version
`
type RegisterWorkspaceProxyParams struct {
@@ -3923,6 +3929,7 @@ type RegisterWorkspaceProxyParams struct {
WildcardHostname string `db:"wildcard_hostname" json:"wildcard_hostname"`
DerpEnabled bool `db:"derp_enabled" json:"derp_enabled"`
DerpOnly bool `db:"derp_only" json:"derp_only"`
+ Version string `db:"version" json:"version"`
ID uuid.UUID `db:"id" json:"id"`
}
@@ -3932,6 +3939,7 @@ func (q *sqlQuerier) RegisterWorkspaceProxy(ctx context.Context, arg RegisterWor
arg.WildcardHostname,
arg.DerpEnabled,
arg.DerpOnly,
+ arg.Version,
arg.ID,
)
var i WorkspaceProxy
@@ -3949,6 +3957,7 @@ func (q *sqlQuerier) RegisterWorkspaceProxy(ctx context.Context, arg RegisterWor
&i.RegionID,
&i.DerpEnabled,
&i.DerpOnly,
+ &i.Version,
)
return i, err
}
@@ -3971,7 +3980,7 @@ SET
updated_at = Now()
WHERE
id = $5
-RETURNING id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only
+RETURNING id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version
`
type UpdateWorkspaceProxyParams struct {
@@ -4006,6 +4015,7 @@ func (q *sqlQuerier) UpdateWorkspaceProxy(ctx context.Context, arg UpdateWorkspa
&i.RegionID,
&i.DerpEnabled,
&i.DerpOnly,
+ &i.Version,
)
return i, err
}
diff --git a/coderd/database/queries/proxies.sql b/coderd/database/queries/proxies.sql
index f43ac6465ca6f..df59d3baf107f 100644
--- a/coderd/database/queries/proxies.sql
+++ b/coderd/database/queries/proxies.sql
@@ -25,6 +25,7 @@ SET
wildcard_hostname = @wildcard_hostname :: text,
derp_enabled = @derp_enabled :: boolean,
derp_only = @derp_only :: boolean,
+ version = @version :: text,
updated_at = Now()
WHERE
id = @id
diff --git a/codersdk/workspaceproxy.go b/codersdk/workspaceproxy.go
index efdc3cc93c57d..0340e2f23f408 100644
--- a/codersdk/workspaceproxy.go
+++ b/codersdk/workspaceproxy.go
@@ -59,6 +59,7 @@ type WorkspaceProxy struct {
CreatedAt time.Time `json:"created_at" format:"date-time" table:"created_at,default_sort"`
UpdatedAt time.Time `json:"updated_at" format:"date-time" table:"updated_at"`
Deleted bool `json:"deleted" table:"deleted"`
+ Version string `json:"version" table:"version"`
}
type CreateWorkspaceProxyRequest struct {
diff --git a/docs/admin/audit-logs.md b/docs/admin/audit-logs.md
index 69c61ad69deed..09ad0aae5bc80 100644
--- a/docs/admin/audit-logs.md
+++ b/docs/admin/audit-logs.md
@@ -20,7 +20,7 @@ We track the following resources:
| User
create, write, delete |
Field | Tracked |
---|
avatar_url | false |
created_at | false |
deleted | true |
email | true |
hashed_password | true |
id | true |
last_seen_at | false |
login_type | true |
quiet_hours_schedule | true |
rbac_roles | true |
status | true |
updated_at | false |
username | true |
|
| Workspace
create, write, delete | Field | Tracked |
---|
automatic_updates | true |
autostart_schedule | true |
created_at | false |
deleted | false |
deleting_at | true |
dormant_at | true |
id | true |
last_used_at | false |
name | true |
organization_id | false |
owner_id | true |
template_id | true |
ttl | true |
updated_at | false |
|
| WorkspaceBuild
start, stop | Field | Tracked |
---|
build_number | false |
created_at | false |
daily_cost | false |
deadline | false |
id | false |
initiator_by_avatar_url | false |
initiator_by_username | false |
initiator_id | false |
job_id | false |
max_deadline | false |
provisioner_state | false |
reason | false |
template_version_id | true |
transition | false |
updated_at | false |
workspace_id | false |
|
-| WorkspaceProxy
| Field | Tracked |
---|
created_at | true |
deleted | false |
derp_enabled | true |
derp_only | true |
display_name | true |
icon | true |
id | true |
name | true |
region_id | true |
token_hashed_secret | true |
updated_at | false |
url | true |
wildcard_hostname | true |
|
+| WorkspaceProxy
| Field | Tracked |
---|
created_at | true |
deleted | false |
derp_enabled | true |
derp_only | true |
display_name | true |
icon | true |
id | true |
name | true |
region_id | true |
token_hashed_secret | true |
updated_at | false |
url | true |
version | true |
wildcard_hostname | true |
|
diff --git a/docs/api/enterprise.md b/docs/api/enterprise.md
index 743fbc19fd532..e25b48aedb34a 100644
--- a/docs/api/enterprise.md
+++ b/docs/api/enterprise.md
@@ -1513,6 +1513,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaceproxies \
"status": "ok"
},
"updated_at": "2019-08-24T14:15:22Z",
+ "version": "string",
"wildcard_hostname": "string"
}
]
@@ -1551,6 +1552,7 @@ Status Code **200**
| `»»»» warnings` | array | false | | Warnings do not prevent the workspace proxy from being healthy, but should be addressed. |
| `»»» status` | [codersdk.ProxyHealthStatus](schemas.md#codersdkproxyhealthstatus) | false | | |
| `»» updated_at` | string(date-time) | false | | |
+| `»» version` | string | false | | |
| `»» wildcard_hostname` | string | false | | Wildcard hostname is the wildcard hostname for subdomain apps. E.g. _.us.example.com E.g. _--suffix.au.example.com Optional. Does not need to be on the same domain as PathAppURL. |
#### Enumerated Values
@@ -1619,6 +1621,7 @@ curl -X POST http://coder-server:8080/api/v2/workspaceproxies \
"status": "ok"
},
"updated_at": "2019-08-24T14:15:22Z",
+ "version": "string",
"wildcard_hostname": "string"
}
```
@@ -1675,6 +1678,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaceproxies/{workspaceproxy} \
"status": "ok"
},
"updated_at": "2019-08-24T14:15:22Z",
+ "version": "string",
"wildcard_hostname": "string"
}
```
@@ -1789,6 +1793,7 @@ curl -X PATCH http://coder-server:8080/api/v2/workspaceproxies/{workspaceproxy}
"status": "ok"
},
"updated_at": "2019-08-24T14:15:22Z",
+ "version": "string",
"wildcard_hostname": "string"
}
```
diff --git a/docs/api/schemas.md b/docs/api/schemas.md
index c2d31f83c4297..544403777a085 100644
--- a/docs/api/schemas.md
+++ b/docs/api/schemas.md
@@ -4086,6 +4086,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
"status": "ok"
},
"updated_at": "2019-08-24T14:15:22Z",
+ "version": "string",
"wildcard_hostname": "string"
}
]
@@ -6649,6 +6650,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
"status": "ok"
},
"updated_at": "2019-08-24T14:15:22Z",
+ "version": "string",
"wildcard_hostname": "string"
}
```
@@ -6669,6 +6671,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
| `path_app_url` | string | false | | Path app URL is the URL to the base path for path apps. Optional unless wildcard_hostname is set. E.g. https://us.example.com |
| `status` | [codersdk.WorkspaceProxyStatus](#codersdkworkspaceproxystatus) | false | | Status is the latest status check of the proxy. This will be empty for deleted proxies. This value can be used to determine if a workspace proxy is healthy and ready to use. |
| `updated_at` | string | false | | |
+| `version` | string | false | | |
| `wildcard_hostname` | string | false | | Wildcard hostname is the wildcard hostname for subdomain apps. E.g. _.us.example.com E.g. _--suffix.au.example.com Optional. Does not need to be on the same domain as PathAppURL. |
## codersdk.WorkspaceProxyStatus
diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go
index e49432091d6db..085f4ac581a9e 100644
--- a/enterprise/audit/table.go
+++ b/enterprise/audit/table.go
@@ -207,6 +207,7 @@ var auditableResourcesTypes = map[any]map[string]Action{
"derp_enabled": ActionTrack,
"derp_only": ActionTrack,
"region_id": ActionTrack,
+ "version": ActionTrack,
},
}
diff --git a/enterprise/coderd/proxyhealth/proxyhealth_test.go b/enterprise/coderd/proxyhealth/proxyhealth_test.go
index 6f20c1e48ebef..fad5601bf3a71 100644
--- a/enterprise/coderd/proxyhealth/proxyhealth_test.go
+++ b/enterprise/coderd/proxyhealth/proxyhealth_test.go
@@ -31,6 +31,7 @@ func insertProxy(t *testing.T, db database.Store, url string) database.Workspace
Url: url,
WildcardHostname: "",
ID: proxy.ID,
+ Version: `v2.34.5-test+beefcake`,
})
require.NoError(t, err, "failed to update proxy")
return proxy
diff --git a/enterprise/coderd/workspaceproxy.go b/enterprise/coderd/workspaceproxy.go
index 49f0849b951b7..eaef17542c6bd 100644
--- a/enterprise/coderd/workspaceproxy.go
+++ b/enterprise/coderd/workspaceproxy.go
@@ -625,6 +625,7 @@ func (api *API) workspaceProxyRegister(rw http.ResponseWriter, r *http.Request)
DerpEnabled: req.DerpEnabled,
DerpOnly: req.DerpOnly,
WildcardHostname: req.WildcardHostname,
+ Version: req.Version,
})
if err != nil {
return xerrors.Errorf("register workspace proxy: %w", err)
@@ -951,6 +952,7 @@ func convertProxy(p database.WorkspaceProxy, status proxyhealth.ProxyStatus) cod
CreatedAt: p.CreatedAt,
UpdatedAt: p.UpdatedAt,
Deleted: p.Deleted,
+ Version: p.Version,
Status: codersdk.WorkspaceProxyStatus{
Status: codersdk.ProxyHealthStatus(status.Status),
Report: status.Report,
diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts
index 27a5687a9db36..51921fd729e26 100644
--- a/site/src/api/typesGenerated.ts
+++ b/site/src/api/typesGenerated.ts
@@ -1581,6 +1581,7 @@ export interface WorkspaceProxy extends Region {
readonly created_at: string;
readonly updated_at: string;
readonly deleted: boolean;
+ readonly version: string;
}
// From codersdk/deployment.go
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts
index ba8dc0458918a..9aeb3560ce961 100644
--- a/site/src/testHelpers/entities.ts
+++ b/site/src/testHelpers/entities.ts
@@ -85,6 +85,7 @@ export const MockPrimaryWorkspaceProxy: TypesGen.WorkspaceProxy = {
derp_only: false,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
+ version: "v2.34.5-test+primary",
deleted: false,
status: {
status: "ok",
@@ -105,6 +106,7 @@ export const MockHealthyWildWorkspaceProxy: TypesGen.WorkspaceProxy = {
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
deleted: false,
+ version: "v2.34.5-test+haswildcard",
status: {
status: "ok",
checked_at: new Date().toISOString(),
@@ -123,6 +125,7 @@ export const MockUnhealthyWildWorkspaceProxy: TypesGen.WorkspaceProxy = {
derp_only: true,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
+ version: "v2.34.5-test+unhealthy",
deleted: false,
status: {
status: "unhealthy",
@@ -151,6 +154,7 @@ export const MockWorkspaceProxies: TypesGen.WorkspaceProxy[] = [
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
deleted: false,
+ version: "v2.34.5-test+nowildcard",
status: {
status: "ok",
checked_at: new Date().toISOString(),