Skip to content

salsiy/serverless-github-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Serverless GitHub App

Reference architecture for a low cost GitHub App on AWS Lambda. Focus is on how to build it: webhook verification, GitHub App auth, SSM secrets, and synchronous handling. The sample handler (release → cross repo repository_dispatch) is optional; swap the handler for your own workflow.

Architecture

flowchart TB
    subgraph github [GitHub]
        App[GitHub App]
        Webhook[Webhook POST]
        ContentsAPI[Contents API]
        DispatchAPI[repository_dispatch API]
        Actions[Target repo Actions]
    end

    subgraph aws [AWS]
        FuncURL[Lambda Function URL]
        Lambda[Go Lambda bootstrap]
        SSM[SSM Parameter Store]
        CW[CloudWatch Logs]
    end

    App --> Webhook
    Webhook -->|HTTPS| FuncURL
    FuncURL --> Lambda
    Lambda -->|init| SSM
    Lambda -->|HMAC verify| Lambda
    Lambda -->|read app-config.yaml| ContentsAPI
    Lambda -->|fan-out| DispatchAPI
    DispatchAPI --> Actions
    Lambda --> CW
Loading
sequenceDiagram
    participant GH as GitHub
    participant URL as LambdaFunctionURL
    participant L as GoHandler
    participant SSM as SSM
    participant API as GitHubAPI

    Note over L,SSM: init once per container
    L->>SSM: GetParameter app-id, key, webhook-secret

    GH->>URL: POST webhook + x-hub-signature-256
    URL->>L: LambdaFunctionURLRequest
    L->>L: verify HMAC-SHA256
    L->>L: parse payload, determine event type
    alt unsupported event
        L-->>GH: 200 skip
    else supported
        L->>API: GetContents app-config.yaml
        loop each target
            L->>API: repository_dispatch
        end
        L-->>GH: 200 or 500
    end
Loading

How it works

Webhook security. Function URL is public (authorization_type = "NONE"). Trust comes from HMAC-SHA256 on x-hub-signature-256 (lowercase on Lambda URLs). Bad signature → 400/401.

Secrets. Env vars store SSM paths, not values. init() loads App ID, private key, and webhook secret once per warm container.

GitHub auth. ghinstallation wraps the HTTP client. Installation ID from the webhook scopes API calls to that org.

Config in repo. Rules live in .github/app-config.yaml, fetched via Contents API. Change targets without redeploying Lambda.

Status codes. Unsupported events return 200 (no retry). Processing errors return 500 (GitHub retries). Individual dispatch failures are logged; webhook still returns 200.

Cost choices. Function URL (no API Gateway), Go on provided.al2023 arm64, 256 MB, no VPC, SSM instead of Secrets Manager.

File Role
app/main.go Handler and init
app/webhook.go Signature verification
app/webhook_processor.go Event routing
app/github_auth.go GitHub App client
app/repo_config_loader.go Repo config
app/github_dispatch.go Outbound API (sample)
app/config.go SSM loader
infra/main.tf Lambda, IAM, Function URL

Prerequisites

GitHub App with contents (read), administration (read/write), release webhook, and a webhook secret. AWS credentials, Terraform ≥ 1.5, Go 1.24.4.

Setup

Store credentials in SSM:

aws ssm put-parameter --name "/dev/github-app/app-id" --value "YOUR_APP_ID" --type "String"
aws ssm put-parameter --name "/dev/github-app-private-key" --value file://your-app.private-key.pem --type "SecureString"
aws ssm put-parameter --name "/dev/github-app-webhook-secret" --value "YOUR_WEBHOOK_SECRET" --type "SecureString"

Deploy and point the GitHub App webhook at the Function URL:

make deploy

Set webhook URL, webhook secret (same as SSM), and enable Release events.

Example: release dispatch

Source repo .github/app-config.yaml:

dispatches:
  - event: "release"
    targets:
      - repo: "target-repo-1"
        event_type: "deploy"

Target repo workflow:

on:
  repository_dispatch:
    types: [deploy]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - run: echo "${{ github.event.client_payload.release.tag_name }}"

Targets use the same owner as the source repo (payload.Repository.Owner.Login).

Monitoring and tests

aws logs tail /aws/lambda/serverless-github-app-123456789012-us-east-1 --follow
make test

Use the function name from terraform output.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors