@cogenta/plugins 0.1.0

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.
Files changed (86) hide show
  1. package/dist/guest/sandbox-entry.mjs +155 -0
  2. package/dist/host/capabilities.d.ts +46 -0
  3. package/dist/host/capabilities.d.ts.map +1 -0
  4. package/dist/host/capabilities.js +105 -0
  5. package/dist/host/capabilities.js.map +1 -0
  6. package/dist/host/protocol.d.ts +58 -0
  7. package/dist/host/protocol.d.ts.map +1 -0
  8. package/dist/host/protocol.js +10 -0
  9. package/dist/host/protocol.js.map +1 -0
  10. package/dist/host/worker-runner.d.ts +92 -0
  11. package/dist/host/worker-runner.d.ts.map +1 -0
  12. package/dist/host/worker-runner.js +196 -0
  13. package/dist/host/worker-runner.js.map +1 -0
  14. package/dist/index.d.ts +34 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +20 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/loader.d.ts +81 -0
  19. package/dist/loader.d.ts.map +1 -0
  20. package/dist/loader.js +190 -0
  21. package/dist/loader.js.map +1 -0
  22. package/dist/manifest.d.ts +93 -0
  23. package/dist/manifest.d.ts.map +1 -0
  24. package/dist/manifest.js +197 -0
  25. package/dist/manifest.js.map +1 -0
  26. package/dist/permissions/describe.d.ts +22 -0
  27. package/dist/permissions/describe.d.ts.map +1 -0
  28. package/dist/permissions/describe.js +158 -0
  29. package/dist/permissions/describe.js.map +1 -0
  30. package/dist/permissions/disabled.d.ts +25 -0
  31. package/dist/permissions/disabled.d.ts.map +1 -0
  32. package/dist/permissions/disabled.js +29 -0
  33. package/dist/permissions/disabled.js.map +1 -0
  34. package/dist/permissions/grants.d.ts +22 -0
  35. package/dist/permissions/grants.d.ts.map +1 -0
  36. package/dist/permissions/grants.js +31 -0
  37. package/dist/permissions/grants.js.map +1 -0
  38. package/dist/permissions/resolve.d.ts +47 -0
  39. package/dist/permissions/resolve.d.ts.map +1 -0
  40. package/dist/permissions/resolve.js +51 -0
  41. package/dist/permissions/resolve.js.map +1 -0
  42. package/dist/permissions/review.d.ts +50 -0
  43. package/dist/permissions/review.d.ts.map +1 -0
  44. package/dist/permissions/review.js +46 -0
  45. package/dist/permissions/review.js.map +1 -0
  46. package/dist/permissions/tables.d.ts +18 -0
  47. package/dist/permissions/tables.d.ts.map +1 -0
  48. package/dist/permissions/tables.js +48 -0
  49. package/dist/permissions/tables.js.map +1 -0
  50. package/dist/registries/plugins.d.ts +74 -0
  51. package/dist/registries/plugins.d.ts.map +1 -0
  52. package/dist/registries/plugins.js +127 -0
  53. package/dist/registries/plugins.js.map +1 -0
  54. package/dist/registries/skills.d.ts +54 -0
  55. package/dist/registries/skills.d.ts.map +1 -0
  56. package/dist/registries/skills.js +113 -0
  57. package/dist/registries/skills.js.map +1 -0
  58. package/dist/registries/skins.d.ts +33 -0
  59. package/dist/registries/skins.d.ts.map +1 -0
  60. package/dist/registries/skins.js +65 -0
  61. package/dist/registries/skins.js.map +1 -0
  62. package/dist/registries/tables.d.ts +44 -0
  63. package/dist/registries/tables.d.ts.map +1 -0
  64. package/dist/registries/tables.js +118 -0
  65. package/dist/registries/tables.js.map +1 -0
  66. package/dist/registries/themes.d.ts +59 -0
  67. package/dist/registries/themes.d.ts.map +1 -0
  68. package/dist/registries/themes.js +82 -0
  69. package/dist/registries/themes.js.map +1 -0
  70. package/dist/semver.d.ts +24 -0
  71. package/dist/semver.d.ts.map +1 -0
  72. package/dist/semver.js +93 -0
  73. package/dist/semver.js.map +1 -0
  74. package/dist/signing/keys.d.ts +18 -0
  75. package/dist/signing/keys.d.ts.map +1 -0
  76. package/dist/signing/keys.js +15 -0
  77. package/dist/signing/keys.js.map +1 -0
  78. package/dist/signing/sign.d.ts +35 -0
  79. package/dist/signing/sign.d.ts.map +1 -0
  80. package/dist/signing/sign.js +63 -0
  81. package/dist/signing/sign.js.map +1 -0
  82. package/dist/signing/verify.d.ts +40 -0
  83. package/dist/signing/verify.d.ts.map +1 -0
  84. package/dist/signing/verify.js +73 -0
  85. package/dist/signing/verify.js.map +1 -0
  86. package/package.json +46 -0
