Skip to content

feat(auth): git push/fetch work without a running helper (Phase 1b)#188

Merged
LiranCohen merged 3 commits into
fix/install-wrapper-symlink-clobberfrom
feat/server-alive
Jun 24, 2026
Merged

feat(auth): git push/fetch work without a running helper (Phase 1b)#188
LiranCohen merged 3 commits into
fix/install-wrapper-symlink-clobberfrom
feat/server-alive

Conversation

@LiranCohen

Copy link
Copy Markdown
Contributor

Phase 1b of the auth/session/server redesign (#186). Stacked on #187 (feat/auth-session-core) — review/merge that first.

What & why

This fixes the "keep the server alive" half of the complaint. Today, when no local helper (daemon) is running, git push/fetch can fail or hang: the credential helper's fallback and the daemon auto-start resolve the vault password via getVaultPassword(), which only knew GITD_PASSWORD → public-reader → a /dev/tty prompt. During a push, git owns stdin, so the prompt often can't run (and never could in CI), so a dead or never-started helper blocked the push.

Now getVaultPassword() also consults the durable secret store from Phase 1 (OS keychain / encrypted file), which is populated on the first unlock. So after gitd auth login, git push/fetch succeed without a prompt even when no helper is running — the credential helper signs a fresh DID push token directly. The helper becomes a performance optimization, not a hard dependency on the critical path.

Changes

  • src/git-remote/tty-prompt.tsgetVaultPassword() is now async and resolves: GITD_PASSWORD → public-reader secret → durable secret store (per profile)/dev/tty prompt → null.
  • src/git-remote/credential-main.tsawait the resolver in the no-daemon fallback (+ doc).
  • src/git-remote/resolve.tsawait the resolver in the daemon auto-start path.
  • src/cli/commands/serve-lifecycle.tsawait the resolver in gitd helper start.
  • src/daemon/lockfile.ts — write lockfiles atomically (temp file + rename) so a crash mid-write can't leave a corrupt lockfile.

Behavior / compatibility

  • The daemon fast-path (POST /auth/token, no password) is unchanged and still preferred when a helper is running.
  • GITD_PASSWORD still wins for CI and is never persisted; the public-reader (no-identity) path is unchanged.
  • No git-server / delegation changes here — wallet-delegated push is a later phase.

Verification

  • bun run build — clean
  • bun run lint — clean (--max-warnings 0)
  • bun test .spec.ts1803 pass, 8 skip, 0 fail (updated tests/tty-prompt.spec.ts covers the new durable-store resolution + GITD_PASSWORD precedence; the async signature change is type-checked across all call sites)

🤖 Generated with Claude Code

LiranCohen and others added 3 commits June 24, 2026 02:31
…mpts

Resolve the vault password through one path (explicit -> GITD_PASSWORD ->
public-reader -> durable secret store -> prompt) and persist a freshly entered
secret per profile in a durable store: the OS keychain (macOS security, Linux
secret-tool) when available, otherwise a machine-keyed AES-256-GCM encrypted
file under ~/.enbox/secrets/. After the first unlock, commands restore the
session without re-prompting for the vault password.

GITD_SECRET_BACKEND=keychain|file|none pins or disables the backend. A cached
secret that is later rejected is cleared automatically to avoid lock-out;
gitd auth logout / reset drop the stored secret.

Part of #186 (Phase 1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
getVaultPassword() now consults the durable secret store (OS keychain /
encrypted file) between the public-reader secret and the /dev/tty prompt, so the
credential helper's direct-signing fallback and the daemon auto-start are
non-interactive after the first unlock. git push / git fetch succeed even when
no local helper is running, and a dead or never-started helper no longer blocks
pushes.

Lockfiles are written atomically (temp + rename) to avoid a corrupt lockfile on
a crash mid-write.

Part of #186 (Phase 1b).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Base automatically changed from feat/auth-session-core to fix/install-wrapper-symlink-clobber June 24, 2026 02:56
@LiranCohen
LiranCohen merged commit a83ded2 into fix/install-wrapper-symlink-clobber Jun 24, 2026
@LiranCohen
LiranCohen deleted the feat/server-alive branch June 24, 2026 02:56
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