{"id":50316952,"url":"https://github.com/strayer/doco-cd-webhook-proxy","last_synced_at":"2026-05-29T00:30:35.281Z","repository":{"id":359883478,"uuid":"1247869006","full_name":"strayer/doco-cd-webhook-proxy","owner":"strayer","description":"Security proxy for doco-cd webhooks — validates and sanitizes GitHub webhook requests so doco-cd never needs to be exposed to the internet","archived":false,"fork":false,"pushed_at":"2026-05-24T00:10:38.000Z","size":7,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-24T00:21:13.797Z","etag":null,"topics":["docker","doco-cd","gitops","golang","security","webhook","webhook-proxy"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/strayer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-23T22:22:52.000Z","updated_at":"2026-05-24T00:10:42.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/strayer/doco-cd-webhook-proxy","commit_stats":null,"previous_names":["strayer/doco-cd-webhook-proxy"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/strayer/doco-cd-webhook-proxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strayer%2Fdoco-cd-webhook-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strayer%2Fdoco-cd-webhook-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strayer%2Fdoco-cd-webhook-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strayer%2Fdoco-cd-webhook-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/strayer","download_url":"https://codeload.github.com/strayer/doco-cd-webhook-proxy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strayer%2Fdoco-cd-webhook-proxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33632271,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","doco-cd","gitops","golang","security","webhook","webhook-proxy"],"created_at":"2026-05-29T00:30:32.808Z","updated_at":"2026-05-29T00:30:35.268Z","avatar_url":"https://github.com/strayer.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# doco-cd-webhook-proxy\n\nA security proxy for [doco-cd](https://doco.cd) webhooks. Receives GitHub push webhooks, validates them, and forwards sanitized requests to an internal doco-cd instance — so doco-cd (and its `docker.sock`) never needs to be exposed to the internet.\n\n## Why\n\n[doco-cd](https://doco.cd) is a GitOps tool that deploys Docker Compose projects by watching Git repositories. It requires `docker.sock` mounted into its container, giving it full root-level access to the Docker host.\n\nWithout this proxy, there are two options:\n\n- **Polling** — doco-cd periodically pulls the repo to check for changes. This works but is slow (at least 1 minute delay), causes unnecessary network traffic, and wears out SD cards on low-power devices like Raspberry Pis.\n- **Direct webhooks** — fast, but requires exposing doco-cd directly to the internet. While doco-cd validates webhook signatures, it has several limitations as a public-facing endpoint:\n  - **No repository allowlist** — anyone who knows the webhook secret can trigger a deployment of *any* repo that doco-cd can pull, not just the ones you intended.\n  - **Full Docker access** — a process with `docker.sock` mounted is effectively root on the host. Exposing it to the internet means any vulnerability in its HTTP handling could lead to full host compromise.\n  - **Raw request forwarding** — the original HTTP request from the internet reaches doco-cd as-is, including all headers and payload fields. Any parser bug or unexpected field could be exploited.\n\nThis proxy closes those gaps: deployments trigger instantly via webhooks, but doco-cd stays on an internal network, unreachable from the internet. The proxy validates the source IP against [GitHub's published CIDR ranges](https://api.github.com/meta), verifies the HMAC signature, enforces a repository allowlist, and **never forwards the original request** — it constructs a new one from scratch using only the validated fields.\n\n## How it works\n\n```\nGitHub ──webhook──▶ proxy ──sanitized request──▶ doco-cd (internal)\n```\n\n1. Validates the HTTP request (POST method, JSON content type, required headers)\n2. Validates the source IP against [GitHub's webhook CIDRs](https://api.github.com/meta)\n3. Verifies the HMAC-SHA256 signature (`X-Hub-Signature-256`)\n4. Validates the payload (required fields, repository allowlist, clone URL format)\n5. Constructs a **new** minimal request to doco-cd — no headers or payload fields are forwarded verbatim\n\n## Configuration\n\n| Variable | Required | Default | Description |\n|---|---|---|---|\n| `GITHUB_WEBHOOK_SECRET` | yes | | Secret shared with GitHub for signature validation |\n| `DOCO_CD_WEBHOOK_SECRET` | yes | | Secret used to sign requests to doco-cd |\n| `DOCO_CD_URL` | yes | | Internal doco-cd URL (e.g. `http://doco-cd:80`) |\n| `ALLOWED_REPOS` | yes | | Comma-separated repository full names (e.g. `org/repo1,org/repo2`) |\n| `LISTEN_ADDR` | no | `:8080` | Address to listen on |\n| `TRUSTED_PROXY_CIDRS` | no | | Comma-separated CIDRs of trusted reverse proxies |\n| `GITHUB_META_REFRESH_INTERVAL` | no | `1h` | How often to refresh GitHub IP ranges |\n\nSecret variables (`GITHUB_WEBHOOK_SECRET`, `DOCO_CD_WEBHOOK_SECRET`) support a `_FILE` suffix variant for use with Docker secrets or mounted files. For example, setting `GITHUB_WEBHOOK_SECRET_FILE=/run/secrets/github_secret` reads the secret from that file instead of the environment variable directly.\n\n\u003e [!NOTE]\n\u003e `GITHUB_WEBHOOK_SECRET` and `DOCO_CD_WEBHOOK_SECRET` should be different values.\n\n## Running with Docker\n\n```yaml\n# compose.yaml\nservices:\n  webhook-proxy:\n    image: ghcr.io/strayer/doco-cd-webhook-proxy:latest\n    ports:\n      - \"8080:8080\"\n    environment:\n      GITHUB_WEBHOOK_SECRET: ${GITHUB_WEBHOOK_SECRET}\n      DOCO_CD_WEBHOOK_SECRET: ${DOCO_CD_WEBHOOK_SECRET}\n      DOCO_CD_URL: http://doco-cd:80\n      ALLOWED_REPOS: org/repo1,org/repo2\n\n  doco-cd:\n    image: ghcr.io/kimdre/doco-cd:latest\n    # ... doco-cd configuration\n```\n\nThe proxy must be able to reach both the internet (to fetch [GitHub's IP ranges](https://api.github.com/meta)) and the internal doco-cd instance. Place it on a shared network with doco-cd, but only expose the proxy's port to the reverse proxy / internet.\n\n## Development Setup\n\nThis project uses [mise](https://mise.jdx.dev) for tool management and [prek](https://github.com/j178/prek) for pre-commit hooks.\n\n```sh\nmise install      # installs Go, goimports, golangci-lint\nprek install      # installs pre-commit hooks\n```\n\nPre-commit hooks run automatically on `git commit`:\n- **goimports** — auto-formats Go files\n- **golangci-lint** — lints for errors (no auto-fix)\n\n## Design\n\nThis proxy is built with a minimal attack surface in mind. The Go application uses only the standard library — no third-party dependencies that could introduce vulnerabilities or supply chain risks. The same principle extends to the build and deployment pipeline: GitHub Actions workflows and Dockerfiles follow security best practices to keep the overall supply chain tight.\n\n## AI Usage Notice\n\nTo ensure the responsible use of AI, this project adheres to a strict policy of human oversight. While a Large Language Model (LLM) is used as an assistive tool, its role is limited to implementation based on human-led design. Every line of AI-generated code is then manually reviewed and validated for correctness, security, and quality before being accepted into the codebase. The final authority and accountability for the code rests with the human developer.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrayer%2Fdoco-cd-webhook-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstrayer%2Fdoco-cd-webhook-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrayer%2Fdoco-cd-webhook-proxy/lists"}