Repository navigation
feat(backend): transactional action revisions and execution binding (WI-2173) - #508
Conversation
…ecutions (WI-2173) Every successful workspace-action definition write now persists an immutable, attributable revision and its durable audit rows in the same transaction as the action row and graph. A revision or audit failure rolls the mutation back, and the create/update/delete/template/import paths all funnel through ActionDefinitionService so adapters cannot double-write history. - Add action_definition_revisions (retained after action deletion) plus actions.current_revision_id and action_execution_logs.definition_revision_id, with a migration that backfills a clearly marked baseline for existing definitions without inventing authorship. - Bind each execution to the exact revision it runs by executing the frozen snapshot and recording its id, reusing the first attempt's revision on durable retries. - Require global action.set_actor to change execution-affecting config on an action with a configured actor; audit denied attempts with safe metadata on the v2, v1, and AI-tool adapters. - Expose authorized v2 revision list/detail endpoints and an action history view in the editor.
|
Size Change: 0 B 🆕 Total Size: 0 B |
Review: changes requestedThree findings at d26cf7d:
Static review only; tests were not run. |
…173) Address review findings on the revision foundation: - Resolve the actor patch and its authorization against the locked action row inside the write transaction. A save that started before a concurrent actor clear can no longer republish the cleared privileged identity in a revision that execution then trusts. - Authorize retained revision reads against the workspace and scope the query by workspace, so history stays reachable after the action row is deleted instead of returning not-found. - Centralize denied privileged-edit auditing in the definition service so the v2, v1, and AI-tool adapters all write a safe denied event. The denied-audit write runs after the mutation transaction rolls back, which avoids re-entering the single SQLite write connection.
|
Addressed all three findings in
Targeted tests pass on SQLite and PostgreSQL (black-box action-revision set, the locked-actor service test, repository retention, and the baseline migration). No new v1 surface; OpenAPI and lint guards are green. |
|
This PR has merge conflicts that need to be resolved before it can be merged. Please rebase on the latest |
|
Merge conflicts have been resolved. |
|
Merge preparation completed in 85aa3e3:
Validation:
PostgreSQL and browser suites were not rerun. Refreshed GitHub checks are running before merge. |
Delivers the WI-2173 audit/revision foundation ahead of Sobek script
execution. Tests live in the paired
core-tests-internalPR.What changed
Immutable, attributable revisions
action_definition_revisionstable captures the full executablesnapshot (trigger + config, nodes + config, edges, actor override,
enablement, execution-role restrictions) plus editor identity/source,
timestamp, source label,
change_summary, andchanged_fields.actions.current_revision_idpoints at the live revision;action_execution_logs.definition_revision_idrecords what ran.source='baseline'revisionfor every existing definition with
editor_user_id = NULLandeditor_source='system', so no historical authorship is invented.Transactional coupling
ActionDefinitionServicenow owns one transaction per mutation: actionrow + graph + revision + audit rows commit or roll back together. An
audit or revision failure aborts the mutation.
create,update,delete, and template application all funnel throughthat service, including the v1 handler and the AI/MCP tools, so adapters
cannot double-write or skip history.
Execution binding
ActionServiceexecutes the frozen revision snapshot and records its id,rather than the mutable action row, so a concurrent edit cannot make the
recorded revision disagree with what ran. Durable retries reuse the
revision from the first attempt. The cached action is never mutated, so
concurrent executions stay isolated.
Authorization hardening
allowed roles) on an action with a configured actor now requires the
global
action.set_actorpermission — on v2, v1, and the AI-tool paths.action.managealone is no longer enough. Denied attempts are auditedwith safe metadata (attempted field names only, never the definition).
action.manageon the workspace(
actions:readscope).API and UI
GET /rest/api/v2/workspaces/{id}/actions/{action_id}/revisionsGET /rest/api/v2/workspaces/{id}/actions/{action_id}/revisions/{revision_id}snapshot. No v1 surface added.
Retention
Revisions are intentionally not cascade-deleted with the action, so an
execution can always be traced back to the definition that ran. They do
cascade with the workspace, matching the existing workspace-deletion wipe.
Out of scope
Asset actions (separate domain, no actor override) and the broader
MCP/CLI authoring and restore tooling in WI-1316.
Tests
All in the paired core-tests PR; see that PR for exact commands. Coverage
includes exact snapshots/diffs and attribution, execution revision binding,
deletion/history retention, baseline migration, actor-edit denial with an
unchanged
actor_user_id, and exact v2 permission contracts on SQLite andPostgreSQL, plus frontend unit and Playwright coverage of the history view.