{"id":50786637,"url":"https://github.com/urutau-ltd/git-cone","last_synced_at":"2026-06-12T08:03:19.747Z","repository":{"id":353465562,"uuid":"1219333559","full_name":"urutau-ltd/git-cone","owner":"urutau-ltd","description":"A security-oriented hard fork of soft-serve.","archived":false,"fork":false,"pushed_at":"2026-05-01T18:11:14.000Z","size":2139,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"develop","last_synced_at":"2026-05-01T20:13:32.427Z","etag":null,"topics":["git","golang","soft-serve","soft-serve-fork","ssh"],"latest_commit_sha":null,"homepage":"","language":"Go","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/urutau-ltd.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":".github/CODEOWNERS","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":"2026-04-23T19:14:17.000Z","updated_at":"2026-05-01T18:11:17.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/urutau-ltd/git-cone","commit_stats":null,"previous_names":["urutau-ltd/git-cone"],"tags_count":54,"template":false,"template_full_name":null,"purl":"pkg:github/urutau-ltd/git-cone","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urutau-ltd%2Fgit-cone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urutau-ltd%2Fgit-cone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urutau-ltd%2Fgit-cone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urutau-ltd%2Fgit-cone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/urutau-ltd","download_url":"https://codeload.github.com/urutau-ltd/git-cone/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urutau-ltd%2Fgit-cone/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34234558,"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-06-12T02:00:06.859Z","response_time":109,"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":["git","golang","soft-serve","soft-serve-fork","ssh"],"created_at":"2026-06-12T08:03:16.570Z","updated_at":"2026-06-12T08:03:19.741Z","avatar_url":"https://github.com/urutau-ltd.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🍦 git-cone\n\n`git-cone` is a security-hardened hard fork of\n[`soft-serve`](https://github.com/charmbracelet/soft-serve). It is intended to\nstay as drop-in compatible as practical while focusing on security fixes and\noperational hardening, not on growing the core product surface.\n\n`cone` is the primary CLI. `soft` remains available as a compatibility layer.\n\nThis fork includes security work imported and adapted from\n[dvrd](https://github.com/dvrd)'s `soft-serve` branch, including the patch set\ndescribed in local commit `8eb4b04` (\"apply dvrd rounds 46-59 fixes\"). That\nimport covered fixes such as SSRF/JWT hardening and several backend/store\ncorrections.\n\nAdditional hardening was then implemented directly in `git-cone`:\n\n- SSH was hardened using stricter KEX, cipher, and MAC defaults in\n  [pkg/ssh/ssh.go](pkg/ssh/ssh.go).\n- SSH stdin was hardened using input rate limiting in\n  [pkg/ssh/middleware.go](pkg/ssh/middleware.go).\n- File serving was hardened by removing the `sendFile` TOCTOU window in\n  [pkg/web/git.go](pkg/web/git.go).\n- User deletion was hardened by fixing repo and row deletion ordering in\n  [pkg/backend/user.go](pkg/backend/user.go).\n\nAs of `v0.13.X` the internals between `soft-serve` and `git-cone` have diverged\na bit more, please don't take this list as exhaustive.\n\n## Highlights\n\n- Pure Go build, including SQLite via `modernc.org/sqlite`\n- SSH TUI and SSH command interface\n- HTTP Git smart protocol and LFS\n- Dual env-prefix support: `GIT_CONE_*` overrides `SOFT_SERVE_*`\n- Optional Gotify notifications for security-relevant events\n- Strict mode for hardened deployments\n- `git://` disabled by default\n- `cone audit`, `repo verify`, and `/health`\n\n## Screenshots\n\n![screenshot1](.repo-assets/git-cone-screenshot.png)\n![screenshot2](.repo-assets/git-cone-screenshot2.png)\n\n## Quick Start\n\nBuild locally:\n\n```bash\nmake build\n./dist/cone serve\n```\n\nOr enter the Guix development shell first:\n\n```bash\nmake shell\nmake build\nmake test\n```\n\nFirst-time SSH admin flow:\n\n1. Start the server with `GIT_CONE_INITIAL_ADMIN_KEYS` pointing to your public\n   key.\n2. Connect with `ssh -p 23231 git@host` for the TUI.\n3. Run admin commands over SSH, for example:\n   `ssh -p 23231 host user create alice` `ssh -p 23231 host repo create demo`\n   `ssh -p 23231 host audit`\n\n## Docker\n\n\u003e [!IMPORTANT]\n\u003e The `latest` tag is literally the latest image built wheter it was tagged\n\u003e not, this includes development builds. Use a pinned version.\n\n```bash\ndocker pull ghcr.io/urutau-ltd/git-cone:\u003ctag\u003e\n```\n\nMinimal Compose example:\n\n```yaml\nservices:\n  git-cone:\n    image: ghcr.io/urutau-ltd/git-cone:latest\n    ports:\n      - \"23231:23231\"\n      - \"127.0.0.1:23232:23232\"\n    volumes:\n      - git-cone-data:/git-cone/data\n      - ./git-cone/hooks:/git-cone/data/hooks\n    environment:\n      - GIT_CONE_DATA_PATH=/git-cone/data\n      - GIT_CONE_INITIAL_ADMIN_KEYS=ssh-ed25519 AAAA...\n      - GIT_CONE_SSH_PUBLIC_URL=ssh://git.example.com\n      - GIT_CONE_HTTP_PUBLIC_URL=https://git.example.com\n      - GIT_CONE_NAME=Git Cone\n      - GIT_CONE_SECURITY_STRICT=true\n    restart: unless-stopped\n\nvolumes:\n  git-cone-data:\n```\n\nContainer notes:\n\n- data lives at `/git-cone/data`\n- hooks live at `/git-cone/data/hooks`\n- the image provides both `cone` and `soft`\n- `/health` is intended for local container health checks such as Docker/Dozzle\n\n## Compatibility\n\nThis fork aims to remain a practical drop-in replacement for recent `soft-serve`\ndeployments.\n\n| Before         | After                                                  |\n| -------------- | ------------------------------------------------------ |\n| `soft serve`   | `cone serve` or `soft serve`                           |\n| `soft browse`  | `cone browse` or `soft browse`                         |\n| `SOFT_SERVE_*` | `GIT_CONE_*` preferred, `SOFT_SERVE_*` still supported |\n\nWhat changed on purpose:\n\n- the preferred binary name is now `cone`\n- `soft` still works and maps to the same implementation\n- the default server name is `Git Cone`\n- the image stores data in `/git-cone/data`\n- `git://` is off by default\n- the server is SQLite-only\n\n### Differences From `soft-serve`\n\nThis fork intentionally diverges from upstream in a few places. These are the\nones operators usually need to know before a migration:\n\n| Area                   | `soft-serve` expectation                     | `git-cone` behavior                                                                  |\n| ---------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------ |\n| Primary binary         | `soft`                                       | `cone` is preferred; `soft` remains as compatibility wrapper                         |\n| Environment prefix     | `SOFT_SERVE_*`                               | `GIT_CONE_*` is preferred; `SOFT_SERVE_*` still works                                |\n| Data path in container | `/soft-serve`                                | `/git-cone/data`                                                                     |\n| Default server name    | Upstream default                             | `Git Cone`                                                                           |\n| Database backends      | Upstream had more room for alternate drivers | SQLite-only                                                                          |\n| `git://` daemon        | Historically available by default            | Disabled by default                                                                  |\n| Strict mode            | Not present                                  | Available via `security.strict`                                                      |\n| SSH crypto defaults    | Upstream defaults                            | Hardened KEX/cipher/MAC policy, including post-quantum KEX for newer OpenSSH clients |\n| Health endpoint        | Not present                                  | `GET /health` returns JSON                                                           |\n| Audit command          | Not present                                  | `ssh host audit`                                                                     |\n| Repo integrity check   | Not present                                  | `ssh host repo verify \u003crepo\u003e`                                                        |\n| Notifications          | No upstream support                          | Optional Gotify notifications added by this fork                                     |\n\nBehavior that stays intentionally compatible:\n\n- SSH TUI remains the main interface\n- Git over SSH and HTTP still work the same way\n- `soft serve`, `soft browse`, and `SOFT_SERVE_*` still work\n- the SSH command surface stays close to upstream, with additive hardening\n  features\n\nFor existing Compose stacks, the least disruptive migration is:\n\n- keep the service name as `soft-serve`\n- keep the volume name as `soft-serve-data`\n- switch the image to `ghcr.io/urutau-ltd/git-cone:latest`\n- mount that volume at `/git-cone/data`\n- set `GIT_CONE_DATA_PATH=/git-cone/data`\n\nExample drop-in replacement:\n\n```yaml\nservices:\n  soft-serve:\n    image: ghcr.io/urutau-ltd/git-cone:latest\n    ports:\n      - \"23231:23231\"\n      - \"23232:23232\"\n    volumes:\n      - soft-serve-data:/git-cone/data\n      - ./soft-serve/hooks:/git-cone/data/hooks\n    environment:\n      - GIT_CONE_DATA_PATH=/git-cone/data\n      - GIT_CONE_INITIAL_ADMIN_KEYS=${SOFT_SERVE_ADMIN_KEY}\n      - GIT_CONE_SSH_PUBLIC_URL=ssh://git.example.com\n      - GIT_CONE_HTTP_PUBLIC_URL=https://git.example.com\n      - GIT_CONE_NAME=Git Cone\n      - GIT_CONE_SECURITY_STRICT=true\n    healthcheck:\n      test: [\"CMD\", \"curl\", \"-fsS\", \"http://127.0.0.1:23232/health\"]\n      interval: 30s\n      timeout: 5s\n      retries: 3\n      start_period: 15s\n```\n\n## CLI Reference\n\nThis section documents the actual command surface exposed by the current fork.\nIt covers:\n\n- the local binary CLI: `cone` and `soft`\n- the SSH command interface users run against the server\n- the repo subcommands under `repo`\n- the internal transport commands Git uses under SSH\n\n### Local Binary CLI\n\n`cone` is the primary binary. `soft` is a compatibility wrapper over the same\nimplementation.\n\n#### Root commands\n\n| Command                  | Purpose                                         | Notes                  |\n| ------------------------ | ----------------------------------------------- | ---------------------- |\n| `cone serve`             | Start the server                                | `soft serve` works too |\n| `cone browse [PATH]`     | Open the local TUI against a repository on disk | Defaults to `.`        |\n| `cone admin migrate`     | Migrate the SQLite schema to the latest version | Local admin command    |\n| `cone admin rollback`    | Roll back the previous database migration       | Local admin command    |\n| `cone admin sync-hooks`  | Rewrite server-managed hooks for all repos      | Local admin command    |\n| `cone hook pre-receive`  | Internal hook entrypoint                        | Hidden; called by Git  |\n| `cone hook update`       | Internal hook entrypoint                        | Hidden; called by Git  |\n| `cone hook post-receive` | Internal hook entrypoint                        | Hidden; called by Git  |\n| `cone hook post-update`  | Internal hook entrypoint                        | Hidden; called by Git  |\n| `cone man`               | Generate a manpage                              | Hidden                 |\n\n#### Local command flags\n\n`cone serve`\n\n- `--sync-hooks` Rewrite hooks for all repositories before the server starts.\n\n`cone browse [PATH]`\n\n- no extra flags\n\n`cone admin migrate`\n\n- no extra flags\n\n`cone admin rollback`\n\n- no extra flags\n\n`cone admin sync-hooks`\n\n- no extra flags\n\n`cone hook ...`\n\n- `--config` Deprecated and ignored. Hook execution reads from the loaded config\n  and environment.\n\n### SSH Usage Model\n\nThe SSH interface has three modes:\n\n1. `ssh -p 23231 host` Opens the interactive TUI.\n2. `ssh -p 23231 host \u003crepo\u003e` Opens the TUI directly on a readable repository.\n3. `ssh -p 23231 host \u003ccommand\u003e ...` Runs a non-interactive SSH command.\n\nThe SSH command help is dynamic and uses the configured public SSH URL to print\nthe correct host and port in examples.\n\n### SSH Top-Level Commands\n\nThese are the public non-interactive commands available over SSH.\n\n| Command                            | Purpose                                              | Access                                                              |\n| ---------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------- |\n| `audit`                            | Show server/session audit information                | Any authenticated user; limited output for unauthenticated sessions |\n| `doctor`                           | Show effective server security and runtime settings  | Admin                                                               |\n| `info`                             | Show information about the current user              | Authenticated user                                                  |\n| `jwt [repository1 repository2...]` | Mint a JWT scoped to the given audience/repositories | Authenticated user                                                  |\n| `pubkey ...`                       | Manage your own SSH public keys                      | Authenticated user                                                  |\n| `repo ...`                         | Manage repositories and inspect repo content         | Varies by subcommand                                                |\n| `set-username USERNAME`            | Change your own username                             | Authenticated user                                                  |\n| `settings ...`                     | Read or change server-wide access settings           | Admin                                                               |\n| `token ...`                        | Manage your own access tokens                        | Authenticated user                                                  |\n| `user ...`                         | Manage users                                         | Admin                                                               |\n\n### SSH Command Details\n\n#### `audit`\n\n```text\nssh -p 23231 host audit\n```\n\nPrints:\n\n- server version\n- current username and admin state when available\n- remote client address and SSH client version\n- active public key fingerprint\n- active public key algorithm\n- public key age when the DB has `created_at`\n- auth mode and whether the session is keyless\n- negotiated hostkey, cipher, KEX, and whether the KEX is post-quantum when the\n  session exposes them\n- owned and collaborator repo counts\n\nUnauthenticated or keyless sessions only get the server version line.\n\n#### `doctor`\n\n```text\nssh -p 23231 host doctor\n```\n\nPrints the effective server-side settings that matter for operations and\nhardening, including:\n\n- strict mode state\n- effective SSH/HTTP/stats/git listen addresses and public URLs\n- LFS and LFS-over-SSH state\n- hook timeout and SSH timeouts\n- host/client key paths and whether those files exist\n- hardened SSH KEX, cipher, and MAC policy\n\n#### `info`\n\n```text\nssh -p 23231 host info\n```\n\nPrints the current user's account details.\n\n#### `jwt [repository1 repository2...]`\n\n```text\nssh -p 23231 host jwt\nssh -p 23231 host jwt repo1 repo2\n```\n\nCreates a signed JWT using the server JWK pair. The listed repositories become\nthe JWT audience.\n\n#### `set-username USERNAME`\n\n```text\nssh -p 23231 host set-username new-name\n```\n\nChanges the username of the authenticated user.\n\n### `pubkey` Commands\n\nManage the public keys attached to the current account.\n\n| Command                        | Purpose                               |\n| ------------------------------ | ------------------------------------- |\n| `pubkey add AUTHORIZED_KEY`    | Add a public key to your account      |\n| `pubkey remove AUTHORIZED_KEY` | Remove a public key from your account |\n| `pubkey list`                  | List your current public keys         |\n\nAliases:\n\n- `pubkeys`\n- `publickey`\n- `publickeys`\n\nExamples:\n\n```bash\nssh -p 23231 host pubkey list\nssh -p 23231 host pubkey add \"ssh-ed25519 AAAA...\"\nssh -p 23231 host pubkey remove \"ssh-ed25519 AAAA...\"\n```\n\n### `token` Commands\n\nManage HTTP/API access tokens for the current user.\n\n| Command             | Purpose                                                     |\n| ------------------- | ----------------------------------------------------------- |\n| `token create NAME` | Create a token and print it once                            |\n| `token list`        | List token IDs, names, creation dates, and expiration state |\n| `token delete ID`   | Delete a token by numeric ID                                |\n\nAliases:\n\n- `token`: alias group `access-token`\n- `token list`: alias `ls`\n- `token delete`: aliases `rm`, `remove`\n\nFlags:\n\n`token create NAME`\n\n- `--expires-in` Expiration duration such as `1y`, `3mo`, `2w`, `5d4h`, or\n  `1h30m`.\n\nExamples:\n\n```bash\nssh -p 23231 host token create \"ci bot\"\nssh -p 23231 host token create \"pipe clone token\" --expires-in 90d\nssh -p 23231 host token list\nssh -p 23231 host token delete 3\n```\n\n### `settings` Commands\n\nThese are server-wide settings stored in the database. They are admin-only.\n\n| Command                               | Purpose                           |\n| ------------------------------------- | --------------------------------- |\n| `settings allow-keyless [true         | false]`                           |\n| `settings anon-access [ACCESS_LEVEL]` | Get or set anonymous access level |\n\nValid `ACCESS_LEVEL` values:\n\n- `no-access`\n- `read-only`\n- `read-write`\n- `admin-access`\n\nExamples:\n\n```bash\nssh -p 23231 host settings allow-keyless false\nssh -p 23231 host settings anon-access no-access\n```\n\nNote:\n\n- when `security.strict` is enabled, `allow-keyless` is forced off\n- when `security.strict` is enabled, `anon-access` is forced to `no-access`\n\n### `user` Commands\n\nAll `user` commands are admin-only.\n\n| Command                                      | Purpose                  |\n| -------------------------------------------- | ------------------------ |\n| `user create USERNAME`                       | Create a new user        |\n| `user delete USERNAME`                       | Delete a user            |\n| `user list`                                  | List all users           |\n| `user add-pubkey USERNAME AUTHORIZED_KEY`    | Add a key to a user      |\n| `user remove-pubkey USERNAME AUTHORIZED_KEY` | Remove a key from a user |\n| `user set-admin USERNAME [true               | false]`                  |\n| `user info USERNAME`                         | Show user details        |\n| `user set-username USERNAME NEW_USERNAME`    | Rename a user            |\n\nAliases:\n\n- `user`: alias group `users`\n- `user list`: alias `ls`\n\nFlags:\n\n`user create USERNAME`\n\n- `-a`, `--admin` Create the user as admin.\n- `-k`, `--key` Attach an initial public key.\n\nExamples:\n\n```bash\nssh -p 23231 host user create alice\nssh -p 23231 host user create pipe-bot --key \"ssh-ed25519 AAAA...\"\nssh -p 23231 host user create release-bot --admin\nssh -p 23231 host user set-admin alice true\nssh -p 23231 host user info alice\n```\n\n### `repo` Commands\n\n`repo` is the largest command group.\n\nAliases for the group:\n\n- `repos`\n- `repository`\n- `repositories`\n\nThe subcommands below are available under:\n\n```text\nssh -p 23231 host repo ...\n```\n\n#### Repo listing and metadata\n\n| Command                                     | Purpose                                 | Access                  |\n| ------------------------------------------- | --------------------------------------- | ----------------------- |\n| `repo list`                                 | List readable repositories              | Readable                |\n| `repo info REPOSITORY`                      | Print repo metadata, branches, and tags | Readable                |\n| `repo description REPOSITORY [DESCRIPTION]` | Get or set description                  | Write/admin             |\n| `repo project-name REPOSITORY [NAME]`       | Get or set project name                 | Write/admin             |\n| `repo private REPOSITORY [true              | false]`                                 | Get or set private flag |\n| `repo hidden REPOSITORY [true               | false]`                                 | Get or set hidden flag  |\n| `repo is-mirror REPOSITORY`                 | Report whether the repo is a mirror     | Readable                |\n\nFlags:\n\n`repo list`\n\n- `-a`, `--all` Include hidden repositories that are otherwise readable.\n\nExamples:\n\n```bash\nssh -p 23231 host repo list\nssh -p 23231 host repo list --all\nssh -p 23231 host repo info demo\nssh -p 23231 host repo description demo \"Internal deployment repo\"\nssh -p 23231 host repo private demo true\n```\n\n#### Repo creation and lifecycle\n\n| Command                           | Purpose                               | Access      |\n| --------------------------------- | ------------------------------------- | ----------- |\n| `repo create REPOSITORY`          | Create a repository                   | Write/admin |\n| `repo import REPOSITORY REMOTE`   | Import a repository from a remote URL | Write/admin |\n| `repo delete REPOSITORY`          | Delete a repository                   | Admin       |\n| `repo rename REPOSITORY NEW_NAME` | Rename a repository                   | Admin       |\n| `repo verify REPOSITORY`          | Run `git fsck --full`                 | Write/admin |\n\nFlags:\n\n`repo create REPOSITORY`\n\n- `-p`, `--private`\n- `-d`, `--description`\n- `-n`, `--name`\n- `-H`, `--hidden`\n\n`repo import REPOSITORY REMOTE`\n\n- `--lfs`\n- `--lfs-endpoint`\n- `-m`, `--mirror`\n- `-p`, `--private`\n- `-d`, `--description`\n- `-n`, `--name`\n- `-H`, `--hidden`\n\nExamples:\n\n```bash\nssh -p 23231 host repo create demo\nssh -p 23231 host repo create secret-repo --private --description \"confidential\"\nssh -p 23231 host repo import upstream https://example.com/repo.git --mirror\nssh -p 23231 host repo verify demo\nssh -p 23231 host repo rename demo demo-archive\n```\n\n#### Repo content inspection\n\n| Command                                   | Purpose                         | Access   |\n| ----------------------------------------- | ------------------------------- | -------- |\n| `repo blob REPOSITORY [REFERENCE] [PATH]` | Print a file from a commit/tree | Readable |\n| `repo tree REPOSITORY [REFERENCE] [PATH]` | Print the repository tree       | Readable |\n| `repo commit REPOSITORY SHA`              | Print a commit diff             | Readable |\n\nFlags:\n\n`repo blob REPOSITORY [REFERENCE] [PATH]`\n\n- `-r`, `--raw`\n- `-l`, `--linenumber`\n- `-c`, `--color`\n\n`repo commit REPOSITORY SHA`\n\n- `-c`, `--color`\n- `-p`, `--patch`\n\nExamples:\n\n```bash\nssh -p 23231 host repo blob demo HEAD README.md\nssh -p 23231 host repo blob demo HEAD README.md --raw\nssh -p 23231 host repo tree demo HEAD\nssh -p 23231 host repo commit demo 0123456789abcdef --patch\n```\n\n#### Branch commands\n\n| Command                                   | Purpose                       | Access      |\n| ----------------------------------------- | ----------------------------- | ----------- |\n| `repo branch list REPOSITORY`             | List branches                 | Readable    |\n| `repo branch default REPOSITORY [BRANCH]` | Get or set the default branch | Write/admin |\n| `repo branch delete REPOSITORY BRANCH`    | Delete a branch               | Write/admin |\n\nExamples:\n\n```bash\nssh -p 23231 host repo branch list demo\nssh -p 23231 host repo branch default demo main\nssh -p 23231 host repo branch delete demo old-branch\n```\n\n#### Tag commands\n\n| Command                          | Purpose      | Access      |\n| -------------------------------- | ------------ | ----------- |\n| `repo tag list REPOSITORY`       | List tags    | Readable    |\n| `repo tag delete REPOSITORY TAG` | Delete a tag | Write/admin |\n\nExamples:\n\n```bash\nssh -p 23231 host repo tag list demo\nssh -p 23231 host repo tag delete demo v0.1.0\n```\n\n#### Collaborator commands\n\n| Command                                       | Purpose               | Access |\n| --------------------------------------------- | --------------------- | ------ |\n| `repo collab add REPOSITORY USERNAME [LEVEL]` | Add a collaborator    | Admin  |\n| `repo collab remove REPOSITORY USERNAME`      | Remove a collaborator | Admin  |\n| `repo collab list REPOSITORY`                 | List collaborators    | Admin  |\n\nValid collaborator levels:\n\n- `no-access`\n- `read-only`\n- `read-write`\n- `admin-access`\n\nIf omitted, `repo collab add` defaults to `read-write`.\n\nExamples:\n\n```bash\nssh -p 23231 host repo collab add demo alice read-only\nssh -p 23231 host repo collab add demo bob admin-access\nssh -p 23231 host repo collab list demo\nssh -p 23231 host repo collab remove demo alice\n```\n\n#### Webhook commands\n\nAll webhook commands are admin-only for the target repository.\n\n| Command                                                               | Purpose                |\n| --------------------------------------------------------------------- | ---------------------- |\n| `repo webhook list REPOSITORY`                                        | List webhooks          |\n| `repo webhook create REPOSITORY URL`                                  | Create a webhook       |\n| `repo webhook delete REPOSITORY WEBHOOK_ID`                           | Delete a webhook       |\n| `repo webhook update REPOSITORY WEBHOOK_ID`                           | Update a webhook       |\n| `repo webhook deliveries list REPOSITORY WEBHOOK_ID`                  | List delivery attempts |\n| `repo webhook deliveries redeliver REPOSITORY WEBHOOK_ID DELIVERY_ID` | Redeliver one attempt  |\n| `repo webhook deliveries get REPOSITORY WEBHOOK_ID DELIVERY_ID`       | Inspect one delivery   |\n\nAliases:\n\n- `repo webhook`: alias `webhooks`\n- `repo webhook deliveries`: aliases `delivery`, `deliver`\n\nFlags:\n\n`repo webhook create REPOSITORY URL`\n\n- `-e`, `--events`\n- `-s`, `--secret`\n- `-a`, `--active`\n- `-c`, `--content-type`\n\n`repo webhook update REPOSITORY WEBHOOK_ID`\n\n- `-e`, `--events`\n- `-s`, `--secret`\n- `-a`, `--active`\n- `-c`, `--content-type`\n- `-u`, `--url`\n\n`--content-type` accepts:\n\n- `json`\n- `form`\n\nExamples:\n\n```bash\nssh -p 23231 host repo webhook list demo\nssh -p 23231 host repo webhook create demo https://example.com/hook --events push --secret supersecret\nssh -p 23231 host repo webhook update demo 4 --active false\nssh -p 23231 host repo webhook deliveries list demo 4\nssh -p 23231 host repo webhook deliveries get demo 4 550e8400-e29b-41d4-a716-446655440000\n```\n\n### Internal SSH Transport Commands\n\nThese are not normally typed by humans. Git and Git LFS invoke them over SSH.\n\n| Command                               | Purpose                   |\n| ------------------------------------- | ------------------------- |\n| `git-upload-pack REPO`                | Clone/fetch over SSH      |\n| `git-upload-archive REPO`             | Archive access over SSH   |\n| `git-receive-pack REPO`               | Push over SSH             |\n| `git-lfs-authenticate REPO OPERATION` | Git LFS auth handshake    |\n| `git-lfs-transfer REPO OPERATION`     | Git LFS transfer protocol |\n\nIf LFS is disabled, the LFS commands are not registered. If `lfs.ssh_enabled` is\nfalse, `git-lfs-transfer` is not registered.\n\nThe Git transport URLs and repository workflow stay the same:\n\n- SSH clone/push: `ssh://host:23231/\u003crepo\u003e.git`\n- HTTP clone/push: `https://host/\u003crepo\u003e.git`\n\n## Authentication and Strict Mode\n\n`strict=true` does not disable token-based HTTP access. It does this:\n\n- forces anonymous access to `no-access`\n- disables keyless access\n- clamps SSH timeouts\n- clamps HTTP CORS to `http.public_url`\n- keeps the stats listener on loopback when enabled\n\nThat means:\n\n- SSH always requires an authorized key\n- HTTP Git/LFS requires valid credentials\n- access tokens still work for automation such as `pipe`\n- `pipe` can keep using internal HTTP with a token behind Caddy; no server-local\n  TLS changes are required for that flow\n\nWith `strict=true`, a non-private repo is not anonymously readable. Today there\nis no per-repo “public override” when global anonymous access is forced off.\n\nThis is intentional hardening. If you need anonymous read access for non-private\nrepos, do not enable strict mode.\n\n## Gotify Notifications\n\n`soft-serve` did not ship with Gotify support. `git-cone` adds it.\n\nUse it if you want the server to send notifications to Gotify for selected\nevents. This can be useful on its own, or alongside tools such as `pipe`.\n\nWhen disabled, the server does not make notification network calls. When\nenabled, notification delivery failures do not block SSH, Git, HTTP, hooks, or\npushes.\n\n### Events\n\nCurrent events emitted by the fork:\n\n| Event                            | Trigger                                   | Priority |\n| -------------------------------- | ----------------------------------------- | -------- |\n| `git-cone: new user`             | A new user is created                     | `5`      |\n| `git-cone: webhook failure`      | A webhook fails 3 times in a row          | `5`      |\n| `git-cone: push to private repo` | A user pushes to a private repository     | `3`      |\n| `git-cone: auth failure burst`   | 5 failed auth attempts from one IP in 60s | `7`      |\n\nWhat these mean in practice:\n\n- `new user`: a new account was created\n- `webhook failure`: one webhook failed 3 times in a row\n- `push to private repo`: someone pushed to a private repository\n- `auth failure burst`: one IP accumulated 5 failed auth attempts in 60 seconds\n\n### Configuration\n\nYAML:\n\n```yaml\nnotify:\n  gotify:\n    enabled: true\n    url: \"https://gotify.example.com\"\n    token: \"YOUR_GOTIFY_APP_TOKEN\"\n    priority: 5\n```\n\nEnvironment variables:\n\n- `GIT_CONE_NOTIFY_GOTIFY_ENABLED=true`\n- `GIT_CONE_NOTIFY_GOTIFY_URL=https://gotify.example.com`\n- `GIT_CONE_NOTIFY_GOTIFY_TOKEN=YOUR_GOTIFY_APP_TOKEN`\n- `GIT_CONE_NOTIFY_GOTIFY_PRIORITY=5`\n\nCompatibility variables with the old prefix also work:\n\n- `SOFT_SERVE_NOTIFY_GOTIFY_ENABLED`\n- `SOFT_SERVE_NOTIFY_GOTIFY_URL`\n- `SOFT_SERVE_NOTIFY_GOTIFY_TOKEN`\n- `SOFT_SERVE_NOTIFY_GOTIFY_PRIORITY`\n\nThe old prefix support here is provided by `git-cone`'s dual-prefix config\nloader. It exists for migration convenience; it is not inherited Gotify support\nfrom upstream.\n\n### Example Compose\n\n```yaml\nservices:\n  soft-serve:\n    image: ghcr.io/urutau-ltd/git-cone:latest\n    environment:\n      - GIT_CONE_NOTIFY_GOTIFY_ENABLED=true\n      - GIT_CONE_NOTIFY_GOTIFY_URL=http://gotify:80\n      - GIT_CONE_NOTIFY_GOTIFY_TOKEN=${GOTIFY_TOKEN}\n      - GIT_CONE_NOTIFY_GOTIFY_PRIORITY=5\n```\n\nNotes:\n\n- internal services such as `pipe` should talk directly to `http://gotify:80`\n- avoid sending trusted service-to-service traffic through Anubis\n- notification delivery failures do not block Git or SSH operations\n\n## Pipe\n\nFor `pipe`, use an access token and internal HTTP:\n\n```text\nhttp://pipe-bot:${PIPE_GIT_TOKEN}@soft-serve:23232\n```\n\nRecommended setup:\n\n1. Create a `pipe-bot` user.\n2. Grant it read-only or admin access to the repos it needs.\n3. Create a token with `ssh cone token create`.\n4. Store that token in your deployment env as `PIPE_GIT_TOKEN`.\n\nThis keeps working with `security.strict=true`. Strict mode disables anonymous\nand keyless access, but it does not disable HTTP token auth for Git/LFS.\n\nIf you also run Gotify, let `pipe` talk to `http://gotify:80` directly on the\ninternal network. Do not put internal service-to-service traffic through Anubis.\n\n## Hooks\n\nGlobal hooks live under `$GIT_CONE_DATA_PATH/hooks/`. The server writes a sample\n`update.sample` hook on first start.\n\n## Configuration\n\nThe generated `config.yaml` is the canonical reference for the settings this\nfork currently exposes.\n\nNotable defaults:\n\n```yaml\ndb:\n  driver: \"sqlite\"\n\ngit:\n  listen_addr: \"\" # git:// disabled by default\n\nhooks:\n  timeout: 30\n\nsecurity:\n  strict: false\n\nnotify:\n  gotify:\n    enabled: false\n```\n\nEnvironment prefixes:\n\n- `GIT_CONE_*` is preferred\n- `SOFT_SERVE_*` remains supported for compatibility\n- if both are set, `GIT_CONE_*` wins\n\nUseful variables:\n\n- `GIT_CONE_DATA_PATH`\n- `GIT_CONE_INITIAL_ADMIN_KEYS`\n- `GIT_CONE_SSH_PUBLIC_URL`\n- `GIT_CONE_HTTP_PUBLIC_URL`\n- `GIT_CONE_NAME`\n- `GIT_CONE_HOOKS_TIMEOUT`\n- `GIT_CONE_SECURITY_STRICT`\n- `GIT_CONE_NOTIFY_GOTIFY_ENABLED`\n- `GIT_CONE_NOTIFY_GOTIFY_URL`\n- `GIT_CONE_NOTIFY_GOTIFY_TOKEN`\n\n## Development\n\nThis repo is Guix-friendly and includes a maintained `manifest.scm`.\n\n```bash\nmake shell\nmake build\nmake test\nmake test-all\nmake image\n```\n\nFiles worth knowing:\n\n- `manifest.scm`: Guix dev environment\n- `Makefile`: common dev and CI entrypoints\n- `.pipe.yml`: project pipeline\n- `internal/cli/cli.go`: shared CLI wiring for `cone` and `soft`\n- `pkg/config/config.go`: defaults and env loading\n- `pkg/ssh/cmd/`: SSH command handlers\n\n## Service Managers\n\nThe repo no longer ships systemd-centric packaging inherited from upstream. If\nyou need host-managed services, optional examples live in\n[docs/service-managers.md](docs/service-managers.md) for:\n\n- SysVinit\n- OpenRC\n- Runit\n- GNU Shepherd\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furutau-ltd%2Fgit-cone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Furutau-ltd%2Fgit-cone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furutau-ltd%2Fgit-cone/lists"}