Add HMAC-SHA256 auth mode to WebhookTrigger#1178
Merged
Conversation
Adds an optional HMAC-SHA256 auth mode to inc/Api/WebhookTrigger.php alongside the existing Bearer flow, unlocking direct integration with GitHub, Stripe, Shopify, Slack, Linear, and other providers that sign the raw request body. What's new - New WebhookSignatureVerifier helper with timing-safe HMAC-SHA256 verification in three formats: sha256=hex, hex, base64. - WebhookTrigger::handle_trigger now branches on scheduling_config .webhook_auth_mode. Missing / unknown mode defaults to 'bearer' for backward compatibility with every shipped flow. - HMAC path honors a configurable signature header (default X-Hub-Signature-256) and a max_body_bytes cap (default 1 MB, 413 on overflow) so unauthenticated clients cannot force arbitrarily large HMAC computations. - WebhookTriggerAbility: executeEnable accepts auth_mode / signature_header / signature_format / generate_secret / secret; new executeSetSecret ability; executeStatus now exposes auth_mode and HMAC header/format but never the secret; executeDisable clears all HMAC fields; executeRegenerate refuses non-bearer flows. - CLI: wp datamachine flows webhook enable gains --auth-mode, --signature-header, --signature-format, --generate-secret, --secret flags; new set-secret subcommand; status + list show auth mode. What's unchanged - Every existing Bearer flow continues to work byte-for-byte. - No engine, job-queue, or run_flow behavior changes — this is purely pre-ability-dispatch auth. Tests - 15 unit tests for WebhookSignatureVerifier (valid/invalid per format, empty secret/body/signature, tampered body, unknown format, hash_equals usage). - 17 WP_UnitTestCase tests for WebhookTrigger + WebhookTriggerAbility covering Bearer regression, HMAC valid/invalid/missing/oversized, status/disable/regenerate/set-secret behavior, and the missing-mode-defaults-to-bearer path. Docs - New docs/api/endpoints/webhook-triggers.md with end-to-end GitHub walkthrough and Shopify / Linear examples. - Updated docs/core-system/wp-cli.md and abilities-api.md. Refs: #1177
Contributor
Homeboy Results —
|
This was referenced Apr 24, 2026
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.
Closes #1177.
Summary
Adds an optional HMAC-SHA256 auth mode to
inc/Api/WebhookTrigger.phpalongside the existing Bearer-token flow. HMAC is the industry-standard webhook auth protocol used by GitHub, Stripe, Shopify, Slack, Linear, Mailgun, Twilio, Plaid, SendGrid, and PayPal. Wiring it in natively means DM can accept these webhooks directly — no mu-plugin bridge, no relay service.webhook_auth_modeis treated asbearer, so every shipped flow is byte-for-byte unchanged.datamachine_run_flow_now, rate limiting, or the downstreaminitial_data.webhook_triggerpayload shape.What's in the box
New
inc/Api/WebhookSignatureVerifier.php— static helper with timing-safeverify_hmac_sha256()supporting three formats:sha256=hex(GitHub),hex(Linear),base64(Shopify).datamachine/webhook-trigger-set-secretability +wp datamachine flows webhook set-secretCLI subcommand.docs/api/endpoints/webhook-triggers.md— full GitHub walkthrough, Shopify/Linear examples, security notes.Changed
WebhookTrigger::handle_trigger()branches onscheduling_config.webhook_auth_mode:bearer→ existing code path (unchanged).hmac_sha256→ read raw body via$request->get_body(), enforcewebhook_max_body_bytescap (default 1 MB → 413), verify signature viaWebhookSignatureVerifier.WebhookTriggerAbility:executeEnableacceptsauth_mode,signature_header,signature_format,generate_secret,secret.executeSetSecretgenerates or rotates the HMAC secret and flips the flow intohmac_sha256mode.executeStatusreturnsauth_modeand HMAC header/format — never the secret.executeDisableclears all HMAC-related fields.executeRegeneratenow refuses to run on HMAC flows (directs the caller toset-secret).WebhookCommandCLI:enablegains--auth-mode,--signature-header,--signature-format,--generate-secret,--secretflags.set-secretsubcommand (--secret=<value>or--generate).statusandlistdisplay the auth mode.Acceptance criteria
--auth-mode=hmac_sha256via CLIauth_mode = hmac_sha256test_bearer_flow_still_works+test_missing_auth_mode_defaults_to_bearer)statusshows auth mode + HMAC header/format, never the secretmax_body_bytescap (default 1 MB) returns 413 on overflow for HMAC flowsTests
tests/Unit/Api/WebhookSignatureVerifierTest.php— 15 pure unit tests: valid / invalid per format, empty secret, empty body, empty signature, wrong secret, tampered body, missingsha256=prefix, format mismatch, uppercase hex, unknown format,hash_equalsusage.tests/Unit/Api/WebhookTriggerTest.php— 17WP_UnitTestCasetests: Bearer regression (3 cases), HMAC valid/invalid/missing/oversized/tampered (5 cases), ability-level behavior (enable modes, set-secret, regenerate refusal, disable clearing), andmissing_auth_mode_defaults_to_bearer.All 32 new tests green:
Full-suite run is clean relative to baseline — only the 37 pre-existing failures from
NetworkSettingsTest,ImportExportStepConfigTest, etc. remain. No new regressions introduced.Lint of modified / new files is clean; the only phpstan finding attributable to
WebhookTriggerAbilitycomes from the sharedFlowHelperstrait and pre-dates this PR (it affects every class that uses the trait).Out of scope (per #1177)
v0=...,t=...,v1=...) — can extendwebhook_signature_formatlater.scheduling_configinto a dedicated credentials table.Verification