@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.
- package/dist/guest/sandbox-entry.mjs +155 -0
- package/dist/host/capabilities.d.ts +46 -0
- package/dist/host/capabilities.d.ts.map +1 -0
- package/dist/host/capabilities.js +105 -0
- package/dist/host/capabilities.js.map +1 -0
- package/dist/host/protocol.d.ts +58 -0
- package/dist/host/protocol.d.ts.map +1 -0
- package/dist/host/protocol.js +10 -0
- package/dist/host/protocol.js.map +1 -0
- package/dist/host/worker-runner.d.ts +92 -0
- package/dist/host/worker-runner.d.ts.map +1 -0
- package/dist/host/worker-runner.js +196 -0
- package/dist/host/worker-runner.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +81 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +190 -0
- package/dist/loader.js.map +1 -0
- package/dist/manifest.d.ts +93 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +197 -0
- package/dist/manifest.js.map +1 -0
- package/dist/permissions/describe.d.ts +22 -0
- package/dist/permissions/describe.d.ts.map +1 -0
- package/dist/permissions/describe.js +158 -0
- package/dist/permissions/describe.js.map +1 -0
- package/dist/permissions/disabled.d.ts +25 -0
- package/dist/permissions/disabled.d.ts.map +1 -0
- package/dist/permissions/disabled.js +29 -0
- package/dist/permissions/disabled.js.map +1 -0
- package/dist/permissions/grants.d.ts +22 -0
- package/dist/permissions/grants.d.ts.map +1 -0
- package/dist/permissions/grants.js +31 -0
- package/dist/permissions/grants.js.map +1 -0
- package/dist/permissions/resolve.d.ts +47 -0
- package/dist/permissions/resolve.d.ts.map +1 -0
- package/dist/permissions/resolve.js +51 -0
- package/dist/permissions/resolve.js.map +1 -0
- package/dist/permissions/review.d.ts +50 -0
- package/dist/permissions/review.d.ts.map +1 -0
- package/dist/permissions/review.js +46 -0
- package/dist/permissions/review.js.map +1 -0
- package/dist/permissions/tables.d.ts +18 -0
- package/dist/permissions/tables.d.ts.map +1 -0
- package/dist/permissions/tables.js +48 -0
- package/dist/permissions/tables.js.map +1 -0
- package/dist/registries/plugins.d.ts +74 -0
- package/dist/registries/plugins.d.ts.map +1 -0
- package/dist/registries/plugins.js +127 -0
- package/dist/registries/plugins.js.map +1 -0
- package/dist/registries/skills.d.ts +54 -0
- package/dist/registries/skills.d.ts.map +1 -0
- package/dist/registries/skills.js +113 -0
- package/dist/registries/skills.js.map +1 -0
- package/dist/registries/skins.d.ts +33 -0
- package/dist/registries/skins.d.ts.map +1 -0
- package/dist/registries/skins.js +65 -0
- package/dist/registries/skins.js.map +1 -0
- package/dist/registries/tables.d.ts +44 -0
- package/dist/registries/tables.d.ts.map +1 -0
- package/dist/registries/tables.js +118 -0
- package/dist/registries/tables.js.map +1 -0
- package/dist/registries/themes.d.ts +59 -0
- package/dist/registries/themes.d.ts.map +1 -0
- package/dist/registries/themes.js +82 -0
- package/dist/registries/themes.js.map +1 -0
- package/dist/semver.d.ts +24 -0
- package/dist/semver.d.ts.map +1 -0
- package/dist/semver.js +93 -0
- package/dist/semver.js.map +1 -0
- package/dist/signing/keys.d.ts +18 -0
- package/dist/signing/keys.d.ts.map +1 -0
- package/dist/signing/keys.js +15 -0
- package/dist/signing/keys.js.map +1 -0
- package/dist/signing/sign.d.ts +35 -0
- package/dist/signing/sign.d.ts.map +1 -0
- package/dist/signing/sign.js +63 -0
- package/dist/signing/sign.js.map +1 -0
- package/dist/signing/verify.d.ts +40 -0
- package/dist/signing/verify.d.ts.map +1 -0
- package/dist/signing/verify.js +73 -0
- package/dist/signing/verify.js.map +1 -0
- package/package.json +46 -0
package/dist/semver.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A small, real semver-range matcher scoped to exactly the range shapes
|
|
3
|
+
* `manifest.ts`'s `SEMVER_RANGE_PATTERN` already accepts: `^1.2.3`,
|
|
4
|
+
* `~1.2.3`, a bare exact `1.2.3`, and a space-separated list of comparators
|
|
5
|
+
* (`>=1.0.0 <2.0.0`). No `semver` dependency (R9) — this is the whole
|
|
6
|
+
* matcher a plugin's `engine` field realistically needs, not a general
|
|
7
|
+
* semver library.
|
|
8
|
+
*/
|
|
9
|
+
const VERSION_PATTERN = /^(\d+)\.(\d+)\.(\d+)/;
|
|
10
|
+
export function parseVersion(input) {
|
|
11
|
+
const match = VERSION_PATTERN.exec(input);
|
|
12
|
+
if (match === null)
|
|
13
|
+
return null;
|
|
14
|
+
const [, major, minor, patch] = match;
|
|
15
|
+
return { major: Number(major), minor: Number(minor), patch: Number(patch) };
|
|
16
|
+
}
|
|
17
|
+
/** -1 if `a < b`, 0 if equal, 1 if `a > b`. */
|
|
18
|
+
export function compareVersions(a, b) {
|
|
19
|
+
if (a.major !== b.major)
|
|
20
|
+
return a.major < b.major ? -1 : 1;
|
|
21
|
+
if (a.minor !== b.minor)
|
|
22
|
+
return a.minor < b.minor ? -1 : 1;
|
|
23
|
+
if (a.patch !== b.patch)
|
|
24
|
+
return a.patch < b.patch ? -1 : 1;
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
function satisfiesComparator(version, comparator) {
|
|
28
|
+
const operatorMatch = /^(>=|<=|>|<|=)?(.+)$/.exec(comparator);
|
|
29
|
+
if (operatorMatch === null)
|
|
30
|
+
return false;
|
|
31
|
+
const [, operator = '=', rest = ''] = operatorMatch;
|
|
32
|
+
const target = parseVersion(rest);
|
|
33
|
+
if (target === null)
|
|
34
|
+
return false;
|
|
35
|
+
const cmp = compareVersions(version, target);
|
|
36
|
+
switch (operator) {
|
|
37
|
+
case '>=':
|
|
38
|
+
return cmp >= 0;
|
|
39
|
+
case '<=':
|
|
40
|
+
return cmp <= 0;
|
|
41
|
+
case '>':
|
|
42
|
+
return cmp > 0;
|
|
43
|
+
case '<':
|
|
44
|
+
return cmp < 0;
|
|
45
|
+
default:
|
|
46
|
+
return cmp === 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* `^1.2.3` — compatible within the same major (or, per npm's own carat
|
|
51
|
+
* semantics for a `0.x` line, the same minor when major is 0, and the same
|
|
52
|
+
* patch when major and minor are both 0).
|
|
53
|
+
*/
|
|
54
|
+
function satisfiesCaret(version, base) {
|
|
55
|
+
if (compareVersions(version, base) < 0)
|
|
56
|
+
return false;
|
|
57
|
+
if (base.major > 0)
|
|
58
|
+
return version.major === base.major;
|
|
59
|
+
if (base.minor > 0)
|
|
60
|
+
return version.major === 0 && version.minor === base.minor;
|
|
61
|
+
return version.major === 0 && version.minor === 0 && version.patch === base.patch;
|
|
62
|
+
}
|
|
63
|
+
/** `~1.2.3` — compatible within the same major.minor. */
|
|
64
|
+
function satisfiesTilde(version, base) {
|
|
65
|
+
if (compareVersions(version, base) < 0)
|
|
66
|
+
return false;
|
|
67
|
+
return version.major === base.major && version.minor === base.minor;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Whether `versionString` satisfies `range`. Returns `false` (never throws)
|
|
71
|
+
* for a range or version this matcher cannot parse — an unparseable engine
|
|
72
|
+
* range already fails `manifest.ts`'s own validation before this is ever
|
|
73
|
+
* called, so this is a defensive fallback, not the primary guard.
|
|
74
|
+
*/
|
|
75
|
+
export function satisfiesRange(versionString, range) {
|
|
76
|
+
const version = parseVersion(versionString);
|
|
77
|
+
if (version === null)
|
|
78
|
+
return false;
|
|
79
|
+
const trimmed = range.trim();
|
|
80
|
+
if (trimmed.startsWith('^')) {
|
|
81
|
+
const base = parseVersion(trimmed.slice(1));
|
|
82
|
+
return base !== null && satisfiesCaret(version, base);
|
|
83
|
+
}
|
|
84
|
+
if (trimmed.startsWith('~')) {
|
|
85
|
+
const base = parseVersion(trimmed.slice(1));
|
|
86
|
+
return base !== null && satisfiesTilde(version, base);
|
|
87
|
+
}
|
|
88
|
+
// A bare version, or a space-separated list of comparators (each ANDed).
|
|
89
|
+
return trimmed
|
|
90
|
+
.split(/\s+/)
|
|
91
|
+
.every((comparator) => comparator.length > 0 && satisfiesComparator(version, comparator));
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=semver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semver.js","sourceRoot":"","sources":["../src/semver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type KeyObject } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* A real Ed25519 key pair, base64-encoded (SPKI for the public half, PKCS8
|
|
4
|
+
* for the private half) — small, fast, natively supported by `node:crypto`
|
|
5
|
+
* since well before this project's Node 22 LTS baseline. Asymmetric, not
|
|
6
|
+
* the HMAC scheme `@cogenta/channels`' approval links use (L6 task 5):
|
|
7
|
+
* a registry signs once, and every independent Cogenta installation must be
|
|
8
|
+
* able to verify without ever holding the signing secret — a shared-secret
|
|
9
|
+
* scheme cannot do that.
|
|
10
|
+
*/
|
|
11
|
+
export interface SigningKeyPair {
|
|
12
|
+
readonly publicKey: string;
|
|
13
|
+
readonly privateKey: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function generateSigningKeyPair(): SigningKeyPair;
|
|
16
|
+
export declare function exportPublicKey(key: KeyObject): string;
|
|
17
|
+
export declare function exportPrivateKey(key: KeyObject): string;
|
|
18
|
+
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/signing/keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,aAAa,CAAA;AAEjE;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AAED,wBAAgB,sBAAsB,IAAI,cAAc,CAMvD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAEtD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAEvD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { generateKeyPairSync } from 'node:crypto';
|
|
2
|
+
export function generateSigningKeyPair() {
|
|
3
|
+
const { publicKey, privateKey } = generateKeyPairSync('ed25519');
|
|
4
|
+
return {
|
|
5
|
+
publicKey: exportPublicKey(publicKey),
|
|
6
|
+
privateKey: exportPrivateKey(privateKey),
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function exportPublicKey(key) {
|
|
10
|
+
return key.export({ type: 'spki', format: 'der' }).toString('base64');
|
|
11
|
+
}
|
|
12
|
+
export function exportPrivateKey(key) {
|
|
13
|
+
return key.export({ type: 'pkcs8', format: 'der' }).toString('base64');
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/signing/keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAkB,MAAM,aAAa,CAAA;AAgBjE,MAAM,UAAU,sBAAsB;IACpC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAA;IAChE,OAAO;QACL,SAAS,EAAE,eAAe,CAAC,SAAS,CAAC;QACrC,UAAU,EAAE,gBAAgB,CAAC,UAAU,CAAC;KACzC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAc;IAC5C,OAAO,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;AACvE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAc;IAC7C,OAAO,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;AACxE,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { PluginManifest } from '../manifest.js';
|
|
2
|
+
/**
|
|
3
|
+
* A deterministic, sorted-key JSON rendering of any signable content — the
|
|
4
|
+
* same value always canonicalizes identically regardless of the property
|
|
5
|
+
* insertion order its producer happened to use. Generic over content shape:
|
|
6
|
+
* a plugin manifest (task 9) and a theme submission (task 12) are both real
|
|
7
|
+
* consumers, and neither is more "canonical" a use than the other — this is
|
|
8
|
+
* the one real canonicalization primitive, not one per registry.
|
|
9
|
+
*/
|
|
10
|
+
export declare function canonicalizeContent(value: unknown): string;
|
|
11
|
+
/**
|
|
12
|
+
* A plugin manifest's canonical content — what actually gets signed for a
|
|
13
|
+
* plugin (name, version, capabilities, provides, ...), not just its name: a
|
|
14
|
+
* signature that only covered the name would prove authorship of a label,
|
|
15
|
+
* not of what the plugin is declared to do.
|
|
16
|
+
*
|
|
17
|
+
* Deliberately scoped to the manifest, not the plugin's full package
|
|
18
|
+
* contents (its actual runtime code): `loadPlugin` (task 2) only ever reads
|
|
19
|
+
* the manifest-declaring module today — no mechanism yet reads a plugin's
|
|
20
|
+
* entry-point code into a string a signature could cover, so extending
|
|
21
|
+
* coverage to the full package is a real, separate piece of work for
|
|
22
|
+
* whichever future task builds that code-reading path.
|
|
23
|
+
*/
|
|
24
|
+
export declare function canonicalizeManifest(manifest: PluginManifest): string;
|
|
25
|
+
/**
|
|
26
|
+
* Signs any canonicalizable content with a real Ed25519 private key (base64
|
|
27
|
+
* PKCS8, `./keys.js`). The publisher-side half of this primitive — a real
|
|
28
|
+
* Cogenta installation never runs this, only the verification half
|
|
29
|
+
* (`./verify.js`) matters there, but both sides must be real for the
|
|
30
|
+
* primitive to be provably correct rather than assumed.
|
|
31
|
+
*/
|
|
32
|
+
export declare function signContent(content: unknown, privateKeyBase64: string): string;
|
|
33
|
+
/** Signs a plugin manifest — the task-9 entry point, now a thin wrapper over `signContent`. */
|
|
34
|
+
export declare function signManifest(manifest: PluginManifest, privateKeyBase64: string): string;
|
|
35
|
+
//# sourceMappingURL=sign.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../../src/signing/sign.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE1D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAErE;AAcD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAU9E;AAED,+FAA+F;AAC/F,wBAAgB,YAAY,CAAC,QAAQ,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEvF"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createPrivateKey, sign as cryptoSign } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* A deterministic, sorted-key JSON rendering of any signable content — the
|
|
4
|
+
* same value always canonicalizes identically regardless of the property
|
|
5
|
+
* insertion order its producer happened to use. Generic over content shape:
|
|
6
|
+
* a plugin manifest (task 9) and a theme submission (task 12) are both real
|
|
7
|
+
* consumers, and neither is more "canonical" a use than the other — this is
|
|
8
|
+
* the one real canonicalization primitive, not one per registry.
|
|
9
|
+
*/
|
|
10
|
+
export function canonicalizeContent(value) {
|
|
11
|
+
return JSON.stringify(sortKeysDeep(value));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A plugin manifest's canonical content — what actually gets signed for a
|
|
15
|
+
* plugin (name, version, capabilities, provides, ...), not just its name: a
|
|
16
|
+
* signature that only covered the name would prove authorship of a label,
|
|
17
|
+
* not of what the plugin is declared to do.
|
|
18
|
+
*
|
|
19
|
+
* Deliberately scoped to the manifest, not the plugin's full package
|
|
20
|
+
* contents (its actual runtime code): `loadPlugin` (task 2) only ever reads
|
|
21
|
+
* the manifest-declaring module today — no mechanism yet reads a plugin's
|
|
22
|
+
* entry-point code into a string a signature could cover, so extending
|
|
23
|
+
* coverage to the full package is a real, separate piece of work for
|
|
24
|
+
* whichever future task builds that code-reading path.
|
|
25
|
+
*/
|
|
26
|
+
export function canonicalizeManifest(manifest) {
|
|
27
|
+
return canonicalizeContent(manifest);
|
|
28
|
+
}
|
|
29
|
+
function sortKeysDeep(value) {
|
|
30
|
+
if (Array.isArray(value))
|
|
31
|
+
return value.map(sortKeysDeep);
|
|
32
|
+
if (value !== null && typeof value === 'object') {
|
|
33
|
+
const sorted = {};
|
|
34
|
+
for (const key of Object.keys(value).sort()) {
|
|
35
|
+
sorted[key] = sortKeysDeep(value[key]);
|
|
36
|
+
}
|
|
37
|
+
return sorted;
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Signs any canonicalizable content with a real Ed25519 private key (base64
|
|
43
|
+
* PKCS8, `./keys.js`). The publisher-side half of this primitive — a real
|
|
44
|
+
* Cogenta installation never runs this, only the verification half
|
|
45
|
+
* (`./verify.js`) matters there, but both sides must be real for the
|
|
46
|
+
* primitive to be provably correct rather than assumed.
|
|
47
|
+
*/
|
|
48
|
+
export function signContent(content, privateKeyBase64) {
|
|
49
|
+
const privateKey = createPrivateKey({
|
|
50
|
+
key: Buffer.from(privateKeyBase64, 'base64'),
|
|
51
|
+
format: 'der',
|
|
52
|
+
type: 'pkcs8',
|
|
53
|
+
});
|
|
54
|
+
const data = Buffer.from(canonicalizeContent(content), 'utf8');
|
|
55
|
+
// Ed25519 has no separate digest step — `null` is the documented algorithm
|
|
56
|
+
// argument `crypto.sign` expects for it.
|
|
57
|
+
return cryptoSign(null, data, privateKey).toString('base64');
|
|
58
|
+
}
|
|
59
|
+
/** Signs a plugin manifest — the task-9 entry point, now a thin wrapper over `signContent`. */
|
|
60
|
+
export function signManifest(manifest, privateKeyBase64) {
|
|
61
|
+
return signContent(manifest, privateKeyBase64);
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=sign.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign.js","sourceRoot":"","sources":["../../src/signing/sign.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,aAAa,CAAA;AAGlE;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAA;AAC5C,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAwB;IAC3D,OAAO,mBAAmB,CAAC,QAAQ,CAAC,CAAA;AACtC,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;IACxD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,MAAM,GAA4B,EAAE,CAAA;QAC1C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAgC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACvE,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,CAAE,KAAiC,CAAC,GAAG,CAAC,CAAC,CAAA;QACrE,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,OAAgB,EAAE,gBAAwB;IACpE,MAAM,UAAU,GAAG,gBAAgB,CAAC;QAClC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC;QAC5C,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,OAAO;KACd,CAAC,CAAA;IACF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAA;IAC9D,2EAA2E;IAC3E,yCAAyC;IACzC,OAAO,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;AAC9D,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,YAAY,CAAC,QAAwB,EAAE,gBAAwB;IAC7E,OAAO,WAAW,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAA;AAChD,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { PluginManifest } from '../manifest.js';
|
|
2
|
+
/**
|
|
3
|
+
* Public keys of registries this installation trusts. Empty: no real
|
|
4
|
+
* plugin registry exists anywhere yet (this whole lot is pre-alpha,
|
|
5
|
+
* `loadPlugin`'s own `engineVersion` default documents the same honest
|
|
6
|
+
* gap). An empty list is the correct, honest default — every `registry`
|
|
7
|
+
* -source plugin fails verification until a real registry key is added
|
|
8
|
+
* here or passed explicitly via `LoadPluginOptions.trustedPublicKeys` —
|
|
9
|
+
* never a placeholder key that would make verification silently vacuous.
|
|
10
|
+
*/
|
|
11
|
+
export declare const TRUSTED_REGISTRY_PUBLIC_KEYS: readonly string[];
|
|
12
|
+
/**
|
|
13
|
+
* Verifies a base64 Ed25519 signature against any canonicalizable content
|
|
14
|
+
* and a base64 SPKI public key. Real, standard verification —
|
|
15
|
+
* `crypto.verify` returns `false` on any mismatch (wrong key, tampered
|
|
16
|
+
* content, malformed signature bytes) rather than throwing, except for a
|
|
17
|
+
* structurally invalid key/signature, which this function treats the same
|
|
18
|
+
* way: not verified, never an uncaught exception.
|
|
19
|
+
*/
|
|
20
|
+
export declare function verifyContentSignature(content: unknown, signatureBase64: string, publicKeyBase64: string): boolean;
|
|
21
|
+
/** Verifies a plugin manifest's signature — the task-9 entry point, now a thin wrapper. */
|
|
22
|
+
export declare function verifyManifestSignature(manifest: PluginManifest, signatureBase64: string, publicKeyBase64: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* A signature verifies if it matches ANY trusted key — one registry
|
|
25
|
+
* operator's key rotation, or several trusted registries, both work without
|
|
26
|
+
* this function's caller needing to know which key actually signed.
|
|
27
|
+
*/
|
|
28
|
+
export declare function verifyContentAgainstTrustedKeys(content: unknown, signatureBase64: string | null, trustedPublicKeys: readonly string[]): boolean;
|
|
29
|
+
/** Verifies a plugin manifest against trusted keys — the task-9 entry point, now a thin wrapper. */
|
|
30
|
+
export declare function verifyPluginSignature(manifest: PluginManifest, signatureBase64: string | null, trustedPublicKeys: readonly string[]): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* A signature travels as a sibling file next to the manifest
|
|
33
|
+
* (`plugin.manifest.mjs.sig`), a single base64 line — never embedded in the
|
|
34
|
+
* manifest object itself, so signing never changes the manifest's own
|
|
35
|
+
* shape (the lot doc's literal `definePlugin({...})` example carries no
|
|
36
|
+
* signature field, and it shouldn't need one: the manifest is signed, not
|
|
37
|
+
* self-describing its own signature).
|
|
38
|
+
*/
|
|
39
|
+
export declare function readSignatureFile(manifestPath: string): Promise<string | null>;
|
|
40
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/signing/verify.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAGpD;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,EAAE,SAAS,MAAM,EAAO,CAAA;AAEjE;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,GACtB,OAAO,CAaT;AAED,2FAA2F;AAC3F,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,cAAc,EACxB,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,GACtB,OAAO,CAET;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,iBAAiB,EAAE,SAAS,MAAM,EAAE,GACnC,OAAO,CAGT;AAED,oGAAoG;AACpG,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,cAAc,EACxB,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,iBAAiB,EAAE,SAAS,MAAM,EAAE,GACnC,OAAO,CAET;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQpF"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { createPublicKey, verify as cryptoVerify } from 'node:crypto';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { canonicalizeContent } from './sign.js';
|
|
4
|
+
/**
|
|
5
|
+
* Public keys of registries this installation trusts. Empty: no real
|
|
6
|
+
* plugin registry exists anywhere yet (this whole lot is pre-alpha,
|
|
7
|
+
* `loadPlugin`'s own `engineVersion` default documents the same honest
|
|
8
|
+
* gap). An empty list is the correct, honest default — every `registry`
|
|
9
|
+
* -source plugin fails verification until a real registry key is added
|
|
10
|
+
* here or passed explicitly via `LoadPluginOptions.trustedPublicKeys` —
|
|
11
|
+
* never a placeholder key that would make verification silently vacuous.
|
|
12
|
+
*/
|
|
13
|
+
export const TRUSTED_REGISTRY_PUBLIC_KEYS = [];
|
|
14
|
+
/**
|
|
15
|
+
* Verifies a base64 Ed25519 signature against any canonicalizable content
|
|
16
|
+
* and a base64 SPKI public key. Real, standard verification —
|
|
17
|
+
* `crypto.verify` returns `false` on any mismatch (wrong key, tampered
|
|
18
|
+
* content, malformed signature bytes) rather than throwing, except for a
|
|
19
|
+
* structurally invalid key/signature, which this function treats the same
|
|
20
|
+
* way: not verified, never an uncaught exception.
|
|
21
|
+
*/
|
|
22
|
+
export function verifyContentSignature(content, signatureBase64, publicKeyBase64) {
|
|
23
|
+
try {
|
|
24
|
+
const publicKey = createPublicKey({
|
|
25
|
+
key: Buffer.from(publicKeyBase64, 'base64'),
|
|
26
|
+
format: 'der',
|
|
27
|
+
type: 'spki',
|
|
28
|
+
});
|
|
29
|
+
const data = Buffer.from(canonicalizeContent(content), 'utf8');
|
|
30
|
+
const signature = Buffer.from(signatureBase64, 'base64');
|
|
31
|
+
return cryptoVerify(null, data, publicKey, signature);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Verifies a plugin manifest's signature — the task-9 entry point, now a thin wrapper. */
|
|
38
|
+
export function verifyManifestSignature(manifest, signatureBase64, publicKeyBase64) {
|
|
39
|
+
return verifyContentSignature(manifest, signatureBase64, publicKeyBase64);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A signature verifies if it matches ANY trusted key — one registry
|
|
43
|
+
* operator's key rotation, or several trusted registries, both work without
|
|
44
|
+
* this function's caller needing to know which key actually signed.
|
|
45
|
+
*/
|
|
46
|
+
export function verifyContentAgainstTrustedKeys(content, signatureBase64, trustedPublicKeys) {
|
|
47
|
+
if (signatureBase64 === null)
|
|
48
|
+
return false;
|
|
49
|
+
return trustedPublicKeys.some((key) => verifyContentSignature(content, signatureBase64, key));
|
|
50
|
+
}
|
|
51
|
+
/** Verifies a plugin manifest against trusted keys — the task-9 entry point, now a thin wrapper. */
|
|
52
|
+
export function verifyPluginSignature(manifest, signatureBase64, trustedPublicKeys) {
|
|
53
|
+
return verifyContentAgainstTrustedKeys(manifest, signatureBase64, trustedPublicKeys);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A signature travels as a sibling file next to the manifest
|
|
57
|
+
* (`plugin.manifest.mjs.sig`), a single base64 line — never embedded in the
|
|
58
|
+
* manifest object itself, so signing never changes the manifest's own
|
|
59
|
+
* shape (the lot doc's literal `definePlugin({...})` example carries no
|
|
60
|
+
* signature field, and it shouldn't need one: the manifest is signed, not
|
|
61
|
+
* self-describing its own signature).
|
|
62
|
+
*/
|
|
63
|
+
export async function readSignatureFile(manifestPath) {
|
|
64
|
+
try {
|
|
65
|
+
const content = await readFile(`${manifestPath}.sig`, 'utf8');
|
|
66
|
+
const trimmed = content.trim();
|
|
67
|
+
return trimmed === '' ? null : trimmed;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/signing/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,aAAa,CAAA;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAE3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAE/C;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAsB,EAAE,CAAA;AAEjE;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAgB,EAChB,eAAuB,EACvB,eAAuB;IAEvB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,eAAe,CAAC;YAChC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC;YAC3C,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,MAAM;SACb,CAAC,CAAA;QACF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAA;QAC9D,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAA;QACxD,OAAO,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,uBAAuB,CACrC,QAAwB,EACxB,eAAuB,EACvB,eAAuB;IAEvB,OAAO,sBAAsB,CAAC,QAAQ,EAAE,eAAe,EAAE,eAAe,CAAC,CAAA;AAC3E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,+BAA+B,CAC7C,OAAgB,EAChB,eAA8B,EAC9B,iBAAoC;IAEpC,IAAI,eAAe,KAAK,IAAI;QAAE,OAAO,KAAK,CAAA;IAC1C,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,sBAAsB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,CAAC,CAAA;AAC/F,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,qBAAqB,CACnC,QAAwB,EACxB,eAA8B,EAC9B,iBAAoC;IAEpC,OAAO,+BAA+B,CAAC,QAAQ,EAAE,eAAe,EAAE,iBAAiB,CAAC,CAAA;AACtF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,YAAoB;IAC1D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,GAAG,YAAY,MAAM,EAAE,MAAM,CAAC,CAAA;QAC7D,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAA;QAC9B,OAAO,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAA;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cogenta/plugins",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Plugin manifest schema, loader, worker isolation and permission model.",
|
|
5
|
+
"license": "MPL-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=22.11.0"
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public",
|
|
22
|
+
"provenance": true
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/cogenta-cms/cogenta.git",
|
|
27
|
+
"directory": "packages/plugins"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc -p tsconfig.json && node -e \"const fs=require('node:fs');fs.mkdirSync('dist/guest',{recursive:true});fs.copyFileSync('src/guest/sandbox-entry.mjs','dist/guest/sandbox-entry.mjs')\"",
|
|
31
|
+
"typecheck": "tsc -p tsconfig.typecheck.json",
|
|
32
|
+
"test": "vitest run --passWithNoTests"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@cogenta/agents": "workspace:*",
|
|
36
|
+
"@cogenta/core": "workspace:*",
|
|
37
|
+
"@cogenta/render": "workspace:*",
|
|
38
|
+
"zod": "catalog:"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@cogenta/blocks": "workspace:*",
|
|
42
|
+
"@cogenta/schema": "workspace:*",
|
|
43
|
+
"typescript": "catalog:",
|
|
44
|
+
"vitest": "catalog:"
|
|
45
|
+
}
|
|
46
|
+
}
|