mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 10:45:59 -10:00
test(worktree): reject stat-cache-hidden source overwrites
Problem: A snapshot-only regression does not establish that the shared tree reader also protects the source workspace before Apply publishes a candidate. Root cause: The old cached index can hide a user's intervening edit from the whole-tree drift check, allowing Apply to return success and overwrite it. Fix: Exercise actual snapshot/candidate/Apply assembly on disposable real Git repositories. Require ErrWorkspaceMoved and unchanged user bytes. Document the existing Git driver confinement and the additional rehashing cost explicitly. Verification: A compiling overlay of the original production file fails for both wrong success and actual overwrite; the repaired owner passes. Full final worktree race passes (48.247s). Broader root and static qualification records are retained separately; production code is unchanged by this test follow-up. Refs #14025 Refs #14133
This commit is contained in:
1 parent
0f943c7f7a
commit
fd8729692b
2 files changed
+64
No files matched your search
@@ -29,6 +29,10 @@ the transaction-library PR #14368. It is not independent security approval.
|
||||
各路径来自现有宿主解析的仓库身份或新建的私有临时目录。新命令仍经现有 Git
|
||||
驱动执行;参数不作为 shell 脚本拼接。真实索引和 refs 不参与私有索引重建。
|
||||
|
||||
The existing driver disables Git hooks/fsmonitor and submodule recursion for
|
||||
`read-tree`. The extra invocations inherit that policy. Index rebuilding and
|
||||
rehashing add work; this slice makes no capture-latency improvement claim.
|
||||
|
||||
## Rules and failure / 规则与失败
|
||||
|
||||
1. The copied index MUST first preserve its staged tree, including explicitly
|
||||
@@ -60,6 +64,9 @@ the transaction-library PR #14368. It is not independent security approval.
|
||||
3. The complete worktree race suite covers neighbouring creation, cancellation,
|
||||
filtering, relative roots, application and rollback behavior. Platform and
|
||||
broader assembly results are reported separately in the PR.
|
||||
4. `TestApplyRejectsStatCacheHiddenSourceEdit` reproduces an actual stale
|
||||
candidate overwriting a hidden user edit with the old code. The repair
|
||||
returns `ErrWorkspaceMoved` and keeps the user's bytes.
|
||||
|
||||
回归先证明旧实现在真实 Git 仓库中捕获旧内容,再验证修复后内容、忽略文件、
|
||||
索引及 HEAD 均符合预期。其他平台和装配层结论按各自实际测试结果记录。
|
||||
@@ -0,0 +1,57 @@
|
||||
package worktree
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestApplyRejectsStatCacheHiddenSourceEdit(t *testing.T) {
|
||||
requireGit(t)
|
||||
root := t.TempDir()
|
||||
gitIn(t, root, "init", "-q")
|
||||
gitIn(t, root, "config", "core.trustctime", "false")
|
||||
gitIn(t, root, "config", "core.checkstat", "minimal")
|
||||
writeRepoFile(t, root, "input", "old\n")
|
||||
path := filepath.Join(root, "input")
|
||||
stamp := time.Now().Add(-time.Hour).Truncate(time.Second)
|
||||
if err := os.Chtimes(path, stamp, stamp); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
gitIn(t, root, "add", "-A")
|
||||
gitIn(t, root, "commit", "-qm", "base")
|
||||
snapshot, err := TakeSnapshot(t.Context(), opened(t, root))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
candidate, err := CreateCandidate(t.Context(), snapshot, t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
if err := RemoveCandidate(context.WithoutCancel(t.Context()), snapshot, candidate); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
writeRepoFile(t, candidate.WorkspaceRoot, "input", "new\n")
|
||||
tree, changes, err := CandidateTree(t.Context(), snapshot, candidate)
|
||||
if err != nil || len(changes) != 1 {
|
||||
t.Fatalf("candidate fixture: %v %v", changes, err)
|
||||
}
|
||||
writeRepoFile(t, root, "input", "usr\n")
|
||||
if err := os.Chtimes(path, stamp, stamp); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if diff := gitIn(t, root, "diff", "--", "input"); diff != "" {
|
||||
t.Fatalf("fixture did not hide the user's edit: %s", diff)
|
||||
}
|
||||
if err := Apply(t.Context(), snapshot, tree, changes); !errors.Is(err, ErrWorkspaceMoved) {
|
||||
t.Errorf("stale candidate was not refused: %v", err)
|
||||
}
|
||||
if got := readRepoFile(t, root, "input"); got != "usr\n" {
|
||||
t.Fatalf("candidate overwrote the user's edit: %q", got)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user