Skip to content

Commit 2b25f46

Browse files
committed
Add organization to audit log response
This replaces the old ID. This is a breaking change but organizations were not being used before.
1 parent c6d96f6 commit 2b25f46

File tree

12 files changed

+236
-58
lines changed

12 files changed

+236
-58
lines changed

cli/organization_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ func TestCurrentOrganization(t *testing.T) {
3232
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
3333
json.NewEncoder(w).Encode([]codersdk.Organization{
3434
{
35-
ID: orgID,
36-
Name: "not-default",
35+
MinimalOrganization: codersdk.MinimalOrganization{
36+
ID: orgID,
37+
Name: "not-default",
38+
},
3739
CreatedAt: time.Now(),
3840
UpdatedAt: time.Now(),
3941
IsDefault: false,

coderd/apidoc/docs.go

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

coderd/apidoc/swagger.json

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

coderd/audit.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,10 @@ func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogs
238238
resourceLink = api.auditLogResourceLink(ctx, dblog, additionalFields)
239239
}
240240

241-
return codersdk.AuditLog{
241+
alog := codersdk.AuditLog{
242242
ID: dblog.ID,
243243
RequestID: dblog.RequestID,
244244
Time: dblog.Time,
245-
OrganizationID: dblog.OrganizationID,
246245
IP: ip,
247246
UserAgent: dblog.UserAgent.String,
248247
ResourceType: codersdk.ResourceType(dblog.ResourceType),
@@ -258,6 +257,17 @@ func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogs
258257
ResourceLink: resourceLink,
259258
IsDeleted: isDeleted,
260259
}
260+
261+
if dblog.OrganizationID != uuid.Nil {
262+
alog.Organization = &codersdk.MinimalOrganization{
263+
ID: dblog.OrganizationID,
264+
Name: dblog.OrganizationName,
265+
DisplayName: dblog.OrganizationDisplayName,
266+
Icon: dblog.OrganizationIcon,
267+
}
268+
}
269+
270+
return alog
261271
}
262272

263273
func auditLogDescription(alog database.GetAuditLogsOffsetRow) string {

coderd/audit_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,83 @@ func TestAuditLogs(t *testing.T) {
9797
require.Equal(t, foundUser, *alogs.AuditLogs[0].User)
9898
})
9999

100+
t.Run("Organization", func(t *testing.T) {
101+
t.Parallel()
102+
103+
ctx := context.Background()
104+
client := coderdtest.New(t, nil)
105+
user := coderdtest.CreateFirstUser(t, client)
106+
107+
o, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
108+
Name: "new-org",
109+
DisplayName: "New organization",
110+
Description: "A new organization to love and cherish until the test is over.",
111+
Icon: "/emojis/1f48f-1f3ff.png",
112+
})
113+
require.NoError(t, err)
114+
115+
err = client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{
116+
OrganizationID: o.ID,
117+
ResourceID: user.UserID,
118+
})
119+
require.NoError(t, err)
120+
121+
alogs, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{
122+
Pagination: codersdk.Pagination{
123+
Limit: 1,
124+
},
125+
})
126+
require.NoError(t, err)
127+
require.Equal(t, int64(1), alogs.Count)
128+
require.Len(t, alogs.AuditLogs, 1)
129+
130+
// Make sure the organization is fully populated.
131+
require.Equal(t, &codersdk.MinimalOrganization{
132+
ID: o.ID,
133+
Name: o.Name,
134+
DisplayName: o.DisplayName,
135+
Icon: o.Icon,
136+
}, alogs.AuditLogs[0].Organization)
137+
138+
// Delete the org and try again, should be mostly empty.
139+
err = client.DeleteOrganization(ctx, o.ID.String())
140+
require.NoError(t, err)
141+
142+
alogs, err = client.AuditLogs(ctx, codersdk.AuditLogsRequest{
143+
Pagination: codersdk.Pagination{
144+
Limit: 1,
145+
},
146+
})
147+
require.NoError(t, err)
148+
require.Equal(t, int64(1), alogs.Count)
149+
require.Len(t, alogs.AuditLogs, 1)
150+
151+
require.Equal(t, &codersdk.MinimalOrganization{
152+
ID: o.ID,
153+
}, alogs.AuditLogs[0].Organization)
154+
155+
// Some audit entries do not have an organization at all, in which case the
156+
// response omits the organization.
157+
err = client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{
158+
ResourceType: codersdk.ResourceTypeAPIKey,
159+
ResourceID: user.UserID,
160+
})
161+
require.NoError(t, err)
162+
163+
alogs, err = client.AuditLogs(ctx, codersdk.AuditLogsRequest{
164+
SearchQuery: "resource_type:api_key",
165+
Pagination: codersdk.Pagination{
166+
Limit: 1,
167+
},
168+
})
169+
require.NoError(t, err)
170+
require.Equal(t, int64(1), alogs.Count)
171+
require.Len(t, alogs.AuditLogs, 1)
172+
173+
// The other will have no organization.
174+
require.Equal(t, (*codersdk.MinimalOrganization)(nil), alogs.AuditLogs[0].Organization)
175+
})
176+
100177
t.Run("WorkspaceBuildAuditLink", func(t *testing.T) {
101178
t.Parallel()
102179

coderd/organizations.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -315,11 +315,13 @@ func (api *API) deleteOrganization(rw http.ResponseWriter, r *http.Request) {
315315
// convertOrganization consumes the database representation and outputs an API friendly representation.
316316
func convertOrganization(organization database.Organization) codersdk.Organization {
317317
return codersdk.Organization{
318-
ID: organization.ID,
319-
Name: organization.Name,
320-
DisplayName: organization.DisplayName,
318+
MinimalOrganization: codersdk.MinimalOrganization{
319+
ID: organization.ID,
320+
Name: organization.Name,
321+
DisplayName: organization.DisplayName,
322+
Icon: organization.Icon,
323+
},
321324
Description: organization.Description,
322-
Icon: organization.Icon,
323325
CreatedAt: organization.CreatedAt,
324326
UpdatedAt: organization.UpdatedAt,
325327
IsDefault: organization.IsDefault,

codersdk/audit.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,13 @@ type AuditDiffField struct {
125125
}
126126

127127
type AuditLog struct {
128-
ID uuid.UUID `json:"id" format:"uuid"`
129-
RequestID uuid.UUID `json:"request_id" format:"uuid"`
130-
Time time.Time `json:"time" format:"date-time"`
131-
OrganizationID uuid.UUID `json:"organization_id" format:"uuid"`
132-
IP netip.Addr `json:"ip"`
133-
UserAgent string `json:"user_agent"`
134-
ResourceType ResourceType `json:"resource_type"`
135-
ResourceID uuid.UUID `json:"resource_id" format:"uuid"`
128+
ID uuid.UUID `json:"id" format:"uuid"`
129+
RequestID uuid.UUID `json:"request_id" format:"uuid"`
130+
Time time.Time `json:"time" format:"date-time"`
131+
IP netip.Addr `json:"ip"`
132+
UserAgent string `json:"user_agent"`
133+
ResourceType ResourceType `json:"resource_type"`
134+
ResourceID uuid.UUID `json:"resource_id" format:"uuid"`
136135
// ResourceTarget is the name of the resource.
137136
ResourceTarget string `json:"resource_target"`
138137
ResourceIcon string `json:"resource_icon"`
@@ -144,6 +143,8 @@ type AuditLog struct {
144143
ResourceLink string `json:"resource_link"`
145144
IsDeleted bool `json:"is_deleted"`
146145

146+
Organization *MinimalOrganization `json:"organization,omitempty"`
147+
147148
User *User `json:"user"`
148149
}
149150

codersdk/organizations.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,22 @@ func ProvisionerTypeValid[T ProvisionerType | string](pt T) error {
3939
}
4040
}
4141

42-
// Organization is the JSON representation of a Coder organization.
43-
type Organization struct {
42+
type MinimalOrganization struct {
4443
ID uuid.UUID `table:"id" json:"id" validate:"required" format:"uuid"`
4544
Name string `table:"name,default_sort" json:"name"`
4645
DisplayName string `table:"display_name" json:"display_name"`
47-
Description string `table:"description" json:"description"`
48-
CreatedAt time.Time `table:"created_at" json:"created_at" validate:"required" format:"date-time"`
49-
UpdatedAt time.Time `table:"updated_at" json:"updated_at" validate:"required" format:"date-time"`
50-
IsDefault bool `table:"default" json:"is_default" validate:"required"`
5146
Icon string `table:"icon" json:"icon"`
5247
}
5348

49+
// Organization is the JSON representation of a Coder organization.
50+
type Organization struct {
51+
MinimalOrganization `table:"m,recursive_inline"`
52+
Description string `table:"description" json:"description"`
53+
CreatedAt time.Time `table:"created_at" json:"created_at" validate:"required" format:"date-time"`
54+
UpdatedAt time.Time `table:"updated_at" json:"updated_at" validate:"required" format:"date-time"`
55+
IsDefault bool `table:"default" json:"is_default" validate:"required"`
56+
}
57+
5458
func (o Organization) HumanName() string {
5559
if o.DisplayName == "" {
5660
return o.Name

docs/api/audit.md

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/api/schemas.md

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

0 commit comments

Comments
 (0)