Skip to content

fix(workflow): honor enabled: false flag at execution time and persist it - #4742

Open
veltri-23 wants to merge 4 commits into
block:mainfrom
veltri-23:fix/4639-enabled-false-honored
Open

fix(workflow): honor enabled: false flag at execution time and persist it#4742
veltri-23 wants to merge 4 commits into
block:mainfrom
veltri-23:fix/4639-enabled-false-honored

Conversation

@veltri-23

Copy link
Copy Markdown

Summary

The workflow enabled: false YAML flag was documented but not authoritative. The cron scheduler and event paths pre-filter on def.enabled, but the webhook, manual-trigger, and approval-resume paths gated only on the DB enabled column, which the definition never wrote (create/upsert hardcoded TRUE). 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. New WorkflowError::Disabled.
  • buzz-db: create_workflow and upsert_workflow now persist the definition's enabled flag instead of hardcoding TRUE; upsert update path sets enabled = EXCLUDED.enabled.
  • Backfill migration 0027: existing definitions with explicit enabled: false get the column flipped, only explicit false values (independent runtime disables and absent flags are left alone).

Changes

File Change
crates/buzz-workflow/src/error.rs Add WorkflowError::Disabled
crates/buzz-workflow/src/executor.rs Fail-closed gate in execute_run + execute_from_step
crates/buzz-workflow/src/lib.rs ensure_workflow_enabled() + unit tests
crates/buzz-db/src/workflow.rs Persist enabled from definition in create/upsert
crates/buzz-db/src/migration.rs Migration count 26 → 27
migrations/0027_workflow_enabled_backfill.sql Backfill explicit enabled: false

Audit fixes (independent Codex review)

A read-only Codex audit of this branch found three issues, all fixed:

  1. CRITICAL — bind-count mismatch in upsert_workflow: the SQL declared 7 placeholders but the code bound 8 parameters, so every upsert failed at runtime. VALUES now uses COALESCE($8, TRUE).
  2. MEDIUM — upsert clobbered runtime disables: the conflict path wrote enabled = EXCLUDED.enabled, silently re-enabling workflows an operator or membership-loss disabled via set_workflow_enabled(false). The conflict path now uses COALESCE($8, workflows.enabled), and enabled_from_definition returns Option<bool> so an absent field preserves the current row value instead of defaulting to true. create_workflow keeps the true default for new rows.
  3. MEDIUM — approval-resume ignored the persisted column: resume_workflow_after_approval never checked workflow.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 are api::media/api::admin tests 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-relay and cargo fmt --check clean.
  • New unit tests: 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.

@veltri-23
veltri-23 requested a review from a team as a code owner August 4, 2026 16:24
@tlongwell-block

Copy link
Copy Markdown
Collaborator

Heads-up before merge: this PR and #4647 both add a migrations/0027_*.sql. sqlx does not detect duplicate versions at resolve time — whichever merges second causes a checksum VersionMismatch(27) at boot, which with BUZZ_AUTO_MIGRATE=true on bb-public is a hard boot failure on every pod (it will NOT fail loudly in CI). #4647 is the active-incident fix and is merging first — please renumber this migration to 0028 (and the count assertion 27 → 28) before merging. Context: Sami's review in the buzz-push-scan-optimization channel, 2026-08-04.

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>
@veltri-23
veltri-23 force-pushed the fix/4639-enabled-false-honored branch from 5a7f337 to 48e3c2f Compare August 4, 2026 18:33
@veltri-23

Copy link
Copy Markdown
Author

Thanks for the heads-up. Fixed: rebased onto main and renumbered the backfill migration to 0028_workflow_enabled_backfill.sql, with the count assertion bumped 27 -> 28. The branch now carries only 0028, so no collision with #4647's 0027_channels_id_lookup_index.sql and no checksum mismatch at boot. Migration test passes locally.

@veltri-23

Copy link
Copy Markdown
Author

@tlongwell-block ^^^

@veltri-23

Copy link
Copy Markdown
Author

@tlongwell-block per your note above: migration renumbered to 0028 and pushed. No collision with #4647 anymore.

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