fix(marketplace): close client contract gaps

This commit is contained in:
2026-08-29 23:21:26 +08:00
parent e4676977b9
commit c4120dd847
9 changed files with 236 additions and 29 deletions

View File

@@ -740,11 +740,11 @@ describe('PluginPackageStore', () => {
expect(index.releases.map(({ release_id }) => release_id)).toEqual(['release-2', 'release-1']);
store.registerActiveWorker('release-1');
await expect(store.uninstall(PLUGIN_ID)).resolves.toMatchObject({
status: 'kept', pluginId: PLUGIN_ID, releaseId: 'release-1', version: '1.0.0',
await expect(store.uninstall(PLUGIN_ID)).resolves.toEqual({
status: 'kept', pluginId: PLUGIN_ID, reason: 'active_worker_reference',
});
await expect(store.readInstalledIndex()).resolves.toHaveLength(1);
await expect(store.getInstalled(PLUGIN_ID)).resolves.toMatchObject({ releaseId: 'release-1' });
await expect(store.getInstalled(PLUGIN_ID)).resolves.toBeNull();
});
it('persists the installed channel and client range, and fails closed after a client upgrade', async () => {
@@ -899,6 +899,49 @@ describe('PluginPackageStore', () => {
expect.objectContaining({ releaseId: 'release-worker' }),
]);
await expect(store.getInstalled(PLUGIN_ID)).resolves.toBeNull();
store.releaseActiveWorker('release-worker');
await expect(store.uninstall(PLUGIN_ID)).resolves.toEqual({
status: 'removed', pluginId: PLUGIN_ID, reason: 'none',
});
await expect(store.readInstalledIndex()).resolves.toEqual([]);
});
it('makes an active current Release unavailable to new workers before deferred cleanup', async () => {
temporaryRoot = await mkdtemp(path.join(process.cwd(), '.marketplace-test-'));
const archive = buildSkillOnlyArchive();
const active = signedGrant(archive, { releaseId: 'release-active' });
const marketplace: MarketplaceClient = {
resolve: vi.fn(async (input: ResolveRequest) => makeResolveResult(input, {
releaseId: active.grant.releaseId,
sha256: active.grant.sha256,
sizeBytes: active.grant.sizeBytes,
})),
issueDownload: vi.fn(async () => active.grant),
downloadContent: async () => archive,
getCurrentAccountBinding: () => ACCOUNT_A,
} as MarketplaceClient;
const store = new PluginPackageStore({
rootDir: temporaryRoot,
marketplace,
getAccountBinding: () => ACCOUNT_A,
keyStore: new Map([['test-key', active.publicKey]]),
clientVersion: '1.0.0',
});
await store.resolveAndInstall({ pluginId: PLUGIN_ID, makeloreVersion: '1.0.0' });
store.registerActiveWorker('release-active');
await expect(store.uninstall(PLUGIN_ID)).resolves.toEqual({
status: 'kept', pluginId: PLUGIN_ID, reason: 'active_worker_reference',
});
await expect(store.getInstalled(PLUGIN_ID)).resolves.toBeNull();
await expect(store.readInstalledIndex()).resolves.toHaveLength(1);
store.releaseActiveWorker('release-active');
await expect(store.uninstall(PLUGIN_ID)).resolves.toEqual({
status: 'removed', pluginId: PLUGIN_ID, reason: 'none',
});
await expect(store.readInstalledIndex()).resolves.toEqual([]);
});
it('preserves the old release across download, signature, and extraction failures', async () => {