/**
 * @license
 * Copyright 2026 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import toml from '@iarna/toml';
import { z } from 'zod';
import { fileURLToPath } from 'node:url';
import { debugLogger } from '../utils/debugLogger.js';
import {} from '../services/sandboxManager.js';
import { sanitizePaths } from '../services/sandboxManager.js';
export const SandboxModeConfigSchema = z.object({
    network: z.boolean(),
    readonly: z.boolean(),
    approvedTools: z.array(z.string()),
    allowOverrides: z.boolean().optional(),
});
export const PersistentCommandConfigSchema = z.object({
    allowed_paths: z.array(z.string()).optional(),
    allow_network: z.boolean().optional(),
});
export const SandboxTomlSchema = z.object({
    modes: z.object({
        plan: SandboxModeConfigSchema,
        default: SandboxModeConfigSchema,
        accepting_edits: SandboxModeConfigSchema,
    }),
    commands: z.record(z.string(), PersistentCommandConfigSchema).default({}),
});
export class SandboxPolicyManager {
    static _DEFAULT_CONFIG = null;
    static get DEFAULT_CONFIG() {
        if (!SandboxPolicyManager._DEFAULT_CONFIG) {
            const __filename = fileURLToPath(import.meta.url);
            const __dirname = path.dirname(__filename);
            const defaultPath = path.join(__dirname, 'policies', 'sandbox-default.toml');
            try {
                const content = fs.readFileSync(defaultPath, 'utf8');
                if (typeof content !== 'string') {
                    SandboxPolicyManager._DEFAULT_CONFIG = {
                        modes: {
                            plan: {
                                network: false,
                                readonly: true,
                                approvedTools: [],
                                allowOverrides: false,
                            },
                            default: {
                                network: false,
                                readonly: true,
                                approvedTools: [],
                                allowOverrides: true,
                            },
                            accepting_edits: {
                                network: false,
                                readonly: false,
                                approvedTools: ['sed', 'grep', 'awk', 'perl', 'cat', 'echo'],
                                allowOverrides: true,
                            },
                        },
                        commands: {},
                    };
                    return SandboxPolicyManager._DEFAULT_CONFIG;
                }
                SandboxPolicyManager._DEFAULT_CONFIG = SandboxTomlSchema.parse(toml.parse(content));
            }
            catch (e) {
                debugLogger.error(`Failed to parse default sandbox policy: ${e}`);
                throw new Error(`Failed to parse default sandbox policy: ${e}`);
            }
        }
        return SandboxPolicyManager._DEFAULT_CONFIG;
    }
    config;
    configPath;
    sessionApprovals = {};
    constructor(customConfigPath) {
        this.configPath =
            customConfigPath ??
                path.join(os.homedir(), '.gemini', 'policies', 'sandbox.toml');
        this.config = this.loadConfig();
    }
    loadConfig() {
        if (!fs.existsSync(this.configPath)) {
            return SandboxPolicyManager.DEFAULT_CONFIG;
        }
        try {
            const content = fs.readFileSync(this.configPath, 'utf8');
            return SandboxTomlSchema.parse(toml.parse(content));
        }
        catch (e) {
            debugLogger.error(`Failed to parse sandbox.toml: ${e}`);
            return SandboxPolicyManager.DEFAULT_CONFIG;
        }
    }
    saveConfig() {
        try {
            const dir = path.dirname(this.configPath);
            if (!fs.existsSync(dir)) {
                fs.mkdirSync(dir, { recursive: true });
            }
            // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
            const content = toml.stringify(this.config);
            fs.writeFileSync(this.configPath, content);
        }
        catch (e) {
            debugLogger.error(`Failed to save sandbox.toml: ${e}`);
        }
    }
    getModeConfig(mode) {
        if (mode === 'plan')
            return this.config.modes.plan;
        if (mode === 'accepting_edits' || mode === 'autoEdit')
            return this.config.modes.accepting_edits;
        if (mode === 'default')
            return this.config.modes.default;
        // Default fallback
        return this.config.modes.default ?? this.config.modes.plan;
    }
    getCommandPermissions(commandName) {
        const persistent = this.config.commands[commandName];
        const session = this.sessionApprovals[commandName];
        return {
            fileSystem: {
                read: [
                    ...(persistent?.allowed_paths ?? []),
                    ...(session?.fileSystem?.read ?? []),
                ],
                write: [
                    ...(persistent?.allowed_paths ?? []),
                    ...(session?.fileSystem?.write ?? []),
                ],
            },
            network: persistent?.allow_network || session?.network || false,
        };
    }
    addSessionApproval(commandName, permissions) {
        const existing = this.sessionApprovals[commandName] || {
            fileSystem: { read: [], write: [] },
            network: false,
        };
        this.sessionApprovals[commandName] = {
            fileSystem: {
                read: Array.from(new Set([
                    ...(existing.fileSystem?.read ?? []),
                    ...(permissions.fileSystem?.read ?? []),
                ])),
                write: Array.from(new Set([
                    ...(existing.fileSystem?.write ?? []),
                    ...(permissions.fileSystem?.write ?? []),
                ])),
            },
            network: existing.network || permissions.network || false,
        };
    }
    addPersistentApproval(commandName, permissions) {
        const existing = this.config.commands[commandName] || {
            allowed_paths: [],
            allow_network: false,
        };
        const newPathsArray = [
            ...(existing.allowed_paths ?? []),
            ...(permissions.fileSystem?.read ?? []),
            ...(permissions.fileSystem?.write ?? []),
        ];
        const newPaths = new Set(sanitizePaths(newPathsArray));
        this.config.commands[commandName] = {
            allowed_paths: Array.from(newPaths),
            allow_network: existing.allow_network || permissions.network || false,
        };
        this.saveConfig();
    }
}
//# sourceMappingURL=sandboxPolicyManager.js.map