fix(relay): descriptive SEC-006 denial + structured skip log for workflow triggers - #5135
Open
iroiro147 wants to merge 1 commit into
Open
fix(relay): descriptive SEC-006 denial + structured skip log for workflow triggers#5135iroiro147 wants to merge 1 commit into
iroiro147 wants to merge 1 commit into
Conversation
…flow triggers When a manual workflow trigger's owner-authority check fails, the relay previously returned the same generic 'not authorized to trigger this workflow' for every failure mode — membership lapse, disabled workflow, SEC-006 elevated-role denial — leaving callers unable to act (issue block#5122's 'silent, no error, no run record'). Split the rejections by cause: * 'only the workflow owner may trigger' (wrong caller) * 'disabled or inactive' (lifecycle) * 'no channel scope' (cannot verify owner authority) * SEC-006 — 'contains exfiltration-capable actions (call_webhook) that require the owner to hold the owner or admin role in this channel' * generic fallback includes the underlying WorkflowError Also enrich the WARN emitted on event-trigger SEC-006 skip with workflow_id, owner_pubkey, and requires_elevated_authority so the same silent failure mode in the on_event path is diagnosable from relay logs alone. Regression tests cover both branches of the new denial helper — SEC-006 hint must name call_webhook + the required roles; the ordinary-denial branch must not leak SEC-006 vocabulary. Signed-off-by: iroiro147 <sarthak.singh@mastersunion.org>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves #5122 (partial).
Root cause analysis
Issue #5122 reports that
call_webhookworkflow steps never deliver HTTP requests, with no error surfaced and no run record visible. The investigation identified three distinct, interlocking causes:Silent SEC-006 denial (actionable, fixed here): When a manual trigger's owner-authority check fails, the relay returned the same generic
"forbidden: not authorized to trigger this workflow"for every failure mode — membership lapse, disabled workflow, SEC-006 elevated-role denial — leaving callers unable to distinguish "you lack the admin role for call_webhook" from "workflow disabled." On the event-trigger path, the skip was only aWARNlog with the workflow_id and error, no owner_pubkey or requires_elevated flag.Run history unreadable (known, separately filed as Workflow run history is unreadable: always returns [] #2980 and workflow run history is write-never: 'buzz workflows runs' queries kinds 46001-46003 but relay never publishes them #4478):
buzz workflows runsqueries Nostr kinds 46001–46003, but the relay never emits those events. Run state lives only in Postgres. This means even whencall_webhookdoes fail (e.g. outbound HTTP blocked by infrastructure), the failure is invisible to the CLI. Not addressed here — it is a larger feature (event emission) tracked in its own issues.Outbound HTTP blocked by deployment (infrastructure, not code): If the relay is hosted where egress HTTP is restricted,
call_webhook_implreturnsErr(WorkflowError::WebhookError(...)), the run is marked Failed in Postgres, but cause Initial release — Sprout Nostr relay with enterprise extensions #2 hides the failure. Not fixable in-repo.What this PR fixes
Split the rejection text by cause in
handle_workflow_triggerso callers can act:"forbidden: only the workflow owner may trigger this workflow"(wrong caller)"forbidden: workflow is {status} (enabled={bool}); active runs require enabled=true and status=Active"(lifecycle)"forbidden: workflow has no channel scope; cannot verify owner authority"(fail-closed)"forbidden: SEC-006 — workflow contains exfiltration-capable actions (call_webhook) that require the owner to hold the 'owner' or 'admin' role in this channel; {underlying_error}"— names the cause and the fix"forbidden: workflow owner's channel authority check failed; {error}"Also enrich the
WARNlog on the event-trigger path (on_event→check_owner_authority) withowner_pubkeyandrequires_elevated_authority, so the same silent skip is diagnosable from relay logs.What this PR does NOT fix
finalize_run) tracked separately.call_webhookdelivery on hosts with blocked outbound HTTP — that is an infrastructure concern; the descriptive error from this PR at least makes the SEC-006 cause visible, and once Workflow run history is unreadable: always returns [] #2980 is fixed, run-history will surface the HTTP error too.Tests
cargo check -p buzz-relay -p buzz-workflow: cleancargo fmt --check -p buzz-relay -p buzz-workflow: cleancargo clippy -p buzz-relay -p buzz-workflow --all-targets -- -D warnings: cleancargo test -p buzz-relay --lib: 854 passed, 8 pre-existing failures (api::admin / api::media, verified identical on base, unrelated)cargo test -p buzz-workflow --lib: 154 passed, 0 faileddenial_for_elevated_definition_names_sec006_and_call_webhook,denial_for_ordinary_definition_has_no_sec006_hintFiles changed
crates/buzz-relay/src/handlers/command_executor.rs(+52/−7): descriptive rejections + extractedworkflow_owner_authority_denialhelper + unit testscrates/buzz-workflow/src/lib.rs(+9/−2): structuredWARNlog withowner_pubkey+requires_elevated_authority