{"id":16024196,"url":"https://github.com/aaronfriel/grapple","last_synced_at":"2026-05-05T18:39:44.821Z","repository":{"id":147824515,"uuid":"101442662","full_name":"AaronFriel/grapple","owner":"AaronFriel","description":"A GitHub mirroring tool","archived":false,"fork":false,"pushed_at":"2017-09-01T00:11:48.000Z","size":55,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-10-10T06:19:11.451Z","etag":null,"topics":["git","github","rust","rust-crate","webhook"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AaronFriel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":null,"dco":null,"cla":null}},"created_at":"2017-08-25T21:15:37.000Z","updated_at":"2017-08-26T09:46:21.000Z","dependencies_parsed_at":null,"dependency_job_id":"f5ac63b0-212f-4e15-abf0-63fdf6092faa","html_url":"https://github.com/AaronFriel/grapple","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/AaronFriel/grapple","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AaronFriel%2Fgrapple","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AaronFriel%2Fgrapple/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AaronFriel%2Fgrapple/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AaronFriel%2Fgrapple/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AaronFriel","download_url":"https://codeload.github.com/AaronFriel/grapple/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AaronFriel%2Fgrapple/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32663429,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-05T11:29:49.557Z","status":"ssl_error","status_checked_at":"2026-05-05T11:29:48.587Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["git","github","rust","rust-crate","webhook"],"created_at":"2024-10-08T19:05:57.571Z","updated_at":"2026-05-05T18:39:44.814Z","avatar_url":"https://github.com/AaronFriel.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Grapple\n\n## A Github Mirroring Tool\n\nGrapple is a tool for mirroring a GitHub based repository by listening for webhooks, pulling changes, and pushing them to a remote repository. Functionality is fairly basic right now, but it can listen to multiple repositories and mirror them. The webserver is built with [Rust](https://www.rust-lang.org/) and the [Rocket](https://rocket.rs) web framework.\n\n## Installing\n\nGrapple relies on features in nightly builds. Using [rustup](https://www.rustup.rs/), use a recent nightly build, e.g.:\n\n```\nrustup default nightly-2017-08-22\n```\n\nAnd then build with `cargo`:\n\n```\ncargo build --release\n```\n\nThis will produce the executable in `target/release/grapple`. The Dockerfile in `./docker` can help you spin it up as a webserver if you copy the release binary into the docker folder.\n\n## Docker image/running Grapple\n\nA recent docker image is hosted at this registry address:\n`registry.gitlab.frielforreal.com/friel/grapple`. Run with:\n\n```\nROCKET_CONFIG_PATH=\"/var/lib/grapple\"\nROCKET_PORT=\"80\"\n\ndocker run --name grapple --restart=unless-stopped \\\n    -v ${ROCKET_CONFIG_PATH}:/var/lib/grapple \\\n    -e ROCKET_ENV=stage \\\n    -e ROCKET_PORT=80 \\\n    -p ${ROCKET_PORT}:80/tcp \\\n    -d registry.gitlab.frielforreal.com/friel/grapple grapple\n```\n\nThe server will listen at `0.0.0.0/github` for webhooks. Verify the server is running with `docker logs`.\n\n## Configuration\n\nGrapple supports `yaml` and `json` configuration formats. A sample file would look like this `config.json`:\n\n```json\n{\n    \"mappings\": [\n        {\n            \"from\": \"AaronFriel/grapple\",\n            \"push_uri\": \"ssh://git@gitlab.frielforreal.com:58432/AaronFriel/grapple.git\",\n            \"deploy_public_key\": \"/var/lib/grapple/AaronFriel_rsa.pub\",\n            \"deploy_private_key\": \"/var/lib/grapple/AaronFriel_rsa\",\n            \"secret\": \"SECRET HERE\"\n        }\n    ]\n}\n```\n\nWith this config, Grapple listens for GitHub webhooks from the repository `AaronFriel/grapple`, and pushes them to my gitlab server. The SSH keys should be deploy keys or otherwise access-limited keys that can only push to the repository of your choice. (Not that I think Grapple is insecure, but these are best practices.) The secret should be the GitHub WebHook secret, which is used to validate the incoming requests.\n\nThe config file can be either `config.json` or `config.yaml`. A yaml configuration would look like this:\n\n```yaml\nmappings:\n  - from: AaronFriel/grapple\n    push_uri: ssh://git@gitlab.frielforreal.com:58432/AaronFriel/grapple.git\n    deploy_public_key: /var/lib/grapple/AaronFriel_rsa.pub\n    deploy_private_key: /var/lib/grapple/AaronFriel_rsa\n    secret: SECRET HERE\n```\n\n## What if something breaks?\n\nThis tool largely builds on existing Rust infrastructure, including the wonderful [git2](https://github.com/alexcrichton/git2-rs) by Alex Crichton. There are almost certainly edge cases that I haven't thought about (e.g.: what happens if someone force pushes to GitHub? I don't know!). If you have any feedback for how to improve it, please submit an issue or pull request for any tests.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faaronfriel%2Fgrapple","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faaronfriel%2Fgrapple","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faaronfriel%2Fgrapple/lists"}