fix(workflow): honor enabled: false flag at execution time and persist it - #4742
fix(workflow): honor enabled: false flag at execution time and persist it#4742veltri-23 wants to merge 4 commits into
Conversation
|
Heads-up before merge: this PR and #4647 both add a |
Signed-off-by: Hunter Veltri <veltrifinancial@gmail.com>
create_workflow and upsert_workflow hardcoded the DB enabled column to TRUE, so a YAML-disabled workflow stayed visible to enabled-workflow list queries. Read enabled from the definition JSON with a true default for legacy rows, and backfill explicit false values in a migration. Bump the embedded-migrator count test to include the new migration. Signed-off-by: Hunter Veltri <veltrifinancial@gmail.com>
… upsert Codex audit of the enabled-flag PR found a bind-count mismatch: upsert_workflow bound 8 parameters but the INSERT declared 7 placeholders, so every upsert failed at runtime. The conflict path also wrote enabled = EXCLUDED.enabled, silently re-enabling workflows an operator or membership-loss had disabled. - upsert_workflow: VALUES uses COALESCE($8, TRUE) and the conflict path uses COALESCE($8, workflows.enabled), so an explicit enabled field wins while an absent field preserves the current row value. - enabled_from_definition now returns Option<bool> to distinguish an explicit flag from the legacy default; create_workflow applies unwrap_or(true). - resume_workflow_after_approval gains the same SEC-006 lifecycle gate as the webhook and manual-trigger paths, so a disabled workflow with a pending approval cannot resume into execution. - Tests updated for the Option<bool> shape. Signed-off-by: Hunter Veltri <veltrifinancial@gmail.com>
PR block#4647 merged as 0027_channels_id_lookup_index.sql, so the embedded migrator would have two version-27 migrations. Whichever merged second breaks the sqlx checksum (VersionMismatch(27)) at boot with BUZZ_AUTO_MIGRATE=true. Renumber to 0028 and bump the count assertion 27 -> 28. Signed-off-by: Hunter Veltri <veltrifinancial@gmail.com>
5a7f337 to
48e3c2f
Compare
|
Thanks for the heads-up. Fixed: rebased onto main and renumbered the backfill migration to |
|
@tlongwell-block ^^^ |
|
@tlongwell-block per your note above: migration renumbered to 0028 and pushed. No collision with #4647 anymore. |
Summary
The workflow
enabled: falseYAML flag was documented but not authoritative. The cron scheduler and event paths pre-filter ondef.enabled, but the webhook, manual-trigger, and approval-resume paths gated only on the DBenabledcolumn, which the definition never wrote (create/upsert hardcodedTRUE). A YAML-disabled workflow could still execute through those entry points, and enabled-workflow list queries could surface it.This PR makes the YAML flag authoritative everywhere:
buzz-workflow:ensure_workflow_enabled()fail-closed gate at both executor entry points (execute_run,execute_from_step) before any run side effects. NewWorkflowError::Disabled.buzz-db:create_workflowandupsert_workflownow persist the definition'senabledflag instead of hardcodingTRUE;upsertupdate path setsenabled = EXCLUDED.enabled.0027: existing definitions with explicitenabled: falseget the column flipped, only explicit false values (independent runtime disables and absent flags are left alone).Changes
crates/buzz-workflow/src/error.rsWorkflowError::Disabledcrates/buzz-workflow/src/executor.rsexecute_run+execute_from_stepcrates/buzz-workflow/src/lib.rsensure_workflow_enabled()+ unit testscrates/buzz-db/src/workflow.rsenabledfrom definition in create/upsertcrates/buzz-db/src/migration.rsmigrations/0027_workflow_enabled_backfill.sqlenabled: falseAudit fixes (independent Codex review)
A read-only Codex audit of this branch found three issues, all fixed:
upsert_workflow: the SQL declared 7 placeholders but the code bound 8 parameters, so every upsert failed at runtime.VALUESnow usesCOALESCE($8, TRUE).enabled = EXCLUDED.enabled, silently re-enabling workflows an operator or membership-loss disabled viaset_workflow_enabled(false). The conflict path now usesCOALESCE($8, workflows.enabled), andenabled_from_definitionreturnsOption<bool>so an absent field preserves the current row value instead of defaulting totrue.create_workflowkeeps thetruedefault for new rows.resume_workflow_after_approvalnever checkedworkflow.enabled, so a disabled workflow with a pending approval could resume. It now applies the same SEC-006 lifecycle gate as the webhook and manual-trigger paths.Testing
cargo test -p buzz-db -p buzz-workflow: 96 + 156 passed, 0 failed.cargo test -p buzz-relay --lib: 826 passed; the 9 failures areapi::media/api::admintests requiring a live Postgres (CI runs these against the dockerized stack) and are unrelated to this change.cargo check -p buzz-db -p buzz-workflow -p buzz-relayandcargo fmt --checkclean.ensure_workflow_enabled_allows_enabled_def,ensure_workflow_enabled_defaults_to_enabled,ensure_workflow_enabled_refuses_disabled_def,enabled_from_definition_honors_explicit_flag_and_default,enabled_from_definition_rejects_invalid_json.