@extenshi/cli 0.8.1 → 0.9.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/cli.js CHANGED
@@ -21,6 +21,7 @@
21
21
  * before the process exits. See telemetry.ts — disabled by default until a
22
22
  * PostHog key is configured, and a no-op under DO_NOT_TRACK / EXTENSHI_TELEMETRY=0.
23
23
  */
24
+ import { readFile } from 'node:fs/promises';
24
25
  import { createRequire } from 'node:module';
25
26
  import * as readline from 'node:readline/promises';
26
27
  import { program } from 'commander';
@@ -29,12 +30,13 @@ import { loadConfig, saveConfig } from './config.js';
29
30
  import { runIconPreview } from './icon.js';
30
31
  import { runPublish } from './publish.js';
31
32
  import { runReviewRisk } from './review-risk.js';
33
+ import { parseRefs, parseStore, runRisk } from './risk.js';
32
34
  import { runScan } from './scan.js';
33
35
  import { captureError, captureEvent, classifyError, flagsFromArgv, flushTelemetry, initTelemetry, } from './telemetry.js';
34
36
  const MISSING_KEY_HELP = "Looks like you don't have an Extenshi API key set up yet — let's fix that.\n" +
35
37
  '\n' +
36
38
  'Getting started is free: no credit card required. Every account includes a\n' +
37
- 'free monthly allowance (25 catalog reads + 5 scans), so you can try things out\n' +
39
+ 'one-time free allowance (10 catalog reads + 3 scans), so you can try things out\n' +
38
40
  'before paying for anything.\n' +
39
41
  '\n' +
40
42
  '1. Create a free account at https://auth.extenshi.io/signup\n' +
@@ -234,6 +236,50 @@ program
234
236
  });
235
237
  });
236
238
  });
239
+ program
240
+ .command('risk [store-ids...]')
241
+ .description('Look up the safety score for extensions you already have, by their STORE ids (the id in the ' +
242
+ 'store URL). Built for inventories: up to 40 extensions per request, and the whole request ' +
243
+ 'costs 1 read credit — not 1 per extension. Scores are cluster-resolved server-side, so they ' +
244
+ 'match what the extension page shows.')
245
+ .option('--store <store>', 'Store the ids belong to: chrome | firefox | edge (default: chrome). Per-id "firefox:some-addon" prefixes override it.')
246
+ .option('--file <path>', 'Read ids from a file instead of (or in addition to) the arguments: one per line, bare id or "store:id". Blank lines and # comments are ignored.')
247
+ .option('--catalog-url <url>', 'Override the catalog BFF base URL (default: https://bff.extenshi.io)')
248
+ .option('--json', 'Output raw JSON')
249
+ .action(async (storeIds, opts) => {
250
+ await runCommand('risk', async () => {
251
+ const defaultStore = parseStore(opts.store ?? 'chrome');
252
+ if (!defaultStore) {
253
+ throw new Error('--store must be one of: chrome, firefox, edge');
254
+ }
255
+ const entries = [...(storeIds ?? [])];
256
+ if (opts.file) {
257
+ let contents;
258
+ try {
259
+ contents = await readFile(opts.file, 'utf8');
260
+ }
261
+ catch {
262
+ throw new Error(`could not read --file "${opts.file}"`);
263
+ }
264
+ entries.push(...contents.split(/\r?\n/));
265
+ }
266
+ const { refs, invalid } = parseRefs(entries, defaultStore);
267
+ if (invalid.length > 0) {
268
+ console.error(`Skipped ${invalid.length} unusable entr(y/ies): ${invalid.slice(0, 5).join(', ')}`);
269
+ }
270
+ const config = await loadConfig();
271
+ if (!config.apiKey) {
272
+ throw new Error(MISSING_KEY_HELP);
273
+ }
274
+ await checkAutoUpdate();
275
+ await runRisk({
276
+ refs,
277
+ bffUrl: (opts.catalogUrl ?? config.bffUrl ?? 'https://bff.extenshi.io').replace(/\/$/, ''),
278
+ apiKey: config.apiKey,
279
+ outputJson: opts.json ?? false,
280
+ });
281
+ });
282
+ });
237
283
  const icon = program
238
284
  .command('icon')
