Gate migrated-ref push on the checkpoint policy · Entire
Gate migrated-ref push on the checkpoint policy
36563bc→main· pfleidi·1w ago·2 files·+86 added/-1 removed
PushMigratedCheckpointRefs flushed the queue without the policy check both pre-push paths enforce, so a policy that blocks checkpoint pushes (diverged or requiring a newer CLI) could be bypassed via the doctor's opt-in push. Apply the same sync-and-gate, returning an error with the refs left queued.
Cover the push entry point: success returns the pushed count and clears the queue; a blocked policy and a failed push both leave refs queued.
Sessions
0c43e61ea113View transcript
Changes
2
cmd/entire/cli/strategy
Mmanual_commit_push.go+6/-1
Mrefs_push_test.go+80
// checkpoint remote, surfacing errors (unlike the fail-soft pre-push path). It is
// the opt-in "push now" invoked by the checkpoint migration command; the caller
// owns the repo. Returns the number of refs pushed — a no-op (0, nil) when
// pushing is disabled or the queue is empty.
// pushing is disabled or the queue is empty. Like the pre-push paths, a
// checkpoint policy that blocks pushing errors with the refs left queued.
func PushMigratedCheckpointRefs(ctx context.Context, repo *git.Repository, remote string) (int, error) {
ps := resolvePushSettings(ctx, remote)
if ps.pushDisabled {
return 0, nil
}
syncCheckpointPolicyForPrePush(ctx, repo, ps)
if !checkpointPolicyAllowsGitHook(ctx, repo) {
return 0, errors.New("checkpoint policy does not allow pushing checkpoint refs; refs stay queued")
}
return flushCheckpointRefsQueue(ctx, repo, ps.pushTarget())
}
import (
"context"
"os/exec"
"path/filepath"
"strings"
"testing"
"github.com/entireio/cli/cmd/entire/cli/checkpoint"
"github.com/entireio/cli/cmd/entire/cli/checkpoint/id"
"github.com/entireio/cli/cmd/entire/cli/paths"
"github.com/entireio/cli/cmd/entire/cli/testutil"
)
// enqueueRefs seeds the repo's push queue with the given refs.
func enqueueRefs(t *testing.T, repo *git.Repository, refs []plumbing.ReferenceName) *checkpoint.PushQueue {
t.Helper()
queue, err := checkpoint.PushQueueForRepo(context.Background(), repo)
require.NoError(t, err)
for _, ref := range refs {
require.NoError(t, queue.Enqueue(ref))
}
return queue
}
func TestPushMigratedCheckpointRefs(t *testing.T) {
workDir, bareDir, refs := setupRepoWithCheckpointRefs(t)
t.Chdir(workDir)
paths.ClearWorktreeRootCache()
repo, err := git.PlainOpen(workDir)
require.NoError(t, err)
queue := enqueueRefs(t, repo, refs)
pushed, err := PushMigratedCheckpointRefs(context.Background(), repo, bareDir)
require.NoError(t, err)
assert.Equal(t, len(refs), pushed)
for _, ref := range refs {
assert.NotEmpty(t, remoteRefHash(t, bareDir, ref), "ref should be on the remote")
}
remaining, err := queue.Drain()
require.NoError(t, err)
assert.Empty(t, remaining, "pushed refs are removed from the queue")
}
func TestPushMigratedCheckpointRefs_PolicyBlocked(t *testing.T) {
workDir, bareDir, refs := setupRepoWithCheckpointRefs(t)
t.Chdir(workDir)
paths.ClearWorktreeRootCache()
repo, err := git.PlainOpen(workDir)
require.NoError(t, err)
writeUnsupportedCheckpointPolicy(t, repo)
queue := enqueueRefs(t, repo, refs)
pushed, err := PushMigratedCheckpointRefs(context.Background(), repo, bareDir)
require.ErrorContains(t, err, "checkpoint policy")
assert.Equal(t, 0, pushed)
remaining, err := queue.Drain()
require.NoError(t, err)
assert.ElementsMatch(t, refs, remaining, "blocked push leaves refs queued")
lsCmd := exec.CommandContext(context.Background(), "git", "ls-remote", bareDir)
lsCmd.Env = testutil.GitIsolatedEnv()
out, err := lsCmd.CombinedOutput()
require.NoError(t, err, "ls-remote failed: %s", out)
for _, ref := range refs {
assert.NotContains(t, string(out), ref.String(), "blocked push must not reach the remote")
}
}
func TestPushMigratedCheckpointRefs_FailureLeavesRefsQueued(t *testing.T) {
workDir, _, refs := setupRepoWithCheckpointRefs(t)
t.Chdir(workDir)
paths.ClearWorktreeRootCache()
repo, err := git.PlainOpen(workDir)
require.NoError(t, err)
queue := enqueueRefs(t, repo, refs)
badTarget := filepath.Join(t.TempDir(), "missing.git")
pushed, err := PushMigratedCheckpointRefs(context.Background(), repo, badTarget)
require.ErrorContains(t, err, "failed to push")
assert.Equal(t, 0, pushed)
remaining, err := queue.Drain()
require.NoError(t, err)
assert.ElementsMatch(t, refs, remaining, "failed push leaves refs queued")
}
// remoteRefFiles lists the files in the tree a ref points at on the bare remote.
func remoteRefFiles(t *testing.T, bareDir string, ref plumbing.ReferenceName) string {
t.Helper()
}`