feat: release 2.5.1
This commit is contained in:
@@ -2,6 +2,7 @@ import { afterEach, describe, expect, test } from "bun:test";
|
||||
import { execFile } from "node:child_process";
|
||||
import {
|
||||
mkdtemp,
|
||||
mkdir,
|
||||
readFile,
|
||||
readlink,
|
||||
rm,
|
||||
@@ -50,6 +51,80 @@ afterEach(async () => {
|
||||
});
|
||||
|
||||
describe("workspace snapshots", () => {
|
||||
test("snapshots Gitless directories deterministically without secrets", async () => {
|
||||
const root = await temporaryDirectory("kuber-workspace-filesystem-");
|
||||
await writeFile(join(root, "Dockerfile"), "FROM scratch\n");
|
||||
await writeFile(join(root, "app.txt"), "application");
|
||||
await writeFile(join(root, ".env.local"), "SECRET=hidden");
|
||||
await writeFile(join(root, "db_credentials.json"), "hidden");
|
||||
|
||||
const first = await enumerateWorkspace(root);
|
||||
const second = await enumerateWorkspace(root);
|
||||
expect(first).toEqual(second);
|
||||
expect(first.manifest.files.map((file) => file.path)).toEqual([
|
||||
"Dockerfile",
|
||||
"app.txt",
|
||||
]);
|
||||
});
|
||||
|
||||
test("works without Git and conservatively prunes ignored/generated and credential files", async () => {
|
||||
const root = await temporaryDirectory("kuber-workspace-no-git-");
|
||||
await writeFile(join(root, ".gitignore"), "local-only/\n*.generated\nsecrets/\n!secrets/keep.txt\n");
|
||||
await writeFile(join(root, "app.ts"), "source");
|
||||
await mkdir(join(root, "local-only"));
|
||||
await writeFile(join(root, "local-only", "hidden"), "secret");
|
||||
await writeFile(join(root, "cache.generated"), "generated");
|
||||
await writeFile(join(root, "credentials.json"), "credential");
|
||||
await writeFile(join(root, ".env.local"), "SECRET=hidden");
|
||||
await mkdir(join(root, "secrets"));
|
||||
await writeFile(join(root, "secrets/keep.txt"), "must remain excluded");
|
||||
await mkdir(join(root, "services/secrets"), { recursive: true });
|
||||
await writeFile(join(root, "services/secrets/production.yaml"), "secret");
|
||||
await mkdir(join(root, "app_credentials"));
|
||||
await writeFile(join(root, "app_credentials/key.json"), "credential");
|
||||
await mkdir(join(root, "config"));
|
||||
await writeFile(join(root, "config/private.yaml"), "config secret");
|
||||
await mkdir(join(root, "secretary"));
|
||||
await writeFile(join(root, "secretary/notes.txt"), "ordinary directory");
|
||||
await mkdir(join(root, ".next"));
|
||||
await writeFile(join(root, ".next/generated"), "generated");
|
||||
const previousPath = process.env.PATH;
|
||||
try {
|
||||
process.env.PATH = "";
|
||||
const snapshot = await enumerateWorkspace(root);
|
||||
expect(snapshot.manifest.files.map((file) => file.path)).toEqual([
|
||||
".gitignore",
|
||||
"app.ts",
|
||||
"secretary/notes.txt",
|
||||
]);
|
||||
} finally {
|
||||
if (previousPath === undefined) delete process.env.PATH;
|
||||
else process.env.PATH = previousPath;
|
||||
}
|
||||
});
|
||||
|
||||
test("uses conservative filesystem mode for an initialized repo when Git is absent from PATH", async () => {
|
||||
const root = await repository();
|
||||
await writeFile(join(root, ".gitignore"), "secrets/\n!secrets/keep.txt\n");
|
||||
await writeFile(join(root, "source.ts"), "source");
|
||||
await writeFile(join(root, ".env.local"), "SECRET=hidden");
|
||||
await mkdir(join(root, "secrets"));
|
||||
await writeFile(join(root, "secrets/keep.txt"), "hidden");
|
||||
const previousPath = process.env.PATH;
|
||||
try {
|
||||
process.env.PATH = "";
|
||||
const first = await enumerateWorkspace(root);
|
||||
const second = await enumerateWorkspace(root);
|
||||
expect(first).toEqual(second);
|
||||
expect(first.manifest.files.map((file) => file.path)).toEqual([
|
||||
".gitignore", "source.ts",
|
||||
]);
|
||||
} finally {
|
||||
if (previousPath === undefined) delete process.env.PATH;
|
||||
else process.env.PATH = previousPath;
|
||||
}
|
||||
});
|
||||
|
||||
test("captures working tracked, untracked, and ignored dotenv files deterministically", async () => {
|
||||
const root = await repository();
|
||||
await writeFile(join(root, ".gitignore"), "ignored*\n.env*\nsub/.env*\n");
|
||||
@@ -139,6 +214,30 @@ describe("workspace snapshots", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("allows ignored special files and prunes ignored directories", async () => {
|
||||
const root = await repository();
|
||||
await writeFile(join(root, ".gitignore"), "ignored-pipe\nignored-dir/\n");
|
||||
await run("mkfifo", [join(root, "ignored-pipe")]);
|
||||
await run("mkdir", [join(root, "ignored-dir")]);
|
||||
await run("mkfifo", [join(root, "ignored-dir/pipe")]);
|
||||
|
||||
await expect(enumerateWorkspace(root)).resolves.toMatchObject({
|
||||
manifest: { files: [{ path: ".gitignore" }] },
|
||||
});
|
||||
});
|
||||
|
||||
test("protects dotenv special files even when ignored", async () => {
|
||||
const root = await repository();
|
||||
await writeFile(join(root, ".gitignore"), "*.pipe\n!keep.pipe\nsub/\n");
|
||||
await run("mkfifo", [join(root, "blocked.pipe")]);
|
||||
await expect(enumerateWorkspace(root)).resolves.toBeDefined();
|
||||
|
||||
await run("mkfifo", [join(root, ".env.pipe")]);
|
||||
await expect(enumerateWorkspace(root)).rejects.toThrow(
|
||||
"Special files are not allowed in workspaces: .env.pipe",
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects traversal, unsorted manifests, ancestor collisions, and corrupt blobs", async () => {
|
||||
expect(() => validateWorkspacePath("../secret")).toThrow(
|
||||
"Unsafe workspace path",
|
||||
|
||||
Reference in New Issue
Block a user