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