@rmartz/pr-policy 0.2.0 → 0.9.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.
package/dist/index.d.ts CHANGED
@@ -10,19 +10,56 @@ interface FileChange {
10
10
  /** Content at the PR head. */
11
11
  headText?: string;
12
12
  }
13
+ /**
14
+ * A repository role, fine-grained where GitHub reports one. `none` covers a
15
+ * non-collaborator and a lookup that failed, so an unknown actor never counts.
16
+ */
17
+ declare const REPO_PERMISSIONS: readonly ["admin", "maintain", "write", "triage", "read", "none"];
18
+ type RepoPermission = (typeof REPO_PERMISSIONS)[number];
19
+ /** Who last applied a label: the actor on its latest `labeled` event. */
20
+ interface LabelActor {
21
+ login: string;
22
+ /** GitHub's actor type: `User`, `Bot`, `Organization`, or `Mannequin`. */
23
+ type: string;
24
+ permission: RepoPermission;
25
+ }
26
+ /**
27
+ * Provenance for one sign-off label on the PR (see `SIGN_OFF_LABELS`).
28
+ * `appliedBy` is absent when no `labeled` event names a live account.
29
+ */
30
+ interface SignOff {
31
+ label: string;
32
+ appliedBy?: LabelActor;
33
+ }
34
+ /** The account that opened a PR, as GitHub reports it (`dependabot[bot]`, `Bot`). */
35
+ interface PullRequestAuthor {
36
+ login: string;
37
+ type: string;
38
+ }
13
39
  /**
14
40
  * The facts about a pull request that policy checks judge. Every field is a
15
- * property of the PR's own content — never its review history, which belongs to
16
- * the separate lifecycle reconciler (rmartz/ai-tools#306).
41
+ * property of the PR's current state — its content and the labels on it, never
42
+ * its review history, which belongs to the separate lifecycle reconciler
43
+ * (rmartz/ai-tools#306).
17
44
  */
18
45
  interface PullRequestFacts {
19
46
  title: string;
47
+ /**
48
+ * The PR description. Optional so a facts document without one still parses;
49
+ * `gatherFacts` always sets it (an empty description is `''`).
50
+ */
51
+ body?: string;
52
+ /** Who opened the PR. `gatherFacts` always sets it. */
53
+ author?: PullRequestAuthor;
20
54
  labels: readonly string[];
55
+ /** Every path the PR touches, including the old path of a rename. */
21
56
  changedFiles: readonly string[];
22
57
  /** Both sides of every changed `.github/workflows/**` file. */
23
58
  workflowChanges: readonly FileChange[];
24
59
  /** Both sides of every changed dependency manifest (`package.json`, `requirements*.txt`). */
25
60
  manifestChanges: readonly FileChange[];
61
+ /** Who applied each sign-off label present on the PR. */
62
+ signOffs: readonly SignOff[];
26
63
  }
27
64
  /**
28
65
  * What a finding does to the `pr-policy` check-run:
@@ -71,6 +108,17 @@ interface PolicyCheck {
71
108
  * `pr-policy` check-run. See docs/adding-a-check.md.
72
109
  */
73
110
  declare const CHECKS: readonly PolicyCheck[];
111
+ /**
112
+ * How a consuming repo tunes the suite. The caller passes these (a CLI flag, an
113
+ * Action input), never the PR, so a PR can't switch off a gate it would fail.
114
+ * Every option defaults to the strictest policy.
115
+ */
116
+ interface PolicyOptions {
117
+ /** Drop the UAT gate, for a repo with no user-acceptance testing to wait on. */
118
+ skipUat?: boolean;
119
+ }
120
+ /** The checks to run for a repo configured with `options`, in report order. */
121
+ declare function selectChecks(options?: PolicyOptions): readonly PolicyCheck[];
74
122
 
75
123
  /**
76
124
  * The indicator vocabulary — the classifier's whole output surface.
@@ -127,9 +175,63 @@ declare function classifyWorkflowChanges(changes: readonly WorkflowFileChange[])
127
175
 
128
176
  declare const CI_CHANGE_CHECK = "ci-change";
129
177
  /** Decide the findings and label edits for one classified PR. */
130
- declare function decideCiChange(classification: Classification, labels: readonly string[]): CheckResult;
178
+ declare function decideCiChange(classification: Classification, pr: Pick<PullRequestFacts, 'labels' | 'signOffs'>): CheckResult;
131
179
  declare const ciChangeCheck: PolicyCheck;
