Fix/plugin audit findings (#2031)

* fix(plugins): enforce manifest apiVersion at install and activation

* test(plugins): exercise the absent-apiVersion default

* feat(plugins): generate the core-event catalog into host-facts

* docs(plugins): explain the packing.listBags write-permission binding

* test(plugins): cover apiVersion upload refusal; tidy docblocks and generator header

* fix(plugin-sdk): validate settings options and oauth like the host

* fix(plugin-sdk): model the full manifest shape and stop dropping fields

* fix(plugin-sdk): drop non-string routeProfiles icons like the host

* docs(plugin-sdk): document host limits, oauth contract, and ignored asUserId

* feat(plugin-sdk): enforce daily budgets and meta quotas in the mock host

* feat(plugin-sdk): expose the generated core-event catalog

* feat(plugin-sdk): scaffold trek range >=3.4.0 <5.0.0 ahead of TREK 4.0

* feat(plugin-sdk): scaffold the oauth broker settings for oauth:client plugins

* chore(plugin-sdk): fix stale mirror docs and the colliding permissions export

* docs(plugin-sdk): add the rate-limit string; restore trek docblock; match host meta sizing

* feat(plugin-sdk): raise the scaffold trek floor to 4.0.0

* docs(wiki): bring the plugin pages in line with the current runtime

* docs: bring the workspace CLAUDE.md guides up to date and make them committable

* feat(plugin-sdk): roll back failed publishes, add unrelease, sync the fork, retro-sign updates

* docs(wiki): document the publish rollback, unrelease, fork sync, and retro-signing

* chore(plugin-sdk): 1.6.0
This commit is contained in:
jubnl
2026-08-24 23:48:36 +02:00
committed by GitHub
parent 4bac447ac8
commit d110b3bb6d
48 changed files with 1895 additions and 169 deletions
@@ -0,0 +1,15 @@
import { it, expect } from 'vitest';
import { SNAPSHOT_GRANT, ENTITY_ID_KEYS } from '../../../src/plugin-event-sink';
import { KNOWN_PERMISSIONS } from '../../../src/nest/plugins/protocol/envelope';
it('every snapshot grant is a known db:read permission', () => {
for (const p of Object.values(SNAPSHOT_GRANT)) {
expect(KNOWN_PERMISSIONS).toContain(p);
expect(p).toMatch(/^db:read:/);
}
});
it('every snapshot family has an id-key path', () => {
for (const family of Object.keys(SNAPSHOT_GRANT)) {
expect(Object.keys(ENTITY_ID_KEYS)).toContain(family);
}
});
@@ -6,6 +6,7 @@ import { describe, it, expect } from 'vitest';
import { parseManifest, ManifestError } from '../../../src/nest/plugins/install/manifest';
const base = { id: 'flight-tracker', name: 'Flight', version: '1.2.0', type: 'widget', apiVersion: 1 };
const withApi = (apiVersion: unknown) => ({ ...base, apiVersion, trek: '>=3.2.0 <4.0.0' });
describe('parseManifest', () => {
it('parses a valid manifest with defaults', () => {
@@ -99,6 +100,23 @@ describe('parseManifest', () => {
});
});
describe('apiVersion', () => {
it.each([[0], [-3], [1.5], ['1']])('rejects non-positive-integer %p', (v) => {
expect(() => parseManifest(withApi(v))).toThrow('apiVersion must be a positive integer');
});
it('defaults to 1 when absent', () => {
const { apiVersion: _omitted, ...noApi } = base;
expect(parseManifest(noApi).apiVersion).toBe(1);
});
it('tolerates a future apiVersion under discovery (no requireTrek)', () => {
expect(parseManifest(withApi(2)).apiVersion).toBe(2);
});
it('refuses a future apiVersion on install paths (requireTrek)', () => {
expect(() => parseManifest(withApi(2), { requireTrek: true }))
.toThrow('plugin requires plugin-API v2; this TREK supports v1');
});
});
describe('parseManifest capabilities', () => {
it('parses a hero widget slot and defaults to sidebar', () => {
const hero = parseManifest({ ...base, capabilities: { widget: { slot: 'hero', title: 'T' } } });