Skip to content

Commit 40db1a5

Browse files
ci(decision-model-lint): Split the audit rule into narrow checks
Replace the broad auth-change audit rule with four narrow rules for secret rotation, token issuance and revocation, privilege grants, and account identity changes. In a whole-codebase run, about 87% of the narrow rules' findings were real, versus about 23% for the broad rule. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent ff1aba5 commit 40db1a5

1 file changed

Lines changed: 63 additions & 9 deletions

File tree

‎decisionModelLinter.config.ts‎

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,25 +118,79 @@ const audit = {
118118
'src/sentry/web/frontend/debug/**',
119119
],
120120
rules: {
121-
authChangeAuditTrail: {
121+
rotatesSecretWithoutRecord: {
122122
prompt:
123-
'Does the code change authentication or access state, and if so, does it record the change with create_audit_entry, create_audit_entry_from_user, create_system_audit_entry, log_service.record_audit_log, or capture_security_activity?',
123+
'Does the code replace an existing client secret, signing secret, or webhook token with a new value at a user\'s request, such as rotating ApiApplication.client_secret or regenerating a project token? Generating a secret while installing an integration or creating a webhook subscription does not count. If so, does the same file record it with create_audit_entry, create_audit_entry_from_user, create_system_audit_entry, log_service.record_audit_log, capture_security_activity, or a sentry.audit logger (logging.getLogger("sentry.audit..."))?',
124124
values: [
125125
{
126-
value: 'UNAUDITED',
126+
value: 'TRUE',
127+
description:
128+
'The code assigns or updates a secret field with a newly generated value. Nothing in the file records it.',
129+
severity: 'warn',
130+
report:
131+
'Record this change: org-level changes with create_audit_entry and an event from sentry/audit_log/register.py, user-level changes with capture_security_activity. If a function this code calls already records it, say so in the PR.',
132+
},
133+
{
134+
value: 'FALSE',
135+
description:
136+
'No secret field gets a new value. Reading or comparing a secret does not count. Or the file records it.',
137+
},
138+
],
139+
},
140+
issuesOrRevokesTokenWithoutRecord: {
141+
prompt:
142+
'Outside the OAuth flows for third-party apps (ApiGrant, ApiAuthorization, the authorize, consent, token, and authorizations endpoints, and Sentry App token exchange or refresh), does the code create, revoke, deactivate, or change the scopes of an ApiToken, OrgAuthToken, ApiKey, SentryAppInstallationToken, or an agent token grant? Authenticating a request with a token does not count. If so, does the same file record it with create_audit_entry, create_audit_entry_from_user, create_system_audit_entry, log_service.record_audit_log, capture_security_activity, or a sentry.audit logger (logging.getLogger("sentry.audit..."))?',
143+
values: [
144+
{
145+
value: 'TRUE',
127146
description:
128-
'The code creates, updates, or deletes auth state and nothing in the file records that action. Auth state is: member roles, team roles, invites, or adding and removing members; AuthProvider or SSO config; linking or unlinking an AuthIdentity; creating, rotating, or revoking an ApiToken, ApiKey, OrgAuthToken, or SentryAppInstallationToken; rotating a Sentry App client secret; 2FA authenticators; password, email, or primary email; superuser or staff grants; and org settings that require 2FA or email verification.',
147+
'The code calls create, delete, or update on one of those token models (for example ApiToken.objects.create, token.delete(), update(date_deactivated=...), or update(scope_list=...)), or calls a function whose name says it grants token scopes (for example create_write_grant). Nothing in the file records it.',
129148
severity: 'warn',
130149
report:
131-
'This changes auth or access state without recording it. Record org changes with create_audit_entry and an event from sentry/audit_log/register.py, and user changes such as password, email, or 2FA with capture_security_activity. If a helper this code calls already records it, say so in the PR.',
150+
'Record this change: org-level changes with create_audit_entry and an event from sentry/audit_log/register.py, user-level changes with capture_security_activity. If a function this code calls already records it, say so in the PR.',
132151
},
133152
{
134-
value: 'AUDITED',
135-
description: 'The code changes auth state and the file records it.',
153+
value: 'FALSE',
154+
description:
155+
'No such token is created, revoked, or rescoped. Authenticating with a token, updating last_used or date_last_used, and the OAuth authorize, consent, and token flows for third-party apps do not count. Or the file records it.',
136156
},
157+
],
158+
},
159+
changesPrivilegeWithoutRecord: {
160+
prompt:
161+
'Does the code grant or remove is_superuser, is_staff, or a UserPermission for a user? Organization and team roles are not privileges here. If so, does the same file record it with create_audit_entry, create_audit_entry_from_user, create_system_audit_entry, log_service.record_audit_log, capture_security_activity, or a sentry.audit logger (logging.getLogger("sentry.audit..."))?',
162+
values: [
137163
{
138-
value: 'NOT_AUTH',
139-
description: 'The code does not change auth or access state.',
164+
value: 'TRUE',
165+
description:
166+
'The code sets is_superuser or is_staff on a User, or creates or deletes a UserPermission, and no audit_logger.info(...) call on a sentry.audit logger follows it. Judge each separately: if is_superuser or is_staff changes and only the UserPermission change is recorded, answer TRUE. Nothing in the file records it.',
167+
severity: 'warn',
168+
report:
169+
'Record this change: org-level changes with create_audit_entry and an event from sentry/audit_log/register.py, user-level changes with capture_security_activity. If a function this code calls already records it, say so in the PR.',
170+
},
171+
{
172+
value: 'FALSE',
173+
description:
174+
'No privilege flag or UserPermission changes. Starting or ending a superuser or staff session, and checking whether a user has a privilege, do not count. Or the file records it.',
175+
},
176+
],
177+
},
178+
changesAccountIdentityWithoutRecord: {
179+
prompt:
180+
'Does the code change a user\'s email or primary email, unlink or delete an AuthIdentity, or merge or delete user accounts? If so, does the same file record it with create_audit_entry, create_audit_entry_from_user, create_system_audit_entry, log_service.record_audit_log, capture_security_activity, or a sentry.audit logger (logging.getLogger("sentry.audit..."))?',
181+
values: [
182+
{
183+
value: 'TRUE',
184+
description:
185+
'The code updates User.email or a UserEmail of an existing user, deletes an AuthIdentity, or merges or deletes User records. Setting the email of a new account being registered does not count. Nothing in the file records it.',
186+
severity: 'warn',
187+
report:
188+
'Record this change: org-level changes with create_audit_entry and an event from sentry/audit_log/register.py, user-level changes with capture_security_activity. If a function this code calls already records it, say so in the PR.',
189+
},
190+
{
191+
value: 'FALSE',
192+
description:
193+
'None of those change. Linking an identity through SSO setup, integration Identity links (Slack, MS Teams, Discord), verifying an email, and logging in do not count. Or the file records it.',
140194
},
141195
],
142196
},

0 commit comments

Comments
 (0)