[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-80477":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":12,"openIssues":14,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":14,"stars7d":14,"stars30d":14,"stars90d":14,"forks30d":14,"starsTrendScore":14,"compositeScore":15,"rankGlobal":10,"rankLanguage":10,"license":16,"archived":17,"fork":17,"defaultBranch":18,"hasWiki":19,"hasPages":17,"topics":20,"createdAt":10,"pushedAt":10,"updatedAt":21,"readmeContent":22,"aiSummary":23,"trendingCount":14,"starSnapshotCount":14,"syncStatus":24,"lastSyncTime":25,"discoverSource":26},80477,"gh-relay","soub4i\u002Fgh-relay","soub4i","Share a private GitHub repo with anyone, no collaborator invite, no paid seat, no cleanup.","",null,"Go",82,10,0,43.12,"MIT License",false,"main",true,[],"2026-06-12 04:01:28","# gh-relay\n\n> Share a private GitHub repo with anyone, no collaborator invite, no paid seat, no cleanup.\n\n[![CI](https:\u002F\u002Fgithub.com\u002Fsoub4i\u002Fgh-relay\u002Factions\u002Fworkflows\u002Fci.yaml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fsoub4i\u002Fgh-relay\u002Factions\u002Fworkflows\u002Fci.yaml)\n[![Release](https:\u002F\u002Fgithub.com\u002Fsoub4i\u002Fgh-relay\u002Factions\u002Fworkflows\u002Frelease.yaml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fsoub4i\u002Fgh-relay\u002Factions\u002Fworkflows\u002Frelease.yaml)\n[![Go Report Card](https:\u002F\u002Fgoreportcard.com\u002Fbadge\u002Fgithub.com\u002Fsoub4i\u002Fgh-relay)](https:\u002F\u002Fgoreportcard.com\u002Freport\u002Fgithub.com\u002Fsoub4i\u002Fgh-relay)\n[![License: MIT](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FLicense-MIT-yellow.svg)](LICENSE)\n\n---\n\nAdding a contractor or auditor as a GitHub collaborator means IT tickets, legal paperwork, a paid seat, and a permission that lingers long after the review is done. Most teams end up emailing zip files or screensharing instead, both worse.\n\n**gh-relay** fixes this in one command. Run it on your machine, share a temporary URL, and your guest gets a read-only browser view of the codebase. When you press `Ctrl+C`, the link is dead, zero cleanup, zero lingering access.\n\n```\n$ export GH_RELAY_TOKEN=ghp_...\n$ gh-relay share --repo my-org\u002Fprivate-app --expire 1h\n\n   Token valid\n   Repository: my-org\u002Fprivate-app (private)\n   Found 12 branch(es)\n   Tunnel active\n\n    Share this URL with your guest:\n    https:\u002F\u002Fshiny-apple-92.trycloudflare.com\n\n    Session expires in: 1h\n  Press Ctrl+C to end the session immediately.\n```\n\n---\n\n## How it works\n\n```\n                          YOUR MACHINE\n┌───────────────────────────────────────────────────────────────────────────┐\n│                                                                           │\n│  GH_RELAY_TOKEN  ──►  ┌─────────────────┐       ┌──────────────────────┐  │\n│  (or --token)         │   gh-relay      │       │   Tunnel Provider    │  │\n│  never leaves         │   proxy         │ ────► │                      │  │\n│                        └─────────────────┘      │  • Cloudflare (free) │  │\n│                              │                  │  • ngrok (free tier) │  │\n│                        ┌─────▼─────┐            └──────────┬───────────┘  │\n│                        │ optional  │                       │              │\n│                        │ passcode  │                       │              │\n│                        │ protection │                      │              │\n│                        └───────────┘                       │              │\n└────────────────────────────────────────────────────────────│──────────────┘\n                                                             │\n                                                             │ temp URL\n                                                             ▼\n┌────────────────────────────────────────────────────────────────────────────┐\n│                              GUEST                                         │\n│                                                                            │\n│   Browser ──► (URL + optional passcode) ──► read-only file browser         │\n│                                                                            │\n│   No GitHub account needed. Cannot push, clone, or download files.         │\n│                                                                            │\n└────────────────────────────────────────────────────────────────────────────┘\n```\n\n1. **You run** `gh-relay share` with your GitHub token and repo name.\n2. **A local proxy** starts on your machine and fetches files from GitHub using your token.\n3. **A secure tunnel** (Cloudflare or ngrok) exposes the proxy via a temporary public URL.\n4. **Your guest opens the URL** and gets a read-only file browser. Optionally protect with a passcode.\n5. **You press `Ctrl+C`** (or `--expire` elapses) and the tunnel closes instantly. The URL is dead.\nYour PAT never leaves your machine. The guest can't push, clone, or access anything you didn't share.\n\n---\n\n## Installation\n\n### Homebrew *(coming soon)*\n\n```bash\nbrew install soub4i\u002Ftap\u002Fgh-relay\n```\n\n### Download a binary\n\nGrab the latest release for your platform from the [Releases page](https:\u002F\u002Fgithub.com\u002Fsoub4i\u002Fgh-relay\u002Freleases).\n\n```bash\n# macOS (Apple Silicon)\ncurl -L https:\u002F\u002Fgithub.com\u002Fsoub4i\u002Fgh-relay\u002Freleases\u002Flatest\u002Fdownload\u002Fgh-relay_darwin_arm64.tar.gz | tar xz\nsudo mv gh-relay \u002Fusr\u002Flocal\u002Fbin\u002F\n\n# macOS (Intel)\ncurl -L https:\u002F\u002Fgithub.com\u002Fsoub4i\u002Fgh-relay\u002Freleases\u002Flatest\u002Fdownload\u002Fgh-relay_darwin_amd64.tar.gz | tar xz\nsudo mv gh-relay \u002Fusr\u002Flocal\u002Fbin\u002F\n\n# Linux (amd64)\ncurl -L https:\u002F\u002Fgithub.com\u002Fsoub4i\u002Fgh-relay\u002Freleases\u002Flatest\u002Fdownload\u002Fgh-relay_linux_amd64.tar.gz | tar xz\nsudo mv gh-relay \u002Fusr\u002Flocal\u002Fbin\u002F\n\n# Windows (amd64) - run in PowerShell\nInvoke-WebRequest -Uri https:\u002F\u002Fgithub.com\u002Fsoub4i\u002Fgh-relay\u002Freleases\u002Flatest\u002Fdownload\u002Fgh-relay_windows_amd64.zip -OutFile gh-relay.zip\nExpand-Archive gh-relay.zip\n```\n\n### Build from source\n\nRequires **Go 1.22+**.\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fsoub4i\u002Fgh-relay\ncd gh-relay\ngo build -o gh-relay .\nsudo mv gh-relay \u002Fusr\u002Flocal\u002Fbin\u002F\n```\n\n### Tunnel prerequisite\n\nYou need at least one tunnel provider installed:\n\n| Provider | Install |\n|---|---|\n| **Cloudflare** *(recommended, free, no account needed)* | [developers.cloudflare.com → Downloads](https:\u002F\u002Fdevelopers.cloudflare.com\u002Fcloudflare-one\u002Fconnections\u002Fconnect-networks\u002Fdownloads\u002F) |\n| **ngrok** | [ngrok.com\u002Fdownload](https:\u002F\u002Fngrok.com\u002Fdownload) |\n\n---\n\n## Usage\n\n### Using environment variable\n\n```bash\nexport GH_RELAY_TOKEN=ghp_YourPersonalAccessToken\ngh-relay share --repo my-org\u002Fprivate-app --expire 1h\n```\n\nIf both `--token` and `GH_RELAY_TOKEN` are set, `--token` takes precedence (a warning is logged).\n\n> **Tip:** Avoid exposing your token in shell history by using `GH_RELAY_TOKEN` instead of `--token`.\n\n### Share a repo\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app\n```\n\n### Set an expiry\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app --expire 30m\n```\n  --expire 30m\n```\n\n### Share a specific branch\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app --branch feature\u002Fnew-auth\n```\n\n### Share only selected paths\n\nUse `--allow` to expose only matching repository paths. Use `--deny` to hide matching paths; deny rules always take precedence over allow rules.\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app --allow \"src\u002F**,docs\u002F**,README.md\"\n```\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app --allow \"src\u002F**,docs\u002F**,README.md\" --deny \".env,.env.*,secrets\u002F**,*.pem\"\n```\n\nFilters are enforced server-side for both `\u002Fapi\u002Ftree` listings and `\u002Fapi\u002Fblob` file access, so a guest cannot bypass a hidden path by manually requesting a blob SHA. Patterns are globs; use `.env,.env.*` if you want to hide both `.env` and files like `.env.local`.\n\n### Use ngrok instead of Cloudflare\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app --tunnel ngrok\n```\n\n### Local only (no tunnel, useful for testing)\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app --tunnel none --port 8080\n# Open http:\u002F\u002Flocalhost:8080 in your browser\n```\n\n### Require an access code\n\nUse `--passcode` to protect the shared URL with a short code. gh-relay prints the URL and access code separately; the guest must enter the code before the repository browser loads.\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app --passcode\n```\n\nYou can also choose the code yourself. Explicit values must use `--passcode=value`, must be 8-128 characters, and cannot be `true` or `false`. Prefer generated codes when possible so the access code does not land in shell history or process listings.\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app --passcode=review-483920\n```\n\nThe access code helps if a URL is accidentally forwarded. It is still a shared secret; anyone with both the URL and code can open the session until it expires or you stop gh-relay.\n\n### Pre-share secret warnings\n\nBefore a share session starts, gh-relay scans the selected branch's shareable repository tree for sensitive-looking paths such as `.env`, `.env.*`, `*.pem`, `*.key`, `id_rsa`, `id_ed25519`, `secrets\u002F`, `credentials.yml`, `config\u002Fcredentials.yml`, `*.p12`, `*.pfx`, `kubeconfig`, `.npmrc`, `.pypirc`, and `terraform.tfvars`. If `--allow` or `--deny` is set, those filters are applied before the warning scan.\n\nPath scanning is enabled by default:\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app\n```\n\nYou can also scan small text files for common high-risk patterns such as AWS access key IDs, GitHub token prefixes, private key headers, and simple assignments like `password=`, `secret=`, `api_key=`, or `token=`:\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app --scan-content\n```\n\nIf findings are detected, gh-relay prints only the file path, finding type, severity, and rule name. It never prints matched secret values.\n\n```text\n⚠️  Potential sensitive files or secrets detected before sharing:\n\nHIGH    path     .env                         matched rule: dotenv file\nHIGH    path     deploy\u002Fprod.pem              matched rule: private key\u002Fcertificate file\nMEDIUM  content  config\u002Fsettings.yml          matched rule: generic token assignment\n\ngh-relay does not print secret values. Review these files before exposing this repo.\n\nContinue sharing? [y\u002FN]:\n```\n\nIn non-interactive mode, gh-relay prints the warning and continues unless `--fail-on-secrets` is set:\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app --fail-on-secrets\n```\n\nTo skip this preflight scan:\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app --no-scan-secrets\n```\n\nThis is a best-effort warning system, not a full security scanner. It does not scan Git history, all branches, generated artifacts outside the selected tree, large blobs, binary files, encrypted files, or every possible secret format. Review sensitive repositories before exposing them.\n\n### Enable audit logging\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app --audit\n```\n\nLogs guest activity to the terminal and prints a summary on exit:\n\n```\n[audit] Guest viewed: src\u002Fmain.go (from 105.190.183.127)\n[audit] GET \u002Fapi\u002Fcommits (from 105.190.183.127)\n\n  SESSION AUDIT SUMMARY\n  Files viewed  : 5 (3 unique)\n  Total requests: 12\n  Unique IPs    : 1\n  Duration      : 4m32s\n```\n\n### Allow guests to download as ZIP\n\n```bash\ngh-relay share --repo my-org\u002Fprivate-app --allow-download\n```\n\nA \"Download ZIP\" button appears in the guest's browser. The ZIP is streamed directly from GitHub through the proxy — nothing is written to disk. Off by default since a downloaded ZIP gives the guest a permanent copy.\n\n### All flags\n\n| Flag | Default | Description |\n|---|---|---|\n| `--token` | *(optional if `GH_RELAY_TOKEN` is set)* | GitHub PAT with `repo` scope, or set via `GH_RELAY_TOKEN` env var. [Generate one here](https:\u002F\u002Fgithub.com\u002Fsettings\u002Ftokens\u002Fnew?scopes=repo). |\n| `--repo` | *(required)* | Target repository in `owner\u002Frepo` format |\n| `--branch` | `main` | Branch to share |\n| `--port` | `8080` | Local port for the proxy server |\n| `--expire` | unlimited | Auto-close after this duration (`30m`, `1h`, `2h30m`) |\n| `--passcode` | disabled | Require a guest access code; use `--passcode` to generate one or `--passcode=value` to set one |\n| `--tunnel` | `cloudflare` | Tunnel provider: `cloudflare`, `ngrok`, or `none` |\n| `--allow` | empty | Comma-separated repository-relative path patterns to include |\n| `--deny` | empty | Comma-separated repository-relative path patterns to exclude; deny rules win |\n| `--scan-secrets` | `true` | Scan repository paths for sensitive files before sharing |\n| `--no-scan-secrets` | `false` | Disable pre-share sensitive file scanning |\n| `--scan-content` | `false` | Also scan small text blobs for common secret patterns |\n| `--fail-on-secrets` | `false` | Exit non-zero if the pre-share scan finds potential secrets |\n| `--audit` | `false` | Log guest activity and print a session summary on exit |\n| `--allow-download` | `false` | Allow guests to download the repository as a ZIP archive |\n\n---\n\n## Security\n\ngh-relay is designed from the ground up to share as little as possible.\n\n| Property | How it's enforced |\n|---|---|\n| **Token never leaves your machine** | All GitHub API calls are made server-side. The guest only receives a short-lived relay token. |\n| **Read-only by design** | The proxy only registers `GET` handlers. `POST`, `PATCH`, `DELETE` return `405` before any session check. |\n| **Optional access code** | `--passcode` keeps the file browser locked until the guest enters the shared code. Failed unlock attempts are rate-limited per client IP. |\n| **Server-side path filters** | Optional `--allow` and `--deny` rules are applied to tree listings and blob reads. Deny rules take precedence and blob requests must match the allowed path, branch, and SHA. |\n| **Pre-share secret warning** | Before opening the tunnel, gh-relay scans the filtered shareable tree for suspicious paths and can optionally scan small text blobs. Findings are sanitized and never include matched secret values. |\n| **Nothing written to disk** | Files are fetched on demand and streamed directly to the guest. No `git clone`, no temp files. |\n| **Instant teardown** | `Ctrl+C` or `--expire` kills the tunnel, shuts the server, and invalidates all session cookies simultaneously. |\n| **No external dependencies in the browser** | The file browser SPA is fully self-contained. No third-party scripts, no CDN calls from the guest's browser. |\n| **Zero trust** | The guest can only see what you share. They can't navigate to other repos, access your GitHub account, or do anything outside the API calls you allow. |\n| **No dependencies on third-party services** | The core functionality relies only on GitHub and your chosen tunnel provider. No analytics, no databases, no external APIs. |\n\n### GitHub token scopes\n\nFor **fine-grained PATs** (recommended):\n- `Contents: Read-only`\n- `Metadata: Read-only`\n\nFor **classic PATs**:\n- `repo` | for private repositories\n- `public_repo` | for public repositories only\n\n> **Tip:** Create a dedicated PAT for gh-relay sessions with the minimum required scopes and a short expiry matching your longest expected review session.\n>\n> **Quick start:** Generate a classic PAT with `repo` scope at https:\u002F\u002Fgithub.com\u002Fsettings\u002Ftokens\u002Fnew?scopes=repo\n\n---\n\n## Guest experience\n\nThe guest opens the URL in any browser, no GitHub account, no sign-in, no extension required. If `--passcode` is enabled, they enter the access code first. They see:\n\n- A **file tree** with folder expand\u002Fcollapse and a live filter\n- A **code viewer** with line numbers for text files\n- A **branch switcher** to explore other branches\n- A **commit history** panel showing recent commits on the active branch\n\nThey cannot clone, push, download a zip, or navigate outside the repository you shared.\n\n---\n\n## Project layout\n\n```\n├── cmd\n│   ├── root.go\n│   └── share.go \u002F\u002F CLI command definitions and flag parsing\n├── go.mod\n├── internal\n│   ├── filter\n│   │   ├── policy.go \u002F\u002F Server-side path allow\u002Fdeny policy\n│   │   └── policy_test.go\n│   ├── github\n│   │   ├── client.go \u002F\u002F GitHub API client and handlers\n│   │   ├── types.go\n│   │   └── utils.go\n│   ├── logo\n│   │   └── logo.go\n│   ├── server\n│   │   ├── server.go \u002F\u002F HTTP server and handlers\n│   │   ├── spa.go\n│   │   ├── types.go\n│   │   └── utils.go\n│   ├── secretscan\n│   │   ├── scanner.go \u002F\u002F Pre-share path and content secret-risk scanner\n│   │   ├── scanner_test.go\n│   │   └── types.go\n│   ├── session\n│   │   ├── manager.go \n│   │   ├── types.go\n│   │   └── utils.go\n│   ├── tunnel\n│   │   ├── cf.go \u002F\u002F Cloudflare tunnel support\n│   │   ├── ngrok.go \u002F\u002F ngrok tunnel support\n│   │   └── tunnel.go \u002F\u002F Tunnel interface and factory\n│   └── version\n│       └── version.go\n├── LICENSE\n├── main.go\n└── README.md\n```\n\nZero external Go dependencies.\n\n---\n\n## Contributing\n\nContributions are welcome. Please open an issue before starting work on a large change so we can discuss the approach first.\n\n```bash\n# Run tests\ngo test .\u002F...\n\n# Run with race detector\ngo test -race .\u002F...\n\n# Vet\ngo vet .\u002F...\n\n# Build\ngo build -o gh-relay .\n```\n\n---\n\n## Roadmap\n\n- [x] File browsing, code viewing, Cloudflare tunnel\n- [x] Branch switcher, commit history\n- [ ] Markdown rendering for README files\n- [ ] System keychain integration for token storage\n- [x] Optional access code protection for the shared URL\n- [ ] `gh` CLI extension (`gh relay share ...`)\n\n---\n\n## License\n\n[MIT](LICENSE) -  © 2025 soub4i\n\n---\n\n> gh-relay is intended for internal collaboration and peer review. Always ensure that sharing code via a relay complies with your organisation's data-handling policies and Terms of Service\n","gh-relay 是一个用于分享私有 GitHub 仓库的工具，无需添加协作者邀请、付费席位或后续清理。其核心功能是通过一条命令生成一个临时链接，让外部人员能够以只读方式在浏览器中查看代码库。该工具使用 Go 语言编写，支持 Cloudflare 和 ngrok 等隧道服务来提供临时访问路径，并且可以通过设置过期时间来控制访问时长，一旦会话结束，链接立即失效，确保安全无残留权限。适用于需要临时与非团队成员（如承包商或审计员）共享代码但又不想给予长期访问权限的情况。",2,"2026-06-11 04:00:54","CREATED_QUERY"]