@@ -0,0 +1,196 @@
1
+ import { Worker } from 'node:worker_threads';
2
+ import { CogentaError } from '@cogenta/core';
3
+ import { resolveGrantedCapabilities } from '../permissions/resolve.js';
4
+ /**
5
+ * The isolated worker boundary itself — "Tout plugin tiers s'exécute dans un
6
+ * worker séparé" (docs/lots/L7-extensibilite.md § Isolation). This is task
7
+ * 3's real deliverable: spawn a worker that cannot reach `fs`/`net`/`process`
8
+ * /env/secrets no matter what code runs inside it, talk to it over a real
9
+ * serialized message protocol, and kill it if it doesn't answer in time.
10
+ *
11
+ * What this does NOT build (deliberately, per the lot's own task split):
12
+ * the real capability-gated SDK object a plugin actually calls (task 4/5),
13
+ * or the full time/memory-limit-and-disable-with-alert policy (task 6) — the
14
+ * timeout below is the minimal, real mechanism this task's own tests need so
15
+ * a hostile or runaway plugin can't hang the process; task 6 owns the
16
+ * complete policy layer on top of it.
17
+ */
18
+ const SANDBOX_ENTRY_URL = new URL('../guest/sandbox-entry.mjs', import.meta.url);
19
+ const DEFAULT_TIMEOUT_MS = 2000;
20
+ const DEFAULT_MAX_OLD_GENERATION_MB = 64;
21
+ /**
22
+ * Node signals a `resourceLimits` heap-limit violation to the parent via the
23
+ * `Worker`'s `'error'` event, carrying a message from V8's own OOM reporting
24
+ * (observed shape: "Worker terminated due to reaching memory limit: JS heap
25
+ * out of memory") — never a distinct error class or a dedicated event type,
26
+ * so this is a real, deliberately narrow message-pattern match, not a guess
27
+ * at a documented API. Anything else that reaches `'error'`/a non-zero exit
28
+ * is classified `'crash'`: still real grounds to disable the plugin, just
29
+ * not a heap-limit violation specifically.
30
+ */
31
+ function classifyFailure(message) {
32
+ return /heap|memory limit|out of memory/i.test(message) ? 'memory' : 'crash';
33
+ }
34
+ let nextRequestId = 1;
35
+ /**
36
+ * Dispatches one real SDK call from the sandbox to its host-side handler
37
+ * (`./capabilities.js`) and reports the outcome back — the handler itself
38
+ * re-verifies the specific request (a domain, a storage key) against the
39
+ * specific granted capability parameters; this function only routes.
40
+ */
41
+ async function handleSdkCall(message, handlers, grantedCapabilities, worker) {
42
+ const handler = handlers[message.method];
43
+ if (handler === undefined) {
44
+ const reply = {
45
+ type: 'sdk-error',
46
+ callId: message.callId,
47
+ message: `no host handler registered for "${message.method}"`,
48
+ };
49
+ worker.postMessage(reply);
50
+ return;
51
+ }
52
+ try {
53
+ const value = await handler(message.args, { grantedCapabilities });
54
+ const reply = { type: 'sdk-result', callId: message.callId, value };
55
+ worker.postMessage(reply);
56
+ }
57
+ catch (error) {
58
+ const reply = {
59
+ type: 'sdk-error',
60
+ callId: message.callId,
61
+ message: error instanceof Error ? error.message : String(error),
62
+ };
63
+ worker.postMessage(reply);
64
+ }
65
+ }
66
+ /**
67
+ * Runs `code` inside a fresh, isolated worker and reports the outcome.
68
+ * `code` is a classic (non-module) script body — the sandbox's real,
69
+ * documented restriction, not an accident: `vm.Script` without an
70
+ * `importModuleDynamically` callback refuses `import()`, and no `require`
71
+ * is ever injected into the sandbox, which is exactly what stops a plugin
72
+ * from reaching `node:fs`/`node:net` no matter which syntax it tries.
73
+ *
74
+ * A fresh `Worker` per call, not a pool — task 6 decides whether a
75
+ * long-lived, reusable worker (with the resource/time policy it owns) is
76
+ * worth the complexity; this task only needs a real, working isolation
77
+ * primitive to build on.
78
+ */
79
+ export async function runIsolated(code, options = {}) {
80
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
81
+ const grantedCapabilities = options.grantedCapabilities ?? [];
82
+ const handlers = options.handlers ?? {};
83
+ const id = nextRequestId;
84
+ nextRequestId += 1;
85
+ const worker = new Worker(SANDBOX_ENTRY_URL, {
86
+ // Never inherit the host's environment — "n'a accès... ni aux variables
87
+ // d'environnement, ni aux secrets" is structural here, not a convention
88
+ // the plugin is merely asked to respect: an empty `env` means the
89
+ // worker's `process.env` (if it were even reachable, which it is not
90
+ // inside the vm sandbox either) genuinely has nothing in it.
91
+ env: {},
92
+ argv: [],
93
+ resourceLimits: {
94
+ maxOldGenerationSizeMb: options.maxOldGenerationSizeMb ?? DEFAULT_MAX_OLD_GENERATION_MB,
95
+ maxYoungGenerationSizeMb: 16,
96
+ },
97
+ stdout: false,
98
+ stderr: false,
99
+ });
100
+ return await new Promise((resolve) => {
101
+ let settled = false;
102
+ const finish = (result) => {
103
+ if (settled)
104
+ return;
105
+ settled = true;
106
+ clearTimeout(timer);
107
+ void worker.terminate();
108
+ resolve(result);
109
+ };
110
+ const timer = setTimeout(() => {
111
+ finish({ ok: false, error: 'plugin worker timed out', reason: 'timeout' });
112
+ }, timeoutMs);
113
+ // `sdk-call` messages arrive zero or more times WHILE `code` runs, each
114
+ // one a real capability request that must be re-verified and executed
115
+ // host-side before the sandbox's own `await sdk.<ns>.<method>(...)` can
116
+ // resolve — this is the RPC loop the guest-side SDK methods (task 4)
117
+ // are built on. It stays a real `.on` listener, not `.once`, since a
118
+ // single run may call several SDK methods before finishing.
119
+ worker.on('message', (message) => {
120
+ if (message.type === 'result') {
121
+ finish({ ok: true, value: message.value });
122
+ return;
123
+ }
124
+ if (message.type === 'error') {
125
+ finish({ ok: false, error: message.message });
126
+ return;
127
+ }
128
+ void handleSdkCall(message, handlers, grantedCapabilities, worker);
129
+ });
130
+ worker.once('error', (error) => {
131
+ const message = error instanceof Error ? error.message : String(error);
132
+ finish({ ok: false, error: message, reason: classifyFailure(message) });
133
+ });
134
+ worker.once('exit', (exitCode) => {
135
+ if (exitCode !== 0) {
136
+ const message = `plugin worker exited with code ${exitCode}`;
137
+ finish({ ok: false, error: message, reason: 'crash' });
138
+ }
139
+ });
140
+ const request = { id, type: 'run', code, grantedCapabilities };
141
+ worker.postMessage(request);
142
+ });
143
+ }
144
+ /**
145
+ * The real entry point for actually running a resolved plugin — unlike
146
+ * `runIsolated`, which task 4 left accepting an externally-decided
147
+ * `grantedCapabilities` list as a placeholder, this computes that list
148
+ * itself via `resolveGrantedCapabilities` (task 5) from the plugin's real
149
+ * manifest and its real, persisted grants. A caller cannot bypass grant
150
+ * resolution by simply passing whatever capability list it wants — the only
151
+ * way a capability reaches the sandbox is a real row in the grant store.
152
+ *
153
+ * Task 6 adds the other two real gates the lot demands: a disabled plugin is
154
+ * refused BEFORE a worker is ever spawned (`PLUGIN_DISABLED`, not a silent
155
+ * no-op), and a timeout or memory-limit violation disables the plugin for
156
+ * every future run, not just the one that failed — "il ne peut pas faire
157
+ * tomber le CMS" is the isolation boundary's job (task 3); making sure it
158
+ * cannot even try again unsupervised is this task's.
159
+ */
160
+ export async function runPlugin(manifest, code, grants, options) {
161
+ const alreadyDisabled = await options.disableStore.isDisabled(manifest.name);
162
+ if (alreadyDisabled !== null) {
163
+ throw new CogentaError({
164
+ code: 'PLUGIN_DISABLED',
165
+ message: `Plugin "${manifest.name}" is disabled (${alreadyDisabled.reason}, since ${alreadyDisabled.disabledAt}) and cannot be run.`,
166
+ hint: 'A human must explicitly re-enable this plugin before it can run again.',
167
+ details: { pluginName: manifest.name, reason: alreadyDisabled.reason },
168
+ });
169
+ }
170
+ const grantedCapabilities = resolveGrantedCapabilities(manifest, grants);
171
+ const result = await runIsolated(code, { ...options, grantedCapabilities });
172
+ if (!result.ok && (result.reason === 'timeout' || result.reason === 'memory')) {
173
+ await options.disableStore.disable(manifest.name, result.reason, result.error);
174
+ options.onPluginDisabled?.({
175
+ pluginName: manifest.name,
176
+ reason: result.reason,
177
+ at: new Date().toISOString(),
178
+ ...(result.error === undefined ? {} : { details: result.error }),
179
+ });
180
+ }
181
+ return result;
182
+ }
183
+ /** Throws instead of returning a discriminated failure — for call sites that want a plain success value or a real error. */
184
+ export async function runIsolatedOrThrow(code, options) {
185
+ const result = await runIsolated(code, options);
186
+ if (result.ok)
187
+ return result.value;
188
+ throw new CogentaError({
189
+ code: result.error === 'plugin worker timed out'
190
+ ? 'PLUGIN_WORKER_TIMEOUT'
191
+ : 'PLUGIN_WORKER_RUNTIME_ERROR',
192
+ message: result.error ?? 'Plugin worker failed for an unknown reason.',
193
+ hint: 'Check the plugin code for an unhandled error, an infinite loop, or excessive memory use.',
194
+ });
195
+ }
196
+ //# sourceMappingURL=worker-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-runner.js","sourceRoot":"","sources":["../../src/host/worker-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ export type { CapabilityCallContext, CapabilityHandler } from './host/capabilities.js';
2
+ export { createContentReadHandler, createHttpFetchHandler, createStorageReadHandler, createStorageWriteHandler, } from './host/capabilities.js';
3
+ export type { IsolatedRunResult, PluginDisabledEvent, RunIsolatedOptions, RunPluginOptions, } from './host/worker-runner.js';
4
+ export { runIsolated, runIsolatedOrThrow, runPlugin } from './host/worker-runner.js';
5
+ export type { LoadPluginOptions, PluginSource, ResolvedPlugin } from './loader.js';
6
+ export { loadPlugin, PLUGIN_MANIFEST_FILE_NAMES, resolveSignatureStatus } from './loader.js';
7
+ export type { PluginBlockProvision, PluginCapabilityName, PluginManifest, PluginManifestIssue, PluginProvides, PluginRuntime, } from './manifest.js';
8
+ export { definePlugin, PLUGIN_CAPABILITY_NAMES, PLUGIN_RUNTIMES, } from './manifest.js';
9
+ export type { PluginCapabilityDescription, PluginCapabilityRisk, } from './permissions/describe.js';
10
+ export { DESCRIBABLE_CAPABILITY_NAMES, describeCapability } from './permissions/describe.js';
11
+ export type { PluginDisabledRecord, PluginDisableStore, PluginViolationReason, } from './permissions/disabled.js';
12
+ export { createPluginDisableStore } from './permissions/disabled.js';
13
+ export type { PluginGrant, PluginGrantStore } from './permissions/grants.js';
14
+ export { createPluginGrantStore } from './permissions/grants.js';
15
+ export { detectCapabilitiesNeedingApproval, resolveGrantedCapabilities, } from './permissions/resolve.js';
16
+ export type { GrantedCapabilityReview, PendingCapabilityReview, } from './permissions/review.js';
17
+ export { describePendingApproval, listGrantedCapabilities, revokeCapability, } from './permissions/review.js';
18
+ export { ensurePluginTables, PERMISSION_TABLES } from './permissions/tables.js';
19
+ export type { PluginRegistry, PluginRegistryOptions, PluginReviewDecision, PluginReviewResult, PluginSubmissionEntry, PluginSubmissionInput, PluginSubmissionStatus, } from './registries/plugins.js';
20
+ export { createPluginRegistry } from './registries/plugins.js';
21
+ export type { SkillRegistry, SkillReviewDecision, SkillReviewResult, SkillSubmissionEntry, SkillSubmissionInput, SkillSubmissionStatus, } from './registries/skills.js';
22
+ export { createSkillRegistry } from './registries/skills.js';
23
+ export type { SkinGallery, SkinGalleryEntry, SkinSubmissionInput, SkinSubmissionStatus, } from './registries/skins.js';
24
+ export { createSkinGallery } from './registries/skins.js';
25
+ export { ensureRegistryTables, REGISTRY_TABLES } from './registries/tables.js';
26
+ export type { ThemeRegistry, ThemeRegistryEntry, ThemeRegistryOptions, ThemeSubmissionInput, ThemeSubmissionStatus, } from './registries/themes.js';
27
+ export { createThemeRegistry } from './registries/themes.js';
28
+ export type { SemverVersion } from './semver.js';
29
+ export { compareVersions, parseVersion, satisfiesRange } from './semver.js';
30
+ export type { SigningKeyPair } from './signing/keys.js';
31
+ export { exportPrivateKey, exportPublicKey, generateSigningKeyPair } from './signing/keys.js';
32
+ export { canonicalizeContent, canonicalizeManifest, signContent, signManifest, } from './signing/sign.js';
33
+ export { readSignatureFile, TRUSTED_REGISTRY_PUBLIC_KEYS, verifyContentAgainstTrustedKeys, verifyContentSignature, verifyManifestSignature, verifyPluginSignature, } from './signing/verify.js';
34
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ export { createContentReadHandler, createHttpFetchHandler, createStorageReadHandler, createStorageWriteHandler, } from './host/capabilities.js';
2
+ export { runIsolated, runIsolatedOrThrow, runPlugin } from './host/worker-runner.js';
3
+ export { loadPlugin, PLUGIN_MANIFEST_FILE_NAMES, resolveSignatureStatus } from './loader.js';
4
+ export { definePlugin, PLUGIN_CAPABILITY_NAMES, PLUGIN_RUNTIMES, } from './manifest.js';
5
+ export { DESCRIBABLE_CAPABILITY_NAMES, describeCapability } from './permissions/describe.js';
6
+ export { createPluginDisableStore } from './permissions/disabled.js';
7
+ export { createPluginGrantStore } from './permissions/grants.js';
8
+ export { detectCapabilitiesNeedingApproval, resolveGrantedCapabilities, } from './permissions/resolve.js';
9
+ export { describePendingApproval, listGrantedCapabilities, revokeCapability, } from './permissions/review.js';
10
+ export { ensurePluginTables, PERMISSION_TABLES } from './permissions/tables.js';
11
+ export { createPluginRegistry } from './registries/plugins.js';
12
+ export { createSkillRegistry } from './registries/skills.js';
13
+ export { createSkinGallery } from './registries/skins.js';
14
+ export { ensureRegistryTables, REGISTRY_TABLES } from './registries/tables.js';
15
+ export { createThemeRegistry } from './registries/themes.js';
16
+ export { compareVersions, parseVersion, satisfiesRange } from './semver.js';
17
+ export { exportPrivateKey, exportPublicKey, generateSigningKeyPair } from './signing/keys.js';
18
+ export { canonicalizeContent, canonicalizeManifest, signContent, signManifest, } from './signing/sign.js';
19
+ export { readSignatureFile, TRUSTED_REGISTRY_PUBLIC_KEYS, verifyContentAgainstTrustedKeys, verifyContentSignature, verifyManifestSignature, verifyPluginSignature, } from './signing/verify.js';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,wBAAwB,CAAA;AAO/B,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAEpF,OAAO,EAAE,UAAU,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAS5F,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,eAAe,GAChB,MAAM,eAAe,CAAA;AAKtB,OAAO,EAAE,4BAA4B,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAM5F,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAA;AAEpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAChE,OAAO,EACL,iCAAiC,EACjC,0BAA0B,GAC3B,MAAM,0BAA0B,CAAA;AAKjC,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAU/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAS9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAO5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAQ9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAE5D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE3E,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC7F,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,WAAW,EACX,YAAY,GACb,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACL,iBAAiB,EACjB,4BAA4B,EAC5B,+BAA+B,EAC/B,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,qBAAqB,CAAA"}
@@ -0,0 +1,81 @@
1
+ import { type PluginManifest } from './manifest.js';
2
+ /**
3
+ * Where a resolved plugin came from — structural, not cosmetic: task 9
4
+ * (signing) and the permissions screen's "avertissement permanent" both key
5
+ * off this. A `local`/`git` plugin is allowed in development mode without a
6
+ * signature; a `registry` plugin is not.
7
+ */
8
+ export type PluginSource = 'registry' | 'local' | 'git';
9
+ /**
10
+ * Checked in order, mirroring `@cogenta/core`'s `CONFIG_FILE_NAMES`
11
+ * (`load-config.ts`) exactly — a plugin's manifest is a user-authored file
12
+ * loaded the same way `cogenta.config.mjs`/`cogenta.schema.mjs` already are,
13
+ * not a bespoke new mechanism.
14
+ */
15
+ export declare const PLUGIN_MANIFEST_FILE_NAMES: readonly ['plugin.manifest.ts', 'plugin.manifest.mts', 'plugin.manifest.js', 'plugin.manifest.mjs'];
16
+ export interface ResolvedPlugin {
17
+ readonly manifest: PluginManifest;
18
+ readonly source: PluginSource;
19
+ /** Absolute path to the package root that was resolved. */
20
+ readonly packageRoot: string;
21
+ /** Absolute path to the manifest file that was loaded. */
22
+ readonly manifestPath: string;
23
+ /** Whether `manifest.engine` is satisfied by `engineVersion` (`loadPlugin`'s option). */
24
+ readonly engineCompatible: boolean;
25
+ /**
26
+ * `true` only for a `local` (or, once resolvable, `git`) source: allowed
27
+ * to run unsigned, "en mode développement" — the real datum a later admin
28
+ * banner's "avertissement permanent" would render. A `registry` plugin is
29
+ * never dev mode: it either verified or `loadPlugin` already refused it.
30
+ */
31
+ readonly devMode: boolean;
32
+ /** `true` only when a `registry` plugin's signature was checked and matched a trusted key. Always `false` in dev mode — there was nothing to check. */
33
+ readonly signatureVerified: boolean;
34
+ }
35
+ export interface LoadPluginOptions {
36
+ /**
37
+ * Cogenta's own version, checked against `manifest.engine`. No real,
38
+ * meaningful Cogenta version exists anywhere yet (pre-alpha; the root
39
+ * `package.json` carries no `version` field, and every workspace package
40
+ * still uses the `0.0.0` placeholder) — `engineCompatible` is real and
41
+ * correctly computed against whatever is passed here, but until a real
42
+ * versioning scheme exists, pass a real Cogenta version explicitly when
43
+ * one exists; the default below is a placeholder that makes every plugin
44
+ * appear compatible, which is the honest behaviour of "no check exists
45
+ * yet" rather than a fabricated pass/fail.
46
+ */
47
+ readonly engineVersion?: string;
48
+ /**
49
+ * Base64 SPKI Ed25519 public keys this call trusts for `registry`-source
50
+ * signature verification. Defaults to `TRUSTED_REGISTRY_PUBLIC_KEYS`
51
+ * (`./signing/verify.js`) — empty until a real registry exists, so every
52
+ * `registry` plugin fails verification by default rather than trusting a
53
+ * placeholder key.
54
+ */
55
+ readonly trustedPublicKeys?: readonly string[];
56
+ }
57
+ /**
58
+ * `source: 'registry'` is where "## Signature" (docs/lots/L7-extensibilite.md)
59
+ * actually bites: "Une signature invalide bloque, sans possibilité de passer
60
+ * outre depuis l'interface." There is deliberately no parameter here that
61
+ * lets a caller force past a missing/invalid signature — the only way past
62
+ * this function is a real, matching signature, because the override this
63
+ * shape could otherwise offer is exactly what the lot's own line means by
64
+ * "sans possibilité de passer outre." `local`/`git` sources skip
65
+ * verification entirely, by design ("autorisé en mode développement"), and
66
+ * are reported back as `devMode: true` for a future admin banner to render
67
+ * as the "avertissement permanent" the lot also asks for.
68
+ */
69
+ export declare function resolveSignatureStatus(source: PluginSource, manifest: PluginManifest, manifestPath: string, trustedPublicKeys: readonly string[]): Promise<{
70
+ readonly devMode: boolean;
71
+ readonly signatureVerified: boolean;
72
+ }>;
73
+ /**
74
+ * Resolves a plugin reference to its package root and source kind, loads
75
+ * and validates its manifest (via `definePlugin`), verifies its signature
76
+ * when required, and reports engine compatibility. Executes no plugin code
77
+ * beyond importing the manifest-declaring module — spawning a worker to run
78
+ * the plugin's actual runtime is task 3, not this one.
79
+ */
80
+ export declare function loadPlugin(reference: string, options?: LoadPluginOptions): Promise<ResolvedPlugin>;
81
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAIA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AAQjE;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,OAAO,GAAG,KAAK,CAAA;AAEvD;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,YACrC,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,CACb,CAAA;AAEV,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IACjC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAA;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,yFAAyF;IACzF,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAA;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,uJAAuJ;IACvJ,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAA;CACpC;AA4ED,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC/C;AAID;;;;;;;;;;;GAWG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,cAAc,EACxB,YAAY,EAAE,MAAM,EACpB,iBAAiB,EAAE,SAAS,MAAM,EAAE,GACnC,OAAO,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAA;CAAE,CAAC,CA0B7E;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,cAAc,CAAC,CAiCzB"}
package/dist/loader.js ADDED
@@ -0,0 +1,190 @@
1
+ import { access, stat } from 'node:fs/promises';
2
+ import { dirname, isAbsolute, join } from 'node:path';
3
+ import { fileURLToPath, pathToFileURL } from 'node:url';
4
+ import { CogentaError } from '@cogenta/core';
5
+ import { definePlugin } from './manifest.js';
6
+ import { satisfiesRange } from './semver.js';
7
+ import { readSignatureFile, TRUSTED_REGISTRY_PUBLIC_KEYS, verifyPluginSignature, } from './signing/verify.js';
8
+ /**
9
+ * Checked in order, mirroring `@cogenta/core`'s `CONFIG_FILE_NAMES`
10
+ * (`load-config.ts`) exactly — a plugin's manifest is a user-authored file
11
+ * loaded the same way `cogenta.config.mjs`/`cogenta.schema.mjs` already are,
12
+ * not a bespoke new mechanism.
13
+ */
14
+ export const PLUGIN_MANIFEST_FILE_NAMES = [
15
+ 'plugin.manifest.ts',
16
+ 'plugin.manifest.mts',
17
+ 'plugin.manifest.js',
18
+ 'plugin.manifest.mjs',
19
+ ];
20
+ async function exists(path) {
21
+ try {
22
+ await access(path);
23
+ return true;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ /**
30
+ * A git reference: `git+https://...`, a bare `https://...\.git`, or the
31
+ * `github:owner/repo` shorthand. Cloning it is a real network/filesystem
32
+ * operation this task deliberately does not build — "résolution" here means
33
+ * "recognise a git source and refuse honestly," not "implement a git
34
+ * client." A local checkout of a git-sourced plugin is loaded exactly like
35
+ * any other local path once it exists on disk.
36
+ */
37
+ function isGitReference(reference) {
38
+ return (reference.startsWith('git+') ||
39
+ reference.startsWith('github:') ||
40
+ /^https?:\/\/.+\.git$/.test(reference));
41
+ }
42
+ function looksLikeLocalPath(reference) {
43
+ return reference.startsWith('.') || reference.startsWith('/') || isAbsolute(reference);
44
+ }
45
+ async function findManifestFile(packageRoot) {
46
+ for (const name of PLUGIN_MANIFEST_FILE_NAMES) {
47
+ const candidate = join(packageRoot, name);
48
+ if (await exists(candidate))
49
+ return candidate;
50
+ }
51
+ throw new CogentaError({
52
+ code: 'PLUGIN_MANIFEST_FILE_NOT_FOUND',
53
+ message: `No plugin manifest found in ${packageRoot}.`,
54
+ hint: `Add one of: ${PLUGIN_MANIFEST_FILE_NAMES.join(', ')}.`,
55
+ details: { packageRoot },
56
+ });
57
+ }
58
+ async function importManifest(manifestPath) {
59
+ let module;
60
+ try {
61
+ module = (await import(pathToFileURL(manifestPath).href));
62
+ }
63
+ catch (error) {
64
+ throw new CogentaError({
65
+ code: 'PLUGIN_MANIFEST_LOAD_FAILED',
66
+ message: `Could not load ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`,
67
+ hint: manifestPath.endsWith('.ts')
68
+ ? 'A TypeScript manifest needs a Node runtime that strips types (Node 22.18+). Use plugin.manifest.mjs on an older one.'
69
+ : 'Check the file for a syntax error, and that every import it uses is installed.',
70
+ cause: error,
71
+ details: { manifestPath },
72
+ });
73
+ }
74
+ if (module.default === undefined) {
75
+ throw new CogentaError({
76
+ code: 'PLUGIN_MANIFEST_EXPORT_INVALID',
77
+ message: `${manifestPath} has no default export.`,
78
+ hint: 'Export the manifest as the default: `export default definePlugin({ … })`.',
79
+ details: { manifestPath },
80
+ });
81
+ }
82
+ // `definePlugin` re-validates even though a well-formed manifest module
83
+ // already called it once at module-load time — a manifest file could
84
+ // export a plain object instead of calling `definePlugin` itself, and
85
+ // this is the only place that can catch that.
86
+ return definePlugin(module.default);
87
+ }
88
+ const NO_REAL_ENGINE_VERSION_YET = '0.0.0';
89
+ /**
90
+ * `source: 'registry'` is where "## Signature" (docs/lots/L7-extensibilite.md)
91
+ * actually bites: "Une signature invalide bloque, sans possibilité de passer
92
+ * outre depuis l'interface." There is deliberately no parameter here that
93
+ * lets a caller force past a missing/invalid signature — the only way past
94
+ * this function is a real, matching signature, because the override this
95
+ * shape could otherwise offer is exactly what the lot's own line means by
96
+ * "sans possibilité de passer outre." `local`/`git` sources skip
97
+ * verification entirely, by design ("autorisé en mode développement"), and
98
+ * are reported back as `devMode: true` for a future admin banner to render
99
+ * as the "avertissement permanent" the lot also asks for.
100
+ */
101
+ export async function resolveSignatureStatus(source, manifest, manifestPath, trustedPublicKeys) {
102
+ if (source !== 'registry') {
103
+ return { devMode: true, signatureVerified: false };
104
+ }
105
+ const signature = await readSignatureFile(manifestPath);
106
+ if (signature === null) {
107
+ throw new CogentaError({
108
+ code: 'PLUGIN_SIGNATURE_MISSING',
109
+ message: `Plugin "${manifest.name}" has no signature file at ${manifestPath}.sig.`,
110
+ hint: 'Registry plugins must be signed. Install from a local path for unsigned development use.',
111
+ details: { pluginName: manifest.name, manifestPath },
112
+ });
113
+ }
114
+ const verified = verifyPluginSignature(manifest, signature, trustedPublicKeys);
115
+ if (!verified) {
116
+ throw new CogentaError({
117
+ code: 'PLUGIN_SIGNATURE_INVALID',
118
+ message: `Plugin "${manifest.name}"'s signature does not match any trusted key.`,
119
+ hint: 'The package may be tampered with, or its signing key is not (yet) trusted by this installation.',
120
+ details: { pluginName: manifest.name, manifestPath },
121
+ });
122
+ }
123
+ return { devMode: false, signatureVerified: true };
124
+ }
125
+ /**
126
+ * Resolves a plugin reference to its package root and source kind, loads
127
+ * and validates its manifest (via `definePlugin`), verifies its signature
128
+ * when required, and reports engine compatibility. Executes no plugin code
129
+ * beyond importing the manifest-declaring module — spawning a worker to run
130
+ * the plugin's actual runtime is task 3, not this one.
131
+ */
132
+ export async function loadPlugin(reference, options = {}) {
133
+ const engineVersion = options.engineVersion ?? NO_REAL_ENGINE_VERSION_YET;
134
+ const trustedPublicKeys = options.trustedPublicKeys ?? TRUSTED_REGISTRY_PUBLIC_KEYS;
135
+ if (isGitReference(reference)) {
136
+ throw new CogentaError({
137
+ code: 'PLUGIN_SOURCE_NOT_FOUND',
138
+ message: `Git-sourced plugins are not resolvable yet: "${reference}".`,
139
+ hint: 'Clone the repository locally and pass its local path instead.',
140
+ details: { reference },
141
+ });
142
+ }
143
+ const source = looksLikeLocalPath(reference) ? 'local' : 'registry';
144
+ const packageRoot = await resolvePackageRoot(reference, source);
145
+ const manifestPath = await findManifestFile(packageRoot);
146
+ const manifest = await importManifest(manifestPath);
147
+ const { devMode, signatureVerified } = await resolveSignatureStatus(source, manifest, manifestPath, trustedPublicKeys);
148
+ return {
149
+ manifest,
150
+ source,
151
+ packageRoot,
152
+ manifestPath,
153
+ engineCompatible: satisfiesRange(engineVersion, manifest.engine),
154
+ devMode,
155
+ signatureVerified,
156
+ };
157
+ }
158
+ async function resolvePackageRoot(reference, source) {
159
+ if (source === 'local') {
160
+ const stats = await stat(reference).catch(() => null);
161
+ if (stats === null || !stats.isDirectory()) {
162
+ throw new CogentaError({
163
+ code: 'PLUGIN_SOURCE_NOT_FOUND',
164
+ message: `No plugin directory at "${reference}".`,
165
+ hint: 'Check the path — it must be an existing directory.',
166
+ details: { reference },
167
+ });
168
+ }
169
+ return reference;
170
+ }
171
+ // A registry package name: resolved via Node's own ESM resolution, the
172
+ // same mechanism any other workspace/npm dependency uses — no bespoke
173
+ // registry client. `import.meta.resolve` throws `ERR_MODULE_NOT_FOUND` on
174
+ // a package that is not installed, which is exactly the failure this task
175
+ // needs to report.
176
+ try {
177
+ const resolvedUrl = import.meta.resolve(`${reference}/package.json`);
178
+ return dirname(fileURLToPath(resolvedUrl));
179
+ }
180
+ catch (error) {
181
+ throw new CogentaError({
182
+ code: 'PLUGIN_SOURCE_NOT_FOUND',
183
+ message: `Could not resolve plugin package "${reference}": ${error instanceof Error ? error.message : String(error)}`,
184
+ hint: 'Install the plugin package, or pass a local path instead.',
185
+ cause: error,
186
+ details: { reference },
187
+ });
188
+ }
189
+ }
190
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"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"}