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

Commita27ac30

Browse files
authored
chore: add sql filter to fetching audit logs (#14070)
* chore: add sql filter to fetching audit logs* use sqlc.embed for audit logs* fix sql query matcher
1 parentd23670a commita27ac30

File tree

16 files changed

+562
-245
lines changed

16 files changed

+562
-245
lines changed

‎coderd/audit.go

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -182,17 +182,17 @@ func (api *API) convertAuditLogs(ctx context.Context, dblogs []database.GetAudit
182182
}
183183

184184
func (api*API)convertAuditLog(ctx context.Context,dblog database.GetAuditLogsOffsetRow) codersdk.AuditLog {
185-
ip,_:=netip.AddrFromSlice(dblog.Ip.IPNet.IP)
185+
ip,_:=netip.AddrFromSlice(dblog.AuditLog.Ip.IPNet.IP)
186186

187187
diff:= codersdk.AuditDiff{}
188-
_=json.Unmarshal(dblog.Diff,&diff)
188+
_=json.Unmarshal(dblog.AuditLog.Diff,&diff)
189189

190190
varuser*codersdk.User
191191
ifdblog.UserUsername.Valid {
192192
// Leaving the organization IDs blank for now; not sure they are useful for
193193
// the audit query anyway?
194194
sdkUser:=db2sdk.User(database.User{
195-
ID:dblog.UserID,
195+
ID:dblog.AuditLog.UserID,
196196
Email:dblog.UserEmail.String,
197197
Username:dblog.UserUsername.String,
198198
CreatedAt:dblog.UserCreatedAt.Time,
@@ -211,7 +211,7 @@ func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogs
211211
}
212212

213213
var (
214-
additionalFieldsBytes= []byte(dblog.AdditionalFields)
214+
additionalFieldsBytes= []byte(dblog.AuditLog.AdditionalFields)
215215
additionalFields audit.AdditionalFields
216216
err=json.Unmarshal(additionalFieldsBytes,&additionalFields)
217217
)
@@ -224,7 +224,7 @@ func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogs
224224
WorkspaceOwner:"unknown",
225225
}
226226

227-
dblog.AdditionalFields,err=json.Marshal(resourceInfo)
227+
dblog.AuditLog.AdditionalFields,err=json.Marshal(resourceInfo)
228228
api.Logger.Error(ctx,"marshal additional fields",slog.Error(err))
229229
}
230230

@@ -239,30 +239,30 @@ func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogs
239239
}
240240

241241
alog:= codersdk.AuditLog{
242-
ID:dblog.ID,
243-
RequestID:dblog.RequestID,
244-
Time:dblog.Time,
242+
ID:dblog.AuditLog.ID,
243+
RequestID:dblog.AuditLog.RequestID,
244+
Time:dblog.AuditLog.Time,
245245
// OrganizationID is deprecated.
246-
OrganizationID:dblog.OrganizationID,
246+
OrganizationID:dblog.AuditLog.OrganizationID,
247247
IP:ip,
248-
UserAgent:dblog.UserAgent.String,
249-
ResourceType:codersdk.ResourceType(dblog.ResourceType),
250-
ResourceID:dblog.ResourceID,
251-
ResourceTarget:dblog.ResourceTarget,
252-
ResourceIcon:dblog.ResourceIcon,
253-
Action:codersdk.AuditAction(dblog.Action),
248+
UserAgent:dblog.AuditLog.UserAgent.String,
249+
ResourceType:codersdk.ResourceType(dblog.AuditLog.ResourceType),
250+
ResourceID:dblog.AuditLog.ResourceID,
251+
ResourceTarget:dblog.AuditLog.ResourceTarget,
252+
ResourceIcon:dblog.AuditLog.ResourceIcon,
253+
Action:codersdk.AuditAction(dblog.AuditLog.Action),
254254
Diff:diff,
255-
StatusCode:dblog.StatusCode,
256-
AdditionalFields:dblog.AdditionalFields,
255+
StatusCode:dblog.AuditLog.StatusCode,
256+
AdditionalFields:dblog.AuditLog.AdditionalFields,
257257
User:user,
258258
Description:auditLogDescription(dblog),
259259
ResourceLink:resourceLink,
260260
IsDeleted:isDeleted,
261261
}
262262

263-
ifdblog.OrganizationID!=uuid.Nil {
263+
ifdblog.AuditLog.OrganizationID!=uuid.Nil {
264264
alog.Organization=&codersdk.MinimalOrganization{
265-
ID:dblog.OrganizationID,
265+
ID:dblog.AuditLog.OrganizationID,
266266
Name:dblog.OrganizationName,
267267
DisplayName:dblog.OrganizationDisplayName,
268268
Icon:dblog.OrganizationIcon,
@@ -276,32 +276,32 @@ func auditLogDescription(alog database.GetAuditLogsOffsetRow) string {
276276
b:= strings.Builder{}
277277
// NOTE: WriteString always returns a nil error, so we never check it
278278
_,_=b.WriteString("{user} ")
279-
ifalog.StatusCode>=400 {
279+
ifalog.AuditLog.StatusCode>=400 {
280280
_,_=b.WriteString("unsuccessfully attempted to ")
281-
_,_=b.WriteString(string(alog.Action))
281+
_,_=b.WriteString(string(alog.AuditLog.Action))
282282
}else {
283-
_,_=b.WriteString(codersdk.AuditAction(alog.Action).Friendly())
283+
_,_=b.WriteString(codersdk.AuditAction(alog.AuditLog.Action).Friendly())
284284
}
285285

286286
// API Key resources (used for authentication) do not have targets and follow the below format:
287287
// "User {logged in | logged out | registered}"
288-
ifalog.ResourceType==database.ResourceTypeApiKey&&
289-
(alog.Action==database.AuditActionLogin||alog.Action==database.AuditActionLogout||alog.Action==database.AuditActionRegister) {
288+
ifalog.AuditLog.ResourceType==database.ResourceTypeApiKey&&
289+
(alog.AuditLog.Action==database.AuditActionLogin||alog.AuditLog.Action==database.AuditActionLogout||alog.AuditLog.Action==database.AuditActionRegister) {
290290
returnb.String()
291291
}
292292

293293
// We don't display the name (target) for git ssh keys. It's fairly long and doesn't
294294
// make too much sense to display.
295-
ifalog.ResourceType==database.ResourceTypeGitSshKey {
295+
ifalog.AuditLog.ResourceType==database.ResourceTypeGitSshKey {
296296
_,_=b.WriteString(" the ")
297-
_,_=b.WriteString(codersdk.ResourceType(alog.ResourceType).FriendlyString())
297+
_,_=b.WriteString(codersdk.ResourceType(alog.AuditLog.ResourceType).FriendlyString())
298298
returnb.String()
299299
}
300300

301301
_,_=b.WriteString(" ")
302-
_,_=b.WriteString(codersdk.ResourceType(alog.ResourceType).FriendlyString())
302+
_,_=b.WriteString(codersdk.ResourceType(alog.AuditLog.ResourceType).FriendlyString())
303303

304-
ifalog.ResourceType==database.ResourceTypeConvertLogin {
304+
ifalog.AuditLog.ResourceType==database.ResourceTypeConvertLogin {
305305
_,_=b.WriteString(" to")
306306
}
307307

@@ -311,9 +311,9 @@ func auditLogDescription(alog database.GetAuditLogsOffsetRow) string {
311311
}
312312

313313
func (api*API)auditLogIsResourceDeleted(ctx context.Context,alog database.GetAuditLogsOffsetRow)bool {
314-
switchalog.ResourceType {
314+
switchalog.AuditLog.ResourceType {
315315
casedatabase.ResourceTypeTemplate:
316-
template,err:=api.Database.GetTemplateByID(ctx,alog.ResourceID)
316+
template,err:=api.Database.GetTemplateByID(ctx,alog.AuditLog.ResourceID)
317317
iferr!=nil {
318318
ifxerrors.Is(err,sql.ErrNoRows) {
319319
returntrue
@@ -322,7 +322,7 @@ func (api *API) auditLogIsResourceDeleted(ctx context.Context, alog database.Get
322322
}
323323
returntemplate.Deleted
324324
casedatabase.ResourceTypeUser:
325-
user,err:=api.Database.GetUserByID(ctx,alog.ResourceID)
325+
user,err:=api.Database.GetUserByID(ctx,alog.AuditLog.ResourceID)
326326
iferr!=nil {
327327
ifxerrors.Is(err,sql.ErrNoRows) {
328328
returntrue
@@ -331,7 +331,7 @@ func (api *API) auditLogIsResourceDeleted(ctx context.Context, alog database.Get
331331
}
332332
returnuser.Deleted
333333
casedatabase.ResourceTypeWorkspace:
334-
workspace,err:=api.Database.GetWorkspaceByID(ctx,alog.ResourceID)
334+
workspace,err:=api.Database.GetWorkspaceByID(ctx,alog.AuditLog.ResourceID)
335335
iferr!=nil {
336336
ifxerrors.Is(err,sql.ErrNoRows) {
337337
returntrue
@@ -340,7 +340,7 @@ func (api *API) auditLogIsResourceDeleted(ctx context.Context, alog database.Get
340340
}
341341
returnworkspace.Deleted
342342
casedatabase.ResourceTypeWorkspaceBuild:
343-
workspaceBuild,err:=api.Database.GetWorkspaceBuildByID(ctx,alog.ResourceID)
343+
workspaceBuild,err:=api.Database.GetWorkspaceBuildByID(ctx,alog.AuditLog.ResourceID)
344344
iferr!=nil {
345345
ifxerrors.Is(err,sql.ErrNoRows) {
346346
returntrue
@@ -357,15 +357,15 @@ func (api *API) auditLogIsResourceDeleted(ctx context.Context, alog database.Get
357357
}
358358
returnworkspace.Deleted
359359
casedatabase.ResourceTypeOauth2ProviderApp:
360-
_,err:=api.Database.GetOAuth2ProviderAppByID(ctx,alog.ResourceID)
360+
_,err:=api.Database.GetOAuth2ProviderAppByID(ctx,alog.AuditLog.ResourceID)
361361
ifxerrors.Is(err,sql.ErrNoRows) {
362362
returntrue
363363
}elseiferr!=nil {
364364
api.Logger.Error(ctx,"unable to fetch oauth2 app",slog.Error(err))
365365
}
366366
returnfalse
367367
casedatabase.ResourceTypeOauth2ProviderAppSecret:
368-
_,err:=api.Database.GetOAuth2ProviderAppSecretByID(ctx,alog.ResourceID)
368+
_,err:=api.Database.GetOAuth2ProviderAppSecretByID(ctx,alog.AuditLog.ResourceID)
369369
ifxerrors.Is(err,sql.ErrNoRows) {
370370
returntrue
371371
}elseiferr!=nil {
@@ -378,17 +378,17 @@ func (api *API) auditLogIsResourceDeleted(ctx context.Context, alog database.Get
378378
}
379379

380380
func (api*API)auditLogResourceLink(ctx context.Context,alog database.GetAuditLogsOffsetRow,additionalFields audit.AdditionalFields)string {
381-
switchalog.ResourceType {
381+
switchalog.AuditLog.ResourceType {
382382
casedatabase.ResourceTypeTemplate:
383383
returnfmt.Sprintf("/templates/%s",
384-
alog.ResourceTarget)
384+
alog.AuditLog.ResourceTarget)
385385

386386
casedatabase.ResourceTypeUser:
387387
returnfmt.Sprintf("/users?filter=%s",
388-
alog.ResourceTarget)
388+
alog.AuditLog.ResourceTarget)
389389

390390
casedatabase.ResourceTypeWorkspace:
391-
workspace,getWorkspaceErr:=api.Database.GetWorkspaceByID(ctx,alog.ResourceID)
391+
workspace,getWorkspaceErr:=api.Database.GetWorkspaceByID(ctx,alog.AuditLog.ResourceID)
392392
ifgetWorkspaceErr!=nil {
393393
return""
394394
}
@@ -397,13 +397,13 @@ func (api *API) auditLogResourceLink(ctx context.Context, alog database.GetAudit
397397
return""
398398
}
399399
returnfmt.Sprintf("/@%s/%s",
400-
workspaceOwner.Username,alog.ResourceTarget)
400+
workspaceOwner.Username,alog.AuditLog.ResourceTarget)
401401

402402
casedatabase.ResourceTypeWorkspaceBuild:
403403
iflen(additionalFields.WorkspaceName)==0||len(additionalFields.BuildNumber)==0 {
404404
return""
405405
}
406-
workspaceBuild,getWorkspaceBuildErr:=api.Database.GetWorkspaceBuildByID(ctx,alog.ResourceID)
406+
workspaceBuild,getWorkspaceBuildErr:=api.Database.GetWorkspaceBuildByID(ctx,alog.AuditLog.ResourceID)
407407
ifgetWorkspaceBuildErr!=nil {
408408
return""
409409
}
@@ -419,10 +419,10 @@ func (api *API) auditLogResourceLink(ctx context.Context, alog database.GetAudit
419419
workspaceOwner.Username,additionalFields.WorkspaceName,additionalFields.BuildNumber)
420420

421421
casedatabase.ResourceTypeOauth2ProviderApp:
422-
returnfmt.Sprintf("/deployment/oauth2-provider/apps/%s",alog.ResourceID)
422+
returnfmt.Sprintf("/deployment/oauth2-provider/apps/%s",alog.AuditLog.ResourceID)
423423

424424
casedatabase.ResourceTypeOauth2ProviderAppSecret:
425-
secret,err:=api.Database.GetOAuth2ProviderAppSecretByID(ctx,alog.ResourceID)
425+
secret,err:=api.Database.GetOAuth2ProviderAppSecretByID(ctx,alog.AuditLog.ResourceID)
426426
iferr!=nil {
427427
return""
428428
}

‎coderd/audit_internal_test.go

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,45 +18,55 @@ func TestAuditLogDescription(t *testing.T) {
1818
{
1919
name:"mainline",
2020
alog: database.GetAuditLogsOffsetRow{
21-
Action:database.AuditActionCreate,
22-
StatusCode:200,
23-
ResourceType:database.ResourceTypeWorkspace,
21+
AuditLog: database.AuditLog{
22+
Action:database.AuditActionCreate,
23+
StatusCode:200,
24+
ResourceType:database.ResourceTypeWorkspace,
25+
},
2426
},
2527
want:"{user} created workspace {target}",
2628
},
2729
{
2830
name:"unsuccessful",
2931
alog: database.GetAuditLogsOffsetRow{
30-
Action:database.AuditActionCreate,
31-
StatusCode:400,
32-
ResourceType:database.ResourceTypeWorkspace,
32+
AuditLog: database.AuditLog{
33+
Action:database.AuditActionCreate,
34+
StatusCode:400,
35+
ResourceType:database.ResourceTypeWorkspace,
36+
},
3337
},
3438
want:"{user} unsuccessfully attempted to create workspace {target}",
3539
},
3640
{
3741
name:"login",
3842
alog: database.GetAuditLogsOffsetRow{
39-
Action:database.AuditActionLogin,
40-
StatusCode:200,
41-
ResourceType:database.ResourceTypeApiKey,
43+
AuditLog: database.AuditLog{
44+
Action:database.AuditActionLogin,
45+
StatusCode:200,
46+
ResourceType:database.ResourceTypeApiKey,
47+
},
4248
},
4349
want:"{user} logged in",
4450
},
4551
{
4652
name:"unsuccessful_login",
4753
alog: database.GetAuditLogsOffsetRow{
48-
Action:database.AuditActionLogin,
49-
StatusCode:401,
50-
ResourceType:database.ResourceTypeApiKey,
54+
AuditLog: database.AuditLog{
55+
Action:database.AuditActionLogin,
56+
StatusCode:401,
57+
ResourceType:database.ResourceTypeApiKey,
58+
},
5159
},
5260
want:"{user} unsuccessfully attempted to login",
5361
},
5462
{
5563
name:"gitsshkey",
5664
alog: database.GetAuditLogsOffsetRow{
57-
Action:database.AuditActionDelete,
58-
StatusCode:200,
59-
ResourceType:database.ResourceTypeGitSshKey,
65+
AuditLog: database.AuditLog{
66+
Action:database.AuditActionDelete,
67+
StatusCode:200,
68+
ResourceType:database.ResourceTypeGitSshKey,
69+
},
6070
},
6171
want:"{user} deleted the git ssh key",
6272
},

‎coderd/audit_test.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7-
"net/http"
87
"strconv"
98
"testing"
109
"time"
@@ -163,19 +162,18 @@ func TestAuditLogs(t *testing.T) {
163162
})
164163
require.NoError(t,err)
165164

166-
// Fetching audit logs without an organization selector should fail
167-
_,err=orgAdmin.AuditLogs(ctx, codersdk.AuditLogsRequest{
165+
// Fetching audit logs without an organization selector should only
166+
// return organization audit logs the org admin is an admin of.
167+
alogs,err:=orgAdmin.AuditLogs(ctx, codersdk.AuditLogsRequest{
168168
Pagination: codersdk.Pagination{
169169
Limit:5,
170170
},
171171
})
172-
varsdkError*codersdk.Error
173-
require.Error(t,err)
174-
require.ErrorAsf(t,err,&sdkError,"error should be of type *codersdk.Error")
175-
require.Equal(t,http.StatusForbidden,sdkError.StatusCode())
172+
require.NoError(t,err)
173+
require.Len(t,alogs.AuditLogs,1)
176174

177175
// Using the organization selector allows the org admin to fetch audit logs
178-
alogs,err:=orgAdmin.AuditLogs(ctx, codersdk.AuditLogsRequest{
176+
alogs,err=orgAdmin.AuditLogs(ctx, codersdk.AuditLogsRequest{
179177
SearchQuery:fmt.Sprintf("organization:%s",owner.OrganizationID.String()),
180178
Pagination: codersdk.Pagination{
181179
Limit:5,

‎coderd/database/dbauthz/dbauthz.go

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,22 +1248,12 @@ func (q *querier) GetApplicationName(ctx context.Context) (string, error) {
12481248
}
12491249

12501250
func (q*querier)GetAuditLogsOffset(ctx context.Context,arg database.GetAuditLogsOffsetParams) ([]database.GetAuditLogsOffsetRow,error) {
1251-
// To optimize the authz checks for audit logs, do not run an authorize
1252-
// check on each individual audit log row. In practice, audit logs are either
1253-
// fetched from a global or an organization scope.
1254-
// Applying a SQL filter would slow down the query for no benefit on how this query is
1255-
// actually used.
1256-
1257-
object:=rbac.ResourceAuditLog
1258-
ifarg.OrganizationID!=uuid.Nil {
1259-
object=object.InOrg(arg.OrganizationID)
1260-
}
1261-
1262-
iferr:=q.authorizeContext(ctx,policy.ActionRead,object);err!=nil {
1263-
returnnil,err
1251+
prep,err:=prepareSQLFilter(ctx,q.auth,policy.ActionRead,rbac.ResourceAuditLog.Type)
1252+
iferr!=nil {
1253+
returnnil,xerrors.Errorf("(dev error) prepare sql filter: %w",err)
12641254
}
12651255

1266-
returnq.db.GetAuditLogsOffset(ctx,arg)
1256+
returnq.db.GetAuthorizedAuditLogsOffset(ctx,arg,prep)
12671257
}
12681258

12691259
func (q*querier)GetAuthorizationUserRoles(ctx context.Context,userID uuid.UUID) (database.GetAuthorizationUserRolesRow,error) {
@@ -3852,3 +3842,7 @@ func (q *querier) GetAuthorizedUsers(ctx context.Context, arg database.GetUsersP
38523842
// GetUsers is authenticated.
38533843
returnq.GetUsers(ctx,arg)
38543844
}
3845+
3846+
func (q*querier)GetAuthorizedAuditLogsOffset(ctx context.Context,arg database.GetAuditLogsOffsetParams,_ rbac.PreparedAuthorized) ([]database.GetAuditLogsOffsetRow,error) {
3847+
returnq.GetAuditLogsOffset(ctx,arg)
3848+
}

‎coderd/database/dbauthz/dbauthz_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,14 @@ func (s *MethodTestSuite) TestAuditLogs() {
266266
_=dbgen.AuditLog(s.T(),db, database.AuditLog{})
267267
check.Args(database.GetAuditLogsOffsetParams{
268268
LimitOpt:10,
269-
}).Asserts(rbac.ResourceAuditLog,policy.ActionRead)
269+
}).Asserts()
270+
}))
271+
s.Run("GetAuthorizedAuditLogsOffset",s.Subtest(func(db database.Store,check*expects) {
272+
_=dbgen.AuditLog(s.T(),db, database.AuditLog{})
273+
_=dbgen.AuditLog(s.T(),db, database.AuditLog{})
274+
check.Args(database.GetAuditLogsOffsetParams{
275+
LimitOpt:10,
276+
},emptyPreparedAuthorized{}).Asserts()
270277
}))
271278
}
272279

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp