diff --git a/internal/hop/docs_test.go b/internal/hop/docs_test.go index 1efb256..217e99b 100644 --- a/internal/hop/docs_test.go +++ b/internal/hop/docs_test.go @@ -83,3 +83,25 @@ func TestDistributionDoesNotRequireGiteaActions(t *testing.T) { t.Fatal("release checklist still depends on a Gitea Actions workflow") } } + +func TestReleaseWorkflowRequiresPreProvisionedCredential(t *testing.T) { + root := filepath.Clean(filepath.Join("..", "..")) + script, err := os.ReadFile(filepath.Join(root, "scripts", "release-local.sh")) + if err != nil { + t.Fatal(err) + } + if !strings.Contains(string(script), "pre-existing scoped GITEA_TOKEN") { + t.Fatal("release script does not require a pre-provisioned credential") + } + if strings.Contains(string(script), "/tokens") { + t.Fatal("release script must not manage provider tokens") + } + checklist, err := os.ReadFile(filepath.Join(root, "wiki", "Release-Checklist.md")) + if err != nil { + t.Fatal(err) + } + if !strings.Contains(string(checklist), "must never create, rotate, list,") || + !strings.Contains(string(checklist), "or revoke account tokens") { + t.Fatal("release checklist does not forbid agent token management") + } +} diff --git a/scripts/release-local.sh b/scripts/release-local.sh index baf5b87..20bb7d6 100755 --- a/scripts/release-local.sh +++ b/scripts/release-local.sh @@ -33,7 +33,7 @@ done if [ "$mode" = --publish ]; then [ -f LICENSE ] || fail "LICENSE is required before publishing" - [ -n "${GITEA_TOKEN:-}" ] || fail "set a scoped GITEA_TOKEN in the local environment" + [ -n "${GITEA_TOKEN:-}" ] || fail "provide a pre-existing scoped GITEA_TOKEN through the local secret store" [ -z "$(git status --porcelain)" ] || fail "the Git worktree must be clean" tag=$(git describe --tags --exact-match HEAD 2>/dev/null) || fail "HEAD must have an exact release tag" diff --git a/skills/hop/SKILL.md b/skills/hop/SKILL.md index 4d6950e..58899b7 100644 --- a/skills/hop/SKILL.md +++ b/skills/hop/SKILL.md @@ -73,6 +73,11 @@ variable or secret-manager name instead. - Do not run `git commit`, `git checkout`, `git switch`, `git branch`, `git rebase`, `git reset`, `git stash`, `git worktree`, or `git push`. - Do not stage files. Hop captures every nonignored workspace change. +- Never create, rotate, enumerate, revoke, or paste account access tokens + through a provider website or API. For release or publishing work, use only a + credential the user has already provisioned in an OS secret store or supplied + through the runtime's secret mechanism. If it is missing, stop and ask the + user to provision it; do not call a token-management endpoint. - Give a subagent project-changing work only after creating a distinct Hop prompt/attempt for that delegation. - Never discard either side of concurrent work. Let Hop perform its three-way diff --git a/skills/hop/references/protocol.md b/skills/hop/references/protocol.md index b227566..c1c0f09 100644 --- a/skills/hop/references/protocol.md +++ b/skills/hop/references/protocol.md @@ -158,6 +158,15 @@ sanitizer replaces detected credential values before any durable write and returns only typed redaction counts. Do not place the value in any later command, summary, output, or source file. +## Account credential boundary + +Hop never creates, rotates, lists, or revokes provider access tokens. Agents +must not use account token-management APIs or settings pages as a shortcut for +publishing work. A release or publishing task may use only a pre-existing +credential the user deliberately provisioned through an OS secret store or the +runtime's secret mechanism. When that credential is absent or invalid, stop and +ask the user to replace it; never mint a task-named token. + ## Exit codes | Code | Meaning | diff --git a/wiki/Release-Checklist.md b/wiki/Release-Checklist.md index 78126d7..c059873 100644 --- a/wiki/Release-Checklist.md +++ b/wiki/Release-Checklist.md @@ -12,8 +12,11 @@ The canonical repository is `githop.xyz/GnosysLabs/Hop`. - Configure `origin` as `https://githop.xyz/GnosysLabs/Hop.git`. - Keep Gitea Actions disabled when the instance does not have dedicated runner capacity; Hop's release process does not depend on it. -- Create a narrowly scoped maintainer access token that can write releases. - Export it as `GITEA_TOKEN` only for the local publish command, then unset it. +- Provision a narrowly scoped maintainer access token outside the agent session + and store it in the operating system's secret store. Agents and release + scripts may use that existing credential, but must never create, rotate, list, + or revoke account tokens through Gitea's website or API. Export it as + `GITEA_TOKEN` only for the local publish command, then unset it. - When upgrading GoReleaser, update its pinned version and four archive checksums in `scripts/release-local.sh` from the official checksum file. - Permit release attachment MIME types for `.tar.gz`, `.zip`, and `.txt` in @@ -49,7 +52,8 @@ default skill destinations while preserving unrelated user files. injected into the binaries automatically. 2. Run `scripts/release-local.sh --snapshot` and inspect the artifacts. 3. Create a signed semantic-version tag such as `v0.1.0-alpha.1` and push it. -4. Export a locally stored, scoped token: `export GITEA_TOKEN=...`. +4. Read a pre-provisioned, locally stored scoped token into `GITEA_TOKEN`. + Do not generate a task-specific token from an agent session. 5. Run `scripts/release-local.sh --publish`. It reruns race tests, vet, installer checks, builds six platform archives, generates `checksums.txt`, and uploads a draft without executing build work on the Gitea server. diff --git a/wiki/Security-and-Privacy.md b/wiki/Security-and-Privacy.md index ac26378..9c7baab 100644 --- a/wiki/Security-and-Privacy.md +++ b/wiki/Security-and-Privacy.md @@ -38,7 +38,9 @@ public key independently. Checksum signing is listed as a launch gate in the Release builds execute on a maintainer machine, not on the Gitea server. Use a trusted, patched machine; keep the release token out of shell history and source files; scope it to the Hop repository; export it only for the publish command; -and unset it immediately afterward. Releases upload as drafts for review. +and unset it immediately afterward. Releases upload as drafts for review. The +token must be provisioned by the user outside the agent session: Hop and its +agents never create, rotate, list, or revoke provider account tokens. ## Filesystem safety