tenseleyflow/shithub / 7856517

Browse files

storage: inject safe.directory=* in RepairSharedPerms git invocation

Operator runs 'shithubd storage repair-shared-perms' as root over
SSH; the bare repos are owned by shithub:shithub. git 2.35+'s
dubious-ownership protection early-exits with the misleading
'fatal: not in a git directory' before it reads core.sharedRepository.

Same env trick the SSH dispatcher uses (cmd/shithubd/ssh_dispatch
injects GIT_CONFIG_COUNT=1 + safe.directory=* for the cross-user
git-receive-pack/upload-pack invocations). The path is verified
contained-in-root above the env injection, so '*' here is safe by
construction — every iteration of this loop targets a path we
already validated.
Authored by espadonne
Committed by mfwolffe
SHA
7856517f8ecd8f70299af3476c49c753c662e85a
Parents
9f6ec52
Tree
d4d82e1

1 changed file

StatusFile+-
M internal/infra/storage/reposfs.go 12 0
internal/infra/storage/reposfs.gomodified
@@ -247,6 +247,12 @@ func (r *RepoFS) CloneBareShared(ctx context.Context, src, dst string) error {
247247
 // that all repos are owned by the `shithub` group already (the
248248
 // shithub user creates them). If a repo's group is wrong, that's a
249249
 // separate provisioning bug; this method's job is only the bits.
250
+//
251
+// Runs git with safe.directory=* injected via env so the operator
252
+// (typically root over SSH) can operate on repos owned by the
253
+// `shithub` user. The same trick is used by the SSH dispatcher.
254
+// Without it, git 2.35+ emits "fatal: not in a git directory" as
255
+// part of the dubious-ownership early exit.
250256
 func (r *RepoFS) RepairSharedPerms(ctx context.Context, path string) error {
251257
 	if err := r.containedInRoot(path); err != nil {
252258
 		return err
@@ -256,6 +262,12 @@ func (r *RepoFS) RepairSharedPerms(ctx context.Context, path string) error {
256262
 	}
257263
 	// Persist the contract in config.
258264
 	cfg := exec.CommandContext(ctx, "git", "-C", path, "config", "core.sharedRepository", "group") //nolint:gosec
265
+	cfg.Env = append(
266
+		os.Environ(),
267
+		"GIT_CONFIG_COUNT=1",
268
+		"GIT_CONFIG_KEY_0=safe.directory",
269
+		"GIT_CONFIG_VALUE_0=*",
270
+	)
259271
 	if out, err := cfg.CombinedOutput(); err != nil {
260272
 		return fmt.Errorf("storage: repofs: git config sharedRepository: %w (output: %s)", err, strings.TrimSpace(string(out)))
261273
 	}