@lucid-fdn/plugin-policy 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucid-fdn/plugin-policy",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Unified capability registry, router, policy engine, and audit hooks for plugins and integrations",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -8,18 +8,10 @@
8
8
  "exports": {
9
9
  ".": {
10
10
  "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
12
13
  }
13
14
  },
14
- "scripts": {
15
- "build": "tsc",
16
- "dev": "tsc --watch",
17
- "typecheck": "tsc --noEmit"
18
- },
19
- "devDependencies": {
20
- "@types/node": "^22.0.0",
21
- "typescript": "^5.7.3"
22
- },
23
15
  "publishConfig": {
24
16
  "access": "public"
25
17
  },
@@ -27,4 +19,4 @@
27
19
  "files": [
28
20
  "dist"
29
21
  ]
30
- }
22
+ }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=audit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"audit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/audit.test.ts"],"names":[],"mappings":""}
@@ -1,54 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { AuditEmitter } from '../audit.js';
3
- const event = {
4
- timestamp: new Date().toISOString(),
5
- pluginSlug: 'lucid-seo',
6
- toolName: 'research_keywords',
7
- executionPath: 'embedded',
8
- durationMs: 5,
9
- success: true,
10
- };
11
- describe('AuditEmitter', () => {
12
- it('emits events to registered handlers', () => {
13
- const emitter = new AuditEmitter();
14
- const handler = vi.fn();
15
- emitter.on(handler);
16
- emitter.emit(event);
17
- expect(handler).toHaveBeenCalledWith(event);
18
- });
19
- it('supports multiple handlers', () => {
20
- const emitter = new AuditEmitter();
21
- const h1 = vi.fn();
22
- const h2 = vi.fn();
23
- emitter.on(h1);
24
- emitter.on(h2);
25
- emitter.emit(event);
26
- expect(h1).toHaveBeenCalledOnce();
27
- expect(h2).toHaveBeenCalledOnce();
28
- });
29
- it('supports unsubscribe', () => {
30
- const emitter = new AuditEmitter();
31
- const handler = vi.fn();
32
- const unsub = emitter.on(handler);
33
- unsub();
34
- emitter.emit(event);
35
- expect(handler).not.toHaveBeenCalled();
36
- });
37
- it('does not throw when handler throws (fire-and-forget)', () => {
38
- const emitter = new AuditEmitter();
39
- emitter.on(() => { throw new Error('boom'); });
40
- const good = vi.fn();
41
- emitter.on(good);
42
- expect(() => emitter.emit(event)).not.toThrow();
43
- expect(good).toHaveBeenCalled();
44
- });
45
- it('clears all handlers', () => {
46
- const emitter = new AuditEmitter();
47
- emitter.on(vi.fn());
48
- emitter.on(vi.fn());
49
- expect(emitter.handlerCount).toBe(2);
50
- emitter.clear();
51
- expect(emitter.handlerCount).toBe(0);
52
- });
53
- });
54
- //# sourceMappingURL=audit.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"audit.test.js","sourceRoot":"","sources":["../../src/__tests__/audit.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=manifest.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"manifest.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/manifest.test.ts"],"names":[],"mappings":""}
@@ -1,83 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { normalizePluginRow } from '../manifest.js';
3
- describe('normalizePluginRow', () => {
4
- it('transforms snake_case DB row to camelCase ActivatedPlugin', () => {
5
- const row = {
6
- plugin_slug: 'lucid-seo',
7
- plugin_name: 'Lucid SEO',
8
- tool_manifest: [{ name: 'research', description: 'Research', parameters: {} }],
9
- enabled_tools: null,
10
- plugin_config: { depth: 3 },
11
- org_config: { orgKey: 'val' },
12
- source: 'first-party',
13
- mcpgate_server_id: null,
14
- kind: 'plugin',
15
- transport: 'embedded',
16
- trust_level: 'internal',
17
- execution_mode: 'in_process',
18
- auth_type: 'none',
19
- auth_provider: null,
20
- };
21
- const result = normalizePluginRow(row);
22
- expect(result.slug).toBe('lucid-seo');
23
- expect(result.name).toBe('Lucid SEO');
24
- expect(result.tools).toHaveLength(1);
25
- expect(result.config).toEqual({ orgKey: 'val', depth: 3 });
26
- expect(result.kind).toBe('plugin');
27
- expect(result.transport).toBe('embedded');
28
- expect(result.trustLevel).toBe('internal');
29
- expect(result.executionMode).toBe('in_process');
30
- expect(result.authType).toBe('none');
31
- });
32
- it('filters tools by enabled_tools', () => {
33
- const row = {
34
- plugin_slug: 'lucid-seo',
35
- plugin_name: 'SEO',
36
- tool_manifest: [
37
- { name: 'research', description: 'A', parameters: {} },
38
- { name: 'analyze', description: 'B', parameters: {} },
39
- ],
40
- enabled_tools: ['research'],
41
- plugin_config: {},
42
- org_config: {},
43
- source: 'first-party',
44
- };
45
- const result = normalizePluginRow(row);
46
- expect(result.tools).toHaveLength(1);
47
- expect(result.tools[0].name).toBe('research');
48
- });
49
- it('handles missing unified fields (old format)', () => {
50
- const row = {
51
- plugin_slug: 'old-plugin',
52
- plugin_name: 'Old Plugin',
53
- manifest_snapshot: [{ name: 'tool1', description: 'T', parameters: {} }],
54
- enabled_tools: null,
55
- config: { key: 'val' },
56
- source: 'mcpgate',
57
- mcpgate_server_id: 'server-1',
58
- };
59
- const result = normalizePluginRow(row);
60
- expect(result.slug).toBe('old-plugin');
61
- expect(result.tools).toHaveLength(1);
62
- expect(result.mcpgateServerId).toBe('server-1');
63
- // Missing UCA fields get safe defaults (least-privileged posture)
64
- expect(result.kind).toBe('plugin');
65
- expect(result.transport).toBe('remote-mcp');
66
- expect(result.trustLevel).toBe('community');
67
- expect(result.executionMode).toBe('gateway');
68
- });
69
- it('merges org config and plugin config (plugin wins)', () => {
70
- const row = {
71
- plugin_slug: 'test',
72
- plugin_name: 'Test',
73
- tool_manifest: [],
74
- enabled_tools: null,
75
- org_config: { shared: 'org', orgOnly: 'yes' },
76
- plugin_config: { shared: 'plugin', pluginOnly: 'yes' },
77
- source: 'first-party',
78
- };
79
- const result = normalizePluginRow(row);
80
- expect(result.config).toEqual({ shared: 'plugin', orgOnly: 'yes', pluginOnly: 'yes' });
81
- });
82
- });
83
- //# sourceMappingURL=manifest.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"manifest.test.js","sourceRoot":"","sources":["../../src/__tests__/manifest.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=policy.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"policy.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/policy.test.ts"],"names":[],"mappings":""}
@@ -1,71 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { resolvePolicy } from '../policy.js';
3
- describe('resolvePolicy', () => {
4
- it('blocks plugins on the admin blocklist', () => {
5
- const result = resolvePolicy({ slug: 'bad-plugin', trustLevel: 'internal', executionMode: 'in_process' }, { blockedPlugins: ['bad-plugin'] });
6
- expect(result.decision).toBe('block');
7
- expect(result.reason).toContain('blocklist');
8
- });
9
- it('forces gateway when forceGateway is set', () => {
10
- const result = resolvePolicy({ slug: 'lucid-seo', trustLevel: 'internal', executionMode: 'in_process' }, { forceGateway: true });
11
- expect(result.decision).toBe('allow_gateway');
12
- expect(result.effectiveMode).toBe('gateway');
13
- });
14
- it('allows internal plugins in-process', () => {
15
- const result = resolvePolicy({
16
- slug: 'lucid-seo',
17
- trustLevel: 'internal',
18
- executionMode: 'in_process',
19
- });
20
- expect(result.decision).toBe('allow_in_process');
21
- expect(result.effectiveMode).toBe('in_process');
22
- });
23
- it('allows verified plugins in-process', () => {
24
- const result = resolvePolicy({
25
- slug: 'partner-plugin',
26
- trustLevel: 'verified',
27
- executionMode: 'in_process',
28
- });
29
- expect(result.decision).toBe('allow_in_process');
30
- expect(result.effectiveMode).toBe('in_process');
31
- });
32
- it('forces community plugins to gateway even if in_process requested', () => {
33
- const result = resolvePolicy({
34
- slug: 'community-plugin',
35
- trustLevel: 'community',
36
- executionMode: 'in_process',
37
- });
38
- expect(result.decision).toBe('allow_gateway');
39
- expect(result.effectiveMode).toBe('gateway');
40
- expect(result.reason).toContain('gateway-only');
41
- });
42
- it('allows community plugins in gateway mode', () => {
43
- const result = resolvePolicy({
44
- slug: 'community-plugin',
45
- trustLevel: 'community',
46
- executionMode: 'gateway',
47
- });
48
- expect(result.decision).toBe('allow_gateway');
49
- expect(result.effectiveMode).toBe('gateway');
50
- });
51
- it('allows internal plugins in gateway mode when requested', () => {
52
- const result = resolvePolicy({
53
- slug: 'lucid-seo',
54
- trustLevel: 'internal',
55
- executionMode: 'gateway',
56
- });
57
- expect(result.decision).toBe('allow_gateway');
58
- expect(result.effectiveMode).toBe('gateway');
59
- });
60
- it('defaults undefined trustLevel to community (safe default)', () => {
61
- const result = resolvePolicy({
62
- slug: 'old-plugin',
63
- trustLevel: undefined,
64
- executionMode: undefined,
65
- });
66
- expect(result.decision).toBe('allow_gateway');
67
- expect(result.effectiveMode).toBe('gateway');
68
- expect(result.reason).toContain('gateway-only');
69
- });
70
- });
71
- //# sourceMappingURL=policy.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"policy.test.js","sourceRoot":"","sources":["../../src/__tests__/policy.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=registry.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/registry.test.ts"],"names":[],"mappings":""}
@@ -1,65 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { PluginRegistry } from '../registry.js';
3
- const seoPlugin = {
4
- slug: 'lucid-seo',
5
- name: 'Lucid SEO',
6
- tools: [
7
- { name: 'research_keywords', description: 'Research keywords', parameters: {} },
8
- { name: 'analyze_serp', description: 'Analyze SERP', parameters: {} },
9
- ],
10
- config: {},
11
- kind: 'plugin',
12
- transport: 'embedded',
13
- trustLevel: 'internal',
14
- executionMode: 'in_process',
15
- authType: 'none',
16
- authProvider: null,
17
- };
18
- const slackPlugin = {
19
- slug: 'slack',
20
- name: 'Slack',
21
- tools: [{ name: 'send_message', description: 'Send a Slack message', parameters: {} }],
22
- config: {},
23
- kind: 'integration',
24
- transport: 'remote-mcp',
25
- trustLevel: 'community',
26
- executionMode: 'gateway',
27
- authType: 'oauth2',
28
- authProvider: 'slack',
29
- };
30
- describe('PluginRegistry', () => {
31
- it('registers and retrieves plugins', () => {
32
- const reg = new PluginRegistry([seoPlugin]);
33
- expect(reg.get('lucid-seo')).toEqual(seoPlugin);
34
- expect(reg.has('lucid-seo')).toBe(true);
35
- expect(reg.has('missing')).toBe(false);
36
- });
37
- it('returns all plugins', () => {
38
- const reg = new PluginRegistry([seoPlugin, slackPlugin]);
39
- expect(reg.getAll()).toHaveLength(2);
40
- expect(reg.size).toBe(2);
41
- });
42
- it('resolves wire tool names with double underscore', () => {
43
- const reg = new PluginRegistry([seoPlugin]);
44
- const resolved = reg.resolveWireToolName('lucid-seo__research_keywords');
45
- expect(resolved?.plugin.slug).toBe('lucid-seo');
46
- expect(resolved?.tool.name).toBe('research_keywords');
47
- });
48
- it('resolves wire tool names with underscore slug (sanitized)', () => {
49
- const reg = new PluginRegistry([seoPlugin]);
50
- // Wire names replace hyphens with underscores
51
- const resolved = reg.resolveWireToolName('lucid_seo__research_keywords');
52
- expect(resolved?.plugin.slug).toBe('lucid-seo');
53
- expect(resolved?.tool.name).toBe('research_keywords');
54
- });
55
- it('returns null for unknown wire tool names', () => {
56
- const reg = new PluginRegistry([seoPlugin]);
57
- expect(reg.resolveWireToolName('unknown__tool')).toBeNull();
58
- expect(reg.resolveWireToolName('no-separator')).toBeNull();
59
- });
60
- it('returns null for known plugin but unknown tool', () => {
61
- const reg = new PluginRegistry([seoPlugin]);
62
- expect(reg.resolveWireToolName('lucid-seo__nonexistent_tool')).toBeNull();
63
- });
64
- });
65
- //# sourceMappingURL=registry.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry.test.js","sourceRoot":"","sources":["../../src/__tests__/registry.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=router.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"router.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/router.test.ts"],"names":[],"mappings":""}
@@ -1,80 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { routePlugin } from '../router.js';
3
- function makePlugin(overrides = {}) {
4
- return {
5
- slug: 'test-plugin',
6
- name: 'Test Plugin',
7
- tools: [],
8
- config: {},
9
- kind: 'plugin',
10
- transport: 'embedded',
11
- trustLevel: 'internal',
12
- executionMode: 'in_process',
13
- authType: 'none',
14
- authProvider: null,
15
- ...overrides,
16
- };
17
- }
18
- describe('routePlugin', () => {
19
- it('routes embedded + internal to embedded path', () => {
20
- const result = routePlugin(makePlugin({
21
- transport: 'embedded',
22
- trustLevel: 'internal',
23
- executionMode: 'in_process',
24
- }));
25
- expect(result.path).toBe('embedded');
26
- });
27
- it('routes embedded + community to gateway-mcp (policy override)', () => {
28
- const result = routePlugin(makePlugin({
29
- transport: 'embedded',
30
- trustLevel: 'community',
31
- executionMode: 'in_process',
32
- }));
33
- expect(result.path).toBe('gateway-mcp');
34
- expect(result.policy.reason).toContain('gateway-only');
35
- });
36
- it('routes remote-mcp to gateway-mcp', () => {
37
- const result = routePlugin(makePlugin({
38
- transport: 'remote-mcp',
39
- trustLevel: 'verified',
40
- executionMode: 'gateway',
41
- mcpgateServerId: 'server-xyz',
42
- }));
43
- expect(result.path).toBe('gateway-mcp');
44
- expect(result.target).toBe('server-xyz');
45
- });
46
- it('routes rest transport to gateway-rest with endpointUrl as target', () => {
47
- const result = routePlugin(makePlugin({
48
- transport: 'rest',
49
- trustLevel: 'verified',
50
- executionMode: 'gateway',
51
- endpointUrl: 'https://api.weather.com/v1',
52
- }));
53
- expect(result.path).toBe('gateway-rest');
54
- expect(result.target).toBe('https://api.weather.com/v1');
55
- });
56
- it('blocks plugins on admin blocklist', () => {
57
- const result = routePlugin(makePlugin({ slug: 'bad-plugin', transport: 'embedded', trustLevel: 'internal' }), { policy: { blockedPlugins: ['bad-plugin'] } });
58
- expect(result.path).toBe('blocked');
59
- });
60
- it('defaults unknown fields to safe values', () => {
61
- // Plugin with no unified fields (old format) — cast to bypass required fields
62
- const result = routePlugin(makePlugin({
63
- transport: undefined,
64
- trustLevel: undefined,
65
- executionMode: undefined,
66
- }));
67
- // Defaults: transport=remote-mcp, trustLevel=community, executionMode=gateway
68
- expect(result.path).toBe('gateway-mcp');
69
- expect(result.policy.effectiveMode).toBe('gateway');
70
- });
71
- it('uses builtin: prefix for fallback server ID', () => {
72
- const result = routePlugin(makePlugin({
73
- slug: 'lucid-seo',
74
- transport: 'remote-mcp',
75
- mcpgateServerId: undefined,
76
- }));
77
- expect(result.target).toBe('builtin:lucid-seo');
78
- });
79
- });
80
- //# sourceMappingURL=router.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"router.test.js","sourceRoot":"","sources":["../../src/__tests__/router.test.ts"],"names":[],"mappings":"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"}