Skip to content

LibFs.buildFileForContract's unlink block has no test, and no test in this repo can currently reach it #66

Description

@thedavidmeister

Audit scope: whole-repo, commit 7aa85a4

Dimension 2 (test coverage) · medium

src/lib/LibFs.sol:68-71

Problem

Deleting the entire if (vm.exists(path)) { vm.removeFile(path); } block leaves
134/134 tests passing. vm.writeFile truncates, so every content test passes
without the unlink. The block's only documented justification is symlink
replacement (LibFs.sol:49-51), and that has no test. (#41 established that the
remove-then-write is unobservable through the NatSpec's idempotency claim; this
is the coverage half — the one behaviour the block is actually kept for is
unprobed.)

There is no symlink-creating cheatcode in forge-std 1.16.1 (only readLink) and
ffi is not enabled anywhere in this repo, so no test can currently reach the
branch's real behaviour.

Evidence

Mutant: unlink block deleted, 134/134 tests still pass.

Proposed fix

Set ffi = true in foundry.toml — the tradeoff, that any test can then shell
out, is named here for triage rather than decided. The narrower forge test --ffi route would need a change in rainix's shared CI, since the reusable runs
plain forge test. Then a test that keeps everything inside the existing grant:

    /// A symlink at the path is unlinked, so the write lands at the path rather
    /// than following the link to its target. A dangling link is the case that
    /// matters: `vm.exists` resolves symlinks and reports it absent.
    function testBuildFileForContractReplacesDanglingSymlink() external {
        string memory name = "LibFsBuildSymlink";
        string memory path = LibFs.pathForContract(name);
        string memory target = "src/generated/LibFsBuildSymlinkTarget.txt";
        cleanupPath(path);
        cleanupPath(target);

        string[] memory command = new string[](4);
        command[0] = "ln";
        command[1] = "-s";
        command[2] = "LibFsBuildSymlinkTarget.txt";
        command[3] = path;
        vm.ffi(command);

        address instance = address(new CodeGennable());
        string memory body = "\n// symlink\n";
        LibFs.buildFileForContract(vm, instance, name, body);

        assertFalse(vm.exists(target), "the write followed the symlink off the path");
        assertEq(vm.readFile(path), expectedFile(instance, body));
        cleanupPath(path);
        cleanupPath(target);
    }

Metadata

Metadata

Labels

auditAudit findingmediumAudit findingpass2Audit finding

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions