Skip to content

Commit 9a878fa

Browse files
committed
Merge branch 'main' into paginate-users/presleyp
2 parents 5715d38 + 820306a commit 9a878fa

22 files changed

+192
-75
lines changed

agent/agent_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"os"
1212
"os/exec"
1313
"os/user"
14+
"path"
1415
"path/filepath"
1516
"runtime"
1617
"strconv"
@@ -231,7 +232,13 @@ func TestAgent(t *testing.T) {
231232
require.NoError(t, err, "get working directory")
232233
require.Equal(t, home, wd, "working directory should be home user home")
233234
tempFile := filepath.Join(t.TempDir(), "sftp")
234-
file, err := client.Create(tempFile)
235+
// SFTP only accepts unix-y paths.
236+
remoteFile := filepath.ToSlash(tempFile)
237+
if !path.IsAbs(remoteFile) {
238+
// On Windows, e.g. "/C:/Users/...".
239+
remoteFile = path.Join("/", remoteFile)
240+
}
241+
file, err := client.Create(remoteFile)
235242
require.NoError(t, err)
236243
err = file.Close()
237244
require.NoError(t, err)

coderd/audit.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,26 @@ func convertAuditLog(dblog database.GetAuditLogsOffsetRow) codersdk.AuditLog {
219219
}
220220
}
221221

