Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14089944
D19050.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
9 KB
Referenced Files
None
Subscribers
None
D19050.diff
View Options
diff --git a/src/applications/herald/application/PhabricatorHeraldApplication.php b/src/applications/herald/application/PhabricatorHeraldApplication.php
--- a/src/applications/herald/application/PhabricatorHeraldApplication.php
+++ b/src/applications/herald/application/PhabricatorHeraldApplication.php
@@ -28,6 +28,10 @@
'name' => pht('Herald User Guide'),
'href' => PhabricatorEnv::getDoclink('Herald User Guide'),
),
+ array(
+ 'name' => pht('User Guide: Webhooks'),
+ 'href' => PhabricatorEnv::getDoclink('User Guide: Webhooks'),
+ ),
);
}
diff --git a/src/applications/herald/worker/HeraldWebhookWorker.php b/src/applications/herald/worker/HeraldWebhookWorker.php
--- a/src/applications/herald/worker/HeraldWebhookWorker.php
+++ b/src/applications/herald/worker/HeraldWebhookWorker.php
@@ -155,6 +155,7 @@
'test' => $request->getIsTestAction(),
'silent' => $request->getIsSilentAction(),
'secure' => $request->getIsSecureAction(),
+ 'epoch' => (int)$request->getDateCreated(),
),
'transactions' => $xaction_data,
);
diff --git a/src/applications/transactions/bulk/PhabricatorBulkEngine.php b/src/applications/transactions/bulk/PhabricatorBulkEngine.php
--- a/src/applications/transactions/bulk/PhabricatorBulkEngine.php
+++ b/src/applications/transactions/bulk/PhabricatorBulkEngine.php
@@ -377,7 +377,7 @@
'')))
->appendChild(
id(new AphrontFormSubmitControl())
- ->setValue(pht('Apply Bulk Edit'))
+ ->setValue(pht('Continue'))
->addCancelButton($cancel_uri));
}
diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
--- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
+++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
@@ -4290,6 +4290,7 @@
->setObjectPHID($object->getPHID())
->setTransactionPHIDs(mpull($xactions, 'getPHID'))
->setTriggerPHIDs($trigger_phids)
+ ->setRetryMode(HeraldWebhookRequest::RETRY_FOREVER)
->setIsSilentAction((bool)$this->getIsSilent())
->setIsSecureAction((bool)$this->getMustEncrypt())
->save();
diff --git a/src/docs/user/userguide/webhooks.diviner b/src/docs/user/userguide/webhooks.diviner
new file mode 100644
--- /dev/null
+++ b/src/docs/user/userguide/webhooks.diviner
@@ -0,0 +1,212 @@
+@title User Guide: Webhooks
+@group userguide
+
+Guide to configuring webhooks.
+
+
+Overview
+========
+
+If you'd like to react to events in Phabricator or publish them into external
+systems, you can configure webhooks.
+
+Configure webhooks in {nav Herald > Webhooks}. Users must have the
+"Can Create Webhooks" permission to create new webhooks.
+
+
+Triggering Hooks
+================
+
+Webhooks can be triggered in two ways:
+
+ - Set the hook mode to **Firehose**. In this mode, your hook will be called
+ for every event.
+ - Set the hook mode to **Enabled**, then write Herald rules which use the
+ **Call webhooks** action to choose when the hook is called. This allows
+ you to choose a narrower range of events to be notified about.
+
+
+Testing Hooks
+=============
+
+To test a webhook, use {nav New Test Request} from the web interface.
+
+You can also use the command-line tool, which supports a few additional
+options:
+
+```
+phabricator/ $ ./bin/webhook call --id 42 --object D123
+```
+
+You can use a tool like [[ https://requestb.in | RequestBin ]] to inspect
+the headers and payload for calls to hooks.
+
+
+Verifying Requests
+==================
+
+When your webhook callback URI receives a request, it didn't necessarily come
+from Phabricator. An attacker or mischievous user can normally call your hook
+directly and pretend to be notifying you of an event.
+
+To verify that the request is authentic, first retrieve the webhook key from
+the web UI with {nav View HMAC Key}. This is a shared secret which will let you
+verify that Phabricator originated a request.
+
+When you receive a request, compute the SHA256 HMAC value of the request body
+using the HMAC key as the key. The value should match the value in the
+`X-Phabricator-Webhook-Signature` field.
+
+To compute the SHA256 HMAC of a string in PHP, do this:
+
+```lang=php
+$signature = hash_hmac('sha256', $request_body, $hmac_key);
+```
+
+To compute the SHA256 HMAC of a string in Python, do this:
+
+```lang=python
+from subprocess import check_output
+
+signature = check_output(
+ [
+ "php",
+ "-r",
+ "echo hash_hmac('sha256', $argv[1], $argv[2]);",
+ "--",
+ request_body,
+ hmac_key
+ ])
+```
+
+Other languages often provide similar support.
+
+If you somehow disclose the key by accident, use {nav Regenerate HMAC Key} to
+throw it away and generate a new one.
+
+
+Request Format
+==============
+
+Webhook callbacks are POST requests with a JSON payload in the body. The
+payload looks like this:
+
+```lang=json
+{
+ "object": {
+ "type": "TASK",
+ "phid": "PHID-TASK-abcd..."
+ },
+ "triggers": [
+ {
+ "phid": "PHID-HRUL-abcd..."
+ }
+ ],
+ "action": {
+ "test": false,
+ "silent": false,
+ "secure": false,
+ "epoch": 12345
+ },
+ "transactions": [
+ {
+ "phid": "PHID-XACT-TASK-abcd..."
+ }
+ ]
+}
+```
+
+The **object** map describes the object which was edited.
+
+The **triggers** are a list of reasons why the hook was called. When the hook
+is triggered by Herald rules, the specific rules which triggered the call will
+be listed. For firehose rules, the rule itself will be listed as the trigger.
+For test calls, the user making the request will be listed as a trigger.
+
+The **action** map has metadata about the action:
+
+ - `test` This was a test call from the web UI or console.
+ - `silent` This is a silent edit which won't send mail or notifications in
+ Phabricator. If your hook is doing something like copying events into
+ a chatroom, it may want to respect this flag.
+ - `secure` Details about this object should only be transmitted over
+ secure channels. Your hook may want to respect this flag.
+ - `epoch` The epoch timestamp when the callback was queued.
+
+The **transactions** list contains information about the actual changes which
+triggered the callback.
+
+
+Responding to Requests
+======================
+
+Although trivial hooks may not need any more information than this to act, the
+information conveyed in the hook body is a minimum set of pointers to relevant
+data and likely insufficient for more complex hooks.
+
+Complex hooks should expect to react to receiving a request by making API
+calls to Conduit to retrieve additional information about the object and
+transactions.
+
+Hooks that are interested in reading object state should generally make a call
+to a method like `maniphest.search` or `differential.revision.search` using
+the PHID from the `object` field to retrieve full details about the object
+state.
+
+Hooks that are interested in changes should generally make a call to
+`transaction.search`, passing the transaction PHIDs as a constraint to retrieve
+details about the transactions.
+
+The `phid.query` method can also be used to retrieve generic information about
+a list of objects.
+
+
+Retries and Rate Limiting
+=========================
+
+Test requests are never retried: they execute exactly once.
+
+Live requests are automatically retried. If your endpoint does not return a
+HTTP 2XX response, the request will be retried regularly until it suceeds.
+
+Retries will continue until the request succeeds or is garbage collected. By
+default, this is after 7 days.
+
+If a webhook is disabled, outstanding queued requests will be failed
+permanently. Activity which occurs while it is disabled will never be sent to
+the callback URI. (Disabling a hook does not "pause" it so that it can be
+"resumed" later and pick back up where it left off in the event stream.)
+
+If a webhook encounters a significant number of errors in a short period of
+time, the webhook will be paused for a few minutes before additional requests
+are made. The web UI shows a warning indicator when a hook is paused because of
+errors.
+
+Hook requests time out after 10 seconds. Consider offloading response handling
+to some kind of worker queue if you expect to routinely require more than 10
+seconds to respond to requests.
+
+Hook callbacks are single-threaded: you will never receive more than one
+simultaneous call to the same webhook from Phabricator. If you have a firehose
+hook on an active install, it may be important to respond to requests quickly
+to avoid accumulating a backlog.
+
+Callbacks may be invoked out-of-order. You should not assume that the order
+you receive requests in is chronological order. If your hook is order-dependent,
+you can ignore the transactions in the callback and use `transaction.search` to
+retrieve a consistent list of ordered changes to the object.
+
+Callbacks may be delayed for an arbitrarily long amount of time, up to the
+garbage collection limit. You should not assume that calls are real time. If
+your hook is doing something time-sensitive, you can measure the delivery delay
+by comparing the current time to the `epoch` value in the `action` field and
+ignoring old actions or handling them in some special way.
+
+
+Next Steps
+==========
+
+Continue by:
+
+ - learning more about Herald with @{article:Herald User Guide}; or
+ - interacting with the Conduit API with @{article:Conduit API Overview}.
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Nov 25, 2:42 PM (21 h, 8 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6786142
Default Alt Text
D19050.diff (9 KB)
Attached To
Mode
D19050: Document how webhooks work
Attached
Detach File
Event Timeline
Log In to Comment