From b2f19cad3c34409a0c92da54c90a6d29e0efeb76 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Wed, 18 Feb 2026 20:59:40 +0100 Subject: [PATCH] fix(audit): record system actor when API tokens are auto-revoked Allow APITokenRevoked audit events to be recorded when tokens are automatically revoked due to inactivity. Override RequiresActor() to return false on APITokenRevoked, following the pattern used by CASBackendStatusChanged. This enables the audit trail to capture auto-revocations with the system actor (system@chainloop.dev) rather than silently dropping the event. Signed-off-by: Miguel Martinez --- .../pkg/auditor/events/apitoken.go | 8 ++++++- .../pkg/auditor/events/apitoken_test.go | 21 ++++++++++++++++--- .../api_token_revoked_by_system.json | 16 ++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 app/controlplane/pkg/auditor/events/testdata/apitokens/api_token_revoked_by_system.json diff --git a/app/controlplane/pkg/auditor/events/apitoken.go b/app/controlplane/pkg/auditor/events/apitoken.go index 08a860836..2964ccdd6 100644 --- a/app/controlplane/pkg/auditor/events/apitoken.go +++ b/app/controlplane/pkg/auditor/events/apitoken.go @@ -1,5 +1,5 @@ // -// Copyright 2025 The Chainloop Authors. +// Copyright 2025-2026 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -95,6 +95,12 @@ type APITokenRevoked struct { *APITokenBase } +// RequiresActor returns false because revocations can be system-generated +// (e.g. auto-revoked due to inactivity by APITokenStaleRevoker). +func (a *APITokenRevoked) RequiresActor() bool { + return false +} + func (a *APITokenRevoked) ActionType() string { return APITokenRevokedActionType } diff --git a/app/controlplane/pkg/auditor/events/apitoken_test.go b/app/controlplane/pkg/auditor/events/apitoken_test.go index 4d72c1f2e..2a4aff418 100644 --- a/app/controlplane/pkg/auditor/events/apitoken_test.go +++ b/app/controlplane/pkg/auditor/events/apitoken_test.go @@ -1,5 +1,5 @@ // -// Copyright 2025 The Chainloop Authors. +// Copyright 2025-2026 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -100,6 +100,18 @@ func TestAPITokenEvents(t *testing.T) { actor: auditor.ActorTypeAPIToken, actorID: apiTokenUUID, }, + { + name: "API Token auto-revoked by system", + event: &events.APITokenRevoked{ + APITokenBase: &events.APITokenBase{ + APITokenID: uuidPtr(apiTokenUUID), + APITokenName: apiTokenName, + }, + }, + expected: "testdata/apitokens/api_token_revoked_by_system.json", + actor: auditor.ActorTypeSystem, + actorID: uuid.Nil, + }, } for _, tt := range tests { @@ -107,9 +119,12 @@ func TestAPITokenEvents(t *testing.T) { opts := []auditor.GeneratorOption{ auditor.WithOrgID(orgUUID), } - if tt.actor == auditor.ActorTypeAPIToken { + switch tt.actor { + case auditor.ActorTypeAPIToken: opts = append(opts, auditor.WithActor(auditor.ActorTypeAPIToken, tt.actorID, "", testAPITokenName)) - } else { + case auditor.ActorTypeSystem: + opts = append(opts, auditor.WithActor(auditor.ActorTypeSystem, uuid.Nil, "", "")) + default: opts = append(opts, auditor.WithActor(auditor.ActorTypeUser, tt.actorID, testEmail, testName)) } diff --git a/app/controlplane/pkg/auditor/events/testdata/apitokens/api_token_revoked_by_system.json b/app/controlplane/pkg/auditor/events/testdata/apitokens/api_token_revoked_by_system.json new file mode 100644 index 000000000..e192e6fd6 --- /dev/null +++ b/app/controlplane/pkg/auditor/events/testdata/apitokens/api_token_revoked_by_system.json @@ -0,0 +1,16 @@ +{ + "ActionType": "APITokenRevoked", + "TargetType": "APIToken", + "TargetID": "2089bb36-e27b-428b-8009-d015c8737c55", + "ActorType": "SYSTEM", + "ActorID": null, + "ActorEmail": "", + "ActorName": "", + "OrgID": "1089bb36-e27b-428b-8009-d015c8737c54", + "Description": "system@chainloop.dev has revoked the API token test-token", + "Info": { + "api_token_id": "2089bb36-e27b-428b-8009-d015c8737c55", + "api_token_name": "test-token" + }, + "Digest": "sha256:f867390a401bccbb15270dd2b54bf325dc56918925da9179af10f12787f0af24" +} \ No newline at end of file