Skip to content
Closed
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
13 changes: 6 additions & 7 deletions extensions/realtime-aec/src/browser-audio-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,23 +150,22 @@ export class BrowserAudioDriver implements AudioDriver {
void this.ensureStarted().catch((err) =>
log.error({ err: String(err) }, "ensureStarted (capture) failed"),
);
const self = this;
const stream: AsyncIterable<Buffer> = {
[Symbol.asyncIterator]() {
[Symbol.asyncIterator]: () => {
return {
next(): Promise<IteratorResult<Buffer>> {
if (self.captureStopped) {
next: (): Promise<IteratorResult<Buffer>> => {
if (this.captureStopped) {
return Promise.resolve({ value: undefined, done: true });
}
const queued = self.captureBuf.shift();
const queued = this.captureBuf.shift();
if (queued) {
return Promise.resolve({ value: queued, done: false });
}
return new Promise<IteratorResult<Buffer>>((resolve) => {
self.capturePending.push({ resolve });
this.capturePending.push({ resolve });
});
},
return(): Promise<IteratorResult<Buffer>> {
return: (): Promise<IteratorResult<Buffer>> => {
return Promise.resolve({ value: undefined, done: true });
},
};
Expand Down
2 changes: 1 addition & 1 deletion packages/realtime/src/backend/stepfun-stateless.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ export class StepfunStatelessAdapter implements BackendAdapter {
let msg: any;
try {
msg = JSON.parse(raw);
} catch (e) {
} catch {
this.log.warn({ raw: raw.slice(0, 200) }, "non-json message");
return;
}
Expand Down
5 changes: 2 additions & 3 deletions packages/realtime/src/vad/cli-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,8 @@ function editDistance(a: string, b: string): number {
bl = b.length;
if (al === 0) return bl;
if (bl === 0) return al;
let prev = new Array(bl + 1),
curr = new Array(bl + 1);
for (let j = 0; j <= bl; j++) prev[j] = j;
let prev = Array.from({ length: bl + 1 }, (_, index) => index),
curr = Array.from({ length: bl + 1 }, () => 0);
for (let i = 1; i <= al; i++) {
curr[0] = i;
for (let j = 1; j <= bl; j++) {
Expand Down
5 changes: 2 additions & 3 deletions packages/realtime/src/vad/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,8 @@ function editDistance(a: string, b: string): number {
if (al === 0) return bl;
if (bl === 0) return al;

let prev = new Array(bl + 1);
let curr = new Array(bl + 1);
for (let j = 0; j <= bl; j++) prev[j] = j;
let prev = Array.from({ length: bl + 1 }, (_, index) => index);
let curr = Array.from({ length: bl + 1 }, () => 0);

for (let i = 1; i <= al; i++) {
curr[0] = i;
Expand Down
236 changes: 129 additions & 107 deletions packages/utils/src/path.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ async function makeWorkspace(): Promise<string> {
return fs.realpath(dir);
}

// Windows symlink creation requires Developer Mode or elevated privileges.
// Linux/macOS CI still exercises these resolver paths.
const symlinkIt = process.platform === "win32" ? it.skip : it;

describe("resolveExistingPathInWorkspace", () => {
it("returns the real path of an existing file inside the workspace", async () => {
const root = await makeWorkspace();
Expand All @@ -232,23 +236,26 @@ describe("resolveExistingPathInWorkspace", () => {
}
});

it("resolves a symlink target that lives inside the workspace", async () => {
const root = await makeWorkspace();
try {
await fs.writeFile(path.join(root, "real.txt"), "data");
await fs.symlink(
path.join(root, "real.txt"),
path.join(root, "link.txt"),
);
const result = await resolveExistingPathInWorkspace(root, "link.txt");
// Returns the resolved real target.
expect(result).toBe(path.join(root, "real.txt"));
} finally {
await fs.rm(root, { recursive: true });
}
});

it("throws when a symlink points outside the workspace", async () => {
symlinkIt(
"resolves a symlink target that lives inside the workspace",
async () => {
const root = await makeWorkspace();
try {
await fs.writeFile(path.join(root, "real.txt"), "data");
await fs.symlink(
path.join(root, "real.txt"),
path.join(root, "link.txt"),
);
const result = await resolveExistingPathInWorkspace(root, "link.txt");
// Returns the resolved real target.
expect(result).toBe(path.join(root, "real.txt"));
} finally {
await fs.rm(root, { recursive: true });
}
},
);

symlinkIt("throws when a symlink points outside the workspace", async () => {
const root = await makeWorkspace();
const outside = await makeWorkspace();
try {
Expand All @@ -266,28 +273,31 @@ describe("resolveExistingPathInWorkspace", () => {
}
});

it("throws when the symlink's parent dir escapes the workspace", async () => {
const root = await makeWorkspace();
const outside = await makeWorkspace();
try {
// 'sub' inside root is a symlink to an outside dir; addressing
// sub/inner.txt makes the symlink parent check fail.
await fs.mkdir(path.join(outside, "real-dir"));
await fs.writeFile(path.join(outside, "real-dir", "inner.txt"), "y");
await fs.symlink(
path.join(outside, "real-dir"),
path.join(root, "sub"),
"dir",
);
// 'sub' itself is a symlink whose realpath is outside.
await expect(resolveExistingPathInWorkspace(root, "sub")).rejects.toThrow(
"Path escapes workspace root",
);
} finally {
await fs.rm(root, { recursive: true });
await fs.rm(outside, { recursive: true });
}
});
symlinkIt(
"throws when the symlink's parent dir escapes the workspace",
async () => {
const root = await makeWorkspace();
const outside = await makeWorkspace();
try {
// 'sub' inside root is a symlink to an outside dir; addressing
// sub/inner.txt makes the symlink parent check fail.
await fs.mkdir(path.join(outside, "real-dir"));
await fs.writeFile(path.join(outside, "real-dir", "inner.txt"), "y");
await fs.symlink(
path.join(outside, "real-dir"),
path.join(root, "sub"),
"dir",
);
// 'sub' itself is a symlink whose realpath is outside.
await expect(
resolveExistingPathInWorkspace(root, "sub"),
).rejects.toThrow("Path escapes workspace root");
} finally {
await fs.rm(root, { recursive: true });
await fs.rm(outside, { recursive: true });
}
},
);

it("rejects for a non-existent path (ENOENT from realpath)", async () => {
const root = await makeWorkspace();
Expand All @@ -302,7 +312,7 @@ describe("resolveExistingPathInWorkspace", () => {
});

describe("resolveAddressedExistingPathInWorkspace", () => {
it("returns the addressed (non-real) resolved path", async () => {
symlinkIt("returns the addressed (non-real) resolved path", async () => {
const root = await makeWorkspace();
try {
await fs.writeFile(path.join(root, "real.txt"), "data");
Expand All @@ -321,7 +331,7 @@ describe("resolveAddressedExistingPathInWorkspace", () => {
}
});

it("throws when symlink escapes workspace", async () => {
symlinkIt("throws when symlink escapes workspace", async () => {
const root = await makeWorkspace();
const outside = await makeWorkspace();
try {
Expand All @@ -341,7 +351,7 @@ describe("resolveAddressedExistingPathInWorkspace", () => {
});

describe("resolveAddressedPathEntryInWorkspace", () => {
it("returns the resolved path early for a symlink entry", async () => {
symlinkIt("returns the resolved path early for a symlink entry", async () => {
const root = await makeWorkspace();
try {
await fs.writeFile(path.join(root, "real.txt"), "data");
Expand Down Expand Up @@ -373,27 +383,30 @@ describe("resolveAddressedPathEntryInWorkspace", () => {
}
});

it("returns resolved symlink even if it escapes (parent check passes)", async () => {
const root = await makeWorkspace();
const outside = await makeWorkspace();
try {
await fs.writeFile(path.join(outside, "secret.txt"), "x");
// Symlink directly in root; its parent (root) is in the workspace, so the
// parent check passes and the symlink branch returns early.
await fs.symlink(
path.join(outside, "secret.txt"),
path.join(root, "link.txt"),
);
const result = await resolveAddressedPathEntryInWorkspace(
root,
"link.txt",
);
expect(result).toBe(path.join(root, "link.txt"));
} finally {
await fs.rm(root, { recursive: true });
await fs.rm(outside, { recursive: true });
}
});
symlinkIt(
"returns resolved symlink even if it escapes (parent check passes)",
async () => {
const root = await makeWorkspace();
const outside = await makeWorkspace();
try {
await fs.writeFile(path.join(outside, "secret.txt"), "x");
// Symlink directly in root; its parent (root) is in the workspace, so the
// parent check passes and the symlink branch returns early.
await fs.symlink(
path.join(outside, "secret.txt"),
path.join(root, "link.txt"),
);
const result = await resolveAddressedPathEntryInWorkspace(
root,
"link.txt",
);
expect(result).toBe(path.join(root, "link.txt"));
} finally {
await fs.rm(root, { recursive: true });
await fs.rm(outside, { recursive: true });
}
},
);
});

describe("resolveWritablePathInWorkspace", () => {
Expand Down Expand Up @@ -421,50 +434,59 @@ describe("resolveWritablePathInWorkspace", () => {
}
});

it("follows a symlinked parent dir to an existing location inside workspace", async () => {
const root = await makeWorkspace();
try {
await fs.mkdir(path.join(root, "actual"));
await fs.symlink(path.join(root, "actual"), path.join(root, "linkdir"));
const result = await resolveWritablePathInWorkspace(
root,
"linkdir/file.txt",
);
// Nearest existing path is the symlink's real target, then file.txt.
expect(result).toBe(path.join(root, "actual", "file.txt"));
} finally {
await fs.rm(root, { recursive: true });
}
});

it("throws when the nearest existing ancestor escapes the workspace", async () => {
const root = await makeWorkspace();
const outside = await makeWorkspace();
try {
await fs.symlink(outside, path.join(root, "escape"), "dir");
await expect(
resolveWritablePathInWorkspace(root, "escape/child.txt"),
).rejects.toThrow("Path escapes workspace root");
} finally {
await fs.rm(root, { recursive: true });
await fs.rm(outside, { recursive: true });
}
});

it("rethrows non-ENOENT errors from realpath (ELOOP cycle)", async () => {
const root = await makeWorkspace();
try {
// a -> b, b -> a: realpath fails with ELOOP, which is not ENOENT, so
// findNearestExistingPath rethrows it (covers the non-ENOENT branch).
await fs.symlink(path.join(root, "b"), path.join(root, "a"));
await fs.symlink(path.join(root, "a"), path.join(root, "b"));
await expect(
resolveWritablePathInWorkspace(root, "a/child.txt"),
).rejects.toThrow(/ELOOP|Symlink cycle|escapes workspace/);
} finally {
await fs.rm(root, { recursive: true });
}
});
symlinkIt(
"follows a symlinked parent dir to an existing location inside workspace",
async () => {
const root = await makeWorkspace();
try {
await fs.mkdir(path.join(root, "actual"));
await fs.symlink(path.join(root, "actual"), path.join(root, "linkdir"));
const result = await resolveWritablePathInWorkspace(
root,
"linkdir/file.txt",
);
// Nearest existing path is the symlink's real target, then file.txt.
expect(result).toBe(path.join(root, "actual", "file.txt"));
} finally {
await fs.rm(root, { recursive: true });
}
},
);

symlinkIt(
"throws when the nearest existing ancestor escapes the workspace",
async () => {
const root = await makeWorkspace();
const outside = await makeWorkspace();
try {
await fs.symlink(outside, path.join(root, "escape"), "dir");
await expect(
resolveWritablePathInWorkspace(root, "escape/child.txt"),
).rejects.toThrow("Path escapes workspace root");
} finally {
await fs.rm(root, { recursive: true });
await fs.rm(outside, { recursive: true });
}
},
);

symlinkIt(
"rethrows non-ENOENT errors from realpath (ELOOP cycle)",
async () => {
const root = await makeWorkspace();
try {
// a -> b, b -> a: realpath fails with ELOOP, which is not ENOENT, so
// findNearestExistingPath rethrows it (covers the non-ENOENT branch).
await fs.symlink(path.join(root, "b"), path.join(root, "a"));
await fs.symlink(path.join(root, "a"), path.join(root, "b"));
await expect(
resolveWritablePathInWorkspace(root, "a/child.txt"),
).rejects.toThrow(/ELOOP|Symlink cycle|escapes workspace/);
} finally {
await fs.rm(root, { recursive: true });
}
},
);

it("resolves a path whose ancestor chain walks up to the workspace root", async () => {
const root = await makeWorkspace();
Expand Down
9 changes: 6 additions & 3 deletions packages/utils/src/shell.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import os from "node:os";
import { enforceOutputLimit, runShell } from "./shell.js";

const BIG_LIMIT = 1_000_000;
const longRunningCommand = `${JSON.stringify(
process.execPath,
)} -e "setTimeout(() => {}, 5000)"`;

// Some runShell cases assert POSIX shell semantics (`;` chaining, `exit N`,
// `for`/`seq`) that cmd.exe does not interpret. Skip those on Windows; the
Expand Down Expand Up @@ -151,7 +154,7 @@ describe("runShell", () => {
});

it("times out a long-running command and kills it", async () => {
const result = await runShell("sleep 5", {
const result = await runShell(longRunningCommand, {
cwd,
timeoutMs: 100,
outputLimit: BIG_LIMIT,
Expand All @@ -164,7 +167,7 @@ describe("runShell", () => {

it("interrupts a running command when the signal aborts mid-flight", async () => {
const controller = new AbortController();
const promise = runShell("sleep 5", {
const promise = runShell(longRunningCommand, {
cwd,
timeoutMs: 10_000,
outputLimit: BIG_LIMIT,
Expand All @@ -190,7 +193,7 @@ describe("runShell", () => {
});

it("returns exitCode -1 when the close code is null (killed by timeout)", async () => {
const result = await runShell("sleep 5", {
const result = await runShell(longRunningCommand, {
cwd,
timeoutMs: 50,
outputLimit: BIG_LIMIT,
Expand Down
Loading
Loading