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);
}
Audit scope: whole-repo, commit 7aa85a4Dimension 2 (test coverage) · medium
src/lib/LibFs.sol:68-71Problem
Deleting the entire
if (vm.exists(path)) { vm.removeFile(path); }block leaves134/134 tests passing.
vm.writeFiletruncates, so every content test passeswithout the unlink. The block's only documented justification is symlink
replacement (
LibFs.sol:49-51), and that has no test. (#41 established that theremove-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) andffiis not enabled anywhere in this repo, so no test can currently reach thebranch's real behaviour.
Evidence
Mutant: unlink block deleted, 134/134 tests still pass.
Proposed fix
Set
ffi = trueinfoundry.toml— the tradeoff, that any test can then shellout, is named here for triage rather than decided. The narrower
forge test --ffiroute would need a change in rainix's shared CI, since the reusable runsplain
forge test. Then a test that keeps everything inside the existing grant: