Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/abstract/RainDeployVerifySnapshot.sol
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,25 @@ abstract contract RainDeployVerifySnapshot is RainDeployVerifyBase {
/// Every release in the frozen record MUST be declared, so that the set the
/// chain group checks is every release this repo has ever cut rather than
/// the ones somebody remembered to list.
///
/// An empty walk passes, and is meant to: that is the state of every deploy
/// repo before its first release. What makes it safe is that the root is
/// the one a snapshot is WRITTEN to — `LIB_FS_ROOT` is the only spelling of
/// it in `LibRainDeploySnapshot` and `testRecordRootIsTheRootTheWriterWritesTo`
/// pins it against `LibFs`'s. Under the writer's own root, finding nothing
/// means there is nothing; under any other, the walk returns an empty list
/// forever, this passes with no subject, and the one check standing between
/// a release dropping out of everything and a green suite is inert.
///
/// Deliberately NOT also guarded by comparing the record's size against the
/// declaration's. The two are emitted one-for-one by `writeReleasedSuitesLib`
/// for a repo that generates its declaration from its record, but this is
/// inherited by any repo that overrides `releasedSuites`, and a declaration
/// with no record behind it is a state such a repo is legitimately in: a
/// release deployed before it adopted this machinery has no frozen record
/// and never will. A size check would red-line that permanently with no way
/// to spell the exemption, while the release it names goes on being checked
/// by everything anchored to a chain.
function testEveryFrozenSnapshotIsReleased() external view {
checkFrozenSnapshotsReleased(
LibRainDeploySnapshot.frozenSnapshotPaths(vm, LibRainDeploySnapshot.LIB_FS_ROOT), releasedSuites()
Expand Down
17 changes: 12 additions & 5 deletions src/lib/LibRainDeploySnapshot.sol
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,22 @@ library LibRainDeploySnapshot {
return string(tagBytes);
}

/// The output root `LibFs` writes to, and the only one it can write to:
/// `LibFs.pathForContract` hardcodes it.
///
/// The only spelling of that root in this library. Everything here that
/// names the root — the directory a snapshot is written into, and the tree
/// the frozen record is walked from — reads it, so a root this library
/// walks that is not a root it writes to is not a state it can be in. The
/// remaining pair, this and `LibFs`'s own, is what
/// `testRecordRootIsTheRootTheWriterWritesTo` pins.
string constant LIB_FS_ROOT = "src/generated";

/// The directory holding a snapshot, rolling or frozen.
/// @param dir The snapshot directory name — a release tag, or `CANDIDATE`.
/// @return The directory path.
function dirForSnapshot(string memory dir) internal pure returns (string memory) {
return string.concat("src/generated/", dir);
return string.concat(LIB_FS_ROOT, "/", dir);
}

/// The contract name that places a generated file inside a snapshot
Expand All @@ -189,10 +200,6 @@ library LibRainDeploySnapshot {
return LibFs.pathForContract(snapshotName(dir, contractName));
}

/// The output root `LibFs` writes to, and the only one it can write to:
/// `LibFs.pathForContract` hardcodes it.
string constant LIB_FS_ROOT = "src/generated";

/// Every file in the FROZEN record: everything inside a release-tag
/// directory under `root`.
///
Expand Down
22 changes: 22 additions & 0 deletions test/src/lib/LibRainDeploySnapshot.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,28 @@ contract LibRainDeploySnapshotTest is Test {
assertEq(LibRainDeploySnapshot.pathForSnapshot("0_1_7", "Foo"), "src/generated/0_1_7/Foo.sol");
}

/// The root the record is WALKED from MUST be the root the writer WRITES
/// to. They are two constants — `LIB_FS_ROOT` here, and the one
/// `LibFs.pathForContract` hardcodes in a package this repo does not own —
/// and a walk of a root nothing writes to returns nothing, which every
/// record-anchored assertion then passes on. Silence is the failure mode,
/// so it is asserted rather than observed.
///
/// Compared through `pathForSnapshot`, which is what a snapshot is written
/// through, so the right hand side is the writer's own root rather than a
/// third restatement of it. The contract name is arbitrary — the path is
/// built by concatenation and names no artifact.
function testRecordRootIsTheRootTheWriterWritesTo() external pure {
assertEq(
LibRainDeploySnapshot.pathForSnapshot("0_1_7", "Foo"),
string.concat(LibRainDeploySnapshot.LIB_FS_ROOT, "/0_1_7/Foo.sol")
);
assertEq(
LibRainDeploySnapshot.dirForSnapshot(LibRainDeploySnapshot.CANDIDATE),
string.concat(LibRainDeploySnapshot.LIB_FS_ROOT, "/", LibRainDeploySnapshot.CANDIDATE)
);
}

/// A snapshot MUST land at the path this library says it does, and writing
/// one over a directory that is already there is the ORDINARY case: the
/// rolling snapshot is regenerated into the same `candidate/` on every
Expand Down
Loading