@extenshi/cli 0.21.0 → 0.22.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/README.md +4 -0
- package/dist/amo-source-detect.d.ts +18 -0
- package/dist/amo-source-detect.d.ts.map +1 -0
- package/dist/amo-source-detect.js +41 -0
- package/dist/amo-source-detect.js.map +1 -0
- package/dist/amo-source.d.ts +41 -0
- package/dist/amo-source.d.ts.map +1 -0
- package/dist/amo-source.js +240 -0
- package/dist/amo-source.js.map +1 -0
- package/dist/amowebstore-md.d.ts +38 -0
- package/dist/amowebstore-md.d.ts.map +1 -0
- package/dist/amowebstore-md.js +118 -0
- package/dist/amowebstore-md.js.map +1 -0
- package/dist/auto-evidence.d.ts +100 -0
- package/dist/auto-evidence.d.ts.map +1 -0
- package/dist/auto-evidence.js +197 -0
- package/dist/auto-evidence.js.map +1 -0
- package/dist/cli.js +265 -8
- package/dist/cli.js.map +1 -1
- package/dist/edgewebstore-md.d.ts +26 -0
- package/dist/edgewebstore-md.d.ts.map +1 -0
- package/dist/edgewebstore-md.js +95 -0
- package/dist/edgewebstore-md.js.map +1 -0
- package/dist/evidence-ingest.d.ts +60 -0
- package/dist/evidence-ingest.d.ts.map +1 -0
- package/dist/evidence-ingest.js +141 -0
- package/dist/evidence-ingest.js.map +1 -0
- package/dist/firefox-rdp.d.ts +55 -0
- package/dist/firefox-rdp.d.ts.map +1 -0
- package/dist/firefox-rdp.js +203 -0
- package/dist/firefox-rdp.js.map +1 -0
- package/dist/gecko-id.d.ts +55 -0
- package/dist/gecko-id.d.ts.map +1 -0
- package/dist/gecko-id.js +132 -0
- package/dist/gecko-id.js.map +1 -0
- package/dist/generate-listing.d.ts +19 -8
- package/dist/generate-listing.d.ts.map +1 -1
- package/dist/generate-listing.js +66 -18
- package/dist/generate-listing.js.map +1 -1
- package/dist/icon.d.ts +18 -0
- package/dist/icon.d.ts.map +1 -1
- package/dist/icon.js +29 -20
- package/dist/icon.js.map +1 -1
- package/dist/media.d.ts +42 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +96 -0
- package/dist/media.js.map +1 -0
- package/dist/package.d.ts +163 -0
- package/dist/package.d.ts.map +1 -0
- package/dist/package.js +500 -0
- package/dist/package.js.map +1 -0
- package/dist/page.d.ts +10 -0
- package/dist/page.d.ts.map +1 -1
- package/dist/page.js +32 -2
- package/dist/page.js.map +1 -1
- package/dist/pay-contract.d.ts +10 -3
- package/dist/pay-contract.d.ts.map +1 -1
- package/dist/pay-contract.js +9 -0
- package/dist/pay-contract.js.map +1 -1
- package/dist/pay-test-cycle.d.ts +40 -0
- package/dist/pay-test-cycle.d.ts.map +1 -0
- package/dist/pay-test-cycle.js +207 -0
- package/dist/pay-test-cycle.js.map +1 -0
- package/dist/pay.d.ts +1 -1
- package/dist/pay.d.ts.map +1 -1
- package/dist/pay.js +1 -0
- package/dist/pay.js.map +1 -1
- package/dist/project.d.ts +39 -1
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +231 -20
- package/dist/project.js.map +1 -1
- package/dist/publish.d.ts +33 -0
- package/dist/publish.d.ts.map +1 -1
- package/dist/publish.js +113 -2
- package/dist/publish.js.map +1 -1
- package/dist/review-checks.d.ts +13 -0
- package/dist/review-checks.d.ts.map +1 -1
- package/dist/review-checks.js.map +1 -1
- package/dist/review-risk.d.ts +10 -1
- package/dist/review-risk.d.ts.map +1 -1
- package/dist/review-risk.js +1 -0
- package/dist/review-risk.js.map +1 -1
- package/dist/scan.d.ts +3 -2
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +4 -2
- package/dist/scan.js.map +1 -1
- package/dist/screenshots-scenes.d.ts +1383 -0
- package/dist/screenshots-scenes.d.ts.map +1 -0
- package/dist/screenshots-scenes.js +276 -0
- package/dist/screenshots-scenes.js.map +1 -0
- package/dist/screenshots.d.ts +145 -0
- package/dist/screenshots.d.ts.map +1 -0
- package/dist/screenshots.js +557 -0
- package/dist/screenshots.js.map +1 -0
- package/dist/smoke.d.ts +81 -0
- package/dist/smoke.d.ts.map +1 -0
- package/dist/smoke.js +491 -0
- package/dist/smoke.js.map +1 -0
- package/dist/store-assets.d.ts +139 -0
- package/dist/store-assets.d.ts.map +1 -0
- package/dist/store-assets.js +582 -0
- package/dist/store-assets.js.map +1 -0
- package/dist/zip.d.ts +57 -0
- package/dist/zip.d.ts.map +1 -0
- package/dist/zip.js +134 -0
- package/dist/zip.js.map +1 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -74,4 +74,8 @@ Use `link` with `{ "appId": "...", "projectId": "..." }` to attach an optional d
|
|
|
74
74
|
|
|
75
75
|
Profile JSON: `{ "appId": "...", "profile": { "displayName": "Author-confirmed name", "supportUrl": "https://example.com/support", "termsUrl": "https://example.com/terms" } }`. Offer JSON: `{ "appId": "...", "sku": "pro", "kind": "subscription", "interval": "month", "amountMinor": 499, "currency": "usd", "title": "Pro", "features": ["premium"] }`. A one-time or lifetime offer uses `interval: null`.
|
|
76
76
|
|
|
77
|
+
`extenshi pay payment-evidence --input '{"appId":"..."}'` prints what Extenshi's payment ledger proves about the application, per mode: checkout completed, license issued, an installation received the signed license, restored on a second installation, refund revoked. It is derived from provider-signed webhooks, carries opaque IDs and timestamps only, and is the same evidence `extenshi release status` uses for the payment check of a linked project. Only a live-mode purchase satisfies a release's payment requirement.
|
|
78
|
+
|
|
79
|
+
`extenshi pay test-cycle --app <appId> [--sku pro] [--refund-key-env NAME]` runs one Stripe TEST-mode purchase against an application whose seller is in test mode and prints that evidence. It refuses a live seller, a non-test Checkout session and a non-test refund key. The CLI acts as the installation: it opens a checkout, prints the hosted URL for payment with card 4242 4242 4242 4242, waits for the webhook, verifies the signed license, optionally refunds with the Stripe TEST secret named by `--refund-key-env` and checks the signed revocation. Test-mode purchases are recorded and shown but do not satisfy a release's payment requirement.
|
|
80
|
+
|
|
77
81
|
Without `--output`, export returns one page with `nextCursor`; pass that cursor to retrieve the next page. With `--output`, all pages are streamed to a new private (0600) JSONL file; existing files are never overwritten, and failures remove incomplete files. Resources: offers, payments, subscriptions, entitlements, customers. Keep exports private. Only the publishable SDK key belongs in extension code.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect vendored/minified files that need a source-code submission on AMO.
|
|
3
|
+
*
|
|
4
|
+
* Shared by `amowebstore-md.ts` (lists them in AMO.md's "Source code" section)
|
|
5
|
+
* and `amo-source.ts` (the `extenshi amo-source` command, which treats an
|
|
6
|
+
* unreproducible one as a hard blocker). AMO policy:
|
|
7
|
+
* https://extensionworkshop.com/documentation/publish/source-code-submission/
|
|
8
|
+
* — minification/bundling/transpilation are allowed, but reviewers must be
|
|
9
|
+
* able to rebuild the pre-build source from provided instructions.
|
|
10
|
+
*/
|
|
11
|
+
import type { FileMap } from './review-checks.js';
|
|
12
|
+
export interface MinifiedFileFinding {
|
|
13
|
+
path: string;
|
|
14
|
+
/** True when the file's own banner states version + commit + build command. */
|
|
15
|
+
hasProvenanceBanner: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function detectMinifiedFiles(files: FileMap): MinifiedFileFinding[];
|
|
18
|
+
//# sourceMappingURL=amo-source-detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amo-source-detect.d.ts","sourceRoot":"","sources":["../src/amo-source-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAcjD,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,+EAA+E;IAC/E,mBAAmB,EAAE,OAAO,CAAA;CAC5B;AAWD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,EAAE,CAOzE"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect vendored/minified files that need a source-code submission on AMO.
|
|
3
|
+
*
|
|
4
|
+
* Shared by `amowebstore-md.ts` (lists them in AMO.md's "Source code" section)
|
|
5
|
+
* and `amo-source.ts` (the `extenshi amo-source` command, which treats an
|
|
6
|
+
* unreproducible one as a hard blocker). AMO policy:
|
|
7
|
+
* https://extensionworkshop.com/documentation/publish/source-code-submission/
|
|
8
|
+
* — minification/bundling/transpilation are allowed, but reviewers must be
|
|
9
|
+
* able to rebuild the pre-build source from provided instructions.
|
|
10
|
+
*/
|
|
11
|
+
const CODE_EXT_RE = /\.(?:m?js|cjs)$/i;
|
|
12
|
+
const MIN_FILENAME_RE = /[.-]min\.(?:m|c)?js$/i;
|
|
13
|
+
/**
|
|
14
|
+
* The banner convention this repo's own build tooling emits for vendored SDK
|
|
15
|
+
* bundles (`extenshi-pay-sdk`, `extenshi-storage-sdk`): version + commit SHA +
|
|
16
|
+
* build command in the first ~2KB. A file carrying it is not "source", but a
|
|
17
|
+
* reviewer (or a developer) can use it to reproduce the build without a
|
|
18
|
+
* separate vendor-src/ archive for THAT file specifically.
|
|
19
|
+
*/
|
|
20
|
+
const PROVENANCE_BANNER_RE = /v\d+\.\d+\.\d+.{0,300}?commit\s+[0-9a-f]{7,40}.{0,300}?built by/is;
|
|
21
|
+
function looksMinified(path, content) {
|
|
22
|
+
if (!CODE_EXT_RE.test(path))
|
|
23
|
+
return false;
|
|
24
|
+
if (MIN_FILENAME_RE.test(path))
|
|
25
|
+
return true;
|
|
26
|
+
if (!content || content.length < 2000)
|
|
27
|
+
return false;
|
|
28
|
+
const lines = content.split('\n');
|
|
29
|
+
const longestLine = lines.reduce((max, l) => Math.max(max, l.length), 0);
|
|
30
|
+
return longestLine > 500 && content.length / lines.length > 300;
|
|
31
|
+
}
|
|
32
|
+
export function detectMinifiedFiles(files) {
|
|
33
|
+
const out = [];
|
|
34
|
+
for (const [path, content] of files) {
|
|
35
|
+
if (!looksMinified(path, content))
|
|
36
|
+
continue;
|
|
37
|
+
out.push({ path, hasProvenanceBanner: PROVENANCE_BANNER_RE.test(content.slice(0, 2000)) });
|
|
38
|
+
}
|
|
39
|
+
return out.sort((a, b) => a.path.localeCompare(b.path));
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=amo-source-detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amo-source-detect.js","sourceRoot":"","sources":["../src/amo-source-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,GAAG,kBAAkB,CAAA;AACtC,MAAM,eAAe,GAAG,uBAAuB,CAAA;AAE/C;;;;;;GAMG;AACH,MAAM,oBAAoB,GAAG,mEAAmE,CAAA;AAQhG,SAAS,aAAa,CAAC,IAAY,EAAE,OAAe;IACnD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IACzC,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAC3C,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI;QAAE,OAAO,KAAK,CAAA;IACnD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACjC,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAA;IACxE,OAAO,WAAW,GAAG,GAAG,IAAI,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,GAAG,CAAA;AAChE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAc;IACjD,MAAM,GAAG,GAA0B,EAAE,CAAA;IACrC,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,EAAE,CAAC;QACrC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC;YAAE,SAAQ;QAC3C,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAA;IAC3F,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;AACxD,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `extenshi amo-source <project-dir> [--out <path>]` — produce the AMO
|
|
3
|
+
* source-code archive + BUILD.md reviewer instructions.
|
|
4
|
+
*
|
|
5
|
+
* AMO requires reviewable source for any minified/bundled/transpiled code so a
|
|
6
|
+
* reviewer can rebuild the extension and diff it against the submitted
|
|
7
|
+
* package: https://extensionworkshop.com/documentation/publish/source-code-submission/
|
|
8
|
+
*
|
|
9
|
+
* This command does NOT run the build itself and does NOT talk to AMO's API
|
|
10
|
+
* (that is `publisher/src/services/firefox.ts`, owned separately). It only:
|
|
11
|
+
* 1. archives the project's tracked-looking source (excluding node_modules,
|
|
12
|
+
* dist, .git, dotenv secrets, and any top-level directory the project's
|
|
13
|
+
* own .gitignore names plainly — e.g. `dist-firefox/`, `dist-edge/`),
|
|
14
|
+
* 2. writes BUILD.md with the exact commands a reviewer needs (Node/npm
|
|
15
|
+
* versions, package manager + lockfile, the build script from
|
|
16
|
+
* package.json), and
|
|
17
|
+
* 3. flags vendored minified files that carry no reproducible-build
|
|
18
|
+
* provenance as BLOCKERS — the developer must vendor their source (e.g.
|
|
19
|
+
* under vendor-src/) before submitting.
|
|
20
|
+
*
|
|
21
|
+
* If the project directory is a clean git working tree, the archive is
|
|
22
|
+
* refused when there are uncommitted changes (matching the pattern this repo
|
|
23
|
+
* already uses for its own extension projects) — the archive should match a
|
|
24
|
+
* commit a reviewer can also check out. A directory that is not a git repo at
|
|
25
|
+
* all is archived as-is; there is nothing to compare it against.
|
|
26
|
+
*/
|
|
27
|
+
import { type MinifiedFileFinding } from './amo-source-detect.js';
|
|
28
|
+
export interface AmoSourceOptions {
|
|
29
|
+
projectDir: string;
|
|
30
|
+
/** Where to write the archive. Default: `amo-source.zip` in the current directory. */
|
|
31
|
+
outputPath?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface AmoSourceResult {
|
|
34
|
+
zipPath: string;
|
|
35
|
+
buildMdPath: string;
|
|
36
|
+
fileCount: number;
|
|
37
|
+
blockers: MinifiedFileFinding[];
|
|
38
|
+
reproducible: MinifiedFileFinding[];
|
|
39
|
+
}
|
|
40
|
+
export declare function runAmoSource(opts: AmoSourceOptions): Promise<AmoSourceResult>;
|
|
41
|
+
//# sourceMappingURL=amo-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amo-source.d.ts","sourceRoot":"","sources":["../src/amo-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,OAAO,EAAuB,KAAK,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAsDtF,MAAM,WAAW,gBAAgB;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,mBAAmB,EAAE,CAAA;IAC/B,YAAY,EAAE,mBAAmB,EAAE,CAAA;CACnC;AAyJD,wBAAsB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAuCnF"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `extenshi amo-source <project-dir> [--out <path>]` — produce the AMO
|
|
3
|
+
* source-code archive + BUILD.md reviewer instructions.
|
|
4
|
+
*
|
|
5
|
+
* AMO requires reviewable source for any minified/bundled/transpiled code so a
|
|
6
|
+
* reviewer can rebuild the extension and diff it against the submitted
|
|
7
|
+
* package: https://extensionworkshop.com/documentation/publish/source-code-submission/
|
|
8
|
+
*
|
|
9
|
+
* This command does NOT run the build itself and does NOT talk to AMO's API
|
|
10
|
+
* (that is `publisher/src/services/firefox.ts`, owned separately). It only:
|
|
11
|
+
* 1. archives the project's tracked-looking source (excluding node_modules,
|
|
12
|
+
* dist, .git, dotenv secrets, and any top-level directory the project's
|
|
13
|
+
* own .gitignore names plainly — e.g. `dist-firefox/`, `dist-edge/`),
|
|
14
|
+
* 2. writes BUILD.md with the exact commands a reviewer needs (Node/npm
|
|
15
|
+
* versions, package manager + lockfile, the build script from
|
|
16
|
+
* package.json), and
|
|
17
|
+
* 3. flags vendored minified files that carry no reproducible-build
|
|
18
|
+
* provenance as BLOCKERS — the developer must vendor their source (e.g.
|
|
19
|
+
* under vendor-src/) before submitting.
|
|
20
|
+
*
|
|
21
|
+
* If the project directory is a clean git working tree, the archive is
|
|
22
|
+
* refused when there are uncommitted changes (matching the pattern this repo
|
|
23
|
+
* already uses for its own extension projects) — the archive should match a
|
|
24
|
+
* commit a reviewer can also check out. A directory that is not a git repo at
|
|
25
|
+
* all is archived as-is; there is nothing to compare it against.
|
|
26
|
+
*/
|
|
27
|
+
import { execFileSync } from 'node:child_process';
|
|
28
|
+
import fs from 'node:fs';
|
|
29
|
+
import path from 'node:path';
|
|
30
|
+
import JSZip from 'jszip';
|
|
31
|
+
import { detectMinifiedFiles } from './amo-source-detect.js';
|
|
32
|
+
const BASE_EXCLUDE_DIRS = new Set([
|
|
33
|
+
'node_modules',
|
|
34
|
+
'.git',
|
|
35
|
+
'dist',
|
|
36
|
+
'build',
|
|
37
|
+
'.turbo',
|
|
38
|
+
'.cache',
|
|
39
|
+
'coverage',
|
|
40
|
+
'.yarn',
|
|
41
|
+
'.next',
|
|
42
|
+
]);
|
|
43
|
+
const ENV_FILE_RE = /^\.env(\..+)?$/i;
|
|
44
|
+
// A plain top-level directory ignore line: letters/digits/-/_/. only, no
|
|
45
|
+
// globs, no nested path, optional trailing slash. Anything more complex
|
|
46
|
+
// (negations, globs, nested paths) is skipped rather than mis-handled — this
|
|
47
|
+
// is a heuristic, not a gitignore engine, and under-excluding is the safer
|
|
48
|
+
// failure mode (a developer notices an oversized archive; over-excluding
|
|
49
|
+
// silently drops source AMO needed).
|
|
50
|
+
const SIMPLE_GITIGNORE_DIR_RE = /^([\w.-]+)\/?$/;
|
|
51
|
+
/**
|
|
52
|
+
* Fold a project's own top-level `.gitignore` build-output directories into
|
|
53
|
+
* the exclude set — `dist-firefox/`, `dist-edge/` etc. are exactly the kind
|
|
54
|
+
* of committed-for-CI build output that should never end up in a "source"
|
|
55
|
+
* archive, and there is no way to enumerate every project's naming scheme in
|
|
56
|
+
* a fixed list.
|
|
57
|
+
*/
|
|
58
|
+
function additionalExcludeDirs(projectDir) {
|
|
59
|
+
const extra = new Set();
|
|
60
|
+
let raw;
|
|
61
|
+
try {
|
|
62
|
+
raw = fs.readFileSync(path.join(projectDir, '.gitignore'), 'utf8');
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return extra;
|
|
66
|
+
}
|
|
67
|
+
for (const line of raw.split('\n')) {
|
|
68
|
+
const trimmed = line.trim();
|
|
69
|
+
if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('!'))
|
|
70
|
+
continue;
|
|
71
|
+
const m = SIMPLE_GITIGNORE_DIR_RE.exec(trimmed);
|
|
72
|
+
if (m)
|
|
73
|
+
extra.add(m[1]);
|
|
74
|
+
}
|
|
75
|
+
return extra;
|
|
76
|
+
}
|
|
77
|
+
const TEXT_CODE_RE = /\.(?:m?js|cjs)$/i;
|
|
78
|
+
const MAX_FILE_BYTES = 25 * 1024 * 1024;
|
|
79
|
+
const LOCKFILES = [
|
|
80
|
+
{ file: 'package-lock.json', manager: 'npm', installCmd: 'npm ci' },
|
|
81
|
+
{ file: 'yarn.lock', manager: 'yarn', installCmd: 'yarn install --immutable' },
|
|
82
|
+
{ file: 'pnpm-lock.yaml', manager: 'pnpm', installCmd: 'pnpm install --frozen-lockfile' },
|
|
83
|
+
];
|
|
84
|
+
function isGitClean(cwd) {
|
|
85
|
+
const git = (...args) => execFileSync('git', args, { cwd, stdio: ['ignore', 'pipe', 'ignore'] })
|
|
86
|
+
.toString()
|
|
87
|
+
.trim();
|
|
88
|
+
try {
|
|
89
|
+
git('rev-parse', '--is-inside-work-tree');
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return { isRepo: false, clean: true };
|
|
93
|
+
}
|
|
94
|
+
const status = git('status', '--porcelain', '--', '.');
|
|
95
|
+
let commit;
|
|
96
|
+
try {
|
|
97
|
+
commit = git('rev-parse', 'HEAD');
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// No commits yet — still archivable, just nothing to diff against.
|
|
101
|
+
}
|
|
102
|
+
return { isRepo: true, clean: status.length === 0, commit };
|
|
103
|
+
}
|
|
104
|
+
function readPackageJson(projectDir) {
|
|
105
|
+
try {
|
|
106
|
+
const raw = fs.readFileSync(path.join(projectDir, 'package.json'), 'utf8');
|
|
107
|
+
return JSON.parse(raw);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return {};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function detectLockfile(projectDir) {
|
|
114
|
+
return LOCKFILES.find((l) => fs.existsSync(path.join(projectDir, l.file)));
|
|
115
|
+
}
|
|
116
|
+
function npmVersion() {
|
|
117
|
+
try {
|
|
118
|
+
return execFileSync('npm', ['--version'], { stdio: ['ignore', 'pipe', 'ignore'] })
|
|
119
|
+
.toString()
|
|
120
|
+
.trim();
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function walkProject(projectDir, outputAbsPath) {
|
|
127
|
+
const zip = new JSZip();
|
|
128
|
+
const textFiles = new Map();
|
|
129
|
+
let fileCount = 0;
|
|
130
|
+
const excludeDirs = new Set([...BASE_EXCLUDE_DIRS, ...additionalExcludeDirs(projectDir)]);
|
|
131
|
+
const walk = (dir) => {
|
|
132
|
+
for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
133
|
+
const full = path.join(dir, ent.name);
|
|
134
|
+
if (path.resolve(full) === path.resolve(outputAbsPath))
|
|
135
|
+
continue; // never zip ourselves
|
|
136
|
+
if (ent.isDirectory()) {
|
|
137
|
+
if (excludeDirs.has(ent.name))
|
|
138
|
+
continue;
|
|
139
|
+
walk(full);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (!ent.isFile())
|
|
143
|
+
continue;
|
|
144
|
+
if (ENV_FILE_RE.test(ent.name))
|
|
145
|
+
continue;
|
|
146
|
+
const stat = fs.statSync(full);
|
|
147
|
+
if (stat.size > MAX_FILE_BYTES)
|
|
148
|
+
continue;
|
|
149
|
+
const rel = path.relative(projectDir, full).split(path.sep).join('/');
|
|
150
|
+
const buf = fs.readFileSync(full);
|
|
151
|
+
zip.file(rel, buf);
|
|
152
|
+
fileCount++;
|
|
153
|
+
if (TEXT_CODE_RE.test(ent.name)) {
|
|
154
|
+
try {
|
|
155
|
+
textFiles.set(rel, buf.toString('utf8'));
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
// Binary content that happened to match the extension — skip minification scan for it.
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
walk(projectDir);
|
|
164
|
+
return { zip, textFiles, fileCount };
|
|
165
|
+
}
|
|
166
|
+
function renderBuildMd(input) {
|
|
167
|
+
const installCmd = input.lockfile?.installCmd ?? 'npm install';
|
|
168
|
+
const buildCmd = input.buildScript ? `npm run ${input.buildScript}` : undefined;
|
|
169
|
+
const commands = [installCmd, buildCmd].filter((c) => Boolean(c));
|
|
170
|
+
const blockersBlock = input.blockers.length === 0
|
|
171
|
+
? '_None detected._'
|
|
172
|
+
: input.blockers
|
|
173
|
+
.map((f) => `- \`${f.path}\` — no reproducible-build banner found. Vendor its pre-minification source (e.g. under \`vendor-src/\`), add a build script that reproduces it byte-for-byte, and document the exact command here.`)
|
|
174
|
+
.join('\n');
|
|
175
|
+
const reproducibleBlock = input.reproducible.length === 0
|
|
176
|
+
? ''
|
|
177
|
+
: `\n## Vendored bundles with a provenance banner\n\n${input.reproducible
|
|
178
|
+
.map((f) => `- \`${f.path}\` — declares its own version/commit/build command in a header comment.`)
|
|
179
|
+
.join('\n')}\n`;
|
|
180
|
+
return `# Source code for AMO review
|
|
181
|
+
|
|
182
|
+
Upload the sibling \`.zip\` in AMO's "Source code" step, and paste the section
|
|
183
|
+
below into the reviewer notes (or attach this file directly if AMO's form
|
|
184
|
+
allows a file upload for build instructions).
|
|
185
|
+
|
|
186
|
+
## Build instructions for reviewers
|
|
187
|
+
|
|
188
|
+
Requirements:
|
|
189
|
+
- Node.js ${input.nodeVersion}${input.npmVersion ? `, npm ${input.npmVersion}` : ''}${input.lockfile ? ` (${input.lockfile.manager}, lockfile included)` : ' (no lockfile found — pin your own versions here)'}
|
|
190
|
+
|
|
191
|
+
\`\`\`sh
|
|
192
|
+
${commands.length > 0 ? commands.join('\n') : '# No install/build script detected in package.json — fill in the exact commands here.'}
|
|
193
|
+
\`\`\`
|
|
194
|
+
|
|
195
|
+
${input.commit ? `Archived from commit \`${input.commit}\`.` : 'Archived from an uncommitted directory (not a git repository, or no commits yet) — there is no commit to diff against.'}
|
|
196
|
+
|
|
197
|
+
## Files that need a source-code submission
|
|
198
|
+
|
|
199
|
+
${blockersBlock}
|
|
200
|
+
${reproducibleBlock}
|
|
201
|
+
## web-ext lint
|
|
202
|
+
|
|
203
|
+
Run \`npx web-ext@10 lint --source-dir <built-output>\` and confirm 0 errors
|
|
204
|
+
before submitting — see
|
|
205
|
+
https://extensionworkshop.com/documentation/develop/web-ext-command-reference/
|
|
206
|
+
`;
|
|
207
|
+
}
|
|
208
|
+
export async function runAmoSource(opts) {
|
|
209
|
+
const projectDir = path.resolve(opts.projectDir);
|
|
210
|
+
if (!fs.existsSync(projectDir) || !fs.statSync(projectDir).isDirectory()) {
|
|
211
|
+
throw new Error(`Project directory not found: ${projectDir}`);
|
|
212
|
+
}
|
|
213
|
+
const git = isGitClean(projectDir);
|
|
214
|
+
if (git.isRepo && !git.clean) {
|
|
215
|
+
throw new Error(`${projectDir} has uncommitted changes. Commit first — the source archive should match a commit a reviewer can also check out.`);
|
|
216
|
+
}
|
|
217
|
+
const zipPath = path.resolve(opts.outputPath ?? 'amo-source.zip');
|
|
218
|
+
const buildMdPath = path.join(path.dirname(zipPath), 'BUILD.md');
|
|
219
|
+
const { zip, textFiles, fileCount } = walkProject(projectDir, zipPath);
|
|
220
|
+
const minified = detectMinifiedFiles(textFiles);
|
|
221
|
+
const blockers = minified.filter((f) => !f.hasProvenanceBanner);
|
|
222
|
+
const reproducible = minified.filter((f) => f.hasProvenanceBanner);
|
|
223
|
+
const pkg = readPackageJson(projectDir);
|
|
224
|
+
const buildMd = renderBuildMd({
|
|
225
|
+
projectDir,
|
|
226
|
+
commit: git.commit,
|
|
227
|
+
nodeVersion: pkg.engines?.node ?? process.version,
|
|
228
|
+
npmVersion: pkg.engines?.npm ?? npmVersion(),
|
|
229
|
+
lockfile: detectLockfile(projectDir),
|
|
230
|
+
buildScript: pkg.scripts?.build ? 'build' : undefined,
|
|
231
|
+
blockers,
|
|
232
|
+
reproducible,
|
|
233
|
+
});
|
|
234
|
+
fs.mkdirSync(path.dirname(zipPath), { recursive: true });
|
|
235
|
+
const buf = await zip.generateAsync({ type: 'nodebuffer', compression: 'DEFLATE' });
|
|
236
|
+
fs.writeFileSync(zipPath, buf);
|
|
237
|
+
fs.writeFileSync(buildMdPath, buildMd, 'utf8');
|
|
238
|
+
return { zipPath, buildMdPath, fileCount, blockers, reproducible };
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=amo-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amo-source.js","sourceRoot":"","sources":["../src/amo-source.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AMO.md — Mozilla Add-ons (addons.mozilla.org) listing draft
|
|
3
|
+
* (`extenshi generate-listing --store firefox`).
|
|
4
|
+
*
|
|
5
|
+
* Shares the Name / Short description / Description / Single purpose
|
|
6
|
+
* headings with CHROMEWEBSTORE.md on purpose — `review-risk --listing AMO.md`
|
|
7
|
+
* parses it through the same `listingDraftFromChromeWebStoreMd` heading
|
|
8
|
+
* lookup.
|
|
9
|
+
*
|
|
10
|
+
* Sources:
|
|
11
|
+
* - gecko.id / strict_min_version: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_specific_settings
|
|
12
|
+
* - data_collection_permissions (mandatory for new submissions since 2025-11-03):
|
|
13
|
+
* https://extensionworkshop.com/documentation/develop/firefox-builtin-data-consent/
|
|
14
|
+
* - source-code submission for minified/bundled files:
|
|
15
|
+
* https://extensionworkshop.com/documentation/publish/source-code-submission/
|
|
16
|
+
* - listing best practices (summary ≤250 chars, categories, support):
|
|
17
|
+
* https://extensionworkshop.com/documentation/develop/create-an-appealing-listing/
|
|
18
|
+
*/
|
|
19
|
+
import type { MinifiedFileFinding } from './amo-source-detect.js';
|
|
20
|
+
import type { Listing } from './listing.js';
|
|
21
|
+
export declare const AMO_FILENAME = "AMO.md";
|
|
22
|
+
export interface AmoGeckoInfo {
|
|
23
|
+
id?: string;
|
|
24
|
+
isPlaceholder?: boolean;
|
|
25
|
+
strictMinVersion?: string;
|
|
26
|
+
dataCollectionRequired?: string[];
|
|
27
|
+
}
|
|
28
|
+
export declare function renderAmoMd(input: {
|
|
29
|
+
listing: Listing | null;
|
|
30
|
+
justifications?: readonly {
|
|
31
|
+
permission: string;
|
|
32
|
+
prompt: string;
|
|
33
|
+
}[];
|
|
34
|
+
singlePurpose?: string;
|
|
35
|
+
gecko?: AmoGeckoInfo;
|
|
36
|
+
minifiedFiles?: readonly MinifiedFileFinding[];
|
|
37
|
+
}): string;
|
|
38
|
+
//# sourceMappingURL=amowebstore-md.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amowebstore-md.d.ts","sourceRoot":"","sources":["../src/amowebstore-md.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE3C,eAAO,MAAM,YAAY,WAAW,CAAA;AAEpC,MAAM,WAAW,YAAY;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAA;CACjC;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE;IAClC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IACvB,cAAc,CAAC,EAAE,SAAS;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAClE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,CAAC,EAAE,YAAY,CAAA;IACpB,aAAa,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAA;CAC9C,GAAG,MAAM,CA4GT"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AMO.md — Mozilla Add-ons (addons.mozilla.org) listing draft
|
|
3
|
+
* (`extenshi generate-listing --store firefox`).
|
|
4
|
+
*
|
|
5
|
+
* Shares the Name / Short description / Description / Single purpose
|
|
6
|
+
* headings with CHROMEWEBSTORE.md on purpose — `review-risk --listing AMO.md`
|
|
7
|
+
* parses it through the same `listingDraftFromChromeWebStoreMd` heading
|
|
8
|
+
* lookup.
|
|
9
|
+
*
|
|
10
|
+
* Sources:
|
|
11
|
+
* - gecko.id / strict_min_version: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_specific_settings
|
|
12
|
+
* - data_collection_permissions (mandatory for new submissions since 2025-11-03):
|
|
13
|
+
* https://extensionworkshop.com/documentation/develop/firefox-builtin-data-consent/
|
|
14
|
+
* - source-code submission for minified/bundled files:
|
|
15
|
+
* https://extensionworkshop.com/documentation/publish/source-code-submission/
|
|
16
|
+
* - listing best practices (summary ≤250 chars, categories, support):
|
|
17
|
+
* https://extensionworkshop.com/documentation/develop/create-an-appealing-listing/
|
|
18
|
+
*/
|
|
19
|
+
export const AMO_FILENAME = 'AMO.md';
|
|
20
|
+
export function renderAmoMd(input) {
|
|
21
|
+
const loc = input.listing?.locales.find((l) => l.locale === input.listing?.defaultLocale) ?? input.listing?.locales[0];
|
|
22
|
+
const justifications = input.justifications ?? [];
|
|
23
|
+
const justBlock = justifications.length === 0
|
|
24
|
+
? '_No sensitive permissions need a reviewer justification yet._'
|
|
25
|
+
: justifications.map((j) => `### ${j.permission}\n\n${j.prompt}`).join('\n\n');
|
|
26
|
+
const gecko = input.gecko ?? {};
|
|
27
|
+
const geckoIdLine = !gecko.id
|
|
28
|
+
? '**NOT SET** — required to sign a Manifest V3 add-on. Add `browser_specific_settings.gecko.id` (e.g. `@your-extension-name` or a GUID); once published, treat it as permanent.'
|
|
29
|
+
: gecko.isPlaceholder
|
|
30
|
+
? `\`${gecko.id}\` — **this looks like a template placeholder.** Replace it before the first AMO upload.`
|
|
31
|
+
: `\`${gecko.id}\``;
|
|
32
|
+
const strictMinLine = gecko.strictMinVersion
|
|
33
|
+
? `\`${gecko.strictMinVersion}\``
|
|
34
|
+
: 'not set — recommended so `web-ext lint` can flag manifest keys/APIs unavailable on older Firefox.';
|
|
35
|
+
const dataCollectionLine = gecko.dataCollectionRequired && gecko.dataCollectionRequired.length > 0
|
|
36
|
+
? `\`${JSON.stringify(gecko.dataCollectionRequired)}\``
|
|
37
|
+
: '**NOT SET** — required for new add-ons submitted to AMO since 2025-11-03. Set `data_collection_permissions.required` to `["none"]` if nothing is collected, or list the categories collected.';
|
|
38
|
+
const minified = input.minifiedFiles ?? [];
|
|
39
|
+
const sourceBlock = minified.length === 0
|
|
40
|
+
? '_No minified/bundled files detected (filename or size/pattern heuristic) — re-check after adding a bundler._'
|
|
41
|
+
: minified
|
|
42
|
+
.map((f) => f.hasProvenanceBanner
|
|
43
|
+
? `- \`${f.path}\` — carries a version/commit/build-command banner. Still upload the source archive; the banner tells the reviewer how to rebuild it, it is not a substitute.`
|
|
44
|
+
: `- \`${f.path}\` — **BLOCKER**: no reproducible-build banner found. Vendor the pre-minification source (e.g. under \`vendor-src/\`) and document the exact build command, or run \`extenshi amo-source\` to generate the archive + BUILD.md.`)
|
|
45
|
+
.join('\n');
|
|
46
|
+
return `# AMO.md
|
|
47
|
+
|
|
48
|
+
Mozilla Add-ons (AMO) listing draft. This is the same listing draft
|
|
49
|
+
\`review-risk --listing\` already accepts as JSON or CHROMEWEBSTORE.md — run:
|
|
50
|
+
|
|
51
|
+
\`npx @extenshi/cli@latest review-risk --listing AMO.md\`
|
|
52
|
+
|
|
53
|
+
Do not paste this into the AMO submission form automatically. Fill it by hand.
|
|
54
|
+
Submit at https://addons.mozilla.org/developers/ → Submit a New Add-on.
|
|
55
|
+
|
|
56
|
+
## Name
|
|
57
|
+
|
|
58
|
+
${loc?.name ?? ''}
|
|
59
|
+
|
|
60
|
+
_AMO has no hard character cap on the name, but keep it short — long names truncate in search results._
|
|
61
|
+
|
|
62
|
+
## Short description
|
|
63
|
+
|
|
64
|
+
${loc?.shortDescription ?? ''}
|
|
65
|
+
|
|
66
|
+
_This is AMO's "summary" field — hard-capped at 250 characters._
|
|
67
|
+
|
|
68
|
+
## Description
|
|
69
|
+
|
|
70
|
+
${loc?.description ?? ''}
|
|
71
|
+
|
|
72
|
+
## Add-on ID (browser_specific_settings.gecko.id)
|
|
73
|
+
|
|
74
|
+
${geckoIdLine}
|
|
75
|
+
|
|
76
|
+
## Minimum Firefox version (strict_min_version)
|
|
77
|
+
|
|
78
|
+
${strictMinLine}
|
|
79
|
+
|
|
80
|
+
## Data collection permissions
|
|
81
|
+
|
|
82
|
+
${dataCollectionLine}
|
|
83
|
+
|
|
84
|
+
## Source code
|
|
85
|
+
|
|
86
|
+
${sourceBlock}
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
_e.g. MIT, GPL-3.0 — AMO publishes the chosen license alongside the add-on._
|
|
91
|
+
|
|
92
|
+
## Categories
|
|
93
|
+
|
|
94
|
+
_Up to 2, e.g. "Appearance", "Other"._
|
|
95
|
+
|
|
96
|
+
## Support
|
|
97
|
+
|
|
98
|
+
- Support email: _required or strongly recommended — users hit a dead end without one_
|
|
99
|
+
- Support website / homepage: _optional_
|
|
100
|
+
|
|
101
|
+
## Single purpose
|
|
102
|
+
|
|
103
|
+
${input.singlePurpose ?? loc?.shortDescription ?? loc?.name ?? ''}
|
|
104
|
+
|
|
105
|
+
## Permission justifications
|
|
106
|
+
|
|
107
|
+
${justBlock}
|
|
108
|
+
|
|
109
|
+
## Notes to reviewer
|
|
110
|
+
|
|
111
|
+
_Test accounts, steps to reach gated/paid features, and a plain-language pointer to the "Source code" section above if any file needs it._
|
|
112
|
+
|
|
113
|
+
## Version history
|
|
114
|
+
|
|
115
|
+
_Record each upload: version, what changed, why._
|
|
116
|
+
`;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=amowebstore-md.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amowebstore-md.js","sourceRoot":"","sources":["../src/amowebstore-md.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,MAAM,CAAC,MAAM,YAAY,GAAG,QAAQ,CAAA;AASpC,MAAM,UAAU,WAAW,CAAC,KAM3B;IACA,MAAM,GAAG,GACR,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,KAAK,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IAC3G,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,IAAI,EAAE,CAAA;IACjD,MAAM,SAAS,GACd,cAAc,CAAC,MAAM,KAAK,CAAC;QAC1B,CAAC,CAAC,+DAA+D;QACjE,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,UAAU,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAEhF,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,EAAE,CAAA;IAC/B,MAAM,WAAW,GAAG,CAAC,KAAK,CAAC,EAAE;QAC5B,CAAC,CAAC,+KAA+K;QACjL,CAAC,CAAC,KAAK,CAAC,aAAa;YACpB,CAAC,CAAC,KAAK,KAAK,CAAC,EAAE,0FAA0F;YACzG,CAAC,CAAC,KAAK,KAAK,CAAC,EAAE,IAAI,CAAA;IAErB,MAAM,aAAa,GAAG,KAAK,CAAC,gBAAgB;QAC3C,CAAC,CAAC,KAAK,KAAK,CAAC,gBAAgB,IAAI;QACjC,CAAC,CAAC,mGAAmG,CAAA;IAEtG,MAAM,kBAAkB,GACvB,KAAK,CAAC,sBAAsB,IAAI,KAAK,CAAC,sBAAsB,CAAC,MAAM,GAAG,CAAC;QACtE,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,sBAAsB,CAAC,IAAI;QACvD,CAAC,CAAC,+LAA+L,CAAA;IAEnM,MAAM,QAAQ,GAAG,KAAK,CAAC,aAAa,IAAI,EAAE,CAAA;IAC1C,MAAM,WAAW,GAChB,QAAQ,CAAC,MAAM,KAAK,CAAC;QACpB,CAAC,CAAC,8GAA8G;QAChH,CAAC,CAAC,QAAQ;aACP,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACV,CAAC,CAAC,mBAAmB;YACpB,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,+JAA+J;YAC9K,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,gOAAgO,CAChP;aACA,IAAI,CAAC,IAAI,CAAC,CAAA;IAEf,OAAO;;;;;;;;;;;;EAYN,GAAG,EAAE,IAAI,IAAI,EAAE;;;;;;EAMf,GAAG,EAAE,gBAAgB,IAAI,EAAE;;;;;;EAM3B,GAAG,EAAE,WAAW,IAAI,EAAE;;;;EAItB,WAAW;;;;EAIX,aAAa;;;;EAIb,kBAAkB;;;;EAIlB,WAAW;;;;;;;;;;;;;;;;;EAiBX,KAAK,CAAC,aAAa,IAAI,GAAG,EAAE,gBAAgB,IAAI,GAAG,EAAE,IAAI,IAAI,EAAE;;;;EAI/D,SAAS;;;;;;;;;CASV,CAAA;AACD,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `--evidence` on `scan`, `review-risk`, `generate-listing` and `test smoke`:
|
|
3
|
+
* turn the result the command just computed into the readiness evidence kind it
|
|
4
|
+
* attests, with the digests `releaseReadiness` matches against, and record it for
|
|
5
|
+
* the project bound in this directory — through the same client path as
|
|
6
|
+
* `extenshi evidence push` (project.ts → recordAgentEvidence).
|
|
7
|
+
*
|
|
8
|
+
* The digests are the contract (shared-types/project-workspace.ts
|
|
9
|
+
* `releaseReadiness`):
|
|
10
|
+
*
|
|
11
|
+
* kind artifactDigest inputDigest locale
|
|
12
|
+
* scan sha256(zip) sha256(zip) —
|
|
13
|
+
* installed sha256(zip) sha256(zip) —
|
|
14
|
+
* permissions sha256(zip) hashMetadata(packaged manifest) —
|
|
15
|
+
* listing sha256(zip) sha256(listing file bytes) each locale
|
|
16
|
+
*
|
|
17
|
+
* `hashMetadata(manifest)` is what `release prepare` stores as manifestDigest,
|
|
18
|
+
* and `sha256(listing file)` is what `release prepare --listing <file>` stores as
|
|
19
|
+
* listingDigest — so evidence recorded here is current exactly when the release
|
|
20
|
+
* binds the same package and the same listing file.
|
|
21
|
+
*
|
|
22
|
+
* Status rules (documented in the CLI docs):
|
|
23
|
+
* scan failed on a REJECTION_LIKELY store-compliance finding or any
|
|
24
|
+
* CRITICAL security finding — the report's own "fail" verdict.
|
|
25
|
+
* permissions failed on a REJECTED review-risk finding outside the listing rules.
|
|
26
|
+
* listing failed only on a REJECTED listing-rule finding for that locale —
|
|
27
|
+
* exactly what would make `review-risk` exit non-zero. Listing rules
|
|
28
|
+
* are ADVISORY by roadmap policy (iteration 2 T9: the v3 dictionary
|
|
29
|
+
* measured a 78.7% false-positive rate) and never fail review-risk,
|
|
30
|
+
* so failing readiness on them would block releases on false
|
|
31
|
+
* positives. An advisory finding leaves the check `passed`.
|
|
32
|
+
* installed the smoke result.
|
|
33
|
+
*
|
|
34
|
+
* `permissions` and `listing` carry a `summary` (finding count, blocking count,
|
|
35
|
+
* distinct check ids) so the advisories behind a `passed` stay visible to
|
|
36
|
+
* whoever reads the record. It is sent only to a server that advertises it
|
|
37
|
+
* (project.ts → recordAgentEvidence).
|
|
38
|
+
*/
|
|
39
|
+
import { type Listing } from './listing.js';
|
|
40
|
+
import type { EvidenceRecord } from './project.js';
|
|
41
|
+
import { type ReviewFinding } from './review-checks.js';
|
|
42
|
+
import type { SmokeResult } from './smoke.js';
|
|
43
|
+
export type EvidenceBrowser = 'chrome' | 'edge' | 'firefox';
|
|
44
|
+
export declare const sha256Hex: (bytes: Uint8Array | string) => string;
|
|
45
|
+
/**
|
|
46
|
+
* Which store(s) the evidence is for: the explicit list, else the browsers
|
|
47
|
+
* `extenshi package` recorded for these exact bytes (Chrome and Edge built from
|
|
48
|
+
* one directory are the same zip), else refuse — mislabelled evidence would
|
|
49
|
+
* satisfy the wrong release.
|
|
50
|
+
*/
|
|
51
|
+
export declare function evidenceBrowsers(artifactPath: string, artifactDigest: string, explicit?: string): EvidenceBrowser[];
|
|
52
|
+
export declare function scanEvidence(input: {
|
|
53
|
+
artifactDigest: string;
|
|
54
|
+
browsers: EvidenceBrowser[];
|
|
55
|
+
body: Record<string, unknown>;
|
|
56
|
+
}): EvidenceRecord[];
|
|
57
|
+
export declare function smokeEvidence(input: {
|
|
58
|
+
browser: EvidenceBrowser;
|
|
59
|
+
result: SmokeResult;
|
|
60
|
+
}): EvidenceRecord[];
|
|
61
|
+
type EvidenceSummary = NonNullable<EvidenceRecord['summary']>;
|
|
62
|
+
/** Counts and distinct check ids — never finding text, which can quote listing copy or code. */
|
|
63
|
+
export declare function findingSummary(findings: readonly ReviewFinding[]): EvidenceSummary;
|
|
64
|
+
export declare function permissionsEvidence(input: {
|
|
65
|
+
artifactDigest: string;
|
|
66
|
+
manifest: unknown;
|
|
67
|
+
browsers: EvidenceBrowser[];
|
|
68
|
+
findings: readonly ReviewFinding[];
|
|
69
|
+
listingCheckIds: ReadonlySet<string>;
|
|
70
|
+
}): EvidenceRecord[];
|
|
71
|
+
/** Listing findings carry `[locale] field…` evidence; one without a locale applies to every locale. */
|
|
72
|
+
export declare function findingLocale(finding: ReviewFinding): string | null;
|
|
73
|
+
export declare function listingEvidence(input: {
|
|
74
|
+
artifactDigest: string;
|
|
75
|
+
listingBytes: Uint8Array | string;
|
|
76
|
+
listing: Listing | null;
|
|
77
|
+
browsers: EvidenceBrowser[];
|
|
78
|
+
/** Output of runListingOnlyChecks for the same listing. */
|
|
79
|
+
listingFindings: readonly ReviewFinding[];
|
|
80
|
+
}): EvidenceRecord[];
|
|
81
|
+
/**
|
|
82
|
+
* `generate-listing --evidence`: read the draft the command just wrote
|
|
83
|
+
* (CHROMEWEBSTORE.md, EDGE.md or AMO.md — one parser, keyed on headings) back
|
|
84
|
+
* over the package, run the listing rules on it and bind the evidence to that
|
|
85
|
+
* file's bytes. `browsers` is the store the draft is for.
|
|
86
|
+
*/
|
|
87
|
+
export declare function generatedListingEvidence(input: {
|
|
88
|
+
artifactBytes: Buffer;
|
|
89
|
+
artifactDigest: string;
|
|
90
|
+
draftPath: string;
|
|
91
|
+
browsers: EvidenceBrowser[];
|
|
92
|
+
}): Promise<EvidenceRecord[]>;
|
|
93
|
+
/**
|
|
94
|
+
* Record the batch for the bound project and say so on stderr (stdout stays the
|
|
95
|
+
* command's own output, e.g. --json). A queued (offline) record sets exit code 1
|
|
96
|
+
* like `evidence push`; any other failure throws — the caller asked for evidence.
|
|
97
|
+
*/
|
|
98
|
+
export declare function recordAutoEvidence(records: EvidenceRecord[], cwd?: string): Promise<void>;
|
|
99
|
+
export {};
|
|
100
|
+
//# sourceMappingURL=auto-evidence.d.ts.map
|