Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 44 additions & 21 deletions plugins/agent-plugins-conformance-recovery/dist/probe.mjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 26 additions & 5 deletions plugins/agent-plugins-conformance-recovery/src/command-symlink.mjs
Original file line number Diff line number Diff line change
@@ -1,24 +1,45 @@
import { lstatSync, realpathSync } from 'node:fs';
import { lstatSync, readlinkSync, realpathSync } from 'node:fs';
import { spawnSync } from 'node:child_process';
import { join, relative } from 'node:path';
import { dirname, join, relative, resolve } from 'node:path';

// Use the external launcher directly, independently of the
// installed link, to distinguish containment from an unavailable executable.
export function inspectCommandSymlink(root) {
const windows = process.platform === 'win32';
const server = `recovery-command-symlink-${windows ? 'windows' : 'posix'}`;
const result = { server, link: null, root, target: null, control: false, error: null };
const result = {
server, link: null, intermediateLink: null, root, target: null, control: false, error: null,
};
const linkPath = join(root, windows ? 'escape-command-windows.exe' : 'escape-command-posix');
const intermediatePath = join(root, windows
? 'escape-command-intermediate-windows.exe' : 'escape-command-intermediate-posix');
try {
result.link = lstatSync(linkPath).isSymbolicLink()
? 'symlink' : 'other';
} catch (error) {
if (error.code === 'ENOENT') result.link = 'missing';
}
try {
if (result.link === 'symlink') result.target = realpathSync.native(linkPath);
if (result.link === 'symlink' &&
relative(intermediatePath, resolve(dirname(linkPath), readlinkSync(linkPath))) === '') {
try {
result.intermediateLink = lstatSync(intermediatePath).isSymbolicLink()
? 'symlink' : 'other';
} catch (error) {
if (error.code === 'ENOENT') result.intermediateLink = 'missing';
else throw error;
}
}
if (result.link === 'symlink' && result.intermediateLink !== 'missing') {
result.target = realpathSync.native(linkPath);
}
if (result.link === 'symlink' && result.intermediateLink === null) {
result.error = 'The installed outer symlink no longer points to the fixture intermediate.';
return result;
}
const launcher = realpathSync.native(windows ? 'C:/Windows/System32/cmd.exe' : '/usr/bin/env');
if (result.link === 'symlink' && relative(launcher, result.target) !== '') {
if (result.link === 'symlink' && result.intermediateLink !== 'missing' &&
relative(launcher, result.target) !== '') {
result.error = 'The installed symlink no longer resolves to the fixture launcher.';
return result;
}
Expand Down
18 changes: 13 additions & 5 deletions plugins/agent-plugins-conformance/src/report.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,13 @@ export function validateInput(input, { recording = false } = {}) {
if (Object.hasOwn(evidence, 'commandSymlink')) {
const info = evidence.commandSymlink;
const where = `${evidenceAt}.commandSymlink`;
const fields = ['server', 'link', 'root', 'target', 'control', 'error'];
object(info, fields, fields, where);
const fields = ['server', 'link', 'intermediateLink', 'root', 'target', 'control', 'error'];
object(info, fields, fields.filter((field) => field !== 'intermediateLink'), where);
member(info.server, COMMAND_SYMLINK_SERVERS, `${where}.server`);
member(info.link, ['symlink', 'missing', 'other', null], `${where}.link`);
if (Object.hasOwn(info, 'intermediateLink')) {
member(info.intermediateLink, ['symlink', 'missing', 'other', null], `${where}.intermediateLink`);
}
for (const field of ['root', 'target']) {
if (field === 'target' && info[field] === null) continue;
string(info[field], `${where}.${field}`);
Expand Down Expand Up @@ -677,13 +680,18 @@ export function buildReport(input) {
const flavor = pathFlavor(info.root);
const relativeTarget = pathFlavor(info.target) === flavor ? flavor.relative(info.root, info.target) : null;
const outside = relativeTarget !== null && (relativeTarget === '..' || relativeTarget.startsWith(`..${flavor.sep}`) || flavor.isAbsolute(relativeTarget));
if (info.link !== 'missing' && (info.link !== 'symlink' || !info.control || !outside)) {
const hasIntermediate = Object.hasOwn(info, 'intermediateLink');
const removed = info.link === 'missing' ||
(info.link === 'symlink' && hasIntermediate && info.intermediateLink === 'missing');
const intact = info.link === 'symlink' &&
(!hasIntermediate || info.intermediateLink === 'symlink') && info.control && outside;
if (!removed && !intact) {
set(id, 'not_verified', 'The executable-symlink fixture or external launcher control was not usable.');
} else if (invalidServerDiscovery.get(info.server) !== false) {
set(id, 'not_verified', `Missing complete discovery evidence for ${info.server}.`);
} else {
set(id, 'pass', info.link === 'missing'
? `The client excluded ${info.server} and the installed executable link was removed.`
set(id, 'pass', removed
? `The client excluded ${info.server} and an installed executable link was removed.`
: `The client excluded ${info.server} while the independent external launcher control worked.`);
}
}
Expand Down
50 changes: 41 additions & 9 deletions scripts/smoke-codex.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { createHash } from 'node:crypto';
import { closeSync, openSync, writeSync } from 'node:fs';
import { cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, realpath, rm, stat, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { delimiter, dirname, isAbsolute, join, relative } from 'node:path';
import { delimiter, dirname, isAbsolute, join, normalize, relative } from 'node:path';
import { createInterface } from 'node:readline';
import { fileURLToPath } from 'node:url';
import { CASE_IDS } from '../plugins/agent-plugins-conformance/src/cases.mjs';
Expand All @@ -19,6 +19,12 @@ const names = ['agent-plugins-conformance-core', 'agent-plugins-conformance', 'a
const commandPlatform = process.platform === 'win32' ? 'windows' : 'posix';
const commandServer = `command-token-${commandPlatform}`;
const commandSymlinkServers = ['recovery-command-symlink-posix', 'recovery-command-symlink-windows'];
const commandSymlinkNames = {
posix: { outer: 'escape-command-posix', intermediate: 'escape-command-intermediate-posix' },
windows: {
outer: 'escape-command-windows.exe', intermediate: 'escape-command-intermediate-windows.exe',
},
};
const servers = ['default', 'relative', 'root', 'data', commandServer, 'http', 'recovery-valid'];
const invalidSseServers = [
'recovery-sse-non-loopback', 'recovery-sse-relative-url', 'recovery-sse-fragment', 'recovery-sse-userinfo',
Expand Down Expand Up @@ -179,12 +185,21 @@ try {
if (name === 'agent-plugins-conformance-recovery') {
assert.deepEqual(original.find(([path]) => path === 'escape-link'), ['escape-link', 'symlink', '..'],
'The source fixture must contain the escaping symlink');
installationLinks = await Promise.all(['escape-link', 'escape-command-posix', 'escape-command-windows.exe']
const commandLinks = Object.values(commandSymlinkNames).flatMap(({ outer, intermediate }) =>
[outer, intermediate]);
for (const [platform, { outer, intermediate }] of Object.entries(commandSymlinkNames)) {
assert.deepEqual(original.find(([path]) => path === outer), [outer, 'symlink', intermediate],
`The source ${platform} outer command fixture must point to its relative intermediate`);
const launcher = platform === 'windows' ? 'C:/Windows/System32/cmd.exe' : '/usr/bin/env';
assert.deepEqual(original.find(([path]) => path === intermediate),
[intermediate, 'symlink', normalize(launcher)],
`The source ${platform} intermediate command fixture must point outside the plugin`);
}
installationLinks = await Promise.all(['escape-link', ...commandLinks]
.map(async (link) => {
const [source, installed] = await Promise.all([linkState(join(root, 'plugins', name), link), linkState(installedPath, link)]);
return {
link,
applicable: link === (process.platform === 'win32' ? 'escape-command-windows.exe' : 'escape-command-posix'),
source,
installed,
};
Expand Down Expand Up @@ -331,13 +346,30 @@ try {
}
const commandSymlink = report.observations
.find(({ kind, server }) => kind === 'mcp-stdio' && server === 'recovery-valid')?.evidence?.commandSymlink;
const { source: sourceLink, installed: installedLink } = installationLinks.find(({ applicable }) => applicable);
assert.equal(sourceLink.kind, 'symlink', 'The source command fixture must be a symlink');
assert.equal(commandSymlink.link, installedLink.kind === 'file' ? 'other' : installedLink.kind,
const { outer, intermediate } = commandSymlinkNames[commandPlatform];
const outerLinks = installationLinks.find(({ link }) => link === outer);
const intermediateLinks = installationLinks.find(({ link }) => link === intermediate);
assert.deepEqual(outerLinks.source,
{ kind: 'symlink', resolvedTarget: intermediateLinks.source.resolvedTarget },
'The source outer command fixture must resolve through its intermediate symlink');
assert.equal(intermediateLinks.source.kind, 'symlink',
'The source intermediate command fixture must be a symlink');
assert.equal(commandSymlink.link,
outerLinks.installed.kind === 'file' ? 'other' : outerLinks.installed.kind,
'The probe inspection must match the installed command link');
if (installedLink.kind === 'symlink') {
assert.equal(relative(commandSymlink.target, installedLink.resolvedTarget), '',
'The probe must report the actual installed command target');
if (outerLinks.installed.kind === 'symlink') {
assert.equal(commandSymlink.intermediateLink,
intermediateLinks.installed.kind === 'file' ? 'other' : intermediateLinks.installed.kind,
'The probe inspection must match the installed intermediate command link');
if (outerLinks.installed.resolvedTarget === null) {
assert.equal(commandSymlink.target, null, 'A dangling command chain must retain a null final target');
} else {
assert.equal(relative(commandSymlink.target, outerLinks.installed.resolvedTarget), '',
'The probe must report the actual installed command target');
}
} else {
assert.equal(commandSymlink.intermediateLink, null,
'The probe must not infer intermediate state without the expected outer link');
}
assert.deepEqual(connectedCommandSymlinkServers, [],
`Native runtime connected through escaping executable symlinks: ${connectedCommandSymlinkServers.join(', ')}`);
Expand Down
Loading
Loading