fix(strategy): make checkpoint_remote authoritative when seeding metadata ref · Entire
fix(strategy): make checkpoint_remote authoritative when seeding metadata ref
70da006→main·
suhaanthayyil·2d ago·3 files·+419 added/-54 removed
Address trail-review findings on how entire enable seeds the local
metadata branch, so a device never seeds STALE checkpoints (issue #1374).
- EnsurePrimaryRef now short-circuits on a configured checkpoint_remote and never consults origin's (possibly stale) primary tracking ref: on a repo migrated from origin-hosted checkpoints to a dedicated checkpoint_remote, the stale origin ref no longer shadows the real remote.
- Replace the literal empty-tree check (isEmptyMetadataBranch) with metadataBranchHasData, which treats an orphan carrying only known init files (vercel.json) as data-free. This lets the re-enable heal fire on vercel-enabled repos whose orphan tip is not literally empty.
- Guard the bootstrap/heal fetch with urlTargetsCheckpointRepo: remote.FetchURL silently falls back to the origin URL in several paths, so verify the resolved URL's owner/repo match the configured checkpoint repo before fetching; a mismatch falls through to the orphan instead of adopting origin's data.
- Heal a data-free orphan by force-setting the local ref to the fetched tip rather than safe-advancing it, which would replay the orphan and leave a stray empty commit.
Tests: TestURLTargetsCheckpointRepo, TestEnsurePrimaryRef_CheckpointRemoteTakesPrecedenceOverOrigin, TestEnsurePrimaryRef_HealsVercelOnlyOrphanFromCheckpointRemote.
Changes
3
cmd/entire/cli/strategy
Mcheckpoint_remote.go+51/-1
Mcheckpoint_remote_test.go+179
Mcommon.go+189/-53
130 unmodified lines
131
132
133
134
134
135
136
137
43 unmodified lines
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
130 unmodified lines
// fetches are globally enabled. Use noFilter for operations that need blob
// content (resume, explain) as opposed to sync operations (push recovery)
// that only need tree structure.
func fetchURLIntoTmpRef(ctx context.Context, dir, remoteURL, srcRef, tmpRef, label string, noFilter bool) error {
func fetchURLIntoTmpRef(ctx context.Context, dir, remoteURL, srcRef, tmpRef, label string, noFilter bool) error { //nolint:unparam // noFilter distinguishes blob-content fetches (true) from tree-only sync fetches (false); kept for the documented fetch-filtering contract even though current callers all need blob content
fetchCtx, cancel := context.WithTimeout(ctx, checkpointRemoteFetchTimeout)
defer cancel()
43 unmodified lines
logging.Info(ctx, "checkpoint-remote: fetched metadata branch from URL")
return nil
}
// resolveCheckpointFetchURL resolves the checkpoint_remote fetch URL for the repo
// rooted at worktreeRoot and verifies it actually targets the configured
// checkpoint repository. It returns ok=false (never an error) when no
// checkpoint_remote is configured or a dedicated checkpoint URL cannot be
// resolved, so callers fall back to keeping the local branch / creating an orphan.
//
// remote.FetchURL silently falls back to the origin remote URL in several paths
// (ENTIRE_CHECKPOINT_TOKEN short-circuit, unparseable origin, non-derivable origin
// protocol). Adopting from origin would contradict the rule that origin is never
// authoritative when a checkpoint_remote is configured (issue #1374), so a resolved
// URL that does not target the configured checkpoint repo is treated as unresolved.
func resolveCheckpointFetchURL(ctx context.Context, worktreeRoot string) (string, bool) {
s, err := settings.Load(ctx)
if err != nil {
logging.Debug(ctx, "checkpoint-remote: could not load settings for metadata fetch URL",
slog.String("error", err.Error()))
return "", false
}
config := s.GetCheckpointRemote()
if config == nil {
return "", false
}
url, err := remote.FetchURL(ctx, remote.FetchURLOptions{WorktreeRoot: worktreeRoot})
if err != nil || strings.TrimSpace(url) == "" {
logging.Debug(ctx, "checkpoint-remote: could not resolve fetch URL for metadata bootstrap",
slog.Any("error", err))
return "", false
}
if !urlTargetsCheckpointRepo(url, config) {
logging.Debug(ctx, "checkpoint-remote: fetch URL did not resolve to the configured checkpoint repo; not adopting from origin",
slog.String("repo", config.Repo))
return "", false
}
return url, true
}
// urlTargetsCheckpointRepo reports whether url points at the configured checkpoint
// repository (host-agnostic, case-insensitive owner/repo match). It distinguishes a
// derived checkpoint URL from remote.FetchURL's origin fallback, which targets the
// origin repository instead. A same-repo checkpoint_remote (origin == checkpoint
// repo) still matches, which is correct: adopting from that URL is adopting the
// checkpoint repo.
func urlTargetsCheckpointRepo(url string, config *settings.CheckpointRemoteConfig) bool {
info, err := remote.ParseURL(url)
if err != nil || info.Owner == "" || info.Repo == "" {
return false
}
return strings.EqualFold(info.Owner+"/"+info.Repo, config.Repo)
}
Mcmd/entire/cli/strategy/checkpoint_remote.go+51/-1
10 unmodified lines
11
12
13
14
15
16
17
18
19
1108 unmodified lines
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
10 unmodified lines
"github.com/entireio/cli/cmd/entire/cli/checkpoint/remote"
"github.com/entireio/cli/cmd/entire/cli/paths"
"github.com/entireio/cli/cmd/entire/cli/settings"
"github.com/entireio/cli/cmd/entire/cli/testutil"
"github.com/entireio/cli/cmd/entire/cli/vercelconfig"
"github.com/go-git/go-git/v6/plumbing"
"github.com/stretchr/testify/assert"
1108 unmodified lines
assert.Empty(t, tree.Entries, "expected empty orphan fallback when checkpoint remote is unreachable")
}
// TestURLTargetsCheckpointRepo verifies the issue #1374 guard that distinguishes a
// derived checkpoint URL from remote.FetchURL's silent origin fallback: only URLs
// whose owner/repo match the configured checkpoint repo (host-agnostic,
// case-insensitive) are accepted.
func TestURLTargetsCheckpointRepo(t *testing.T) {
t.Parallel()
config := &settings.CheckpointRemoteConfig{Provider: "github", Repo: "org/checkpoints"}
tests := []struct {
name string
url string
want bool
}{
{"HTTPS checkpoint repo", "https://github.com/org/checkpoints.git", true},
{"SSH checkpoint repo", "git@github.com:org/checkpoints.git", true},
{"enterprise host, same repo path", "https://github.example.com/org/checkpoints.git", true},
{"case-insensitive owner/repo", "https://github.com/Org/Checkpoints.git", true},
{"origin fallback (different repo)", "https://github.com/org/main-repo.git", false},
{"different owner", "https://github.com/other/checkpoints.git", false},
{"unparseable url", "not a url", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
assert.Equal(t, tt.want, urlTargetsCheckpointRepo(tt.url, config))
})
}
}
// TestEnsurePrimaryRef_CheckpointRemoteTakesPrecedenceOverOrigin verifies issue
// #1374: when a checkpoint_remote is configured, EnsurePrimaryRef adopts its branch
// even when a stale origin/entire/checkpoints/v1 tracking ref is present. Origin is
// no longer the authoritative checkpoint store, so it must not be seeded from.
//
// Not parallel: uses t.Chdir().
func TestEnsurePrimaryRef_CheckpointRemoteTakesPrecedenceOverOrigin(t *testing.T) {
ctx := context.Background()
// Checkpoint remote holds the authoritative checkpoint.
checkpointRemoteDir := t.TempDir()
testutil.InitRepo(t, checkpointRemoteDir)
testutil.WriteFile(t, checkpointRemoteDir, "f.txt", "init")
testutil.GitAdd(t, checkpointRemoteDir, "f.txt")
testutil.GitCommit(t, checkpointRemoteDir, "init")
cpDefault := checkpointRemoteCurrentBranch(ctx, t, checkpointRemoteDir)
runCheckpointRemoteGit(ctx, t, checkpointRemoteDir, "checkout", "--orphan", paths.MetadataBranchName)
runCheckpointRemoteGit(ctx, t, checkpointRemoteDir, "rm", "-rf", ".")
commitCheckpointRemoteMetadata(ctx, t, checkpointRemoteDir, "aaaaaaaaaaaa", "authoritative")
runCheckpointRemoteGit(ctx, t, checkpointRemoteDir, "checkout", cpDefault)
cpTip := checkpointRemoteRevParse(ctx, t, checkpointRemoteDir, paths.MetadataBranchName)
// Origin holds a different, stale checkpoint branch.
originDir := t.TempDir()
testutil.InitRepo(t, originDir)
testutil.WriteFile(t, originDir, "f.txt", "init")
testutil.GitAdd(t, originDir, "f.txt")
testutil.GitCommit(t, originDir, "init")
originDefault := checkpointRemoteCurrentBranch(ctx, t, originDir)
runCheckpointRemoteGit(ctx, t, originDir, "checkout", "--orphan", paths.MetadataBranchName)
runCheckpointRemoteGit(ctx, t, originDir, "rm", "-rf", ".")
commitCheckpointRemoteMetadata(ctx, t, originDir, "bbbbbbbbbbbb", "stale")
runCheckpointRemoteGit(ctx, t, originDir, "checkout", originDefault)
// Local repo (device B): fetch origin so a stale origin tracking ref exists,
// then repoint origin at an SSH URL so FetchURL derives the github checkpoint
// URL. The stale tracking ref and its objects survive the set-url.
localDir := t.TempDir()
testutil.InitRepo(t, localDir)
testutil.WriteFile(t, localDir, "f.txt", "init")
testutil.GitAdd(t, localDir, "f.txt")
testutil.GitCommit(t, localDir, "init")
runCheckpointRemoteGit(ctx, t, localDir, "remote", "add", "origin", "file://"+originDir)
runCheckpointRemoteGit(ctx, t, localDir, "fetch", "origin")
runCheckpointRemoteGit(ctx, t, localDir, "remote", "set-url", "origin", "git@github.com:org/main-repo.git")
entireDir := filepath.Join(localDir, ".entire")
require.NoError(t, os.MkdirAll(entireDir, 0o755))
require.NoError(t, os.WriteFile(
filepath.Join(entireDir, paths.SettingsFileName),
[]byte(`{"enabled": true, "strategy_options": {"checkpoint_remote": {"provider": "github", "repo": "org/checkpoints"}}}`),
0o644,
))
// The SSH origin + github checkpoint_remote resolves (via remote.FetchURL) to
// git@github.com:org/checkpoints.git. Redirect that derived URL to the local
// checkpoint remote so the real fetch path runs hermetically.
redirectGitURL(t, localDir, "git@github.com:org/checkpoints.git", "file://"+checkpointRemoteDir)
t.Chdir(localDir)
paths.ClearWorktreeRootCache()
repo, err := OpenRepository(ctx)
require.NoError(t, err)
defer repo.Close()
// Sanity: the stale origin tracking ref exists and differs from the remote.
originRef, err := repo.Reference(plumbing.NewRemoteReferenceName("origin", paths.MetadataBranchName), true)
require.NoError(t, err, "test setup: origin tracking ref should exist")
require.NotEqual(t, cpTip, originRef.Hash().String(), "test setup: origin must differ from checkpoint remote")
require.NoError(t, EnsurePrimaryRef(WithCheckpointRemoteBootstrap(ctx), repo))
got := checkpointRemoteRevParse(ctx, t, localDir, paths.MetadataBranchName)
assert.Equal(t, cpTip, got, "local branch should adopt the checkpoint remote, not the stale origin ref")
files := checkpointRemoteMetadataFiles(ctx, t, localDir)
assert.Contains(t, files, "aa/aaaaaaaaaa/"+paths.MetadataFileName, "authoritative checkpoint-remote data should be present")
assert.NotContains(t, files, "bb/bbbbbbbbbb/"+paths.MetadataFileName, "stale origin data must not be adopted")
}
// TestEnsurePrimaryRef_HealsVercelOnlyOrphanFromCheckpointRemote verifies the issue
// #1374 heal covers a local metadata branch carrying only vercel.json — the
// orphan-init state in a vercel-enabled repo. A literal empty-tree check skipped it
// (the tree is not empty), leaving those devices divergent forever.
//
// Not parallel: uses t.Chdir().
func TestEnsurePrimaryRef_HealsVercelOnlyOrphanFromCheckpointRemote(t *testing.T) {
ctx := context.Background()
// Checkpoint remote holds the authoritative checkpoint.
remoteDir := t.TempDir()
testutil.InitRepo(t, remoteDir)
testutil.WriteFile(t, remoteDir, "f.txt", "init")
testutil.GitAdd(t, remoteDir, "f.txt")
testutil.GitCommit(t, remoteDir, "init")
remoteDefault := checkpointRemoteCurrentBranch(ctx, t, remoteDir)
runCheckpointRemoteGit(ctx, t, remoteDir, "checkout", "--orphan", paths.MetadataBranchName)
runCheckpointRemoteGit(ctx, t, remoteDir, "rm", "-rf", ".")
commitCheckpointRemoteMetadata(ctx, t, remoteDir, "aaaaaaaaaaaa", "device-a")
runCheckpointRemoteGit(ctx, t, remoteDir, "checkout", remoteDefault)
remoteTip := checkpointRemoteRevParse(ctx, t, remoteDir, paths.MetadataBranchName)
// Local repo (device B): a local orphan carrying only vercel.json — the
// vercel-enabled bug state left behind by orphan initialization.
localDir := t.TempDir()
testutil.InitRepo(t, localDir)
testutil.WriteFile(t, localDir, "f.txt", "init")
testutil.GitAdd(t, localDir, "f.txt")
testutil.GitCommit(t, localDir, "init")
runCheckpointRemoteGit(ctx, t, localDir, "remote", "add", "origin", "git@github.com:org/main-repo.git")
localDefault := checkpointRemoteCurrentBranch(ctx, t, localDir)
runCheckpointRemoteGit(ctx, t, localDir, "checkout", "--orphan", paths.MetadataBranchName)
runCheckpointRemoteGit(ctx, t, localDir, "rm", "-rf", ".")
testutil.WriteFile(t, localDir, vercelconfig.FileName, `{"git":{"deploymentEnabled":{"entire/**":false}}}`)
runCheckpointRemoteGit(ctx, t, localDir, "add", vercelconfig.FileName)
runCheckpointRemoteGit(ctx, t, localDir, "commit", "-m", "Initialize metadata branch")
runCheckpointRemoteGit(ctx, t, localDir, "checkout", localDefault)
entireDir := filepath.Join(localDir, ".entire")
require.NoError(t, os.MkdirAll(entireDir, 0o755))
require.NoError(t, os.WriteFile(
filepath.Join(entireDir, paths.SettingsFileName),
[]byte(`{"enabled": true, "strategy_options": {"checkpoint_remote": {"provider": "github", "repo": "org/checkpoints"}}}`),
0o644,
))
redirectGitURL(t, localDir, "git@github.com:org/checkpoints.git", "file://"+remoteDir)
t.Chdir(localDir)
paths.ClearWorktreeRootCache()
repo, err := OpenRepository(ctx)
require.NoError(t, err)
defer repo.Close()
vercelOnlyTip := checkpointRemoteRevParse(ctx, t, localDir, paths.MetadataBranchName)
require.NotEqual(t, remoteTip, vercelOnlyTip, "test setup: vercel-only orphan must differ from remote tip")
require.NoError(t, EnsurePrimaryRef(WithCheckpointRemoteBootstrap(ctx), repo))
healed := checkpointRemoteRevParse(ctx, t, localDir, paths.MetadataBranchName)
assert.Equal(t, remoteTip, healed,
"a vercel.json-only orphan should be treated as un-initialized and healed to the exact remote tip")
files := checkpointRemoteMetadataFiles(ctx, t, localDir)
assert.Contains(t, files, "aa/aaaaaaaaaa/"+paths.MetadataFileName, "the healed branch should contain the checkpoint remote data")
}
// redirectGitURL appends a git `url.<replacement>.insteadOf = <match>` rule to
// the repo-local config so any git operation on matchURL is transparently
// rewritten to replacementURL. This lets tests point a derived remote URL at a