@openai/agents-core
Version:
The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.
160 lines • 6.27 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.clearDirectory = clearDirectory;
exports.shouldSkipSnapshotPath = shouldSkipSnapshotPath;
exports.readStableSnapshotDirectoryEntries = readStableSnapshotDirectoryEntries;
exports.readStableSnapshotFile = readStableSnapshotFile;
exports.writeStableSnapshotFile = writeStableSnapshotFile;
exports.assertSafeSnapshotDestinationPath = assertSafeSnapshotDestinationPath;
const node_fs_1 = require("node:fs");
const promises_1 = require("node:fs/promises");
const node_path_1 = require("node:path");
const errors_1 = require("../../../errors.js");
const hostPath_1 = require("../../shared/hostPath.js");
const SNAPSHOT_FILE_READ_FLAGS = node_fs_1.constants.O_RDONLY | node_fs_1.constants.O_NOFOLLOW;
const SNAPSHOT_FILE_WRITE_FLAGS = node_fs_1.constants.O_WRONLY |
node_fs_1.constants.O_CREAT |
node_fs_1.constants.O_TRUNC |
node_fs_1.constants.O_NOFOLLOW;
async function clearDirectory(destinationRoot) {
await assertSafeSnapshotDestinationPath(destinationRoot, destinationRoot);
const entries = await (0, promises_1.readdir)(destinationRoot);
await Promise.all(entries.map(async (entry) => {
await (0, promises_1.rm)((0, node_path_1.join)(destinationRoot, entry), { recursive: true, force: true });
}));
}
function shouldSkipSnapshotPath(relativePath, excludedLogicalPaths) {
for (const excluded of excludedLogicalPaths) {
if (excluded === '' ||
relativePath === excluded ||
relativePath.startsWith(`${excluded}/`)) {
return true;
}
}
return false;
}
async function readStableSnapshotDirectoryEntries(sourceRoot, expectedSourceStats) {
const sourceStats = await (0, promises_1.lstat)(sourceRoot);
if (!sourceStats.isDirectory() ||
(expectedSourceStats &&
!sameFilesystemEntry(sourceStats, expectedSourceStats))) {
throw snapshotPathChangedError(sourceRoot);
}
const entries = await (0, promises_1.readdir)(sourceRoot, { withFileTypes: true });
await assertStableSnapshotDirectory(sourceRoot, sourceStats);
return entries;
}
async function assertStableSnapshotDirectory(sourceRoot, expectedSourceStats) {
const sourceStats = await (0, promises_1.lstat)(sourceRoot);
if (!sourceStats.isDirectory() ||
!sameFilesystemEntry(sourceStats, expectedSourceStats)) {
throw snapshotPathChangedError(sourceRoot);
}
}
async function readStableSnapshotFile(sourcePath, expectedSourceStats) {
const sourceStats = await (0, promises_1.lstat)(sourcePath);
if (!sourceStats.isFile() ||
!sameFilesystemEntry(sourceStats, expectedSourceStats)) {
throw snapshotPathChangedError(sourcePath);
}
let handle;
try {
handle = await (0, promises_1.open)(sourcePath, SNAPSHOT_FILE_READ_FLAGS);
}
catch (error) {
if (isPathChangedError(error)) {
throw snapshotPathChangedError(sourcePath);
}
throw error;
}
try {
const openedStats = await handle.stat();
if (!openedStats.isFile() ||
!sameFilesystemEntry(openedStats, sourceStats)) {
throw snapshotPathChangedError(sourcePath);
}
return await handle.readFile();
}
finally {
await handle.close();
}
}
async function writeStableSnapshotFile(destinationRoot, destinationPath, content, mode) {
await assertSafeSnapshotDestinationPath(destinationRoot, destinationPath);
let handle;
try {
handle = await (0, promises_1.open)(destinationPath, SNAPSHOT_FILE_WRITE_FLAGS, mode);
}
catch (error) {
if (isPathChangedError(error)) {
throw snapshotPathChangedError(destinationPath);
}
throw error;
}
try {
await handle.writeFile(content);
if (mode !== undefined) {
await handle.chmod(mode);
}
}
finally {
await handle.close();
}
await assertSafeSnapshotDestinationPath(destinationRoot, destinationPath);
}
async function assertSafeSnapshotDestinationPath(destinationRoot, destinationPath) {
const rootStats = await (0, promises_1.lstat)(destinationRoot).catch(() => undefined);
if (!rootStats?.isDirectory() || rootStats.isSymbolicLink()) {
throw snapshotPathChangedError(destinationRoot);
}
const rootRealPath = await (0, promises_1.realpath)(destinationRoot).catch(() => {
throw snapshotPathChangedError(destinationRoot);
});
const relativeDestination = (0, node_path_1.relative)(destinationRoot, destinationPath);
if ((0, hostPath_1.relativeHostPathEscapesRoot)(relativeDestination)) {
throw snapshotPathChangedError(destinationPath);
}
if (relativeDestination === '') {
return;
}
let current = destinationRoot;
for (const segment of relativeDestination.split(node_path_1.sep)) {
if (!segment) {
continue;
}
current = (0, node_path_1.join)(current, segment);
const currentStats = await (0, promises_1.lstat)(current).catch((error) => {
if (error.code === 'ENOENT') {
return undefined;
}
throw error;
});
if (!currentStats) {
return;
}
if (currentStats.isSymbolicLink()) {
throw snapshotPathChangedError(current);
}
const currentRealPath = await (0, promises_1.realpath)(current).catch(() => {
throw snapshotPathChangedError(current);
});
if (!(0, hostPath_1.isHostPathWithinRoot)(rootRealPath, currentRealPath)) {
throw snapshotPathChangedError(current);
}
}
}
function snapshotPathChangedError(path) {
return new errors_1.UserError(`Sandbox snapshot path changed while copying: ${path}`);
}
function isPathChangedError(error) {
return (typeof error === 'object' &&
error !== null &&
'code' in error &&
(error.code === 'ELOOP' ||
error.code === 'ENOENT' ||
error.code === 'ENOTDIR'));
}
function sameFilesystemEntry(left, right) {
return left.dev === right.dev && left.ino === right.ino;
}
//# sourceMappingURL=snapshotFilesystem.js.map