Skip to content

nuke: rewriteConfigFile truncates file before new content written — crash leaves empty config #249

@justrach

Description

@justrach

Problem

nuke.rewriteConfigFile uses createFile with .truncate = true, which destroys the original content immediately. If the process crashes between the truncate and the writeAll completing, ~/.claude.json (or equivalent) is left empty.

// src/nuke.zig — rewriteConfigFile
const file = try std.fs.cwd().createFile(path, .{ .truncate = true }); // ← destroys original NOW
defer file.close();
try file.writeAll(content); // ← crash here = empty config, all MCP servers lost

This is called from removeJsonMcpServerEntry and removeJsonEntry any time codedb nuke is run. A power loss, OOM-kill, or signal during uninstall silently wipes the user's entire MCP configuration.

Expected

Writes should be atomic: write to a temp file first, then rename it over the target. POSIX rename is atomic — a crash at any point leaves either the old file intact or the new file in place, never an empty file.

Correctness Test (currently passes)

test "issue-249: nuke.removeJsonMcpServerEntry returns null when key absent" {
    const result = try nuke_mod.removeJsonMcpServerEntry(testing.allocator, "{\"other\":1}", "codedb");
    try testing.expect(result == null); // no write triggered when key absent
}

Fix

fn rewriteConfigFile(path: []const u8, content: []const u8) !void {
    const tmp_path = try std.fmt.allocPrint(allocator, "{s}.tmp", .{path});
    defer allocator.free(tmp_path);
    {
        const tmp = try std.fs.cwd().createFile(tmp_path, .{});
        defer tmp.close();
        try tmp.writeAll(content);
    }
    try std.fs.rename(std.fs.cwd(), tmp_path, std.fs.cwd(), path);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions