Require user-provisioned release credentials

Hop-State: A_06FN6KM758JV6S44F6CA6W0
Hop-Proposal: R_06FN6KJWAY5XWVMCVQHCXKR
Hop-Task: T_06FN6GZKFMRV2HP5N7XMNSR
Hop-Attempt: AT_06FN6GZKFP22ZCFRXGB7V00
This commit is contained in:
Hop
2026-07-11 15:31:23 -07:00
parent 7139b9e1a7
commit 853acec229
6 changed files with 47 additions and 5 deletions
+22
View File
@@ -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")
}
}
+1 -1
View File
@@ -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"
+5
View File
@@ -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
+9
View File
@@ -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 |
+7 -3
View File
@@ -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.
+3 -1
View File
@@ -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