Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add workspace auditing#3966

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
coadler merged 1 commit intomainfromcolin/workspace-auditing
Sep 10, 2022
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletioncoderd/users_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -391,7 +391,8 @@ func TestPostUsers(t *testing.T) {
Password: "testing",
})
require.NoError(t, err)
assert.Len(t, auditor.AuditLogs, 1)

require.Len(t, auditor.AuditLogs, 1)
assert.Equal(t, database.AuditActionCreate, auditor.AuditLogs[0].Action)
})
}
Expand Down
78 changes: 69 additions & 9 deletionscoderd/workspaces.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,7 @@ import (

"cdr.dev/slog"

"github.com/coder/coder/coderd/audit"
"github.com/coder/coder/coderd/autobuild/schedule"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/httpapi"
Expand DownExpand Up@@ -248,8 +249,18 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request)

// Create a new workspace for the currently authenticated user.
func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Request) {
organization := httpmw.OrganizationParam(r)
apiKey := httpmw.APIKey(r)
var (
organization = httpmw.OrganizationParam(r)
apiKey = httpmw.APIKey(r)
aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{
Features: api.FeaturesService,
Log: api.Logger,
Request: r,
Action: database.AuditActionCreate,
})
)
Comment on lines +252 to +261
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

It's shorter to not put these in a var block, so I'd rather have them out. What do you think?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I'm sorta partial to just having a var block at the top of each handler, I think it separates them cleanly from the actual code. Don't feel super strongly though, but I think it should be consistent.

defer commitAudit()

if !api.Authorize(r, rbac.ActionCreate,
rbac.ResourceWorkspace.InOrg(organization.ID).WithOwner(apiKey.UserID.String())) {
httpapi.ResourceNotFound(rw)
Expand DownExpand Up@@ -325,7 +336,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
})
return
}
if !errors.Is(err, sql.ErrNoRows) {
iferr != nil &&!errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
Message: fmt.Sprintf("Internal error fetching workspace by name %q.", createWorkspace.Name),
Detail: err.Error(),
Expand DownExpand Up@@ -457,6 +468,8 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
})
return
}
aReq.New = workspace

users, err := api.Database.GetUsersByIDs(r.Context(), []uuid.UUID{apiKey.UserID, workspaceBuild.InitiatorID})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
Expand All@@ -476,7 +489,18 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
}

func (api *API) patchWorkspace(rw http.ResponseWriter, r *http.Request) {
workspace := httpmw.WorkspaceParam(r)
var (
workspace = httpmw.WorkspaceParam(r)
aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{
Features: api.FeaturesService,
Log: api.Logger,
Request: r,
Action: database.AuditActionWrite,
})
)
defer commitAudit()
aReq.Old = workspace

if !api.Authorize(r, rbac.ActionUpdate, workspace) {
httpapi.ResourceNotFound(rw)
return
Expand All@@ -488,18 +512,20 @@ func (api *API) patchWorkspace(rw http.ResponseWriter, r *http.Request) {
}

if req.Name == "" || req.Name == workspace.Name {
aReq.New = workspace
// Nothing changed, optionally this could be an error.
rw.WriteHeader(http.StatusNoContent)
return
}

// The reason we double check here is in case more fields can be
// patched in the future, it's enough if one changes.
name := workspace.Name
if req.Name != "" || req.Name != workspace.Name {
name = req.Name
}

_, err := api.Database.UpdateWorkspace(r.Context(), database.UpdateWorkspaceParams{
newWorkspace, err := api.Database.UpdateWorkspace(r.Context(), database.UpdateWorkspaceParams{
ID: workspace.ID,
Name: name,
})
Expand DownExpand Up@@ -534,11 +560,23 @@ func (api *API) patchWorkspace(rw http.ResponseWriter, r *http.Request) {
return
}

aReq.New = newWorkspace
rw.WriteHeader(http.StatusNoContent)
}

func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) {
workspace := httpmw.WorkspaceParam(r)
var (
workspace = httpmw.WorkspaceParam(r)
aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{
Features: api.FeaturesService,
Log: api.Logger,
Request: r,
Action: database.AuditActionWrite,
})
)
defer commitAudit()
aReq.Old = workspace

if !api.Authorize(r, rbac.ActionUpdate, workspace) {
httpapi.ResourceNotFound(rw)
return
Expand DownExpand Up@@ -578,10 +616,26 @@ func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) {
})
return
}

newWorkspace := workspace
newWorkspace.AutostartSchedule = dbSched
aReq.New = newWorkspace

