-
Notifications
You must be signed in to change notification settings - Fork 0
recover the source from the published sourcemaps — 8 of 8 versions rebuild byte-identically #18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| node_modules/ | ||
| dist/ | ||
| *.tgz | ||
| .env | ||
| .env.local |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| # Source recovery — where this code came from, and how you can check | ||
|
|
||
| This repository advertised itself as the source of `@wave-av/cli` while containing no source at | ||
| all. Eight versions were published to npm between 2026-04-03 and 2026-08-04 from a working copy | ||
| that was never committed. Anyone who ran `npm install @wave-av/cli` and followed the `repository` | ||
| link the package itself carries arrived at a README and a LICENSE, and **the code executing on | ||
| their machine existed in no public repository.** | ||
|
|
||
| This directory closes that gap. It is worth being precise about what kind of claim that is. | ||
|
|
||
| ## The source was recovered, not reconstructed | ||
|
|
||
| Every published version of `@wave-av/cli` ships `dist/index.js.map`, and that sourcemap carries | ||
| `sourcesContent` — not merely the *names* of the original files but their **complete contents**, | ||
| pre-compilation. All 70 TypeScript files under `src/` were extracted from it verbatim. Nothing here | ||
| was inferred from the compiled bundle, hand-written to match, or reasoned backwards from types. | ||
|
|
||
| ## The receipt: it rebuilds byte-for-byte | ||
|
|
||
| The claim "this is the source" is checkable, so it was checked, on **every** published version | ||
| rather than a sample: | ||
|
|
||
| | version | rebuilt `dist/index.js` vs published | | ||
| |---|---| | ||
| | 1.0.0 | **byte-identical** | | ||
| | 1.0.2 | **byte-identical** | | ||
| | 1.0.3 | **byte-identical** | | ||
| | 1.0.4 | **byte-identical** | | ||
| | 1.0.5 | **byte-identical** | | ||
| | 1.0.6 | **byte-identical** | | ||
| | 1.0.7 | **byte-identical** | | ||
| | 1.0.8 | **byte-identical** | | ||
|
|
||
| Re-derive any row yourself: | ||
|
|
||
| ```sh | ||
| # 1. fetch what npm actually shipped | ||
| # NOTE: --registry does NOT override a scope mapping. If your npm config points @wave-av at a | ||
| # private registry, the plain form 404s against the wrong host and reads as "not published". | ||
| npm pack @wave-av/cli@1.0.8 --@wave-av:registry=https://registry.npmjs.org | ||
| tar -xzf wave-av-cli-1.0.8.tgz | ||
|
|
||
| # 2. extract the original sources out of the published sourcemap | ||
| node -e ' | ||
| const m = require("./package/dist/index.js.map"), fs = require("fs"), p = require("path"); | ||
| m.sources.forEach((s, i) => { | ||
| const f = p.join("recovered", s.replace(/^\.\.\//, "")); | ||
| fs.mkdirSync(p.dirname(f), { recursive: true }); | ||
| fs.writeFileSync(f, m.sourcesContent[i]); | ||
| }); | ||
| ' | ||
|
|
||
| # 3. build and compare | ||
| npm ci --include=dev && npx tsup | ||
| cmp dist/index.js package/dist/index.js && echo IDENTICAL | ||
| ``` | ||
|
|
||
| `cmp` exits 0 silently on a match. | ||
|
|
||
| ## What was authored for this recovery, and is therefore NOT recovered | ||
|
|
||
| Two files. The sourcemap contains source, not build configuration, so these were written to make | ||
| the tree buildable and are stated here rather than left to look like they came out of the artifact: | ||
|
|
||
| - **`tsconfig.json`** — a conventional strict ES2022/ESNext configuration. | ||
| - **`tsup.config.ts`** — entry `src/index.ts`, ESM, node18, sourcemap on, shebang banner. | ||
|
|
||
| They are not guesses in any loose sense: they are the settings under which the output matches the | ||
| published bytes exactly, on all eight versions. A different plausible configuration would have | ||
| produced a different bundle and the comparison above would have failed. But they were **written**, | ||
| not **recovered**, and conflating the two would be the same class of error this whole exercise | ||
| exists to correct. | ||
|
|
||
| `package.json` was taken from the published manifest, which npm preserves in full — including | ||
| `scripts` and `devDependencies`. | ||
|
|
||
| ## Safety | ||
|
|
||
| The recovered tree was scanned with `gitleaks` before being proposed here: **no leaks found**, | ||
| ~200KB across 70 files. This mattered more than it looks. The sourcemap has been publicly | ||
| downloadable since 2026-04-03, so a hardcoded credential inside it would have been a live | ||
| four-month exposure — a fact about the *published package*, not a risk created by recovering it. | ||
|
|
||
| ## What this does and does not settle | ||
|
|
||
| It settles the question *"what source produced the code now running on their machine?"* for every | ||
| version of `@wave-av/cli`, with a receipt anyone outside WAVE can reproduce. | ||
|
|
||
| It does **not** settle it for `@wave-av/workflow-sdk`, whose seven published versions carry no | ||
| sourcemap at all. That package's source is recoverable only as a *reconstruction* — a tree that can | ||
| be proven to produce the published bytes, which is a genuinely weaker claim than a tree that did. | ||
| The two must not be recorded as the same thing. | ||
|
|
||
| ## Provenance of the versions themselves | ||
|
|
||
| Recovering the source does not retroactively create the tags that never existed. Tagging each | ||
| published version against its own `cmp` receipt is tracked separately; until those tags exist, this | ||
| file is the record of where the code came from. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| { | ||
| "name": "@wave-av/cli", | ||
| "version": "1.0.8", | ||
| "description": "WAVE CLI \u2014 manage live streams, productions, and video infrastructure from your terminal. 34 command groups.", | ||
| "main": "./dist/index.js", | ||
| "type": "module", | ||
| "bin": { | ||
| "wave": "./dist/index.js" | ||
| }, | ||
| "files": [ | ||
| "dist", | ||
| "templates", | ||
| "README.md", | ||
| "CHANGELOG.md" | ||
| ], | ||
| "scripts": { | ||
| "build": "tsup", | ||
| "dev": "tsup --watch", | ||
| "type-check": "tsc --noEmit", | ||
| "test": "vitest run", | ||
| "test:watch": "vitest", | ||
| "lint": "eslint src/", | ||
| "prepublishOnly": "npm run build" | ||
|
Comment on lines
+20
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1. lint script missing eslint package.json defines lint as eslint src/, but eslint is not listed in dependencies or devDependencies, so npm run lint will fail in CI on a clean install. This introduces a deterministic new CI failure risk for the configured lint command. Agent Prompt
|
||
| }, | ||
| "keywords": [ | ||
| "wave", | ||
| "cli", | ||
| "streaming", | ||
| "video", | ||
| "broadcast", | ||
| "production", | ||
| "live", | ||
| "webrtc", | ||
| "srt", | ||
| "rtmp", | ||
| "terminal" | ||
| ], | ||
| "author": "WAVE Inc. <sdk@wave.online>", | ||
| "license": "MIT", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/wave-av/cli.git", | ||
| "directory": "." | ||
| }, | ||
| "homepage": "https://docs.wave.online/cli", | ||
| "bugs": { | ||
| "url": "https://github.com/wave-av/cli/issues" | ||
| }, | ||
| "engines": { | ||
| "node": ">=18.0.0" | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public", | ||
| "provenance": false, | ||
| "registry": "https://registry.npmjs.org/" | ||
| }, | ||
| "dependencies": { | ||
| "@wave-av/sdk": "^2.0.11", | ||
| "chalk": "^5.4.1", | ||
| "cli-table3": "^0.6.5", | ||
| "commander": "^13.1.0", | ||
| "conf": "^13.1.0", | ||
| "inquirer": "^12.3.2", | ||
| "keytar": "^7.9.0", | ||
| "open": "^10.1.0", | ||
| "ora": "^8.2.0", | ||
| "ws": "^8.18.0", | ||
| "yaml": "^2.7.0", | ||
| "zod": "^3.22.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@sentry/node": "^9.4.0", | ||
| "@types/inquirer": "^9.0.7", | ||
| "@types/node": "^22.13.0", | ||
| "@types/ws": "^8.5.14", | ||
| "tsup": "^8.0.0", | ||
| "typescript": "^5.9.3", | ||
| "vitest": "^4.0.16" | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,174 @@ | ||
| import { Command } from "commander"; | ||
| import chalk from "chalk"; | ||
| import { registerAuthCommands } from "./commands/auth/index.js"; | ||
| import { registerOrgCommands } from "./commands/org/index.js"; | ||
| import { registerConfigCommands } from "./commands/config/index.js"; | ||
| import { registerStreamCommands } from "./commands/stream/index.js"; | ||
| import { registerStudioCommands } from "./commands/studio/index.js"; | ||
| import { registerClipCommands } from "./commands/clips/index.js"; | ||
| import { registerEditorCommands } from "./commands/editor/index.js"; | ||
| import { registerVoiceCommands } from "./commands/voice/index.js"; | ||
| import { registerPhoneCommands } from "./commands/phone/index.js"; | ||
| import { registerCollabCommands } from "./commands/collab/index.js"; | ||
| import { registerCaptionsCommands } from "./commands/captions/index.js"; | ||
| import { registerChaptersCommands } from "./commands/chapters/index.js"; | ||
| import { registerAICommands } from "./commands/ai/index.js"; | ||
| import { registerTranscribeCommands } from "./commands/transcribe/index.js"; | ||
| import { registerSentimentCommands } from "./commands/sentiment/index.js"; | ||
| import { registerSearchCommands } from "./commands/search/index.js"; | ||
| import { registerSceneCommands } from "./commands/scene/index.js"; | ||
| import { registerFleetCommands } from "./commands/fleet/index.js"; | ||
| import { registerGhostCommands } from "./commands/ghost/index.js"; | ||
| import { registerMeshCommands } from "./commands/mesh/index.js"; | ||
| import { registerEdgeCommands } from "./commands/edge/index.js"; | ||
| import { registerAnalyticsCommands } from "./commands/analytics/index.js"; | ||
| import { registerPrismCommands } from "./commands/prism/index.js"; | ||
| import { registerZoomCommands } from "./commands/zoom/index.js"; | ||
| import { registerVaultCommands } from "./commands/vault/index.js"; | ||
| import { registerMarketplaceCommands } from "./commands/marketplace/index.js"; | ||
| import { registerConnectCommands } from "./commands/connect/index.js"; | ||
| import { registerDistributionCommands } from "./commands/distribution/index.js"; | ||
| import { registerDesktopCommands } from "./commands/desktop/index.js"; | ||
| import { registerSignageCommands } from "./commands/signage/index.js"; | ||
| import { registerQrCommands } from "./commands/qr/index.js"; | ||
| import { registerAudienceCommands } from "./commands/audience/index.js"; | ||
| import { registerCreatorCommands } from "./commands/creator/index.js"; | ||
| import { registerPodcastCommands } from "./commands/podcast/index.js"; | ||
| import { registerSlidesCommands } from "./commands/slides/index.js"; | ||
| import { registerUsbCommands } from "./commands/usb/index.js"; | ||
| import { registerNotifyCommands } from "./commands/notify/index.js"; | ||
| import { registerDrmCommands } from "./commands/drm/index.js"; | ||
| import { registerBillingCommands } from "./commands/billing/index.js"; | ||
| import { registerListenCommands } from "./commands/listen/index.js"; | ||
| import { registerLogsCommands } from "./commands/logs/index.js"; | ||
| import { registerTriggerCommands } from "./commands/trigger/index.js"; | ||
| import { registerDevCommands } from "./commands/dev/index.js"; | ||
| import { registerOpenCommands } from "./commands/open/index.js"; | ||
| import { registerInitCommands } from "./commands/init/index.js"; | ||
| import { registerAdminCommands } from "./commands/admin/index.js"; | ||
| import { registerDoctorCommands } from "./commands/doctor/index.js"; | ||
| import { registerStatusCommands } from "./commands/status/index.js"; | ||
| import { registerCompletionCommands } from "./commands/completion/index.js"; | ||
| import { registerApiCommands } from "./commands/api/index.js"; | ||
| import { registerLinkCommands } from "./commands/link/index.js"; | ||
| import { detectEnvironment } from "./lib/environment.js"; | ||
|
|
||
| function printBanner(): void { | ||
| // WAVE brand gradient: blue (#3366FF) -> purple (#7B41E8) -> cyan (#33BBCC) | ||
| const b = chalk.hex("#3366FF"); // primary blue | ||
| const p = chalk.hex("#7B41E8"); // secondary purple | ||
| const c = chalk.hex("#33BBCC"); // accent cyan | ||
| const d = chalk.dim; | ||
|
|
||
| console.log(""); | ||
| console.log(` ${b("██╗ ██╗")} ${p("█████╗ ")} ${p("██╗ ██╗")} ${c("███████╗")}`); | ||
| console.log(` ${b("██║ ██║")} ${p("██╔══██╗")} ${p("██║ ██║")} ${c("██╔════╝")}`); | ||
| console.log(` ${b("██║ █╗ ██║")} ${p("███████║")} ${p("██║ ██║")} ${c("█████╗ ")}`); | ||
| console.log(` ${b("██║███╗██║")} ${p("██╔══██║")} ${p("╚██╗ ██╔╝")} ${c("██╔══╝ ")}`); | ||
| console.log(` ${b("╚███╔███╔╝")} ${p("██║ ██║")} ${p(" ╚████╔╝ ")} ${c("███████╗")}`); | ||
| console.log(` ${b(" ╚══╝╚══╝ ")} ${p("╚═╝ ╚═╝")} ${p(" ╚═══╝ ")} ${c("╚══════╝")}`); | ||
| console.log(""); | ||
| console.log(` ${d("Enterprise Streaming Platform")} ${chalk.hex("#555")("v1.0.0")}`); | ||
| console.log(` ${d("─".repeat(45))}`); | ||
| console.log(""); | ||
| } | ||
|
|
||
| export function createProgram(): Command { | ||
| const program = new Command(); | ||
|
|
||
| program | ||
| .name("wave") | ||
| .description("WAVE CLI - Command-line interface for the WAVE streaming platform") | ||
| .version("1.0.0", "-v, --version") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 The CLI reports the wrong version number The version reported to users is hardcoded to an old value ( Three hardcoded 1.0.0 strings vs package.json 1.0.8
Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| .option("-o, --output <format>", "Output format: table, json, yaml", "table") | ||
| .option("--project <name>", "Override project context") | ||
| .option("--org <id>", "Override organization") | ||
| .option("-c, --confirm", "Skip confirmation prompts") | ||
| .option("--no-color", "Disable colored output") | ||
| .option("--debug", "Verbose debug logging"); | ||
|
|
||
| // Auth & Config | ||
| registerAuthCommands(program); | ||
| registerOrgCommands(program); | ||
| registerConfigCommands(program); | ||
| registerInitCommands(program); | ||
| registerLinkCommands(program); | ||
|
|
||
| // Core APIs (P1) | ||
| registerStreamCommands(program); | ||
| registerStudioCommands(program); | ||
|
|
||
| // Production (P1) | ||
| registerClipCommands(program); | ||
| registerEditorCommands(program); | ||
| registerVoiceCommands(program); | ||
| registerPhoneCommands(program); | ||
| registerCollabCommands(program); | ||
| registerCaptionsCommands(program); | ||
| registerChaptersCommands(program); | ||
| registerAICommands(program); | ||
| registerTranscribeCommands(program); | ||
|
|
||
| // Intelligence (P2) | ||
| registerSentimentCommands(program); | ||
| registerSearchCommands(program); | ||
| registerSceneCommands(program); | ||
|
|
||
| // Enterprise (P2) | ||
| registerFleetCommands(program); | ||
| registerGhostCommands(program); | ||
| registerMeshCommands(program); | ||
| registerEdgeCommands(program); | ||
| registerAnalyticsCommands(program); | ||
| registerPrismCommands(program); | ||
| registerZoomCommands(program); | ||
|
|
||
| // Content & Commerce (P3) | ||
| registerVaultCommands(program); | ||
| registerMarketplaceCommands(program); | ||
| registerConnectCommands(program); | ||
| registerDistributionCommands(program); | ||
| registerDesktopCommands(program); | ||
| registerSignageCommands(program); | ||
| registerQrCommands(program); | ||
| registerAudienceCommands(program); | ||
| registerCreatorCommands(program); | ||
|
|
||
| // Specialized (P4) | ||
| registerPodcastCommands(program); | ||
| registerSlidesCommands(program); | ||
| registerUsbCommands(program); | ||
|
|
||
| // Cross-cutting | ||
| registerNotifyCommands(program); | ||
| registerDrmCommands(program); | ||
| registerBillingCommands(program); | ||
|
|
||
| // Developer tools | ||
| registerListenCommands(program); | ||
| registerLogsCommands(program); | ||
| registerTriggerCommands(program); | ||
| registerDevCommands(program); | ||
| registerOpenCommands(program); | ||
|
|
||
| // Admin | ||
| registerAdminCommands(program); | ||
|
|
||
| // Diagnostics & utilities | ||
| registerDoctorCommands(program); | ||
| registerStatusCommands(program); | ||
| registerCompletionCommands(program); | ||
| registerApiCommands(program); | ||
|
|
||
| // Skip banner for AI agents and CI (they prefer clean output) | ||
| const env = detectEnvironment(); | ||
| if (!env.isAgent && !env.isCI) { | ||
| const originalHelp = program.helpInformation.bind(program); | ||
| program.helpInformation = function () { | ||
| printBanner(); | ||
| return originalHelp(); | ||
| }; | ||
| } | ||
|
|
||
| return program; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
6. Recovery command cannot install
🐞 Bug⚙ MaintainabilityAgent Prompt
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools