{"id":37227740,"url":"https://github.com/kitplummer/goa","last_synced_at":"2026-01-15T03:23:47.844Z","repository":{"id":43724419,"uuid":"439427761","full_name":"kitplummer/goa","owner":"kitplummer","description":"GitOps Agent - continuously monitors a remote git repository against local/any change, and performs actions (e.g. executes a provided command) - given a periodicity that is defined as a time intervals [NOTE: very much pre-release at this point.]","archived":false,"fork":false,"pushed_at":"2026-01-10T19:41:28.000Z","size":413,"stargazers_count":4,"open_issues_count":5,"forks_count":0,"subscribers_count":3,"default_branch":"develop","last_synced_at":"2026-01-11T00:56:17.480Z","etag":null,"topics":["gitops"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kitplummer.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":"SECURITY.md","support":null}},"created_at":"2021-12-17T18:34:41.000Z","updated_at":"2026-01-10T19:39:02.000Z","dependencies_parsed_at":"2022-08-22T13:00:55.510Z","dependency_job_id":null,"html_url":"https://github.com/kitplummer/goa","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/kitplummer/goa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kitplummer%2Fgoa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kitplummer%2Fgoa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kitplummer%2Fgoa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kitplummer%2Fgoa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kitplummer","download_url":"https://codeload.github.com/kitplummer/goa/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kitplummer%2Fgoa/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28442270,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-15T00:55:22.719Z","status":"online","status_checked_at":"2026-01-15T02:00:08.019Z","response_time":62,"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":["gitops"],"created_at":"2026-01-15T03:23:47.149Z","updated_at":"2026-01-15T03:23:47.835Z","avatar_url":"https://github.com/kitplummer.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# goa\n[GitOps](https://www.redhat.com/en/topics/devops/what-is-gitops) Agent - continuously monitors a remote git repository against local/any change, and performs actions (e.g. executes a provided command) - given a periodicity that is defined as a time intervals.\n\n## Security Warning\n\n**goa executes arbitrary commands** from the `-c` flag or `.goa` files in monitored repositories. Before using goa:\n\n- **Never run as root** - use a dedicated unprivileged user\n- **Only monitor trusted repositories** - a compromised repo can execute malicious code\n- **Use `--timeout`** - prevent runaway commands from consuming resources\n- **Use deploy keys** - prefer read-only deploy keys over personal access tokens\n\nSee [SECURITY.md](SECURITY.md) for detailed security considerations and deployment recommendations.\n\n## Installation\n\n### From crates.io (recommended)\n```bash\ncargo install gitops-agent\n```\n\n### From releases\nDownload a binary from the [releases](https://github.com/kitplummer/goa/releases) for your OS and CPU architecture. Be sure to make the binary executable on UNIX-based OSes (e.g. `chmod +x goa`).\n\n## Usage\n### Top-level\n\n#### Help (--help)\n```\nA command-line GitOps utility agent\n\nUsage: goa \u003cCOMMAND\u003e\n\nCommands:\n  spy      Spy a remote git repo for changes, will continuously execute defined script/command on a diff\n  radicle  Watch a Radicle repository for changes via HTTP API\n  help     Print this message or the help of the given subcommand(s)\n\nOptions:\n  -h, --help  Print help\n```\n\n#### Version (--version)\nThis does exactly what you'd expect.\n\n### Subcommand-level \n\n#### Spy\n```\nSpy a remote git repo for changes, will continuously execute defined script/command on a diff\n\nUsage: goa spy [OPTIONS] \u003cURL\u003e\n\nArguments:\n  \u003cURL\u003e  The remote git repo to watch for changes\n\nOptions:\n  -b, --branch \u003cBRANCH\u003e            The branch of the remote git repo to watch for changes [default: main]\n  -d, --delay \u003cDELAY\u003e              The time between checks in seconds, max 65535 [default: 120]\n  -u, --username \u003cUSERNAME\u003e        Username, owner of the token - required for private repos\n  -t, --token \u003cTOKEN\u003e              The access token for cloning and fetching of the remote repo\n  -c, --command \u003cCOMMAND\u003e          The command to run when a change is detected [default: ]\n  -v, --verbosity \u003cVERBOSITY\u003e      Adjust level of stdout, 0 no goa output, max 2 (debug) [default: 1]\n  -e, --exec-on-start              Execute the command, or .goa file, on start\n  -x, --exit-on-first-diff         Exit immediately after first diff spied\n  -T, --target-path \u003cTARGET_PATH\u003e  The target path for the clone\n      --timeout \u003cTIMEOUT\u003e          Timeout for command execution in seconds (0 = no timeout) [default: 0]\n  -h, --help                       Print help\n```\n\n#### Examples\n\n* `goa spy -c 'echo \"hello from goa\"' -e -d 20 https://github.com/kitplummer/goa_tester`\n\nThis will echo out to the command line on startup, and then on any change to the main branch, looking for changes every 20 seconds.\n\n* `goa spy -d 120 -b develop -v 2 https://github.com/kitplummer/goa_tester`\n\nThis will execute the contents of the `.goa` file in the repo on any diffs found in the develop branch, looking for changes every 120 seconds. It will also log out debug-level details, which occur inside the processing loop (may get noisy).\n\n* `goa spy -c 'echo \"change by ${GOA_LAST_COMMIT_AUTHOR} made to main branch\"' https://github.com/kitplummer/goa_tester`\n\nThis will output the author of the last commit made to the main branch, looking for changes every 120 seconds.\n\n* `goa spy -c 'echo \"changed!\"' -x https://github.com/kitplummer/goa_tester`\n\nThis will output \"changed!\" on stdout then exit after the first diff is identified on the \"main\" branch of the provided remote repo.\n\n* `goa spy -c 'echo \"changed!\"' -T \"/tmp/goa\" -x https://github.com/kitplummer/goa_tester`\n\nWill do the same as above, but create the local clone at `/tmp/goa`.\n\n#### Radicle\n\nWatch a [Radicle](https://radicle.xyz) repository for changes via HTTP API. This enables CI/CD for decentralized git projects.\n\n```\nWatch a Radicle repository for changes via HTTP API\n\nUsage: goa radicle [OPTIONS] --seed-url \u003cSEED_URL\u003e --rid \u003cRID\u003e\n\nOptions:\n  -s, --seed-url \u003cSEED_URL\u003e      The Radicle seed node URL (e.g., https://iris.radicle.xyz)\n  -r, --rid \u003cRID\u003e                The Radicle repository ID (e.g., rad:z3fF7wV6LXz915ND1nbHTfeY3Qcq7)\n  -c, --command \u003cCOMMAND\u003e        The command to run when a change is detected [default: ]\n  -d, --delay \u003cDELAY\u003e            The time between checks in seconds, max 65535 [default: 120]\n  -v, --verbosity \u003cVERBOSITY\u003e    Adjust level of stdout, 0 no goa output, max 2 (debug) [default: 1]\n      --timeout \u003cTIMEOUT\u003e        Timeout for command execution in seconds (0 = no timeout) [default: 0]\n  -p, --watch-patches            Watch for patch (PR) updates in addition to head changes\n  -l, --local-path \u003cLOCAL_PATH\u003e  Local working directory for command execution and .goa file\n```\n\n##### Radicle Examples\n\n* Watch for pushes and patches on a Radicle repo:\n```bash\ngoa radicle -s https://iris.radicle.xyz -r rad:z3fF7wV6LXz915ND1nbHTfeY3Qcq7 -c './run-ci.sh'\n```\n\n* Watch only for head changes (no patches):\n```bash\ngoa radicle -s https://iris.radicle.xyz -r rad:z3fF7wV6LXz915ND1nbHTfeY3Qcq7 -c 'echo \"new push!\"' --watch-patches=false\n```\n\n##### Radicle Environment Variables\n\nWhen triggered by Radicle events, goa provides these environment variables:\n\n| Variable | Description |\n|----------|-------------|\n| `GOA_RADICLE_RID` | Repository ID (e.g., `rad:z3fF7wV6LXz915ND1nbHTfeY3Qcq7`) |\n| `GOA_RADICLE_URL` | Seed node URL |\n| `GOA_TRIGGER_TYPE` | `push` or `patch` |\n| `GOA_COMMIT_OID` | Commit SHA to test |\n| `GOA_PATCH_ID` | Patch ID (if trigger_type=patch) |\n| `GOA_BASE_COMMIT` | Base commit for patches |\n| `GOA_PATCH_STATE` | Patch state: open/merged/archived |\n| `GOA_PATCH_TITLE` | Patch title |\n\n##### Example CI Script for Radicle\n\n```bash\n#!/bin/bash\necho \"Testing commit $GOA_COMMIT_OID\"\nif [ \"$GOA_TRIGGER_TYPE\" = \"patch\" ]; then\n  echo \"Patch: $GOA_PATCH_ID - $GOA_PATCH_TITLE\"\n  echo \"Base: $GOA_BASE_COMMIT\"\nfi\n\n# Clone from local Radicle storage and checkout the commit\ngit clone ~/.radicle/storage/${GOA_RADICLE_RID#rad:} /tmp/ci-$$\ncd /tmp/ci-$$\ngit checkout $GOA_COMMIT_OID\n\n# Run tests\ncargo test\n```\n\n### Using a `.goa` File\n\nIf no `-c`/`--command` is provided when starting `goa` - it will automatically look for a `.goa` file in the remote git repository, and execute the command within it.\n\nThe `.goa` file can only run a single command (right now, maybe multilines in the future)\n\nAn example repo with a `.goa` file can be seen here: https://github.com/kitplummer/goa_tester\n\n### Environment Variables\n\nWhen `goa` executes it provides details on the latest commit through environment variables:\n\n* `GOA_LAST_COMMIT_ID` -\u003e the commit hash of the last commit on the spied upon branch\n* `GOA_LAST_COMMIT_TIME` -\u003e the timestamp of the last commit\n* `GOA_LAST_COMMIT_AUTHOR` -\u003e the author of the last commit\n* `GOA_LAST_COMMIT_MESSAGE` -\u003e the message of the last commit\n\nIf there is something specific you're looking for here, let me know via an [issue](https://github.com/kitplummer/goa/issues).\n\n### Windows\n\nUnderneath, goa is providing the `cmd /C` so you don't need to pass that in - just the command.\n\n`goa spy -c 'echo hello' -d 20 -v 2 https://github.com/kitplummer/goa_tester`\n\nAnd if you are using a `.goa` file, reference the command calling a batch like\n\n```\n.\\hello.bat\n```\n\n### Running as a container\n\nNote: public release of the container to the GitHub registry is a work-in-progress - we'll update the doc here when the container is pushed within the release process.  For now you can build the container then run it.\n\n```\ndocker run -it --rm kitplummer/goa spy --help\n```\n\nRunning from a container, depending on the permissions of the underlying container system may cause issues with the abilty to execute commands from goa itself.  Also, it might make more sense for goa to be integrated into a container that includes to the commands to be executed.\n\n## Builds\nFor each release we're currently building binaries for:\n* Generic x86_64 Linux (only tested on current Ubuntu)\n* Arm 32-bit for Linux (tested on Raspian on a RaspberryPi Zero)\n* Arm 64-bit for Linux (tested on Ubuntu on a RaspberryPi 4)\n* 64-bit for CentOS 7\n* Windows (only tested in a VM of Windows 11)\n* macOS (tested on current macOS)\n\nNeed something else, let me know and i'll add the cross-compile to the GitHub Actions pipeline.\n\n## Contributing\n\nNothing formal, but PRs are the means. Create an [issue](https://github.com/kitplummer/goa/issues) if you have a question, comment, or just because. :D\n\n## License\n\n```\nMIT License\n\nCopyright (c) 2021 Kit Plummer\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkitplummer%2Fgoa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkitplummer%2Fgoa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkitplummer%2Fgoa/lists"}