222+
type WorkspaceResourceInfo struct {
223+
WorkspaceName string
224+
}
225+
222226
func auditLogDescription(alog database.GetAuditLogsOffsetRow) string {
223227
str := fmt.Sprintf("{user} %s %s",
224228
codersdk.AuditAction(alog.Action).FriendlyString(),
225229
codersdk.ResourceType(alog.ResourceType).FriendlyString(),
226230
)
227231

232+
// Strings for build updates follow the below format:
233+
// "{user} started workspace build for workspace {target}"
234+
// where target is a workspace instead of the workspace build
235+
if alog.ResourceType == database.ResourceTypeWorkspaceBuild {
236+
workspaceBytes := []byte(alog.AdditionalFields)
237+
var workspaceResourceInfo WorkspaceResourceInfo
238+
_ = json.Unmarshal(workspaceBytes, &workspaceResourceInfo)
239+
str += " for workspace " + workspaceResourceInfo.WorkspaceName
240+
}
241+
228242
// We don't display the name for git ssh keys. It's fairly long and doesn't
229243
// make too much sense to display.
230244
if alog.ResourceType != database.ResourceTypeGitSshKey {
@@ -288,6 +302,8 @@ func resourceTypeFromString(resourceTypeString string) string {
288302
return resourceTypeString
289303
case codersdk.ResourceTypeWorkspace:
290304
return resourceTypeString
305+
case codersdk.ResourceTypeWorkspaceBuild:
306+
return resourceTypeString
291307
case codersdk.ResourceTypeGitSSHKey:
292308
return resourceTypeString
293309
case codersdk.ResourceTypeAPIKey:

coderd/audit/diff.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ type Auditable interface {
1616
database.User |
1717
database.Workspace |
1818
database.GitSSHKey |
19-
database.Group
19+
database.Group |
20+
database.WorkspaceBuild
2021
}
2122

2223
// Map is a map of changed fields in an audited resource. It maps field names to

coderd/audit/request.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ type RequestParams struct {
2020
Audit Auditor
2121
Log slog.Logger
2222

23-
Request *http.Request
24-
Action database.AuditAction
23+
Request *http.Request
24+
Action database.AuditAction
25+
AdditionalFields json.RawMessage
2526
}
2627

2728
type Request[T Auditable] struct {
@@ -43,6 +44,9 @@ func ResourceTarget[T Auditable](tgt T) string {
4344
return typed.Username
4445
case database.Workspace:
4546
return typed.Name
47+
case database.WorkspaceBuild:
48+
// this isn't used
49+
return string(typed.BuildNumber)
4650
case database.GitSSHKey:
4751
return typed.PublicKey
4852
case database.Group:
@@ -64,6 +68,8 @@ func ResourceID[T Auditable](tgt T) uuid.UUID {
6468
return typed.ID
6569
case database.Workspace:
6670
return typed.ID
71+
case database.WorkspaceBuild:
72+
return typed.ID
6773
case database.GitSSHKey:
6874
return typed.UserID
6975
case database.Group:
@@ -85,6 +91,8 @@ func ResourceType[T Auditable](tgt T) database.ResourceType {
8591
return database.ResourceTypeUser
8692
case database.Workspace:
8793
return database.ResourceTypeWorkspace
94+
case database.WorkspaceBuild:
95+
return database.ResourceTypeWorkspaceBuild
8896
case database.GitSSHKey:
8997
return database.ResourceTypeGitSshKey
9098
case database.Group:
@@ -129,6 +137,10 @@ func InitRequest[T Auditable](w http.ResponseWriter, p *RequestParams) (*Request
129137
}
130138
}
131139

140+
if p.AdditionalFields == nil {
141+
p.AdditionalFields = json.RawMessage("{}")
142+
}
143+
132144
ip := parseIP(p.Request.RemoteAddr)
133145
err := p.Audit.Export(ctx, database.AuditLog{
134146
ID: uuid.New(),
@@ -143,7 +155,7 @@ func InitRequest[T Auditable](w http.ResponseWriter, p *RequestParams) (*Request
143155
Diff: diffRaw,
144156
StatusCode: int32(sw.Status),
145157
RequestID: httpmw.RequestID(p.Request),
146-
AdditionalFields: json.RawMessage("{}"),
158+
AdditionalFields: p.AdditionalFields,
147159
})
148160
if err != nil {
149161
p.Log.Error(logCtx, "export audit log", slog.Error(err))

coderd/database/dump.sql

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- It's not possible to drop enum values from enum types, so the UP has "IF NOT
2+
-- EXISTS".
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
ALTER TYPE audit_action ADD VALUE IF NOT EXISTS 'start';
2+
ALTER TYPE audit_action ADD VALUE IF NOT EXISTS 'stop';
3+
4+
ALTER TYPE resource_type ADD VALUE IF NOT EXISTS 'workspace_build';

coderd/database/models.go

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/workspacebuilds.go

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"golang.org/x/exp/slices"
1616
"golang.org/x/xerrors"
1717

18+
"cdr.dev/slog"
1819
"github.com/coder/coder/coderd/audit"
1920
"github.com/coder/coder/coderd/database"
2021
"github.com/coder/coder/coderd/httpapi"
@@ -278,28 +279,62 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
278279
return
279280
}
280281

281-
// we only want to create audit logs for delete builds right now
282+
auditor := api.Auditor.Load()
283+
284+
// if user deletes a workspace, audit the workspace
282285
if action == rbac.ActionDelete {
283-
var (
284-
auditor = api.Auditor.Load()
285-
aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{
286-
Audit: *auditor,
287-
Log: api.Logger,
288-
Request: r,
289-
Action: database.AuditActionDelete,
290-
})
291-
)
286+
aReq, commitAudit := audit.InitRequest[database.Workspace](rw, &audit.RequestParams{
287+
Audit: *auditor,
288+
Log: api.Logger,
289+
Request: r,
290+
Action: database.AuditActionDelete,
291+
})
292292

293293
defer commitAudit()
294294
aReq.Old = workspace
295295
}
296296

297-
if createBuild.TemplateVersionID == uuid.Nil {
298-
latestBuild, err := api.Database.GetLatestWorkspaceBuildByWorkspaceID(ctx, workspace.ID)
297+
latestBuild, latestBuildErr := api.Database.GetLatestWorkspaceBuildByWorkspaceID(ctx, workspace.ID)
298+
299+
// if a user starts/stops a workspace, audit the workspace build
300+
if action == rbac.ActionUpdate {
301+
var auditAction database.AuditAction
302+
if createBuild.Transition == codersdk.WorkspaceTransitionStart {
303+
auditAction = database.AuditActionStart
304+
} else if createBuild.Transition == codersdk.WorkspaceTransitionStop {
305+
auditAction = database.AuditActionStop
306+
} else {
307+
auditAction = database.AuditActionWrite
308+
}
309+
310+
// We pass the workspace name to the Auditor so that it
311+
// can form a friendly string for the user.
312+
workspaceResourceInfo := map[string]string{
313+
"workspaceName": workspace.Name,
314+
}
315+
316+
wriBytes, err := json.Marshal(workspaceResourceInfo)
299317
if err != nil {
318+
api.Logger.Error(ctx, "could not marshal workspace name", slog.Error(err))
319+
}
320+
321+
aReq, commitAudit := audit.InitRequest[database.WorkspaceBuild](rw, &audit.RequestParams{
322+
Audit: *auditor,
323+
Log: api.Logger,
324+
Request: r,
325+
Action: auditAction,
326+
AdditionalFields: wriBytes,
327+
})
328+
329+
defer commitAudit()
330+
aReq.Old = latestBuild
331+
}
332+
333+
if createBuild.TemplateVersionID == uuid.Nil {
334+
if latestBuildErr != nil {
300335
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
301336
Message: "Internal error fetching the latest workspace build.",
302-
Detail: err.Error(),
337+
Detail: latestBuildErr.Error(),
303338
})
304339
return
305340
}

coderd/workspacebuilds_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,6 @@ func TestWorkspaceBuildStatus(t *testing.T) {
579579
require.EqualValues(t, codersdk.WorkspaceStatusDeleted, workspace.LatestBuild.Status)
580580

581581
// assert an audit log has been created for deletion
582-
require.Len(t, auditor.AuditLogs, 5)
583-
assert.Equal(t, database.AuditActionDelete, auditor.AuditLogs[4].Action)
582+
require.Len(t, auditor.AuditLogs, 7)
583+
assert.Equal(t, database.AuditActionDelete, auditor.AuditLogs[6].Action)
584584
}

codersdk/audit.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const (
1919
ResourceTypeTemplateVersion ResourceType = "template_version"
2020
ResourceTypeUser ResourceType = "user"
2121
ResourceTypeWorkspace ResourceType = "workspace"
22+
ResourceTypeWorkspaceBuild ResourceType = "workspace_build"
2223
ResourceTypeGitSSHKey ResourceType = "git_ssh_key"
2324
ResourceTypeAPIKey ResourceType = "api_key"
2425
ResourceTypeGroup ResourceType = "group"
@@ -36,6 +37,8 @@ func (r ResourceType) FriendlyString() string {
3637
return "user"
3738
case ResourceTypeWorkspace:
3839
return "workspace"
40+
case ResourceTypeWorkspaceBuild:
41+
return "workspace build"
3942
case ResourceTypeGitSSHKey:
4043
return "git ssh key"
4144
case ResourceTypeAPIKey:
@@ -53,6 +56,8 @@ const (
5356
AuditActionCreate AuditAction = "create"
5457
AuditActionWrite AuditAction = "write"
5558
AuditActionDelete AuditAction = "delete"
59+
AuditActionStart AuditAction = "start"
60+
AuditActionStop AuditAction = "stop"
5661
)
5762

5863
func (a AuditAction) FriendlyString() string {
@@ -63,6 +68,10 @@ func (a AuditAction) FriendlyString() string {
6368
return "updated"
6469
case AuditActionDelete:
6570
return "deleted"
71+
case AuditActionStart:
72+
return "started"
73+
case AuditActionStop:
74+
return "stopped"
6675
default:
6776
return "unknown"
6877
}

dogfood/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
FROM rust:slim AS rust-utils
22
# Install rust helper programs
33
# ENV CARGO_NET_GIT_FETCH_WITH_CLI=true
4-
env CARGO_INSTALL_ROOT=/tmp/
4+
ENV CARGO_INSTALL_ROOT=/tmp/
55
RUN cargo install exa bat ripgrep typos-cli watchexec-cli
66

77
FROM ubuntu AS go

enterprise/audit/table.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,21 @@ var AuditableResources = auditMap(map[any]map[string]Action{
109109
"organization_id": ActionIgnore, // Never changes.
110110
"avatar_url": ActionTrack,
111111
},
112+
// We don't show any diff for the WorkspaceBuild resource
113+
&database.WorkspaceBuild{}: {
114+
"id": ActionIgnore,
115+
"created_at": ActionIgnore,
116+
"updated_at": ActionIgnore,
117+
"workspace_id": ActionIgnore,
118+
"template_version_id": ActionIgnore,
119+
"build_number": ActionIgnore,
120+
"transition": ActionIgnore,
121+
"initiator_id": ActionIgnore,
122+
"provisioner_state": ActionIgnore,
123+
"job_id": ActionIgnore,
124+
"deadline": ActionIgnore,
125+
"reason": ActionIgnore,
126+
},
112127
})
113128

114129
// auditMap converts a map of struct pointers to a map of struct names as

go.mod

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,6 @@ replace tailscale.com => github.com/coder/tailscale v1.1.1-0.20221015033036-5861
5151
// makes importing it directly a bit messy.
5252
replace github.com/gliderlabs/ssh => github.com/coder/ssh v0.0.0-20220811105153-fcea99919338
5353

54-
// The sftp server implementation used by us does not support changing
55-
// the working directory, this fork adds support for it.
56-
//
57-
// Attempt to upstream: https://github.com/pkg/sftp/pull/528
58-
replace github.com/pkg/sftp => github.com/mafredri/sftp v1.13.6-0.20221014125459-6a7168cf46fd
59-
6054
require (
6155
cdr.dev/slog v1.4.2-0.20220525200111-18dce5c2cd5f
6256
cloud.google.com/go/compute v1.10.0
@@ -119,7 +113,7 @@ require (
119113
github.com/pion/udp v0.1.1
120114
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
121115
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
122-
github.com/pkg/sftp v1.13.5
116+
github.com/pkg/sftp v1.13.6-0.20221018182125-7da137aa03f0
123117
github.com/prometheus/client_golang v1.13.0
124118
github.com/quasilyte/go-ruleguard/dsl v0.3.21
125119
github.com/robfig/cron/v3 v3.0.1

go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,8 +1230,6 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69
12301230
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
12311231
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
12321232
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
1233-
github.com/mafredri/sftp v1.13.6-0.20221014125459-6a7168cf46fd h1:X7ZK1YGbCoPkllDq/lG5PLV4k3LVddypzoH5hVgzmiw=
1234-
github.com/mafredri/sftp v1.13.6-0.20221014125459-6a7168cf46fd/go.mod h1:wHDZ0IZX6JcBYRK1TH9bcVq8G7TLpVHYIGJRFnmPfxg=
12351233
github.com/mafredri/udp v0.1.2-0.20220805105907-b2872e92e98d h1:E+lU8/1jcUd3guqaRvjAGCcwoPe7jcYrNv9K0OzEwdQ=
12361234
github.com/mafredri/udp v0.1.2-0.20220805105907-b2872e92e98d/go.mod h1:GUd681aT3Tj7pdNkUtqBz5pp/GLMGIaMI9Obq6+ob48=
12371235
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -1516,6 +1514,10 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
15161514
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
15171515
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
15181516
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
1517+
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
1518+
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
1519+
github.com/pkg/sftp v1.13.6-0.20221018182125-7da137aa03f0 h1:QJypP3NZEUt+ka49zyp/MSdpjjM9EYkg0WA1NZQaxT0=
1520+
github.com/pkg/sftp v1.13.6-0.20221018182125-7da137aa03f0/go.mod h1:wHDZ0IZX6JcBYRK1TH9bcVq8G7TLpVHYIGJRFnmPfxg=
15191521
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
15201522
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
15211523
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=

site/src/api/typesGenerated.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,7 @@ export interface WorkspacesRequest extends Pagination {
915915
export type APIKeyScope = "all" | "application_connect"
916916

917917
// From codersdk/audit.go
918-
export type AuditAction = "create" | "delete" | "write"
918+
export type AuditAction = "create" | "delete" | "start" | "stop" | "write"
919919

920920
// From codersdk/workspacebuilds.go
921921
export type BuildReason = "autostart" | "autostop" | "initiator"
@@ -975,6 +975,7 @@ export type ResourceType =
975975
| "template_version"
976976
| "user"
977977
| "workspace"
978+
| "workspace_build"
978979

979980
// From codersdk/sse.go
980981
export type ServerSentEventType = "data" | "error" | "ping"

0 commit comments

Comments
 (0)