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);
    }

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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