Skip to content

fix(server): five audit_log calls omit the required action argument - #3181

Merged
bghira merged 1 commit into
bghira:mainfrom
Anai-Guo:fix-audit-log-missing-action
Aug 31, 2026
Merged

fix(server): five audit_log calls omit the required action argument#3181
bghira merged 1 commit into
bghira:mainfrom
Anai-Guo:fix-audit-log-missing-action

Conversation

@Anai-Guo

Copy link
Copy Markdown
Contributor

Problem

audit_log takes action as a required positional parameter:

# simpletuner_sdk/server/services/cloud/audit.py:638
async def audit_log(
    event_type: AuditEventType,
    action: str,
    **kwargs,
) -> int:
    store = get_audit_store()
    return await store.log(event_type, action, **kwargs)

Five call sites pass event_type as a keyword and never pass action at all, so each
raises:

TypeError: audit_log() missing 1 required positional argument: 'action'
file lines
server/routes/approvals.py 421, 486, 572, 636
server/services/cloud/credential_resolver.py 126

Impact differs by site

routes/approvals.py — unguarded, fires after the state change. At L421 the approval
has already been committed and the job already unblocked in the queue before the audit
call runs:

    if scheduler:
        await scheduler.approve_job(request.job_id, request_id)   # state already mutated
...
    # Audit log
    if request:
        await audit_log(                       # <-- raises here
            event_type=AuditEventType.JOB_APPROVED,

So the endpoint returns 500 for an approval that actually succeeded, and no audit record
is written. Same for reject (L486) and the bulk paths (L572, L636).

credential_resolver.py — swallowed. That call sits inside a try/except Exception
that logs at debug level, so credential-use auditing has silently never recorded anything.

The correct shape is already in the codebase

routes/auth.py calls it correctly throughout — positional event_type, then a
human-readable action string:

await audit_log(
    AuditEventType.AUTH_LOGIN_SUCCESS,
    f"User '{user.username}' logged in",
    actor_id=user.id,
    ...
)

approvals.py is the only module that consistently disagrees.

Verification

Binding each call against the real signature, with a working auth.py call as control:

audit_log signature: (event_type, action, **kwargs)

UNPATCHED  approvals.py:421   -> TypeError: missing a required argument: 'action'
CONTROL    auth.py:211        -> bound OK
PATCHED    approvals.py:421   -> bound OK

Change

Passes action positionally at all five sites, matching auth.py's phrasing. Every value
interpolated (request.job_id, user.username, provider, credential_name) is already
in scope and already used in the adjacent details dict. No behaviour changes beyond the
audit records now actually being written.


🤖 Generated with Claude Code

audit_log(event_type, action, **kwargs) takes action positionally, but
five call sites pass event_type as a keyword and never pass action, so
each raises TypeError: missing a required argument: 'action'.

In routes/approvals.py the four calls are unguarded and run after the
approval has already been committed, so the endpoint 500s on a request
that actually succeeded and no audit record is written. In
services/cloud/credential_resolver.py the call sits inside a try/except
that logs at debug level, so credential-use auditing silently never
records anything.

Pass action positionally in the same style as routes/auth.py.
@bghira

bghira commented Aug 31, 2026

Copy link
Copy Markdown
Owner

thanks

@bghira
bghira merged commit 286c6a6 into bghira:main Aug 31, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants