Skip to content

Commit 0f162b1

Browse files
committed
simplify auditInitRequest in workspaceapps
1 parent 8d7a763 commit 0f162b1

File tree

1 file changed

+39
-71
lines changed
  • coderd/workspaceapps

1 file changed

+39
-71
lines changed

coderd/workspaceapps/db.go

Lines changed: 39 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -401,27 +401,22 @@ func (p *DBTokenProvider) auditInitRequest(ctx context.Context, w http.ResponseW
401401
}
402402
committed = true
403403

404-
if sw.Status == http.StatusSeeOther {
405-
// Redirects aren't interesting as we will capture the audit
406-
// log after the redirect.
407-
//
408-
// There's a case where we call httpmw.RedirectToLogin for
409-
// path-based apps the user doesn't have access to, in which
410-
// case the dashboard login redirect is used and we end up
411-
// not hitting the workspaceapps API again due to dashboard
412-
// showing 404. (Bug?)
413-
return
414-
}
415-
416404
if aReq.dbReq == nil {
417405
// App doesn't exist, there's information in the Request
418406
// struct but we need UUIDs for audit logging.
419407
return
420408
}
421409

422-
userID := uuid.NullUUID{}
410+
userID := uuid.Nil
423411
if aReq.apiKey != nil {
424-
userID = uuid.NullUUID{Valid: true, UUID: aReq.apiKey.UserID}
412+
userID = aReq.apiKey.UserID
413+
}
414+
userAgent := r.UserAgent()
415+
416+
// Approximation of the status code.
417+
statusCode := sw.Status
418+
if statusCode == 0 {
419+
statusCode = http.StatusOK
425420
}
426421

