|
| 1 | +// SPDX-License-Identifier: PMPL-1.0-or-later |
| 2 | +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk> |
| 3 | += Hyperpolymath Git Remote URL Policy (SSH-only) |
| 4 | +Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk> |
| 5 | +:revnumber: 1.0.0 |
| 6 | +:revdate: 2026-05-17 |
| 7 | +:toc: |
| 8 | +:toc-placement: preamble |
| 9 | + |
| 10 | +Canonical git remote-URL policy for all `hyperpolymath/*` repositories |
| 11 | +and every local clone. All maintainers and AI agents must follow this |
| 12 | +document. It resolves |
| 13 | +link:https://github.com/hyperpolymath/standards/issues/69[standards#69] |
| 14 | +(parent link:https://github.com/hyperpolymath/standards/issues/66[#66]). |
| 15 | + |
| 16 | +== Problem |
| 17 | + |
| 18 | +A clone of `claude-integrations` (a second checkout under `repos/ci`) |
| 19 | +had an `x-access-token:gho_…` token embedded directly in its `origin` |
| 20 | +URL. Token-in-URL remotes leak credentials into: |
| 21 | + |
| 22 | +* `.git/config` (plaintext, world-readable in many setups) |
| 23 | +* shell history and process listings on every `git` invocation |
| 24 | +* CI logs and `git remote -v` output pasted into issues |
| 25 | + |
| 26 | +== Policy |
| 27 | + |
| 28 | +[discrete] |
| 29 | +=== 1. SSH-only remotes |
| 30 | + |
| 31 | +All remotes for `hyperpolymath/*` repositories MUST use the SSH form: |
| 32 | + |
| 33 | +[source] |
| 34 | +---- |
| 35 | +git@github.com:hyperpolymath/<repo>.git |
| 36 | +---- |
| 37 | + |
| 38 | +The following are PROHIBITED for tracked/long-lived clones: |
| 39 | + |
| 40 | +* `https://x-access-token:<token>@github.com/…` |
| 41 | +* `https://<user>:<PAT>@github.com/…` |
| 42 | +* any URL embedding a `gho_`, `ghp_`, `ghs_`, or `github_pat_` secret |
| 43 | + |
| 44 | +HTTPS without an embedded credential (auth delegated to the `gh` |
| 45 | +credential helper / `git-credential`) is acceptable for ephemeral, |
| 46 | +throw-away CI checkouts only. |
| 47 | + |
| 48 | +[discrete] |
| 49 | +=== 2. Token handling |
| 50 | + |
| 51 | +Tokens are supplied exclusively via the `gh` credential helper or an |
| 52 | +environment variable consumed by `git-credential`. They are never |
| 53 | +written into a remote URL, a tracked file, or a commit. |
| 54 | + |
| 55 | +[discrete] |
| 56 | +=== 3. Audit |
| 57 | + |
| 58 | +Run estate-wide before any sync: |
| 59 | + |
| 60 | +[source,bash] |
| 61 | +---- |
| 62 | +for d in ~/dev/*/; do |
| 63 | + [ -d "$d/.git" ] || continue |
| 64 | + u=$(git -C "$d" remote get-url origin 2>/dev/null) |
| 65 | + case "$u" in |
| 66 | + *x-access-token*|*ghp_*|*gho_*|*ghs_*|*github_pat_*|https://*:*@*) |
| 67 | + echo "TOKEN-IN-URL: $d" ;; |
| 68 | + esac |
| 69 | +done |
| 70 | +---- |
| 71 | + |
| 72 | +Audit of `2026-05-17`: 20 local `~/dev` clones scanned, *0* |
| 73 | +token-in-URL remotes (the exposed `repos/ci` clone was scrubbed to |
| 74 | +SSH in the originating session). |
| 75 | + |
| 76 | +[discrete] |
| 77 | +=== 4. Remediation of an exposed token |
| 78 | + |
| 79 | +A token that has appeared in a URL is considered compromised and MUST |
| 80 | +be rotated at |
| 81 | +link:https://github.com/settings/tokens[github.com/settings/tokens] |
| 82 | +(or the issuing GitHub App) regardless of whether the URL was pushed. |
| 83 | +Rotation is a manual browser action owned by the maintainer and is the |
| 84 | +one remaining open item under standards#69. |
| 85 | + |
| 86 | +== Enforcement |
| 87 | + |
| 88 | +`gitbot` rejects any push whose `.git/config` (when present in tree) or |
| 89 | +remediation script reintroduces a token-in-URL remote. New clones in |
| 90 | +provisioning scripts use the SSH form by default. |
0 commit comments