@@ -401,27 +401,22 @@ func (p *DBTokenProvider) auditInitRequest(ctx context.Context, w http.ResponseW
401
401
}
402
402
committed = true
403
403
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
-
416
404
if aReq .dbReq == nil {
417
405
// App doesn't exist, there's information in the Request
418
406
// struct but we need UUIDs for audit logging.
419
407
return
420
408
}
421
409
422
- userID := uuid.NullUUID {}
410
+ userID := uuid .Nil
423
411
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
425
420
}
426
421
427
422
type additionalFields struct {
@@ -443,50 +438,34 @@ func (p *DBTokenProvider) auditInitRequest(ctx context.Context, w http.ResponseW
443
438
appInfo .SlugOrPort = aReq .dbReq .AppSlugOrPort
444
439
}
445
440
441
+ // If we end up logging, ensure relevant fields are set.
446
442
logger := p .Logger .With (
447
443
slog .F ("workspace_id" , aReq .dbReq .Workspace .ID ),
448
444
slog .F ("agent_id" , aReq .dbReq .Agent .ID ),
449
445
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 ),
451
448
slog .F ("app_slug_or_port" , appInfo .SlugOrPort ),
449
+ slog .F ("status_code" , statusCode ),
452
450
)
453
451
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 ) {
464
454
// nolint:gocritic // System context is needed to write audit sessions.
465
455
dangerousSystemCtx := dbauthz .AsSystemRestricted (ctx )
466
456
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.
474
459
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
- }
483
460
484
- sessionID , err = tx . InsertWorkspaceAppAuditSession ( dangerousSystemCtx , database. InsertWorkspaceAppAuditSessionParams {
461
+ // Data.
485
462
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.
488
465
Ip : aReq .ip ,
466
+ UserAgent : userAgent ,
489
467
SlugOrPort : appInfo .SlugOrPort ,
468
+ StatusCode : int32 (statusCode ),
490
469
StartedAt : aReq .time ,
491
470
UpdatedAt : aReq .time ,
492
471
})
@@ -504,34 +483,23 @@ func (p *DBTokenProvider) auditInitRequest(ctx context.Context, w http.ResponseW
504
483
return
505
484
}
506
485
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
522
490
}
523
491
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 ))
529
496
}
530
497
531
498
// We use the background audit function instead of init request
532
499
// here because we don't know the resource type ahead of time.
533
500
// This also allows us to log unauthenticated access.
534
501
auditor := * p .Auditor .Load ()
502
+ requestID := httpmw .RequestID (r )
535
503
switch {
536
504
case aReq .dbReq .App .ID != uuid .Nil :
537
505
audit .BackgroundAudit (ctx , & audit.BackgroundAuditParams [database.WorkspaceApp ]{
@@ -540,12 +508,12 @@ func (p *DBTokenProvider) auditInitRequest(ctx context.Context, w http.ResponseW
540
508
541
509
Action : database .AuditActionOpen ,
542
510
OrganizationID : aReq .dbReq .Workspace .OrganizationID ,
543
- UserID : userID . UUID ,
544
- RequestID : sessionID ,
511
+ UserID : userID ,
512
+ RequestID : requestID ,
545
513
Time : aReq .time ,
546
- Status : status ,
514
+ Status : statusCode ,
547
515
IP : aReq .ip .IPNet .IP .String (),
548
- UserAgent : r . UserAgent () ,
516
+ UserAgent : userAgent ,
549
517
New : aReq .dbReq .App ,
550
518
AdditionalFields : appInfoBytes ,
551
519
})
@@ -557,12 +525,12 @@ func (p *DBTokenProvider) auditInitRequest(ctx context.Context, w http.ResponseW
557
525
558
526
Action : database .AuditActionOpen ,
559
527
OrganizationID : aReq .dbReq .Workspace .OrganizationID ,
560
- UserID : userID . UUID ,
561
- RequestID : sessionID ,
528
+ UserID : userID ,
529
+ RequestID : requestID ,
562
530
Time : aReq .time ,
563
- Status : status ,
531
+ Status : statusCode ,
564
532
IP : aReq .ip .IPNet .IP .String (),
565
- UserAgent : r . UserAgent () ,
533
+ UserAgent : userAgent ,
566
534
New : aReq .dbReq .Agent ,
567
535
AdditionalFields : appInfoBytes ,
568
536
})
0 commit comments