proof-pr 0.1.13 → 0.1.14
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 +9 -2
- package/dist/index.js +195 -6
- 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.
|
|
15
|
+
当前应输出 `0.1.14`。
|
|
16
16
|
|
|
17
17
|
不知道用哪个功能时:
|
|
18
18
|
|
|
@@ -22,6 +22,13 @@ npx proof-pr@latest
|
|
|
22
22
|
npx proof-pr@latest guide
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
不接入仓库,先体验报告:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx proof-pr@latest demo workflow --locale zh-CN
|
|
29
|
+
npx proof-pr@latest demo --list
|
|
30
|
+
```
|
|
31
|
+
|
|
25
32
|
初始化配置和 GitHub Action:
|
|
26
33
|
|
|
27
34
|
```bash
|
|
@@ -65,7 +72,7 @@ npx proof-pr@latest benchmark --cases benchmarks/cases
|
|
|
65
72
|
## GitHub Action
|
|
66
73
|
|
|
67
74
|
```yaml
|
|
68
|
-
- uses: linsk27/proof-pr@v0.1.
|
|
75
|
+
- uses: linsk27/proof-pr@v0.1.14
|
|
69
76
|
with:
|
|
70
77
|
fail-on: high
|
|
71
78
|
comment: "true"
|
package/dist/index.js
CHANGED
|
@@ -25728,7 +25728,131 @@ 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.
|
|
25731
|
+
const CLI_VERSION = "0.1.14";
|
|
25732
|
+
const DEMO_CASES = [
|
|
25733
|
+
{
|
|
25734
|
+
id: "workflow",
|
|
25735
|
+
title: "高权限 workflow 运行不可信 PR 代码",
|
|
25736
|
+
description: "演示 pull_request_target 与 PR head checkout 组合风险。",
|
|
25737
|
+
diffText: `diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
|
|
25738
|
+
index 1111111..2222222 100644
|
|
25739
|
+
--- a/.github/workflows/pr.yml
|
|
25740
|
+
+++ b/.github/workflows/pr.yml
|
|
25741
|
+
@@ -1,7 +1,17 @@
|
|
25742
|
+
name: PR automation
|
|
25743
|
+
on:
|
|
25744
|
+
+ pull_request_target:
|
|
25745
|
+
+ types: [opened, synchronize]
|
|
25746
|
+
+
|
|
25747
|
+
jobs:
|
|
25748
|
+
test:
|
|
25749
|
+
runs-on: ubuntu-latest
|
|
25750
|
+
steps:
|
|
25751
|
+
- - uses: actions/checkout@v4
|
|
25752
|
+
+ - uses: actions/checkout@v4
|
|
25753
|
+
+ with:
|
|
25754
|
+
+ repository: \${{ github.event.pull_request.head.repo.full_name }}
|
|
25755
|
+
+ ref: \${{ github.event.pull_request.head.sha }}
|
|
25756
|
+
+ - run: pnpm install
|
|
25757
|
+
+ - run: pnpm test
|
|
25758
|
+
`
|
|
25759
|
+
},
|
|
25760
|
+
{
|
|
25761
|
+
id: "secret",
|
|
25762
|
+
title: "疑似 secret 被提交",
|
|
25763
|
+
description: "演示 .env、OpenAI key、数据库连接串等敏感内容会被拦截。",
|
|
25764
|
+
diffText: `diff --git a/.env b/.env
|
|
25765
|
+
new file mode 100644
|
|
25766
|
+
index 0000000..1111111
|
|
25767
|
+
--- /dev/null
|
|
25768
|
+
+++ b/.env
|
|
25769
|
+
@@ -0,0 +1,2 @@
|
|
25770
|
+
+OPENAI_API_KEY=sk-proj-examplevalueexamplevalue1234567890
|
|
25771
|
+
+DATABASE_URL=postgres://demo:super-secret-password@example.com:5432/app
|
|
25772
|
+
`
|
|
25773
|
+
},
|
|
25774
|
+
{
|
|
25775
|
+
id: "dependency",
|
|
25776
|
+
title: "依赖大版本升级",
|
|
25777
|
+
description: "演示依赖 major upgrade 需要 changelog、迁移说明和验证证据。",
|
|
25778
|
+
diffText: `diff --git a/package.json b/package.json
|
|
25779
|
+
index 1111111..2222222 100644
|
|
25780
|
+
--- a/package.json
|
|
25781
|
+
+++ b/package.json
|
|
25782
|
+
@@ -1,8 +1,8 @@
|
|
25783
|
+
{
|
|
25784
|
+
"dependencies": {
|
|
25785
|
+
- "react": "^18.2.0",
|
|
25786
|
+
+ "react": "^19.0.0",
|
|
25787
|
+
"zod": "^3.25.1"
|
|
25788
|
+
},
|
|
25789
|
+
"devDependencies": {
|
|
25790
|
+
"typescript": "^5.9.3"
|
|
25791
|
+
}
|
|
25792
|
+
}
|
|
25793
|
+
`
|
|
25794
|
+
},
|
|
25795
|
+
{
|
|
25796
|
+
id: "mcp",
|
|
25797
|
+
title: "MCP 本地命令和凭据面",
|
|
25798
|
+
description: "演示 MCP / agent 配置中的 command、args、env 风险。",
|
|
25799
|
+
diffText: `diff --git a/.cursor/mcp.json b/.cursor/mcp.json
|
|
25800
|
+
new file mode 100644
|
|
25801
|
+
index 0000000..1111111
|
|
25802
|
+
--- /dev/null
|
|
25803
|
+
+++ b/.cursor/mcp.json
|
|
25804
|
+
@@ -0,0 +1,11 @@
|
|
25805
|
+
+{
|
|
25806
|
+
+ "mcpServers": {
|
|
25807
|
+
+ "local-admin": {
|
|
25808
|
+
+ "command": "node",
|
|
25809
|
+
+ "args": ["scripts/admin-server.js"],
|
|
25810
|
+
+ "env": {
|
|
25811
|
+
+ "API_TOKEN": "\${LOCAL_API_TOKEN}"
|
|
25812
|
+
+ }
|
|
25813
|
+
+ }
|
|
25814
|
+
+ }
|
|
25815
|
+
+}
|
|
25816
|
+
`,
|
|
25817
|
+
config: { preset: "mcp-security" }
|
|
25818
|
+
},
|
|
25819
|
+
{
|
|
25820
|
+
id: "ui-evidence",
|
|
25821
|
+
title: "UI 改动缺少截图证据",
|
|
25822
|
+
description: "演示 Evidence Contract:组件改动必须提供截图和验证说明。",
|
|
25823
|
+
diffText: `diff --git a/src/components/Button.tsx b/src/components/Button.tsx
|
|
25824
|
+
index 1111111..2222222 100644
|
|
25825
|
+
--- a/src/components/Button.tsx
|
|
25826
|
+
+++ b/src/components/Button.tsx
|
|
25827
|
+
@@ -1,3 +1,7 @@
|
|
25828
|
+
export function Button() {
|
|
25829
|
+
- return <button>Save</button>;
|
|
25830
|
+
+ return (
|
|
25831
|
+
+ <button className="primary">
|
|
25832
|
+
+ Save
|
|
25833
|
+
+ </button>
|
|
25834
|
+
+ );
|
|
25835
|
+
}
|
|
25836
|
+
`,
|
|
25837
|
+
config: {
|
|
25838
|
+
evidence: {
|
|
25839
|
+
contracts: [
|
|
25840
|
+
{
|
|
25841
|
+
id: "ui-screenshot",
|
|
25842
|
+
title: "UI changes need screenshots",
|
|
25843
|
+
paths: ["src/components/**"],
|
|
25844
|
+
requires: ["screenshot", "verification"],
|
|
25845
|
+
severity: "medium"
|
|
25846
|
+
}
|
|
25847
|
+
]
|
|
25848
|
+
}
|
|
25849
|
+
},
|
|
25850
|
+
pullRequest: {
|
|
25851
|
+
title: "Update button styling",
|
|
25852
|
+
body: "This updates the primary button style and spacing so the layout is easier to scan."
|
|
25853
|
+
}
|
|
25854
|
+
}
|
|
25855
|
+
];
|
|
25732
25856
|
const build_program = new Command();
|
|
25733
25857
|
build_program
|
|
25734
25858
|
.name("proof-pr")
|
|
@@ -25754,6 +25878,37 @@ build_program
|
|
|
25754
25878
|
process.exitCode = 1;
|
|
25755
25879
|
}
|
|
25756
25880
|
});
|
|
25881
|
+
build_program
|
|
25882
|
+
.command("demo")
|
|
25883
|
+
.description("Run a built-in ProofPR demo case without cloning this repository.")
|
|
25884
|
+
.argument("[case]", "Demo case id. Use --list to see available cases.", "workflow")
|
|
25885
|
+
.option("--list", "List built-in demo cases.", false)
|
|
25886
|
+
.option("--format <format>", "Output format: markdown, json, sarif, or html.", parseFormat, "markdown")
|
|
25887
|
+
.option("--output <path>", "Write demo report output to a file instead of stdout.")
|
|
25888
|
+
.option("--locale <locale>", "Report language: en or zh-CN.", "zh-CN")
|
|
25889
|
+
.action(async (caseId, options) => {
|
|
25890
|
+
if (options.list) {
|
|
25891
|
+
process.stdout.write(renderDemoList());
|
|
25892
|
+
return;
|
|
25893
|
+
}
|
|
25894
|
+
const demoCase = DEMO_CASES.find((item) => item.id === caseId);
|
|
25895
|
+
if (!demoCase) {
|
|
25896
|
+
throw new Error(`Unknown demo case "${caseId}". Run "proof-pr demo --list" to see available cases.`);
|
|
25897
|
+
}
|
|
25898
|
+
const result = scanDiff(demoCase.diffText, {
|
|
25899
|
+
config: demoCase.config,
|
|
25900
|
+
pullRequest: demoCase.pullRequest
|
|
25901
|
+
});
|
|
25902
|
+
const locale = parseLocale(options.locale, "zh-CN");
|
|
25903
|
+
const output = renderDemoOutput(demoCase, result, options.format, locale);
|
|
25904
|
+
if (options.output) {
|
|
25905
|
+
await writeOutput(options.output, `${output}\n`);
|
|
25906
|
+
process.stdout.write(`ProofPR demo ${options.format} report written to ${options.output}\n`);
|
|
25907
|
+
}
|
|
25908
|
+
else {
|
|
25909
|
+
process.stdout.write(`${output}\n`);
|
|
25910
|
+
}
|
|
25911
|
+
});
|
|
25757
25912
|
build_program
|
|
25758
25913
|
.command("scan", { isDefault: true })
|
|
25759
25914
|
.description("Scan a git diff and print a ProofPR report.")
|
|
@@ -25867,15 +26022,18 @@ function renderGuide() {
|
|
|
25867
26022
|
npx proof-pr@latest scan --base origin/main --head HEAD --format sarif --output proofpr.sarif
|
|
25868
26023
|
适合在 CI 里配合 github/codeql-action/upload-sarif 使用。
|
|
25869
26024
|
|
|
25870
|
-
6.
|
|
25871
|
-
npx proof-pr@latest
|
|
25872
|
-
|
|
26025
|
+
6. 不接入仓库,先试跑内置案例
|
|
26026
|
+
npx proof-pr@latest demo workflow --locale zh-CN
|
|
26027
|
+
不需要 clone 仓库或寻找 examples 文件,也能快速看到 ProofPR 会抓什么风险。
|
|
25873
26028
|
|
|
25874
|
-
7.
|
|
26029
|
+
7. 查看所有内置案例
|
|
26030
|
+
npx proof-pr@latest demo --list
|
|
26031
|
+
|
|
26032
|
+
8. 验证规则样本是否仍然命中
|
|
25875
26033
|
npx proof-pr@latest benchmark --cases benchmarks/cases
|
|
25876
26034
|
适合维护 ProofPR 规则或发版前回归。
|
|
25877
26035
|
|
|
25878
|
-
|
|
26036
|
+
9. 调整审查强度
|
|
25879
26037
|
打开 .proofpr.yml,把 preset 改成 security-strict、dependency-careful 或 mcp-security。
|
|
25880
26038
|
|
|
25881
26039
|
结果在哪里看:
|
|
@@ -25883,6 +26041,37 @@ function renderGuide() {
|
|
|
25883
26041
|
- 本地 CLI:终端输出;如果用了 --output,就看写出的 HTML / JSON / SARIF / Markdown 文件。
|
|
25884
26042
|
`;
|
|
25885
26043
|
}
|
|
26044
|
+
function renderDemoList() {
|
|
26045
|
+
const rows = DEMO_CASES.map((item) => `- ${item.id}: ${item.title}\n ${item.description}`).join("\n");
|
|
26046
|
+
return `ProofPR 内置案例
|
|
26047
|
+
|
|
26048
|
+
用法:
|
|
26049
|
+
npx proof-pr@latest demo <case> --locale zh-CN
|
|
26050
|
+
|
|
26051
|
+
可用案例:
|
|
26052
|
+
${rows}
|
|
26053
|
+
`;
|
|
26054
|
+
}
|
|
26055
|
+
function renderDemoOutput(demoCase, result, format, locale) {
|
|
26056
|
+
if (format === "json") {
|
|
26057
|
+
return JSON.stringify({
|
|
26058
|
+
demo: {
|
|
26059
|
+
id: demoCase.id,
|
|
26060
|
+
title: demoCase.title,
|
|
26061
|
+
description: demoCase.description
|
|
26062
|
+
},
|
|
26063
|
+
result
|
|
26064
|
+
}, null, 2);
|
|
26065
|
+
}
|
|
26066
|
+
if (format === "markdown") {
|
|
26067
|
+
return `# ProofPR demo: ${demoCase.title}
|
|
26068
|
+
|
|
26069
|
+
${demoCase.description}
|
|
26070
|
+
|
|
26071
|
+
${renderMarkdownReport(result, locale)}`;
|
|
26072
|
+
}
|
|
26073
|
+
return renderOutput(result, format, locale);
|
|
26074
|
+
}
|
|
25886
26075
|
async function runDoctor(options) {
|
|
25887
26076
|
const checks = [];
|
|
25888
26077
|
const nextSteps = new Set();
|