UNPKG

@openai/agents-core

Version:

The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.

1,589 lines • 71.6 kB
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NON_RESUMABLE_MOUNT_AUTHORITY_KEY = exports.REDACTED_MOUNT_CREDENTIAL_PATHS_KEY = void 0;
exports.isMountCredentialFileEnvironmentName = isMountCredentialFileEnvironmentName;
exports.markSandboxSessionStateUnsafe = markSandboxSessionStateUnsafe;
exports.isSandboxSessionStateUnsafe = isSandboxSessionStateUnsafe;
exports.assertSandboxSessionStateUsable = assertSandboxSessionStateUsable;
exports.withExclusiveSandboxManifestMutation = withExclusiveSandboxManifestMutation;
exports.withExclusiveSandboxStateInspection = withExclusiveSandboxStateInspection;
exports.captureSandboxStateGeneration = captureSandboxStateGeneration;
exports.assertSandboxStateGenerationUnchanged = assertSandboxStateGenerationUnchanged;
exports.configuredMountCredentialFields = configuredMountCredentialFields;
exports.manifestHasInContainerMounts = manifestHasInContainerMounts;
exports.manifestHasNonResumableMountAuthority = manifestHasNonResumableMountAuthority;
exports.persistedManifestRecordHasNonResumableMountAuthority = persistedManifestRecordHasNonResumableMountAuthority;
exports.validateMountCredentialBoundaries = validateMountCredentialBoundaries;
exports.validateMountEnvironmentCredentialBoundaries = validateMountEnvironmentCredentialBoundaries;
exports.resolveAndValidateMountEnvironment = resolveAndValidateMountEnvironment;
exports.validateMountCredentialBoundariesAtEffectivePath = validateMountCredentialBoundariesAtEffectivePath;
exports.copyValidatedMountEffectivePaths = copyValidatedMountEffectivePaths;
exports.sanitizeMountCredentialEnvironmentForPersistence = sanitizeMountCredentialEnvironmentForPersistence;
exports.serializeMountCredentialRedactionMetadata = serializeMountCredentialRedactionMetadata;
exports.deserializeMountCredentialRedactionMetadata = deserializeMountCredentialRedactionMetadata;
exports.sanitizePersistedManifestRecord = sanitizePersistedManifestRecord;
exports.recordPendingMountCredentialPaths = recordPendingMountCredentialPaths;
exports.validateMountCredentialRedactionPaths = validateMountCredentialRedactionPaths;
exports.recordPersistedMountTopology = recordPersistedMountTopology;
exports.rebindPersistedMountCredentials = rebindPersistedMountCredentials;
exports.recordLiveMountCredentialAuthority = recordLiveMountCredentialAuthority;
exports.captureLiveMountRuntimeAuthority = captureLiveMountRuntimeAuthority;
exports.liveMountRuntimeAuthorityMatches = liveMountRuntimeAuthorityMatches;
exports.captureLiveMountCredentialAuthority = captureLiveMountCredentialAuthority;
exports.captureLiveMountEnvironmentAuthority = captureLiveMountEnvironmentAuthority;
exports.captureLiveMountCredentialAuthorityIfAbsent = captureLiveMountCredentialAuthorityIfAbsent;
exports.copyTrustedMountCredentialRebindProvenance = copyTrustedMountCredentialRebindProvenance;
exports.liveMountCredentialAuthorityMatches = liveMountCredentialAuthorityMatches;
exports.assertLiveMountCredentialAuthorityMatches = assertLiveMountCredentialAuthorityMatches;
exports.liveMountEnvironmentAuthorityMatches = liveMountEnvironmentAuthorityMatches;
exports.assertLiveMountEnvironmentAuthorityMatches = assertLiveMountEnvironmentAuthorityMatches;
exports.assertExistingMountTopologyPreserved = assertExistingMountTopologyPreserved;
exports.assertMountCredentialsRebound = assertMountCredentialsRebound;
exports.redactMountCredentialsForPersistence = redactMountCredentialsForPersistence;
exports.mountCredentialFileReferences = mountCredentialFileReferences;
exports.validateMountCredentialFileEffectivePaths = validateMountCredentialFileEffectivePaths;
exports.mountCredentialEnvironmentForEntry = mountCredentialEnvironmentForEntry;
const errors_1 = require("../errors.js");
const errors_2 = require("./errors.js");
const entries_1 = require("./entries/index.js");
const manifest_1 = require("./manifest.js");
const stableJson_1 = require("./shared/stableJson.js");
const credentials_1 = require("./shared/credentials.js");
const posixPath_1 = require("./shared/posixPath.js");
const typedMountConfig_1 = require("./shared/typedMountConfig.js");
exports.REDACTED_MOUNT_CREDENTIAL_PATHS_KEY = '__openaiAgentsRedactedMountCredentialPaths';
exports.NON_RESUMABLE_MOUNT_AUTHORITY_KEY = '__openaiAgentsNonResumableMountAuthority';
const CREDENTIAL_FIELDS_BY_MOUNT_TYPE = {
    s3_mount: ['accessKeyId', 'secretAccessKey', 'sessionToken'],
    gcs_mount: [
        'accessId',
        'secretAccessKey',
        'serviceAccountCredentials',
        'serviceAccountFile',
        'accessToken',
    ],
    r2_mount: ['accessKeyId', 'secretAccessKey'],
    azure_blob_mount: ['accountKey', 'identityClientId'],
    box_mount: [
        'clientSecret',
        'accessToken',
        'token',
        'boxConfigFile',
        'configCredentials',
    ],
};
const ALL_CREDENTIAL_FIELDS = [
    ...new Set(Object.values(CREDENTIAL_FIELDS_BY_MOUNT_TYPE).flat()),
];
const STRATEGY_CREDENTIAL_FIELDS = [
    'mountStrategy.driverOptions',
    'mountStrategy.credentialEnvironment',
    'mountStrategy.pattern.configFilePath',
    'mountStrategy.pattern.args',
    'mountStrategy.pattern.extraArgs',
    'mountStrategy.pattern.command',
    'mountStrategy.pattern.options.extraOptions',
];
const INSIDE_SANDBOX_STRATEGIES = new Set([
    'in_container',
    'e2b_cloud_bucket',
    'daytona_cloud_bucket',
    'vercel_cloud_bucket',
    'blaxel_cloud_bucket',
]);
const ENVIRONMENT_CREDENTIAL_STRATEGIES = new Set([
    'in_container',
    'e2b_cloud_bucket',
    'daytona_cloud_bucket',
    'vercel_cloud_bucket',
]);
const OUTSIDE_SANDBOX_STRATEGIES = new Set([
    'docker_volume',
    'local_bind',
    'modal_cloud_bucket',
    'cloudflare_bucket_mount',
    'blaxel_drive',
]);
const RCLONE_STRATEGY_TYPES = [
    'in_container',
    'e2b_cloud_bucket',
    'daytona_cloud_bucket',
];
const IN_CONTAINER_MOUNT_CREDENTIAL_CAPABILITIES = [
    {
        strategyTypes: RCLONE_STRATEGY_TYPES,
        provider: 's3',
        patternType: 'rclone',
        mountScopedCredentialFields: [
            'accessKeyId',
            'secretAccessKey',
            'sessionToken',
        ],
        broadCredentialFields: [
            'mountStrategy.credentialEnvironment',
            'mountStrategy.pattern.configFilePath',
        ],
        enablesBroadCredentialDiscovery: true,
    },
    {
        strategyTypes: RCLONE_STRATEGY_TYPES,
        provider: 'r2',
        patternType: 'rclone',
        mountScopedCredentialFields: ['accessKeyId', 'secretAccessKey'],
        broadCredentialFields: [
            'mountStrategy.credentialEnvironment',
            'mountStrategy.pattern.configFilePath',
        ],
        enablesBroadCredentialDiscovery: true,
    },
    {
        strategyTypes: RCLONE_STRATEGY_TYPES,
        provider: 'gcs',
        patternType: 'rclone',
        mountScopedCredentialFields: [
            'accessId',
            'secretAccessKey',
            'serviceAccountCredentials',
            'accessToken',
        ],
        broadCredentialFields: [
            'serviceAccountFile',
            'mountStrategy.credentialEnvironment',
            'mountStrategy.pattern.configFilePath',
        ],
        enablesBroadCredentialDiscovery: true,
    },
    {
        strategyTypes: RCLONE_STRATEGY_TYPES,
        provider: 'azure_blob',
        patternType: 'rclone',
        mountScopedCredentialFields: ['accountKey'],
        broadCredentialFields: [
            'identityClientId',
            'managedIdentity',
            'mountStrategy.credentialEnvironment',
            'mountStrategy.pattern.configFilePath',
        ],
        enablesBroadCredentialDiscovery: true,
    },
    {
        strategyTypes: RCLONE_STRATEGY_TYPES,
        provider: 'box',
        patternType: 'rclone',
        mountScopedCredentialFields: [
            'clientSecret',
            'accessToken',
            'token',
            'configCredentials',
        ],
        broadCredentialFields: [
            'boxConfigFile',
            'mountStrategy.credentialEnvironment',
            'mountStrategy.pattern.configFilePath',
        ],
    },
    {
        strategyTypes: ['in_container'],
        provider: 's3',
        patternType: 'mountpoint',
        mountScopedCredentialFields: [
            'accessKeyId',
            'secretAccessKey',
            'sessionToken',
        ],
        broadCredentialFields: ['mountStrategy.credentialEnvironment'],
        enablesBroadCredentialDiscovery: true,
    },
    {
        strategyTypes: ['in_container'],
        provider: 'gcs',
        patternType: 'mountpoint',
        mountScopedCredentialFields: ['accessId', 'secretAccessKey'],
        broadCredentialFields: [],
    },
    {
        strategyTypes: ['in_container'],
        provider: 'azure_blob',
        patternType: 'fuse',
        mountScopedCredentialFields: ['accountKey'],
        broadCredentialFields: ['identityClientId', 'managedIdentity'],
        enablesBroadCredentialDiscovery: true,
    },
    {
        strategyTypes: ['in_container'],
        provider: 's3_files',
        patternType: 's3files',
        mountScopedCredentialFields: [],
        broadCredentialFields: [
            'workloadIdentity',
            'extraOptions',
            'config.extraOptions',
            'mountStrategy.pattern.options.extraOptions',
        ],
        enablesBroadCredentialDiscovery: true,
    },
    {
        strategyTypes: ['vercel_cloud_bucket'],
        provider: 's3',
        mountScopedCredentialFields: [
            'accessKeyId',
            'secretAccessKey',
            'sessionToken',
        ],
        broadCredentialFields: ['mountStrategy.credentialEnvironment'],
        enablesBroadCredentialDiscovery: true,
    },
    {
        strategyTypes: ['blaxel_cloud_bucket'],
        provider: 's3',
        mountScopedCredentialFields: [
            'accessKeyId',
            'secretAccessKey',
            'sessionToken',
        ],
        broadCredentialFields: [],
    },
    {
        strategyTypes: ['blaxel_cloud_bucket'],
        provider: 'r2',
        mountScopedCredentialFields: ['accessKeyId', 'secretAccessKey'],
        broadCredentialFields: [],
    },
    {
        strategyTypes: ['blaxel_cloud_bucket'],
        provider: 'gcs',
        mountScopedCredentialFields: [
            'accessId',
            'secretAccessKey',
            'serviceAccountCredentials',
            'accessToken',
        ],
        broadCredentialFields: ['serviceAccountFile'],
    },
];
const S3_MOUNT_ENVIRONMENT_NAMES = [
    'AWS_ACCESS_KEY_ID',
    'AWS_SECRET_ACCESS_KEY',
    'AWS_SESSION_TOKEN',
    'AWS_SECURITY_TOKEN',
    'AWS_REGION',
    'AWS_DEFAULT_REGION',
    'AWS_PROFILE',
    'AWS_SHARED_CREDENTIALS_FILE',
    'AWS_CONFIG_FILE',
    'AWS_SDK_LOAD_CONFIG',
    'AWS_ROLE_ARN',
    'AWS_WEB_IDENTITY_TOKEN_FILE',
    'AWS_ROLE_SESSION_NAME',
    'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI',
    'AWS_CONTAINER_CREDENTIALS_FULL_URI',
    'AWS_CONTAINER_AUTHORIZATION_TOKEN',
    'AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE',
];
const S3_MOUNT_CREDENTIAL_ENVIRONMENT_NAMES = [
    'AWS_ACCESS_KEY_ID',
    'AWS_SECRET_ACCESS_KEY',
    'AWS_SESSION_TOKEN',
    'AWS_SECURITY_TOKEN',
    'AWS_PROFILE',
    'AWS_SHARED_CREDENTIALS_FILE',
    'AWS_CONFIG_FILE',
    'AWS_ROLE_ARN',
    'AWS_WEB_IDENTITY_TOKEN_FILE',
    'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI',
    'AWS_CONTAINER_CREDENTIALS_FULL_URI',
    'AWS_CONTAINER_AUTHORIZATION_TOKEN',
    'AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE',
];
const S3_MOUNT_BROAD_CREDENTIAL_ENVIRONMENT_NAMES = [
    'AWS_PROFILE',
    'AWS_SHARED_CREDENTIALS_FILE',
    'AWS_CONFIG_FILE',
    'AWS_SDK_LOAD_CONFIG',
    'AWS_ROLE_ARN',
    'AWS_WEB_IDENTITY_TOKEN_FILE',
    'AWS_ROLE_SESSION_NAME',
    'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI',
    'AWS_CONTAINER_CREDENTIALS_FULL_URI',
    'AWS_CONTAINER_AUTHORIZATION_TOKEN',
    'AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE',
];
const GCS_MOUNT_ENVIRONMENT_NAMES = [
    'GOOGLE_APPLICATION_CREDENTIALS',
    'GOOGLE_CLOUD_PROJECT',
    'CLOUDSDK_CORE_PROJECT',
];
const CREDENTIAL_FILE_ENVIRONMENT_NAMES = new Set([
    'AWS_SHARED_CREDENTIALS_FILE',
    'AWS_CONFIG_FILE',
    'AWS_WEB_IDENTITY_TOKEN_FILE',
    'AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE',
    'GOOGLE_APPLICATION_CREDENTIALS',
]);
function isMountCredentialFileEnvironmentName(name) {
    return (CREDENTIAL_FILE_ENVIRONMENT_NAMES.has(name) ||
        name === 'RCLONE_CONFIG' ||
        (name.startsWith('RCLONE_CONFIG_') &&
            (name.endsWith('_FILE') || name.endsWith('_PATH'))));
}
const pendingMountCredentialPaths = new WeakMap();
const persistedMountTopologyManifests = new WeakSet();
const liveMountCredentialAuthority = new WeakMap();
const validatedMountEffectivePaths = new WeakMap();
const liveMountEnvironmentAuthority = new WeakMap();
const liveMountRuntimeAuthority = new WeakMap();
const trustedCredentialReboundManifests = new WeakSet();
const unsafeManifestTransitionStates = new WeakSet();
const pendingManifestMutationCounts = new WeakMap();
const sandboxStateAccessTails = new WeakMap();
const sandboxStateGenerations = new WeakMap();
function markSandboxSessionStateUnsafe(state) {
    unsafeManifestTransitionStates.add(state);
}
function isSandboxSessionStateUnsafe(state) {
    return unsafeManifestTransitionStates.has(state);
}
function assertSandboxSessionStateUsable(state) {
    if (!isSandboxSessionStateUnsafe(state)) {
        return;
    }
    throw new errors_2.SandboxProviderError('Sandbox session is unavailable because a privileged manifest transition failed after provider side effects may have started.', { operation: 'manifest transition' });
}
async function withExclusiveSandboxManifestMutation(state, operation) {
    const pendingCount = pendingManifestMutationCounts.get(state) ?? 0;
    pendingManifestMutationCounts.set(state, pendingCount + 1);
    sandboxStateGenerations.set(state, sandboxStateGeneration(state) + 1);
    try {
        return await withExclusiveSandboxStateAccess(state, operation);
    }
    finally {
        const remaining = (pendingManifestMutationCounts.get(state) ?? 1) - 1;
        if (remaining > 0) {
            pendingManifestMutationCounts.set(state, remaining);
        }
        else {
            pendingManifestMutationCounts.delete(state);
        }
        sandboxStateGenerations.set(state, sandboxStateGeneration(state) + 1);
    }
}
async function withExclusiveSandboxStateInspection(state, operation) {
    return await withExclusiveSandboxStateAccess(state, operation);
}
async function withExclusiveSandboxStateAccess(state, operation) {
    assertSandboxSessionStateUsable(state);
    const previous = sandboxStateAccessTails.get(state) ?? Promise.resolve();
    let release;
    const turn = new Promise((resolve) => {
        release = resolve;
    });
    const tail = previous.catch(() => { }).then(() => turn);
    sandboxStateAccessTails.set(state, tail);
    await previous.catch(() => { });
    try {
        assertSandboxSessionStateUsable(state);
        return await operation();
    }
    finally {
        release();
        if (sandboxStateAccessTails.get(state) === tail) {
            sandboxStateAccessTails.delete(state);
        }
    }
}
function captureSandboxStateGeneration(state) {
    assertSandboxSessionStateUsable(state);
    if ((pendingManifestMutationCounts.get(state) ?? 0) > 0) {
        throw new errors_1.UserError('Sandbox state cannot be inspected while a manifest mutation is in progress.');
    }
    return sandboxStateGeneration(state);
}
function assertSandboxStateGenerationUnchanged(state, generation) {
    assertSandboxSessionStateUsable(state);
    if ((pendingManifestMutationCounts.get(state) ?? 0) > 0 ||
        sandboxStateGeneration(state) !== generation) {
        throw new errors_1.UserError('Sandbox manifest changed while session state was being inspected.');
    }
}
function sandboxStateGeneration(state) {
    return sandboxStateGenerations.get(state) ?? 0;
}
function configuredMountCredentialFields(entry) {
    const entryRecord = entry;
    const configured = ALL_CREDENTIAL_FIELDS.filter((field) => entryRecord[field] !== undefined && entryRecord[field] !== null).sort();
    for (const field of STRATEGY_CREDENTIAL_FIELDS) {
        const value = readNestedField(entryRecord, field);
        if (value !== undefined &&
            value !== null &&
            strategyFieldContainsCredentials(field, value)) {
            configured.push(field);
        }
    }
    const opaqueCredentialFields = [
        ...(mountConfigContainsOpaqueFields(entry) ? ['config'] : []),
        ...(entry.type === 's3_files_mount'
            ? ['extraOptions', 'config.extraOptions']
            : []),
    ];
    for (const field of opaqueCredentialFields) {
        const value = readNestedField(entryRecord, field);
        if (value !== undefined &&
            value !== null &&
            strategyFieldContainsCredentials(field, value)) {
            configured.push(field);
        }
    }
    if (entry.type === 'mount' &&
        INSIDE_SANDBOX_STRATEGIES.has(mountStrategyType(entry)) &&
        entryRecord.source !== undefined &&
        entryRecord.source !== null) {
        configured.push('source');
    }
    return [...new Set(configured)].sort();
}
function mountConfigContainsOpaqueFields(entry) {
    if (!isRecord(entry.config) || Object.keys(entry.config).length === 0) {
        return false;
    }
    if (entry.type === 'mount') {
        return true;
    }
    const topologyFields = new Set(Object.keys((0, typedMountConfig_1.typedMountProviderConfig)(entry).config));
    return Object.keys(entry.config).some((field) => !topologyFields.has(field));
}
function manifestHasInContainerMounts(manifest) {
    return manifest
        .mountTargets()
        .some(({ entry }) => INSIDE_SANDBOX_STRATEGIES.has(mountStrategyType(entry)));
}
function manifestHasNonResumableMountAuthority(manifest) {
    return [...mountsByLogicalPath(manifest).values()].some((mount) => mountHasNonResumableAuthority(mount));
}
function persistedManifestRecordHasNonResumableMountAuthority(value) {
    return rawManifestEntriesHaveNonResumableMountAuthority(value.entries);
}
function rawManifestEntriesHaveNonResumableMountAuthority(value) {
    if (!isRecord(value)) {
        return false;
    }
    return Object.values(value).some((entry) => {
        if (!isRecord(entry)) {
            return false;
        }
        return (mountHasNonResumableAuthority(entry) ||
            rawManifestEntriesHaveNonResumableMountAuthority(entry.children));
    });
}
function mountHasNonResumableAuthority(value) {
    if (!isRecord(value)) {
        return false;
    }
    const driverOptions = readNestedField(value, 'mountStrategy.driverOptions');
    const pattern = mountStrategyPattern(value.mountStrategy);
    const opaquePatternFields = [
        pattern?.args,
        pattern?.extraArgs,
        readNestedField(pattern ?? {}, 'options.extraOptions'),
    ];
    const opaqueS3FilesOptions = value.type === 's3_files_mount'
        ? [value.extraOptions, readNestedField(value, 'config.extraOptions')]
        : [];
    return (mountRecordHasOpaqueConfig(value) ||
        (isRecord(driverOptions) && Object.keys(driverOptions).length > 0) ||
        [...opaquePatternFields, ...opaqueS3FilesOptions].some((field) => strategyFieldContainsCredentials('opaque', field)) ||
        (typeof pattern?.command === 'string' && pattern.command.length > 0) ||
        (typeof pattern?.configFilePath === 'string' &&
            pattern.configFilePath.length > 0));
}
function mountRecordHasOpaqueConfig(value) {
    if (!isRecord(value.config) || Object.keys(value.config).length === 0) {
        return false;
    }
    if (value.type === 'mount') {
        return true;
    }
    if (value.type !== 's3_mount' &&
        value.type !== 'gcs_mount' &&
        value.type !== 'r2_mount' &&
        value.type !== 'azure_blob_mount' &&
        value.type !== 'box_mount' &&
        value.type !== 's3_files_mount') {
        return true;
    }
    const topologyFields = new Set(Object.keys((0, typedMountConfig_1.typedMountProviderConfig)(value).config));
    return Object.keys(value.config).some((field) => !topologyFields.has(field));
}
function validateMountCredentialBoundaries(manifest) {
    for (const { entry, mountPath } of manifest.mountTargets()) {
        validateExplicitMountCredentialPairs(entry);
        validateRclonePatternArguments(entry, mountPath);
        const credentialFields = [
            ...configuredMountCredentialFields(entry),
            ...implicitWorkloadIdentityCredentialFields(entry),
        ];
        const strategyType = mountStrategyType(entry);
        if (OUTSIDE_SANDBOX_STRATEGIES.has(strategyType)) {
            if (credentialFields.length > 0) {
                assertMountCredentialFilesAreNotSerializedManifestEntries(manifest, entry, mountPath);
            }
            continue;
        }
        const acknowledgement = mountCredentialExposureAcknowledgement(manifest, mountPath);
        if (credentialFields.length === 0 &&
            !acknowledgement.mount_scoped &&
            !acknowledgement.broad) {
            continue;
        }
        const capability = inContainerMountCredentialCapability(entry);
        const details = {
            mountPath,
            mountType: entry.type,
            mountStrategy: strategyType,
            mountProvider: sdkOwnedMountProvider(entry),
            mountPattern: resolvedInContainerMountPatternType(entry),
            credentialFields,
        };
        if (!capability) {
            throw new errors_2.SandboxMountError('Credential-bearing in-container mounts require an SDK-supported strategy, provider, mount type, and pattern combination before exposure can be acknowledged. Use a supported typed mount and strategy, a credentialless helper, or an external or provider-native mount strategy.', details, 'mount_config_invalid');
        }
        const requiredAuthorities = classifyMountCredentialAuthorities(capability, credentialFields, details);
        validateAcknowledgementSupportedByCapability(capability, acknowledgement, details);
        if (credentialFields.length > 0) {
            assertMountCredentialFilesAreNotSerializedManifestEntries(manifest, entry, mountPath);
        }
        for (const authority of requiredAuthorities) {
            if (acknowledgement[authority]) {
                continue;
            }
            const broad = authority === 'broad';
            throw new errors_2.SandboxMountError(broad
                ? 'Broad credential authority cannot be exposed to a helper inside a model-controlled sandbox by default. Use a credentialless or external/provider-native strategy, or explicitly acknowledge broad credential exposure for this exact path with Manifest.withInContainerMountBroadCredentialExposureAcknowledged().'
                : 'Mount-scoped credentials cannot be exposed to a helper inside a model-controlled sandbox by default. Use a credentialless or external/provider-native strategy, or explicitly acknowledge credential exposure for this exact path with Manifest.withInContainerMountCredentialExposureAcknowledged().', details, 'mount_config_invalid');
        }
    }
}
function inContainerMountCredentialCapability(entry) {
    const strategyType = mountStrategyType(entry);
    const provider = sdkOwnedMountProvider(entry);
    if (!provider) {
        return undefined;
    }
    const patternType = resolvedInContainerMountPatternType(entry);
    return IN_CONTAINER_MOUNT_CREDENTIAL_CAPABILITIES.find((capability) => capability.strategyTypes.includes(strategyType) &&
        capability.provider === provider &&
        capability.patternType === patternType);
}
function sdkOwnedMountProvider(entry) {
    if (entry.type === 'mount') {
        return undefined;
    }
    const provider = (0, typedMountConfig_1.typedMountProviderConfig)(entry).provider;
    return entry.provider === undefined || entry.provider === provider
        ? provider
        : undefined;
}
function resolvedInContainerMountPatternType(entry) {
    const patternType = mountStrategyPattern(entry.mountStrategy)?.type;
    if (patternType !== undefined) {
        return typeof patternType === 'string' ? patternType : undefined;
    }
    const strategyType = mountStrategyType(entry);
    if (strategyType === 'e2b_cloud_bucket' ||
        strategyType === 'daytona_cloud_bucket') {
        return 'rclone';
    }
    if (strategyType !== 'in_container') {
        return undefined;
    }
    return entry.type === 's3_files_mount'
        ? 's3files'
        : entry.type === 's3_mount' ||
            entry.type === 'r2_mount' ||
            entry.type === 'gcs_mount' ||
            entry.type === 'azure_blob_mount' ||
            entry.type === 'box_mount'
            ? 'rclone'
            : undefined;
}
function classifyMountCredentialAuthorities(capability, credentialFields, details) {
    const mountScopedFields = new Set(capability.mountScopedCredentialFields);
    const broadFields = new Set(capability.broadCredentialFields);
    const unsupportedCredentialFields = credentialFields.filter((field) => !mountScopedFields.has(field) && !broadFields.has(field));
    if (unsupportedCredentialFields.length > 0) {
        throw new errors_2.SandboxMountError('The selected in-container mount capability does not support exposing these credential fields. Use the credential fields supported by this typed mount and strategy, or choose a credentialless or external/provider-native strategy.', { ...details, unsupportedCredentialFields }, 'mount_config_invalid');
    }
    const authorities = new Set();
    if (credentialFields.some((field) => mountScopedFields.has(field))) {
        authorities.add('mount_scoped');
    }
    if (credentialFields.some((field) => broadFields.has(field))) {
        authorities.add('broad');
    }
    return authorities;
}
function validateAcknowledgementSupportedByCapability(capability, acknowledgement, details) {
    if (acknowledgement.mount_scoped &&
        capability.mountScopedCredentialFields.length === 0) {
        throw new errors_2.SandboxMountError('The selected in-container mount capability does not support mount-scoped credential exposure acknowledgement.', details, 'mount_config_invalid');
    }
    if (acknowledgement.broad &&
        capability.broadCredentialFields.length === 0 &&
        capability.enablesBroadCredentialDiscovery !== true) {
        throw new errors_2.SandboxMountError('The selected in-container mount capability does not support broad credential exposure acknowledgement.', details, 'mount_config_invalid');
    }
}
function mountCredentialExposureAcknowledgement(manifest, mountPath) {
    return {
        mount_scoped: (0, manifest_1.manifestAcknowledgesInContainerMountCredentialExposure)(manifest, mountPath, 'mount_scoped'),
        broad: (0, manifest_1.manifestAcknowledgesInContainerMountCredentialExposure)(manifest, mountPath, 'broad'),
    };
}
function validateRclonePatternArguments(entry, mountPath) {
    const pattern = mountStrategyPattern(entry.mountStrategy);
    if (pattern?.type !== 'rclone') {
        return;
    }
    const unsupportedFields = ['args', 'extraArgs'].flatMap((field) => {
        const value = pattern[field];
        if (value === undefined || isCredentialFreeRcloneArgumentList(value)) {
            return [];
        }
        return [`mountStrategy.pattern.${field}`];
    });
    if (unsupportedFields.length === 0) {
        return;
    }
    throw new errors_2.SandboxMountError('Unsupported rclone mount args or extraArgs can bypass credential-file validation. Use typed mount options or mountStrategy.pattern.configFilePath instead.', { mountPath, mountType: entry.type, credentialFields: unsupportedFields }, 'mount_config_invalid');
}
function isCredentialFreeRcloneArgumentList(value) {
    if (!Array.isArray(value) ||
        !value.every((item) => typeof item === 'string')) {
        return false;
    }
    for (let index = 0; index < value.length; index += 1) {
        const argument = value[index];
        if (argument === '--vfs-cache-mode') {
            const mode = value[index + 1];
            if (!['off', 'minimal', 'writes', 'full'].includes(mode ?? '')) {
                return false;
            }
            index += 1;
            continue;
        }
        const mode = argument.match(/^--vfs-cache-mode=(.+)$/u)?.[1];
        if (mode && ['off', 'minimal', 'writes', 'full'].includes(mode)) {
            continue;
        }
        return false;
    }
    return true;
}
function validateExplicitMountCredentialPairs(entry) {
    const entryRecord = entry;
    const accessKeyId = optionalCredentialString(entryRecord.accessKeyId);
    const secretAccessKey = optionalCredentialString(entryRecord.secretAccessKey);
    if (entry.type === 's3_mount' || entry.type === 'r2_mount') {
        (0, credentials_1.validateCredentialPair)({
            accessKeyId,
            secretAccessKey,
            message: `${entry.type} requires both accessKeyId and secretAccessKey when either is provided.`,
            details: { mountType: entry.type },
            code: 'mount_config_invalid',
        });
        if (optionalCredentialString(entryRecord.sessionToken) !== undefined &&
            (!accessKeyId || !secretAccessKey)) {
            throw new errors_2.SandboxMountError(`${entry.type} requires a complete accessKeyId and secretAccessKey pair when sessionToken is provided.`, { mountType: entry.type }, 'mount_config_invalid');
        }
        return;
    }
    if (entry.type === 'gcs_mount') {
        (0, credentials_1.validateCredentialPair)({
            accessKeyId: optionalCredentialString(entryRecord.accessId),
            secretAccessKey,
            message: 'gcs_mount requires both accessId and secretAccessKey when either is provided.',
            details: { mountType: entry.type },
            code: 'mount_config_invalid',
        });
    }
}
function validateMountCredentialEnvironmentPairs(entry, environment, unresolvedEnvironmentNames = new Set()) {
    if (entry.type === 's3_mount' ||
        entry.type === 'r2_mount' ||
        entry.type === 's3_files_mount') {
        const entryRecord = entry;
        if (!(entryRecord.accessKeyId && entryRecord.secretAccessKey)) {
            const accessKeyId = optionalCredentialString(environment.AWS_ACCESS_KEY_ID);
            const secretAccessKey = optionalCredentialString(environment.AWS_SECRET_ACCESS_KEY);
            const accessPairIsUnresolved = unresolvedEnvironmentNames.has('AWS_ACCESS_KEY_ID') ||
                unresolvedEnvironmentNames.has('AWS_SECRET_ACCESS_KEY');
            if (!accessPairIsUnresolved) {
                (0, credentials_1.validateCredentialPair)({
                    accessKeyId,
                    secretAccessKey,
                    message: 'S3 mount environment credentials require both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY when either is provided.',
                    details: { mountType: entry.type },
                    code: 'mount_config_invalid',
                });
            }
            if (!accessPairIsUnresolved &&
                !unresolvedEnvironmentNames.has('AWS_SESSION_TOKEN') &&
                !unresolvedEnvironmentNames.has('AWS_SECURITY_TOKEN') &&
                (optionalCredentialString(environment.AWS_SESSION_TOKEN) !==
                    undefined ||
                    optionalCredentialString(environment.AWS_SECURITY_TOKEN) !==
                        undefined) &&
                (!accessKeyId || !secretAccessKey)) {
                throw new errors_2.SandboxMountError('S3 mount environment credentials require a complete AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY pair when a session token is provided.', { mountType: entry.type }, 'mount_config_invalid');
            }
        }
    }
    const rcloneRemotePrefixes = new Set();
    for (const name of Object.keys(environment)) {
        const prefix = name.match(/^(RCLONE_CONFIG_.+)_(?:ACCESS_KEY_ID|SECRET_ACCESS_KEY|SESSION_TOKEN|SECURITY_TOKEN)$/u)?.[1];
        if (prefix) {
            rcloneRemotePrefixes.add(prefix);
        }
    }
    for (const prefix of rcloneRemotePrefixes) {
        const accessKeyId = optionalCredentialString(environment[`${prefix}_ACCESS_KEY_ID`]);
        const secretAccessKey = optionalCredentialString(environment[`${prefix}_SECRET_ACCESS_KEY`]);
        const accessPairIsUnresolved = unresolvedEnvironmentNames.has(`${prefix}_ACCESS_KEY_ID`) ||
            unresolvedEnvironmentNames.has(`${prefix}_SECRET_ACCESS_KEY`);
        if (!accessPairIsUnresolved) {
            (0, credentials_1.validateCredentialPair)({
                accessKeyId,
                secretAccessKey,
                message: 'Rclone remote environment credentials require both ACCESS_KEY_ID and SECRET_ACCESS_KEY when either is provided.',
                details: { mountType: entry.type, remote: prefix },
                code: 'mount_config_invalid',
            });
        }
        if (!accessPairIsUnresolved &&
            !unresolvedEnvironmentNames.has(`${prefix}_SESSION_TOKEN`) &&
            !unresolvedEnvironmentNames.has(`${prefix}_SECURITY_TOKEN`) &&
            (optionalCredentialString(environment[`${prefix}_SESSION_TOKEN`]) !==
                undefined ||
                optionalCredentialString(environment[`${prefix}_SECURITY_TOKEN`]) !==
                    undefined) &&
            (!accessKeyId || !secretAccessKey)) {
            throw new errors_2.SandboxMountError('Rclone remote environment credentials require a complete ACCESS_KEY_ID and SECRET_ACCESS_KEY pair when a session token is provided.', { mountType: entry.type, remote: prefix }, 'mount_config_invalid');
        }
    }
}
function optionalCredentialString(value) {
    return typeof value === 'string' && value.length > 0 ? value : undefined;
}
function implicitWorkloadIdentityCredentialFields(entry) {
    if (!INSIDE_SANDBOX_STRATEGIES.has(mountStrategyType(entry))) {
        return [];
    }
    if (entry.type === 's3_files_mount') {
        return ['workloadIdentity'];
    }
    if (entry.type === 'azure_blob_mount' &&
        mountStrategyPattern(entry.mountStrategy)?.type === 'fuse' &&
        !entry.accountKey &&
        !entry.identityClientId) {
        return ['managedIdentity'];
    }
    return [];
}
function validateMountEnvironmentCredentialBoundaries(manifest, environment, options = {}) {
    const unresolvedEnvironmentNames = new Set(options.preserveDeferredValuePresence
        ? Object.entries(manifest.environment)
            .filter(([name, value]) => !Object.prototype.hasOwnProperty.call(environment, name) &&
            ((0, manifest_1.isEnvValueReference)(value) || value.resolver !== undefined))
            .map(([name]) => name)
        : []);
    const effectiveEnvironment = mountEffectiveEnvironment(manifest, environment, unresolvedEnvironmentNames);
    const candidate = (0, manifest_1.cloneManifest)(manifest);
    for (const { entry, mountPath } of candidate.mountTargets()) {
        const credentialEnvironment = mountCredentialEnvironmentForEntry(entry, effectiveEnvironment);
        validateMountCredentialEnvironmentPairs(entry, credentialEnvironment, unresolvedEnvironmentNames);
        if (Object.keys(credentialEnvironment).length === 0) {
            continue;
        }
        const strategy = entry.mountStrategy;
        if (!isRecord(strategy)) {
            continue;
        }
        strategy.credentialEnvironment = credentialEnvironment;
        assertMountCredentialFilesAreNotSerializedManifestEntries(candidate, entry, mountPath, credentialEnvironment);
    }
    validateMountCredentialBoundaries(candidate);
}
async function resolveAndValidateMountEnvironment(manifest) {
    if (!manifest
        .mountTargets()
        .some(({ entry }) => ENVIRONMENT_CREDENTIAL_STRATEGIES.has(mountStrategyType(entry)))) {
        return (0, manifest_1.cloneManifest)(manifest);
    }
    const environment = await manifest.resolveEnvironment();
    validateMountEnvironmentCredentialBoundaries(manifest, environment);
    const resolved = (0, manifest_1.cloneManifest)(manifest);
    for (const [name, original] of Object.entries(manifest.environment)) {
        resolved.environment[name] = new manifest_1.Environment({
            value: environment[name] ?? '',
            ...(original.ephemeral ? { ephemeral: true } : {}),
            ...(original.description ? { description: original.description } : {}),
        });
    }
    return resolved;
}
function validateMountCredentialBoundariesAtEffectivePath(manifest, logicalPath, entry, effectivePath) {
    const effectiveAcknowledgement = mountCredentialExposureAcknowledgement(manifest, effectivePath);
    const declaredPath = manifest
        .mountTargets()
        .find((target) => target.logicalPath === logicalPath)?.mountPath;
    const declaredAcknowledgement = declaredPath
        ? mountCredentialExposureAcknowledgement(manifest, declaredPath)
        : { mount_scoped: false, broad: false };
    for (const authority of ['mount_scoped', 'broad']) {
        if (declaredAcknowledgement[authority] &&
            !effectiveAcknowledgement[authority]) {
            throw new errors_2.SandboxMountError('Mount credentials cannot be exposed to a helper inside a model-controlled sandbox because the effective mount path does not match the trusted exact-path acknowledgement.', {
                mountType: entry.type,
                mountStrategy: mountStrategyType(entry),
                credentialAuthority: authority,
            }, 'mount_config_invalid');
        }
    }
    if (effectiveAcknowledgement.mount_scoped || effectiveAcknowledgement.broad) {
        const capability = inContainerMountCredentialCapability(entry);
        if (!capability) {
            throw new errors_2.SandboxMountError('Credential-bearing in-container mounts require an SDK-supported strategy, provider, mount type, and pattern combination before exposure can be acknowledged.', {
                mountType: entry.type,
                mountStrategy: mountStrategyType(entry),
                mountProvider: sdkOwnedMountProvider(entry),
                mountPattern: resolvedInContainerMountPatternType(entry),
            }, 'mount_config_invalid');
        }
        validateAcknowledgementSupportedByCapability(capability, effectiveAcknowledgement, {
            mountType: entry.type,
            mountStrategy: mountStrategyType(entry),
            mountProvider: sdkOwnedMountProvider(entry),
            mountPattern: resolvedInContainerMountPatternType(entry),
        });
    }
    const effectivePaths = new Map(validatedMountEffectivePaths.get(manifest) ?? []);
    effectivePaths.set(logicalPath, (0, posixPath_1.normalizePosixPath)(effectivePath));
    validatedMountEffectivePaths.set(manifest, effectivePaths);
    return {
        credentialExposureAcknowledged: effectiveAcknowledgement.mount_scoped || effectiveAcknowledgement.broad,
        broadCredentialExposureAcknowledged: effectiveAcknowledgement.broad,
    };
}
function copyValidatedMountEffectivePaths(target, ...sources) {
    const effectivePaths = new Map();
    for (const source of sources) {
        for (const [logicalPath, effectivePath] of validatedMountEffectivePaths.get(source) ?? []) {
            effectivePaths.set(logicalPath, effectivePath);
        }
    }
    if (effectivePaths.size > 0) {
        validatedMountEffectivePaths.set(target, effectivePaths);
    }
}
function sanitizeMountCredentialEnvironmentForPersistence(state) {
    const environment = state.environment ?? {};
    const credentialNames = mountCredentialEnvironmentNamesForPersistence(state.manifest, environment);
    const sanitizedManifest = (0, manifest_1.cloneManifest)(state.manifest);
    const sanitizedEnvironment = { ...environment };
    for (const name of credentialNames) {
        delete sanitizedEnvironment[name];
        const manifestEnvironment = sanitizedManifest.environment[name];
        if (manifestEnvironment) {
            sanitizedManifest.environment[name] = new manifest_1.Environment({
                value: '',
                ephemeral: true,
                ...(manifestEnvironment.description
                    ? { description: manifestEnvironment.description }
                    : {}),
            });
        }
    }
    return { manifest: sanitizedManifest, environment: sanitizedEnvironment };
}
function mountEffectiveEnvironment(manifest, environment, unresolvedEnvironmentNames = new Set()) {
    return {
        ...Object.fromEntries(Object.entries(manifest.environment).map(([name, value]) => [
            name,
            unresolvedEnvironmentNames.has(name)
                ? '__openai_unresolved_environment_reference__'
                : value.value,
        ])),
        ...environment,
    };
}
function serializeMountCredentialRedactionMetadata(state) {
    const paths = new Set(readMountCredentialPaths(state));
    for (const [path, mount] of mountsByLogicalPath(state.manifest)) {
        if (configuredMountCredentialFields(mount).length > 0) {
            paths.add(path);
        }
    }
    return {
        ...(paths.size > 0
            ? { [exports.REDACTED_MOUNT_CREDENTIAL_PATHS_KEY]: [...paths] }
            : {}),
        ...(manifestHasNonResumableMountAuthority(state.manifest)
            ? { [exports.NON_RESUMABLE_MOUNT_AUTHORITY_KEY]: true }
            : {}),
    };
}
function deserializeMountCredentialRedactionMetadata(state) {
    const paths = readMountCredentialPaths(state);
    return {
        ...(paths.length > 0
            ? { [exports.REDACTED_MOUNT_CREDENTIAL_PATHS_KEY]: paths }
            : {}),
        ...(state[exports.NON_RESUMABLE_MOUNT_AUTHORITY_KEY] === true
            ? { [exports.NON_RESUMABLE_MOUNT_AUTHORITY_KEY]: true }
            : {}),
    };
}
function sanitizePersistedManifestRecord(value) {
    if (manifest_1.MOUNT_CREDENTIAL_EXPOSURE_POLICY_KEYS.some((key) => key in value)) {
        throw new TypeError('Persisted sandbox manifest cannot configure mount credential exposure policy.');
    }
    const rawEntries = value.entries;
    if (rawEntries === undefined) {
        return { record: { ...value }, credentialPaths: [] };
    }
    if (!isRecord(rawEntries)) {
        throw new TypeError('Persisted sandbox manifest entries must be an object.');
    }
    assertRawPersistedCredentialFilesAreNotManifestEntries(value, rawEntries);
    const entries = structuredClone(rawEntries);
    const record = { ...value, entries };
    const credentialPaths = [];
    sanitizeRawEntryMapping(entries, '', credentialPaths);
    return { record, credentialPaths: [...new Set(credentialPaths)] };
}
function recordPendingMountCredentialPaths(manifest, paths) {
    if (paths.length > 0) {
        pendingMountCredentialPaths.set(manifest, [...new Set(paths)]);
    }
}
function validateMountCredentialRedactionPaths(manifest, paths) {
    assertCredentialPathsReferenceMounts(paths, mountsByLogicalPath(manifest));
}
function recordPersistedMountTopology(manifest) {
    persistedMountTopologyManifests.add(manifest);
}
function rebindPersistedMountCredentials(state, trustedManifest) {
    const paths = [
        ...new Set([
            ...readMountCredentialPaths(state),
            ...(pendingMountCredentialPaths.get(state.manifest) ?? []),
        ]),
    ];
    const persistedMounts = mountsByLogicalPath(state.manifest);
    assertCredentialPathsReferenceMounts(paths, persistedMounts);
    if (!trustedManifest) {
        if (paths.length === 0 &&
            (!persistedMountTopologyManifests.has(state.manifest) ||
                persistedMounts.size === 0)) {
            return state;
        }
        throw new errors_2.SandboxMountError('Sandbox session state contains mount topology that requires a current trusted manifest before resume.', undefined, 'mount_config_invalid');
    }
    const trustedMounts = mountsByLogicalPath(trustedManifest);
    if (persistedMountTopologyManifests.has(state.manifest) &&
        manifestHasNonResumableMountAuthority(trustedManifest)) {
        throw new errors_2.SandboxMountError('Sandbox session state contains opaque mount authority that cannot be validated after persistence. Create a fresh sandbox from current trusted configuration.', undefined, 'mount_config_invalid');
    }
    assertMatchingMountTopology(state.manifest, trustedManifest, persistedMounts, trustedMounts);
    for (const path of paths) {
        const trustedMount = trustedMounts.get(path);
        if (configuredMountCredentialFields(trustedMount).length === 0) {
            throw new errors_2.SandboxMountError(`Current trusted manifest no longer provides credential authority for persisted mount entry: ${path}. Create a fresh sandbox from current trusted configuration.`, undefined, 'mount_config_invalid');
        }
    }
    const reboundManifest = (0, manifest_1.cloneManifest)(state.manifest);
    const reboundMounts = mountsByLogicalPath(reboundManifest);
    for (const [path, mount] of reboundMounts) {
        restoreMountCredentials(mount, trustedMounts.get(path));
    }
    (0, manifest_1.replaceManifestMountCredentialExposurePolicy)(reboundManifest, trustedManifest);
    validateMountCredentialBoundaries(reboundManifest);
    trustedCredentialReboundManifests.add(reboundManifest);
    const rebound = { ...state, manifest: reboundManifest };
    delete rebound[exports.REDACTED_MOUNT_CREDENTIAL_PATHS_KEY];
    return rebound;
}
function recordLiveMountCredentialAuthority(target, source) {
    const authoritySource = liveMountCredentialAuthority.get(source) ?? source;
    const authority = (0, manifest_1.cloneManifest)(authoritySource);
    copyValidatedMountEffectivePaths(authority, authoritySource);
    liveMountCredentialAuthority.set(target, authority);
    const environmentAuthority = liveMountEnvironmentAuthority.get(source);
    if (environmentAuthority !== undefined) {
        liveMountEnvironmentAuthority.set(target, environmentAuthority);
    }
    const runtimeAuthority = liveMountRuntimeAuthority.get(source);
    if (runtimeAuthority !== undefined) {
        liveMountRuntimeAuthority.set(target, new Map(runtimeAuthority));
    }
}
function captureLiveMountRuntimeAuthority(manifest, key, signature) {
    const authority = new Map(liveMountRuntimeAuthority.get(manifest) ?? []);
    authority.set(key, signature);
    liveMountRuntimeAuthority.set(manifest, authority);
}
function liveMountRuntimeAuthorityMatches(manifest, key, signature) {
    return liveMountRuntimeAuthority.get(manifest)?.get(key) === signature;
}
function captureLiveMountCredentialAuthority(manifest, environment) {
    const authority = (0, manifest_1.cloneManifest)(manifest);
    copyValidatedMountEffectivePaths(authority, manifest);
    liveMountCredentialAuthority.set(manifest, authority);
    if (environment) {
        captureLiveMountEnvironmentAuthority(manifest, environment);
    }
}
function captureLiveMountEnvironmentAuthority(manifest, environment) {
    liveMountEnvironmentAuthority.set(manifest, mountCredentialEnvironmentAuthoritySignature(manifest, environment));
}
function captureLiveMountCredentialAuthorityIfAbsent(manifest, environment) {
    if (!liveMountCredentialAuthority.has(manifest)) {
        captureLiveMountCredentialAuthority(manifest, environment);
    }
    else if (environment && !liveMountEnvironmentAuthority.has(manifest)) {
        liveMountEnvironmentAuthority.set(manifest, mountCredentialEnvironmentAuthoritySignature(manifest, environment));
    }
}
function copyTrustedMountCredentialRebindProvenance(target, source) {
    if (trustedCredentialReboundManifests.has(source)) {
        trustedCredentialReboundManifests.add(target);
    }
}
function liveMountCredentialAuthorityMatches(liveManifest, trustedManifest) {
    const liveMounts = mountsByLogicalPath(liveManifest);
    const trustedMounts = mountsByLogicalPath(trustedManifest);
    try {
        assertMatchingMountTopology(liveManifest, trustedManifest, liveMounts, trustedMounts);
    }
    catch (error) {
        if (error instanceof errors_2.SandboxMountError) {
            return false;
        }
        throw error;
    }
    const authority = liveMountCredentialAuthority.get(liveManifest) ?? liveManifest;
    return (mountCredentialAuthoritySignature(authority, authority) ===
        mountCredentialAuthoritySignature(trustedManifest, authority));
}
function assertLiveMountCredentialAuthorityMatches(liveManifest, candidateManifest) {
    if (liveMountCredentialAuthorityMatches(liveManifest, candidateManifest)) {
        return;
    }
    throw new errors_2.SandboxMountError('Sandbox mount authority does not match the active session. Route topology changes through materializeEntry() or applyManifest(), or create a fresh sandbox session.', undefined, 'mount_config_invalid');
}
function liveMountEnvironmentAuthorityMatches(liveManifest, trustedManifest, trustedEnvironment) {
    const trustedAuthority = mountCredentialEnvironmentAuthoritySignature(trustedManifest, trustedEnvironment);
    return ((liveMountEnvironmentAuthority.get(liveManifest) ??
        mountCredentialEnvironmentAuthoritySignature(liveManifest, {})) ===
        trustedAuthority);
}
function assertLiveMountEnvironmentAuthorityMatches(liveManifest, trustedManifest, trustedEnvironment) {
    if (liveMountEnvironmentAuthorityMatches(liveManifest, trustedManifest, trustedEnvironment)) {
        return;
    }
    throw new errors_2.SandboxMountError('Sandbox mount environment authority does not match the active session. Create a fresh sandbox session from current trusted configuration.', undefined, 'mount_config_invalid');
}
function assertExistingMountTopologyPreserved(currentManifest, nextManifest) {
    const currentMounts = mountsByLogicalPath(currentManifest);
    if (currentMounts.size === 0) {
        return;
    }
    const nextMounts = mountsByLogicalPath(nextManifest);
    const changedPaths = [...currentMounts]
        .filter(([path, currentMount]) => {
        const nextMount = nextMounts.get(path);
        return (nextMount === undefined ||
            (0, stableJson_1.stableJsonStringify)(redactMountCredentialsForPersistence(currentMount)) !==
                (0, stableJson_1.stableJsonStringify)(redactMountCredentialsForPersistence(nextMount)));
    })
        .map(([path]) => path)
        .sort();
    if (currentManifest.root !== nextManifest.root || changedPaths.length > 0) {
        throw new errors_2.SandboxMountError(`Active sandbox mounts cannot be removed or replaced by a manifest mutation${changedPaths.length > 0 ? `: ${changedPaths.join(', ')}` : ''}. Create a fresh sandbox session instead.`, undefined, 'mount_config_invalid');
    }
}
function assertMountCredentialsRebound(state) {
    if (state[exports.NON_RESUMABLE_MOUNT_AUTHORITY_KEY] === true) {
        throw new errors_2.SandboxMountError('Sandbox session state contains non-resumable mount authority. Create a fresh sandbox from current trusted configuration.', undefined, 'mount_config_invalid');
    }
    const paths = [
        ...new Set([
            ...readMountCredentialPaths(state),
            ...(pendingMountCredentialPaths.get(state.manifest) ?? []),
        ]),
    ];
    if (paths.length > 0) {
        throw new errors_2.SandboxMountError(`Sandbox session state requires trusted mount credentials for these entry paths: ${paths.join(', ')}. Resume it through the Runner with a current manifest that defines each mount.`, undefined, 'mount_config_invalid');
    }
    if (manifestHasInContainerMounts(state.manifest)) {
        throw new errors_2.SandboxMountError('Sandbox session state with in-container mounts cannot be resumed safely. Create a fresh sandbox so mount helpers are recreated from current trusted configuration.', undefined, 'mount_config_invalid');
    }
    const mounts = mountsByLogicalPath(state.manifest);
    const requiresTrustedRebind = (persistedMountTopologyManifests.has(state.manifest) && mounts.size > 0) ||
        [...mounts.values()].some((mount) => configuredMountCredentialFields(mount).length > 0);
    if (requiresTrustedRebind &&
        !trustedCredentialReboundManifests.has(state.manifest)) {
        throw new errors_2.SandboxMountError('Persisted sandbox mount topology must be rebound from a current trusted manifest before resume.', undefined, 'mount_config_invalid');
    }
}
function readMountCredentialPaths(state) {
    const value = state[exports.REDACTED_MOUNT_CREDENTIAL_PATHS_KEY];
    if (value === undefined) {
        return [];
    }
    if (!Array.isArray(value) ||
        !value.every((path) => typeof path === 'string')) {
        throw new TypeError('Persisted sandbox mount credential marker must be an array of strings.');
    }
    return value;
}
function sanitizeRawEntryMapping(entries, prefix, credentialPaths) {
    for (const [name, rawEntry] of Object.entries(entries)) {
        if (!isRecord(rawEntry)) {
            throw new TypeError('Persisted sandbox manifest entries must contain objects.');
        }
        const path = prefix ? `${prefix}/${name}` : name;
        const type = typeof rawEntry.type === 'string' ? rawEntry.type : '';
        const looksLikeMount = type === 'mount' ||
            type.endsWith('_mount') ||
            'mountStrategy' in rawEntry;
        let removed = false;
        if (looksLikeMount) {
            const fields = configuredMountCredentialFields(rawEntry);
            for (const field of fields) {
                const value = readNestedField(rawEntry, field);
                if (value !== undefined && value !== null) {
                    removed = true;
                }
                deleteNestedField(rawEntry, field);
            }
        }
        if (removed) {
            credentialPaths.push(path);
        }
        if (type === 'dir' && rawEntry.children !== undefined) {
            if (!isRecord(rawEntry.children)) {
                throw new TypeError('Persisted sandbox directory children must be an object.');
            }
            sanitizeRawEntryMapping(rawEntry.children, path, credentialPaths);
        }
    }
}
function assertRawPersistedCredentialFilesAreNotManifestEntries(manifestRecord, entries) {
    const entriesByPath = new Map();
    collectRawEntries(entries, '', entriesByPath);
    const root = typeof manifestRecord.root === 'string'
        ? manifestRecord.root
        : '/workspace';
    const environment = rawPersistedEnvironment(manifestRecord.environment);
    for (const [logicalPath, entry] of entriesByPath) {
        const type = typeof entry.type === 'string' ? entry.type : '';
        const looksLikeMount = type === 'mount' || type.endsWith('_mount') || 'mountStrategy' in entry;
        if (!looksLikeMount) {
            continue;
        }
        const credentialEnvironment = mountCredentialEnvironmentForEntry(entry, environment);
        const pattern = mountStrategyPattern(entry.mountStrategy);
        const credentialFiles = new Map();
        for (const [field, value] of [
            ['serviceAccountFile', entry.serviceAccountFile],
            ['boxConfigFile', entry.boxConfigFile],
            ['mountStrategy.pattern.configFilePath', pattern?.configFilePath],
        ]) {
            if (typeof value === 'string' && value.trim() !== '') {
                credentialFiles.set(field, value);
            }
        }
        for (const [name, value] of Object.entries(credentialEnvironment)) {
            if (isMountCredentialFileEnvironmentName(name) && value.trim() !== '') {
                credentialFiles.set(`environment.${name}`, value);
            }
        }
        const serializedCredentialFields = [...credentialFiles]
            .filter(([, value]) => rawCredentialFileReferenceMatchesEntry(value, root, entriesByPath))
            .map(([field]) => field)
            .sort();
        if (serializedCredentialFields.length > 0) {
            throw new errors_2.SandboxMountError('Mount credential files cannot come from a serialized manifest entry.', {
                mountPath: (0, posixPath_1.normalizePosixPath)(`${root}/${logicalPath}`),
                mountType: type,
                credentialFields: serializedCredentialFields,
            }, 'mount_config_invalid');
        }
    }
}
function collectRawEntries(entries, prefix, output) {
    for (const [name, value] of Object.entries(entries)) {
        if (!isRecord(value)) {
            continue;
        }
        const path = prefix ? `${prefix}/${name}` : name;
        output.set(path, value);
        if (value.type === 'dir' && isRecord(value.children)) {
            collectRawEntries(value.children, path, output);
        }
    }
}
function rawPersistedEnvironment(value) {
    if (!isRecord(value)) {
        return {};
    }
    return Object.fromEntries(Object.entries(value).flatMap(([name, rawValue]) => {
        if (typeof rawValue === 'string') {
            return [[name, rawValue]];
        }
        if (isRecord(rawValue) && typeof rawValue.value === 'string') {
            return [[name, rawValue.value]];
        }
        return [];
    }));
}
function rawCredentialFileReferenceMatchesEntry(value, root, entriesByPath) {
    const normalizedReference = value.startsWith('/')
        ? (0, posixPath_1.normalizePosixPath)(value)
        : (0, manifest_1.normalizeRelativePath)(value);
    for (const [logicalPath, entry] of entriesByPath) {
        const entryPath = value.startsWith('/')
            ? (0, posixPath_1.normalizePosixPath)(`${root}/${logicalPath}`)
            : logicalPath;
        if (entryPath === normalizedReference ||
            (entryIsRecursiveSource(entry) &&
                (0, posixPath_1.isUnderPosixPath)(normalizedReference, entryPath))) {
            return true;
        }
    }
    return false;
}
function redactMountCredentialsForPersistence(entry) {
    const redacted = structuredClone(entry);
    if (entry.type !== 'mount') {
        // Typed mount topology is also represented by canonical top-level fields and
        // is regenerated during manifest normalization. Dropping config here keeps
        // residual provider authority out of persisted state and topology checks.
        delete redacted.config;
    }
    for (const field of configuredMountCredentialFields(entry)) {
        deleteNestedField(redacted, field);
    }
    return redacted;
}
function restoreMountCredentials(target, trusted) {
    const targetRecord = target;
    const trustedRecord = trusted;
    const fields = new Set([
        ...configuredMountCredentialFields(target),
        ...configuredMountCredentialFields(trusted),
    ]);
    for (const field of fields) {
        const trustedValue = readNestedField(trustedRecord, field);
        if (trustedValue !== undefined) {
            writeNestedField(targetRecord, field, structuredClone(trustedValue));
        }
        else {
            deleteNestedField(targetRecord, field);
        }
    }
}
function assertMatchingMountTopology(persistedManifest, trustedManifest, persisted, trusted) {
    if (persistedManifest.root !== trustedManifest.root) {
        throw new errors_2.SandboxMountError('Sandbox session state mount root does not match current trusted configuration.', undefined, 'mount_config_invalid');
    }
    const allPaths = new Set([...persisted.keys(), ...trusted.keys()]);
    const topologyMismatch = [...allPaths]
        .filter((path) => !persisted.has(path) || !trusted.has(path))
        .sort();
    if (topologyMismatch.length > 0) {
        throw new errors_2.SandboxMountError(`Sandbox session state mount topology does not match current trusted configuration for these entry paths: ${topologyMismatch.join(', ')}.`, undefined, 'mount_config_invalid');
    }
    const configMismatch = [...persisted.keys()]
        .filter((path) => (0, stableJson_1.stableJsonStringify)(redactMountCredentialsForPersistence(persisted.get(path))) !==
        (0, stableJson_1.stableJsonStringify)(redactMountCredentialsForPersistence(trusted.get(path))))
        .sort();
    if (configMismatch.length > 0) {
        throw new errors_2.SandboxMountError(`Sandbox session state mount configuration does not match current trusted configuration for these entry paths: ${configMismatch.join(', ')}.`, undefined, 'mount_config_invalid');
    }
}
function assertCredentialPathsReferenceMounts(paths, mounts) {
    if (paths.some((path) => !mounts.has(path))) {
        throw new TypeError('Persisted sandbox mount credential marker contains an invalid path.');
    }
}
function mountsByLogicalPath(manifest) {
    return new Map([...manifest.iterEntries()]
        .filter(({ entry }) => (0, entries_1.isMount)(entry))
        .map(({ logicalPath, entry }) => [
        logicalPath,
        entry,
    ]));
}
function mountCredentialAuthoritySignature(manifest, effectivePathSource) {
    const effectivePaths = validatedMountEffectivePaths.get(effectivePathSource);
    return (0, stableJson_1.stableJsonStringify)(manifest
        .mountTargets()
        .sort((left, right) => left.logicalPath.localeCompare(right.logicalPath))
        .map(({ logicalPath, mountPath, entry: mount }) => {
        const mountRecord = mount;
        const effectivePath = effectivePaths?.get(logicalPath) ?? (0, posixPath_1.normalizePosixPath)(mountPath);
        const credentials = Object.fromEntries(configuredMountCredentialFields(mount).map((field) => [
            field,
            readNestedField(mountRecord, field),
        ]));
        return {
            path: logicalPath,
            effectivePath,
            credentials,
            inContainerExposureAcknowledgement: mountCredentialExposureAcknowledgement(manifest, effectivePath),
        };
    }));
}
function assertMountCredentialFilesAreNotSerializedManifestEntries(manifest, entry, mountPath, credentialEnvironment = {}) {
    const credentialFiles = mountCredentialFileReferences(manifest, entry, credentialEnvironment);
    const manifestEntries = [...manifest.iterEntries()];
    const serializedCredentialFields = credentialFiles
        .filter(({ path }) => {
        const normalized = path.startsWith('/')
            ? (0, posixPath_1.normalizePosixPath)(path)
            : (0, manifest_1.normalizeRelativePath)(path);
        return manifestEntries.some(({ logicalPath, absolutePath, entry }) => {
            const entryPath = path.startsWith('/') ? absolutePath : logicalPath;
            return (entryPath === normalized ||
                (entryIsRecursiveSource(entry) &&
                    (0, posixPath_1.isUnderPosixPath)(normalized, entryPath)));
        });
    })
        .map(({ field }) => field)
        .sort();
    if (serializedCredentialFields.length === 0) {
        return;
    }
    throw new errors_2.SandboxMountError('Mount credential files cannot come from a serialized manifest entry.', {
        mountPath,
        mountType: entry.type,
        credentialFields: serializedCredentialFields,
    }, 'mount_config_invalid');
}
function mountCredentialFileReferences(manifest, entry, environment = {}) {
    const pattern = mountStrategyPattern(entry.mountStrategy);
    const entryRecord = entry;
    const credentialFiles = new Map();
    for (const [field, value] of [
        ['serviceAccountFile', entryRecord.serviceAccountFile],
        ['boxConfigFile', entryRecord.boxConfigFile],
        ['mountStrategy.pattern.configFilePath', pattern?.configFilePath],
    ]) {
        if (typeof value === 'string' && value.trim() !== '') {
            credentialFiles.set(field, value);
        }
    }
    const credentialEnvironment = mountCredentialEnvironmentForEntry(entry, mountEffectiveEnvironment(manifest, environment));
    for (const [name, value] of Object.entries(credentialEnvironment)) {
        if (isMountCredentialFileEnvironmentName(name) && value.trim() !== '') {
            credentialFiles.set(`environment.${name}`, value);
        }
    }
    return [...credentialFiles].map(([field, path]) => ({ field, path }));
}
function validateMountCredentialFileEffectivePaths(args) {
    const serializedCredentialFields = args.credentialFiles
        .filter(({ path }) => args.manifestEntries.some((entry) => entry.path === path ||
        (entry.recursive && (0, posixPath_1.isUnderPosixPath)(path, entry.path))))
        .map(({ field }) => field)
        .sort();
    if (serializedCredentialFields.length === 0) {
        return;
    }
    throw new errors_2.SandboxMountError('Mount credential files cannot resolve to a serialized manifest entry.', {
        mountPath: args.mountPath,
        mountType: args.entry.type,
        credentialFields: serializedCredentialFields,
    }, 'mount_config_invalid');
}
function entryIsRecursiveSource(entry) {
    return entry.type === 'local_dir' || entry.type === 'git_repo';
}
function mountCredentialEnvironmentNamesForPersistence(manifest, environment) {
    const names = new Set();
    const configuredNames = new Set([
        ...Object.keys(manifest.environment),
        ...Object.keys(environment),
    ]);
    for (const { entry } of manifest.mountTargets()) {
        if (!(0, entries_1.isMount)(entry) ||
            !ENVIRONMENT_CREDENTIAL_STRATEGIES.has(mountStrategyType(entry))) {
            continue;
        }
        if (mountUsesRcloneEnvironment(entry)) {
            for (const name of configuredNames) {
                if (name === 'RCLONE_CONFIG' || name.startsWith('RCLONE_CONFIG_')) {
                    names.add(name);
                }
            }
        }
        if (entry.type === 's3_mount' ||
            entry.type === 'r2_mount' ||
            entry.type === 's3_files_mount') {
            for (const name of [
                ...S3_MOUNT_CREDENTIAL_ENVIRONMENT_NAMES,
                ...S3_MOUNT_BROAD_CREDENTIAL_ENVIRONMENT_NAMES,
            ]) {
                if (configuredNames.has(name)) {
                    names.add(name);
                }
            }
        }
        if (entry.type === 'gcs_mount') {
            for (const name of GCS_MOUNT_ENVIRONMENT_NAMES) {
                if (configuredNames.has(name)) {
                    names.add(name);
                }
            }
        }
    }
    return names;
}
function mountCredentialEnvironmentForEntry(entry, environment) {
    if (!(0, entries_1.isMount)(entry)) {
        return {};
    }
    if (!ENVIRONMENT_CREDENTIAL_STRATEGIES.has(mountStrategyType(entry))) {
        return {};
    }
    const names = new Set();
    if (mountUsesRcloneEnvironment(entry)) {
        for (const name of Object.keys(environment)) {
            if (name === 'RCLONE_CONFIG' || name.startsWith('RCLONE_CONFIG_')) {
                names.add(name);
            }
        }
    }
    const entryRecord = entry;
    const usesS3EntryCredentialPair = Boolean(entryRecord.accessKeyId && entryRecord.secretAccessKey);
    const exposesShadowedCredentialEnvironment = mountUsesRcloneEnvironment(entry);
    const usesS3CredentialEnvironment = ((!usesS3EntryCredentialPair || exposesShadowedCredentialEnvironment) &&
        S3_MOUNT_CREDENTIAL_ENVIRONMENT_NAMES.some((name) => environment[name] !== undefined)) ||
        S3_MOUNT_BROAD_CREDENTIAL_ENVIRONMENT_NAMES.some((name) => environment[name] !== undefined);
    if ((entry.type === 's3_mount' ||
        entry.type === 'r2_mount' ||
        entry.type === 's3_files_mount') &&
        usesS3CredentialEnvironment) {
        const environmentNames = usesS3EntryCredentialPair && !exposesShadowedCredentialEnvironment
            ? S3_MOUNT_BROAD_CREDENTIAL_ENVIRONMENT_NAMES
            : S3_MOUNT_ENVIRONMENT_NAMES;
        for (const name of environmentNames) {
            names.add(name);
        }
    }
    const usesGcsEntryCredentials = Boolean((entryRecord.accessId && entryRecord.secretAccessKey) ||
        entryRecord.serviceAccountCredentials ||
        entryRecord.serviceAccountFile ||
        entryRecord.accessToken);
    if (entry.type === 'gcs_mount' &&
        (!usesGcsEntryCredentials || exposesShadowedCredentialEnvironment) &&
        environment.GOOGLE_APPLICATION_CREDENTIALS !== undefined) {
        for (const name of GCS_MOUNT_ENVIRONMENT_NAMES) {
            names.add(name);
        }
    }
    return Object.fromEntries([...names].flatMap((name) => environment[name] === undefined ? [] : [[name, environment[name]]]));
}
function mountCredentialEnvironmentAuthoritySignature(manifest, environment) {
    return (0, stableJson_1.stableJsonStringify)(manifest
        .mountTargets()
        .map(({ mountPath, entry }) => ({
        mountPath,
        environment: mountCredentialEnvironmentForEntry(entry, environment),
    }))
        .filter(({ environment: authority }) => Object.keys(authority).length > 0)
        .sort(({ mountPath: left }, { mountPath: right }) => left.localeCompare(right)));
}
function mountStrategyType(entry) {
    const type = entry.mountStrategy?.type;
    return typeof type === 'string' ? type : '<unknown>';
}
function mountStrategyPattern(value) {
    if (!isRecord(value)) {
        return undefined;
    }
    return isRecord(value.pattern) ? value.pattern : undefined;
}
function mountUsesRcloneEnvironment(entry) {
    const strategyType = mountStrategyType(entry);
    if (strategyType === 'vercel_cloud_bucket') {
        return false;
    }
    if (strategyType === 'e2b_cloud_bucket' ||
        strategyType === 'daytona_cloud_bucket') {
        return true;
    }
    const patternType = mountStrategyPattern(entry.mountStrategy)?.type;
    if (patternType !== undefined) {
        return patternType === 'rclone';
    }
    return (strategyType === 'in_container' &&
        (entry.type === 's3_mount' ||
            entry.type === 'r2_mount' ||
            entry.type === 'gcs_mount' ||
            entry.type === 'azure_blob_mount' ||
            entry.type === 'box_mount'));
}
function strategyFieldContainsCredentials(field, value) {
    if (field === 'mountStrategy.pattern.args' ||
        field === 'mountStrategy.pattern.extraArgs') {
        return !isCredentialFreeRcloneArgumentList(value);
    }
    if (Array.isArray(value)) {
        return value.length > 0;
    }
    if (isRecord(value)) {
        return Object.keys(value).length > 0;
    }
    if (typeof value === 'string') {
        return value.trim().length > 0;
    }
    return field.endsWith('configFilePath') || value !== undefined;
}
function readNestedField(record, field) {
    let current = record;
    for (const segment of field.split('.')) {
        if (!isRecord(current)) {
            return undefined;
        }
        current = current[segment];
    }
    return current;
}
function writeNestedField(record, field, value) {
    const segments = field.split('.');
    let current = record;
    for (const segment of segments.slice(0, -1)) {
        if (!isRecord(current[segment])) {
            current[segment] = {};
        }
        current = current[segment];
    }
    current[segments.at(-1)] = value;
}
function deleteNestedField(record, field) {
    const segments = field.split('.');
    let current = record;
    for (const segment of segments.slice(0, -1)) {
        if (!isRecord(current[segment])) {
            return;
        }
        current = current[segment];
    }
    delete current[segments.at(-1)];
}
function isRecord(value) {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
}
//# sourceMappingURL=mountSecurity.js.map