239
285
  .description('Icon utilities for browser extensions (free, fully offline)');
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -1112,7 +1112,7 @@ export function renderIconPreviewHtml(input) {
1112
1112
  <span class="next-ico">${SCAN_ICON}</span>
1113
1113
  <div class="next-body">
1114
1114
  <code>npx @extenshi/cli scan dist.zip</code>
1115
- <p>Pre-publish security scan of the built artifact, with a free monthly allowance.</p>
1115
+ <p>Pre-publish security scan of the built artifact, with a free allowance.</p>
1116
1116
  </div>
1117
1117
  </div>
1118
1118
  <div class="next-item">
package/dist/risk.d.ts ADDED
@@ -0,0 +1,76 @@
1
+ /**
2
+ * `extenshi risk` — bulk safety lookup for extensions you already have,
3
+ * addressed by their STORE ids.
4
+ *
5
+ * This is the inventory case: you hold a list of installed extensions (from a
6
+ * fleet report, an MDM export, `chrome://extensions`) and want to know which of
7
+ * them are risky, without knowing their catalog ids.
8
+ *
9
+ * Why it exists as its own command
10
+ * --------------------------------
11
+ * Doing this one extension at a time cost three metered catalog reads each
12
+ * (resolve the store id → follow the cluster canonical → fetch the risk
13
+ * summary). This command hits `security.getSecuritySummaryBatch`, which answers
14
+ * up to {@link MAX_EXTENSIONS_PER_REQUEST} extensions in ONE metered read — an
15
+ * 87-extension inventory drops from 261 credits to 3.
16
+ *
17
+ * Cluster correctness is handled server-side: each store id is resolved through
18
+ * its cross-store cluster to the same listing the extension page renders, so a
19
+ * score printed here matches the page a user can open. When the score comes
20
+ * from a DIFFERENT store's listing of the same extension (cluster members are
21
+ * scanned independently and genuinely disagree), the row says so rather than
22
+ * presenting a sibling's number as this listing's own.
23
+ */
24
+ /**
25
+ * Max extensions per request.
26
+ *
27
+ * CROSS-PACKAGE SYNC POINT — this is a published npm package and cannot import
28
+ * from the BFF. The authority is `METERED_BATCH_MAX_EXTENSIONS` in
29
+ * `catalog/catalog-bff/src/lib/metered-batch-cap.ts`, which rejects an over-cap
30
+ * request; this constant only lets the CLI fail fast with a useful message
31
+ * instead of round-tripping. Pinned by `risk.test.ts`.
32
+ */
33
+ export declare const MAX_EXTENSIONS_PER_REQUEST = 40;
34
+ export type Store = 'CHROME' | 'FIREFOX' | 'EDGE';
35
+ export interface StoreRef {
36
+ storeId: string;
37
+ store: Store;
38
+ }
39
+ /** Normalise a user-supplied store name, or undefined when unrecognised. */
40
+ export declare function parseStore(value: string | undefined): Store | undefined;
41
+ /**
42
+ * Parse the id list a caller supplied (argv and/or a `--file`) into store refs.
43
+ *
44
+ * Accepted per entry: a bare id (uses `defaultStore`) or `store:id`, so one
45
+ * file can mix browsers — which is the normal shape of a real inventory.
46
+ * Blank lines and `#` comments are skipped. Duplicates collapse: a user with
47
+ * the same extension in two profiles should not pay for it twice.
48
+ */
49
+ export declare function parseRefs(entries: string[], defaultStore: Store): {
50
+ refs: StoreRef[];
51
+ invalid: string[];
52
+ };
53
+ /** One row as returned by the BFF batch (fields beyond these are ignored). */
54
+ interface RiskRow {
55
+ storeId?: string;
56
+ store?: string;
57
+ extensionId?: number | null;
58
+ canonicalExtensionId?: number | null;
59
+ extensionName?: string | null;
60
+ riskCategory?: string | null;
61
+ riskScore?: number | string | null;
62
+ scoredExtensionId?: number | null;
63
+ scoredStore?: string | null;
64
+ totalFindings?: number | null;
65
+ lastScanDate?: string | null;
66
+ }
67
+ export declare function rankRow(row: RiskRow): number;
68
+ export interface RunRiskOptions {
69
+ refs: StoreRef[];
70
+ bffUrl: string;
71
+ apiKey?: string;
72
+ outputJson: boolean;
73
+ }
74
+ export declare function runRisk(opts: RunRiskOptions): Promise<void>;
75
+ export {};
76
+ //# sourceMappingURL=risk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risk.d.ts","sourceRoot":"","sources":["../src/risk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAOH;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAE5C,MAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAA;AAEjD,MAAM,WAAW,QAAQ;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,KAAK,CAAA;CACZ;AAQD,4EAA4E;AAC5E,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,SAAS,CAGvE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,KAAK,GAAG;IAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CA8BzG;AAED,8EAA8E;AAC9E,UAAU,OAAO;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAClC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AA0CD,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAE5C;AAED,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,QAAQ,EAAE,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,OAAO,CAAA;CACnB;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAmDjE"}
package/dist/risk.js ADDED
@@ -0,0 +1,214 @@
1
+ /**
2
+ * `extenshi risk` — bulk safety lookup for extensions you already have,
3
+ * addressed by their STORE ids.
4
+ *
5
+ * This is the inventory case: you hold a list of installed extensions (from a
6
+ * fleet report, an MDM export, `chrome://extensions`) and want to know which of
7
+ * them are risky, without knowing their catalog ids.
8
+ *
9
+ * Why it exists as its own command
10
+ * --------------------------------
11
+ * Doing this one extension at a time cost three metered catalog reads each
12
+ * (resolve the store id → follow the cluster canonical → fetch the risk
13
+ * summary). This command hits `security.getSecuritySummaryBatch`, which answers
14
+ * up to {@link MAX_EXTENSIONS_PER_REQUEST} extensions in ONE metered read — an
15
+ * 87-extension inventory drops from 261 credits to 3.
16
+ *
17
+ * Cluster correctness is handled server-side: each store id is resolved through
18
+ * its cross-store cluster to the same listing the extension page renders, so a
19
+ * score printed here matches the page a user can open. When the score comes
20
+ * from a DIFFERENT store's listing of the same extension (cluster members are
21
+ * scanned independently and genuinely disagree), the row says so rather than
22
+ * presenting a sibling's number as this listing's own.
23
+ */
24
+ import chalk from 'chalk';
25
+ import { fetch } from 'undici';
26
+ const FETCH_TIMEOUT_MS = 20_000;
27
+ /**
28
+ * Max extensions per request.
29
+ *
30
+ * CROSS-PACKAGE SYNC POINT — this is a published npm package and cannot import
31
+ * from the BFF. The authority is `METERED_BATCH_MAX_EXTENSIONS` in
32
+ * `catalog/catalog-bff/src/lib/metered-batch-cap.ts`, which rejects an over-cap
33
+ * request; this constant only lets the CLI fail fast with a useful message
34
+ * instead of round-tripping. Pinned by `risk.test.ts`.
35
+ */
36
+ export const MAX_EXTENSIONS_PER_REQUEST = 40;
37
+ const STORE_ALIASES = {
38
+ chrome: 'CHROME',
39
+ firefox: 'FIREFOX',
40
+ edge: 'EDGE',
41
+ };
42
+ /** Normalise a user-supplied store name, or undefined when unrecognised. */
43
+ export function parseStore(value) {
44
+ if (!value)
45
+ return undefined;
46
+ return STORE_ALIASES[value.trim().toLowerCase()];
47
+ }
48
+ /**
49
+ * Parse the id list a caller supplied (argv and/or a `--file`) into store refs.
50
+ *
51
+ * Accepted per entry: a bare id (uses `defaultStore`) or `store:id`, so one
52
+ * file can mix browsers — which is the normal shape of a real inventory.
53
+ * Blank lines and `#` comments are skipped. Duplicates collapse: a user with
54
+ * the same extension in two profiles should not pay for it twice.
55
+ */
56
+ export function parseRefs(entries, defaultStore) {
57
+ const refs = [];
58
+ const invalid = [];
59
+ const seen = new Set();
60
+ for (const raw of entries) {
61
+ const line = raw.trim();
62
+ if (!line || line.startsWith('#'))
63
+ continue;
64
+ let store = defaultStore;
65
+ let storeId = line;
66
+ const sep = line.indexOf(':');
67
+ if (sep > 0) {
68
+ const named = parseStore(line.slice(0, sep));
69
+ if (named) {
70
+ store = named;
71
+ storeId = line.slice(sep + 1).trim();
72
+ }
73
+ }
74
+ if (!storeId || storeId.length > 100) {
75
+ invalid.push(line);
76
+ continue;
77
+ }
78
+ const key = `${store}:${storeId}`;
79
+ if (seen.has(key))
80
+ continue;
81
+ seen.add(key);
82
+ refs.push({ storeId, store });
83
+ }
84
+ return { refs, invalid };
85
+ }
86
+ /**
87
+ * The website's coefficient: 100 = safest. The backend stores RISK (0 = safest),
88
+ * so every user-facing surface inverts it — printing the raw number here would
89
+ * make the CLI contradict the extension page by construction.
90
+ */
91
+ function toSafetyScore(risk) {
92
+ if (risk === undefined || risk === null)
93
+ return null;
94
+ const value = Number(risk);
95
+ if (!Number.isFinite(value))
96
+ return null;
97
+ return Math.max(0, Math.min(100, Math.round((100 - value) * 100) / 100));
98
+ }
99
+ function colorForCategory(category) {
100
+ switch (category) {
101
+ case 'CRITICAL':
102
+ return chalk.bgRed.white;
103
+ case 'HIGH':
104
+ return chalk.red;
105
+ case 'MEDIUM':
106
+ return chalk.yellow;
107
+ case 'LOW':
108
+ return chalk.cyan;
109
+ case 'NONE':
110
+ return chalk.green;
111
+ default:
112
+ return chalk.gray;
113
+ }
114
+ }
115
+ /** Severity order for the printed table: worst first, unscanned last. */
116
+ const CATEGORY_RANK = {
117
+ CRITICAL: 0,
118
+ HIGH: 1,
119
+ MEDIUM: 2,
120
+ REVIEW_REQUIRED: 3,
121
+ LOW: 4,
122
+ NONE: 5,
123
+ UNKNOWN: 6,
124
+ };
125
+ export function rankRow(row) {
126
+ return CATEGORY_RANK[row.riskCategory ?? ''] ?? 7;
127
+ }
128
+ export async function runRisk(opts) {
129
+ if (opts.refs.length === 0) {
130
+ throw new Error('no extension ids given. Pass ids as arguments or use --file <path>.');
131
+ }
132
+ if (opts.refs.length > MAX_EXTENSIONS_PER_REQUEST) {
133
+ throw new Error(`${opts.refs.length} extensions given; the limit is ${MAX_EXTENSIONS_PER_REQUEST} per request.\n` +
134
+ `Split the list into batches of ${MAX_EXTENSIONS_PER_REQUEST} or fewer — each request costs ` +
135
+ '1 read credit, whatever its size.');
136
+ }
137
+ // tRPC queries travel as a GET query string, so the batch size bounds the URL
138
+ // length. Worst case the schema allows — 40 entries of 100-char Firefox ids —
139
+ // measured at 7,060 bytes and verified against the live BFF (HTTP 200), which
140
+ // leaves ~1 KB under nginx's default 8 KB header buffer. That margin is the
141
+ // real constraint on raising MAX_EXTENSIONS_PER_REQUEST: a larger cap needs
142
+ // the header buffer raised (or a POST transport) first, not just a new number.
143
+ const input = encodeURIComponent(JSON.stringify({ extensions: opts.refs }));
144
+ const url = `${opts.bffUrl}/api/trpc/security.getSecuritySummaryBatch?input=${input}`;
145
+ let res;
146
+ try {
147
+ res = await fetch(url, {
148
+ headers: opts.apiKey ? { authorization: `Bearer ${opts.apiKey}` } : {},
149
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
150
+ });
151
+ }
152
+ catch (err) {
153
+ const e = err;
154
+ const why = e.name === 'TimeoutError' ? `timed out after ${FETCH_TIMEOUT_MS / 1000}s` : e.message;
155
+ throw new Error(`could not reach the catalog (${why})`);
156
+ }
157
+ const body = (await res.json().catch(() => null));
158
+ if (body?.error?.message)
159
+ throw new Error(body.error.message);
160
+ if (!res.ok)
161
+ throw new Error(`catalog returned HTTP ${res.status}`);
162
+ const rows = (Array.isArray(body?.result?.data) ? body.result.data : []);
163
+ if (opts.outputJson) {
164
+ console.log(JSON.stringify({ requested: opts.refs.length, matched: rows.length, extensions: rows }, null, 2));
165
+ return;
166
+ }
167
+ printTable(opts.refs, rows);
168
+ }
169
+ function printTable(refs, rows) {
170
+ const byKey = new Map(rows.map((r) => [`${r.store}:${r.storeId}`, r]));
171
+ const sorted = [...rows].sort((a, b) => rankRow(a) - rankRow(b));
172
+ console.log('');
173
+ console.log(chalk.bold(`Safety for ${refs.length} extension${refs.length === 1 ? '' : 's'} (100 = safest)`));
174
+ console.log('');
175
+ if (sorted.length === 0) {
176
+ console.log(chalk.gray(' None of these ids matched a catalog listing.'));
177
+ }
178
+ for (const row of sorted) {
179
+ const color = colorForCategory(row.riskCategory);
180
+ const score = toSafetyScore(row.riskScore);
181
+ const name = row.extensionName ?? row.storeId ?? '(unnamed)';
182
+ const scoreText = score === null ? chalk.gray(' —') : color(String(score).padStart(3));
183
+ const category = row.riskCategory ? color(row.riskCategory) : chalk.gray('not scanned');
184
+ console.log(` ${scoreText} ${chalk.bold(name)} ${category}`);
185
+ const details = [];
186
+ const canonical = row.canonicalExtensionId ?? row.extensionId;
187
+ if (canonical != null)
188
+ details.push(`https://catalog.extenshi.io/extensions/${canonical}`);
189
+ if (row.totalFindings != null)
190
+ details.push(`${row.totalFindings} findings`);
191
+ if (details.length > 0)
192
+ console.log(chalk.gray(` ${details.join(' · ')}`));
193
+ // Cluster members are scanned independently and their scores disagree,
194
+ // so a borrowed number is labelled rather than presented as this
195
+ // listing's own.
196
+ if (row.scoredExtensionId != null && row.scoredExtensionId !== row.extensionId && row.scoredStore) {
197
+ console.log(chalk.gray(` score measured on this extension's ${row.scoredStore} listing`));
198
+ }
199
+ }
200
+ const missing = refs.filter((ref) => !byKey.has(`${ref.store}:${ref.storeId}`));
201
+ if (missing.length > 0) {
202
+ console.log('');
203
+ console.log(chalk.gray(` ${missing.length} id(s) have no catalog listing yet (not a safety verdict):`));
204
+ for (const ref of missing)
205
+ console.log(chalk.gray(` ${ref.store.toLowerCase()}:${ref.storeId}`));
206
+ }
207
+ const unscanned = rows.filter((r) => r.riskCategory == null).length;
208
+ if (unscanned > 0) {
209
+ console.log('');
210
+ console.log(chalk.gray(` ${unscanned} listed but never scanned — no score is not a clean bill of health.`));
211
+ }
212
+ console.log('');
213
+ }
214
+ //# sourceMappingURL=risk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risk.js","sourceRoot":"","sources":["../src/risk.ts"],"names":[],"mappings":"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"}
package/dist/scan.d.ts CHANGED
@@ -31,7 +31,7 @@ import { type ComplianceReviewPayload } from './compliance-review.js';
31
31
  * ownership you have verified, and ONLY when you name one with
32
32
  * `--extension-id <id>` (the numeric catalog ID of a verified extension). A
33
33
  * bare `extenshi scan <artifact>` running on free credits therefore 403s —
34
- * which is confusing when dojo just says "5 free scans left".
34
+ * which is confusing when dojo just says "3 free scans left".
35
35
  *
36
36
  * The BFF signals this case via a stable `errorCode`
37
37
  * (`FREE_REQUIRES_CLAIM` / `FREE_REQUIRES_VERIFIED_OWNERSHIP`). The CLI ships
package/dist/scan.js CHANGED
@@ -44,7 +44,7 @@ const DOJO_URL = 'https://dojo.extenshi.io';
44
44
  * ownership you have verified, and ONLY when you name one with
45
45
  * `--extension-id <id>` (the numeric catalog ID of a verified extension). A
46
46
  * bare `extenshi scan <artifact>` running on free credits therefore 403s —
47
- * which is confusing when dojo just says "5 free scans left".
47
+ * which is confusing when dojo just says "3 free scans left".
48
48
  *
49
49
  * The BFF signals this case via a stable `errorCode`
50
50
  * (`FREE_REQUIRES_CLAIM` / `FREE_REQUIRES_VERIFIED_OWNERSHIP`). The CLI ships
@@ -1,19 +1,26 @@
1
1
  /**
2
- * Canonical regex-based SVG scrubber, shared by the offline CLI preview and the
3
- * hosted dojo generator so both strip the exact same constructs.
2
+ * Canonical regex-based SVG scrubber, shared by the offline CLI preview, the
3
+ * hosted dojo generator and the catalog-bff persistence path so all three strip
4
+ * the exact same constructs.
4
5
  *
5
6
  * Regex-based (not DOM-based) on purpose: it must run in Node with no DOMParser
6
7
  * — the CLI runs offline in a terminal, and the dojo API route runs server-side.
7
8
  * Patterns intentionally over-remove rather than under-remove: an icon has no
8
9
  * legitimate use for scripts, styles, animation, or external references.
9
10
  *
10
- * SINGLE SOURCE, TWO COPIES: this file exists byte-identical at
11
- * tools/extenshi-cli/src/svg-scrub.ts (canonical — edit here)
11
+ * SINGLE SOURCE, THREE COPIES: this file exists byte-identical at
12
+ * tools/extenshi-cli/src/svg-scrub.ts (canonical — edit here)
12
13
  * dojo/src/lib/tools/svg-scrub.ts (synced copy for the dojo build)
14
+ * catalog/catalog-bff/src/lib/svg-scrub.ts (synced copy for the BFF build)
13
15
  * because the published @extenshi/cli npm package cannot depend on unpublished
14
- * workspace packages, and dojo's Docker build does not build the CLI package.
16
+ * workspace packages, and neither dojo's nor the BFF's Docker build builds the
17
+ * CLI package. The BFF copy is the load-bearing one for welcome pages: it
18
+ * sanitizes agent-authored SVG *before it is persisted*, so a hostile block can
19
+ * never reach the database, let alone a rendered page.
15
20
  * A test in tools/extenshi-cli/src/icon.test.ts fails CI when the copies drift;
16
- * after editing, run: cp tools/extenshi-cli/src/svg-scrub.ts dojo/src/lib/tools/svg-scrub.ts
21
+ * after editing, run:
22
+ * cp tools/extenshi-cli/src/svg-scrub.ts dojo/src/lib/tools/svg-scrub.ts
23
+ * cp tools/extenshi-cli/src/svg-scrub.ts catalog/catalog-bff/src/lib/svg-scrub.ts
17
24
  *
18
25
  * This is the same rationale as icon-preview.ts (see the note there).
19
26
  */
@@ -1 +1 @@
1
- {"version":3,"file":"svg-scrub.d.ts","sourceRoot":"","sources":["../src/svg-scrub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,eAAO,MAAM,kBAAkB,8LAiBrB,CAAA;AAIV;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA0BlD"}
1
+ {"version":3,"file":"svg-scrub.d.ts","sourceRoot":"","sources":["../src/svg-scrub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,eAAO,MAAM,kBAAkB,8LAiBrB,CAAA;AAIV;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA0BlD"}
package/dist/svg-scrub.js CHANGED
@@ -1,19 +1,26 @@
1
1
  /**
2
- * Canonical regex-based SVG scrubber, shared by the offline CLI preview and the
3
- * hosted dojo generator so both strip the exact same constructs.
2
+ * Canonical regex-based SVG scrubber, shared by the offline CLI preview, the
3
+ * hosted dojo generator and the catalog-bff persistence path so all three strip
4
+ * the exact same constructs.
4
5
  *
5
6
  * Regex-based (not DOM-based) on purpose: it must run in Node with no DOMParser
6
7
  * — the CLI runs offline in a terminal, and the dojo API route runs server-side.
7
8
  * Patterns intentionally over-remove rather than under-remove: an icon has no
8
9
  * legitimate use for scripts, styles, animation, or external references.
9
10
  *
10
- * SINGLE SOURCE, TWO COPIES: this file exists byte-identical at
11
- * tools/extenshi-cli/src/svg-scrub.ts (canonical — edit here)
11
+ * SINGLE SOURCE, THREE COPIES: this file exists byte-identical at
12
+ * tools/extenshi-cli/src/svg-scrub.ts (canonical — edit here)
12
13
  * dojo/src/lib/tools/svg-scrub.ts (synced copy for the dojo build)
14
+ * catalog/catalog-bff/src/lib/svg-scrub.ts (synced copy for the BFF build)
13
15
  * because the published @extenshi/cli npm package cannot depend on unpublished
14
- * workspace packages, and dojo's Docker build does not build the CLI package.
16
+ * workspace packages, and neither dojo's nor the BFF's Docker build builds the
17
+ * CLI package. The BFF copy is the load-bearing one for welcome pages: it
18
+ * sanitizes agent-authored SVG *before it is persisted*, so a hostile block can
19
+ * never reach the database, let alone a rendered page.
15
20
  * A test in tools/extenshi-cli/src/icon.test.ts fails CI when the copies drift;
16
- * after editing, run: cp tools/extenshi-cli/src/svg-scrub.ts dojo/src/lib/tools/svg-scrub.ts
21
+ * after editing, run:
22
+ * cp tools/extenshi-cli/src/svg-scrub.ts dojo/src/lib/tools/svg-scrub.ts
23
+ * cp tools/extenshi-cli/src/svg-scrub.ts catalog/catalog-bff/src/lib/svg-scrub.ts
17
24
  *
18
25
  * This is the same rationale as icon-preview.ts (see the note there).
19
26
  */
@@ -1 +1 @@
1
- {"version":3,"file":"svg-scrub.js","sourceRoot":"","sources":["../src/svg-scrub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,8EAA8E;AAC9E,+EAA+E;AAC/E,0EAA0E;AAC1E,4CAA4C;AAC5C,MAAM,CAAC,MAAM,kBAAkB,GAAG;IACjC,QAAQ;IACR,OAAO;IACP,eAAe;IACf,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,MAAM;IACN,OAAO;IACP,UAAU;IACV,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,kBAAkB;IAClB,eAAe;IACf,KAAK;CACI,CAAA;AAEV,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE7C;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACzC,OAAO,CACN,GAAG;QACF,mEAAmE;QACnE,gEAAgE;QAChE,oEAAoE;QACpE,sEAAsE;SACrE,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC;SAChD,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;SAChC,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC;QACnC,2EAA2E;QAC3E,oEAAoE;QACpE,wEAAwE;QACxE,yEAAyE;QACzE,wEAAwE;SACvE,OAAO,CAAC,IAAI,MAAM,CAAC,SAAS,QAAQ,kCAAkC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;SAClF,OAAO,CAAC,IAAI,MAAM,CAAC,SAAS,QAAQ,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;QAC/D,8DAA8D;SAC7D,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC;SACzC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC;SACzC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC;QAC1C,sDAAsD;SACrD,OAAO,CAAC,4DAA4D,EAAE,EAAE,CAAC;SACzE,OAAO,CAAC,4DAA4D,EAAE,EAAE,CAAC;SACzE,IAAI,EAAE,CACR,CAAA;AACF,CAAC"}
1
+ {"version":3,"file":"svg-scrub.js","sourceRoot":"","sources":["../src/svg-scrub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,8EAA8E;AAC9E,+EAA+E;AAC/E,0EAA0E;AAC1E,4CAA4C;AAC5C,MAAM,CAAC,MAAM,kBAAkB,GAAG;IACjC,QAAQ;IACR,OAAO;IACP,eAAe;IACf,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,MAAM;IACN,OAAO;IACP,UAAU;IACV,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,kBAAkB;IAClB,eAAe;IACf,KAAK;CACI,CAAA;AAEV,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE7C;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACzC,OAAO,CACN,GAAG;QACF,mEAAmE;QACnE,gEAAgE;QAChE,oEAAoE;QACpE,sEAAsE;SACrE,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC;SAChD,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;SAChC,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC;QACnC,2EAA2E;QAC3E,oEAAoE;QACpE,wEAAwE;QACxE,yEAAyE;QACzE,wEAAwE;SACvE,OAAO,CAAC,IAAI,MAAM,CAAC,SAAS,QAAQ,kCAAkC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;SAClF,OAAO,CAAC,IAAI,MAAM,CAAC,SAAS,QAAQ,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;QAC/D,8DAA8D;SAC7D,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC;SACzC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC;SACzC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC;QAC1C,sDAAsD;SACrD,OAAO,CAAC,4DAA4D,EAAE,EAAE,CAAC;SACzE,OAAO,CAAC,4DAA4D,EAAE,EAAE,CAAC;SACzE,IAAI,EAAE,CACR,CAAA;AACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@extenshi/cli",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "description": "Pre-publish security scanner for browser extensions",
5
5
  "type": "module",
6
6
  "publishConfig": {