Skip to content

fix(relay): auto-create git_repo_path so kind:30617 init can't silently fail#545

Merged
tlongwell-block merged 1 commit into
mainfrom
dawn/git-repo-root-autocreate
May 12, 2026
Merged

fix(relay): auto-create git_repo_path so kind:30617 init can't silently fail#545
tlongwell-block merged 1 commit into
mainfrom
dawn/git-repo-root-autocreate

Conversation

@tlongwell-block
Copy link
Copy Markdown
Collaborator

Problem

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, two things happen and neither is obvious:

  1. Transport — every clone/push gets HTTP 500 git service misconfigured (crates/sprout-relay/src/api/git/transport.rs:237).
  2. Side effecthandle_git_repo_announcement fails at canonicalize_root(). The ingest pipeline only logs side-effect failures at warn! 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 can get-repo it 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 push immediately hit git service misconfigured.

This currently requires operators to mkdir the 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.rscreate_dir_all(git_repo_path) during config load. Fails loudly with ConfigError::InvalidValue if 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 — defensive create_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 cryptic failed to canonicalize repo root you'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/null returns ConfigError::InvalidValue mentioning SPROUT_GIT_REPO_PATH.
running 7 tests
test config::tests::git_repo_path_is_created_if_missing ... ok
test config::tests::git_repo_path_unwritable_returns_error ... ok
... (146 lib tests pass, 0 fail)

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 bumped created_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.

…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.
@tlongwell-block tlongwell-block force-pushed the dawn/git-repo-root-autocreate branch from 2bcb110 to 9dead35 Compare May 12, 2026 20:32
@tlongwell-block tlongwell-block merged commit 08e00a6 into main May 12, 2026
15 checks passed
@tlongwell-block tlongwell-block deleted the dawn/git-repo-root-autocreate branch May 12, 2026 20:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant