mirror of
https://github.com/coder/coder.git
synced 2025-07-08 11:39:50 +00:00
chore: insert audit log entries for organization CRUD (#13660)
* chore: insert audit log entries for organization CRUD
This commit is contained in:
@ -23,7 +23,8 @@ type Auditable interface {
|
||||
database.OAuth2ProviderApp |
|
||||
database.OAuth2ProviderAppSecret |
|
||||
database.CustomRole |
|
||||
database.AuditableOrganizationMember
|
||||
database.AuditableOrganizationMember |
|
||||
database.Organization
|
||||
}
|
||||
|
||||
// Map is a map of changed fields in an audited resource. It maps field names to
|
||||
|
@ -107,6 +107,8 @@ func ResourceTarget[T Auditable](tgt T) string {
|
||||
return typed.Name
|
||||
case database.AuditableOrganizationMember:
|
||||
return typed.Username
|
||||
case database.Organization:
|
||||
return typed.Name
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown resource %T for ResourceTarget", tgt))
|
||||
}
|
||||
@ -148,6 +150,8 @@ func ResourceID[T Auditable](tgt T) uuid.UUID {
|
||||
return typed.ID
|
||||
case database.AuditableOrganizationMember:
|
||||
return typed.UserID
|
||||
case database.Organization:
|
||||
return typed.ID
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown resource %T for ResourceID", tgt))
|
||||
}
|
||||
@ -187,6 +191,8 @@ func ResourceType[T Auditable](tgt T) database.ResourceType {
|
||||
return database.ResourceTypeCustomRole
|
||||
case database.AuditableOrganizationMember:
|
||||
return database.ResourceTypeOrganizationMember
|
||||
case database.Organization:
|
||||
return database.ResourceTypeOrganization
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown resource %T for ResourceType", typed))
|
||||
}
|
||||
@ -227,6 +233,8 @@ func ResourceRequiresOrgID[T Auditable]() bool {
|
||||
return true
|
||||
case database.AuditableOrganizationMember:
|
||||
return true
|
||||
case database.Organization:
|
||||
return true
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown resource %T for ResourceRequiresOrgID", tgt))
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/audit"
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
@ -41,8 +42,22 @@ func (*API) organization(rw http.ResponseWriter, r *http.Request) {
|
||||
// @Success 201 {object} codersdk.Organization
|
||||
// @Router /organizations [post]
|
||||
func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
apiKey := httpmw.APIKey(r)
|
||||
var (
|
||||
// organizationID is required before the audit log entry is created.
|
||||
organizationID = uuid.New()
|
||||
ctx = r.Context()
|
||||
apiKey = httpmw.APIKey(r)
|
||||
auditor = api.Auditor.Load()
|
||||
aReq, commitAudit = audit.InitRequest[database.Organization](rw, &audit.RequestParams{
|
||||
Audit: *auditor,
|
||||
Log: api.Logger,
|
||||
Request: r,
|
||||
Action: database.AuditActionCreate,
|
||||
OrganizationID: organizationID,
|
||||
})
|
||||
)
|
||||
aReq.Old = database.Organization{}
|
||||
defer commitAudit()
|
||||
|
||||
var req codersdk.CreateOrganizationRequest
|
||||
if !httpapi.Read(ctx, rw, r, &req) {
|
||||
@ -78,7 +93,7 @@ func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
organization, err = tx.InsertOrganization(ctx, database.InsertOrganizationParams{
|
||||
ID: uuid.New(),
|
||||
ID: organizationID,
|
||||
Name: req.Name,
|
||||
DisplayName: req.DisplayName,
|
||||
Description: req.Description,
|
||||
@ -119,6 +134,7 @@ func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
aReq.New = organization
|
||||
httpapi.Write(ctx, rw, http.StatusCreated, convertOrganization(organization))
|
||||
}
|
||||
|
||||
@ -133,8 +149,20 @@ func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) {
|
||||
// @Success 200 {object} codersdk.Organization
|
||||
// @Router /organizations/{organization} [patch]
|
||||
func (api *API) patchOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
organization := httpmw.OrganizationParam(r)
|
||||
var (
|
||||
ctx = r.Context()
|
||||
organization = httpmw.OrganizationParam(r)
|
||||
auditor = api.Auditor.Load()
|
||||
aReq, commitAudit = audit.InitRequest[database.Organization](rw, &audit.RequestParams{
|
||||
Audit: *auditor,
|
||||
Log: api.Logger,
|
||||
Request: r,
|
||||
Action: database.AuditActionWrite,
|
||||
OrganizationID: organization.ID,
|
||||
})
|
||||
)
|
||||
aReq.Old = organization
|
||||
defer commitAudit()
|
||||
|
||||
var req codersdk.UpdateOrganizationRequest
|
||||
if !httpapi.Read(ctx, rw, r, &req) {
|
||||
@ -208,6 +236,7 @@ func (api *API) patchOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
aReq.New = organization
|
||||
httpapi.Write(ctx, rw, http.StatusOK, convertOrganization(organization))
|
||||
}
|
||||
|
||||
@ -220,8 +249,20 @@ func (api *API) patchOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
// @Success 200 {object} codersdk.Response
|
||||
// @Router /organizations/{organization} [delete]
|
||||
func (api *API) deleteOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
organization := httpmw.OrganizationParam(r)
|
||||
var (
|
||||
ctx = r.Context()
|
||||
organization = httpmw.OrganizationParam(r)
|
||||
auditor = api.Auditor.Load()
|
||||
aReq, commitAudit = audit.InitRequest[database.Organization](rw, &audit.RequestParams{
|
||||
Audit: *auditor,
|
||||
Log: api.Logger,
|
||||
Request: r,
|
||||
Action: database.AuditActionDelete,
|
||||
OrganizationID: organization.ID,
|
||||
})
|
||||
)
|
||||
aReq.Old = organization
|
||||
defer commitAudit()
|
||||
|
||||
if organization.IsDefault {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
@ -239,6 +280,7 @@ func (api *API) deleteOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
aReq.New = database.Organization{}
|
||||
httpapi.Write(ctx, rw, http.StatusOK, codersdk.Response{
|
||||
Message: "Organization has been deleted.",
|
||||
})
|
||||
|
@ -525,7 +525,7 @@ func TestPostUsers(t *testing.T) {
|
||||
|
||||
require.Len(t, auditor.AuditLogs(), numLogs)
|
||||
require.Equal(t, database.AuditActionCreate, auditor.AuditLogs()[numLogs-1].Action)
|
||||
require.Equal(t, database.AuditActionLogin, auditor.AuditLogs()[numLogs-2].Action)
|
||||
require.Equal(t, database.AuditActionLogin, auditor.AuditLogs()[numLogs-3].Action)
|
||||
|
||||
require.Len(t, user.OrganizationIDs, 1)
|
||||
assert.Equal(t, firstUser.OrganizationID, user.OrganizationIDs[0])
|
||||
|
Reference in New Issue
Block a user