132
180
 
181
+ /**
182
+ * Check 4: a Dependabot PR changes only the updates it claims. bot-automerge
183
+ * merges these PRs without a human review, on the premise that the PR is what
184
+ * the bot says it is. This check enforces that premise: it reads the claim from
185
+ * the description and blocks on any change the claim doesn't cover — a stray
186
+ * path, an unclaimed dependency, a version other than the claimed one, or an
187
+ * edit Dependabot never makes. A mismatch means someone else pushed to the
188
+ * branch or edited the body; recreating the PR clears it.
189
+ *
190
+ * Applies only to PRs opened by `dependabot[bot]`. See docs/checks/dependabot.md.
191
+ */
192
+
193
+ declare const DEPENDABOT_CHECK = "dependabot";
194
+ declare const DEPENDABOT_LOGIN = "dependabot[bot]";
195
+ /** Every way this Dependabot PR's content departs from its claimed updates. */
196
+ declare function decideDependabot(pr: PullRequestFacts): CheckResult;
197
+ declare const dependabotCheck: PolicyCheck;
198
+
199
+ /**
200
+ * The updates a Dependabot PR claims, read from its description. The body is
201
+ * Dependabot's own record: a review agent may retitle the PR (`chore(deps):` →
202
+ * `ci(deps):`), but nothing rewrites the body. Three sentence forms carry every
203
+ * claim Dependabot makes, plus a summary table:
204
+ *
205
+ * - `Bumps [name](url) from A to B.` — a single update.
206
+ * - `| [name](url) | `A` | `B` |` — a row of the table a large group opens
207
+ * with. Dependabot truncates a long description, cutting off the per-package
208
+ * lines, but the table comes first and survives.
209
+ * - ``Updates `name` from A to B`` — one entry of a grouped update, or of a
210
+ * single PR that bumps packages together.
211
+ * - `Updates the requirements on [name](url) to permit ...` — a range change
212
+ * with no single target version.
213
+ *
214
+ * A group header (`Bumps the npm group with 3 updates: [a](url) and [b](url).`)
215
+ * names every package but no version. Its names count as claims with no target,
216
+ * so a truncated body that lost an `Updates` line still covers that package;
217
+ * wherever a versioned line survives, its version is the one checked.
218
+ */
219
+ /** One claimed update. `to` is absent for a range change or a removal. */
220
+ interface Claim {
221
+ name: string;
222
+ to?: string;
223
+ }
224
+ /**
225
+ * Every update the description claims, once per package. A package claimed
226
+ * twice with different targets keeps the last, which is what Dependabot's
227
+ * per-package `Updates` line states after a summary `Bumps` line.
228
+ */
229
+ declare function parseClaims(body: string): Claim[];
230
+
231
+ declare const MERGE_BLOCK_CHECK = "merge-block";
232
+ declare function decideMergeBlock(pr: PullRequestFacts): CheckResult;
233
+ declare const mergeBlockCheck: PolicyCheck;
234
+
133
235
  /**
134
236
  * Which files this guard considers "a CI workflow".
135
237
  *
@@ -204,6 +306,16 @@ declare const CI_APPROVAL_NEEDED_LABEL = "CI approval needed";
204
306
  * applies it.
205
307
  */
206
308
  declare const CI_CHANGE_APPROVED_LABEL = "CI change approved";
309
+ /**
310
+ * Labels a person puts on a PR to stop it merging. The merge-block check holds
311
+ * `pr-policy` while any of them is present, and never applies or removes one.
312
+ * `dnm` is shorthand for `do not merge`.
313
+ */
314
+ declare const DO_NOT_MERGE_LABEL = "do not merge";
315
+ declare const DNM_LABEL = "dnm";
316
+ declare const BLOCKED_LABEL = "blocked";
317
+ declare const ESCALATION_NEEDED_LABEL = "escalation needed";
318
+ declare const BLOCKING_LABELS: readonly ["do not merge", "dnm", "blocked", "escalation needed"];
207
319
  /**
208
320
  * Labels the title check reads and never writes. They belong to the review and
209
321
  * release flow: `breaking change` is the source of truth for a breaking PR,
@@ -247,7 +359,8 @@ declare function evaluatePolicy(pr: PullRequestFacts, checks?: readonly PolicyCh
247
359
 
248
360
  /**
249
361
  * Parse and validate a JSON facts document into `PullRequestFacts`.
250
- * `workflowChanges` and `manifestChanges` are optional and default to none.
362
+ * `workflowChanges`, `manifestChanges`, and `signOffs` are optional and default
363
+ * to none; `body` and `author` are optional and stay absent. With no `signOffs`, no sign-off label counts: trust fails closed.
251
364
  */
