mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 21:46:49 +00:00
Fix/plugin audit findings (#2031)
* fix(plugins): enforce manifest apiVersion at install and activation * test(plugins): exercise the absent-apiVersion default * feat(plugins): generate the core-event catalog into host-facts * docs(plugins): explain the packing.listBags write-permission binding * test(plugins): cover apiVersion upload refusal; tidy docblocks and generator header * fix(plugin-sdk): validate settings options and oauth like the host * fix(plugin-sdk): model the full manifest shape and stop dropping fields * fix(plugin-sdk): drop non-string routeProfiles icons like the host * docs(plugin-sdk): document host limits, oauth contract, and ignored asUserId * feat(plugin-sdk): enforce daily budgets and meta quotas in the mock host * feat(plugin-sdk): expose the generated core-event catalog * feat(plugin-sdk): scaffold trek range >=3.4.0 <5.0.0 ahead of TREK 4.0 * feat(plugin-sdk): scaffold the oauth broker settings for oauth:client plugins * chore(plugin-sdk): fix stale mirror docs and the colliding permissions export * docs(plugin-sdk): add the rate-limit string; restore trek docblock; match host meta sizing * feat(plugin-sdk): raise the scaffold trek floor to 4.0.0 * docs(wiki): bring the plugin pages in line with the current runtime * docs: bring the workspace CLAUDE.md guides up to date and make them committable * feat(plugin-sdk): roll back failed publishes, add unrelease, sync the fork, retro-sign updates * docs(wiki): document the publish rollback, unrelease, fork sync, and retro-signing * chore(plugin-sdk): 1.6.0
This commit is contained in:
@@ -57,6 +57,23 @@ export interface ScaffoldOptions {
|
||||
|
||||
export const TEMPLATES = ['blank', 'notification-channel'] as const;
|
||||
|
||||
/**
|
||||
* The credential fields the OAuth broker (server-side `oauth.getToken`) needs to run the
|
||||
* authorization-code flow on the plugin's behalf. ALL `scope: 'instance'` — unlike the
|
||||
* notification-channel template's `scope: 'user'` settings above, these are configured ONCE
|
||||
* per install by an admin, not per recipient: the broker itself reads them at token-exchange
|
||||
* time, there is no per-user client id/secret. Deliberately not user-scoped.
|
||||
*/
|
||||
const OAUTH_SETTINGS: Array<{
|
||||
key: string; label: string; input_type: string; required: boolean; secret?: boolean; scope: 'instance';
|
||||
}> = [
|
||||
{ key: 'oauth_authorize_url', label: 'OAuth authorize URL', input_type: 'text', required: true, scope: 'instance' },
|
||||
{ key: 'oauth_token_url', label: 'OAuth token URL', input_type: 'text', required: true, scope: 'instance' },
|
||||
{ key: 'oauth_scopes', label: 'OAuth scopes (space-separated)', input_type: 'text', required: false, scope: 'instance' },
|
||||
{ key: 'oauth_client_id', label: 'OAuth client id', input_type: 'text', required: true, scope: 'instance' },
|
||||
{ key: 'oauth_client_secret', label: 'OAuth client secret', input_type: 'text', required: true, secret: true, scope: 'instance' },
|
||||
];
|
||||
|
||||
/** Mirrors the server's widget slots (and the manifest validator's). */
|
||||
export const WIDGET_SLOTS = ['sidebar', 'hero', 'place-detail', 'day-detail', 'reservation-detail'] as const;
|
||||
export type WidgetSlot = (typeof WIDGET_SLOTS)[number];
|
||||
@@ -121,11 +138,13 @@ export function scaffold(name: string, type: string, targetDir: string, opts: Sc
|
||||
author: opts.author || 'Your Name',
|
||||
description: opts.description || (isChannel ? `Deliver TREK notifications over ${displayName}.` : 'Describe what your plugin does.'),
|
||||
type,
|
||||
// 3.4.0, not 3.3.0. The `ctx` namespaces this scaffold is written against — ctx.meta,
|
||||
// ctx.places, ctx.days, ctx.itinerary, ctx.costs, ctx.packing, ctx.files — only exist from
|
||||
// 3.4.0. Claiming 3.3.0 lets the plugin install on a host where they are `undefined`, which
|
||||
// fails at the first call with a TypeError instead of a clear "incompatible" at install.
|
||||
trek: '>=3.4.0 <4.0.0',
|
||||
// Floor 4.0.0: the host surface this scaffold is written against — the enforced
|
||||
// apiVersion gate, the generated core-event catalog (EVENT_FAMILIES /
|
||||
// EVENT_SNAPSHOT_GRANT), the OAuth-broker settings contract — is the TREK 4 surface.
|
||||
// Claiming an older floor lets the plugin install on a host where parts of it are
|
||||
// missing, which fails at the first call instead of a clear "incompatible" at install.
|
||||
// Ceiling 5.0.0: bounded, per the trek-range rule; widen only against a tested host.
|
||||
trek: '>=4.0.0 <5.0.0',
|
||||
nativeModules: false,
|
||||
permissions: perms,
|
||||
// Dependency declarations (empty by default). `requiredAddons` lists addon ids
|
||||
@@ -183,6 +202,16 @@ export function scaffold(name: string, type: string, targetDir: string, opts: Sc
|
||||
},
|
||||
];
|
||||
}
|
||||
// The broker (ctx.oauth.getToken) needs somewhere to read the authorize/token URLs and the
|
||||
// app's client id/secret — an admin configures them once, instance-wide, and the broker
|
||||
// reads them at token-exchange time. Merge with any settings the template above already
|
||||
// wrote (a channel template never grants oauth:client today, so there is no real overlap,
|
||||
// but keys are deduped anyway rather than trusting that stays true).
|
||||
if (perms.includes('oauth:client')) {
|
||||
const existing = (manifest.settings as Array<{ key: string }> | undefined) ?? [];
|
||||
const seen = new Set(existing.map((s) => s.key));
|
||||
manifest.settings = [...existing, ...OAUTH_SETTINGS.filter((s) => !seen.has(s.key))];
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.join(root, 'trek-plugin.json'), JSON.stringify(manifest, null, 2) + '\n');
|
||||
fs.writeFileSync(path.join(root, 'server', 'index.js'), isChannel ? CHANNEL_JS : SERVER_JS(perms.includes('db:own')));
|
||||
|
||||
Reference in New Issue
Block a user