66 "errors"
77 "fmt"
88 "net/http"
9+ "slices"
910 "time"
1011
1112 "github.com/blang/semver/v4"
@@ -264,6 +265,17 @@ func AuditEventUnaryInterceptor(logger *zap.Logger, eventPairChecker audit.Event
264265 }
265266 }()
266267
268+ // When delete occurs there is no object returned. Audit log for rollout and rule
269+ // includes a limited set of fields, so we need to store the deleted record in the context
270+ // to improve audit log information. See https://github.com/orgs/flipt-io/discussions/4311
271+ if slices .ContainsFunc (requests , func (r flipt.Request ) bool {
272+ return r .Action == flipt .ActionDelete && slices .Contains ([]flipt.Subject {
273+ flipt .SubjectRollout , flipt .SubjectRule ,
274+ }, r .Subject )
275+ }) {
276+ ctx = context .WithValue (ctx , audit .DeletedRecordCtxKey , map [any ]any {})
277+ }
278+
267279 resp , err := handler (ctx , req )
268280 for _ , request := range requests {
269281 if err != nil {
@@ -279,7 +291,18 @@ func AuditEventUnaryInterceptor(logger *zap.Logger, eventPairChecker audit.Event
279291 // Delete and Order request(s) have to be handled separately because they do not
280292 // return the concrete type but rather an *empty.Empty response.
281293 if request .Action == flipt .ActionDelete {
282- events = append (events , audit .NewEvent (request , actor , r ))
294+ payload := any (r )
295+ // Try to load deleted record from context and add extra info if possible.
296+ data , ok := ctx .Value (audit .DeletedRecordCtxKey ).(map [any ]any )
297+ if ok && data [req ] != nil {
298+ switch r := data [req ].(type ) {
299+ case * flipt.Rollout :
300+ payload = audit .NewRollout (r )
301+ case * flipt.Rule :
302+ payload = audit .NewRule (r )
303+ }
304+ }
305+ events = append (events , audit .NewEvent (request , actor , payload ))
283306 continue
284307 }
285308
0 commit comments