proof-pr 0.1.14 → 0.1.15

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.
Files changed (3) hide show
  1. package/README.md +11 -5
  2. package/dist/index.js +97 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -12,7 +12,7 @@ ProofPR 是给开源维护者和工程团队使用的 PR 证据门禁。它在
12
12
  npx proof-pr@latest --version
13
13
  ```
14
14
 
15
- 当前应输出 `0.1.14`。
15
+ 当前应输出 `0.1.15`。
16
16
 
17
17
  不知道用哪个功能时:
18
18
 
@@ -35,7 +35,13 @@ npx proof-pr@latest demo --list
35
35
  npx proof-pr@latest init
36
36
  ```
37
37
 
38
- 这个命令会生成 `.proofpr.yml` 和 `.github/workflows/proofpr.yml`,提交后打开 PR 即可看到报告。
38
+ 这个命令会生成 `.proofpr.yml`、`.github/workflows/proofpr.yml` 和 `.github/pull_request_template.md`,提交后打开 PR 即可看到报告。
39
+
40
+ 已接入仓库单独补 PR 模板:
41
+
42
+ ```bash
43
+ npx proof-pr@latest template
44
+ ```
39
45
 
40
46
  体检接入状态:
41
47
 
@@ -43,7 +49,7 @@ npx proof-pr@latest init
43
49
  npx proof-pr@latest doctor
44
50
  ```
45
51
 
46
- 这个命令会检查配置文件、workflow、Action 版本、PR 权限和本地 diff 是否可读。
52
+ 这个命令会检查配置文件、workflow、PR 模板、Action 版本、PR 权限和本地 diff 是否可读。
47
53
 
48
54
  本地扫描当前分支:
49
55
 
@@ -54,7 +60,7 @@ npx proof-pr@latest scan --base origin/main --head HEAD --locale zh-CN
54
60
  扫描内置案例:
55
61
 
56
62
  ```bash
57
- npx proof-pr@latest scan --diff-file examples/cases/workflow-untrusted-checkout.diff --locale zh-CN
63
+ npx proof-pr@latest demo workflow --locale zh-CN
58
64
  ```
59
65
 
60
66
  生成独立 HTML 可视化报告:
@@ -72,7 +78,7 @@ npx proof-pr@latest benchmark --cases benchmarks/cases
72
78
  ## GitHub Action
73
79
 
74
80
  ```yaml
75
- - uses: linsk27/proof-pr@v0.1.14
81
+ - uses: linsk27/proof-pr@v0.1.15
76
82
  with:
77
83
  fail-on: high
78
84
  comment: "true"
