@synoikia/core 0.2.1-rc.0 → 0.4.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/LICENSE +1 -1
- package/dist/app.js +1 -4
- package/dist/app.js.map +1 -1
- package/dist/audit-query.d.ts +2 -1
- package/dist/audit-query.js +1 -1
- package/dist/audit-query.js.map +1 -1
- package/dist/auth/mcp-tokens.d.ts +0 -10
- package/dist/auth/mcp-tokens.js +1 -1
- package/dist/auth/mcp-tokens.js.map +1 -1
- package/dist/auth/oauth.d.ts +0 -17
- package/dist/auth/oauth.js +5 -12
- package/dist/auth/oauth.js.map +1 -1
- package/dist/auth/oidc.d.ts +2 -16
- package/dist/auth/oidc.js +3 -3
- package/dist/auth/oidc.js.map +1 -1
- package/dist/auth/users.d.ts +0 -1
- package/dist/auth/users.js +1 -1
- package/dist/auth/users.js.map +1 -1
- package/dist/catalog/groups.d.ts +14 -31
- package/dist/catalog/groups.js +56 -81
- package/dist/catalog/groups.js.map +1 -1
- package/dist/catalog/rules.d.ts +1 -1
- package/dist/catalog/rules.js +1 -1
- package/dist/catalog/rules.js.map +1 -1
- package/dist/catalog/sync.d.ts +6 -2
- package/dist/catalog/sync.js +33 -8
- package/dist/catalog/sync.js.map +1 -1
- package/dist/config/env.d.ts +0 -8
- package/dist/config/env.js +0 -2
- package/dist/config/env.js.map +1 -1
- package/dist/db/index.d.ts +0 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/schema.d.ts +19 -19
- package/dist/db/schema.js +3 -2
- package/dist/db/schema.js.map +1 -1
- package/dist/gate/access.d.ts +21 -10
- package/dist/gate/access.js +58 -26
- package/dist/gate/access.js.map +1 -1
- package/dist/gate/match.d.ts +0 -11
- package/dist/gate/match.js +1 -1
- package/dist/gate/match.js.map +1 -1
- package/dist/gate/pipeline.js +21 -12
- package/dist/gate/pipeline.js.map +1 -1
- package/dist/gate/redact.d.ts +22 -1
- package/dist/gate/redact.js +78 -2
- package/dist/gate/redact.js.map +1 -1
- package/dist/http/admin/auth.d.ts +0 -2
- package/dist/http/admin/auth.js +2 -2
- package/dist/http/admin/auth.js.map +1 -1
- package/dist/http/admin/instances.js +21 -14
- package/dist/http/admin/instances.js.map +1 -1
- package/dist/http/mcp/approval-routes.d.ts +0 -2
- package/dist/http/mcp/approval-routes.js +1 -1
- package/dist/http/mcp/approval-routes.js.map +1 -1
- package/dist/http/mcp/endpoint.d.ts +0 -4
- package/dist/http/mcp/endpoint.js +3 -3
- package/dist/http/mcp/endpoint.js.map +1 -1
- package/dist/http/mcp/oauth-routes.d.ts +1 -6
- package/dist/http/mcp/oauth-routes.js +3 -3
- package/dist/http/mcp/oauth-routes.js.map +1 -1
- package/dist/http/mcp/pages.d.ts +0 -8
- package/dist/http/mcp/pages.js +1 -1
- package/dist/http/mcp/pages.js.map +1 -1
- package/dist/instances/connection.d.ts +0 -2
- package/dist/instances/connection.js +1 -1
- package/dist/instances/connection.js.map +1 -1
- package/dist/lock.d.ts +0 -12
- package/dist/lock.js +1 -1
- package/dist/lock.js.map +1 -1
- package/dist/main.js +4 -0
- package/dist/main.js.map +1 -1
- package/dist/notify/service.d.ts +2 -43
- package/dist/notify/service.js +2 -2
- package/dist/notify/service.js.map +1 -1
- package/dist/plugins/default-repo.d.ts +9 -0
- package/dist/plugins/default-repo.js +10 -0
- package/dist/plugins/default-repo.js.map +1 -0
- package/dist/plugins/discovery.d.ts +8 -17
- package/dist/plugins/discovery.js +19 -51
- package/dist/plugins/discovery.js.map +1 -1
- package/dist/plugins/process.js +4 -1
- package/dist/plugins/process.js.map +1 -1
- package/dist/plugins/repos.d.ts +33 -16
- package/dist/plugins/repos.js +67 -26
- package/dist/plugins/repos.js.map +1 -1
- package/dist/sandbox/index.d.ts +0 -1
- package/dist/sandbox/index.js +1 -1
- package/dist/sandbox/index.js.map +1 -1
- package/dist/settings.d.ts +2 -1
- package/dist/settings.js +1 -1
- package/dist/settings.js.map +1 -1
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +10 -19
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/repository.d.ts +21 -0
- package/dist/testing/repository.js +96 -0
- package/dist/testing/repository.js.map +1 -0
- package/drizzle/0009_drop_plugin_source.sql +1 -0
- package/drizzle/0010_access_by_kind.sql +35 -0
- package/drizzle/0011_sensitive_params.sql +1 -0
- package/drizzle/meta/0009_snapshot.json +2347 -0
- package/drizzle/meta/0010_snapshot.json +2347 -0
- package/drizzle/meta/0011_snapshot.json +2354 -0
- package/drizzle/meta/_journal.json +21 -0
- package/package.json +2 -2
|
@@ -1,35 +1,26 @@
|
|
|
1
1
|
import type { Manifest } from '@synoikia/plugin-sdk';
|
|
2
2
|
import type { Db } from '../db/index.js';
|
|
3
|
-
/** Plugin discovery (design §4.1):
|
|
4
|
-
export type PluginSource = 'core' | 'repo';
|
|
3
|
+
/** Plugin discovery (design §4.1): the plugins installed in `DATA_DIR/plugins`. */
|
|
5
4
|
export type DiscoveredPlugin = {
|
|
6
5
|
status: 'ok';
|
|
7
|
-
source: PluginSource;
|
|
8
6
|
dir: string;
|
|
9
7
|
manifest: Manifest;
|
|
10
8
|
} | {
|
|
11
9
|
status: 'invalid' | 'incompatible';
|
|
12
|
-
source: PluginSource;
|
|
13
10
|
dir: string;
|
|
14
11
|
manifest?: Manifest;
|
|
15
12
|
pluginId: string;
|
|
16
13
|
error: string;
|
|
17
14
|
};
|
|
18
|
-
export declare function inspectPluginDir(dir: string
|
|
19
|
-
/** Scans
|
|
20
|
-
export declare function discoverPlugins(
|
|
21
|
-
dir: string;
|
|
22
|
-
source: PluginSource;
|
|
23
|
-
}[]): DiscoveredPlugin[];
|
|
24
|
-
export declare const pluginIdOf: (p: DiscoveredPlugin) => string;
|
|
15
|
+
export declare function inspectPluginDir(dir: string): DiscoveredPlugin;
|
|
16
|
+
/** Scans the plugins directory's immediate subdirectories that contain a manifest.json. */
|
|
17
|
+
export declare function discoverPlugins(root: string): DiscoveredPlugin[];
|
|
25
18
|
/**
|
|
26
|
-
* Upserts discovery results into `plugins`. New
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* never deleted, so their instances and history remain.
|
|
19
|
+
* Upserts discovery results into `plugins`. New plugins start disabled: enabling one is the admin's
|
|
20
|
+
* review of what it may do (design §4.2). Two directories declaring the same id keep only the first.
|
|
21
|
+
* Plugins no longer on disk are marked invalid, never deleted, so their instances and history remain.
|
|
30
22
|
*/
|
|
31
|
-
export declare function syncPluginRegistry(db: Db, discovered: DiscoveredPlugin[], opts
|
|
32
|
-
autoEnableCore: boolean;
|
|
23
|
+
export declare function syncPluginRegistry(db: Db, discovered: DiscoveredPlugin[], opts?: {
|
|
33
24
|
now?: Date;
|
|
34
25
|
}): {
|
|
35
26
|
added: string[];
|
|
@@ -11,20 +11,19 @@ function explain(err) {
|
|
|
11
11
|
return err.issues.map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`).join('; ');
|
|
12
12
|
return err instanceof Error ? err.message : String(err);
|
|
13
13
|
}
|
|
14
|
-
export function inspectPluginDir(dir
|
|
14
|
+
export function inspectPluginDir(dir) {
|
|
15
15
|
const fallbackId = path.basename(dir);
|
|
16
16
|
let manifest;
|
|
17
17
|
try {
|
|
18
18
|
manifest = parseManifest(JSON.parse(readFileSync(path.join(dir, 'manifest.json'), 'utf8')));
|
|
19
19
|
}
|
|
20
20
|
catch (err) {
|
|
21
|
-
return { status: 'invalid',
|
|
21
|
+
return { status: 'invalid', dir, pluginId: fallbackId, error: `manifest.json: ${explain(err)}` };
|
|
22
22
|
}
|
|
23
23
|
const entry = path.join(dir, manifest.entry);
|
|
24
24
|
if (!existsSync(entry)) {
|
|
25
25
|
return {
|
|
26
26
|
status: 'invalid',
|
|
27
|
-
source,
|
|
28
27
|
dir,
|
|
29
28
|
manifest,
|
|
30
29
|
pluginId: manifest.id,
|
|
@@ -36,7 +35,6 @@ export function inspectPluginDir(dir, source) {
|
|
|
36
35
|
if (!realpathSync(entry).startsWith(realDir + path.sep)) {
|
|
37
36
|
return {
|
|
38
37
|
status: 'invalid',
|
|
39
|
-
source,
|
|
40
38
|
dir,
|
|
41
39
|
manifest,
|
|
42
40
|
pluginId: manifest.id,
|
|
@@ -46,41 +44,33 @@ export function inspectPluginDir(dir, source) {
|
|
|
46
44
|
if (!isSdkCompatible(manifest)) {
|
|
47
45
|
return {
|
|
48
46
|
status: 'incompatible',
|
|
49
|
-
source,
|
|
50
47
|
dir,
|
|
51
48
|
manifest,
|
|
52
49
|
pluginId: manifest.id,
|
|
53
50
|
error: `requires plugin SDK ${manifest.sdk}; core implements ${SDK_VERSION}`,
|
|
54
51
|
};
|
|
55
52
|
}
|
|
56
|
-
return { status: 'ok',
|
|
53
|
+
return { status: 'ok', dir, manifest };
|
|
57
54
|
}
|
|
58
|
-
/** Scans
|
|
59
|
-
export function discoverPlugins(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
found.push(inspectPluginDir(dir, root.source));
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return found;
|
|
55
|
+
/** Scans the plugins directory's immediate subdirectories that contain a manifest.json. */
|
|
56
|
+
export function discoverPlugins(root) {
|
|
57
|
+
if (!existsSync(root))
|
|
58
|
+
return [];
|
|
59
|
+
return readdirSync(root)
|
|
60
|
+
.sort()
|
|
61
|
+
.map((name) => path.join(root, name))
|
|
62
|
+
.filter((dir) => statSync(dir).isDirectory() && existsSync(path.join(dir, 'manifest.json')))
|
|
63
|
+
.map((dir) => inspectPluginDir(dir));
|
|
72
64
|
}
|
|
73
|
-
|
|
65
|
+
const pluginIdOf = (p) => (p.status === 'ok' ? p.manifest.id : p.pluginId);
|
|
74
66
|
/**
|
|
75
|
-
* Upserts discovery results into `plugins`. New
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* never deleted, so their instances and history remain.
|
|
67
|
+
* Upserts discovery results into `plugins`. New plugins start disabled: enabling one is the admin's
|
|
68
|
+
* review of what it may do (design §4.2). Two directories declaring the same id keep only the first.
|
|
69
|
+
* Plugins no longer on disk are marked invalid, never deleted, so their instances and history remain.
|
|
79
70
|
*/
|
|
80
|
-
export function syncPluginRegistry(db, discovered, opts) {
|
|
71
|
+
export function syncPluginRegistry(db, discovered, opts = {}) {
|
|
81
72
|
const now = opts.now ?? new Date();
|
|
82
73
|
const out = { added: [], updated: [], missing: [], rejected: [] };
|
|
83
|
-
const coreIds = new Set(discovered.filter((p) => p.source === 'core').map(pluginIdOf));
|
|
84
74
|
db.transaction((tx) => {
|
|
85
75
|
const existing = new Map(tx
|
|
86
76
|
.select()
|
|
@@ -90,10 +80,6 @@ export function syncPluginRegistry(db, discovered, opts) {
|
|
|
90
80
|
const seen = new Set();
|
|
91
81
|
for (const p of discovered) {
|
|
92
82
|
const pluginId = pluginIdOf(p);
|
|
93
|
-
if (p.source === 'repo' && coreIds.has(pluginId)) {
|
|
94
|
-
out.rejected.push(pluginId);
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
83
|
if (seen.has(pluginId)) {
|
|
98
84
|
out.rejected.push(pluginId);
|
|
99
85
|
continue;
|
|
@@ -101,40 +87,22 @@ export function syncPluginRegistry(db, discovered, opts) {
|
|
|
101
87
|
seen.add(pluginId);
|
|
102
88
|
const fields = {
|
|
103
89
|
version: p.manifest?.version ?? '0.0.0',
|
|
104
|
-
source: p.source,
|
|
105
90
|
path: p.dir,
|
|
106
91
|
manifest: p.manifest ?? {},
|
|
107
92
|
status: p.status,
|
|
108
93
|
statusError: p.status === 'ok' ? null : p.error,
|
|
109
94
|
};
|
|
110
95
|
const prev = existing.get(pluginId);
|
|
111
|
-
if (prev?.source === 'repo' && p.source === 'core') {
|
|
112
|
-
// A core release now ships this id. Its instances must not silently switch to different code
|
|
113
|
-
// with the same secrets: the repo row stays as it was, unusable, until an admin resolves it.
|
|
114
|
-
const statusError = `A core plugin now uses the id "${pluginId}". Uninstall this repository plugin (after moving its endpoints) to use the core one.`;
|
|
115
|
-
if (prev.status !== 'invalid' || prev.statusError !== statusError) {
|
|
116
|
-
tx.update(plugins).set({ status: 'invalid', statusError }).where(eq(plugins.id, prev.id)).run();
|
|
117
|
-
writeAudit(tx, {
|
|
118
|
-
kind: 'plugin',
|
|
119
|
-
decision: 'plugin_id_conflict',
|
|
120
|
-
actorKind: 'system',
|
|
121
|
-
detail: { pluginId, repoVersion: prev.version, coreVersion: fields.version },
|
|
122
|
-
}, now);
|
|
123
|
-
}
|
|
124
|
-
out.rejected.push(pluginId);
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
96
|
if (!prev) {
|
|
128
|
-
const enabled = p.status === 'ok' && p.source === 'core' && opts.autoEnableCore;
|
|
129
97
|
tx.insert(plugins)
|
|
130
|
-
.values({ id: randomUUID(), pluginId, ...fields, enabled, installedAt: now })
|
|
98
|
+
.values({ id: randomUUID(), pluginId, ...fields, enabled: false, installedAt: now })
|
|
131
99
|
.run();
|
|
132
100
|
out.added.push(pluginId);
|
|
133
101
|
writeAudit(tx, {
|
|
134
102
|
kind: 'plugin',
|
|
135
103
|
decision: 'plugin_discovered',
|
|
136
104
|
actorKind: 'system',
|
|
137
|
-
detail: { pluginId, ...fields, manifest: undefined, enabled },
|
|
105
|
+
detail: { pluginId, ...fields, manifest: undefined, enabled: false },
|
|
138
106
|
}, now);
|
|
139
107
|
}
|
|
140
108
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/plugins/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnF,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/plugins/discovery.ts"],"names":[],"mappings":"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"}
|
package/dist/plugins/process.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { fork } from 'node:child_process';
|
|
2
2
|
import { EventEmitter } from 'node:events';
|
|
3
|
+
import { realpathSync } from 'node:fs';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
import { GuideSchema, OptionSchema, PrepareWriteResultSchema, RegistryEntrySchema, ResolvedTargetSchema, ResolveOperationResultSchema, SummarizeResultSchema, SyncCatalogResultSchema, TestConnectionResultSchema, } from '@synoikia/plugin-sdk';
|
|
5
6
|
import { z } from 'zod';
|
|
@@ -73,7 +74,9 @@ export class PluginProcess extends EventEmitter {
|
|
|
73
74
|
start() {
|
|
74
75
|
if (this.child)
|
|
75
76
|
throw new Error('Plugin process already started');
|
|
76
|
-
|
|
77
|
+
// The permission model checks real paths, but the grant is taken literally: through a symlinked dir (macOS's
|
|
78
|
+
// /var -> /private/var tmpdir, a symlinked DATA_DIR) the child could not even load its own entry.
|
|
79
|
+
const dir = realpathSync(path.resolve(this.opts.dir));
|
|
77
80
|
this.child = fork(path.resolve(dir, this.opts.entry), [], {
|
|
78
81
|
cwd: dir,
|
|
79
82
|
execArgv: ['--permission', `--allow-fs-read=${dir}`, `--max-old-space-size=${this.opts.memoryMb ?? 256}`],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process.js","sourceRoot":"","sources":["../../src/plugins/process.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"process.js","sourceRoot":"","sources":["../../src/plugins/process.ts"],"names":[],"mappings":"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"}
|
package/dist/plugins/repos.d.ts
CHANGED
|
@@ -20,14 +20,6 @@ export declare const IndexSchema: z.ZodObject<{
|
|
|
20
20
|
}, z.core.$strip>>;
|
|
21
21
|
}, z.core.$strip>;
|
|
22
22
|
export type RepoIndex = z.infer<typeof IndexSchema>;
|
|
23
|
-
export declare const AddRepoSchema: z.ZodObject<{
|
|
24
|
-
url: z.ZodURL;
|
|
25
|
-
signingMode: z.ZodEnum<{
|
|
26
|
-
signed: "signed";
|
|
27
|
-
unsigned: "unsigned";
|
|
28
|
-
}>;
|
|
29
|
-
confirmPublicKey: z.ZodOptional<z.ZodString>;
|
|
30
|
-
}, z.core.$strip>;
|
|
31
23
|
export declare const InstallSchema: z.ZodObject<{
|
|
32
24
|
repoId: z.ZodString;
|
|
33
25
|
pluginId: z.ZodString;
|
|
@@ -55,8 +47,6 @@ export interface RepoServiceOptions {
|
|
|
55
47
|
/** Start (and resync) every servable instance of a plugin row. */
|
|
56
48
|
startPlugin: (pluginRowId: string) => Promise<void>;
|
|
57
49
|
}
|
|
58
|
-
/** The parts of a manifest that change what a plugin may do; an update touching them needs review. */
|
|
59
|
-
export declare function permissionChanges(before: unknown, after: unknown): string[];
|
|
60
50
|
/**
|
|
61
51
|
* Replaces `target` with `next`, keeping the previous copy at `backup` until the swap succeeded. If
|
|
62
52
|
* moving `next` in fails, the previous copy is moved back, so a failed update never leaves no plugin.
|
|
@@ -92,8 +82,8 @@ export declare class PluginRepoService {
|
|
|
92
82
|
lastFetchError: string | null;
|
|
93
83
|
}[];
|
|
94
84
|
/**
|
|
95
|
-
* Adds a repository. Signed repos take two calls: the first answers 409 `confirm_key` with the
|
|
96
|
-
*
|
|
85
|
+
* Adds a repository. Signed repos take two calls: the first answers 409 `confirm_key` with the
|
|
86
|
+
* public key, the second repeats the request with `confirmPublicKey` once the admin has checked it out of band.
|
|
97
87
|
*/
|
|
98
88
|
add(raw: unknown, actor?: Actor): Promise<{
|
|
99
89
|
id: string;
|
|
@@ -112,6 +102,31 @@ export declare class PluginRepoService {
|
|
|
112
102
|
lastFetchedAt: Date | null;
|
|
113
103
|
lastFetchError: string | null;
|
|
114
104
|
}>;
|
|
105
|
+
/**
|
|
106
|
+
* Adds a signed repository whose key ships with core, without fetching its index (the next refresh
|
|
107
|
+
* does). Runs once per `marker`: a repo the admin removed stays removed.
|
|
108
|
+
*/
|
|
109
|
+
addPreconfigured(repo: {
|
|
110
|
+
url: string;
|
|
111
|
+
name: string;
|
|
112
|
+
publicKey: string;
|
|
113
|
+
}, marker?: string): {
|
|
114
|
+
id: string;
|
|
115
|
+
url: string;
|
|
116
|
+
name: string | null;
|
|
117
|
+
signingMode: "signed" | "unsigned";
|
|
118
|
+
publicKey: string | null;
|
|
119
|
+
keyId: string | null;
|
|
120
|
+
keyStatus: "ok" | "key_changed";
|
|
121
|
+
/** When the key changed: the new key awaiting confirmation. */
|
|
122
|
+
offeredKey: {
|
|
123
|
+
publicKey: string;
|
|
124
|
+
keyId: string;
|
|
125
|
+
} | null;
|
|
126
|
+
pluginCount: number;
|
|
127
|
+
lastFetchedAt: Date | null;
|
|
128
|
+
lastFetchError: string | null;
|
|
129
|
+
} | null;
|
|
115
130
|
/** Re-reads the index. A changed signing key blocks installs until re-confirmed. */
|
|
116
131
|
refresh(id: string): Promise<{
|
|
117
132
|
id: string;
|
|
@@ -130,7 +145,10 @@ export declare class PluginRepoService {
|
|
|
130
145
|
lastFetchedAt: Date | null;
|
|
131
146
|
lastFetchError: string | null;
|
|
132
147
|
}>;
|
|
133
|
-
/**
|
|
148
|
+
/**
|
|
149
|
+
* Daily refresh (design §10). A repo whose last fetch failed is retried on every call (hourly), so a
|
|
150
|
+
* start-up network hiccup doesn't leave it empty for a day. Failures are recorded on the row, never thrown.
|
|
151
|
+
*/
|
|
134
152
|
refreshStale(maxAgeMs?: number): Promise<void>;
|
|
135
153
|
/** Pins the key a refreshed index now offers, after the admin checked it against the publisher's. */
|
|
136
154
|
confirmKey(id: string, publicKey: string, actor?: Actor): {
|
|
@@ -167,7 +185,7 @@ export declare class PluginRepoService {
|
|
|
167
185
|
installed: {
|
|
168
186
|
version: string;
|
|
169
187
|
fromThisRepo: boolean;
|
|
170
|
-
|
|
188
|
+
managed: boolean;
|
|
171
189
|
} | null;
|
|
172
190
|
updateAvailable: boolean;
|
|
173
191
|
blocked: string | null;
|
|
@@ -180,7 +198,6 @@ export declare class PluginRepoService {
|
|
|
180
198
|
id: string;
|
|
181
199
|
pluginId: string;
|
|
182
200
|
version: string;
|
|
183
|
-
source: "core" | "repo";
|
|
184
201
|
repoId: string | null;
|
|
185
202
|
path: string;
|
|
186
203
|
sha256: string | null;
|
|
@@ -192,7 +209,7 @@ export declare class PluginRepoService {
|
|
|
192
209
|
installedAt: Date;
|
|
193
210
|
}>;
|
|
194
211
|
private installLocked;
|
|
195
|
-
/** Removes an installed
|
|
212
|
+
/** Removes an installed plugin. Blocked while any instance uses it. */
|
|
196
213
|
uninstall(pluginRowOrId: string, actor?: Actor): void;
|
|
197
214
|
}
|
|
198
215
|
export {};
|
package/dist/plugins/repos.js
CHANGED
|
@@ -9,7 +9,7 @@ import semver from 'semver';
|
|
|
9
9
|
import * as tar from 'tar';
|
|
10
10
|
import { z } from 'zod';
|
|
11
11
|
import { writeAudit } from '../audit.js';
|
|
12
|
-
import { pluginInstances, pluginRepos, plugins } from '../db/schema.js';
|
|
12
|
+
import { pluginInstances, pluginRepos, plugins, settings } from '../db/schema.js';
|
|
13
13
|
import { ConflictError, NotFoundError, ServiceError, ValidationError } from '../errors.js';
|
|
14
14
|
import { CORE_VERSION } from '../version.js';
|
|
15
15
|
import { inspectPluginDir } from './discovery.js';
|
|
@@ -47,7 +47,7 @@ export const IndexSchema = z.object({
|
|
|
47
47
|
}))
|
|
48
48
|
.max(500),
|
|
49
49
|
});
|
|
50
|
-
|
|
50
|
+
const AddRepoSchema = z.object({
|
|
51
51
|
url: z.url(),
|
|
52
52
|
signingMode: z.enum(['signed', 'unsigned']),
|
|
53
53
|
/**
|
|
@@ -64,8 +64,10 @@ export const InstallSchema = z.object({
|
|
|
64
64
|
confirm: z.string().optional(),
|
|
65
65
|
});
|
|
66
66
|
const MAX_REDIRECTS = 5;
|
|
67
|
+
/** `settings` row recording that the pre-configured repository was added once. */
|
|
68
|
+
const DEFAULT_REPO_MARKER = 'plugin_repos.preconfigured';
|
|
67
69
|
/** The parts of a manifest that change what a plugin may do; an update touching them needs review. */
|
|
68
|
-
|
|
70
|
+
function permissionChanges(before, after) {
|
|
69
71
|
const b = (before ?? {});
|
|
70
72
|
const a = (after ?? {});
|
|
71
73
|
const pick = {
|
|
@@ -220,8 +222,8 @@ export class PluginRepoService {
|
|
|
220
222
|
.map((r) => this.publicRepo(r));
|
|
221
223
|
}
|
|
222
224
|
/**
|
|
223
|
-
* Adds a repository. Signed repos take two calls: the first answers 409 `confirm_key` with the
|
|
224
|
-
*
|
|
225
|
+
* Adds a repository. Signed repos take two calls: the first answers 409 `confirm_key` with the
|
|
226
|
+
* public key, the second repeats the request with `confirmPublicKey` once the admin has checked it out of band.
|
|
225
227
|
*/
|
|
226
228
|
async add(raw, actor = {}) {
|
|
227
229
|
const input = AddRepoSchema.parse(raw);
|
|
@@ -266,6 +268,43 @@ export class PluginRepoService {
|
|
|
266
268
|
});
|
|
267
269
|
return this.publicRepo(this.repoRow(id));
|
|
268
270
|
}
|
|
271
|
+
/**
|
|
272
|
+
* Adds a signed repository whose key ships with core, without fetching its index (the next refresh
|
|
273
|
+
* does). Runs once per `marker`: a repo the admin removed stays removed.
|
|
274
|
+
*/
|
|
275
|
+
addPreconfigured(repo, marker = DEFAULT_REPO_MARKER) {
|
|
276
|
+
if (this.db.select().from(settings).where(eq(settings.key, marker)).get())
|
|
277
|
+
return null;
|
|
278
|
+
const url = this.checkUrl(repo.url);
|
|
279
|
+
const key = parsePublicKey(repo.publicKey);
|
|
280
|
+
const exists = this.db.select().from(pluginRepos).where(eq(pluginRepos.url, url)).get();
|
|
281
|
+
const id = randomUUID();
|
|
282
|
+
this.db.transaction((tx) => {
|
|
283
|
+
tx.insert(settings)
|
|
284
|
+
.values({ key: marker, value: { url, addedAt: this.now().toISOString() } })
|
|
285
|
+
.run();
|
|
286
|
+
if (exists)
|
|
287
|
+
return;
|
|
288
|
+
tx.insert(pluginRepos)
|
|
289
|
+
.values({
|
|
290
|
+
id,
|
|
291
|
+
url,
|
|
292
|
+
name: repo.name,
|
|
293
|
+
signingMode: 'signed',
|
|
294
|
+
publicKey: key.base64,
|
|
295
|
+
keyFingerprint: key.keyId,
|
|
296
|
+
keyStatus: 'ok',
|
|
297
|
+
})
|
|
298
|
+
.run();
|
|
299
|
+
writeAudit(tx, {
|
|
300
|
+
kind: 'config',
|
|
301
|
+
decision: 'plugin_repo_added',
|
|
302
|
+
actorKind: 'system',
|
|
303
|
+
detail: { id, url, name: repo.name, signingMode: 'signed', keyId: key.keyId, preconfigured: true },
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
return exists ? null : this.publicRepo(this.repoRow(id));
|
|
307
|
+
}
|
|
269
308
|
/** Re-reads the index. A changed signing key blocks installs until re-confirmed. */
|
|
270
309
|
async refresh(id) {
|
|
271
310
|
const row = this.repoRow(id);
|
|
@@ -306,10 +345,14 @@ export class PluginRepoService {
|
|
|
306
345
|
}
|
|
307
346
|
return this.publicRepo(this.repoRow(id));
|
|
308
347
|
}
|
|
309
|
-
/**
|
|
348
|
+
/**
|
|
349
|
+
* Daily refresh (design §10). A repo whose last fetch failed is retried on every call (hourly), so a
|
|
350
|
+
* start-up network hiccup doesn't leave it empty for a day. Failures are recorded on the row, never thrown.
|
|
351
|
+
*/
|
|
310
352
|
async refreshStale(maxAgeMs = 24 * 60 * 60_000) {
|
|
311
353
|
for (const row of this.db.select().from(pluginRepos).all()) {
|
|
312
|
-
|
|
354
|
+
const fresh = row.lastFetchedAt && this.now().getTime() - row.lastFetchedAt.getTime() < maxAgeMs;
|
|
355
|
+
if (fresh && !row.lastFetchError)
|
|
313
356
|
continue;
|
|
314
357
|
await this.refresh(row.id).catch(() => undefined);
|
|
315
358
|
}
|
|
@@ -377,7 +420,7 @@ export class PluginRepoService {
|
|
|
377
420
|
.map((v) => v.version);
|
|
378
421
|
const latest = semver.rsort([...compatible])[0] ?? null;
|
|
379
422
|
const current = installed.get(p.id);
|
|
380
|
-
const fromHere = current
|
|
423
|
+
const fromHere = !!current && current.repoId === repo.id;
|
|
381
424
|
out.push({
|
|
382
425
|
repoId: repo.id,
|
|
383
426
|
repoName: repo.name,
|
|
@@ -387,15 +430,13 @@ export class PluginRepoService {
|
|
|
387
430
|
description: p.description ?? null,
|
|
388
431
|
versions: p.versions.map((v) => ({ version: v.version, compatible: compatible.includes(v.version) })),
|
|
389
432
|
latest,
|
|
390
|
-
installed: current ? { version: current.version, fromThisRepo: fromHere,
|
|
433
|
+
installed: current ? { version: current.version, fromThisRepo: fromHere, managed: !!current.repoId } : null,
|
|
391
434
|
updateAvailable: !!(fromHere && latest && semver.gt(latest, current.version)),
|
|
392
|
-
blocked: current?.
|
|
393
|
-
? '
|
|
394
|
-
:
|
|
395
|
-
? '
|
|
396
|
-
:
|
|
397
|
-
? 'key_changed'
|
|
398
|
-
: null,
|
|
435
|
+
blocked: current?.repoId && !fromHere
|
|
436
|
+
? 'installed_from_elsewhere'
|
|
437
|
+
: repo.keyStatus === 'key_changed'
|
|
438
|
+
? 'key_changed'
|
|
439
|
+
: null,
|
|
399
440
|
});
|
|
400
441
|
}
|
|
401
442
|
}
|
|
@@ -480,11 +521,12 @@ export class PluginRepoService {
|
|
|
480
521
|
throw new ConflictError('incompatible', `${input.pluginId}@${input.version} needs core ${version.minCoreVersion} or newer`);
|
|
481
522
|
}
|
|
482
523
|
const current = this.db.select().from(plugins).where(eq(plugins.pluginId, input.pluginId)).get();
|
|
483
|
-
if (current?.
|
|
484
|
-
throw new ConflictError('
|
|
485
|
-
if (current && current.repoId !== repo.id) {
|
|
486
|
-
throw new ConflictError('installed_from_elsewhere', `"${input.pluginId}" is installed from another source; uninstall it first`);
|
|
524
|
+
if (current?.repoId && current.repoId !== repo.id) {
|
|
525
|
+
throw new ConflictError('installed_from_elsewhere', `"${input.pluginId}" is installed from another repository; uninstall it first`);
|
|
487
526
|
}
|
|
527
|
+
// A plugin no repository manages (a built-in plugin from before 0.3.0, or one copied in by hand) is
|
|
528
|
+
// adopted: this install replaces its files and keeps its row, so its endpoints carry over.
|
|
529
|
+
const adopting = !!current && !current.repoId;
|
|
488
530
|
if (repo.signingMode === 'unsigned' && input.confirm !== input.pluginId) {
|
|
489
531
|
throw new ConflictError('confirm_required', `This repository is unsigned. Type "${input.pluginId}" to install anyway`);
|
|
490
532
|
}
|
|
@@ -511,7 +553,7 @@ export class PluginRepoService {
|
|
|
511
553
|
const work = path.join(this.stagingDir, randomUUID());
|
|
512
554
|
try {
|
|
513
555
|
const root = await this.extract(tarball, work);
|
|
514
|
-
const inspected = inspectPluginDir(root
|
|
556
|
+
const inspected = inspectPluginDir(root);
|
|
515
557
|
if (inspected.status !== 'ok')
|
|
516
558
|
throw new ValidationError('invalid_plugin', inspected.error);
|
|
517
559
|
if (inspected.manifest.id !== input.pluginId || inspected.manifest.version !== input.version) {
|
|
@@ -536,7 +578,8 @@ export class PluginRepoService {
|
|
|
536
578
|
// New installs start disabled, and an update that changes what the plugin may do is disabled
|
|
537
579
|
// again: enabling it is the admin's review of its binding, capabilities and hosts (design §4.2).
|
|
538
580
|
const review = current ? permissionChanges(current.manifest, inspected.manifest) : [];
|
|
539
|
-
|
|
581
|
+
// Adopted code comes from a new source, so it waits for the admin's review like a new install.
|
|
582
|
+
const enabled = current && !adopting ? current.enabled && review.length === 0 : false;
|
|
540
583
|
this.db.transaction((tx) => {
|
|
541
584
|
tx.update(plugins)
|
|
542
585
|
.set({ repoId: repo.id, sha256, signatureVerified, enabled })
|
|
@@ -544,7 +587,7 @@ export class PluginRepoService {
|
|
|
544
587
|
.run();
|
|
545
588
|
writeAudit(tx, {
|
|
546
589
|
kind: 'config',
|
|
547
|
-
decision: current ? 'plugin_updated' : 'plugin_installed',
|
|
590
|
+
decision: adopting ? 'plugin_adopted' : current ? 'plugin_updated' : 'plugin_installed',
|
|
548
591
|
actorKind: 'user',
|
|
549
592
|
actorId: actor.userId,
|
|
550
593
|
detail: {
|
|
@@ -567,14 +610,12 @@ export class PluginRepoService {
|
|
|
567
610
|
rmSync(work, { recursive: true, force: true });
|
|
568
611
|
}
|
|
569
612
|
}
|
|
570
|
-
/** Removes an installed
|
|
613
|
+
/** Removes an installed plugin. Blocked while any instance uses it. */
|
|
571
614
|
uninstall(pluginRowOrId, actor = {}) {
|
|
572
615
|
const row = this.db.select().from(plugins).where(eq(plugins.id, pluginRowOrId)).get() ??
|
|
573
616
|
this.db.select().from(plugins).where(eq(plugins.pluginId, pluginRowOrId)).get();
|
|
574
617
|
if (!row)
|
|
575
618
|
throw new NotFoundError('plugin_not_found', 'No such plugin');
|
|
576
|
-
if (row.source === 'core')
|
|
577
|
-
throw new ConflictError('core_plugin', 'Core plugins cannot be uninstalled; disable them instead');
|
|
578
619
|
const instances = this.db.select().from(pluginInstances).where(eq(pluginInstances.pluginId, row.id)).all();
|
|
579
620
|
if (instances.length) {
|
|
580
621
|
throw new ConflictError('plugin_has_instances', 'Delete this plugin’s endpoints first', {
|