/**
 * @license
 * Copyright 2026 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { MacOsSandboxManager } from './MacOsSandboxManager.js';
import { ShellExecutionService } from '../../services/shellExecutionService.js';
import { getSecureSanitizationConfig } from '../../services/environmentSanitization.js';
import {} from '../../services/sandboxManager.js';
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
import os from 'node:os';
import fs from 'node:fs';
import path from 'node:path';
import http from 'node:http';
/**
 * A simple asynchronous wrapper for execFile that returns the exit status,
 * stdout, and stderr. Unlike spawnSync, this does not block the Node.js
 * event loop, allowing the local HTTP test server to function.
 */
async function runCommand(command) {
    try {
        const { stdout, stderr } = await promisify(execFile)(command.program, command.args, {
            cwd: command.cwd,
            env: command.env,
            encoding: 'utf-8',
        });
        return { status: 0, stdout, stderr };
    }
    catch (error) {
        const err = error;
        return {
            status: err.code ?? 1,
            stdout: err.stdout ?? '',
            stderr: err.stderr ?? '',
        };
    }
}
describe.skipIf(os.platform() !== 'darwin')('MacOsSandboxManager Integration', () => {
    describe('Basic Execution', () => {
        it('should execute commands within the workspace', async () => {
            const manager = new MacOsSandboxManager({ workspace: process.cwd() });
            const command = await manager.prepareCommand({
                command: 'echo',
                args: ['sandbox test'],
                cwd: process.cwd(),
                env: process.env,
            });
            const execResult = await runCommand(command);
            expect(execResult.status).toBe(0);
            expect(execResult.stdout.trim()).toBe('sandbox test');
        });
        it('should support interactive pseudo-terminals (node-pty)', async () => {
            const manager = new MacOsSandboxManager({ workspace: process.cwd() });
            const abortController = new AbortController();
            // Verify that node-pty file descriptors are successfully allocated inside the sandbox
            // by using the bash [ -t 1 ] idiom to check if stdout is a TTY.
            const handle = await ShellExecutionService.execute('bash -c "if [ -t 1 ]; then echo True; else echo False; fi"', process.cwd(), () => { }, abortController.signal, true, {
                sanitizationConfig: getSecureSanitizationConfig(),
                sandboxManager: manager,
            });
            const result = await handle.result;
            expect(result.error).toBeNull();
            expect(result.exitCode).toBe(0);
            expect(result.output).toContain('True');
        });
    });
    describe('File System Access', () => {
        it('should block file system access outside the workspace', async () => {
            const manager = new MacOsSandboxManager({ workspace: process.cwd() });
            const blockedPath = '/Users/Shared/.gemini_test_sandbox_blocked';
            const command = await manager.prepareCommand({
                command: 'touch',
                args: [blockedPath],
                cwd: process.cwd(),
                env: process.env,
            });
            const execResult = await runCommand(command);
            expect(execResult.status).not.toBe(0);
            expect(execResult.stderr).toContain('Operation not permitted');
        });
        it('should grant file system access to explicitly allowed paths', async () => {
            // Create a unique temporary directory to prevent artifacts and test flakiness
            const allowedDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gemini-sandbox-test-'));
            try {
                const manager = new MacOsSandboxManager({
                    workspace: process.cwd(),
                });
                const testFile = path.join(allowedDir, 'test.txt');
                const command = await manager.prepareCommand({
                    command: 'touch',
                    args: [testFile],
                    cwd: process.cwd(),
                    env: process.env,
                    policy: {
                        allowedPaths: [allowedDir],
                    },
                });
                const execResult = await runCommand(command);
                expect(execResult.status).toBe(0);
            }
            finally {
                fs.rmSync(allowedDir, { recursive: true, force: true });
            }
        });
    });
    describe('Network Access', () => {
        let testServer;
        let testServerUrl;
        beforeAll(async () => {
            testServer = http.createServer((_, res) => {
                // Ensure connections are closed immediately to prevent hanging
                res.setHeader('Connection', 'close');
                res.writeHead(200);
                res.end('ok');
            });
            await new Promise((resolve, reject) => {
                testServer.on('error', reject);
                testServer.listen(0, '127.0.0.1', () => {
                    const address = testServer.address();
                    testServerUrl = `http://127.0.0.1:${address.port}`;
                    resolve();
                });
            });
        });
        afterAll(async () => {
            if (testServer) {
                await new Promise((resolve) => {
                    testServer.close(() => resolve());
                });
            }
        });
        it('should block network access by default', async () => {
            const manager = new MacOsSandboxManager({ workspace: process.cwd() });
            const command = await manager.prepareCommand({
                command: 'curl',
                args: ['-s', '--connect-timeout', '1', testServerUrl],
                cwd: process.cwd(),
                env: process.env,
            });
            const execResult = await runCommand(command);
            expect(execResult.status).not.toBe(0);
        });
        it('should grant network access when explicitly allowed', async () => {
            const manager = new MacOsSandboxManager({
                workspace: process.cwd(),
            });
            const command = await manager.prepareCommand({
                command: 'curl',
                args: ['-s', '--connect-timeout', '1', testServerUrl],
                cwd: process.cwd(),
                env: process.env,
                policy: {
                    networkAccess: true,
                },
            });
            const execResult = await runCommand(command);
            expect(execResult.status).toBe(0);
            expect(execResult.stdout.trim()).toBe('ok');
        });
    });
});
//# sourceMappingURL=MacOsSandboxManager.integration.test.js.map