@@ -3,6 +3,7 @@ package coderd
3
3
import (
4
4
"context"
5
5
"database/sql"
6
+ "encoding/json"
6
7
"errors"
7
8
"fmt"
8
9
"math"
@@ -431,6 +432,37 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
431
432
// Client probably doesn't care about this error, so just log it.
432
433
api .Logger .Error (ctx , "failed to post provisioner job to pubsub" , slog .Error (err ))
433
434
}
435
+
436
+ // We may need to complete the audit if wsbuilder determined that
437
+ // no provisioner could handle an orphan-delete job and completed it.
438
+ if createBuild .Orphan && createBuild .Transition == codersdk .WorkspaceTransitionDelete && provisionerJob .CompletedAt .Valid {
439
+ buildResourceInfo := audit.AdditionalFields {
440
+ WorkspaceName : workspace .Name ,
441
+ BuildNumber : strconv .Itoa (int (workspaceBuild .BuildNumber )),
442
+ BuildReason : workspaceBuild .Reason ,
443
+ WorkspaceID : workspace .ID ,
444
+ WorkspaceOwner : workspace .OwnerName ,
445
+ }
446
+ briBytes , err := json .Marshal (buildResourceInfo )
447
+ if err != nil {
448
+ api .Logger .Error (ctx , "failed to marshal build resource info for audit" , slog .Error (err ))
449
+ }
450
+ auditor := api .Auditor .Load ()
451
+ bag := audit .BaggageFromContext (ctx )
452
+ audit .BackgroundAudit (ctx , & audit.BackgroundAuditParams [database.WorkspaceBuild ]{
453
+ Audit : * auditor ,
454
+ Log : api .Logger ,
455
+ UserID : provisionerJob .InitiatorID ,
456
+ OrganizationID : workspace .OrganizationID ,
457
+ RequestID : provisionerJob .ID ,
458
+ IP : bag .IP ,
459
+ Action : database .AuditActionDelete ,
460
+ Old : previousWorkspaceBuild ,
461
+ New : * workspaceBuild ,
462
+ Status : http .StatusOK ,
463
+ AdditionalFields : briBytes ,
464
+ })
465
+ }
434
466
}
435
467
436
468
apiBuild , err := api .convertWorkspaceBuild (
0 commit comments