| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, | |
| * software distributed under the License is distributed on an | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the | |
| * specific language governing permissions and limitations | |
| * under the License. | |
| */ | |
| import assert from 'node:assert/strict'; | |
| import { spawnSync } from 'node:child_process'; | |
| import { | |
| chmod, | |
| mkdir, | |
| mkdtemp, | |
| readFile, | |
| realpath, | |
| rm, | |
| symlink, | |
| writeFile, | |
| } from 'node:fs/promises'; | |
| import { tmpdir } from 'node:os'; | |
| import { join } from 'node:path'; | |
| import { test } from 'node:test'; | |
| import { fileURLToPath } from 'node:url'; | |
| import { requireComputerUseLabRoot } from './lab-root.mjs'; | |
| test('Computer Use CLI advertises only the supported evidence commands', () => { | |
| const result = spawnSync( | |
| process.execPath, | |
| [fileURLToPath(new URL('../computer-use.mjs', import.meta.url)), '--help'], | |
| { encoding: 'utf8' }, | |
| ); | |
| assert.equal(result.status, 0, result.stderr); | |
| assert.equal( | |
| result.stdout, | |
| `Usage: node scripts/computer-use.mjs <command> [options]\n\nCommands:\n prepare\n real-ax\n real-model\n restart-soak\n provider-matrix\n`, | |
| ); | |
| }); | |
| test('rejects missing and invalid Computer Use Lab roots', async () => { | |
| const root = await mkdtemp(join(tmpdir(), 'maka-cu-lab-root-invalid-')); | |
| try { | |
| assert.throws( | |
| () => requireComputerUseLabRoot({}), | |
| new Error( | |
| 'MAKA_CU_AX_MODEL_LAB_ROOT is required: point it at a local checkout of the Codex CUA Lab fixture', | |
| ), | |
| ); | |
| assert.throws( | |
| () => requireComputerUseLabRoot({ MAKA_CU_AX_MODEL_LAB_ROOT: ' ' }), | |
| /MAKA_CU_AX_MODEL_LAB_ROOT is required/, | |
| ); | |
| assert.throws( | |
| () => requireComputerUseLabRoot({ MAKA_CU_AX_MODEL_LAB_ROOT: 'relative/lab' }), | |
| /MAKA_CU_AX_MODEL_LAB_ROOT must be an absolute path/, | |
| ); | |
| assert.throws( | |
| () => requireComputerUseLabRoot({ MAKA_CU_AX_MODEL_LAB_ROOT: join(root, 'missing') }), | |
| /MAKA_CU_AX_MODEL_LAB_ROOT must point to an existing directory/, | |
| ); | |
| assert.throws( | |
| () => requireComputerUseLabRoot({ MAKA_CU_AX_MODEL_LAB_ROOT: root }), | |
| /MAKA_CU_AX_MODEL_LAB_ROOT must contain an executable test-app\/launch\.sh/, | |
| ); | |
| const nonExecutableRoot = join(root, 'non-executable'); | |
| const launcherPath = join(nonExecutableRoot, 'test-app', 'launch.sh'); | |
| await mkdir(join(nonExecutableRoot, 'test-app'), { recursive: true }); | |
| await writeFile(launcherPath, '#!/usr/bin/env bash\n'); | |
| await chmod(launcherPath, 0o644); | |
| assert.throws( | |
| () => requireComputerUseLabRoot({ MAKA_CU_AX_MODEL_LAB_ROOT: nonExecutableRoot }), | |
| /MAKA_CU_AX_MODEL_LAB_ROOT must contain an executable test-app\/launch\.sh/, | |
| ); | |
| } finally { | |
| await rm(root, { recursive: true, force: true }); | |
| } | |
| }); | |
| test('canonicalizes a valid Computer Use Lab root', async () => { | |
| const root = await mkdtemp(join(tmpdir(), 'maka-cu-lab-root-valid-')); | |
| try { | |
| const fixtureRoot = join(root, 'fixture'); | |
| const linkedRoot = join(root, 'fixture-link'); | |
| const launcherPath = join(fixtureRoot, 'test-app', 'launch.sh'); | |
| await mkdir(join(fixtureRoot, 'test-app'), { recursive: true }); | |
| await writeFile(launcherPath, '#!/usr/bin/env bash\n'); | |
| await chmod(launcherPath, 0o755); | |
| await symlink(fixtureRoot, linkedRoot); | |
| assert.equal( | |
| requireComputerUseLabRoot({ MAKA_CU_AX_MODEL_LAB_ROOT: linkedRoot }), | |
| await realpath(fixtureRoot), | |
| ); | |
| } finally { | |
| await rm(root, { recursive: true, force: true }); | |
| } | |
| }); | |
| test('Lab-backed entry points require the configured root', async () => { | |
| const entryPoints = [ | |
| 'process-restart-harness.mjs', | |
| 'process-restart-launcher.mjs', | |
| 'real-ax-harness.mjs', | |
| 'real-ax-launcher.mjs', | |
| ]; | |
| for (const entryPoint of entryPoints) { | |
| const source = await readFile(new URL(entryPoint, import.meta.url), 'utf8'); | |
| assert.match( | |
| source, | |
| /const labRoot = requireComputerUseLabRoot\(\);/, | |
| `${entryPoint} must require the configured Lab root`, | |
| ); | |
| assert.doesNotMatch( | |
| source, | |
| /codex-computer-use-lab/i, | |
| `${entryPoint} must not embed a contributor-specific Lab checkout`, | |
| ); | |
| } | |
| }); | |
| test('real AX harness supplies every explicit runtime permission authority', async () => { | |
| const source = await readFile(new URL('real-ax-harness.mjs', import.meta.url), 'utf8'); | |
| assert.match(source, /readExecutionBoundary:\s*async \(\) =>/); | |
| assert.match(source, /readPermissionMode:\s*async \(\) => 'bypass'/); | |
| }); |