Applications → bulk Move to status: the person's own username is recorded as the actor, so each timeline says \"via alex\ #410

Closed
opened 2026-10-01 10:46:30 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading every caller of change_status and what it passes as actor.

Checked again on 2026-10-01 against main at 0a5cad587: still present.

ApplicationEvent.actor is for entries written by something other than the person at the keyboard: an API token, a plugin, an import. The bulk status action on the Applications table fills it with the person's own username, so a move they made themselves in the browser is labelled as if something else made it, and the same act is recorded two ways depending on which button they pressed.

  • Where: applications/views.py:328 (ApplicationBulkView._status: change_status(application, wanted, actor=str(request.user))); the field's contract at applications/models.py:561-563 ("Who wrote it when it was not the person at the keyboard … Blank means the person themselves"); the marker at templates/applications/partials/timeline.html:44-48.
  • What happens: someone ticks ten applications and moves them to Ghosted. User.__str__ returns the username (accounts/models.py:127-128), so each of the ten entries stores actor="alex", and each timeline shows the move followed by "via alex", the muted marker that elsewhere means "API token laptop-agent" or "imap plugin". The single status card (ApplicationStatusView.post, applications/views.py:543), the board and the edit form pass no actor for the same move.
  • Why it matters: the timeline misattributes the person's own action, and everything else that reads actor gets it too: the API's event payloads (api/schemas.py:677, :706), the export (core/export.py:213, :226), and the status_changed notification data handed to notifier plugins (notifications/slow.py:176). Anything that uses a non-blank actor to tell automation from the person counts bulk moves as automated.
  • Fix: drop the actor argument in _status, as every other browser path does. If the bulk origin is worth keeping, say it in the entry's note, not in actor.

Done when

  • A test in tests/security/test_bulk_actions.py, beside test_a_status_change_writes_a_timeline_entry, asserts that the entry a bulk status move writes has actor == ""; it fails today with the username.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading every caller of `change_status` and what it passes as `actor`. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. `ApplicationEvent.actor` is for entries written by something other than the person at the keyboard: an API token, a plugin, an import. The bulk status action on the Applications table fills it with the person's own username, so a move they made themselves in the browser is labelled as if something else made it, and the same act is recorded two ways depending on which button they pressed. - **Where:** `applications/views.py:328` (`ApplicationBulkView._status`: `change_status(application, wanted, actor=str(request.user))`); the field's contract at `applications/models.py:561-563` ("Who wrote it when it was not the person at the keyboard … Blank means the person themselves"); the marker at `templates/applications/partials/timeline.html:44-48`. - **What happens:** someone ticks ten applications and moves them to *Ghosted*. `User.__str__` returns the username (`accounts/models.py:127-128`), so each of the ten entries stores `actor="alex"`, and each timeline shows the move followed by "via alex", the muted marker that elsewhere means "API token laptop-agent" or "imap plugin". The single status card (`ApplicationStatusView.post`, `applications/views.py:543`), the board and the edit form pass no actor for the same move. - **Why it matters:** the timeline misattributes the person's own action, and everything else that reads `actor` gets it too: the API's event payloads (`api/schemas.py:677`, `:706`), the export (`core/export.py:213`, `:226`), and the `status_changed` notification data handed to notifier plugins (`notifications/slow.py:176`). Anything that uses a non-blank actor to tell automation from the person counts bulk moves as automated. - **Fix:** drop the `actor` argument in `_status`, as every other browser path does. If the bulk origin is worth keeping, say it in the entry's note, not in `actor`. ## Done when - A test in `tests/security/test_bulk_actions.py`, beside `test_a_status_change_writes_a_timeline_entry`, asserts that the entry a bulk status move writes has `actor == ""`; it fails today with the username.
tiagoagueda added this to the 0.6.0 milestone 2026-10-01 10:46:30 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#410
No description provided.