diff --git a/.npmignore b/.npmignore index a667f43..c50d170 100644 --- a/.npmignore +++ b/.npmignore @@ -1,3 +1,11 @@ docs/ .claude/ .cursor/ + +# 密钥文件:package.json 的 files 白名单之外的第二道防线。 +# 注意 .npmignore 一旦存在就会完全接管 .gitignore,.gitignore 里的规则不再生效。 +.env +.env.* +!.env.example +*.pem +*.key diff --git a/package.json b/package.json index f7b5e35..83a7b2e 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,19 @@ "bin": { "ritmex-bot": "./bin/ritmex-bot" }, + "files": [ + "bin", + "src", + "scripts", + "index.ts", + "tsconfig.json", + "setup.sh", + ".env.example", + "README_en.md", + "cli-guide.md", + "cli-guide.en.md", + "grid-trading.md" + ], "scripts": { "dev": "bun run index.ts", "start": "bun run index.ts", @@ -20,6 +33,8 @@ "test": "bun x vitest run", "test:exchange-contract": "bun x vitest run tests/exchange-contract-suite.test.ts tests/exchange-factory.test.ts tests/config.test.ts", "test:watch": "bun x vitest", + "check:pack": "bun run scripts/check-pack.ts", + "prepublishOnly": "bun run scripts/check-pack.ts", "start:trend:silent": "bun run index.ts --strategy trend --silent", "start:maker:silent": "bun run index.ts --strategy maker --silent", "start:offset:silent": "bun run index.ts --strategy offset-maker --silent", diff --git a/scripts/check-pack.ts b/scripts/check-pack.ts new file mode 100644 index 0000000..74e6ddc --- /dev/null +++ b/scripts/check-pack.ts @@ -0,0 +1,38 @@ +#!/usr/bin/env bun +// 发布前闸门:阻止密钥文件进入 npm tarball。 +// 0.1.0 曾把 .env 发到 registry —— .npmignore 一旦存在就完全接管 .gitignore, +// 而当时的 .npmignore 没有列 .env,.gitignore 里的规则形同虚设。 + +import { spawnSync } from "node:child_process"; + +const DENY = [ + /^\.env$/, + /^\.env\.(?!example$)/, + /^\.npmrc$/, + /\.pem$/, + /\.key$/, + /(^|\/)id_(rsa|ed25519)$/, +]; + +const result = spawnSync("npm", ["pack", "--dry-run", "--json"], { encoding: "utf8" }); +if (result.status !== 0) { + console.error(result.stderr); + process.exit(1); +} + +const [meta] = JSON.parse(result.stdout) as Array<{ files: Array<{ path: string }> }>; +if (!meta) { + console.error("无法解析 npm pack 输出,发布已中止。"); + process.exit(1); +} + +const leaked = meta.files.map((file) => file.path).filter((path) => DENY.some((re) => re.test(path))); + +if (leaked.length > 0) { + console.error("\n发布已中止 —— tarball 中包含密钥文件:"); + for (const path of leaked) console.error(` - ${path}`); + console.error(""); + process.exit(1); +} + +console.log(`pack 检查通过:${meta.files.length} 个文件,未发现密钥文件。`);