package/dist/index.js CHANGED
@@ -25728,7 +25728,7 @@ function dedupeFindings(findings) {
25728
25728
 
25729
25729
 
25730
25730
  const execFileAsync = (0,external_node_util_namespaceObject.promisify)(external_node_child_process_.execFile);
25731
- const CLI_VERSION = "0.1.14";
25731
+ const CLI_VERSION = "0.1.15";
25732
25732
  const DEMO_CASES = [
25733
25733
  {
25734
25734
  id: "workflow",
@@ -25869,6 +25869,7 @@ build_program
25869
25869
  .description("Check whether ProofPR is installed correctly in the current repository.")
25870
25870
  .option("--config <path>", "Path to .proofpr.yml.", ".proofpr.yml")
25871
25871
  .option("--workflow-path <path>", "Path to the GitHub Actions workflow.", ".github/workflows/proofpr.yml")
25872
+ .option("--pr-template-path <path>", "Path to the pull request template.", ".github/pull_request_template.md")
25872
25873
  .option("--base <ref>", "Base git ref used for local diff checks.", "origin/main")
25873
25874
  .option("--head <ref>", "Head git ref used for local diff checks.", "HEAD")
25874
25875
  .action(async (options) => {
@@ -25878,6 +25879,15 @@ build_program
25878
25879
  process.exitCode = 1;
25879
25880
  }
25880
25881
  });
25882
+ build_program
25883
+ .command("template")
25884
+ .description("Create a ProofPR-friendly pull request template.")
25885
+ .option("--output <path>", "Path to write the pull request template.", ".github/pull_request_template.md")
25886
+ .option("--force", "Overwrite the existing template.", false)
25887
+ .action(async (options) => {
25888
+ await writeIfMissing(options.output, renderPullRequestTemplate(), options.force);
25889
+ process.stdout.write(`ProofPR pull request template written to ${options.output}\n\nNext:\n1. Commit the template.\n2. Ask contributors to fill verification, reproduction, screenshot, changelog, and permission rationale sections when relevant.\n3. Run npx proof-pr@latest doctor to check setup.\n`);
25890
+ });
25881
25891
  build_program
25882
25892
  .command("demo")
25883
25893
  .description("Run a built-in ProofPR demo case without cloning this repository.")
@@ -25951,13 +25961,26 @@ build_program
25951
25961
  .description("Create a starter .proofpr.yml and GitHub Actions workflow.")
25952
25962
  .option("--config-path <path>", "Path to write the ProofPR configuration file.", ".proofpr.yml")
25953
25963
  .option("--workflow-path <path>", "Path to write the GitHub Actions workflow.", ".github/workflows/proofpr.yml")
25964
+ .option("--no-pr-template", "Skip creating .github/pull_request_template.md.")
25965
+ .option("--pr-template-path <path>", "Path to write the pull request template.", ".github/pull_request_template.md")
25954
25966
  .option("--preset <preset>", `Config preset: ${listConfigPresets().join(", ")}.`, parsePresetOption, "open-source-maintainer")
25955
25967
  .option("--fail-on <level>", "Workflow failure threshold: low, medium, high, or never.", parseFailLevel, "high")
25956
25968
  .option("--force", "Overwrite existing files.", false)
25957
25969
  .action(async (options) => {
25958
25970
  await writeIfMissing(options.configPath, renderConfigTemplate(options.preset), options.force);
25959
25971
  await writeIfMissing(options.workflowPath, renderWorkflowTemplate(options.failOn), options.force);
25960
- process.stdout.write(`ProofPR initialized.\n\nCreated:\n- ${options.configPath}\n- ${options.workflowPath}\n\nNext:\n1. Commit these files.\n2. Open or update a pull request.\n3. Read the ProofPR comment or Actions summary.\n\nLocal check:\nnpx proof-pr@latest scan --base origin/main --head HEAD --locale zh-CN\n\nNeed another task?\nnpx proof-pr@latest guide\n`);
25972
+ const created = [options.configPath, options.workflowPath];
25973
+ const skipped = [];
25974
+ if (options.prTemplate) {
25975
+ const wroteTemplate = await writeIfMissingSoft(options.prTemplatePath, renderPullRequestTemplate(), options.force);
25976
+ if (wroteTemplate) {
25977
+ created.push(options.prTemplatePath);
25978
+ }
25979
+ else {
25980
+ skipped.push(`${options.prTemplatePath} already exists`);
25981
+ }
25982
+ }
25983
+ process.stdout.write(`ProofPR initialized.\n\nCreated:\n${created.map((item) => `- ${item}`).join("\n")}${skipped.length > 0 ? `\n\nSkipped:\n${skipped.map((item) => `- ${item}`).join("\n")}` : ""}\n\nNext:\n1. Commit these files.\n2. Open or update a pull request.\n3. Read the ProofPR comment or Actions summary.\n\nLocal check:\nnpx proof-pr@latest scan --base origin/main --head HEAD --locale zh-CN\n\nNeed another task?\nnpx proof-pr@latest guide\n`);
25961
25984
  });
25962
25985
  build_program
25963
25986
  .command("benchmark")
@@ -26004,36 +26027,40 @@ function renderGuide() {
26004
26027
 
26005
26028
  1. 接入 GitHub PR 自动检查
26006
26029
  npx proof-pr@latest init
26007
- 然后提交 .proofpr.yml 和 .github/workflows/proofpr.yml,打开 PR 后看评论和 Actions summary。
26030
+ 然后提交 .proofpr.yml、.github/workflows/proofpr.yml 和 .github/pull_request_template.md,打开 PR 后看评论和 Actions summary。
26008
26031
 
26009
26032
  2. 体检当前仓库接入状态
26010
26033
  npx proof-pr@latest doctor
26011
- 检查配置文件、workflow、Action 版本、PR 权限和本地 diff 是否正常。
26034
+ 检查配置文件、workflow、PR 模板、Action 版本、PR 权限和本地 diff 是否正常。
26012
26035
 
26013
- 3. 本地检查当前分支
26036
+ 3. 已接入仓库,单独补 PR 模板
26037
+ npx proof-pr@latest template
26038
+ 引导贡献者填写验证、复现、截图、changelog 和权限理由。
26039
+
26040
+ 4. 本地检查当前分支
26014
26041
  npx proof-pr@latest scan --base origin/main --head HEAD --locale zh-CN
26015
26042
  适合在发 PR 前先看风险、证据评分和 Review 行动清单。
26016
26043
 
26017
- 4. 生成可分享 HTML 报告
26044
+ 5. 生成可分享 HTML 报告
26018
26045
  npx proof-pr@latest scan --base origin/main --head HEAD --locale zh-CN --format html --output proofpr-report.html
26019
26046
  生成后用浏览器打开 proofpr-report.html。
26020
26047
 
26021
- 5. 生成 GitHub Code Scanning 的 SARIF
26048
+ 6. 生成 GitHub Code Scanning 的 SARIF
26022
26049
  npx proof-pr@latest scan --base origin/main --head HEAD --format sarif --output proofpr.sarif
26023
26050
  适合在 CI 里配合 github/codeql-action/upload-sarif 使用。
26024
26051
 
26025
- 6. 不接入仓库,先试跑内置案例
26052
+ 7. 不接入仓库,先试跑内置案例
26026
26053
  npx proof-pr@latest demo workflow --locale zh-CN
26027
26054
  不需要 clone 仓库或寻找 examples 文件,也能快速看到 ProofPR 会抓什么风险。
26028
26055
 
26029
- 7. 查看所有内置案例
26056
+ 8. 查看所有内置案例
26030
26057
  npx proof-pr@latest demo --list
26031
26058
 
26032
- 8. 验证规则样本是否仍然命中
26059
+ 9. 验证规则样本是否仍然命中
26033
26060
  npx proof-pr@latest benchmark --cases benchmarks/cases
26034
26061
  适合维护 ProofPR 规则或发版前回归。
26035
26062
 
26036
- 9. 调整审查强度
26063
+ 10. 调整审查强度
26037
26064
  打开 .proofpr.yml,把 preset 改成 security-strict、dependency-careful 或 mcp-security。
26038
26065
 
26039
26066
  结果在哪里看:
@@ -26113,6 +26140,7 @@ async function runDoctor(options) {
26113
26140
  checks.push({ level: "fail", title: `缺少 ${options.workflowPath}` });
26114
26141
  nextSteps.add("运行 npx proof-pr@latest init 生成 .github/workflows/proofpr.yml。");
26115
26142
  }
26143
+ await inspectPullRequestTemplate(options.prTemplatePath, checks, nextSteps);
26116
26144
  await inspectGitDiff(options, checks, nextSteps);
26117
26145
  if (nextSteps.size === 0) {
26118
26146
  nextSteps.add("当前接入状态正常;可以打开 PR,或运行 npx proof-pr@latest scan --base origin/main --head HEAD --locale zh-CN 做本地自查。");
@@ -26158,6 +26186,29 @@ function inspectWorkflow(workflow, checks, nextSteps) {
26158
26186
  nextSteps.add("建议在 workflow permissions 中加入 contents: read。");
26159
26187
  }
26160
26188
  }
26189
+ async function inspectPullRequestTemplate(path, checks, nextSteps) {
26190
+ if (!(await pathExists(path))) {
26191
+ checks.push({ level: "warn", title: `缺少 ${path}` });
26192
+ nextSteps.add("运行 npx proof-pr@latest template 生成 PR 模板,引导贡献者补充验证、复现、截图和权限理由。");
26193
+ return;
26194
+ }
26195
+ const template = await (0,promises_namespaceObject.readFile)(path, "utf8");
26196
+ checks.push({ level: "pass", title: `${path} 已存在` });
26197
+ if (/验证|verification|test/i.test(template)) {
26198
+ checks.push({ level: "pass", title: "PR 模板会提示验证证据" });
26199
+ }
26200
+ else {
26201
+ checks.push({ level: "warn", title: "PR 模板没有明显的验证证据提示" });
26202
+ nextSteps.add("在 PR 模板中加入“验证方式”栏目,减少 ProofPR 报告里的证据不足。");
26203
+ }
26204
+ if (/复现|reproduction|before|after|截图|screenshot|权限|permission/i.test(template)) {
26205
+ checks.push({ level: "pass", title: "PR 模板覆盖复现、截图或权限理由提示" });
26206
+ }
26207
+ else {
26208
+ checks.push({ level: "warn", title: "PR 模板缺少复现、截图或权限理由提示" });
26209
+ nextSteps.add("在 PR 模板中加入复现、截图、changelog、权限理由等可选栏目。");
26210
+ }
26211
+ }
26161
26212
  async function inspectGitDiff(options, checks, nextSteps) {
26162
26213
  try {
26163
26214
  const { stdout } = await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"]);
@@ -26244,6 +26295,14 @@ async function writeIfMissing(path, contents, force) {
26244
26295
  await (0,promises_namespaceObject.mkdir)((0,external_node_path_.dirname)(path), { recursive: true });
26245
26296
  await (0,promises_namespaceObject.writeFile)(path, contents, "utf8");
26246
26297
  }
26298
+ async function writeIfMissingSoft(path, contents, force) {
26299
+ if (!force && (await pathExists(path))) {
26300
+ return false;
26301
+ }
26302
+ await (0,promises_namespaceObject.mkdir)((0,external_node_path_.dirname)(path), { recursive: true });
26303
+ await (0,promises_namespaceObject.writeFile)(path, contents, "utf8");
26304
+ return true;
26305
+ }
26247
26306
  async function writeOutput(path, contents) {
26248
26307
  await (0,promises_namespaceObject.mkdir)((0,external_node_path_.dirname)(path), { recursive: true });
26249
26308
  await (0,promises_namespaceObject.writeFile)(path, contents, "utf8");
@@ -26291,6 +26350,33 @@ jobs:
26291
26350
  annotations: "true"
26292
26351
  `;
26293
26352
  }
26353
+ function renderPullRequestTemplate() {
26354
+ return `## 变更说明
26355
+
26356
+ 请说明这个 PR 为什么需要、改了什么、影响范围是什么。
26357
+
26358
+ ## 验证方式
26359
+
26360
+ - [ ] 已运行自动化测试:
26361
+ - [ ] 已完成手动验证:
26362
+ - [ ] 不需要测试,原因:
26363
+
26364
+ ## 复现 / Before & After
26365
+
26366
+ 如果是 bug fix,请写复现步骤、预期结果和实际结果。
26367
+ 如果是 UI 改动,请附 before/after 截图或录屏。
26368
+
26369
+ ## 依赖 / CI / 权限 / MCP 变更
26370
+
26371
+ 如果改了依赖、lockfile、GitHub Actions、MCP、环境变量或权限,请说明原因和安全影响。
26372
+
26373
+ ## 发布风险
26374
+
26375
+ - [ ] 无破坏性变更
26376
+ - [ ] 需要迁移说明 / changelog
26377
+ - [ ] 需要灰度或回滚方案
26378
+ `;
26379
+ }
26294
26380
  function renderOutput(result, format, locale) {
26295
26381
  if (format === "json") {
26296
26382
  return JSON.stringify(result, null, 2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "proof-pr",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "CLI for ProofPR, a maintainer-focused pull request evidence scanner.",
5
5
  "license": "MIT",
6
6
  "type": "module",