fix(plugin): remediate ML-07 R2 findings
This commit is contained in:
@@ -4,13 +4,15 @@ import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import { afterEach, describe, expect, it } from 'vitest';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { PiManagedExtensionHost } from '../../electron/coding-runtime/pi/extension-host';
|
||||
import { PiSubagentScheduler } from '../../electron/coding-runtime/pi/subagent';
|
||||
import { PiProcessBudget } from '../../electron/coding-runtime/pi/worker-pool';
|
||||
import type { AgentBrowserModule } from '../../electron/agent-browser';
|
||||
import { CodingAttachmentStore } from '../../electron/coding-projects/attachment-store';
|
||||
import { PiProductTools } from '../../electron/coding-runtime/pi/product-tools';
|
||||
import { CodingCapabilityRegistryImpl } from '../../electron/coding-plugins/registry';
|
||||
import type { PluginPolicyClientState } from '../../electron/services/plugin-policy-client';
|
||||
import {
|
||||
DATA_SERVICE_PLUGIN_DEFINITION,
|
||||
type CodingPluginToolDefinition,
|
||||
@@ -46,6 +48,118 @@ afterEach(async () => {
|
||||
});
|
||||
|
||||
describe('Makelore Pi extension bundle', () => {
|
||||
it('hydrates persisted Pi identity through reconnect and event replay into the capability registry', async () => {
|
||||
const root = await mkdtemp(path.join(tmpdir(), 'makelore-pi-persisted-identity-'));
|
||||
roots.push(root);
|
||||
const policy: PluginPolicyClientState = {
|
||||
status: 'current', revision: 23, lastVerifiedAt: 1,
|
||||
catalog: {
|
||||
schema_version: 1, catalog_version: 'catalog-23', pricing_version: null,
|
||||
plugins: [{
|
||||
plugin_id: DATA_SERVICE_PLUGIN_DEFINITION.id,
|
||||
supported_contract_versions: [DATA_SERVICE_PLUGIN_DEFINITION.contractVersion],
|
||||
status: 'active',
|
||||
capabilities: [{
|
||||
capability_id: 'data-service.control',
|
||||
operations: [{
|
||||
operation: 'inspect',
|
||||
billing: { mode: 'included', entitlement_scope: null, notice: 'Included' },
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
};
|
||||
const invoke = vi.fn(async () => ({
|
||||
success: true as const, status: 200, code: null, error: null, retryable: false as const,
|
||||
payload_schema: 'data-service.v1', data: { instance_id: 'instance-a' },
|
||||
}));
|
||||
const capabilityRegistry = new CodingCapabilityRegistryImpl({
|
||||
policyClient: { getState: () => policy, refresh: vi.fn().mockResolvedValue(undefined) },
|
||||
getEnabledPluginIds: async () => [DATA_SERVICE_PLUGIN_DEFINITION.id],
|
||||
definitions: [DATA_SERVICE_PLUGIN_DEFINITION],
|
||||
adapters: [{
|
||||
pluginId: DATA_SERVICE_PLUGIN_DEFINITION.id,
|
||||
async inspect() { return { status: 'ready' }; },
|
||||
invoke,
|
||||
}],
|
||||
});
|
||||
const host = new PiManagedExtensionHost();
|
||||
host.configureProductTools(new PiProductTools({
|
||||
browser: {} as AgentBrowserModule,
|
||||
attachments: new CodingAttachmentStore(path.join(root, 'attachments')),
|
||||
bundledSkillsDir: path.resolve('resources/coding-skills'),
|
||||
capabilityRegistry,
|
||||
}));
|
||||
hosts.push(host);
|
||||
const inspectTool = DATA_SERVICE_PLUGIN_DEFINITION.tools.find(
|
||||
({ name }) => name === 'data_service_inspect',
|
||||
);
|
||||
if (!inspectTool) throw new Error('inspect definition missing');
|
||||
const worker = await host.registerWorker({
|
||||
conversationId: 'persisted-conversation', generation: 1, projectId: 'project-a',
|
||||
projectPath: root, extensionsDir: root,
|
||||
skillEntries: [{ id: 'data-service', entryPath: 'skills/data-service/SKILL.md' }],
|
||||
catalogRevision: policy.revision,
|
||||
tools: [inspectTool],
|
||||
});
|
||||
await host.bindRun('persisted-conversation', 1, 'persisted-run');
|
||||
const persistedContext = JSON.parse(await readFile(
|
||||
worker.env.MAKELORE_PI_CONTEXT_FILE as string,
|
||||
'utf8',
|
||||
)) as { runId?: string };
|
||||
expect(persistedContext.runId).toBe('persisted-run');
|
||||
|
||||
const previous = {
|
||||
bridge: process.env.MAKELORE_PI_BRIDGE_URL,
|
||||
token: process.env.MAKELORE_PI_WORKER_TOKEN,
|
||||
context: process.env.MAKELORE_PI_CONTEXT_FILE,
|
||||
role: process.env.MAKELORE_PI_WORKER_ROLE,
|
||||
};
|
||||
Object.assign(process.env, worker.env);
|
||||
try {
|
||||
const executeAfterHydration = async (connection: string) => {
|
||||
const module = await import(
|
||||
/* @vite-ignore */ `${pathToFileURL(worker.extensionPath).href}?connection=${connection}`
|
||||
) as {
|
||||
default(factory: {
|
||||
registerTool(tool: ExtensionTool): void;
|
||||
on(event: string, handler: ExtensionHandler): void;
|
||||
}): void | Promise<void>;
|
||||
};
|
||||
const tools = new Map<string, ExtensionTool>();
|
||||
await module.default({
|
||||
registerTool: (tool) => tools.set(tool.name, tool),
|
||||
on: () => undefined,
|
||||
});
|
||||
return await tools.get('data_service_inspect')?.execute?.(
|
||||
'persisted-resource', {}, new AbortController().signal,
|
||||
);
|
||||
};
|
||||
|
||||
const first = await executeAfterHydration('initial');
|
||||
const replay = await executeAfterHydration('reconnect');
|
||||
expect(first).toMatchObject({
|
||||
details: {
|
||||
plugin_id: DATA_SERVICE_PLUGIN_DEFINITION.id,
|
||||
request_id: 'pi:persisted-run:persisted-resource',
|
||||
},
|
||||
});
|
||||
expect(replay).toMatchObject({
|
||||
details: { request_id: 'pi:persisted-run:persisted-resource' },
|
||||
});
|
||||
expect(invoke).toHaveBeenCalledTimes(2);
|
||||
} finally {
|
||||
for (const [key, value] of Object.entries(previous)) {
|
||||
const environmentKey = key === 'bridge' ? 'MAKELORE_PI_BRIDGE_URL'
|
||||
: key === 'token' ? 'MAKELORE_PI_WORKER_TOKEN'
|
||||
: key === 'context' ? 'MAKELORE_PI_CONTEXT_FILE'
|
||||
: 'MAKELORE_PI_WORKER_ROLE';
|
||||
if (value === undefined) delete process.env[environmentKey];
|
||||
else process.env[environmentKey] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('materializes only the frozen plugin declarations and lease metadata', async () => {
|
||||
const root = await mkdtemp(path.join(tmpdir(), 'makelore-pi-dynamic-bundle-'));
|
||||
roots.push(root);
|
||||
|
||||
Reference in New Issue
Block a user