Skip to content

Audit retention job likely never purges: runs without a tenant context (same bug as #1405) #1411

Closed

Description

@iammukeshm

Found while reviewing #1406, by reading the code. Not reproduced yet.

AuditRetentionJob (Hangfire recurring job auditing-retention) runs ExecuteDeleteAsync on AuditDbContext.AuditRecords with no tenant context:

  • AuditRecordConfiguration calls builder.IsMultiTenant(), and AuditDbContext : BaseDbContext, so the table carries the Finbuckle tenant filter.
  • The job is registered via AddOrUpdate with no tenant job parameter, so FshJobActivator.ReceiveParameters never sets a tenant.

This is the same shape as #1405 (SessionCleanupHostedService → NullReferenceException in the tenant filter on every run). Expected result: every retention run fails, and Hangfire retries it until it gives up, so audit tables grow without bound in every tenant. Even if the filter didn't throw, the job would only purge whichever tenant happened to be resolved.

There are also no tests for AuditRetentionJob (nothing in src/Tests references it).

Suggested fix

Same pattern as #1406: iterate IMultiTenantStore<AppTenantInfo>.GetAllAsync(), open a scope per tenant, set IMultiTenantContextSetter, and run the sweep. Catch and log per tenant so one tenant's failure doesn't stop the others. Add an integration test that seeds old and new records in two tenants and asserts per-tenant deletion. It must fail on the current code first.

Also worth doing

Check that every other background entry point (hosted services and recurring jobs) that touches a BaseDbContext entity sets a tenant. As of this issue: Files' purge jobs use IgnoreQueryFilters, RolePermissionSyncHostedService iterates tenants, Billing uses a plain DbContext, and Sessions is fixed by #1406. An architecture test for this would be even better, though it's hard to express in NetArchTest.

Activity

  1. added a commit that references this issue on Sep 30, 2026
    b696bbd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions