patchdrill 0.1.0

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 (169) hide show
  1. package/.patchdrill.yml +33 -0
  2. package/CHANGELOG.md +150 -0
  3. package/CONTRIBUTING.md +59 -0
  4. package/LICENSE +21 -0
  5. package/README.md +601 -0
  6. package/SECURITY.md +28 -0
  7. package/action.yml +338 -0
  8. package/dist/baseline.d.ts +9 -0
  9. package/dist/baseline.js +38 -0
  10. package/dist/baseline.js.map +1 -0
  11. package/dist/cli.d.ts +19 -0
  12. package/dist/cli.js +662 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/codeowners.d.ts +14 -0
  15. package/dist/codeowners.js +104 -0
  16. package/dist/codeowners.js.map +1 -0
  17. package/dist/command-plan.d.ts +3 -0
  18. package/dist/command-plan.js +26 -0
  19. package/dist/command-plan.js.map +1 -0
  20. package/dist/demo.d.ts +5 -0
  21. package/dist/demo.js +525 -0
  22. package/dist/demo.js.map +1 -0
  23. package/dist/dependency.d.ts +4 -0
  24. package/dist/dependency.js +1424 -0
  25. package/dist/dependency.js.map +1 -0
  26. package/dist/doctor.d.ts +26 -0
  27. package/dist/doctor.js +183 -0
  28. package/dist/doctor.js.map +1 -0
  29. package/dist/evidence.d.ts +64 -0
  30. package/dist/evidence.js +352 -0
  31. package/dist/evidence.js.map +1 -0
  32. package/dist/git.d.ts +16 -0
  33. package/dist/git.js +349 -0
  34. package/dist/git.js.map +1 -0
  35. package/dist/i18n-catalog.d.ts +8 -0
  36. package/dist/i18n-catalog.js +446 -0
  37. package/dist/i18n-catalog.js.map +1 -0
  38. package/dist/i18n.d.ts +20 -0
  39. package/dist/i18n.js +67 -0
  40. package/dist/i18n.js.map +1 -0
  41. package/dist/init.d.ts +13 -0
  42. package/dist/init.js +312 -0
  43. package/dist/init.js.map +1 -0
  44. package/dist/markdown-links.d.ts +18 -0
  45. package/dist/markdown-links.js +180 -0
  46. package/dist/markdown-links.js.map +1 -0
  47. package/dist/package-scripts.d.ts +3 -0
  48. package/dist/package-scripts.js +55 -0
  49. package/dist/package-scripts.js.map +1 -0
  50. package/dist/planner.d.ts +8 -0
  51. package/dist/planner.js +2351 -0
  52. package/dist/planner.js.map +1 -0
  53. package/dist/policy.d.ts +12 -0
  54. package/dist/policy.js +255 -0
  55. package/dist/policy.js.map +1 -0
  56. package/dist/project.d.ts +2 -0
  57. package/dist/project.js +1085 -0
  58. package/dist/project.js.map +1 -0
  59. package/dist/release-readiness.d.ts +25 -0
  60. package/dist/release-readiness.js +426 -0
  61. package/dist/release-readiness.js.map +1 -0
  62. package/dist/report-annotations.d.ts +3 -0
  63. package/dist/report-annotations.js +28 -0
  64. package/dist/report-annotations.js.map +1 -0
  65. package/dist/report-contract.d.ts +2 -0
  66. package/dist/report-contract.js +82 -0
  67. package/dist/report-contract.js.map +1 -0
  68. package/dist/report-html.d.ts +7 -0
  69. package/dist/report-html.js +706 -0
  70. package/dist/report-html.js.map +1 -0
  71. package/dist/report-sarif.d.ts +2 -0
  72. package/dist/report-sarif.js +90 -0
  73. package/dist/report-sarif.js.map +1 -0
  74. package/dist/report.d.ts +14 -0
  75. package/dist/report.js +310 -0
  76. package/dist/report.js.map +1 -0
  77. package/dist/risk.d.ts +19 -0
  78. package/dist/risk.js +1226 -0
  79. package/dist/risk.js.map +1 -0
  80. package/dist/runner.d.ts +8 -0
  81. package/dist/runner.js +113 -0
  82. package/dist/runner.js.map +1 -0
  83. package/dist/scan.d.ts +2 -0
  84. package/dist/scan.js +195 -0
  85. package/dist/scan.js.map +1 -0
  86. package/dist/schema.d.ts +12 -0
  87. package/dist/schema.js +30 -0
  88. package/dist/schema.js.map +1 -0
  89. package/dist/stack-coverage.d.ts +8 -0
  90. package/dist/stack-coverage.js +94 -0
  91. package/dist/stack-coverage.js.map +1 -0
  92. package/dist/types.d.ts +206 -0
  93. package/dist/types.js +2 -0
  94. package/dist/types.js.map +1 -0
  95. package/dist/verification.d.ts +11 -0
  96. package/dist/verification.js +108 -0
  97. package/dist/verification.js.map +1 -0
  98. package/docs/ANNOTATIONS.md +34 -0
  99. package/docs/ARCHITECTURE.md +79 -0
  100. package/docs/BASELINES.md +32 -0
  101. package/docs/CASE_STUDIES.md +106 -0
  102. package/docs/CODEOWNERS.md +23 -0
  103. package/docs/DASHBOARD.md +87 -0
  104. package/docs/EVIDENCE.md +55 -0
  105. package/docs/LAUNCH_PLAYBOOK.md +103 -0
  106. package/docs/MONOREPOS.md +74 -0
  107. package/docs/POLICY.md +98 -0
  108. package/docs/PROOF_PACKS.md +57 -0
  109. package/docs/PR_COMMENTS.md +56 -0
  110. package/docs/RELEASE.md +35 -0
  111. package/docs/ROADMAP.md +152 -0
  112. package/docs/RULE_CATALOG.md +90 -0
  113. package/docs/SARIF.md +74 -0
  114. package/docs/SCHEMAS.md +49 -0
  115. package/docs/SECURITY_POSTURE.md +32 -0
  116. package/docs/STACK_COVERAGE.md +20 -0
  117. package/docs/assets/patchdrill-demo.svg +21 -0
  118. package/docs/media/patchdrill-dashboard.png +0 -0
  119. package/docs/media/patchdrill-demo.gif +0 -0
  120. package/examples/case-studies/README.md +20 -0
  121. package/examples/demo/README.md +21 -0
  122. package/examples/demo/patchdrill-demo-summary.md +35 -0
  123. package/examples/demo/patchdrill-demo.html +623 -0
  124. package/examples/demo/patchdrill-demo.json +355 -0
  125. package/examples/demo/patchdrill-demo.md +120 -0
  126. package/examples/demo/patchdrill-demo.sarif +195 -0
  127. package/examples/report.md +128 -0
  128. package/examples/risky-agent-pr/README.md +15 -0
  129. package/examples/risky-agent-pr/patchdrill-demo-summary.md +41 -0
  130. package/examples/risky-agent-pr/patchdrill-demo.html +681 -0
  131. package/examples/risky-agent-pr/patchdrill-demo.json +483 -0
  132. package/examples/risky-agent-pr/patchdrill-demo.md +140 -0
  133. package/examples/risky-agent-pr/patchdrill-demo.sarif +398 -0
  134. package/fixtures/stacks/README.md +4 -0
  135. package/fixtures/stacks/android-gradle/fixture.json +33 -0
  136. package/fixtures/stacks/aspnet-core-service/fixture.json +36 -0
  137. package/fixtures/stacks/bazel-workspace/fixture.json +30 -0
  138. package/fixtures/stacks/buck2-workspace/fixture.json +30 -0
  139. package/fixtures/stacks/cargo-workspace/fixture.json +48 -0
  140. package/fixtures/stacks/django-app/fixture.json +25 -0
  141. package/fixtures/stacks/docker-compose/fixture.json +17 -0
  142. package/fixtures/stacks/dockerfile-service/fixture.json +17 -0
  143. package/fixtures/stacks/dotnet-service/fixture.json +36 -0
  144. package/fixtures/stacks/dotnet-solution-filter/fixture.json +62 -0
  145. package/fixtures/stacks/fastapi-app/fixture.json +29 -0
  146. package/fixtures/stacks/go-workspace/fixture.json +48 -0
  147. package/fixtures/stacks/java-gradle/fixture.json +29 -0
  148. package/fixtures/stacks/java-maven/fixture.json +32 -0
  149. package/fixtures/stacks/kubernetes-helm/fixture.json +25 -0
  150. package/fixtures/stacks/kubernetes-kustomize/fixture.json +21 -0
  151. package/fixtures/stacks/nested-go-workspace/fixture.json +51 -0
  152. package/fixtures/stacks/nextjs-app/fixture.json +34 -0
  153. package/fixtures/stacks/node-turbo-workspace/fixture.json +39 -0
  154. package/fixtures/stacks/pants-python/fixture.json +33 -0
  155. package/fixtures/stacks/php-composer/fixture.json +31 -0
  156. package/fixtures/stacks/python-service/fixture.json +21 -0
  157. package/fixtures/stacks/rails-app/fixture.json +25 -0
  158. package/fixtures/stacks/spring-boot-gradle/fixture.json +29 -0
  159. package/fixtures/stacks/spring-boot-maven/fixture.json +43 -0
  160. package/fixtures/stacks/swift-package/fixture.json +21 -0
  161. package/fixtures/stacks/terraform-module/fixture.json +17 -0
  162. package/fixtures/stacks/uv-python-service/fixture.json +47 -0
  163. package/fixtures/stacks/xcode-app/fixture.json +72 -0
  164. package/package.json +80 -0
  165. package/schemas/patchdrill-doctor.schema.json +171 -0
  166. package/schemas/patchdrill-evidence.schema.json +239 -0
  167. package/schemas/patchdrill-policy.schema.json +170 -0
  168. package/schemas/patchdrill-release-check.schema.json +78 -0
  169. package/schemas/patchdrill-report.schema.json +647 -0
package/README.md ADDED
@@ -0,0 +1,601 @@
1
+ # PatchDrill
2
+
3
+ [![CI](https://github.com/seungdori/patchdrill/actions/workflows/ci.yml/badge.svg)](https://github.com/seungdori/patchdrill/actions/workflows/ci.yml)
4
+ ![deterministic](https://img.shields.io/badge/deterministic-yes-2ea44f)
5
+ ![runs offline](https://img.shields.io/badge/runs-offline-2ea44f)
6
+ ![no model call](https://img.shields.io/badge/no%20model%20call-%E2%9C%93-2ea44f)
7
+ ![no telemetry](https://img.shields.io/badge/no%20telemetry-%E2%9C%93-2ea44f)
8
+ ![read-only by default](https://img.shields.io/badge/read--only-by%20default-2ea44f)
9
+ ![license MIT](https://img.shields.io/badge/license-MIT-blue)
10
+
11
+ ## Your AI reviewer says LGTM. CI is green. The PR still shouldn't merge.
12
+
13
+ PatchDrill is the **deterministic proof layer between code review and CI** for AI-generated and human patches. It reads the git diff and tells you exactly what proof should exist before you merge — **no model call, no network, the same answer every time.**
14
+
15
+ **Not a linter. Not SAST. Not an AI reviewer.** It answers the one question those tools never ask: *what proof should exist for THIS diff before merge — and what's missing?*
16
+
17
+ [![PatchDrill Proof Pack for a risky AI-agent PR — FAIL, risk 94/100](docs/media/patchdrill-demo.gif)](docs/media/patchdrill-dashboard.png)
18
+
19
+ *An AI agent opened this PR. PatchDrill scored it **FAIL · 94/100** — a privileged `pull_request_target` workflow checkout, a leaked secret, a disabled test script — in one offline, deterministic command. No model call. (Click for the full still report; regenerate the GIF with `vhs demo/patchdrill.tape`.)*
20
+
21
+ **What it catches in a diff:**
22
+
23
+ - **Leaked secrets** — `.env` files, private keys, and token-shaped strings added in the patch
24
+ - **Prompt injection** — instructions slipped into `AGENTS.md`, issue templates, and docs an agent will read
25
+ - **Workflow escalation** — broad token writes, `pull_request_target`, OIDC exchange, `secrets: inherit`, unpinned actions, remote-script pipes
26
+ - **Missing proof** — source changed with no test changed; required checks planned but never run
27
+ - **Dependency drift** — manifest changes with no matching lockfile (and lockfile drift with no manifest intent)
28
+ - **The verification it implies** — the actual commands for the *changed* packages + downstream dependents across ~25 ecosystems, not just root-level defaults
29
+
30
+ > **Built for teams merging AI-/agent-authored PRs who can't eyeball every diff anymore.** Run it locally in 30 seconds — no config, no CI changes, no API key:
31
+ >
32
+ > ```bash
33
+ > npx --yes github:seungdori/patchdrill demo --scenario risky-agent-pr
34
+ > ```
35
+
36
+ Output is a portable **Proof Pack** — Markdown, JSON, SARIF, a self-contained HTML dashboard, and a hash-stamped evidence manifest — that a human, a CI gate, an auditor, or a frontier model can all inspect. Run it in your language with `--locale ko|ja|zh`.
37
+
38
+ ## 30-Second Demo
39
+
40
+ Generate a risky AI-agent PR scenario without needing a git repository:
41
+
42
+ ```bash
43
+ npx --yes github:seungdori/patchdrill demo --scenario risky-agent-pr --output patchdrill-risky-demo
44
+ ```
45
+
46
+ Then inspect the reviewer-facing artifacts:
47
+
48
+ ```bash
49
+ cat patchdrill-risky-demo/patchdrill-demo-summary.md
50
+ open patchdrill-risky-demo/patchdrill-demo.html
51
+ ```
52
+
53
+ PatchDrill should show a privileged workflow boundary, secret-looking content, package lifecycle script risk, and the verification plan a reviewer should ask for before merge.
54
+
55
+ ```bash
56
+ npx --yes github:seungdori/patchdrill scan --base origin/main --run \
57
+ --evidence patchdrill-evidence.json \
58
+ --summary-markdown patchdrill-summary.md \
59
+ --markdown patchdrill-report.md \
60
+ --json patchdrill-report.json \
61
+ --sarif patchdrill.sarif \
62
+ --html patchdrill-dashboard.html \
63
+ --fail-on high \
64
+ --max-risk 69
65
+ npx --yes github:seungdori/patchdrill verify --evidence patchdrill-evidence.json
66
+ ```
67
+
68
+ ## Why Star It
69
+
70
+ - Makes AI-era PRs reviewable without asking another model to be the source of truth.
71
+ - Builds a Proof Pack for each patch: Markdown for humans, JSON for bots with required structured verification status, SARIF for GitHub code scanning, a self-contained HTML dashboard, compact PR summaries, and a later-verifiable audit manifest with report, artifact, and command-output hashes.
72
+ - Works locally first and in CI later. `scan` never mutates the repository, and commands only run when `--run` is set.
73
+ - Flags the review surfaces that routinely hide regressions: auth, billing, migrations, secrets, CI workflow supply chain, package automation scripts, infra, lockfiles, large diffs, prompt-injection content, missing test changes, and required checks that were planned but not run.
74
+ - Infers reviewable commands from the patch instead of only running root-level defaults.
75
+ - Works with the tools you already have: git, npm, pnpm, yarn, bun, pytest, Django, FastAPI, cargo, Go, Maven, Gradle, Spring Boot, Android Gradle, Ruby, Rails, RSpec, PHP, Composer, Laravel, dotnet, ASP.NET Core, Swift, Xcode, Terraform, Docker, Kubernetes, Helm, Bazel, and Buck2.
76
+ - Supports policy-as-code through `.patchdrill.yml`, including default, regulated, and agentic starter packs.
77
+ - Ships with serious open-source security posture: CodeQL, OpenSSF Scorecard, Dependabot, strict tests, and package dry-run verification.
78
+ - Understands Node, Cargo, Go, and Pants workspaces, plus nested Python projects, nested Cargo and Go workspaces, Turborepo, and Nx, targeting changed packages plus downstream dependents instead of blindly running only root-level commands.
79
+ - Includes first-party stack fixtures for Node/Turborepo, Next.js, Python, uv-managed Python, Django, FastAPI, Rails, PHP/Composer, Terraform, Docker/Compose, Kubernetes/Helm/Kustomize, Java/Maven/Gradle, Spring Boot Maven/Gradle, Android Gradle, .NET, ASP.NET Core, SwiftPM, Xcode, Bazel, Buck2, Pants, Cargo, and Go repository shapes.
80
+ - Explains package.json, pyproject.toml, requirements.txt, NuGet PackageReference and central PackageVersion files, Maven pom.xml, Gradle build files and version catalogs, Gemfile, composer.json, go.mod, Cargo.toml, npm package-lock, pnpm-lock, yarn.lock, bun.lock, go.sum, Cargo.lock, poetry.lock, uv.lock, Pipfile.lock, Gemfile.lock, and composer.lock dependency additions, removals, and version updates instead of only saying "lockfile changed."
81
+ - Flags dependency proof gaps such as manifest-only dependency changes or lockfile-only resolution drift.
82
+ - Adds CODEOWNERS owner hints to changed files so reviewers can see the responsible teams.
83
+ - Includes launch-friendly case studies, a public stack coverage matrix, and per-command verification status so teams can evaluate what evidence PatchDrill actually emits.
84
+
85
+ ## What It Does
86
+
87
+ PatchDrill answers four questions every reviewer asks:
88
+
89
+ 1. What changed?
90
+ 2. Which parts of the stack are touched?
91
+ 3. What should be run to prove this patch?
92
+ 4. What risk remains after the drill?
93
+
94
+ PatchDrill is not another AI code reviewer. It does not ask a model whether a diff "looks good." It builds deterministic evidence:
95
+
96
+ | Layer | Primary question | Deterministic? | Runs commands? | Output |
97
+ | --- | --- | --- | --- | --- |
98
+ | AI PR reviewer | Does this diff look right? | No | Usually no | Comments, suggestions, design feedback |
99
+ | Traditional CI | Did preconfigured checks pass? | Yes | Yes | Logs and pass/fail status |
100
+ | SAST/SCA scanner | Does this match a known security or dependency rule? | Yes | Sometimes | Alerts and vulnerability findings |
101
+ | Review automation | Did configured review automation fire? | Yes | Sometimes | PR comments and annotations |
102
+ | PatchDrill | What proof should exist for this diff? | Yes | Only with `--run` | Proof Pack, risk findings, command plan, policy gate |
103
+
104
+ The boundary is intentional: models are good at judgment, while PatchDrill is good at producing the same reviewable safety evidence for the same patch every time. Run PatchDrill first, then hand the Proof Pack to a human reviewer, CI gate, audit trail, or frontier model.
105
+
106
+ ## Proof Pack
107
+
108
+ A Proof Pack is the portable evidence bundle generated for a patch:
109
+
110
+ - Compact Markdown summary for PR comments and step summaries.
111
+ - Full Markdown report for human review.
112
+ - JSON report for bots, dashboards, and policy gates.
113
+ - SARIF report for GitHub code scanning.
114
+ - Self-contained HTML dashboard, including optional trend history.
115
+ - Evidence manifest that records report, artifact, and command-output digests.
116
+
117
+ See [docs/EVIDENCE.md](docs/EVIDENCE.md) for manifest verification and [docs/PROOF_PACKS.md](docs/PROOF_PACKS.md) for how to use Proof Packs in review workflows.
118
+
119
+ Print the boundary and suggested first commands from the CLI:
120
+
121
+ ```bash
122
+ patchdrill explain
123
+ ```
124
+
125
+ Example summary:
126
+
127
+ ```text
128
+ PatchDrill Gate PASS - assessment WARN, risk 42/100, confidence 58/100
129
+ Gate policy: fail-on critical, max-risk 69
130
+ Changed files: 4, +121/-18
131
+ Required commands: 3, optional commands: 1
132
+ Verification evidence: 0 run, 0 passed, 0 failed, 0 timed out, 3 missing required, 1 optional skipped
133
+ Added lines inspected: 121
134
+ Top findings:
135
+ - [high] High-impact product area changed (src/auth/session.ts)
136
+ - [medium] Source changed without test changes
137
+ Run with --run to execute required verification commands. Add --run-optional to include optional checks.
138
+ ```
139
+
140
+ ## Install
141
+
142
+ Run it instantly with no install, straight from GitHub:
143
+
144
+ ```bash
145
+ npx --yes github:seungdori/patchdrill scan --base origin/main
146
+ ```
147
+
148
+ Once the npm package is published, the same works without the `github:` prefix:
149
+
150
+ ```bash
151
+ npx patchdrill scan --base origin/main
152
+ ```
153
+
154
+ Or install the published package globally:
155
+
156
+ ```bash
157
+ npm install -g patchdrill
158
+ patchdrill scan --base origin/main
159
+ ```
160
+
161
+ The examples below use `patchdrill` for readability. Replace it with `npx --yes github:seungdori/patchdrill` when running directly from this repository.
162
+
163
+ ## Quickstart
164
+
165
+ Try the output without a git repository:
166
+
167
+ ```bash
168
+ patchdrill demo --output patchdrill-demo
169
+ ```
170
+
171
+ Try the failure case that shows what PatchDrill catches in an agent-authored PR:
172
+
173
+ ```bash
174
+ patchdrill demo --scenario risky-agent-pr --output patchdrill-risky-demo
175
+ ```
176
+
177
+ Diagnose what PatchDrill can infer from your repository before changing CI:
178
+
179
+ ```bash
180
+ patchdrill doctor
181
+ ```
182
+
183
+ For automation:
184
+
185
+ ```bash
186
+ patchdrill doctor --format json
187
+ ```
188
+
189
+ Analyze uncommitted work:
190
+
191
+ ```bash
192
+ patchdrill scan
193
+ ```
194
+
195
+ Analyze a branch against `main`:
196
+
197
+ ```bash
198
+ patchdrill scan --base origin/main
199
+ ```
200
+
201
+ Run the inferred required commands:
202
+
203
+ ```bash
204
+ patchdrill scan --base origin/main --run
205
+ ```
206
+
207
+ Include optional checks such as browser/e2e and static-analysis plans:
208
+
209
+ ```bash
210
+ patchdrill scan --base origin/main --run --run-optional
211
+ ```
212
+
213
+ Write and verify a Proof Pack:
214
+
215
+ ```bash
216
+ patchdrill scan --base origin/main --run \
217
+ --evidence patchdrill-evidence.json \
218
+ --summary-markdown patchdrill-summary.md \
219
+ --markdown patchdrill-report.md \
220
+ --json patchdrill-report.json \
221
+ --sarif patchdrill.sarif \
222
+ --html patchdrill-dashboard.html
223
+ patchdrill verify --evidence patchdrill-evidence.json
224
+ ```
225
+
226
+ Create a static dashboard from a saved JSON report:
227
+
228
+ ```bash
229
+ patchdrill dashboard --json patchdrill-report.json --output patchdrill-dashboard.html
230
+ ```
231
+
232
+ `patchdrill dashboard` validates each saved JSON report contract before rendering, so stale or incomplete reports do not become polished dashboards.
233
+
234
+ Verify an evidence manifest against its generated artifacts:
235
+
236
+ ```bash
237
+ patchdrill verify --evidence patchdrill-evidence.json
238
+ ```
239
+
240
+ Check whether this repository is ready for npm/GitHub Action release:
241
+
242
+ ```bash
243
+ patchdrill release-check
244
+ patchdrill release-check --format json
245
+ ```
246
+
247
+ The release workflow also runs required PatchDrill verification, generates a local Proof Pack smoke bundle, and verifies its evidence manifest before `npm pack --dry-run`.
248
+
249
+ For automation:
250
+
251
+ ```bash
252
+ patchdrill release-check --format json
253
+ ```
254
+
255
+ Regenerate an evidence manifest after final artifact post-processing:
256
+
257
+ ```bash
258
+ patchdrill evidence --json patchdrill-report.json --evidence patchdrill-evidence.json \
259
+ --summary-markdown patchdrill-summary.md \
260
+ --markdown patchdrill-report.md \
261
+ --sarif patchdrill.sarif \
262
+ --html patchdrill-dashboard.html
263
+ ```
264
+
265
+ `patchdrill evidence` validates the saved JSON report contract first, including the required structured verification status, before writing the manifest.
266
+
267
+ See committed demo outputs in [examples/demo](examples/demo), including `patchdrill-demo-summary.md` as the PR comment preview.
268
+
269
+ Read the launch case studies in [docs/CASE_STUDIES.md](docs/CASE_STUDIES.md) and the fixture-backed support matrix in [docs/STACK_COVERAGE.md](docs/STACK_COVERAGE.md).
270
+
271
+ Add repeated JSON reports in oldest-to-newest order to show run trends:
272
+
273
+ ```bash
274
+ patchdrill dashboard --json previous-report.json --json patchdrill-report.json --output patchdrill-dashboard.html
275
+ ```
276
+
277
+ Use the GitHub Action with PR comments:
278
+
279
+ ```yaml
280
+ - uses: seungdori/patchdrill@v0
281
+ with:
282
+ base: origin/${{ github.base_ref }}
283
+ pr-comment: "true"
284
+ ```
285
+
286
+ The Action emits GitHub Checks annotations by default. See [docs/ANNOTATIONS.md](docs/ANNOTATIONS.md).
287
+
288
+ Use policy-as-code:
289
+
290
+ ```bash
291
+ patchdrill scan --config .patchdrill.yml
292
+ ```
293
+
294
+ Export JSON Schemas for editors and bots:
295
+
296
+ ```bash
297
+ patchdrill schema policy > patchdrill-policy.schema.json
298
+ patchdrill schema report > patchdrill-report.schema.json
299
+ patchdrill schema evidence > patchdrill-evidence.schema.json
300
+ patchdrill schema doctor > patchdrill-doctor.schema.json
301
+ patchdrill schema release-check > patchdrill-release-check.schema.json
302
+ ```
303
+
304
+ Compare against a previous report:
305
+
306
+ ```bash
307
+ patchdrill scan --baseline previous-patchdrill-report.json --max-risk-delta 0 --json patchdrill-report.json
308
+ ```
309
+
310
+ Add a GitHub Actions workflow:
311
+
312
+ ```bash
313
+ patchdrill init
314
+ ```
315
+
316
+ Add a workflow and starter policy:
317
+
318
+ ```bash
319
+ patchdrill init --policy
320
+ ```
321
+
322
+ Use a stricter starter policy pack:
323
+
324
+ ```bash
325
+ patchdrill init --policy-pack regulated
326
+ ```
327
+
328
+ ## CLI
329
+
330
+ ```text
331
+ patchdrill scan [options]
332
+ patchdrill dashboard --json <report.json> [--json <report.json>...] [--output <dashboard.html>]
333
+ patchdrill demo [--scenario <name>] [--output <directory>]
334
+ patchdrill doctor [--format text|json]
335
+ patchdrill evidence --json <report.json> --evidence <evidence.json> [artifact options]
336
+ patchdrill init [--force] [--policy] [--policy-pack <name>]
337
+ patchdrill explain
338
+ patchdrill release-check [--format text|json]
339
+ patchdrill schema [policy|report|evidence|doctor|release-check] [--output <path>]
340
+ patchdrill verify --evidence <patchdrill-evidence.json>
341
+ ```
342
+
343
+ Options:
344
+
345
+ | Option | Description |
346
+ | --- | --- |
347
+ | `--base <ref>` | Compare against a base ref, for example `origin/main`. |
348
+ | `--head <ref>` | Head ref when using `--base`, default `HEAD`. |
349
+ | `--config <path>` | Read policy from `.patchdrill.yml/json` or a specific path. |
350
+ | `--baseline <path>` | Compare against a previous PatchDrill JSON report. |
351
+ | `--evidence <path>` | Write a Proof Pack evidence manifest during `scan`/`evidence`, or select one for `verify`. `scan --evidence` requires `--json` so the manifest can verify the report contract. |
352
+ | `--run` | Execute required inferred verification commands. |
353
+ | `--run-optional` | With `--run`, also execute optional verification commands. |
354
+ | `--github-annotations` | Emit GitHub Actions log annotations for findings. |
355
+ | `--summary-markdown <path>` | Write a compact Markdown summary for PR comments or step summaries. |
356
+ | `--markdown <path>` | Write a Markdown report. |
357
+ | `--json <path>` | Write a JSON report. |
358
+ | `--sarif <path>` | Write a SARIF report for GitHub code scanning. |
359
+ | `--html <path>` | Write a self-contained static HTML dashboard. |
360
+ | `--fail-on <level>` | Fail when findings meet severity: `info`, `low`, `medium`, `high`, `critical`. |
361
+ | `--max-risk <score>` | Fail when risk score is above a 0-100 threshold, default `69`. |
362
+ | `--max-risk-delta <score>` | Fail when baseline risk increase is above a 0-100 threshold. Requires `--baseline`. |
363
+ | `--max-output-chars <n>` | Keep the last `n` characters from each command output stream, default `20000`. |
364
+ | `--command-timeout-ms <n>` | Stop each verification command after `n` milliseconds. |
365
+ | `--quiet` | Only use exit code. |
366
+ | `--locale <lang>` | Language for human-facing reports (markdown, summary, HTML, console): `en`, `ko`, `ja`, `zh`. Defaults to the system locale (`LC_ALL`/`LANG`), then English. JSON and SARIF stay English. |
367
+ | `--policy` | Create `.patchdrill.yml` when used with `patchdrill init`. |
368
+ | `--policy-pack <name>` | Starter policy pack for `patchdrill init`: `default`, `regulated`, `agentic`. |
369
+ | `--scenario <name>` | Demo scenario for `patchdrill demo`: `review-ready`, `risky-agent-pr`. |
370
+ | `--format <format>` | Output format for `doctor` and `release-check`: `text`, `json`. |
371
+ | `--list` | List available schemas when used with `patchdrill schema`. |
372
+ | `--output <path>` | Write a schema/dashboard file or demo artifact directory. |
373
+
374
+ Boolean flags accept explicit values such as `--run=false`, `--quiet=true`, and `--github-annotations=off`.
375
+
376
+ ## Supported Signals
377
+
378
+ PatchDrill detects project shape from repo manifests:
379
+
380
+ | Ecosystem | Signals | Typical commands |
381
+ | --- | --- | --- |
382
+ | Node | `package.json`, lockfiles, scripts | `npm run typecheck`, `npm run check:types`, `npm run lint`, `npm run test`, `npm run test:unit`, `npm run build`, optional `npm run test:e2e` |
383
+ | Python | `pyproject.toml`, `uv.lock`, `requirements.txt`, `setup.py`, `manage.py`, nested Python package roots, `FastAPI()`, FastAPI routers/dependencies, Ruff/mypy/Pyright config | `uv run pytest tests/test_module.py`, `cd packages/api && uv run pytest`, `python -m pytest`, `python manage.py test`, `python -m compileall .`, optional `uv run ruff check .`, optional `uv run mypy .`, optional `uv run pyright`, FastAPI app and changed-module import smoke |
384
+ | Rust | `Cargo.toml`, root and nested Cargo workspaces | `cargo test --all-targets`, `cargo test -p crate --all-targets`, `cargo test --manifest-path packages/wasm/Cargo.toml -p crate --all-targets`, `cargo clippy -p crate --all-targets -- -D warnings` |
385
+ | Go | `go.mod`, `go.work`, nested Go module and workspace roots | `go test ./...`, `cd services/api && go test ./...`, `go test ./module/...`, `cd services/go && go test ./module/...`, `go vet ./module/...` |
386
+ | Java/Kotlin | `pom.xml`, `build.gradle`, wrappers | `mvn test`, `gradle test`, `./gradlew test`, `./gradlew bootJar` |
387
+ | Android | `com.android.application`, `com.android.library`, `AndroidManifest.xml`, build types, product flavors, `variantFilter`, variant source sets, generated source paths | `./gradlew testDebugUnitTest`, `./gradlew testReleaseUnitTest`, `./gradlew testFreeDebugUnitTest`, `./gradlew testMinApi24DemoDebugUnitTest`, `./gradlew assemble<Variant>`, `./gradlew lint<Variant>` |
388
+ | Ruby/Rails | `Gemfile`, `Gemfile.lock`, `config/application.rb`, RSpec metadata | `bin/rails test`, `bundle exec rails test`, `bundle exec rspec`, `bundle exec rake test` |
389
+ | PHP/Laravel | `composer.json`, `composer.lock`, `artisan`, `phpunit.xml` | `composer validate --strict`, `composer test`, `php artisan test`, `vendor/bin/phpunit`, PHP syntax lint fallback |
390
+ | .NET | `global.json`, `.slnf`, `.sln`, `.csproj`, `ProjectReference` | `dotnet test App.slnf`, `dotnet test tests/Api.Tests/Api.Tests.csproj`, `dotnet build src/Api/Api.csproj --no-restore`, `dotnet publish src/Api/Api.csproj --no-restore` |
391
+ | Swift | `Package.swift`, `Package.resolved`, `*.swift` | `swift test`, `swift build` |
392
+ | Xcode | `.xcworkspace`, `.xcodeproj`, shared `.xcscheme`, `.xctestplan`, Apple app source/resources, scheme target platforms | `xcodebuild -workspace App.xcworkspace -scheme App -testPlan AppTests test`, `xcodebuild -project App.xcodeproj -scheme App -destination generic/platform=iOS build`, `xcodebuild -project App.xcodeproj -scheme App -showdestinations` |
393
+ | Terraform | `*.tf`, `*.tfvars` | `terraform fmt -check && terraform validate` |
394
+ | Docker | `Dockerfile`, Compose files | `docker build .`, `docker compose -f compose.yaml config` |
395
+ | Kubernetes | `Chart.yaml`, `kustomization.yaml`, `k8s/`, `kubernetes/`, `manifests/` | `helm lint .`, `kubectl kustomize .`, `kubectl apply --dry-run=client -f k8s` |
396
+ | Bazel | `MODULE.bazel`, `WORKSPACE`, `BUILD.bazel`, `.bazelrc` | `bazel test //path/...`, `bazel build //path/...`, `bazel query 'rdeps(//..., set(//path/...))'`, optional downstream `tests(rdeps(...))` promotion, graph-wide fallback for root metadata |
397
+ | Buck2 | `.buckconfig`, `BUCK`, `BUCK.v2` | `buck2 test //path/...`, `buck2 build //path/...`, `buck2 uquery 'rdeps(//..., set(//path/...))'`, optional downstream `testsof(rdeps(...))` promotion, graph-wide fallback for root metadata |
398
+ | Pants | `pants.toml` | `pants --changed-since=HEAD --changed-dependents=transitive test` |
399
+ | GitHub Actions | `.github/workflows/*` | workflow diff review |
400
+
401
+ For Node workspaces, PatchDrill detects `package.json` workspaces and `pnpm-workspace.yaml`, then emits package-scoped commands such as `pnpm --filter @acme/api run test` or `npm --workspace @acme/api run build` for directly changed packages and downstream dependents. When `turbo.json` or `nx.json` is present, it plans native task-runner commands such as `pnpm exec turbo run test --filter=@acme/api` or `npx nx run api:test`. See [docs/MONOREPOS.md](docs/MONOREPOS.md).
402
+
403
+ For nested Python projects, PatchDrill treats each discovered `pyproject.toml`, `uv.lock`, `requirements.txt`, or `manage.py` package root as its own verification scope, so a monorepo can plan `cd packages/pine-engine && uv run pytest` instead of incorrectly collapsing every Python change into a root command.
404
+
405
+ For Cargo workspaces, including workspaces nested below a JavaScript or polyglot monorepo root, PatchDrill reads `[workspace].members`, crate names, and workspace-internal dependencies, then emits `cargo test -p crate --all-targets` or `cargo test --manifest-path packages/wasm/Cargo.toml -p crate --all-targets` plus optional clippy plans for changed crates and downstream dependent crates.
406
+
407
+ For nested Go modules and Go workspaces, PatchDrill treats each discovered `go.mod` or `go.work` root as its own verification scope. For Go workspaces, PatchDrill reads `go.work` `use` entries, module names, and workspace-internal `require` dependencies, then emits `go test ./module/...` or `cd services/go && go test ./module/...` plus optional `go vet` plans for changed modules and downstream dependent modules.
408
+
409
+ For Pants repositories, PatchDrill uses Pants' native Git-aware changed target selection with `--changed-since` and `--changed-dependents=transitive`, so Pants keeps ownership of target graph expansion across languages.
410
+
411
+ ## Risk Model
412
+
413
+ PatchDrill scores a patch from 0 to 100. Higher is riskier.
414
+
415
+ The current deterministic rules look for:
416
+
417
+ - Any changed files that need review and verification evidence.
418
+ - Secret-bearing files such as `.env` and private keys.
419
+ - Secret-looking values added inside the diff, including private keys and common token formats.
420
+ - Prompt-injection instructions added to agent-visible files such as `AGENTS.md`, issue templates, and Markdown docs.
421
+ - High-impact paths: auth, billing, sessions, migrations, security, crypto, permissions.
422
+ - Infra and release behavior: Docker, Terraform, Kubernetes, GitHub Actions.
423
+ - Workflow supply-chain risk: broad token writes, `pull_request_target`, inherited secrets, local reusable workflow fan-out to mutable remote reusable workflows, mutable reusable workflows receiving inherited secrets or caller OIDC permissions, environment-scoped OIDC deployment jobs, cloud OIDC credential exchange without environment protection, unpinned actions, mutable `docker://` action images, remote script pipes, untrusted PR metadata interpolation, and privileged PR-head checkout combinations.
424
+ - Package automation script risk: install/prepare/pack/publish lifecycle scripts, verification scripts removed or replaced with no-op commands, and package scripts that pipe remote downloads into interpreters.
425
+ - Dependency manifest and lockfile changes.
426
+ - package.json, pyproject.toml, requirements.txt, NuGet PackageReference and central PackageVersion files, Maven pom.xml, Gradle build files and version catalogs, Gemfile, composer.json, go.mod, Cargo.toml, npm package-lock, pnpm-lock, yarn.lock, bun.lock, go.sum, Cargo.lock, poetry.lock, uv.lock, Pipfile.lock, Gemfile.lock, and composer.lock dependency additions, removals, and updates.
427
+ - Dependency proof gaps: direct dependency manifest changes without matching lockfile evidence, and lockfile resolution changes without matching manifest dependency intent.
428
+ - Legacy binary `bun.lockb` changes with guidance to migrate toward the text `bun.lock` format.
429
+ - Source changes without nearby, mirrored, or framework-convention matching test changes.
430
+ - Large line deltas and binary files.
431
+ - Required verification commands that were inferred or configured but not run.
432
+ - Failed verification commands.
433
+ - Custom policy rules from `.patchdrill.yml`.
434
+
435
+ The risk model is intentionally explainable. Every score increase is represented as a finding in the report.
436
+
437
+ See [docs/RULE_CATALOG.md](docs/RULE_CATALOG.md) for the built-in rule IDs and what each one means.
438
+
439
+ ## Policy-As-Code
440
+
441
+ PatchDrill reads `.patchdrill.yml`, `.patchdrill.yaml`, or `.patchdrill.json` from the repository root.
442
+
443
+ ```yaml
444
+ failOn: high
445
+ maxRisk: 69
446
+
447
+ ignoredPaths:
448
+ - generated/**
449
+
450
+ requiredCommands:
451
+ - id: contract-tests
452
+ command: npm run test:contracts
453
+ reason: API surfaces changed.
454
+
455
+ rules:
456
+ - id: payments-owner-review
457
+ title: Payments owner review required
458
+ severity: critical
459
+ path: src/payments/**
460
+ ```
461
+
462
+ See [docs/POLICY.md](docs/POLICY.md).
463
+
464
+ ## GitHub Actions
465
+
466
+ Generate a workflow:
467
+
468
+ ```bash
469
+ patchdrill init
470
+ ```
471
+
472
+ Or add it manually:
473
+
474
+ ```yaml
475
+ name: PatchDrill
476
+
477
+ on:
478
+ pull_request:
479
+
480
+ permissions:
481
+ contents: read
482
+ pull-requests: write
483
+ security-events: write
484
+
485
+ jobs:
486
+ patchdrill:
487
+ runs-on: ubuntu-latest
488
+ steps:
489
+ - uses: actions/checkout@v6
490
+ with:
491
+ fetch-depth: 0
492
+ - uses: seungdori/patchdrill@v0
493
+ id: patchdrill
494
+ with:
495
+ base: origin/${{ github.base_ref }}
496
+ evidence: patchdrill-evidence.json
497
+ summary: patchdrill-summary.md
498
+ markdown: patchdrill-report.md
499
+ json: patchdrill-report.json
500
+ sarif: patchdrill.sarif
501
+ html: patchdrill-dashboard.html
502
+ fail-on: high
503
+ max-risk: "69"
504
+ run: "true"
505
+ command-timeout-ms: "600000"
506
+ annotations: "true"
507
+ step-summary: "true"
508
+ pr-comment: "true"
509
+ # Optional: newline-separated previous JSON reports downloaded from earlier artifacts.
510
+ # dashboard-history: |
511
+ # reports/patchdrill-previous.json
512
+ - uses: github/codeql-action/upload-sarif@v4
513
+ if: always()
514
+ with:
515
+ sarif_file: ${{ steps.patchdrill.outputs.report-sarif }}
516
+ - uses: actions/upload-artifact@v7
517
+ if: always()
518
+ with:
519
+ name: patchdrill-report
520
+ path: |
521
+ ${{ steps.patchdrill.outputs.report-evidence }}
522
+ ${{ steps.patchdrill.outputs.report-markdown }}
523
+ ${{ steps.patchdrill.outputs.report-summary }}
524
+ ${{ steps.patchdrill.outputs.report-json }}
525
+ ${{ steps.patchdrill.outputs.report-html }}
526
+ ${{ steps.patchdrill.outputs.report-sarif }}
527
+ ```
528
+
529
+ Action boolean inputs accept explicit values: `"true"`, `"false"`, `"1"`, `"0"`, `"yes"`, `"no"`, `"on"`, and `"off"`. Execution and annotation toggles are passed through the same CLI boolean parser, so `run: "false"` never executes repository commands.
530
+
531
+ ## Example Report
532
+
533
+ See [examples/report.md](examples/report.md).
534
+ For Proof Pack review workflows, see [docs/PROOF_PACKS.md](docs/PROOF_PACKS.md).
535
+ For code scanning integration, see [docs/SARIF.md](docs/SARIF.md).
536
+ For repository security posture, see [docs/SECURITY_POSTURE.md](docs/SECURITY_POSTURE.md).
537
+ For pull request comments, see [docs/PR_COMMENTS.md](docs/PR_COMMENTS.md).
538
+ For static HTML dashboards, see [docs/DASHBOARD.md](docs/DASHBOARD.md).
539
+ For evidence manifest verification, see [docs/EVIDENCE.md](docs/EVIDENCE.md).
540
+ For machine-readable schemas, see [docs/SCHEMAS.md](docs/SCHEMAS.md).
541
+ For owner hints, see [docs/CODEOWNERS.md](docs/CODEOWNERS.md).
542
+ For risk deltas, see [docs/BASELINES.md](docs/BASELINES.md).
543
+ For the built-in risk rules, see [docs/RULE_CATALOG.md](docs/RULE_CATALOG.md).
544
+
545
+ ## Release Provenance
546
+
547
+ PatchDrill includes a release workflow for npm trusted publishing and provenance. Configure the package as a trusted publisher in npm, then publish from a GitHub Release. See [docs/RELEASE.md](docs/RELEASE.md).
548
+
549
+ Before publishing, run:
550
+
551
+ ```bash
552
+ patchdrill release-check
553
+ ```
554
+
555
+ ## Dependency Review
556
+
557
+ PatchDrill summarizes dependency changes from changed `package.json`, `pyproject.toml`, `requirements.txt`, NuGet `PackageReference` / `PackageVersion` manifests, Maven `pom.xml`, Gradle `build.gradle` / `build.gradle.kts` / `libs.versions.toml`, `Gemfile`, `composer.json`, `go.mod`, `Cargo.toml`, npm `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `bun.lock`, `go.sum`, `Cargo.lock`, `poetry.lock`, `uv.lock`, `Pipfile.lock`, `Gemfile.lock`, and `composer.lock` files, listing the package, dependency section or lockfile path, change type, previous version, and new version in Markdown and JSON reports. It also flags dependency proof gaps, such as direct manifest changes without matching lockfile evidence or lockfile-only resolution drift without manifest intent. This complements heavier SCA tools by making reviewer-visible dependency intent explicit.
558
+
559
+ ## Package Script Review
560
+
561
+ PatchDrill also summarizes `package.json` script additions, removals, and updates in Markdown, JSON, and HTML reports. Risk findings call out install/prepare/pack/publish lifecycle hooks, no-op verification scripts, removed test/lint/build scripts, and package scripts that pipe remote downloads into interpreters.
562
+
563
+ ## Design Principles
564
+
565
+ - Deterministic first. No model call is required to get a useful answer. Findings, risk score, and command plan are reproducible for the same diff; the report's `generatedAt` timestamp is the only intentionally variable field, and it honors `SOURCE_DATE_EPOCH` so reports can be made byte-identical for caching, snapshotting, and reproducible audits.
566
+ - Proof Packs over vibes. A reviewer should see the exact commands, findings, artifacts, and digests.
567
+ - Local by default. Source code stays in your checkout.
568
+ - Conservative scoring. PatchDrill would rather ask for proof than silently bless a risky patch.
569
+ - Extensible later. The rule engine is small enough for contributors to add ecosystems and policies.
570
+ - Trustworthy distribution. CI verifies build, tests, SARIF generation, and npm package contents.
571
+
572
+ ## Roadmap
573
+
574
+ - Broader first-party fixture coverage for common open-source stacks.
575
+ - More native affected-task integrations beyond Turborepo, Nx, Pants, Cargo, Go, Bazel, and Buck workspaces.
576
+ - Local TUI for interactively accepting or rejecting inferred verification commands.
577
+ - Optional LLM summary mode that never replaces deterministic findings.
578
+
579
+ ## FAQ
580
+
581
+ **Is this an AI tool?** No. PatchDrill makes **zero model calls**, needs no API key, and runs fully offline. The same diff in produces a byte-identical Proof Pack out (it honors `SOURCE_DATE_EPOCH`). It is the deterministic layer that exists *because* AI writes code now — not another AI.
582
+
583
+ **Isn't this just a linter or SAST?** No. A linter checks code against fixed rules; SAST matches known vulnerability patterns. PatchDrill infers what verification *this specific diff* implies and reports the proof that *should* exist but doesn't — including required checks that were planned but never run. No linter or SAST tracks that gap.
584
+
585
+ **Is it another CI gate I have to add?** It doesn't have to be. Run it locally in 30 seconds with no config (`npx --yes github:seungdori/patchdrill demo`). It maps what your existing review and CI should each cover for a diff; `scan` never mutates your repo and commands run only with `--run`.
586
+
587
+ **Does it phone home?** No network calls, no telemetry, no account. Your source never leaves your checkout.
588
+
589
+ **Why trust a new project?** You don't have to trust the maintainer or a star count — re-run any Proof Pack and get byte-identical output, and verify every artifact hash yourself. CI proves the tool against first-party fixtures for ~25 stack shapes.
590
+
591
+ ## Contributing
592
+
593
+ Read [CONTRIBUTING.md](CONTRIBUTING.md). Good first contributions are new ecosystem detectors, risk rules, and real-world report fixtures.
594
+
595
+ ## Security
596
+
597
+ PatchDrill executes commands only when you pass `--run`. It runs inferred required commands in your repository shell; optional commands require both `--run` and `--run-optional`. When required checks are planned but not executed, PatchDrill reports that as missing verification evidence instead of silently treating the patch as proven. Markdown, compact summaries, the HTML dashboard, and console output label each planned command as passed, failed, timed out, not run, or skipped optional. `patchdrill init` writes a CI workflow with `run: "true"` and a per-command timeout so pull requests produce command evidence by default. Review the verification plan first when scanning untrusted repos. See [SECURITY.md](SECURITY.md).
598
+
599
+ ## License
600
+
601
+ MIT
package/SECURITY.md ADDED
@@ -0,0 +1,28 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ Please open a private security advisory on GitHub or email the maintainers once a public contact is listed.
6
+
7
+ Include:
8
+
9
+ - PatchDrill version or commit.
10
+ - Operating system and Node version.
11
+ - A minimal repo or diff that reproduces the issue.
12
+ - Whether `--run` was used.
13
+
14
+ ## Execution Model
15
+
16
+ PatchDrill has two modes:
17
+
18
+ - `scan`: reads git metadata and local files, then emits a plan and risk report.
19
+ - `scan --run`: executes inferred required verification commands in the repository shell.
20
+ - `scan --run --run-optional`: also executes optional verification commands such as browser, e2e, or static-analysis checks.
21
+
22
+ Do not use `--run` or `--run-optional` on untrusted repositories until you have reviewed the verification plan.
23
+
24
+ PatchDrill omits matched secret values from findings and SARIF messages. File names and line numbers can still be sensitive in private repositories, so treat generated reports as internal artifacts unless reviewed.
25
+
26
+ ## Data Handling
27
+
28
+ PatchDrill does not send source code or reports to a network service. Reports are written only to paths you request.