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
27 changes: 27 additions & 0 deletions tools/hygiene/check-bash-retirement-inventory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ describe("buildInventoryReport", () => {
expect(report.allowlistIntegrity.duplicateEntries).toEqual([]);
expect(report.allowlistIntegrity.orderViolations).toEqual([]);
expect(report.allowlistIntegrity.uncategorizedEntries).toEqual([]);
expect(report.allowlistIntegrity.staleCategoryEntries).toEqual([]);
expect(report.retained).toHaveLength(EXPECTED_RETAINED_SHELL.length);
expect(report.drift.unexpected).toEqual([]);
expect(report.drift.missingRetained).toEqual([]);
Expand Down Expand Up @@ -72,6 +73,7 @@ describe("buildInventoryReport", () => {
expect(report.allowlistIntegrity.duplicateEntries).toEqual([duplicate]);
expect(report.allowlistIntegrity.orderViolations).toEqual([]);
expect(report.allowlistIntegrity.uncategorizedEntries).toEqual([]);
expect(report.allowlistIntegrity.staleCategoryEntries).toEqual([]);
expect(report.drift.unexpected).toEqual([]);
expect(report.drift.missingRetained).toEqual([]);
});
Expand All @@ -84,6 +86,20 @@ describe("buildInventoryReport", () => {
expect(report.allowlistIntegrity.duplicateEntries).toEqual([]);
expect(report.allowlistIntegrity.orderViolations).toEqual([{ index: 1, previous: second, current: first }]);
expect(report.allowlistIntegrity.uncategorizedEntries).toEqual([]);
expect(report.allowlistIntegrity.staleCategoryEntries).toEqual([]);
expect(report.drift.unexpected).toEqual([]);
expect(report.drift.missingRetained).toEqual([]);
});

test("flags category metadata entries that are no longer retained", () => {
const [stale, rest] = splitExpectedRetained();
const report = buildInventoryReport(rest, rest);

expect(hasDrift(report)).toBe(true);
expect(report.allowlistIntegrity.duplicateEntries).toEqual([]);
expect(report.allowlistIntegrity.orderViolations).toEqual([]);
expect(report.allowlistIntegrity.uncategorizedEntries).toEqual([]);
expect(report.allowlistIntegrity.staleCategoryEntries).toEqual([stale]);
expect(report.drift.unexpected).toEqual([]);
expect(report.drift.missingRetained).toEqual([]);
});
Expand Down Expand Up @@ -161,4 +177,15 @@ describe("renderReport", () => {
expect(rendered).toContain(duplicate);
expect(rendered).not.toContain("## Unexpected non-Lean shell files");
});

test("renders stale category map entries as allowlist integrity errors", () => {
const [stale, rest] = splitExpectedRetained();
const rendered = renderReport(buildInventoryReport(rest, rest));

expect(rendered).toContain("## Retained shell allowlist integrity errors");
expect(rendered).toContain("free of stale category metadata");
expect(rendered).toContain("### Stale category entries");
expect(rendered).toContain(stale);
expect(rendered).not.toContain("## Unexpected non-Lean shell files");
});
});
21 changes: 19 additions & 2 deletions tools/hygiene/check-bash-retirement-inventory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ interface AllowlistIntegrity {
readonly duplicateEntries: readonly string[];
readonly orderViolations: readonly AllowlistOrderViolation[];
readonly uncategorizedEntries: readonly string[];
readonly staleCategoryEntries: readonly string[];
}

export type RetainedShellCategory =
Expand Down Expand Up @@ -180,6 +181,7 @@ export const trackedNonLeanBashFilesFromGit = trackedNonLeanShellFilesFromGit;

function inspectAllowlistIntegrity(expectedRetained: readonly string[]): AllowlistIntegrity {
const counts = new Map<string, number>();
const expectedSet = new Set(expectedRetained);
const orderViolations: AllowlistOrderViolation[] = [];
const uncategorizedEntries = new Set<string>();

Expand All @@ -200,18 +202,24 @@ function inspectAllowlistIntegrity(expectedRetained: readonly string[]): Allowli
.map(([file]) => file)
.sort((a, b) => a.localeCompare(b));

const staleCategoryEntries = Object.keys(RETAINED_SHELL_CATEGORY_BY_FILE)
.filter((file) => !expectedSet.has(file))
.sort((a, b) => a.localeCompare(b));

return {
duplicateEntries,
orderViolations,
uncategorizedEntries: [...uncategorizedEntries].sort((a, b) => a.localeCompare(b)),
staleCategoryEntries,
};
}

function hasAllowlistIntegrityDrift(integrity: AllowlistIntegrity): boolean {
return (
integrity.duplicateEntries.length > 0 ||
integrity.orderViolations.length > 0 ||
integrity.uncategorizedEntries.length > 0
integrity.uncategorizedEntries.length > 0 ||
integrity.staleCategoryEntries.length > 0
);
}

Expand Down Expand Up @@ -282,6 +290,7 @@ export function renderReport(report: InventoryReport): string {
lines.push(`allowlist_duplicates: ${String(report.allowlistIntegrity.duplicateEntries.length)}`);
lines.push(`allowlist_order_violations: ${String(report.allowlistIntegrity.orderViolations.length)}`);
lines.push(`allowlist_uncategorized: ${String(report.allowlistIntegrity.uncategorizedEntries.length)}`);
lines.push(`allowlist_stale_category_entries: ${String(report.allowlistIntegrity.staleCategoryEntries.length)}`);
lines.push(`unexpected: ${String(report.drift.unexpected.length)}`);
lines.push(`missing_retained: ${String(report.drift.missingRetained.length)}`);
lines.push("");
Expand All @@ -298,7 +307,9 @@ export function renderReport(report: InventoryReport): string {
if (hasAllowlistIntegrityDrift(report.allowlistIntegrity)) {
lines.push("## Retained shell allowlist integrity errors");
lines.push("");
lines.push("The retained shell allowlist must be unique and sorted before repo shell drift is classified.");
lines.push(
"The retained shell allowlist must be unique, sorted, fully categorized, and free of stale category metadata before repo shell drift is classified.",
);
lines.push("");
if (report.allowlistIntegrity.duplicateEntries.length > 0) {
lines.push("### Duplicate entries");
Expand All @@ -320,6 +331,12 @@ export function renderReport(report: InventoryReport): string {
for (const file of report.allowlistIntegrity.uncategorizedEntries) lines.push(`- ${file}`);
lines.push("");
}
if (report.allowlistIntegrity.staleCategoryEntries.length > 0) {
lines.push("### Stale category entries");
lines.push("");
for (const file of report.allowlistIntegrity.staleCategoryEntries) lines.push(`- ${file}`);
lines.push("");
Comment thread
AceHack marked this conversation as resolved.
}
return `${lines.join("\n")}\n`;
}
if (report.drift.unexpected.length > 0) {
Expand Down
Loading