fix(reference): scope ignore rules and honor local Git case policy

This commit is contained in:
morluto
2026-10-24 02:27:18 +08:00
parent 3f49545320
commit 1998640669
10 changed files with 493 additions and 136 deletions
+11 -2
View File
@@ -407,8 +407,17 @@ other facts. No fixed output-size or runtime improvement is promised.
The import records hashes and metadata for the supplied files, separately
from observations of the current app. For a directory inside a Git checkout,
it records the HEAD of the nearest enclosing repository; whether the working
tree matches that commit remains unknown. It honors the source tree's `.gitignore`
and applies default exclusions for common generated and dependency paths such
tree matches that commit remains unknown. Root selection follows filesystem
symlink/parent semantics before canonical identity is derived. It honors
`.gitignore` files at the selected root and in traversed child directories,
with patterns relative to their containing directory and deeper negations
applied only when the parent was not excluded. Matching uses the nearest
repository's local `core.ignorecase` setting (false when unset), including the
shared configuration of linked worktrees. Policy and Git metadata reads retain
their descriptor cleanup under the import's resource owner; unreadable policy
is a typed failure, not an empty policy. Above-root `.gitignore` files, global
excludes, `.git/info/exclude`, config includes and worktree-specific config are
not loaded. The import also applies default exclusions for common generated and dependency paths such
as `node_modules/`, `dist/`, and `*.log`. Pattern-based exclusions record the
matched pattern and whether it came from project, default, caller, or sensitive
path policy. Links into excluded paths retain their internal target metadata;
@@ -0,0 +1,57 @@
import { lstat } from "node:fs/promises";
import { dirname, join } from "node:path";
import { absoluteCallerPath } from "../filesystem/callerPath.js";
/** Parsed repository locations shared by HEAD and local ignore-policy readers. */
export interface ReferenceSourceGitDirectory {
readonly repository: string;
readonly gitDirectory: string;
readonly commonDirectory: string;
}
/** Locate the nearest repository without running Git or following config includes. */
export const locateReferenceSourceGitDirectory = async (
root: string,
readText: (path: string) => Promise<string>,
signal?: AbortSignal,
): Promise<ReferenceSourceGitDirectory | undefined> => {
let repository = root;
for (;;) {
signal?.throwIfAborted();
const dotgit = join(repository, ".git");
let metadata;
try {
metadata = await lstat(dotgit);
} catch (cause: unknown) {
if (!hasCode(cause, "ENOENT")) throw cause;
const parent = dirname(repository);
if (parent === repository) return undefined;
repository = parent;
continue;
}
let gitDirectory = dotgit;
if (metadata.isFile()) {
const pointer = (await readText(dotgit)).replace(/\r?\n$/u, "");
if (!pointer.startsWith("gitdir: ") || pointer.length === 8)
throw new Error("Invalid Git directory pointer");
gitDirectory = absoluteCallerPath(pointer.slice(8), { cwd: repository });
}
let commonDirectory = gitDirectory;
try {
const common = (await readText(join(gitDirectory, "commondir"))).replace(
/\r?\n$/u,
"",
);
commonDirectory = absoluteCallerPath(common, { cwd: gitDirectory });
} catch (cause: unknown) {
if (!hasCode(cause, "ENOENT")) throw cause;
}
return { repository, gitDirectory, commonDirectory };
}
};
const hasCode = (cause: unknown, code: string): boolean =>
typeof cause === "object" &&
cause !== null &&
"code" in cause &&
cause.code === code;
+2 -1
View File
@@ -119,7 +119,7 @@ const createShouldExclude =
: kind === "unknown"
? [path, `${path}/`]
: [path];
const firstMatch = (matcher: typeof secrets) => {
const firstMatch = (matcher: Pick<typeof secrets, "test">) => {
const results = patternPaths.map((patternPath) =>
matcher.test(patternPath),
);
@@ -181,6 +181,7 @@ export const importReferenceSource = async (
readReferenceSource(root, resources, {
...(options.signal === undefined ? {} : { signal: options.signal }),
shouldExclude,
beforeDirectory: prepared.value.beforeDirectory,
}),
readReferenceSourceVcs(root, resources, options.signal),
]);
+206 -69
View File
@@ -1,5 +1,8 @@
import { lstat, realpath, stat } from "node:fs/promises";
import fs from "node:fs";
import { join } from "node:path";
import { locateReferenceSourceGitDirectory } from "./ReferenceSourceGitDirectory.js";
import type { ReferenceSourceReaderError } from "../reference/ReferenceSourceReaderTypes.js";
import ignore from "ignore";
import {
@@ -25,7 +28,10 @@ import {
/** Validated inputs ready for filesystem traversal. */
export interface PreparedReferenceSourceImport {
readonly root: string;
readonly ignored: ReturnType<typeof ignore>;
readonly ignored: Pick<ReturnType<typeof ignore>, "test">;
readonly beforeDirectory: (
path: string,
) => Promise<Result<undefined, ReferenceSourceReaderError>>;
readonly secrets: ReturnType<typeof ignore>;
}
@@ -102,82 +108,213 @@ const resolveRoot = async (
}
};
/** Read one policy/configuration file through the existing descriptor owner. */
const readPolicyFile = async (
policyPath: string,
resources: ArtifactResourceScope,
signal?: AbortSignal,
): Promise<Result<string | undefined, ReferenceSourceImportError>> => {
try {
let present = true;
try {
await lstat(policyPath);
} catch (cause: unknown) {
if (
!(
typeof cause === "object" &&
cause !== null &&
"code" in cause &&
cause.code === "ENOENT"
)
)
throw cause;
present = false;
}
if (signal?.aborted === true)
throw new IgnorePolicyReadCancelled(signal.reason);
if (present) {
let text: string;
try {
text = await readRegularFileText(policyPath, {
signal,
cancellationFailure: (reason) =>
new IgnorePolicyReadCancelled(reason),
});
} catch (cause: unknown) {
if (cause instanceof IgnorePolicyReadCancelled) throw cause;
if (!(cause instanceof RegularFileCleanupFailure)) throw cause;
const retry = await retryRegularFileCleanup(cause, resources, signal);
const operationCancellation =
cause.outcome.kind === "failed"
? regularFileCancellation(cause)
: undefined;
if (retry.cleanup !== undefined) {
const primary =
retry.outcome.kind === "failed"
? retry.outcome.cause
: cause.cleanupCause;
const primaryCause = ignorePolicyCause(primary);
return err({
...failure(
isIgnorePolicyCancellation(primary) ||
operationCancellation !== undefined
? "cancelled"
: "io",
`Reference source ignore policy could not be read at ${policyPath}: ${errorMessage(primaryCause)}`,
),
cleanup: retry.cleanup,
cause: primaryCause,
});
}
if (retry.outcome.kind === "failed") {
if (operationCancellation !== undefined)
throw new IgnorePolicyReadCancelled(operationCancellation.reason);
throw retry.outcome.cause;
}
text = retry.outcome.value;
}
return ok(text);
}
return ok(undefined);
} catch (cause: unknown) {
const causeValue = ignorePolicyCause(cause);
return err({
...failure(
isIgnorePolicyCancellation(cause) ? "cancelled" : "io",
`Reference source policy could not be read at ${policyPath}: ${errorMessage(causeValue)}`,
),
cause: causeValue,
});
}
};
const readIgnoreCase = async (
root: string,
resources: ArtifactResourceScope,
signal?: AbortSignal,
): Promise<Result<boolean, ReferenceSourceImportError>> => {
let readFailure: ReferenceSourceImportError | undefined;
const readText = async (path: string): Promise<string> => {
// isomorphic-git probes readFile() without a path to detect promise APIs.
if (path === undefined)
throw new TypeError("Git metadata path is required");
const read = await readPolicyFile(path, resources, signal);
if (!read.ok) {
readFailure = read.error;
throw read.error;
}
if (read.value === undefined) {
const absent = new Error(`Git metadata file is absent: ${path}`);
Object.assign(absent, { code: "ENOENT" });
throw absent;
}
return read.value;
};
try {
const location = await locateReferenceSourceGitDirectory(
root,
readText,
signal,
);
if (location === undefined) return ok(false);
const { getConfig } = await import("isomorphic-git");
const value = await getConfig({
fs: { ...fs, promises: { ...fs.promises, readFile: readText } },
gitdir: location.commonDirectory,
path: "core.ignorecase",
});
if (readFailure !== undefined) return err(readFailure);
if (value === undefined) return ok(false);
// The installed Git parser applies the core.ignorecase boolean schema.
if (typeof value === "boolean") return ok(value);
return err(
failure(
"io",
`Invalid core.ignorecase in ${location.commonDirectory}/config`,
),
);
} catch (cause: unknown) {
if (readFailure !== undefined) return err(readFailure);
if (isAborted(signal) || isIgnorePolicyCancellation(cause))
return err(failure("cancelled", "Reference source import cancelled"));
return err({
...failure(
"io",
`Reference source Git policy could not be read: ${errorMessage(cause)}`,
),
cause,
});
}
};
const buildIgnored = async (
root: string,
excludePaths: readonly string[],
resources: ArtifactResourceScope,
signal?: AbortSignal,
): Promise<Result<ReturnType<typeof ignore>, ReferenceSourceImportError>> => {
const ignored = ignore();
const policyPath = join(root, ".gitignore");
let present = true;
try {
await lstat(policyPath);
} catch (cause: unknown) {
if (
!(
typeof cause === "object" &&
cause !== null &&
"code" in cause &&
cause.code === "ENOENT"
)
)
throw cause;
present = false;
}
if (signal?.aborted === true)
throw new IgnorePolicyReadCancelled(signal.reason);
if (present) {
let text: string;
try {
text = await readRegularFileText(policyPath, {
signal,
cancellationFailure: (reason) => new IgnorePolicyReadCancelled(reason),
});
} catch (cause: unknown) {
if (cause instanceof IgnorePolicyReadCancelled) throw cause;
if (!(cause instanceof RegularFileCleanupFailure)) throw cause;
const retry = await retryRegularFileCleanup(cause, resources, signal);
const operationCancellation =
cause.outcome.kind === "failed"
? regularFileCancellation(cause)
: undefined;
if (retry.cleanup !== undefined) {
const primary =
retry.outcome.kind === "failed"
? retry.outcome.cause
: cause.cleanupCause;
const primaryCause = ignorePolicyCause(primary);
return err({
...failure(
isIgnorePolicyCancellation(primary) ||
operationCancellation !== undefined
? "cancelled"
: "io",
`Reference source ignore policy could not be read at ${policyPath}: ${errorMessage(primaryCause)}`,
),
cleanup: retry.cleanup,
cause: primaryCause,
});
}
if (retry.outcome.kind === "failed") {
if (operationCancellation !== undefined)
throw new IgnorePolicyReadCancelled(operationCancellation.reason);
throw retry.outcome.cause;
}
text = retry.outcome.value;
}
addMarkedPatterns(ignored, [text], "project-ignored");
}
): Promise<
Result<
Pick<PreparedReferenceSourceImport, "ignored" | "beforeDirectory">,
ReferenceSourceImportError
>
> => {
const ignoreCase = await readIgnoreCase(root, resources, signal);
if (!ignoreCase.ok) return ignoreCase;
const mandatory = ignore();
addMarkedPatterns(
ignored,
mandatory,
DEFAULT_REFERENCE_SOURCE_IGNORE_PATTERNS,
"default-ignored",
);
for (const path of excludePaths) {
addMarkedPatterns(ignored, [path, `${path}/`], "caller-excluded");
}
return ok(ignored);
for (const path of excludePaths)
addMarkedPatterns(mandatory, [path, `${path}/`], "caller-excluded");
const scopes = new Map<string, ReturnType<typeof ignore>>();
const loadDirectory = async (
path: string,
): Promise<Result<undefined, ReferenceSourceImportError>> => {
if (scopes.has(path)) return ok(undefined);
const policyPath =
path === "." ? join(root, ".gitignore") : join(root, path, ".gitignore");
const read = await readPolicyFile(policyPath, resources, signal);
if (!read.ok) return read;
const matcher = ignore({ ignoreCase: ignoreCase.value });
if (read.value !== undefined)
addMarkedPatterns(matcher, [read.value], "project-ignored");
scopes.set(path, matcher);
return ok(undefined);
};
const rootPolicy = await loadDirectory(".");
if (!rootPolicy.ok) return rootPolicy;
return ok({
ignored: {
test: (path) => {
const mandatoryMatch = mandatory.test(path);
if (mandatoryMatch.ignored) return mandatoryMatch;
let result = mandatoryMatch;
const pieces = path.replace(/\/$/u, "").split("/");
for (let depth = 0; depth < pieces.length; depth += 1) {
const scope = depth === 0 ? "." : pieces.slice(0, depth).join("/");
const matcher = scopes.get(scope);
if (matcher === undefined) continue;
const scopedPath =
pieces.slice(depth).join("/") + (path.endsWith("/") ? "/" : "");
const match = matcher.test(scopedPath);
if (match.ignored || match.unignored) result = match;
}
return result;
},
},
beforeDirectory: async (path) => {
const loaded = await loadDirectory(path);
return loaded.ok
? loaded
: err({
...loaded.error,
tag: "reference-source-reader",
code: loaded.error.code === "cancelled" ? "cancelled" : "io",
});
},
});
};
/** Resolve the caller-selected directory and build path filters. */
@@ -201,7 +338,7 @@ export const prepareReferenceSourceImport = async (
if (!ignored.ok) return ignored;
return ok({
root: root.value,
ignored: ignored.value,
...ignored.value,
secrets: ignore().add([...options.policy.secretPatterns]),
});
} catch (cause: unknown) {
+28 -49
View File
@@ -1,6 +1,6 @@
import fs from "node:fs";
import { lstat } from "node:fs/promises";
import { dirname, join, resolve } from "node:path";
import { join } from "node:path";
import { locateReferenceSourceGitDirectory } from "./ReferenceSourceGitDirectory.js";
import { err, ok, type Result } from "../domain/result.js";
import type { ArtifactResourceScope } from "../artifacts/ArtifactResourceScope.js";
import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
@@ -30,26 +30,8 @@ export const readReferenceSourceVcs = async (
): Promise<Result<ReferenceSourceVcsInfo, ReferenceSourceReaderError>> => {
try {
return await resources.run(async () => {
// Like Git, a subdirectory belongs to its nearest enclosing repository;
// only a missing `.git` at every ancestor means no version control.
let repository = resolve(root);
for (;;) {
if (isAborted(signal)) return ok(unknownVcs());
try {
await lstat(join(repository, ".git"));
break;
} catch (cause: unknown) {
if (errorCode(cause) !== "ENOENT") return ok(unknownVcs());
}
const parent = dirname(repository);
if (parent === repository)
return ok({ kind: "none", head: null, dirty: null });
repository = parent;
}
try {
const head = await resolveSourceHead(repository, resources, signal);
if (isAborted(signal)) return ok(unknownVcs());
return ok({ kind: "git", head, dirty: null });
return ok(await resolveSourceVcs(root, resources, signal));
} catch (cause: unknown) {
if (cause instanceof ArtifactReaderFailure) throw cause;
return ok(unknownVcs());
@@ -67,11 +49,11 @@ const unknownVcs = (): ReferenceSourceVcsInfo => ({
dirty: null,
});
const resolveSourceHead = async (
const resolveSourceVcs = async (
root: string,
resources: ArtifactResourceScope,
signal?: AbortSignal,
): Promise<string> => {
): Promise<ReferenceSourceVcsInfo> => {
// isomorphic-git is loaded on first use so CLI and MCP startup skip it.
const { resolveRef } = await import("isomorphic-git");
let failedRead: { readonly cause: unknown } | undefined;
@@ -198,35 +180,32 @@ const resolveSourceHead = async (
if (failedRead !== undefined) throw failedRead.cause;
return head;
};
const dotgit = join(root, ".git");
if (!(await lstat(dotgit)).isFile()) return readRef({ ref: "HEAD" });
const pointer = (await readMetadataText(dotgit)).replace(/\r?\n$/u, "");
if (!pointer.startsWith("gitdir: ") || pointer.length === 8)
throw new Error("Invalid Git directory pointer");
const gitdir = resolve(root, pointer.slice(8));
let commonDirectory: string;
try {
commonDirectory = resolve(
gitdir,
(await readMetadataText(join(gitdir, "commondir"))).replace(
/\r?\n$/u,
"",
),
);
} catch (cause: unknown) {
if (errorCode(cause) !== "ENOENT") throw cause;
return readRef({ gitdir, ref: "HEAD" });
}
const head = (await readMetadataText(join(gitdir, "HEAD"))).trim();
if (!head.startsWith("ref: ")) return readRef({ gitdir, ref: "HEAD" });
const ref = head.slice(5);
const privateRef = ["refs/bisect/", "refs/rewritten/", "refs/worktree/"].some(
(prefix) => ref.startsWith(prefix),
const locations = await locateReferenceSourceGitDirectory(
root,
readMetadataText,
signal,
);
return readRef({
gitdir: privateRef ? gitdir : commonDirectory,
if (locations === undefined) return { kind: "none", head: null, dirty: null };
const { gitDirectory, commonDirectory } = locations;
if (gitDirectory === commonDirectory) {
const head = await readRef({ gitdir: gitDirectory, ref: "HEAD" });
return isAborted(signal)
? unknownVcs()
: { kind: "git", head, dirty: null };
}
const headText = (await readMetadataText(join(gitDirectory, "HEAD"))).trim();
const ref = headText.startsWith("ref: ") ? headText.slice(5) : "HEAD";
const privateRef =
ref === "HEAD" ||
["refs/bisect/", "refs/rewritten/", "refs/worktree/"].some((prefix) =>
ref.startsWith(prefix),
);
const head = await readRef({
gitdir: privateRef ? gitDirectory : commonDirectory,
ref,
});
if (isAborted(signal)) return unknownVcs();
return { kind: "git", head, dirty: null };
};
const errorCode = (cause: unknown): string | undefined =>
+3
View File
@@ -60,6 +60,9 @@ const readSource = async (
...(options.shouldExclude === undefined
? {}
: { shouldExclude: options.shouldExclude }),
...(options.beforeDirectory === undefined
? {}
: { beforeDirectory: options.beforeDirectory }),
entries: [],
exclusions: [],
pending: [{ path: canonicalRoot }],
@@ -65,6 +65,11 @@ export const traverseDirectory = async (
recordDirectoryFailure(state, current.path, before.code, before.message);
return { ok: true, value: undefined };
}
const policy = await state.beforeDirectory?.(
pathFromRoot(state.root, current.path),
);
if (policy !== undefined && !policy.ok) return policy;
if (isAborted(state.signal)) return err(cancelled());
const directories: PendingDirectory[] = [];
let readFailure: string | undefined;
let unrepresentableNameCount = 0;
@@ -18,6 +18,10 @@ export type ReferenceSourceExclusionKind = ReferenceSourceEntryKind | "unknown";
export interface ReferenceSourceReaderOptions {
readonly signal?: AbortSignal;
/** Prepare directory-scoped policy after directory identity admission, before enumeration. */
readonly beforeDirectory?: (
path: string,
) => Promise<ReferenceSourceResult<undefined>>;
readonly shouldExclude?: (
path: string,
kind: ReferenceSourceExclusionKind,
@@ -95,6 +99,10 @@ export type TraversalState = {
readonly root: string;
readonly rootIdentity: BigIntStats;
readonly signal?: AbortSignal;
/** Prepare directory-scoped policy after directory identity admission, before enumeration. */
readonly beforeDirectory?: (
path: string,
) => Promise<ReferenceSourceResult<undefined>>;
readonly shouldExclude?: (
path: string,
kind: ReferenceSourceExclusionKind,
@@ -0,0 +1,126 @@
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it } from "vitest";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { execFileOutput } from "../../../src/process/ExecFileOutput.js";
import { importReferenceSource } from "../../support/referenceSourceResourceScope.js";
const importTree = async (root: string) => {
const result = await importReferenceSource({
root,
caller: "ignore-policy-test",
policy: { secretPatterns: [] },
});
if (!result.ok) throw result.error;
return result.value;
};
it("scopes nested ignore rules and negations like Git while preserving mandatory exclusions", async () => {
const root = await createTestTempDirectory("rea-reference-scoped-policy-");
await execFileOutput("git", ["init", "--initial-branch=main", root]);
await execFileOutput("git", [
"-C",
root,
"config",
"core.ignorecase",
"false",
]);
await mkdir(join(root, "packages", "widget", "blocked"), { recursive: true });
await mkdir(join(root, "packages", "widget", "node_modules"));
await mkdir(join(root, "sibling"));
await writeFile(join(root, ".gitignore"), "*.tmp\nblocked/\n");
await writeFile(
join(root, "packages", "widget", ".gitignore"),
"/local.js\n!keep.tmp\n!node_modules/\n",
);
await writeFile(
join(root, "packages", "widget", "blocked", ".gitignore"),
"!inside.js\n",
);
const excluded = [
"drop.tmp",
"packages/widget/local.js",
"packages/widget/blocked/inside.js",
];
const included = [
"packages/widget/keep.tmp",
"packages/widget/main.js",
"sibling/local.js",
];
for (const path of [
...excluded,
...included,
"packages/widget/node_modules/dependency.js",
])
await writeFile(join(root, path), "export const value = 1;\n");
const oracle = await execFileOutput("git", [
"-C",
root,
"check-ignore",
"--no-index",
...excluded,
...included,
]);
expect(oracle.stdout.trim().split(/\r?\n/u)).toEqual(excluded);
const graph = await importTree(root);
const files = graph.entries
.filter(({ kind }) => kind === "file")
.map(({ path }) => path);
for (const path of included) expect(files).toContain(path);
for (const path of [
...excluded,
"packages/widget/node_modules/dependency.js",
])
expect(files).not.toContain(path);
expect(graph.exclusions).toContainEqual({
path: "packages/widget/local.js",
entry_kind: "file",
reason: "project-ignored",
pattern: "/local.js",
});
expect(graph.exclusions).toContainEqual({
path: "packages/widget/node_modules",
entry_kind: "directory",
reason: "default-ignored",
pattern: "node_modules/",
});
expect(
await readFile(join(root, "packages", "widget", "keep.tmp"), "utf8"),
).toBe("export const value = 1;\n");
});
it.each([false, true])(
"honors local core.ignorecase=%s against Git's check-ignore oracle",
async (ignoreCase) => {
const root = await createTestTempDirectory("rea-reference-ignore-case-");
await execFileOutput("git", ["init", "--initial-branch=main", root]);
await execFileOutput("git", [
"-C",
root,
"config",
"core.ignorecase",
String(ignoreCase),
]);
await writeFile(join(root, ".gitignore"), "*.TMP\n");
await writeFile(join(root, "upper.TMP"), "upper\n");
await writeFile(join(root, "lower.tmp"), "lower\n");
const oracle = await execFileOutput("git", [
"-C",
root,
"check-ignore",
"--no-index",
"upper.TMP",
"lower.tmp",
]);
const expected = oracle.stdout.trim().split(/\r?\n/u);
const graph = await importTree(root);
expect(
graph.exclusions
.filter(({ reason }) => reason === "project-ignored")
.map(({ path }) => path),
).toEqual([...expected].sort());
expect(graph.entries.some(({ path }) => path === "lower.tmp")).toBe(
!ignoreCase,
);
},
);
@@ -87,37 +87,69 @@ const createPackedRefRepository = async () => {
return { root, looseRef, packedRefs };
};
it("retains failed .gitignore cleanup under the caller's scope", async () => {
const root = await createTestTempDirectory("rea-reference-ignore-owner-");
const path = join(root, ".gitignore");
await writeFile(path, "generated/\n");
it.each([".", "nested"])(
"retains failed %s/.gitignore cleanup under the caller's scope",
async (directory) => {
const root = await createTestTempDirectory("rea-reference-ignore-owner-");
await mkdir(join(root, directory), { recursive: true });
const path = join(root, directory, ".gitignore");
await writeFile(path, "generated/\n");
const resources = new ArtifactResourceScope();
const close = failCloseUntilAllowed(path);
onTestFinished(async () => {
close.allow();
await resources.close().catch(() => undefined);
});
const result = await importReferenceSource(
{
root,
caller: "reference-source-metadata-cleanup-test",
policy: { secretPatterns: [] },
},
resources,
);
expect(result).toMatchObject({
ok: false,
error: {
code: "io",
cleanup: {
resources: [path],
reason: expect.stringContaining("injected metadata close failure"),
},
},
});
expect(close.calls()).toBe(2);
close.allow();
await resources.close();
expect(close.calls()).toBe(3);
},
);
it("retains local Git configuration cleanup before trusting ignore policy", async () => {
const root = await createTestTempDirectory("rea-reference-config-owner-");
await execFileOutput("git", ["init", "--initial-branch=main"], { cwd: root });
const path = join(root, ".git", "config");
const resources = new ArtifactResourceScope();
const close = failCloseUntilAllowed(path);
onTestFinished(async () => {
close.allow();
await resources.close().catch(() => undefined);
});
const result = await importReferenceSource(
{
root,
caller: "reference-source-metadata-cleanup-test",
caller: "reference-source-config-cleanup-test",
policy: { secretPatterns: [] },
},
resources,
);
expect(result).toMatchObject({
ok: false,
error: {
code: "io",
cleanup: {
resources: [path],
reason: expect.stringContaining("injected metadata close failure"),
},
},
error: { code: "io", cleanup: { resources: [path] } },
});
expect(close.calls()).toBe(2);
close.allow();
await resources.close();
expect(close.calls()).toBe(3);
@@ -135,7 +167,7 @@ it("preserves Git metadata cleanup failure and the completed source read", async
const bytes = "export const value = 1;\n";
await writeFile(source, bytes);
await writeFile(join(sourceRoot, ".git"), "gitdir: ../repository/.git\n");
const head = join(sourceRoot, ".git");
const head = join(repository, ".git", "HEAD");
const resources = new ArtifactResourceScope();
const close = failCloseUntilAllowed(head);
onTestFinished(async () => {