🧲 feat: Enable Secure Attached Environment Pairing (#15355)

* feat: add secure code environment pairing

* fix: satisfy code environment type checks

* fix: secure code environment administration

* fix: isolate code pairing control plane

* fix: validate code pairing control responses

* fix: secure code pairing transport

* fix: validate code pairing wire format

* fix: harden pairing secret lookup
This commit is contained in:
Danny Avila 2026-08-30 17:12:20 -04:00 committed by GitHub
parent 7533d138fa
commit a9ccac8656
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 810 additions and 0 deletions

View file

@ -520,6 +520,7 @@ if (cluster.isMaster) {
app.use('/api/admin/insights', routes.insights);
app.use('/api/admin', routes.adminAuth);
app.use('/api/admin/skills', routes.adminSkills);
app.use('/api/admin/code-environments', routes.adminCodeEnvironments);
app.use('/api/actions', routes.actions);
app.use('/api/keys', routes.keys);
app.use('/api/api-keys', routes.apiKeys);

View file

@ -367,6 +367,7 @@ const startServer = async () => {
app.use('/api/admin/insights', routes.insights);
app.use('/api/admin', routes.adminAuth);
app.use('/api/admin/config', routes.adminConfig);
app.use('/api/admin/code-environments', routes.adminCodeEnvironments);
app.use('/api/admin/langfuse', routes.adminLangfuse);
app.use('/api/admin/grants', routes.adminGrants);
app.use('/api/admin/groups', routes.adminGroups);

View file

@ -0,0 +1,17 @@
const express = require('express');
const { createAdminCodeEnvironmentHandlers } = require('@librechat/api');
const { SystemCapabilities } = require('@librechat/data-schemas');
const { requireCapability } = require('~/server/middleware/roles/capabilities');
const { getAppConfig } = require('~/server/services/Config');
const { requireJwtAuth } = require('~/server/middleware');
const router = express.Router();
const requireAdminAccess = requireCapability(SystemCapabilities.ACCESS_ADMIN);
const requireCodeEnvironmentManage = requireCapability(SystemCapabilities.MANAGE_CODE_ENVIRONMENTS);
const handlers = createAdminCodeEnvironmentHandlers({ getAppConfig });
router.use(requireJwtAuth, requireAdminAccess, requireCodeEnvironmentManage);
router.post('/:environmentId/pairings', handlers.createPairing);
router.post('/:environmentId/revoke', handlers.revokeWorker);
module.exports = router;

View file

@ -0,0 +1,74 @@
const express = require('express');
const request = require('supertest');
const middlewareCalls = [];
const mockRequireJwtAuth = jest.fn((req, _res, next) => {
middlewareCalls.push('jwt');
req.user = { id: 'admin-1', role: 'ADMIN' };
next();
});
const mockRequireCapability = jest.fn((capability) => (req, _res, next) => {
middlewareCalls.push(capability);
next();
});
const mockHandlers = {
createPairing: jest.fn((req, res) =>
res.status(200).json({ operation: 'pair', environmentId: req.params.environmentId }),
),
revokeWorker: jest.fn((req, res) =>
res.status(200).json({ operation: 'revoke', environmentId: req.params.environmentId }),
),
};
const mockGetAppConfig = jest.fn();
jest.mock('@librechat/data-schemas', () => ({
SystemCapabilities: {
ACCESS_ADMIN: 'access:admin',
MANAGE_CODE_ENVIRONMENTS: 'manage:code_environments',
},
}));
jest.mock('@librechat/api', () => ({
createAdminCodeEnvironmentHandlers: jest.fn(() => mockHandlers),
}));
jest.mock('~/server/middleware/roles/capabilities', () => ({
requireCapability: mockRequireCapability,
}));
jest.mock('~/server/middleware', () => ({
requireJwtAuth: mockRequireJwtAuth,
}));
jest.mock('~/server/services/Config', () => ({
getAppConfig: mockGetAppConfig,
}));
function createApp() {
delete require.cache[require.resolve('./code')];
const router = require('./code');
const app = express();
app.use(express.json());
app.use('/api/admin/code-environments', router);
return app;
}
describe('admin code environment routes', () => {
beforeEach(() => {
middlewareCalls.length = 0;
jest.clearAllMocks();
});
it.each([
['pairings', 'createPairing', 'pair'],
['revoke', 'revokeWorker', 'revoke'],
])('protects and delegates the %s operation', async (path, handlerName, operation) => {
const response = await request(createApp())
.post(`/api/admin/code-environments/attached-vm/${path}`)
.expect(200);
expect(response.body).toEqual({ operation, environmentId: 'attached-vm' });
expect(middlewareCalls).toEqual(['jwt', 'access:admin', 'manage:code_environments']);
expect(mockHandlers[handlerName]).toHaveBeenCalledTimes(1);
});
});

View file

@ -3,6 +3,7 @@ const assistants = require('./assistants');
const categories = require('./categories');
const adminAuth = require('./admin/auth');
const adminConfig = require('./admin/config');
const adminCodeEnvironments = require('./admin/code');
const adminLangfuse = require('./admin/langfuse');
const adminGrants = require('./admin/grants');
const adminGroups = require('./admin/groups');
@ -47,6 +48,7 @@ module.exports = {
auth,
adminAuth,
adminConfig,
adminCodeEnvironments,
adminLangfuse,
adminGrants,
adminGroups,

View file

@ -136,6 +136,9 @@ const baseEnv = {
ASSISTANTS_API_KEY: 'e2e-mock-assistants-key',
ASSISTANTS_BASE_URL: `http://127.0.0.1:${ASSISTANTS_PORT}/v1`,
ASSISTANTS_MODELS: 'gpt-4o-mini',
...(process.env.E2E_CODE_BRIDGE_ADMIN_TOKEN
? { E2E_CODE_BRIDGE_ADMIN_TOKEN: process.env.E2E_CODE_BRIDGE_ADMIN_TOKEN }
: {}),
...vanillaOverrides,
};
@ -210,6 +213,14 @@ function writeRuntimeMockConfig() {
.replace('# __E2E_DYNAMIC_MCP_STDIO_ENV__', dynamicMcpConfig.stdioEnv)
.replace('# __E2E_DYNAMIC_MCP_NETWORK_SERVERS__', dynamicMcpConfig.networkServers);
const codeBridgeURL = process.env.E2E_CODE_BRIDGE_URL;
const codeBridgePairing = process.env.E2E_CODE_BRIDGE_ADMIN_TOKEN
? [
' owner: deployment',
' pairing:',
' workerId: e2e-vm',
' tokenEnv: E2E_CODE_BRIDGE_ADMIN_TOKEN',
]
: [];
config = config.replace(
'# __E2E_CODE_BRIDGE_CONFIG__',
codeBridgeURL
@ -223,6 +234,7 @@ function writeRuntimeMockConfig() {
' type: attached',
` baseURL: ${JSON.stringify(codeBridgeURL)}`,
' default: true',
...codeBridgePairing,
].join('\n ')
: '# __E2E_CODE_BRIDGE_CONFIG__',
);

View file

@ -12,6 +12,13 @@ import {
const CODE_VALUE = 'librechat-bridge-persisted';
interface PairingResponse {
environmentId: string;
workerId: string;
code: string;
expiresAt: string;
}
test.describe('attached stateful code environment', () => {
test.skip(!process.env.E2E_CODE_BRIDGE_URL, 'E2E_CODE_BRIDGE_URL is required');
@ -26,6 +33,21 @@ test.describe('attached stateful code environment', () => {
try {
const token = await getAccessToken(page);
if (process.env.E2E_CODE_BRIDGE_ADMIN_TOKEN) {
const pairing = await requestJson<PairingResponse>(page, {
path: '/api/admin/code-environments/e2e-vm/pairings',
token,
method: 'POST',
});
expect(pairing).toMatchObject({
environmentId: 'e2e-vm',
workerId: 'e2e-vm',
code: expect.stringMatching(/^[A-Za-z0-9_-]{32}$/),
expiresAt: expect.any(String),
});
expect(pairing).not.toHaveProperty('token');
expect(Number.isFinite(Date.parse(pairing.expiresAt))).toBe(true);
}
const agent = await requestJson<AgentDetail>(page, {
path: '/api/agents',
token,

View file

@ -578,6 +578,12 @@ endpoints:
# name: Engineering VM
# type: attached
# baseURL: https://code-bridge.example.com/v1
# # Enables the admin pairing API without placing the administrator
# # secret in YAML or returning its environment-variable name to users.
# owner: deployment
# pairing:
# workerId: engineering-vm
# tokenEnv: CODE_BRIDGE_ADMIN_TOKEN
# # (optional) Trusted origin for internal event delivery. By default, LibreChat
# # uses its own bound listener; override only for an internal TLS/front-door route.
# eventDriven:

View file

@ -0,0 +1,313 @@
import type { AppConfig } from '@librechat/data-schemas';
import type { Response } from 'express';
import type { ServerRequest } from '~/types/http';
import { createAdminCodeEnvironmentHandlers } from './code';
interface MockResponse extends Response {
statusCode: number;
body?: Record<string, unknown>;
}
function mockResponse(): MockResponse {
const response = {
statusCode: 200,
body: undefined as Record<string, unknown> | undefined,
status(code: number) {
response.statusCode = code;
return response;
},
json(body: Record<string, unknown>) {
response.body = body;
return response;
},
};
return response as unknown as MockResponse;
}
function request(): ServerRequest {
return {
params: { environmentId: 'attached-vm' },
user: { id: 'admin-1', role: 'ADMIN' },
} as unknown as ServerRequest;
}
function config(): AppConfig {
return {
endpoints: {
agents: {
statefulCodeSessions: {
allowedEnvironments: ['conversation'],
environments: [
{
id: 'attached-vm',
name: 'Attached VM',
type: 'attached',
baseURL: 'https://bridge.example.com/v1/',
default: true,
owner: 'deployment',
pairing: {
workerId: 'vm-1',
tokenEnv: 'CODE_BRIDGE_ADMIN_TOKEN',
},
},
],
},
},
},
} as unknown as AppConfig;
}
describe('createAdminCodeEnvironmentHandlers', () => {
it('creates a one-time pairing code without exposing the administrator token', async () => {
const fetchImpl = jest.fn().mockResolvedValue(
Response.json({
protocolVersion: 1,
workerId: 'vm-1',
code: 'one-time-code-value-that-is-long',
expiresAt: '2099-08-30T12:00:00.000Z',
}),
);
const handlers = createAdminCodeEnvironmentHandlers({
getAppConfig: jest.fn().mockResolvedValue(config()),
readSecret: jest.fn().mockReturnValue('administrator-bootstrap-token'),
fetchImpl,
});
const response = mockResponse();
await handlers.createPairing(request(), response);
expect(fetchImpl).toHaveBeenCalledWith(
'https://bridge.example.com/v1/bridge/pairings',
expect.objectContaining({
method: 'POST',
headers: {
Authorization: 'Bearer administrator-bootstrap-token',
'Content-Type': 'application/json',
},
body: JSON.stringify({ workerId: 'vm-1' }),
}),
);
expect(response.statusCode).toBe(200);
expect(response.body).toEqual({
environmentId: 'attached-vm',
workerId: 'vm-1',
code: 'one-time-code-value-that-is-long',
expiresAt: '2099-08-30T12:00:00.000Z',
});
expect(JSON.stringify(response.body)).not.toContain('administrator-bootstrap-token');
});
it('uses only YAML config when resolving pairing secrets and destinations', async () => {
const writableOverride = config();
const overriddenEnvironment =
writableOverride.endpoints?.agents?.statefulCodeSessions?.environments?.[0];
if (overriddenEnvironment == null) {
throw new Error('Expected the test code environment');
}
overriddenEnvironment.baseURL = 'https://attacker.example.com/v1';
overriddenEnvironment.pairing = { workerId: 'vm-1', tokenEnv: 'DATABASE_URL' };
const getAppConfig = jest.fn(async (options: { baseOnly?: boolean }) =>
options.baseOnly === true ? config() : writableOverride,
);
const readSecret = jest.fn((name: string) =>
name === 'CODE_BRIDGE_ADMIN_TOKEN' ? 'deployment-token' : 'sensitive-database-secret',
);
const fetchImpl = jest.fn().mockResolvedValue(
Response.json({
protocolVersion: 1,
workerId: 'vm-1',
code: 'one-time-code-value-that-is-long',
expiresAt: '2099-08-30T12:00:00.000Z',
}),
);
const handlers = createAdminCodeEnvironmentHandlers({
getAppConfig,
readSecret,
fetchImpl,
});
await handlers.createPairing(request(), mockResponse());
expect(getAppConfig).toHaveBeenCalledWith({ baseOnly: true });
expect(readSecret).toHaveBeenCalledWith('CODE_BRIDGE_ADMIN_TOKEN');
expect(readSecret).not.toHaveBeenCalledWith('DATABASE_URL');
expect(fetchImpl).toHaveBeenCalledWith(
'https://bridge.example.com/v1/bridge/pairings',
expect.any(Object),
);
});
it('fails closed before outbound traffic when the administrator token is unavailable', async () => {
const fetchImpl = jest.fn();
const handlers = createAdminCodeEnvironmentHandlers({
getAppConfig: jest.fn().mockResolvedValue(config()),
readSecret: jest.fn().mockReturnValue(undefined),
fetchImpl,
});
const response = mockResponse();
await handlers.createPairing(request(), response);
expect(response.statusCode).toBe(503);
expect(response.body).toEqual({ error: 'Code environment pairing is not configured' });
expect(fetchImpl).not.toHaveBeenCalled();
});
it('treats inherited process environment properties as missing secrets', async () => {
const deploymentConfig = config();
const environment = deploymentConfig.endpoints?.agents?.statefulCodeSessions?.environments?.[0];
if (environment?.pairing == null) throw new Error('Expected the test pairing configuration');
environment.pairing.tokenEnv = 'constructor';
const fetchImpl = jest.fn();
const handlers = createAdminCodeEnvironmentHandlers({
getAppConfig: jest.fn().mockResolvedValue(deploymentConfig),
fetchImpl,
});
const response = mockResponse();
await handlers.createPairing(request(), response);
expect(response.statusCode).toBe(503);
expect(response.body).toEqual({ error: 'Code environment pairing is not configured' });
expect(fetchImpl).not.toHaveBeenCalled();
});
it('normalizes the bridge base URL before appending control paths', async () => {
const deploymentConfig = config();
const environment = deploymentConfig.endpoints?.agents?.statefulCodeSessions?.environments?.[0];
if (environment == null) throw new Error('Expected the test code environment');
environment.baseURL = ' https://bridge.example.com/v1/ ';
const fetchImpl = jest.fn().mockResolvedValue(
Response.json({
protocolVersion: 1,
workerId: 'vm-1',
code: 'one-time-code-value-that-is-long',
expiresAt: '2099-08-30T12:00:00.000Z',
}),
);
const handlers = createAdminCodeEnvironmentHandlers({
getAppConfig: jest.fn().mockResolvedValue(deploymentConfig),
readSecret: jest.fn().mockReturnValue('administrator-bootstrap-token'),
fetchImpl,
});
await handlers.createPairing(request(), mockResponse());
expect(fetchImpl).toHaveBeenCalledWith(
'https://bridge.example.com/v1/bridge/pairings',
expect.any(Object),
);
});
it('rejects insecure non-loopback pairing before reading or sending credentials', async () => {
const deploymentConfig = config();
const environment = deploymentConfig.endpoints?.agents?.statefulCodeSessions?.environments?.[0];
if (environment == null) throw new Error('Expected the test code environment');
environment.baseURL = 'http://bridge.example.com/v1';
const readSecret = jest.fn().mockReturnValue('administrator-bootstrap-token');
const fetchImpl = jest.fn();
const handlers = createAdminCodeEnvironmentHandlers({
getAppConfig: jest.fn().mockResolvedValue(deploymentConfig),
readSecret,
fetchImpl,
});
const response = mockResponse();
await handlers.createPairing(request(), response);
expect(response.statusCode).toBe(409);
expect(response.body).toEqual({
error: 'Code environment pairing requires secure transport',
});
expect(readSecret).not.toHaveBeenCalled();
expect(fetchImpl).not.toHaveBeenCalled();
});
it('rejects an expired one-time pairing code', async () => {
const fetchImpl = jest.fn().mockResolvedValue(
Response.json({
protocolVersion: 1,
workerId: 'vm-1',
code: 'expired-one-time-code-value',
expiresAt: '2000-01-01T00:00:00.000Z',
}),
);
const handlers = createAdminCodeEnvironmentHandlers({
getAppConfig: jest.fn().mockResolvedValue(config()),
readSecret: jest.fn().mockReturnValue('administrator-bootstrap-token'),
fetchImpl,
});
const response = mockResponse();
await handlers.createPairing(request(), response);
expect(response.statusCode).toBe(502);
expect(response.body).toEqual({ error: 'Code API returned an invalid pairing response' });
});
it('rejects a pairing code outside the 32-character base64url wire format', async () => {
const fetchImpl = jest.fn().mockResolvedValue(
Response.json({
protocolVersion: 1,
workerId: 'vm-1',
code: 'invalid code value with whitespace',
expiresAt: '2099-08-30T12:00:00.000Z',
}),
);
const handlers = createAdminCodeEnvironmentHandlers({
getAppConfig: jest.fn().mockResolvedValue(config()),
readSecret: jest.fn().mockReturnValue('administrator-bootstrap-token'),
fetchImpl,
});
const response = mockResponse();
await handlers.createPairing(request(), response);
expect(response.statusCode).toBe(502);
expect(response.body).toEqual({ error: 'Code API returned an invalid pairing response' });
});
it('revokes the environment worker without returning bridge credentials', async () => {
const fetchImpl = jest
.fn()
.mockResolvedValue(Response.json({ protocolVersion: 1, revoked: true }));
const handlers = createAdminCodeEnvironmentHandlers({
getAppConfig: jest.fn().mockResolvedValue(config()),
readSecret: jest.fn().mockReturnValue('administrator-bootstrap-token'),
fetchImpl,
});
const response = mockResponse();
await handlers.revokeWorker(request(), response);
expect(fetchImpl).toHaveBeenCalledWith(
'https://bridge.example.com/v1/bridge/workers/vm-1/revoke',
expect.objectContaining({ method: 'POST', redirect: 'error' }),
);
expect(response.statusCode).toBe(200);
expect(response.body).toEqual({
environmentId: 'attached-vm',
workerId: 'vm-1',
revoked: true,
});
expect(JSON.stringify(response.body)).not.toContain('administrator-bootstrap-token');
});
it('rejects an invalid revocation acknowledgement', async () => {
const fetchImpl = jest
.fn()
.mockResolvedValue(Response.json({ protocolVersion: 1, revoked: false }));
const handlers = createAdminCodeEnvironmentHandlers({
getAppConfig: jest.fn().mockResolvedValue(config()),
readSecret: jest.fn().mockReturnValue('administrator-bootstrap-token'),
fetchImpl,
});
const response = mockResponse();
await handlers.revokeWorker(request(), response);
expect(response.statusCode).toBe(502);
expect(response.body).toEqual({ error: 'Code API returned an invalid revocation response' });
});
});

View file

@ -0,0 +1,212 @@
import { EModelEndpoint, isSecureCodeEnvironmentControlURL } from 'librechat-data-provider';
import type { AppConfig } from '@librechat/data-schemas';
import type { Response } from 'express';
import type { GetAppConfigOptions } from '~/app/service';
import type { ServerRequest } from '~/types/http';
const CODE_BRIDGE_REQUEST_TIMEOUT_MS = 10_000;
type AgentsEndpointConfig = NonNullable<AppConfig['endpoints']>[EModelEndpoint.agents];
type StatefulCodeSessionsConfig = NonNullable<
NonNullable<AgentsEndpointConfig>['statefulCodeSessions']
>;
type ConfiguredCodeEnvironment = NonNullable<StatefulCodeSessionsConfig['environments']>[number];
type FetchImpl = (
input: Parameters<typeof fetch>[0],
init?: Parameters<typeof fetch>[1],
) => ReturnType<typeof fetch>;
interface CodePairingResponse {
protocolVersion: number;
workerId: string;
code: string;
expiresAt: string;
}
interface CodeRevocationResponse {
protocolVersion: number;
revoked: true;
}
export interface AdminCodeEnvironmentDeps {
getAppConfig: (options: GetAppConfigOptions) => Promise<AppConfig>;
readSecret?: (name: string) => string | undefined;
fetchImpl?: FetchImpl;
}
function environmentId(req: ServerRequest): string {
const params = req.params as { environmentId?: string };
return params.environmentId?.trim() ?? '';
}
function findEnvironment(appConfig: AppConfig, id: string): ConfiguredCodeEnvironment | undefined {
return appConfig.endpoints?.[EModelEndpoint.agents]?.statefulCodeSessions?.environments?.find(
(environment) => environment.id === id,
);
}
function pairingConfig(environment: ConfiguredCodeEnvironment):
| {
workerId: string;
tokenEnv: string;
}
| undefined {
if (environment.type !== 'attached' || environment.owner !== 'deployment') {
return undefined;
}
return environment.pairing;
}
function bridgeUrl(environment: ConfiguredCodeEnvironment, path: string): string {
return `${environment.baseURL.trim().replace(/\/+$/, '')}${path}`;
}
function validPairingResponse(value: unknown, workerId: string): value is CodePairingResponse {
if (typeof value !== 'object' || value == null) return false;
const response = value as Partial<CodePairingResponse>;
const expiresAt = typeof response.expiresAt === 'string' ? Date.parse(response.expiresAt) : NaN;
return (
response.protocolVersion === 1 &&
response.workerId === workerId &&
typeof response.code === 'string' &&
/^[A-Za-z0-9_-]{32}$/.test(response.code) &&
Number.isFinite(expiresAt) &&
expiresAt > Date.now()
);
}
function validRevocationResponse(value: unknown): value is CodeRevocationResponse {
if (typeof value !== 'object' || value == null) return false;
const response = value as Partial<CodeRevocationResponse>;
return response.protocolVersion === 1 && response.revoked === true;
}
export function createAdminCodeEnvironmentHandlers(deps: AdminCodeEnvironmentDeps): {
createPairing: (req: ServerRequest, res: Response) => Promise<Response>;
revokeWorker: (req: ServerRequest, res: Response) => Promise<Response>;
} {
const fetchImpl = deps.fetchImpl ?? fetch;
const readSecret =
deps.readSecret ??
((name: string) =>
Object.prototype.hasOwnProperty.call(process.env, name) ? process.env[name] : undefined);
async function resolve(
req: ServerRequest,
res: Response,
): Promise<
| {
id: string;
environment: ConfiguredCodeEnvironment;
pairing: { workerId: string; tokenEnv: string };
token: string;
}
| Response
> {
const id = environmentId(req);
/** Pairing credentials are deployment control-plane state. Resolve only
* YAML-backed configuration; writable database overrides must never
* choose tokenEnv or the outbound destination. */
const appConfig = await deps.getAppConfig({ baseOnly: true });
const environment = findEnvironment(appConfig, id);
if (environment == null) {
return res.status(404).json({ error: 'Code environment was not found' });
}
const pairing = pairingConfig(environment);
if (pairing == null) {
return res.status(409).json({ error: 'Code environment does not support pairing' });
}
if (!isSecureCodeEnvironmentControlURL(environment.baseURL)) {
return res.status(409).json({ error: 'Code environment pairing requires secure transport' });
}
const token = readSecret(pairing.tokenEnv)?.trim();
if (!token) {
return res.status(503).json({ error: 'Code environment pairing is not configured' });
}
return { id, environment, pairing, token };
}
async function createPairing(req: ServerRequest, res: Response): Promise<Response> {
const resolved = await resolve(req, res);
if ('statusCode' in resolved) return resolved;
try {
const response = await fetchImpl(bridgeUrl(resolved.environment, '/bridge/pairings'), {
method: 'POST',
headers: {
Authorization: `Bearer ${resolved.token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ workerId: resolved.pairing.workerId }),
redirect: 'error',
signal: AbortSignal.timeout(CODE_BRIDGE_REQUEST_TIMEOUT_MS),
});
if (!response.ok) {
return res.status(502).json({
error: 'Code API rejected the pairing request',
upstreamStatus: response.status,
});
}
const payload = (await response.json()) as unknown;
if (!validPairingResponse(payload, resolved.pairing.workerId)) {
return res.status(502).json({ error: 'Code API returned an invalid pairing response' });
}
return res.status(200).json({
environmentId: resolved.id,
workerId: payload.workerId,
code: payload.code,
expiresAt: payload.expiresAt,
});
} catch (error) {
const timedOut = error instanceof Error && error.name === 'TimeoutError';
return res.status(timedOut ? 504 : 502).json({
error: timedOut ? 'Code API pairing request timed out' : 'Code API pairing request failed',
});
}
}
async function revokeWorker(req: ServerRequest, res: Response): Promise<Response> {
const resolved = await resolve(req, res);
if ('statusCode' in resolved) return resolved;
try {
const workerId = encodeURIComponent(resolved.pairing.workerId);
const response = await fetchImpl(
bridgeUrl(resolved.environment, `/bridge/workers/${workerId}/revoke`),
{
method: 'POST',
headers: {
Authorization: `Bearer ${resolved.token}`,
'Content-Type': 'application/json',
},
body: '{}',
redirect: 'error',
signal: AbortSignal.timeout(CODE_BRIDGE_REQUEST_TIMEOUT_MS),
},
);
if (!response.ok) {
return res.status(502).json({
error: 'Code API rejected the revocation request',
upstreamStatus: response.status,
});
}
const payload = (await response.json()) as unknown;
if (!validRevocationResponse(payload)) {
return res.status(502).json({ error: 'Code API returned an invalid revocation response' });
}
return res.status(200).json({
environmentId: resolved.id,
workerId: resolved.pairing.workerId,
revoked: true,
});
} catch (error) {
const timedOut = error instanceof Error && error.name === 'TimeoutError';
return res.status(timedOut ? 504 : 502).json({
error: timedOut
? 'Code API revocation request timed out'
: 'Code API revocation request failed',
});
}
}
return { createPairing, revokeWorker };
}

View file

@ -6,6 +6,7 @@ export { createAdminRolesHandlers } from './roles';
export { createAdminSkillsSyncAccess, createAdminSkillsSyncHandlers } from './skills';
export { createAdminUsersHandlers } from './users';
export { createAdminAuditLogHandlers } from './auditLog';
export { createAdminCodeEnvironmentHandlers } from './code';
export { resolveConfigSecret, redactConfigSecretMaps } from './secrets';
export type { AdminConfigDeps } from './config';
export type { AdminLangfuseDeps } from './langfuse';
@ -15,3 +16,4 @@ export type { AdminRolesDeps } from './roles';
export type { AdminSkillSyncAccessDeps, AdminSkillSyncDeps } from './skills';
export type { AdminUsersDeps } from './users';
export type { AdminAuditLogDeps } from './auditLog';
export type { AdminCodeEnvironmentDeps } from './code';

View file

@ -106,12 +106,14 @@ describe('resolveCodeExecutionContext', () => {
name: 'Managed',
type: 'managed',
baseURL: 'https://managed.example/v1',
owner: 'deployment',
},
{
id: 'my-vm',
name: 'My VM',
type: 'attached',
baseURL: 'https://bridge.example/v1/',
owner: 'deployment',
},
],
userId: 'user-1',
@ -137,6 +139,7 @@ describe('resolveCodeExecutionContext', () => {
type: 'attached' as const,
baseURL,
default: true,
owner: 'deployment' as const,
});
const first = resolveCodeExecutionContext({
statefulSessions: true,
@ -166,6 +169,7 @@ describe('resolveCodeExecutionContext', () => {
type: 'attached',
baseURL: 'https://bridge.example/v1',
default: true,
owner: 'deployment',
},
],
userId: 'user-1',

View file

@ -523,6 +523,108 @@ describe('agentsEndpointSchema', () => {
}
});
it('accepts deployment-owned pairing configuration for an attached environment', () => {
const result = agentsEndpointSchema.safeParse({
statefulCodeSessions: {
allowedEnvironments: ['conversation'],
environments: [
{
id: 'attached-vm',
name: 'Attached VM',
type: 'attached',
baseURL: 'https://bridge.example.com/v1',
default: true,
owner: 'deployment',
pairing: {
workerId: 'vm-1',
tokenEnv: 'CODE_BRIDGE_ADMIN_TOKEN',
},
},
],
},
});
expect(result.success).toBe(true);
if (result.success) {
expect(result.data.statefulCodeSessions?.environments?.[0]).toMatchObject({
owner: 'deployment',
pairing: {
workerId: 'vm-1',
tokenEnv: 'CODE_BRIDGE_ADMIN_TOKEN',
},
});
}
});
it('rejects pairing configuration for a managed environment', () => {
const result = agentsEndpointSchema.safeParse({
statefulCodeSessions: {
allowedEnvironments: ['conversation'],
environments: [
{
id: 'managed',
name: 'Managed',
type: 'managed',
baseURL: 'https://code.example.com/v1',
default: true,
pairing: {
workerId: 'vm-1',
tokenEnv: 'CODE_BRIDGE_ADMIN_TOKEN',
},
},
],
},
});
expect(result.success).toBe(false);
});
it('rejects pairing over insecure non-loopback transport', () => {
const result = agentsEndpointSchema.safeParse({
statefulCodeSessions: {
allowedEnvironments: ['conversation'],
environments: [
{
id: 'attached-vm',
name: 'Attached VM',
type: 'attached',
baseURL: 'http://bridge.example.com/v1',
default: true,
pairing: {
workerId: 'vm-1',
tokenEnv: 'CODE_BRIDGE_ADMIN_TOKEN',
},
},
],
},
});
expect(result.success).toBe(false);
});
it('allows loopback HTTP pairing for local development', () => {
const result = agentsEndpointSchema.safeParse({
statefulCodeSessions: {
allowedEnvironments: ['conversation'],
environments: [
{
id: 'attached-vm',
name: 'Attached VM',
type: 'attached',
baseURL: 'http://127.0.0.1:23112/v1',
default: true,
pairing: {
workerId: 'vm-1',
tokenEnv: 'CODE_BRIDGE_ADMIN_TOKEN',
},
},
],
},
});
expect(result.success).toBe(true);
});
it('rejects ambiguous execution environment routing', () => {
const environment = {
id: 'attached-vm',

View file

@ -1023,6 +1023,17 @@ const codeEnvironmentBaseURLSchema = z
{ message: 'Code environment baseURL must be an HTTP(S) base URL without query or fragment' },
);
export function isSecureCodeEnvironmentControlURL(baseURL: string): boolean {
try {
const url = new URL(baseURL.trim());
if (url.protocol === 'https:') return true;
if (url.protocol !== 'http:') return false;
return url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '[::1]';
} catch {
return false;
}
}
export const agentsEndpointSchema = baseEndpointSchema
.omit({ baseURL: true })
.merge(
@ -1073,6 +1084,17 @@ export const agentsEndpointSchema = baseEndpointSchema
type: z.enum(['managed', 'attached']),
baseURL: codeEnvironmentBaseURLSchema,
default: z.boolean().optional(),
/** Ownership is explicit even though the first pairing control
* plane supports deployment-owned workers only. */
owner: z.literal('deployment').optional().default('deployment'),
/** Server-only enrollment metadata. `tokenEnv` names an
* environment variable and never contains the token itself. */
pairing: z
.object({
workerId: z.string().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/),
tokenEnv: z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/),
})
.optional(),
}),
)
.optional(),
@ -1082,6 +1104,23 @@ export const agentsEndpointSchema = baseEndpointSchema
const ids = new Set<string>();
let defaults = 0;
for (const environment of value.environments) {
if (environment.pairing != null && environment.type !== 'attached') {
context.addIssue({
code: z.ZodIssueCode.custom,
message: 'Only attached code environments may configure pairing',
path: ['environments', environment.id, 'pairing'],
});
}
if (
environment.pairing != null &&
!isSecureCodeEnvironmentControlURL(environment.baseURL)
) {
context.addIssue({
code: z.ZodIssueCode.custom,
message: 'Paired code environments require HTTPS outside loopback development',
path: ['environments', environment.id, 'baseURL'],
});
}
if (ids.has(environment.id)) {
context.addIssue({
code: z.ZodIssueCode.custom,

View file

@ -29,6 +29,8 @@ export const SystemCapabilities = {
READ_AGENTS: 'read:agents',
MANAGE_AGENTS: 'manage:agents',
MANAGE_MCP_SERVERS: 'manage:mcpservers',
/** Enrolls and revokes deployment-owned Code API workers. */
MANAGE_CODE_ENVIRONMENTS: 'manage:code_environments',
READ_PROMPTS: 'read:prompts',
MANAGE_PROMPTS: 'manage:prompts',
READ_SKILLS: 'read:skills',
@ -252,6 +254,7 @@ export const CAPABILITY_CATEGORIES: CapabilityCategory[] = [
SystemCapabilities.MANAGE_ASSISTANTS,
SystemCapabilities.READ_ASSISTANTS,
SystemCapabilities.MANAGE_MCP_SERVERS,
SystemCapabilities.MANAGE_CODE_ENVIRONMENTS,
SystemCapabilities.MANAGE_SHARED_LINKS,
SystemCapabilities.READ_SHARED_LINKS,
],