rw.WriteHeader(http.StatusNoContent)
}

func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) {
workspace := httpmw.WorkspaceParam(r)
var (
workspace = httpmw.WorkspaceParam(r)
aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{
Features: api.FeaturesService,
Log: api.Logger,
Request: r,
Action: database.AuditActionWrite,
})
)
defer commitAudit()

if !api.Authorize(r, rbac.ActionUpdate, workspace) {
httpapi.ResourceNotFound(rw)
return
Expand All@@ -592,6 +646,8 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) {
return
}

var dbTTL sql.NullInt64

err := api.Database.InTx(func(s database.Store) error {
template, err := s.GetTemplateByID(r.Context(), workspace.TemplateID)
if err != nil {
Expand All@@ -601,7 +657,7 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) {
return xerrors.Errorf("fetch workspace template: %w", err)
}

dbTTL, err:= validWorkspaceTTLMillis(req.TTLMillis, time.Duration(template.MaxTtl))
dbTTL, err = validWorkspaceTTLMillis(req.TTLMillis, time.Duration(template.MaxTtl))
if err != nil {
return codersdk.ValidationError{Field: "ttl_ms", Detail: err.Error()}
}
Expand DownExpand Up@@ -630,7 +686,11 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) {
return
}

httpapi.Write(rw, http.StatusOK, nil)
newWorkspace := workspace
newWorkspace.Ttl = dbTTL
aReq.New = newWorkspace

rw.WriteHeader(http.StatusNoContent)
}

func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) {
Expand Down
21 changes: 18 additions & 3 deletionscoderd/workspaces_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,10 +9,13 @@ import (
"time"

"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/coder/coder/coderd/audit"
"github.com/coder/coder/coderd/autobuild/schedule"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/rbac"
"github.com/coder/coder/coderd/util/ptr"
"github.com/coder/coder/codersdk"
Expand DownExpand Up@@ -214,12 +217,16 @@ func TestPostWorkspacesByOrganization(t *testing.T) {

t.Run("Create", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
auditor := audit.NewMock()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, Auditor: auditor})
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
_ = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)

require.Len(t, auditor.AuditLogs, 4)
assert.Equal(t, database.AuditActionCreate, auditor.AuditLogs[3].Action)
})

t.Run("TemplateNoTTL", func(t *testing.T) {
Expand DownExpand Up@@ -949,7 +956,8 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()
var (
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
auditor = audit.NewMock()
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, Auditor: auditor})
user = coderdtest.CreateFirstUser(t, client)
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
Expand DownExpand Up@@ -994,6 +1002,9 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {
require.Equal(t, testCase.expectedNext, next, "unexpected next scheduled autostart time")
interval := next.Sub(testCase.at)
require.Equal(t, testCase.expectedInterval, interval, "unexpected interval")

require.Len(t, auditor.AuditLogs, 5)
assert.Equal(t, database.AuditActionWrite, auditor.AuditLogs[4].Action)
})
}

Expand DownExpand Up@@ -1086,7 +1097,8 @@ func TestWorkspaceUpdateTTL(t *testing.T) {
mutators = append(mutators, testCase.modifyTemplate)
}
var (
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
auditor = audit.NewMock()
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, Auditor: auditor})
user = coderdtest.CreateFirstUser(t, client)
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
Expand DownExpand Up@@ -1116,6 +1128,9 @@ func TestWorkspaceUpdateTTL(t *testing.T) {
require.NoError(t, err, "fetch updated workspace")

require.Equal(t, testCase.ttlMillis, updated.TTLMillis, "expected autostop ttl to equal requested")

require.Len(t, auditor.AuditLogs, 5)
assert.Equal(t, database.AuditActionWrite, auditor.AuditLogs[4].Action)
})
}

Expand Down
4 changes: 2 additions & 2 deletionscodersdk/workspaces.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -183,7 +183,7 @@ func (c *Client) UpdateWorkspaceAutostart(ctx context.Context, id uuid.UUID, req
return xerrors.Errorf("update workspace autostart: %w", err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
if res.StatusCode != http.StatusNoContent {
return readBodyAsError(res)
}
return nil
Expand All@@ -203,7 +203,7 @@ func (c *Client) UpdateWorkspaceTTL(ctx context.Context, id uuid.UUID, req Updat
return xerrors.Errorf("update workspace time until shutdown: %w", err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
if res.StatusCode != http.StatusNoContent {
return readBodyAsError(res)
}
return nil
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp