fix(relay): auto-create git_repo_path so kind:30617 init can't silently fail#545
Merged
Merged
Conversation
…ly fail
The git smart-HTTP transport and the kind:30617 side-effect handler both
canonicalize `config.git_repo_path` before any disk work. If that directory
doesn't exist on the relay host:
- The transport returns HTTP 500 'git service misconfigured' (transport.rs:237)
to every clone/push.
- The side-effect handler that initializes the bare repo from a repo
announcement fails at canonicalize, and the ingest pipeline only logs
side-effect failures at warn! level (ingest.rs:1530) — so the announcement
event is stored but no repo is ever created on disk. The relay looks like
it accepted the repo creation, but pushes 500 forever.
This previously required operators to mkdir the directory out of band. Since
the relay already owns the data layout below that root (`{owner}/{repo}.git`,
`.names/`), it should self-provision the root the same way.
Changes:
- `config.rs`: `create_dir_all(git_repo_path)` during config load. Fails
loudly with ConfigError::InvalidValue if the path can't be created (e.g.
permissions, path-under-file), instead of letting the relay come up healthy
with a broken git service.
- `side_effects.rs::handle_git_repo_announcement`: defensive
`create_dir_all(git_repo_root)` before canonicalize, in case the directory
is removed at runtime or the deployment skipped config bootstrap somehow.
Returns a clear error rather than the cryptic 'failed to canonicalize repo
root' from a missing dir.
Tests:
- `git_repo_path_is_created_if_missing`: config load against a non-existent
nested path succeeds and creates the directory.
- `git_repo_path_unwritable_returns_error` (unix): config load against a
path under `/dev/null` returns ConfigError::InvalidValue.
Post-deploy note: existing kind:30617 announcements published against a
broken-root relay won't auto-heal — their side effect already ran (and was
swallowed). Owners need to re-publish the announcement to trigger init.
2bcb110 to
9dead35
Compare
This was referenced May 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The git smart-HTTP transport and the kind:30617 side-effect handler both canonicalize
config.git_repo_pathbefore any disk work. If that directory doesn't exist on the relay host, two things happen and neither is obvious:git service misconfigured(crates/sprout-relay/src/api/git/transport.rs:237).handle_git_repo_announcementfails atcanonicalize_root(). The ingest pipeline only logs side-effect failures atwarn!level (ingest.rs:1530), so the kind:30617 event is stored but the bare repo is never created on disk. From the client's perspective, the relay accepted the announcement (you canget-repoit back), but every subsequent push 500s.Reproduced on stage: published a valid kind:30617 from the CLI, got a successful event ID back, then
git pushimmediately hitgit service misconfigured.This currently requires operators to
mkdirthe directory out of band. Since the relay already owns the data layout below that root ({owner_hex}/{repo}.git/,.names/...), it should self-provision the root the same way it does for other relay-owned state.Fix
config.rs—create_dir_all(git_repo_path)during config load. Fails loudly withConfigError::InvalidValueif the path can't be created (permissions, path-under-a-file, etc.), instead of letting the relay come up healthy with a silently broken git service.side_effects.rs::handle_git_repo_announcement— defensivecreate_dir_all(git_repo_root)before canonicalize, in case the directory is removed at runtime or a future deployment path bypasses config bootstrap. Returns a clear error rather than the crypticfailed to canonicalize repo rootyou'd otherwise see in logs.Tests
git_repo_path_is_created_if_missing— config load against a non-existent nested path succeeds and creates the directory.git_repo_path_unwritable_returns_error(unix-gated) — config load against a path under/dev/nullreturnsConfigError::InvalidValuementioningSPROUT_GIT_REPO_PATH.Post-deploy note
Existing kind:30617 announcements published against a broken-root relay won't auto-heal — their side effect already ran (and was swallowed by
warn!). Owners need to re-publish the announcement (a fresh event with bumpedcreated_at) to trigger the init path. New announcements after deploy are fine.Scope
Relay-only change. No API/wire/format changes. No client changes needed.