@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at recaptime-dev/main 223 lines 7.0 kB view raw
1@title User Guide: Webhooks 2@group userguide 3 4Guide to configuring webhooks. 5 6 7Overview 8======== 9 10If you'd like to react to events in Phorge or publish them into external 11systems, you can configure webhooks. 12 13Configure webhooks in {nav Herald > Webhooks}. Users must have the 14"Can Create Webhooks" permission to create new webhooks. 15 16 17Triggering Hooks 18================ 19 20Webhooks can be triggered in two ways: 21 22 - Set the hook mode to **Firehose**. In this mode, your hook will be called 23 for every event. 24 - Set the hook mode to **Enabled**, then write Herald rules which use the 25 **Call webhooks** action to choose when the hook is called. This allows 26 you to choose a narrower range of events to be notified about. 27 28 29Testing Hooks 30============= 31 32To test a webhook, use {nav New Test Request} from the web interface. 33 34You can also use the command-line tool, which supports a few additional 35options: 36 37``` 38phorge/ $ ./bin/webhook call --id 42 --object D123 39``` 40 41 42Verifying Requests 43================== 44 45When your webhook callback URI receives a request, it didn't necessarily come 46from Phorge. An attacker or mischievous user can normally call your hook 47directly and pretend to be notifying you of an event. 48 49To verify that the request is authentic, first retrieve the webhook key from 50the web UI with {nav View HMAC Key}. This is a shared secret which will let you 51verify that Phorge originated a request. 52 53When you receive a request, compute the SHA256 HMAC value of the request body 54using the HMAC key as the key. The value should match the value in the 55`X-Phabricator-Webhook-Signature` field. 56 57To compute the SHA256 HMAC of a string in PHP, do this: 58 59```lang=php 60$signature = hash_hmac('sha256', $request_body, $hmac_key); 61``` 62 63To compute the SHA256 HMAC of a string in Python, do this: 64 65```lang=python 66from subprocess import check_output 67 68signature = check_output( 69 [ 70 "php", 71 "-r", 72 "echo hash_hmac('sha256', $argv[1], $argv[2]);", 73 "--", 74 request_body, 75 hmac_key 76 ]) 77``` 78 79Other languages often provide similar support. 80 81If you somehow disclose the key by accident, use {nav Regenerate HMAC Key} to 82throw it away and generate a new one. 83 84 85Request Format 86============== 87 88Webhook callbacks are POST requests with a JSON payload in the body. The 89payload looks like this: 90 91```lang=json 92{ 93 "object": { 94 "type": "TASK", 95 "phid": "PHID-TASK-abcd..." 96 }, 97 "triggers": [ 98 { 99 "phid": "PHID-HRUL-abcd..." 100 } 101 ], 102 "action": { 103 "test": false, 104 "silent": false, 105 "secure": false, 106 "epoch": 12345 107 }, 108 "transactions": [ 109 { 110 "phid": "PHID-XACT-TASK-abcd..." 111 } 112 ] 113} 114``` 115 116The **object** map describes the object which was edited. 117 118The **triggers** are a list of reasons why the hook was called. When the hook 119is triggered by Herald rules, the specific rules which triggered the call will 120be listed. For firehose rules, the rule itself will be listed as the trigger. 121For test calls, the user making the request will be listed as a trigger. 122 123The **action** map has metadata about the action: 124 125 - `test` This was a test call from the web UI or console. 126 - `silent` This is a silent edit which won't send mail or notifications in 127 Phorge. If your hook is doing something like copying events into 128 a chatroom, it may want to respect this flag. 129 - `secure` Details about this object should only be transmitted over 130 secure channels. Your hook may want to respect this flag. 131 - `epoch` The epoch timestamp when the callback was queued. 132 133The **transactions** list contains information about the actual changes which 134triggered the callback. 135 136 137Responding to Requests 138====================== 139 140Although trivial hooks may not need any more information than this to act, the 141information conveyed in the hook body is a minimum set of pointers to relevant 142data and likely insufficient for more complex hooks. 143 144Complex hooks should expect to react to receiving a request by making API 145calls to Conduit to retrieve additional information about the object and 146transactions. 147 148Hooks that are interested in reading object state should generally make a call 149to a method like `maniphest.search` or `differential.revision.search` using 150the PHID from the `object` field to retrieve full details about the object 151state. 152 153Hooks that are interested in changes should generally make a call to 154`transaction.search`, passing the transaction PHIDs as a constraint to retrieve 155details about the transactions. 156 157For example, your call to `transaction.search` may look something like this: 158 159```lang=json 160{ 161 "objectIdentifier": "PHID-XXXX-abcdef", 162 "constraints": { 163 "phids": [ 164 "PHID-XACT-XXXX-11111111", 165 "PHID-XACT-XXXX-22222222" 166 ] 167 } 168} 169``` 170 171The `phid.query` method can also be used to retrieve generic information about 172a list of objects. 173 174 175Retries and Rate Limiting 176========================= 177 178Test requests are never retried: they execute exactly once. 179 180Live requests are automatically retried. If your endpoint does not return a 181HTTP 2XX response, the request will be retried regularly until it succeeds. 182 183Retries will continue until the request succeeds or is garbage collected. By 184default, this is after 7 days. 185 186If a webhook is disabled, outstanding queued requests will be failed 187permanently. Activity which occurs while it is disabled will never be sent to 188the callback URI. (Disabling a hook does not "pause" it so that it can be 189"resumed" later and pick back up where it left off in the event stream.) 190 191If a webhook encounters a significant number of errors in a short period of 192time, the webhook will be paused for a few minutes before additional requests 193are made. The web UI shows a warning indicator when a hook is paused because of 194errors. 195 196Hook requests time out after 10 seconds. Consider offloading response handling 197to some kind of worker queue if you expect to routinely require more than 10 198seconds to respond to requests. 199 200Hook callbacks are single-threaded: you will never receive more than one 201simultaneous call to the same webhook from Phorge. If you have a firehose 202hook on an active install, it may be important to respond to requests quickly 203to avoid accumulating a backlog. 204 205Callbacks may be invoked out-of-order. You should not assume that the order 206you receive requests in is chronological order. If your hook is order-dependent, 207you can ignore the transactions in the callback and use `transaction.search` to 208retrieve a consistent list of ordered changes to the object. 209 210Callbacks may be delayed for an arbitrarily long amount of time, up to the 211garbage collection limit. You should not assume that calls are real time. If 212your hook is doing something time-sensitive, you can measure the delivery delay 213by comparing the current time to the `epoch` value in the `action` field and 214ignoring old actions or handling them in some special way. 215 216 217Next Steps 218========== 219 220Continue by: 221 222 - learning more about Herald with @{article:Herald User Guide}; or 223 - interacting with the Conduit API with @{article:Conduit API Overview}.