daemon: rewrite git identity sync + file_sync on ext4 toolkit

ensureGitIdentityOnWorkDisk, writeGitIdentity, runFileSync, and
copyHostDir all dropped their mount + sudo install/mkdir/chmod/chown
scaffolding. Every write now goes through MkdirExt4,
WriteExt4FileOwned, ReadExt4File, and the new MkdirAllExt4 helper —
all sudoless against user-owned ext4 images.

Net effect with the prior two commits: ensureWorkDisk, authsync, image
seeding, git identity sync, and file_sync no longer mount the work
disk or spawn sudo mkdir/chmod/chown/cat/install. Only the
image-build path (which legitimately produces root-owned artifacts)
still touches MountTempDir.

The filesystemRunner test harness grew a small debugfs/e2cp/e2rm
emulator so the WorkspaceService tests keep exercising their real
code paths without a live ext4 image. The mock is deliberately
dumb — it only implements the subset runFileSync and writeGitIdentity
drive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Thales Maciel 2026-04-23 18:29:30 -03:00
parent f0685366ec
commit 6ab1a2b844
No known key found for this signature in database
GPG key ID: 33112E6833C34679
3 changed files with 253 additions and 74 deletions

View file

@ -2031,11 +2031,147 @@ func (r *filesystemRunner) RunSudo(ctx context.Context, args ...string) ([]byte,
default:
return nil, fmt.Errorf("unexpected chown args: %v", args)
}
case "debugfs":
return runFakeDebugfs(args[1:])
case "e2cp":
// e2cp SRC IMAGE:/GUEST → plain file copy into IMAGE dir
if len(args) != 3 {
return nil, fmt.Errorf("unexpected e2cp args: %v", args)
}
image, guest, ok := splitImageColonPath(args[2])
if !ok {
return nil, fmt.Errorf("e2cp dst missing image:path separator: %v", args)
}
target := filepath.Join(image, guest)
data, err := os.ReadFile(args[1])
if err != nil {
return nil, err
}
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
return nil, err
}
return nil, os.WriteFile(target, data, 0o600)
case "e2rm":
// e2rm IMAGE:/GUEST → plain file delete; missing is not fatal
if len(args) != 2 {
return nil, fmt.Errorf("unexpected e2rm args: %v", args)
}
image, guest, ok := splitImageColonPath(args[1])
if !ok {
return nil, fmt.Errorf("e2rm missing image:path separator: %v", args)
}
target := filepath.Join(image, guest)
if err := os.Remove(target); err != nil && !os.IsNotExist(err) {
return nil, err
}
return nil, nil
default:
return nil, fmt.Errorf("unexpected sudo command: %v", args)
}
}
// runFakeDebugfs emulates the subset of debugfs commands the ext4
// toolkit drives in per-line mode (the stdin-batched path doesn't run
// under filesystemRunner because it doesn't implement StdinRunner).
// Supported: stat/cat, plus -w mkdir/set_inode_field. Inode 2 <2>
// set_inode_field is a no-op — tests don't care about root-inode mode
// beyond it not exploding.
func runFakeDebugfs(args []string) ([]byte, error) {
// Forms:
// debugfs -R "<cmd>" <image> (read-only)
// debugfs -w -R "<cmd>" <image> (single write)
if len(args) < 3 {
return nil, fmt.Errorf("unexpected debugfs args: %v", args)
}
write := false
rest := args
if rest[0] == "-w" {
write = true
rest = rest[1:]
}
if len(rest) != 3 || rest[0] != "-R" {
return nil, fmt.Errorf("unexpected debugfs args: %v", args)
}
cmdLine := strings.TrimSpace(rest[1])
image := rest[2]
fields := strings.Fields(cmdLine)
if len(fields) == 0 {
return nil, fmt.Errorf("empty debugfs command")
}
switch fields[0] {
case "stat":
if len(fields) != 2 {
return nil, fmt.Errorf("unexpected debugfs stat: %q", cmdLine)
}
target := filepath.Join(image, strings.Trim(fields[1], `"`))
if _, err := os.Stat(target); err != nil {
if os.IsNotExist(err) {
return []byte("stat: File not found by ext2_lookup while starting pathname"), nil
}
return nil, err
}
return []byte("Inode: 12 Type: directory"), nil
case "cat":
if len(fields) != 2 {
return nil, fmt.Errorf("unexpected debugfs cat: %q", cmdLine)
}
target := filepath.Join(image, strings.Trim(fields[1], `"`))
data, err := os.ReadFile(target)
if err != nil {
return nil, err
}
return data, nil
case "mkdir":
if !write {
return nil, fmt.Errorf("debugfs mkdir requires -w: %q", cmdLine)
}
if len(fields) != 2 {
return nil, fmt.Errorf("unexpected debugfs mkdir: %q", cmdLine)
}
target := filepath.Join(image, strings.Trim(fields[1], `"`))
return nil, os.MkdirAll(target, 0o755)
case "set_inode_field":
// set_inode_field <path-or-<2>> <field> <value>
// Mode changes on non-root targets: honour the perm bits so
// tests can assert file mode. Root inode <2>, uid, gid are
// no-ops — tests don't inspect them.
if !write {
return nil, fmt.Errorf("debugfs set_inode_field requires -w: %q", cmdLine)
}
if len(fields) != 4 {
return nil, fmt.Errorf("unexpected set_inode_field: %q", cmdLine)
}
target := strings.Trim(fields[1], `"`)
if target == "<2>" || fields[2] != "mode" {
return nil, nil
}
raw := strings.TrimPrefix(fields[3], "0")
v, err := strconv.ParseUint(raw, 8, 32)
if err != nil {
return nil, fmt.Errorf("parse set_inode_field mode %q: %w", fields[3], err)
}
return nil, os.Chmod(filepath.Join(image, target), os.FileMode(v)&os.ModePerm)
case "rdump":
// rdump <src> <dst>
return nil, fmt.Errorf("rdump not supported in filesystemRunner")
default:
return nil, fmt.Errorf("unsupported debugfs cmd: %q", cmdLine)
}
}
// splitImageColonPath splits an e2cp/e2rm "image:path" argument.
// Returns image, path, true on success. Only the LAST colon is split
// on since image paths on disk may contain one (rare) and guest paths
// always start with "/".
func splitImageColonPath(arg string) (string, string, bool) {
idx := strings.LastIndex(arg, ":/")
if idx < 0 {
return "", "", false
}
return arg[:idx], arg[idx+1:], true
}
// parseInstallArgs recognises the `install` invocations banger emits
// and returns (source, destination, parsed mode). Anything else is an
// error so the test stub stays a closed set.