427422
type additionalFields struct {
@@ -443,50 +438,34 @@ func (p *DBTokenProvider) auditInitRequest(ctx context.Context, w http.ResponseW
443438
appInfo.SlugOrPort = aReq.dbReq.AppSlugOrPort
444439
}
445440

441+
// If we end up logging, ensure relevant fields are set.
446442
logger := p.Logger.With(
447443
slog.F("workspace_id", aReq.dbReq.Workspace.ID),
448444
slog.F("agent_id", aReq.dbReq.Agent.ID),
449445
slog.F("app_id", aReq.dbReq.App.ID),
450-
slog.F("user_id", userID.UUID),
446+
slog.F("user_id", userID),
447+
slog.F("user_agent", userAgent),
451448
slog.F("app_slug_or_port", appInfo.SlugOrPort),
449+
slog.F("status_code", statusCode),
452450
)
453451

454-
appInfoBytes, err := json.Marshal(appInfo)
455-
if err != nil {
456-
logger.Error(ctx, "marshal additional fields failed", slog.Error(err))
457-
}
458-
459-
var (
460-
updatedIDs []uuid.UUID
461-
sessionID = uuid.Nil
462-
)
463-
err = p.Database.InTx(func(tx database.Store) error {
452+
var startedAt time.Time
453+
err := p.Database.InTx(func(tx database.Store) (err error) {
464454
// nolint:gocritic // System context is needed to write audit sessions.
465455
dangerousSystemCtx := dbauthz.AsSystemRestricted(ctx)
466456

467-
updatedIDs, err = tx.UpdateWorkspaceAppAuditSession(dangerousSystemCtx, database.UpdateWorkspaceAppAuditSessionParams{
468-
AgentID: aReq.dbReq.Agent.ID,
469-
AppID: uuid.NullUUID{Valid: aReq.dbReq.App.ID != uuid.Nil, UUID: aReq.dbReq.App.ID},
470-
UserID: userID,
471-
Ip: aReq.ip,
472-
SlugOrPort: appInfo.SlugOrPort,
473-
UpdatedAt: aReq.time,
457+
startedAt, err = tx.UpsertWorkspaceAppAuditSession(dangerousSystemCtx, database.UpsertWorkspaceAppAuditSessionParams{
458+
// Config.
474459
StaleIntervalMS: p.WorkspaceAppAuditSessionTimeout.Milliseconds(),
475-
})
476-
if err != nil {
477-
return xerrors.Errorf("update workspace app audit session: %w", err)
478-
}
479-
if len(updatedIDs) > 0 {
480-
// Session is valid and got updated, no need to create a new audit log.
481-
return nil
482-
}
483460

484-
sessionID, err = tx.InsertWorkspaceAppAuditSession(dangerousSystemCtx, database.InsertWorkspaceAppAuditSessionParams{
461+
// Data.
485462
AgentID: aReq.dbReq.Agent.ID,
486-
AppID: uuid.NullUUID{Valid: aReq.dbReq.App.ID != uuid.Nil, UUID: aReq.dbReq.App.ID},
487-
UserID: userID,
463+
AppID: aReq.dbReq.App.ID, // Can be unset, in which case uuid.Nil is fine.
464+
UserID: userID, // Can be unset, in which case uuid.Nil is fine.
488465
Ip: aReq.ip,
466+
UserAgent: userAgent,
489467
SlugOrPort: appInfo.SlugOrPort,
468+
StatusCode: int32(statusCode),
490469
StartedAt: aReq.time,
491470
UpdatedAt: aReq.time,
492471
})
@@ -504,34 +483,23 @@ func (p *DBTokenProvider) auditInitRequest(ctx context.Context, w http.ResponseW
504483
return
505484
}
506485

507-
if sessionID == uuid.Nil {
508-
if sw.Status < 400 {
509-
// Session was updated and no error occurred, no need to
510-
// create a new audit log.
511-
return
512-
}
513-
if len(updatedIDs) > 0 {
514-
// Session was updated but an error occurred, we need to
515-
// create a new audit log.
516-
sessionID = updatedIDs[0]
517-
} else {
518-
// This shouldn't happen, but fall-back to request so it
519-
// can be correlated to _something_.
520-
sessionID = httpmw.RequestID(r)
521-
}
486+
if !startedAt.Equal(aReq.time) {
487+
// If the unique session wasn't renewed, we don't want to log a new
488+
// audit event for it.
489+
return
522490
}
523491

524-
// Mimic the behavior of a HTTP status writer
525-
// by defaulting to 200 if the status is 0.
526-
status := sw.Status
527-
if status == 0 {
528-
status = http.StatusOK
492+
// Marshal additional fields only if we're writing an audit log entry.
493+
appInfoBytes, err := json.Marshal(appInfo)
494+
if err != nil {
495+
logger.Error(ctx, "marshal additional fields failed", slog.Error(err))
529496
}
530497

531498
// We use the background audit function instead of init request
532499
// here because we don't know the resource type ahead of time.
533500
// This also allows us to log unauthenticated access.
534501
auditor := *p.Auditor.Load()
502+
requestID := httpmw.RequestID(r)
535503
switch {
536504
case aReq.dbReq.App.ID != uuid.Nil:
537505
audit.BackgroundAudit(ctx, &audit.BackgroundAuditParams[database.WorkspaceApp]{
@@ -540,12 +508,12 @@ func (p *DBTokenProvider) auditInitRequest(ctx context.Context, w http.ResponseW
540508

541509
Action: database.AuditActionOpen,
542510
OrganizationID: aReq.dbReq.Workspace.OrganizationID,
543-
UserID: userID.UUID,
544-
RequestID: sessionID,
511+
UserID: userID,
512+
RequestID: requestID,
545513
Time: aReq.time,
546-
Status: status,
514+
Status: statusCode,
547515
IP: aReq.ip.IPNet.IP.String(),
548-
UserAgent: r.UserAgent(),
516+
UserAgent: userAgent,
549517
New: aReq.dbReq.App,
550518
AdditionalFields: appInfoBytes,
551519
})
@@ -557,12 +525,12 @@ func (p *DBTokenProvider) auditInitRequest(ctx context.Context, w http.ResponseW
557525

558526
Action: database.AuditActionOpen,
559527
OrganizationID: aReq.dbReq.Workspace.OrganizationID,
560-
UserID: userID.UUID,
561-
RequestID: sessionID,
528+
UserID: userID,
529+
RequestID: requestID,
562530
Time: aReq.time,
563-
Status: status,
531+
Status: statusCode,
564532
IP: aReq.ip.IPNet.IP.String(),
565-
UserAgent: r.UserAgent(),
533+
UserAgent: userAgent,
566534
New: aReq.dbReq.Agent,
567535
AdditionalFields: appInfoBytes,
568536
})

0 commit comments

Comments
 (0)