252
365
  declare function parseFacts(raw: string): PullRequestFacts;
253
366
 
@@ -272,5 +385,9 @@ declare function applyLabelEdits(target: PullRequestTarget, evaluation: PolicyEv
272
385
  declare function checkRunBody(evaluation: PolicyEvaluation, now: Date): Record<string, unknown>;
273
386
  /** Post (or complete) the one `pr-policy` check-run on the head commit. */
274
387
  declare function postCheckRun(target: PullRequestTarget, headSha: string, evaluation: PolicyEvaluation): Promise<void>;
388
+ /** The request body for the `pr-policy` commit status mirroring this evaluation. */
389
+ declare function statusBody(evaluation: PolicyEvaluation, runUrl: string | undefined): Record<string, unknown>;
390
+ /** Post the verdict: the `pr-policy` check-run, then the matching commit status. */
391
+ declare function postVerdict(target: PullRequestTarget, headSha: string, evaluation: PolicyEvaluation): Promise<void>;
275
392
 
276
- export { AMBIGUOUS_INDICATORS, type AmbiguousIndicator, BREAKING_CHANGE_LABEL, CHECKS, CI_APPROVAL_NEEDED_LABEL, CI_CHANGE_APPROVED_LABEL, CI_CHANGE_CHECK, CI_CHANGE_VERDICTS, CI_SENSITIVE_PACKAGES, COMMIT_TYPES, type CheckResult, type CheckRunReport, type CiChangeVerdict, type Classification, type CommitType, FUNCTIONAL_TYPES, type FileChange, type Finding, HOTFIX_LABEL, type Indicator, type IndicatorClass, type IndicatorKind, LOOSENING_INDICATORS, type LooseningIndicator, POLICY_OUTCOMES, PR_POLICY_CHECK_NAME, type ParsedTitle, type PolicyCheck, type PolicyEvaluation, type PolicyOutcome, type PullRequestFacts, type PullRequestTarget, RELEASE_PLEASE_PENDING_LABEL, TITLE_CHECK, type WorkflowFileChange, applyLabelEdits, buildReport, checkRunBody, ciChangeCheck, classifyWorkflowChanges, classifyWorkflowFile, decideCiChange, decideTitle, evaluatePolicy, gatherFacts, isManifestPath, isWorkflowPath, parseFacts, parseTitle, postCheckRun, sensitiveBumps, titleCheck };
393
+ export { AMBIGUOUS_INDICATORS, type AmbiguousIndicator, BLOCKED_LABEL, BLOCKING_LABELS, BREAKING_CHANGE_LABEL, CHECKS, CI_APPROVAL_NEEDED_LABEL, CI_CHANGE_APPROVED_LABEL, CI_CHANGE_CHECK, CI_CHANGE_VERDICTS, CI_SENSITIVE_PACKAGES, COMMIT_TYPES, type CheckResult, type CheckRunReport, type CiChangeVerdict, type Claim, type Classification, type CommitType, DEPENDABOT_CHECK, DEPENDABOT_LOGIN, DNM_LABEL, DO_NOT_MERGE_LABEL, ESCALATION_NEEDED_LABEL, FUNCTIONAL_TYPES, type FileChange, type Finding, HOTFIX_LABEL, type Indicator, type IndicatorClass, type IndicatorKind, LOOSENING_INDICATORS, type LooseningIndicator, MERGE_BLOCK_CHECK, POLICY_OUTCOMES, PR_POLICY_CHECK_NAME, type ParsedTitle, type PolicyCheck, type PolicyEvaluation, type PolicyOptions, type PolicyOutcome, type PullRequestAuthor, type PullRequestFacts, type PullRequestTarget, RELEASE_PLEASE_PENDING_LABEL, TITLE_CHECK, type WorkflowFileChange, applyLabelEdits, buildReport, checkRunBody, ciChangeCheck, classifyWorkflowChanges, classifyWorkflowFile, decideCiChange, decideDependabot, decideMergeBlock, decideTitle, dependabotCheck, evaluatePolicy, gatherFacts, isManifestPath, isWorkflowPath, mergeBlockCheck, parseClaims, parseFacts, parseTitle, postCheckRun, postVerdict, selectChecks, sensitiveBumps, statusBody, titleCheck };
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import {
2
2
  AMBIGUOUS_INDICATORS,
3
+ BLOCKED_LABEL,
4
+ BLOCKING_LABELS,
3
5
  BREAKING_CHANGE_LABEL,
4
6
  CHECKS,
5
7
  CI_APPROVAL_NEEDED_LABEL,
@@ -8,9 +10,15 @@ import {
8
10
  CI_CHANGE_VERDICTS,
9
11
  CI_SENSITIVE_PACKAGES,
10
12
  COMMIT_TYPES,
13
+ DEPENDABOT_CHECK,
14
+ DEPENDABOT_LOGIN,
15
+ DNM_LABEL,
16
+ DO_NOT_MERGE_LABEL,
17
+ ESCALATION_NEEDED_LABEL,
11
18
  FUNCTIONAL_TYPES,
12
19
  HOTFIX_LABEL,
13
20
  LOOSENING_INDICATORS,
21
+ MERGE_BLOCK_CHECK,
14
22
  POLICY_OUTCOMES,
15
23
  PR_POLICY_CHECK_NAME,
16
24
  RELEASE_PLEASE_PENDING_LABEL,
@@ -22,19 +30,29 @@ import {
22
30
  classifyWorkflowChanges,
23
31
  classifyWorkflowFile,
24
32
  decideCiChange,
33
+ decideDependabot,
34
+ decideMergeBlock,
25
35
  decideTitle,
36
+ dependabotCheck,
26
37
  evaluatePolicy,
27
38
  gatherFacts,
28
39
  isManifestPath,
29
40
  isWorkflowPath,
41
+ mergeBlockCheck,
42
+ parseClaims,
30
43
  parseFacts,
31
44
  parseTitle,
32
45
  postCheckRun,
46
+ postVerdict,
47
+ selectChecks,
33
48
  sensitiveBumps,
49
+ statusBody,
34
50
  titleCheck
35
- } from "./chunk-QINHHFJN.js";
51
+ } from "./chunk-PVXDVMME.js";
36
52
  export {
37
53
  AMBIGUOUS_INDICATORS,
54
+ BLOCKED_LABEL,
55
+ BLOCKING_LABELS,
38
56
  BREAKING_CHANGE_LABEL,
39
57
  CHECKS,
40
58
  CI_APPROVAL_NEEDED_LABEL,
@@ -43,9 +61,15 @@ export {
43
61
  CI_CHANGE_VERDICTS,
44
62
  CI_SENSITIVE_PACKAGES,
45
63
  COMMIT_TYPES,
64
+ DEPENDABOT_CHECK,
65
+ DEPENDABOT_LOGIN,
66
+ DNM_LABEL,
67
+ DO_NOT_MERGE_LABEL,
68
+ ESCALATION_NEEDED_LABEL,
46
69
  FUNCTIONAL_TYPES,
47
70
  HOTFIX_LABEL,
48
71
  LOOSENING_INDICATORS,
72
+ MERGE_BLOCK_CHECK,
49
73
  POLICY_OUTCOMES,
50
74
  PR_POLICY_CHECK_NAME,
51
75
  RELEASE_PLEASE_PENDING_LABEL,
@@ -57,14 +81,22 @@ export {
57
81
  classifyWorkflowChanges,
58
82
  classifyWorkflowFile,
59
83
  decideCiChange,
84
+ decideDependabot,
85
+ decideMergeBlock,
60
86
  decideTitle,
87
+ dependabotCheck,
61
88
  evaluatePolicy,
62
89
  gatherFacts,
63
90
  isManifestPath,
64
91
  isWorkflowPath,
92
+ mergeBlockCheck,
93
+ parseClaims,
65
94
  parseFacts,
66
95
  parseTitle,
67
96
  postCheckRun,
97
+ postVerdict,
98
+ selectChecks,
68
99
  sensitiveBumps,
100
+ statusBody,
69
101
  titleCheck
70
102
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmartz/pr-policy",
3
- "version": "0.2.0",
3
+ "version": "0.9.0",
4
4
  "description": "Read-only PR content classifiers — CI-change classification, title-type rules, and more — reported as one blocking pr-policy check-run. Distributed as a pinned Action kept current by Dependabot.",
5
5
  "keywords": [
6
6
  "pr-policy",