Skip to content

test: git-remote coverage (1/4) — plan + backend matrix, real-hook push, hermeticity#1636

Open
Soph wants to merge 5 commits into
mainfrom
soph/git-remote-tests-1-infra
Open

test: git-remote coverage (1/4) — plan + backend matrix, real-hook push, hermeticity#1636
Soph wants to merge 5 commits into
mainfrom
soph/git-remote-tests-1-infra

Conversation

@Soph

@Soph Soph commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator

https://entire.io/gh/entireio/cli/trails/757

Part 1 of a 4-PR stack adding systematic test coverage for git-remote operations across both checkpoint backends. The plan (committed here as docs/testing/git-remote-test-plan.md) came out of a survey of existing e2e/integration coverage, the production remote code paths, and past remote-related regressions.

Stack: this PR → #2/4 (P0 hook & cross-machine) → #3/4 (divergence matrix) → #4/4 (OPF, degraded remotes, shallow clones, e2e).

What's here

  • Test plan — gap analysis + coverage map (groups A–H), including the product decisions it surfaces (Checkpoint reads always target origin while pushes follow the hook remote (non-origin remotes unsupported) #1634, git-refs: push queue is drained by the first successful push — checkpoints never reach a second remote #1635).
  • I-1: integration backend matrixTestEnv.CheckpointStore injects ENTIRE_CHECKPOINTS_PRIMARY into every spawned CLI and git hook process (condensation happens in post-commit), ForEachBackend(t, fn) subtest helper, and backend-aware assertions (CheckpointsPresentLocally/OnRemote, RemoteCheckpointState, LatestCheckpointID) mirroring e2e/testutil/backend.go. The remote-touching suites (remote_operations_test.go, http_remote_test.go, explain fetch-on-miss) now run under both backends.
  • I-2: real-hook push helpersGitPushWithHooks (no --no-verify) + InstallRealPrePushHook run a plain git push through the installed pre-push hook exactly as git does (stdin refspecs); RunPrePush now feeds computed stdin instead of nil. Smoke test proves a plain git push alone lands checkpoints on a bare remote under both backends — the first end-to-end assertion of the real hook. Plus e2e AssertCheckpointsOnRemote.
  • I-4: hermeticity tripwire — integration tests route github.com/gitlab.com HTTPS through a dead loopback proxy (insteadOf rewrites broke trail forge detection, so this blocks at transport level only), with a self-test proving external hosts fail in ~20ms. Regression class: tests doing live github.com fetches / triggering macOS keychain prompts (strategy: stop resolvePushSettings tests from fetching github.com #1463).

Verification

  • mise run fmt && mise run lint clean per commit
  • mise run test:integration green
  • mise run test:e2e:canary green under both E2E_CHECKPOINT_STORE values

🤖 Generated with Claude Code

https://claude.ai/code/session_012yi3hHGAGepwfrfjPETjGq


Note

Low Risk
Test-only and documentation changes; production behavior is unchanged aside from optional hermetic git config when ENTIRE_TEST_GIT_HERMETIC is set in tests.

Overview
Adds docs/testing/git-remote-test-plan.md as the roadmap for remote/checkpoint coverage across git-branch and git-refs, and lands the first infrastructure slice from that plan.

Dual-backend integration matrix: ForEachBackend plus TestEnv.CheckpointStore inject ENTIRE_CHECKPOINTS_PRIMARY into CLI and hook subprocesses; backend-aware helpers (CheckpointsPresentLocally/OnRemote, CheckpointExistsOnRemote, RemoteCheckpointState, LatestCheckpointID) replace hardcoded entire/checkpoints/v1 checks. Remote-focused suites (remote_operations_test, http_remote_test, explain fetch-on-miss) now run under both backends, with comments/skips where behavior still differs (v1-only rebase/treeless tests, a documented git-refs skip for staging-after-stop).

Real pre-push path: GitPushWithHooks / InstallRealPrePushHook exercise a normal git push through the installed hook; RunPrePush feeds realistic stdin refspecs. New TestGitPushWithHooks_SyncsCheckpointsToRemote asserts checkpoints reach the bare remote without explicit RunPrePush. E2E gains AssertCheckpointsOnRemote.

Hermeticity: integration TestMain sets ENTIRE_TEST_GIT_HERMETIC and GIT_TERMINAL_PROMPT=0; testutil appends per-host HTTPS proxy config to the isolation git config so accidental github.com/gitlab.com dials fail fast, with TestHermeticityGuard_ExternalHostFailsFast as a regression guard.

Reviewed by Cursor Bugbot for commit aec192c. Configure here.

Soph and others added 4 commits July 4, 2026 19:05
Gap analysis and test plan for remote/upstream git coverage across both
checkpoint storage backends (git-branch and git-refs), based on the
existing e2e/integration inventory, production remote code paths, and
past remote-related regressions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012yi3hHGAGepwfrfjPETjGq
The integration suite had no git-refs coverage: every remote-touching test
asserted the git-branch v1-branch topology only, while the e2e suite already
ran both backends. This adds the missing axis.

TestEnv gains a CheckpointStore field injected as ENTIRE_CHECKPOINTS_PRIMARY
into every spawned CLI and git hook (cliEnv + gitHookEnv), and propagated to
clones. A ForEachBackend(t, fn) helper runs "git-branch"/"git-refs" subtests,
plus backend-aware assertion helpers (CheckpointsPresentLocally/OnRemote,
CheckpointExistsOnRemote, RemoteCheckpointState, LatestCheckpointID) mirroring
e2e/testutil/backend.go so one test asserts against either topology.

Wires the pre-push and graceful-degradation tests in remote_operations_test.go,
the HTTPS push/token tests in http_remote_test.go, and the explain
fetch-on-miss test under both backends. Tests whose assertions are inherently
v1-branch-shaped (commit counts/subjects, rebase parent counts, checkpoint_remote
routing, treeless v1 clone, v1-ref-hash divergence) stay git-branch-only with an
explicit rationale pointing at their git-refs follow-up in the test plan.

One genuine git-refs divergence surfaced and is flagged, not papered over:
when a session stages its file changes after the stop hook, git-refs
condensation creates no per-checkpoint ref (git-branch still creates the local
v1 checkpoint). Skipped for git-refs with a KNOWN BUG note; a fresh repo and a
stage-before-stop clone both create the ref correctly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012yi3hHGAGepwfrfjPETjGq
Entire-Checkpoint: f96568923ebd
The real git-invoked pre-push hook was never asserted end to end. Integration
RunPrePush spawned the hook with Stdin=nil, and GitPush always passed
--no-verify, so a completely broken hook would go unnoticed; e2e remote tests
masked the same gap by always calling PushCheckpointRefs explicitly.

Integration TestEnv gains:
- InstallRealPrePushHook + GitPushWithHooks: a plain `git push` (no --no-verify)
  that runs the installed hook exactly as git runs it — realistic stdin refspec
  lines and remote name/URL argv, inheriting the checkpoint-store env.
- RunPrePush now feeds realistic stdin (defaultPrePushStdin) instead of nil,
  with RunPrePushWithStdin as an escape hatch for the empty-stdin no-op case.
  GitPush keeps --no-verify for setup plumbing.

A smoke test (seed of A1) proves GitPushWithHooks lands checkpoints on a bare
remote with NO explicit checkpoint push, under both backends via ForEachBackend.

e2e gains AssertCheckpointsOnRemote(t, s, bareDir), asserting the
backend-appropriate refs are present on the bare remote for later use by the
section-3 e2e tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012yi3hHGAGepwfrfjPETjGq
Entire-Checkpoint: 51ee64d92120
Integration/unit tests have historically made live github.com fetches and
triggered macOS keychain prompts when checkpoint-token / checkpoint_remote
resolution was in play (#1463, 53bc37a). This adds a TestMain-level tripwire.

When ENTIRE_TEST_GIT_HERMETIC is set (the integration TestMain sets it, plus
GIT_TERMINAL_PROMPT=0), GitIsolatedEnv's global git config routes HTTPS
transport to github.com/gitlab.com through a dead loopback proxy, so any test
that accidentally dials those hosts fails fast instead of reaching the network
or prompting for credentials.

The config lives in the file GIT_CONFIG_GLOBAL points at because GitIsolatedEnv
strips inherited GIT_CONFIG_* env, so the GIT_CONFIG_COUNT-injected insteadOf
approach would be filtered out for every spawned binary. A dead per-host proxy
is used rather than url.insteadOf: insteadOf rewrites the effective URL git
reports on read, which broke origin-URL forge detection (trail_resume). The
proxy blocks transport only and is scoped per host, so the in-process 127.0.0.1
HTTPS test server and the checkpoint-token GIT_CONFIG_* injection are unaffected.

A self-test proves the tripwire fires: `git ls-remote https://github.com/...`
fails fast (~20ms) without network or prompt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012yi3hHGAGepwfrfjPETjGq
Entire-Checkpoint: b3d8c9729839

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the first slice of systematic git-remote test coverage across both checkpoint backends by introducing an integration backend matrix, exercising the real pre-push hook via plain git push, and enforcing hermetic git transport in integration tests to prevent accidental external network access.

Changes:

  • Introduces a dual-backend integration test matrix (git-branch vs git-refs) with backend-aware assertion helpers.
  • Adds “real hook” push helpers/tests so a plain git push exercises the installed pre-push hook end-to-end.
  • Adds a hermeticity tripwire for integration tests by routing HTTPS transport for external hosts through a dead loopback proxy, plus a guard test.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
e2e/testutil/repo.go Adds an E2E assertion helper to verify checkpoints landed on a bare remote without an explicit checkpoint push.
docs/testing/git-remote-test-plan.md New test plan documenting coverage gaps, priorities, and sequencing for git-remote behaviors across both backends.
cmd/entire/cli/testutil/testutil.go Adds opt-in hermetic git config injection (dead loopback proxy) to prevent accidental external HTTPS dials in tests.
cmd/entire/cli/integration_test/testenv.go Adds backend selection env injection, real-hook push helpers, and realistic stdin for pre-push direct invocation.
cmd/entire/cli/integration_test/setup_test.go Sets GIT_TERMINAL_PROMPT=0 and enables the hermetic git tripwire for the whole integration suite.
cmd/entire/cli/integration_test/remote_operations_test.go Runs remote operation tests under both backends and switches assertions to backend-aware helpers.
cmd/entire/cli/integration_test/real_hook_push_test.go New integration test proving plain git push via the real installed pre-push hook syncs checkpoints to the remote.
cmd/entire/cli/integration_test/http_remote_test.go Runs selected HTTPS remote tests under both backends and adjusts assertions accordingly.
cmd/entire/cli/integration_test/hermeticity_test.go New guard test ensuring external-host git HTTPS attempts fail fast under the hermeticity tripwire.
cmd/entire/cli/integration_test/explain_test.go Runs fetch-on-miss explain coverage under both backends (v1 fetch vs per-checkpoint RefFetcher).
cmd/entire/cli/integration_test/backend.go Adds backend constants, ForEachBackend, and backend-aware local/remote checkpoint assertion helpers.

Comment thread e2e/testutil/repo.go
Comment on lines +210 to +216
if UsingGitRefs() {
out := gitOutputSafe(bareDir, "for-each-ref", "--format=%(refname)", checkpointRefPrefix)
if strings.TrimSpace(out) == "" {
t.Errorf("expected at least one %s* ref on remote %s, found none", checkpointRefPrefix, bareDir)
}
return
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c6636c4 — the git-refs arm now uses GitOutputErr and reports the git error distinctly from "found none".

Comment on lines +112 to +118
cmd := exec.CommandContext(env.T.Context(), "git", "for-each-ref", "--format=%(refname) %(objectname)", prefix)
cmd.Dir = bareDir
cmd.Env = testutil.GitIsolatedEnv()
out, err := cmd.Output()
if err != nil {
return ""
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c6636c4 — RemoteCheckpointState now fails the test on git error instead of returning "" (which could have made the idempotence comparison pass vacuously).

Comment on lines +26 to +28
// ls-remote against a public-looking github URL must be refused immediately
// by the insteadOf redirect to 127.0.0.1:1, not hang on DNS/network or block
// on a credential prompt.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c6636c4 — comment now describes the actual mechanism (per-host http..proxy entries from testutil.hermeticGitConfig).

- AssertCheckpointsOnRemote (git-refs arm): surface git errors instead of
  reporting a misleading "found none" via gitOutputSafe
- RemoteCheckpointState: fail the test on git error instead of returning
  "" (two broken invocations comparing equal would pass vacuously)
- hermeticity self-test comment: the guard is per-host http proxy entries,
  not an insteadOf redirect

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012yi3hHGAGepwfrfjPETjGq
Entire-Checkpoint: d4f06e259d79
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants