mirror of
https://github.com/hanzoai/forge.git
synced 2026-10-30 15:00:39 +00:00
The binary was gitea and admin work was `gitea admin ...`. Nothing in this fork
is Gitea, so the daemon is now `gitd`: EXECUTABLE, /app/gitd/gitd, the
/usr/local/bin/gitd wrapper, the s6 service, the CLI's own name, and the delegate
each repository's git hooks execute.
The delegate is the whole risk. Every repo on disk carries
hooks/<hook>.d/<binary> containing setting.AppPath verbatim, and the outer
hooks/<hook> runs EVERY executable in <hook>.d/ and rejects the push if any exits
non-zero. So this rename is a migration, not a rename, and it is safe only
because both halves move together:
* AppPath moves (/usr/local/bin/gitea -> /usr/local/bin/gitd), which is what
makes routers.syncAppConfForGit re-run SyncRepositoryHooks over every
repository on the first boot after the upgrade — and it runs inside
InitWebInstalled, i.e. before the listener opens, so no push can ever meet a
stale hook. `gitd admin regenerate hooks` remains the manual lever.
* createDelegateHooks now deletes legacyDelegateHookNames. Without it each repo
would keep BOTH hooks/<hook>.d/gitea and .../gitd, the stale one would exit
127, and every push would fail forever. It deletes LAST: dying midway leaves
two delegates and a loud failure, where deleting first would leave none and
silently bypass every server-side check.
* checkDelegateHooks reports a surviving legacy delegate before any other
check, so `doctor --fix` heals a repo the sync missed.
Anything OUTSIDE this repo that invokes the binary by absolute path must move in
the same change that bumps the image tag — today that is the oauth-sync init
container in hanzoai/universe, which runs /app/gitea/gitea.
Deleted rather than renamed: snap/ (published a snap literally named gitea),
contrib/service/* and contrib/fhs-compliant-script (service units for a gitea
binary we no longer build) and contrib/upgrade.sh (fetched upstream Gitea from
dl.gitea.com and installed it OVER ours). We ship one artifact, the container.
Deliberately untouched: /data/gitea, gitea.db, /var/lib/gitea, /etc/gitea. Those
are the durable volume layout of a live server, and moving them is a data
migration with nothing to do with the binary's name.
43 lines
1.6 KiB
Go
43 lines
1.6 KiB
Go
// Copyright 2026 The Hanzo Git Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package gitrepo
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// The gitea->gitd binary rename moved the delegate file every repository's
|
|
// "<hook>" script executes. The outer script runs EVERY executable in
|
|
// "<hook>.d/" and rejects the push on any non-zero exit, so a delegate left over
|
|
// from the old name would invoke a binary path that no longer exists and break
|
|
// every push. Regeneration must delete it, and the checker must see it.
|
|
func TestCreateDelegateHooksRemovesLegacyDelegate(t *testing.T) {
|
|
hookDir := filepath.Join(t.TempDir(), "hooks")
|
|
require.NoError(t, os.MkdirAll(filepath.Join(hookDir, "pre-receive.d"), os.ModePerm))
|
|
|
|
legacy := filepath.Join(hookDir, "pre-receive.d", "gitea")
|
|
require.NoError(t, os.WriteFile(legacy, []byte("#!/usr/bin/env bash\n/usr/local/bin/gitea hook pre-receive\n"), 0o777))
|
|
|
|
results, err := checkDelegateHooks(hookDir)
|
|
require.NoError(t, err)
|
|
assert.Contains(t, results, "legacy hook file "+legacy+" still exists and would reject every push")
|
|
|
|
require.NoError(t, createDelegateHooks(hookDir))
|
|
|
|
assert.NoFileExists(t, legacy)
|
|
assert.FileExists(t, filepath.Join(hookDir, "pre-receive.d", "gitd"))
|
|
|
|
// A repository that has been regenerated is clean: no leftovers, nothing
|
|
// out of date. This is what the live server reaches on its first boot after
|
|
// the rename, via routers.syncAppConfForGit -> SyncRepositoryHooks.
|
|
results, err = checkDelegateHooks(hookDir)
|
|
require.NoError(t, err)
|
|
assert.Empty(t, results)
|
|
}
|