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
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
classifyPublicIntakePullRequest,
fetchPublicApplicationCandidate,
hydratePublicApplicationCandidate,
measureHydrationDirectory,
preflightPublicApplicationCandidateFetch,
PUBLIC_BETA_DISCLAIMER,
runBoundedHydrationGitProcess,
Expand Down Expand Up @@ -67,6 +68,33 @@ test("blobless maintenance classification never materializes an unexpected 100 M
assert.equal(fs.existsSync(path.join(candidateData, "skills")), false);
});

test("bounded repository measurement tolerates Git removing a temporary child directory", (t) => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), "public-hook-measure-race-"));
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
const stableBytes = Buffer.from("stable object bytes");
fs.writeFileSync(path.join(root, "stable-object"), stableBytes);
const transientDirectory = path.join(root, "temporary-pack");
fs.mkdirSync(transientDirectory);
fs.writeFileSync(path.join(transientDirectory, "in-flight.pack"), "temporary bytes");

const originalLstatSync = fs.lstatSync;
let removed = false;
fs.lstatSync = function lstatAndRemoveTemporaryDirectory(target, options) {
const status = originalLstatSync.call(fs, target, options);
if (!removed && target === transientDirectory) {
removed = true;
fs.rmSync(transientDirectory, { recursive: true, force: true });
}
return status;
};
try {
assert.equal(measureHydrationDirectory(root), stableBytes.length);
} finally {
fs.lstatSync = originalLstatSync;
}
assert.equal(removed, true);
});

test("trusted application validation hydrates only the six closed package blobs", async (t) => {
const fixture = createRevisionPair(t);
const packageFiles = makePackage();
Expand Down
20 changes: 16 additions & 4 deletions scripts/verify-public-hook-application-core.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1344,7 +1344,7 @@ function hydrationGitEnvironment() {
return environment;
}

function measureHydrationDirectory(directory) {
export function measureHydrationDirectory(directory) {
const root = path.resolve(directory ?? "");
if (!fs.statSync(root, { throwIfNoEntry: false })?.isDirectory()) {
systemBlocked("HYDRATION_STORAGE_INVALID", "The candidate object store is missing.");
Expand All @@ -1354,16 +1354,28 @@ function measureHydrationDirectory(directory) {
let totalBytes = 0;
while (pending.length > 0) {
const current = pending.pop();
for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
let entriesInDirectory;
try {
entriesInDirectory = fs.readdirSync(current, { withFileTypes: true });
} catch (error) {
// Git creates, renames, and removes temporary pack directories while a
// bounded fetch is active. A child that disappears between traversal
// steps is harmless; the stable final measurement still runs after Git
// exits. The object-store root itself must always remain present.
if (current !== root && error?.code === "ENOENT") continue;
throw error;
}
for (const entry of entriesInDirectory) {
entries += 1;
if (entries > HYDRATION_MAXIMUM_ENTRIES) {
systemBlocked("HYDRATION_STORAGE_INVALID", "The candidate object store exceeds its trusted entry bound.");
}
const entryPath = path.join(current, entry.name);
if (entry.isDirectory()) {
const status = fs.lstatSync(entryPath, { throwIfNoEntry: false });
if (status === undefined) continue;
if (status.isDirectory()) {
pending.push(entryPath);
} else {
const status = fs.lstatSync(entryPath);
if (status.isFile() || status.isSymbolicLink()) totalBytes += status.size;
}
if (!Number.isSafeInteger(totalBytes)) {
Expand Down
Loading