From cdff4e30cf0c0b731588b97cf05700dc29e0d7af Mon Sep 17 00:00:00 2001 From: Evan Vetere Date: Fri, 26 Jun 2026 23:17:33 -0400 Subject: [PATCH 1/2] fix: null-guard responseObject.metadata.name in ActivityPolicy creates The create rules dereference audit.responseObject.metadata.name in their summary, but a rejected create (409/422/admission-deny) returns a Status object with no metadata.name. The rules still match (keyed on verb/request), so CEL raises "no such key: name", the event goes to the DLQ, and retries fail identically -- a slow DLQ leak (same class as the gateway policy leak that fired DLQSlowLeak in prod). Guard the leaf and fall back to audit.objectRef.name across the resourcemanager (project, organization), iam (role, group, serviceaccount), and identity (serviceaccount) create rules. --- config/services/activity/policies/iam/group-policy.yaml | 2 +- config/services/activity/policies/iam/role-policy.yaml | 2 +- .../services/activity/policies/iam/serviceaccount-policy.yaml | 2 +- .../activity/policies/resourcemanager/organization-policy.yaml | 2 +- .../activity/policies/resourcemanager/project-policy.yaml | 2 +- config/services/identity/policies/serviceaccount-policy.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config/services/activity/policies/iam/group-policy.yaml b/config/services/activity/policies/iam/group-policy.yaml index 7d5a124c..e2b3426c 100644 --- a/config/services/activity/policies/iam/group-policy.yaml +++ b/config/services/activity/policies/iam/group-policy.yaml @@ -25,7 +25,7 @@ spec: auditRules: - name: create match: "!audit.user.username.startsWith('system:') && audit.verb == 'create'" - summary: "{{ actor }} created group {{ link(audit.responseObject.metadata.name, audit.objectRef) }}" + summary: "{{ actor }} created group {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : link(audit.objectRef.name, audit.objectRef) }}" - name: delete match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete'" diff --git a/config/services/activity/policies/iam/role-policy.yaml b/config/services/activity/policies/iam/role-policy.yaml index 79eff0bc..70506c94 100644 --- a/config/services/activity/policies/iam/role-policy.yaml +++ b/config/services/activity/policies/iam/role-policy.yaml @@ -12,7 +12,7 @@ spec: auditRules: - name: create match: "!audit.user.username.startsWith('system:') && audit.verb == 'create'" - summary: "{{ actor }} created role {{ link(audit.responseObject.metadata.name, audit.objectRef) }}" + summary: "{{ actor }} created role {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : link(audit.objectRef.name, audit.objectRef) }}" - name: delete match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete'" diff --git a/config/services/activity/policies/iam/serviceaccount-policy.yaml b/config/services/activity/policies/iam/serviceaccount-policy.yaml index 3c281705..ab932577 100644 --- a/config/services/activity/policies/iam/serviceaccount-policy.yaml +++ b/config/services/activity/policies/iam/serviceaccount-policy.yaml @@ -26,7 +26,7 @@ spec: auditRules: - name: create match: "!audit.user.username.startsWith('system:') && audit.verb == 'create'" - summary: "{{ actor }} created service account {{ link(audit.responseObject.metadata.name, audit.objectRef) }}" + summary: "{{ actor }} created service account {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : link(audit.objectRef.name, audit.objectRef) }}" - name: delete match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete'" diff --git a/config/services/activity/policies/resourcemanager/organization-policy.yaml b/config/services/activity/policies/resourcemanager/organization-policy.yaml index eb4ac89c..05712c0d 100644 --- a/config/services/activity/policies/resourcemanager/organization-policy.yaml +++ b/config/services/activity/policies/resourcemanager/organization-policy.yaml @@ -26,7 +26,7 @@ spec: auditRules: - name: create match: "!audit.user.username.startsWith('system:') && audit.verb == 'create'" - summary: "{{ actor }} created organization {{ link(audit.responseObject.metadata.name, audit.objectRef) }}" + summary: "{{ actor }} created organization {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : link(audit.objectRef.name, audit.objectRef) }}" - name: delete match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete'" diff --git a/config/services/activity/policies/resourcemanager/project-policy.yaml b/config/services/activity/policies/resourcemanager/project-policy.yaml index a2696494..ee1d0268 100644 --- a/config/services/activity/policies/resourcemanager/project-policy.yaml +++ b/config/services/activity/policies/resourcemanager/project-policy.yaml @@ -25,7 +25,7 @@ spec: auditRules: - name: create match: "!audit.user.username.startsWith('system:') && audit.verb == 'create'" - summary: "{{ actor }} created project {{ link(audit.responseObject.metadata.name, audit.objectRef) }}" + summary: "{{ actor }} created project {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : link(audit.objectRef.name, audit.objectRef) }}" - name: delete match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete'" diff --git a/config/services/identity/policies/serviceaccount-policy.yaml b/config/services/identity/policies/serviceaccount-policy.yaml index 3c281705..ab932577 100644 --- a/config/services/identity/policies/serviceaccount-policy.yaml +++ b/config/services/identity/policies/serviceaccount-policy.yaml @@ -26,7 +26,7 @@ spec: auditRules: - name: create match: "!audit.user.username.startsWith('system:') && audit.verb == 'create'" - summary: "{{ actor }} created service account {{ link(audit.responseObject.metadata.name, audit.objectRef) }}" + summary: "{{ actor }} created service account {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : link(audit.objectRef.name, audit.objectRef) }}" - name: delete match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete'" From a5284bd53f44123fc8c0563866d5a424309bd49f Mon Sep 17 00:00:00 2001 From: Evan Vetere Date: Sat, 27 Jun 2026 00:54:26 -0400 Subject: [PATCH 2/2] fix: extend ActivityPolicy create fallback for rejected generateName creates The create summaries guarded responseObject.metadata.name and fell back to audit.objectRef.name, but a generateName create rejected before a name is assigned has an EMPTY objectRef.name. The else branch then derefs audit.objectRef.name on a Status responseObject and raises "no such key: name" again, so the event still dead-letters. The assigned name is carried on the Status at responseObject.details.name. Replace each create summary with a per-level-guarded fallback chain: responseObject.metadata.name -> objectRef.name -> responseObject.details.name -> literal The details branch is guarded with has(responseObject.details) because some Status responses carry no details. Confirmed live in the sibling NSO repo: activity-processor logs show generateName creates (Connector) re-failing the DLQ retry on the objectRef.name branch. Same latent gap exists for every metadata.name create rule here. Co-Authored-By: Claude Opus 4.8 (1M context) --- config/services/activity/policies/iam/group-policy.yaml | 2 +- config/services/activity/policies/iam/role-policy.yaml | 2 +- .../services/activity/policies/iam/serviceaccount-policy.yaml | 2 +- .../activity/policies/resourcemanager/organization-policy.yaml | 2 +- .../activity/policies/resourcemanager/project-policy.yaml | 2 +- config/services/identity/policies/serviceaccount-policy.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config/services/activity/policies/iam/group-policy.yaml b/config/services/activity/policies/iam/group-policy.yaml index e2b3426c..37a14ce8 100644 --- a/config/services/activity/policies/iam/group-policy.yaml +++ b/config/services/activity/policies/iam/group-policy.yaml @@ -25,7 +25,7 @@ spec: auditRules: - name: create match: "!audit.user.username.startsWith('system:') && audit.verb == 'create'" - summary: "{{ actor }} created group {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : link(audit.objectRef.name, audit.objectRef) }}" + summary: "{{ actor }} created group {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : has(audit.objectRef.name) ? link(audit.objectRef.name, audit.objectRef) : (has(audit.responseObject.details) && has(audit.responseObject.details.name)) ? link(audit.responseObject.details.name, audit.objectRef) : link('a group', audit.objectRef) }}" - name: delete match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete'" diff --git a/config/services/activity/policies/iam/role-policy.yaml b/config/services/activity/policies/iam/role-policy.yaml index 70506c94..53b210a8 100644 --- a/config/services/activity/policies/iam/role-policy.yaml +++ b/config/services/activity/policies/iam/role-policy.yaml @@ -12,7 +12,7 @@ spec: auditRules: - name: create match: "!audit.user.username.startsWith('system:') && audit.verb == 'create'" - summary: "{{ actor }} created role {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : link(audit.objectRef.name, audit.objectRef) }}" + summary: "{{ actor }} created role {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : has(audit.objectRef.name) ? link(audit.objectRef.name, audit.objectRef) : (has(audit.responseObject.details) && has(audit.responseObject.details.name)) ? link(audit.responseObject.details.name, audit.objectRef) : link('a role', audit.objectRef) }}" - name: delete match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete'" diff --git a/config/services/activity/policies/iam/serviceaccount-policy.yaml b/config/services/activity/policies/iam/serviceaccount-policy.yaml index ab932577..c212d369 100644 --- a/config/services/activity/policies/iam/serviceaccount-policy.yaml +++ b/config/services/activity/policies/iam/serviceaccount-policy.yaml @@ -26,7 +26,7 @@ spec: auditRules: - name: create match: "!audit.user.username.startsWith('system:') && audit.verb == 'create'" - summary: "{{ actor }} created service account {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : link(audit.objectRef.name, audit.objectRef) }}" + summary: "{{ actor }} created service account {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : has(audit.objectRef.name) ? link(audit.objectRef.name, audit.objectRef) : (has(audit.responseObject.details) && has(audit.responseObject.details.name)) ? link(audit.responseObject.details.name, audit.objectRef) : link('a service account', audit.objectRef) }}" - name: delete match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete'" diff --git a/config/services/activity/policies/resourcemanager/organization-policy.yaml b/config/services/activity/policies/resourcemanager/organization-policy.yaml index 05712c0d..ae51dbd3 100644 --- a/config/services/activity/policies/resourcemanager/organization-policy.yaml +++ b/config/services/activity/policies/resourcemanager/organization-policy.yaml @@ -26,7 +26,7 @@ spec: auditRules: - name: create match: "!audit.user.username.startsWith('system:') && audit.verb == 'create'" - summary: "{{ actor }} created organization {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : link(audit.objectRef.name, audit.objectRef) }}" + summary: "{{ actor }} created organization {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : has(audit.objectRef.name) ? link(audit.objectRef.name, audit.objectRef) : (has(audit.responseObject.details) && has(audit.responseObject.details.name)) ? link(audit.responseObject.details.name, audit.objectRef) : link('an organization', audit.objectRef) }}" - name: delete match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete'" diff --git a/config/services/activity/policies/resourcemanager/project-policy.yaml b/config/services/activity/policies/resourcemanager/project-policy.yaml index ee1d0268..786e50c7 100644 --- a/config/services/activity/policies/resourcemanager/project-policy.yaml +++ b/config/services/activity/policies/resourcemanager/project-policy.yaml @@ -25,7 +25,7 @@ spec: auditRules: - name: create match: "!audit.user.username.startsWith('system:') && audit.verb == 'create'" - summary: "{{ actor }} created project {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : link(audit.objectRef.name, audit.objectRef) }}" + summary: "{{ actor }} created project {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : has(audit.objectRef.name) ? link(audit.objectRef.name, audit.objectRef) : (has(audit.responseObject.details) && has(audit.responseObject.details.name)) ? link(audit.responseObject.details.name, audit.objectRef) : link('a project', audit.objectRef) }}" - name: delete match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete'" diff --git a/config/services/identity/policies/serviceaccount-policy.yaml b/config/services/identity/policies/serviceaccount-policy.yaml index ab932577..c212d369 100644 --- a/config/services/identity/policies/serviceaccount-policy.yaml +++ b/config/services/identity/policies/serviceaccount-policy.yaml @@ -26,7 +26,7 @@ spec: auditRules: - name: create match: "!audit.user.username.startsWith('system:') && audit.verb == 'create'" - summary: "{{ actor }} created service account {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : link(audit.objectRef.name, audit.objectRef) }}" + summary: "{{ actor }} created service account {{ has(audit.responseObject.metadata.name) ? link(audit.responseObject.metadata.name, audit.objectRef) : has(audit.objectRef.name) ? link(audit.objectRef.name, audit.objectRef) : (has(audit.responseObject.details) && has(audit.responseObject.details.name)) ? link(audit.responseObject.details.name, audit.objectRef) : link('a service account', audit.objectRef) }}" - name: delete match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete'"