Slide 1

Slide 1 text

Sylvain Mauduit @swop Senior Software Engineer, Etsy GitHub bot with Symfony

Slide 2

Slide 2 text

GitHub bot | Definition A GitHub bot is a web app which is going to react to events happening on GitHub by performing some action on its side and/or will trigger other behaviours on GitHub

Slide 3

Slide 3 text

GitHub bot | Workflow Event Something happens on GitHub GITHUB Triggers a Web Hook call GitHub will call your server GITHUB Web hook request handling Process the event CUSTOM APP (BOT) Use GitHub API as an output CUSTOM APP (BOT)

Slide 4

Slide 4 text

GitHub bot | Today’s menu 1. Connect GitHub to our app via GitHub web hooks 2. Communicate with GitHub via the GitHub API

Slide 5

Slide 5 text

Use web hooks to connect our app to GitHub Image source: pexels.com

Slide 6

Slide 6 text

Each GitHub activity will trigger an event. Comment on commit on deployment on fork comment on issue/PR labelling an issue when open a PR on push … You can request a web hook call on all/some events GitHub | Events

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

X-GitHub-Event
 Event type
 commit_comment
 deployment
 fork
 issue_comment
 pull_request, push … Web hook payload | Headers

Slide 12

Slide 12 text

X-Hub-Signature
 Signed web hook payload (using a shared secret)
 sha1=5b97ee25c90585f5b809e87d5be7bd942e3c7a28 Web hook payload | Headers

Slide 13

Slide 13 text

X-GitHub-Delivery
 Unique ID for the web hook call
 72d3162e-cc78-11e3-81ab-4c9367dc0958 Web hook payload | Headers

Slide 14

Slide 14 text

User-Agent
 Prefixed User Agent
 GitHub-Hookshot/{hash} Web hook payload | Headers

Slide 15

Slide 15 text

JSON
 (or form-urlencoded) representation of the event and its context Web hook payload | Body (POST)

Slide 16

Slide 16 text

Web hook payload | Example POST /webhook HTTP/1.1 Host: my_awesome_bot.com User-Agent: GitHub-Hookshot/044aadd Content-Type: application/json X-GitHub-Event: issues X-Github-Delivery: 72d3162e-cc78-11e3-81ab-4c9367dc0958 X-Hub-Signature: sha1=5b97ee25c90585f5b809e87d5be7bd942e3c7a28

Slide 17

Slide 17 text

Web hook payload | Example { "action": "opened", "issue": { "url": "https://api.github.com/repos/octocat/Hello-World/issues/1347", "number": 1347, ... }, "repository" : { "id": 1296269, "full_name": "octocat/Hello-World", ... }, "sender": { "login": "octocat", "id": 1, ... } }

Slide 18

Slide 18 text

Web hook | Security Whitelist GitHub IPs Check web hook request signature

Slide 19

Slide 19 text

Web hook | Security Recreate the signature and compare it Using the same secret CUSTOM APP Sign the web hook call Using the secret GITHUB REQUEST X-Hub-Signature sha1=5b97ee25c9… Secret
 my_secret https://developer.github.com/webhooks/securing/

Slide 20

Slide 20 text

Web hook | Security headers->get('X-Hub-Signature'); $explodeResult = explode('=', $signature, 2); if (2 !== count($explodeResult)) { return false; // Invalid signature header } list($algorithm, $hash) = $explodeResult; $payload = $request->getContent(); $payloadHash = hash_hmac($algorithm, $payload, 'my_secret'); if ($hash !== $payloadHash) { return false; // Invalid signature (wrong secret or altered payload) }

Slide 21

Slide 21 text

Communicate with GitHub via the GitHub API Image source: pexels.com

Slide 22

Slide 22 text

https://developer.github.com/v3/ GitHub API | Docs

Slide 23

Slide 23 text

KnpLabs/php-github-api GitHub API | PHP client

Slide 24

Slide 24 text

Several choice to auth to GitHub API Personal tokens JWT OAuth2 app … Easy way to start (and test the bot): Personal access token https://github.com/settings/tokens/new GitHub API | Authentication

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

GitHub API | Authentication container->getParameter('kernel.cache_dir') ); $client = new Client( new CachedHttpClient( ['cache_dir' => $cacheDir] ) ); $client->authenticate($token, null, Client::AUTH_HTTP_TOKEN);

