import { spawnSync } from "node:child_process"; import { createHmac, createVerify, generateKeyPairSync } from "node:crypto"; import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { describe, expect, test } from "bun:test"; import { amoUploadReady, amoValidationErrors, assertCredentials, assertOfficialRepository, assertIdenticalBuildDirectories, buildApprovalNotes, chromeSubmissionPlan, chromeUploadFinished, compareVersions, copySourceArchive, createAmoJwt, createChromeClient, createFirefoxClient, createGoogleServiceAccountAssertion, credentialPresence, firefoxSubmissionPlan, formatSubmissionReport, redactDiagnostics, runSubmissionStage, FIREFOX_LICENSE_SLUG, highestCrxVersion, OFFICIAL_REPOSITORY, parsePublishArgs, resolveReleaseNotes, shouldCopyExtensionSource, SHARED_EXTENSION_SOURCE_FILES, sourceRebuildEnvironment, submitChrome, submitFirefox, workspacePackageManifests, } from "./publish-web-clipper.mjs"; const workflow = readFileSync( new URL("../.github/workflows/extension-store.yml", import.meta.url), "utf8", ); describe("web clipper store command", () => { test("reports HTTP field errors, nested details and status without leaking credentials", async () => { const client = createChromeClient({ accessToken: "private-access", fetchImpl: async () => ({ ok: false, status: 400, text: async () => JSON.stringify({ error: { code: 400, status: "INVALID_ARGUMENT", message: "Requirements missing", details: [{ fieldViolations: [{ field: "privacy", description: "Justify declarativeNetRequestWithHostAccess" }] }], access_token: "private-access", } }), }) }); let failure; try { await runSubmissionStage("chrome.publish", () => client.publish()); } catch (error) { failure = error; } const report = formatSubmissionReport("0.2.0", [["Chrome", { action: "failed", stage: failure.stage, reason: failure.message }]]); expect(report).toContain("HTTP 400"); expect(report).toContain("INVALID_ARGUMENT"); expect(report).toContain("Justify declarativeNetRequestWithHostAccess"); expect(report).toContain("Failure stage: chrome.publish"); expect(report).not.toContain("private-access"); expect(report).toContain("publication unconfirmed"); }); test("distinguishes pending, staged, published and blocked results in the shared report", () => { for (const [result, expected] of [ [{ action: "submitted", state: "PENDING_REVIEW" }, "Submitted for review; publication unconfirmed"], [{ action: "already-submitted", submittedState: "STAGED" }, "Approved and staged; not yet published"], [{ action: "submitted", state: "PUBLISHED" }, "Published (confirmed by store API)"], [{ action: "already-published", published: "0.2.1" }, "Store version: 0.2.1"], [{ action: "waiting-review", reason: "Another version is pending" }, "Not submitted; publication unconfirmed"], ]) expect(formatSubmissionReport("0.2.0", [["Chrome", result]])).toContain(expected); expect(formatSubmissionReport("0.2.0", [["Firefox", { action: "submitted", sourceAttached: true }]])) .toContain("Submitted for review; publication unconfirmed"); }); test("redacts private approval notes and environment secrets and renders API markup literally", () => { expect(redactDiagnostics({ approval_notes: "private login", errors: ["bad field"] })).not.toContain("private login"); const report = formatSubmissionReport("0.2.0", [["Firefox", { action: "failed", reason: "secret-value ```