Slide 27

Slide 27 text

GitHub API | Call the API issue() ->comments() ->create( 'Octocat', 'Hello-World', 1337, ['body' => 'Hello!'] );

Slide 28

Slide 28 text

Demo Open-Source enthusiast bot Image source: pexels.com github.com/Swop/open-source-enthusiast-bot

Slide 29

Slide 29 text

Tips | Development Ngrok
 https://ngrok.com/
 Expose you dev env to the world KnpLabs/php-github-api
 https://github.com/KnpLabs/php-github-api
 GitHub API client for PHP

Slide 30

Slide 30 text

Tips | Development Swop/github-webhook
 https://github.com/Swop/github-webhook
 GitHub web hook signature validator & payload deserializer Swop/github-webhook-bundle
 https://github.com/Swop/github-webhook-bundle
 Symfony bundle around the above lib + web hook declaration on controllers with annotations

Slide 31

Slide 31 text

Tips | Want to try middleware approach? Swop/github-webhook-middleware
 https://github.com/Swop/github-webhook-middleware
 PSR-15 & PSR-7 middleware Swop/github-webhook-stackphp
 https://github.com/Swop/github-webhook-stackphp
 StackPHP middleware

Slide 32

Slide 32 text

Middleware | With Zend Stratigility use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Swop\GitHubWebHook\Security\SignatureValidator; use Swop\GitHubWebHookMiddleware\GithubWebHook; $app = (new \Zend\Stratigility\MiddlewarePipe()) ->pipe(new GithubWebHook(new SignatureValidator(), 'my_secret')) ->pipe('/webhook', function (RequestInterface $request, ResponseInterface $response) { // The security has been check. // Do some stuff with the web hook... return new \Zend\Diactoros\Response\JsonResponse(['message' => 'OK']); }); $request = \Zend\Diactoros\ServerRequestFactory::fromGlobals(); \Zend\Diactoros\Server::createServerFromRequest($app, $request) ->listen(new \Zend\Stratigility\NoopFinalHandler());

Slide 33

Slide 33 text

How we’re using this

Slide 34

Slide 34 text

Bot | Notificator Main controller Wildcard GitHub event types GitHub Web hook REQUEST github. {event_type} DISPATCH (Eventually) Performs actions or get more info on GitHub (using the API) Check review label Internal hook Check review status on merge Internal hook … Internal hook github. {event_type} Notification Notification Notification Attach resulting notifications to the initial event

Slide 35

Slide 35 text

Bot | Notificator Main controller Wildcard GitHub event types GitHub Web hook REQUEST github. {event_type} DISPATCH Notification Notification Notification SlackOutput Post Slack message MailOutput Send a mail MonologOutput Log the notification GitHubOutput Comment on PR/commit StatsDOutput Increment a metric
 on Graphite Output chain LOOP OVER NOTIFICATIONS

Slide 36

Slide 36 text

Bot | Notificator

Slide 37

Slide 37 text

Going further | Here’s some ideas… Create a GitHub “Integration”
 https://developer.github.com/early-access/integrations/
 • Uses JWT instead of personal tokens • Act on its own instead of behalf a user • Web hooks / permissions are built-in

Slide 38

Slide 38 text

Going further | Here’s some ideas… Register your web hooks from… your bot web page
 Travis CI-like
 • Create a web interface on your app • Use GitHub API to auto-register itself as web hook on the user-selected repos.

Slide 39

Slide 39 text

Going further | Here’s some ideas…

Slide 40

Slide 40 text

You like these toys? Join us! Senior full-stack eng. Senior backend eng. iOS eng. Contact me: [email protected] Image source: pexels.com