@homeflare/alchemy 0.25.1 → 0.27.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/github/declare-repo-baseline.d.ts +11 -0
- package/dist/github/declare-repo-baseline.d.ts.map +1 -0
- package/dist/github/index.d.ts +20 -11
- package/dist/github/index.d.ts.map +1 -1
- package/dist/github/index.js +715 -4
- package/dist/github/index.js.map +14 -4
- package/dist/github/repo-baseline-data.d.ts +75 -0
- package/dist/github/repo-baseline-data.d.ts.map +1 -0
- package/dist/github/repo-policy.d.ts +4 -4
- package/dist/github/repo-policy.d.ts.map +1 -1
- package/dist/github/repository-ruleset-constraints.d.ts +105 -0
- package/dist/github/repository-ruleset-constraints.d.ts.map +1 -0
- package/dist/github/repository-ruleset-errors.d.ts +97 -0
- package/dist/github/repository-ruleset-errors.d.ts.map +1 -0
- package/dist/github/repository-ruleset-fake-octokit.d.ts +24 -0
- package/dist/github/repository-ruleset-fake-octokit.d.ts.map +1 -0
- package/dist/github/repository-ruleset-fixtures.d.ts +20 -0
- package/dist/github/repository-ruleset-fixtures.d.ts.map +1 -0
- package/dist/github/repository-ruleset-form.d.ts +30 -0
- package/dist/github/repository-ruleset-form.d.ts.map +1 -0
- package/dist/github/repository-ruleset-guards.d.ts +70 -0
- package/dist/github/repository-ruleset-guards.d.ts.map +1 -0
- package/dist/github/repository-ruleset-octokit.d.ts +5 -0
- package/dist/github/repository-ruleset-octokit.d.ts.map +1 -0
- package/dist/github/repository-ruleset-probe.d.ts +87 -0
- package/dist/github/repository-ruleset-probe.d.ts.map +1 -0
- package/dist/github/repository-ruleset-reconcile.d.ts +24 -0
- package/dist/github/repository-ruleset-reconcile.d.ts.map +1 -0
- package/dist/github/repository-ruleset-test-helpers.d.ts +32 -0
- package/dist/github/repository-ruleset-test-helpers.d.ts.map +1 -0
- package/dist/github/repository-ruleset.d.ts +89 -0
- package/dist/github/repository-ruleset.d.ts.map +1 -0
- package/dist/launchd/index.js +51 -47
- package/dist/launchd/index.js.map +5 -4
- package/dist/launchd/sudo-guard-mode.d.ts +62 -0
- package/dist/launchd/sudo-guard-mode.d.ts.map +1 -0
- package/dist/launchd/sudo-guard.d.ts +1 -38
- package/dist/launchd/sudo-guard.d.ts.map +1 -1
- package/dist/linux/fake-sudo-root.d.ts +26 -0
- package/dist/linux/fake-sudo-root.d.ts.map +1 -0
- package/dist/linux/fake-sudo.d.ts +56 -0
- package/dist/linux/fake-sudo.d.ts.map +1 -0
- package/dist/linux/index.d.ts +2 -0
- package/dist/linux/index.d.ts.map +1 -1
- package/dist/linux/index.js +1134 -2
- package/dist/linux/index.js.map +22 -5
- package/dist/linux/sudo-allowlist-chown.d.ts +12 -0
- package/dist/linux/sudo-allowlist-chown.d.ts.map +1 -0
- package/dist/linux/sudo-allowlist-dir.d.ts +6 -0
- package/dist/linux/sudo-allowlist-dir.d.ts.map +1 -0
- package/dist/linux/sudo-allowlist.d.ts +40 -0
- package/dist/linux/sudo-allowlist.d.ts.map +1 -0
- package/dist/linux/sudo-exec.d.ts +31 -0
- package/dist/linux/sudo-exec.d.ts.map +1 -0
- package/dist/linux/sudo-guard.d.ts +36 -0
- package/dist/linux/sudo-guard.d.ts.map +1 -0
- package/dist/linux/sudo-runner.d.ts +37 -0
- package/dist/linux/sudo-runner.d.ts.map +1 -0
- package/dist/linux/sudo-stage.d.ts +22 -0
- package/dist/linux/sudo-stage.d.ts.map +1 -0
- package/dist/linux/sudo-write.d.ts +25 -0
- package/dist/linux/sudo-write.d.ts.map +1 -0
- package/dist/linux/unit-form.d.ts +2 -0
- package/dist/linux/unit-form.d.ts.map +1 -1
- package/dist/litellm/fake-litellm.d.ts.map +1 -1
- package/dist/proxmox/fake-pve-lxc.d.ts.map +1 -1
- package/docs/launchd-sudo.md +12 -3
- package/docs/linux-host.md +3 -3
- package/docs/linux-sudo.md +187 -0
- package/docs/repo-policy-ruleset-hazards.md +8 -0
- package/docs/repo-policy.md +27 -12
- package/docs/repository-ruleset.md +114 -0
- package/docs/upstream-conformance.md +12 -1
- package/docs/upstream-pr-ruleset-fixes.md +77 -0
- package/package.json +1 -1
- package/src/github/declare-repo-baseline.ts +42 -0
- package/src/github/index.ts +43 -11
- package/src/github/repo-baseline-data.test.ts +76 -0
- package/src/github/repo-baseline-data.ts +86 -0
- package/src/github/repo-policy.ts +17 -17
- package/src/github/repository-ruleset-constraints.ts +136 -0
- package/src/github/repository-ruleset-coverage.test.ts +82 -0
- package/src/github/repository-ruleset-errors.ts +136 -0
- package/src/github/repository-ruleset-fake-octokit.ts +131 -0
- package/src/github/repository-ruleset-fixtures.ts +183 -0
- package/src/github/repository-ruleset-form.ts +212 -0
- package/src/github/repository-ruleset-guards.ts +194 -0
- package/src/github/repository-ruleset-lifecycle.test.ts +172 -0
- package/src/github/repository-ruleset-octokit.ts +140 -0
- package/src/github/repository-ruleset-probe.ts +116 -0
- package/src/github/repository-ruleset-reconcile.ts +176 -0
- package/src/github/repository-ruleset-test-helpers.ts +102 -0
- package/src/github/repository-ruleset-wire.test.ts +66 -0
- package/src/github/repository-ruleset-write-refusals.test.ts +199 -0
- package/src/github/repository-ruleset-write.test.ts +83 -0
- package/src/github/repository-ruleset.ts +219 -0
- package/src/launchd/sudo-guard-mode.ts +111 -0
- package/src/launchd/sudo-guard.ts +3 -79
- package/src/launchd/sudo-modes.test.ts +38 -1
- package/src/linux/fake-sudo-root.ts +157 -0
- package/src/linux/fake-sudo.ts +142 -0
- package/src/linux/index.ts +2 -0
- package/src/linux/sudo-allowlist-chown.ts +71 -0
- package/src/linux/sudo-allowlist-dir.ts +103 -0
- package/src/linux/sudo-allowlist.test.ts +252 -0
- package/src/linux/sudo-allowlist.ts +223 -0
- package/src/linux/sudo-exec.ts +118 -0
- package/src/linux/sudo-guard.test.ts +136 -0
- package/src/linux/sudo-guard.ts +142 -0
- package/src/linux/sudo-lifecycle.test.ts +151 -0
- package/src/linux/sudo-runner.test.ts +206 -0
- package/src/linux/sudo-runner.ts +164 -0
- package/src/linux/sudo-stage.ts +50 -0
- package/src/linux/sudo-write.ts +167 -0
- package/src/linux/unit-form.ts +2 -1
- package/src/litellm/fake-litellm.ts +2 -0
- package/src/proxmox/client.test.ts +17 -3
- package/src/proxmox/fake-pve-lxc.ts +10 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
declare const DuplicateRuleset_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
2
|
+
readonly _tag: "DuplicateRuleset";
|
|
3
|
+
} & Readonly<A>;
|
|
4
|
+
/**
|
|
5
|
+
* More than one ruleset shares a name (and target) on the same repository. `probeByName`
|
|
6
|
+
* fails BEFORE reading either one — see repository-ruleset-probe.ts — because there is no
|
|
7
|
+
* way to know which one is "ours" and guessing risks converging the wrong ruleset.
|
|
8
|
+
*/
|
|
9
|
+
export declare class DuplicateRuleset extends DuplicateRuleset_base<{
|
|
10
|
+
readonly owner: string;
|
|
11
|
+
readonly repository: string;
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly ids: readonly number[];
|
|
14
|
+
}> {
|
|
15
|
+
get message(): string;
|
|
16
|
+
}
|
|
17
|
+
declare const BypassActorWidened_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
18
|
+
readonly _tag: "BypassActorWidened";
|
|
19
|
+
} & Readonly<A>;
|
|
20
|
+
/** A declared `bypassActors` entry names an actor the live ruleset does not have. Widening
|
|
21
|
+
* bypass is a handoff, never a deploy — see repository-ruleset-guards.ts. */
|
|
22
|
+
export declare class BypassActorWidened extends BypassActorWidened_base<{
|
|
23
|
+
readonly owner: string;
|
|
24
|
+
readonly repository: string;
|
|
25
|
+
readonly name: string;
|
|
26
|
+
readonly widened: readonly string[];
|
|
27
|
+
}> {
|
|
28
|
+
get message(): string;
|
|
29
|
+
}
|
|
30
|
+
declare const UndeclaredLiveRule_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
31
|
+
readonly _tag: "UndeclaredLiveRule";
|
|
32
|
+
} & Readonly<A>;
|
|
33
|
+
/** A live rule's `type` is neither modeled nor explicitly refused by RULE_TYPE_COVERAGE, or is
|
|
34
|
+
* refused and present live anyway. The PUT replaces `rules` wholesale, so silently omitting a
|
|
35
|
+
* live rule type would drop it — this fails the plan by name instead. */
|
|
36
|
+
export declare class UndeclaredLiveRule extends UndeclaredLiveRule_base<{
|
|
37
|
+
readonly owner: string;
|
|
38
|
+
readonly repository: string;
|
|
39
|
+
readonly name: string;
|
|
40
|
+
readonly ruleType: string;
|
|
41
|
+
}> {
|
|
42
|
+
get message(): string;
|
|
43
|
+
}
|
|
44
|
+
declare const RequiredChecksOmitted_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
45
|
+
readonly _tag: "RequiredChecksOmitted";
|
|
46
|
+
} & Readonly<A>;
|
|
47
|
+
/** The declaration omits `requiredStatusChecks` while adopting or updating a live ruleset that
|
|
48
|
+
* HAS one. Declare the contexts, or declare `requiredStatusChecks: false` to remove them. */
|
|
49
|
+
export declare class RequiredChecksOmitted extends RequiredChecksOmitted_base<{
|
|
50
|
+
readonly owner: string;
|
|
51
|
+
readonly repository: string;
|
|
52
|
+
readonly name: string;
|
|
53
|
+
readonly liveContexts: readonly string[];
|
|
54
|
+
}> {
|
|
55
|
+
get message(): string;
|
|
56
|
+
}
|
|
57
|
+
declare const NeverReportedContext_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
58
|
+
readonly _tag: "NeverReportedContext";
|
|
59
|
+
} & Readonly<A>;
|
|
60
|
+
/** A context being ADDED to `requiredStatusChecks` has never reported success on the default
|
|
61
|
+
* branch. Requiring it would leave every future pull request pending forever. */
|
|
62
|
+
export declare class NeverReportedContext extends NeverReportedContext_base<{
|
|
63
|
+
readonly owner: string;
|
|
64
|
+
readonly repository: string;
|
|
65
|
+
readonly context: string;
|
|
66
|
+
}> {
|
|
67
|
+
get message(): string;
|
|
68
|
+
}
|
|
69
|
+
declare const RulesetConstraintRefused_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
70
|
+
readonly _tag: "RulesetConstraintRefused";
|
|
71
|
+
} & Readonly<A>;
|
|
72
|
+
/** A prop value the wire form or GitHub's own schema refuses — an approval count outside 0–10,
|
|
73
|
+
* an empty `allowedMergeMethods`, or an unmodeled rule `type` in the declaration itself. */
|
|
74
|
+
export declare class RulesetConstraintRefused extends RulesetConstraintRefused_base<{
|
|
75
|
+
readonly field: string;
|
|
76
|
+
readonly reason: string;
|
|
77
|
+
}> {
|
|
78
|
+
get message(): string;
|
|
79
|
+
}
|
|
80
|
+
declare const ReadbackMismatch_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
81
|
+
readonly _tag: "ReadbackMismatch";
|
|
82
|
+
} & Readonly<A>;
|
|
83
|
+
/** The independent readback GET after a write does not match what was sent, for one of the
|
|
84
|
+
* fields this family refuses to leave unverified (S10: the write's own report is never proof). */
|
|
85
|
+
export declare class ReadbackMismatch extends ReadbackMismatch_base<{
|
|
86
|
+
readonly owner: string;
|
|
87
|
+
readonly repository: string;
|
|
88
|
+
readonly name: string;
|
|
89
|
+
readonly field: string;
|
|
90
|
+
readonly sent: unknown;
|
|
91
|
+
readonly read: unknown;
|
|
92
|
+
}> {
|
|
93
|
+
get message(): string;
|
|
94
|
+
}
|
|
95
|
+
export type RepositoryRulesetError = DuplicateRuleset | BypassActorWidened | UndeclaredLiveRule | RequiredChecksOmitted | NeverReportedContext | RulesetConstraintRefused | ReadbackMismatch;
|
|
96
|
+
export {};
|
|
97
|
+
//# sourceMappingURL=repository-ruleset-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-ruleset-errors.d.ts","sourceRoot":"","sources":["../../src/github/repository-ruleset-errors.ts"],"names":[],"mappings":";;;AAQA;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,sBAAqC;IACzE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAM7B;CACF;;;;AAED;6EAC6E;AAC7E,qBAAa,kBAAmB,SAAQ,wBAAuC;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAM7B;CACF;;;;AAED;;yEAEyE;AACzE,qBAAa,kBAAmB,SAAQ,wBAAuC;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAO7B;CACF;;;;AAED;6FAC6F;AAC7F,qBAAa,qBAAsB,SAAQ,2BAA0C;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAO7B;CACF;;;;AAED;iFACiF;AACjF,qBAAa,oBAAqB,SAAQ,0BAAyC;IACjF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAM7B;CACF;;;;AAED;4FAC4F;AAC5F,qBAAa,wBAAyB,SAAQ,8BAA6C;IACzF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAE7B;CACF;;;;AAED;kGACkG;AAClG,qBAAa,gBAAiB,SAAQ,sBAAqC;IACzE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAM7B;CACF;AAED,MAAM,MAAM,sBAAsB,GAC9B,gBAAgB,GAChB,kBAAkB,GAClB,kBAAkB,GAClB,qBAAqB,GACrB,oBAAoB,GACpB,wBAAwB,GACxB,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CreateRulesetBody } from './repository-ruleset-constraints.ts';
|
|
2
|
+
import type { RulesetOctokit, RulesetRecord } from './repository-ruleset-probe.ts';
|
|
3
|
+
/** Serves a fixed `{repo: RulesetRecord}` map and fails any write — for tests that must prove
|
|
4
|
+
* a plan is a pure read (a noop, or a refusal caught before any write). */
|
|
5
|
+
export declare function makeGetOnlyFake(byRepo: Readonly<Record<string, RulesetRecord>>): RulesetOctokit;
|
|
6
|
+
export interface RecordedWrite {
|
|
7
|
+
readonly op: 'create' | 'update' | 'delete';
|
|
8
|
+
readonly repo: string;
|
|
9
|
+
readonly body?: CreateRulesetBody;
|
|
10
|
+
}
|
|
11
|
+
export interface RecordingFake {
|
|
12
|
+
readonly octokit: RulesetOctokit;
|
|
13
|
+
readonly writes: RecordedWrite[];
|
|
14
|
+
/** Whether `hasContextReportedSuccess` answers `true` — defaults to `true` (every context
|
|
15
|
+
* has reported); set per-context to test `NeverReportedContext`. */
|
|
16
|
+
readonly reportedContexts: Set<string>;
|
|
17
|
+
}
|
|
18
|
+
/** An in-memory GitHub: `create` assigns an id and stores the record verbatim (merging the
|
|
19
|
+
* REQUEST body, not re-deriving it, so a test can inspect exactly what reconcile sent);
|
|
20
|
+
* `update` replaces the stored rules/enforcement/etc from the body; every write is also
|
|
21
|
+
* appended to `writes` for direct assertions ("N changed values give N non-noop results" is
|
|
22
|
+
* checked by counting entries here, not by re-reading state). */
|
|
23
|
+
export declare function makeRecordingFake(initial: Readonly<Record<string, RulesetRecord>>): RecordingFake;
|
|
24
|
+
//# sourceMappingURL=repository-ruleset-fake-octokit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-ruleset-fake-octokit.d.ts","sourceRoot":"","sources":["../../src/github/repository-ruleset-fake-octokit.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAkB,MAAM,+BAA+B,CAAC;AAKnG;2EAC2E;AAC3E,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,GAAG,cAAc,CAsB/F;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,iBAAiB,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC;IACjC;wEACoE;IACpE,QAAQ,CAAC,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACxC;AAID;;;;iEAIiE;AACjE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,GAAG,aAAa,CAqEjG"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The 16 live GitHub rulesets this family was walked against — captured 2026-09-23 by the
|
|
3
|
+
* planner's read-only `gh api` survey (owner `taslabs-net`; no secrets in any of these rows,
|
|
4
|
+
* only ruleset configuration GitHub already shows to any collaborator). Used by
|
|
5
|
+
* repository-ruleset-lifecycle.test.ts as a GET-only loopback fake, so a real baseline diff is
|
|
6
|
+
* checked against real shapes rather than a hand-picked "easy" fixture.
|
|
7
|
+
*
|
|
8
|
+
* Two simplifications from the raw survey, both noted here rather than silently taken:
|
|
9
|
+
* - `aimto`'s `secret scan (any app)` context is recorded as plain `secret scan` — the survey
|
|
10
|
+
* did not say the wire context string differs, only that the workflow's check-suite scope
|
|
11
|
+
* does; nothing in this family reads that scope, so it would not change any comparison.
|
|
12
|
+
* - `updated_at` is a placeholder ISO date derived from the survey's two-digit day, not the
|
|
13
|
+
* real timestamp (which the survey did not capture to the second).
|
|
14
|
+
*/
|
|
15
|
+
import type { RulesetRecord } from './repository-ruleset-probe.ts';
|
|
16
|
+
/** Keyed by repo name — every row from the LIVE SURVEY's per-repo ruleset table. */
|
|
17
|
+
export declare const LIVE_RULESET_FIXTURES: Readonly<Record<string, RulesetRecord>>;
|
|
18
|
+
/** repos with NO live ruleset at all (measured: 0 rulesets), per the survey's RULESETS section. */
|
|
19
|
+
export declare const REPOS_WITH_NO_RULESET: readonly string[];
|
|
20
|
+
//# sourceMappingURL=repository-ruleset-fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-ruleset-fixtures.d.ts","sourceRoot":"","sources":["../../src/github/repository-ruleset-fixtures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AA0DnE,oFAAoF;AACpF,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CA0GzE,CAAC;AAEF,mGAAmG;AACnG,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAAwB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Props → wire form, and a canonical form for comparing two wire rulesets.
|
|
3
|
+
*
|
|
4
|
+
* ★ THE CANONICALIZATION IS THE NEVER-NOOP FIX. Upstream `GitHub.Ruleset#reconcile` compares
|
|
5
|
+
* `desired` against the live GET with a raw `deepEqual` (see repository-ruleset.ts's header).
|
|
6
|
+
* GitHub does not promise to echo `rules`, `allowed_merge_methods` or `checks` back in
|
|
7
|
+
* request order, and a live `required_status_checks` check carries `integration_id: null`
|
|
8
|
+
* where the request never sent the key at all — so an unsorted, un-normalized comparison
|
|
9
|
+
* drifts against itself on every single plan. `canonicalizeWireRuleset` sorts every list that
|
|
10
|
+
* has no meaningful order and drops nullish `integration_id` before two wire rulesets are
|
|
11
|
+
* ever compared.
|
|
12
|
+
*/
|
|
13
|
+
import type { RepositoryRulesetProps, RepositoryRulesetRules } from './repository-ruleset.ts';
|
|
14
|
+
import type { CreateRulesetBody, WireRule } from './repository-ruleset-constraints.ts';
|
|
15
|
+
export declare function buildWireRules(rules: RepositoryRulesetRules | undefined): WireRule[];
|
|
16
|
+
/** The full desired wire body, minus `owner`/`repo` — sent verbatim to `createRepoRuleset` or
|
|
17
|
+
* `updateRepoRuleset`. */
|
|
18
|
+
export declare function desiredWireRuleset(props: RepositoryRulesetProps): CreateRulesetBody;
|
|
19
|
+
/**
|
|
20
|
+
* Normalize a wire ruleset (desired OR observed) so two representations of the same policy
|
|
21
|
+
* compare equal regardless of the order GitHub happens to echo lists back in.
|
|
22
|
+
*
|
|
23
|
+
* ⚠️ `input: unknown`, DELIBERATELY, NOT `CreateRulesetBody | RulesetRecord`. The two real
|
|
24
|
+
* callers (our own request body, and GitHub's JSON response) are independently typed and
|
|
25
|
+
* under `exactOptionalPropertyTypes` a shared structural interface fights both of them at
|
|
26
|
+
* once for no safety this function actually uses — every field below is read defensively,
|
|
27
|
+
* the same way a live GET already has to be, so a typed façade here would be decorative.
|
|
28
|
+
*/
|
|
29
|
+
export declare function canonicalizeWireRuleset(input: unknown): unknown;
|
|
30
|
+
//# sourceMappingURL=repository-ruleset-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-ruleset-form.d.ts","sourceRoot":"","sources":["../../src/github/repository-ruleset-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EACV,sBAAsB,EAEtB,sBAAsB,EAEvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AA2DvF,wBAAgB,cAAc,CAAC,KAAK,EAAE,sBAAsB,GAAG,SAAS,GAAG,QAAQ,EAAE,CAmCpF;AAED;0BAC0B;AAC1B,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,sBAAsB,GAAG,iBAAiB,CAqBnF;AA+CD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAiB/D"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Everything `reconcile` refuses before it writes, and why. Extracted so
|
|
3
|
+
* repository-ruleset.ts stays the wiring, and the reasoning stays whole — the same split
|
|
4
|
+
* `repo-policy-guards.ts` uses for `declareRepoPolicy`.
|
|
5
|
+
*/
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import type { RepositoryRulesetProps } from './repository-ruleset.ts';
|
|
8
|
+
import { BypassActorWidened, NeverReportedContext, RequiredChecksOmitted, UndeclaredLiveRule } from './repository-ruleset-errors.ts';
|
|
9
|
+
import type { RulesetOctokit, RulesetRecord } from './repository-ruleset-probe.ts';
|
|
10
|
+
/**
|
|
11
|
+
* ⛔ A CREATE REQUIRES `[]`; `undefined` on a create is the same thing (nothing live to widen
|
|
12
|
+
* from). On an update/adopt, `undefined` means unmanaged — the caller never sees this guard
|
|
13
|
+
* because repository-ruleset.ts sends the LIVE value back unchanged in that case, and this
|
|
14
|
+
* function is only called when `props.bypassActors` is explicitly declared.
|
|
15
|
+
*/
|
|
16
|
+
export declare function bypassWideningRefusal(input: {
|
|
17
|
+
readonly owner: string;
|
|
18
|
+
readonly repository: string;
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly declared: RepositoryRulesetProps['bypassActors'];
|
|
21
|
+
readonly live: RulesetRecord | undefined;
|
|
22
|
+
}): BypassActorWidened | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Refuses (a) any live rule of a REFUSED type — this resource can never represent it, and the
|
|
25
|
+
* PUT replaces `rules` wholesale, so silence would drop it; and (b) ANY live rule of a MODELED
|
|
26
|
+
* type the declaration is silent about — same hazard, for every rule this resource owns.
|
|
27
|
+
*
|
|
28
|
+
* ⚠️ `declaredTypes` MUST BE PRESENCE, NOT TRUTHINESS — this is the fix for a real bug this
|
|
29
|
+
* family's own design first shipped with. A plain `rules?.deletion` check cannot distinguish
|
|
30
|
+
* "omitted" from "declared `false`", so `undeclaredLiveRuleRefusal` originally exempted every
|
|
31
|
+
* boolean rule (`creation`/`update`/`deletion`/`requiredLinearHistory`/`requiredSignatures`/
|
|
32
|
+
* `nonFastForward`) as "fully owned — omission IS the removal". Concretely, that meant: a
|
|
33
|
+
* live ruleset has `deletion: true` (blocks branch deletion); a caller declares this resource
|
|
34
|
+
* with `rules: { pullRequest: {...}, requiredStatusChecks: {...} }`, simply forgetting
|
|
35
|
+
* `deletion: true` — an easy mistake, since omitting an optional boolean is not a type error.
|
|
36
|
+
* The wholesale PUT would have sent `rules` without a `deletion` entry, silently REMOVING
|
|
37
|
+
* branch-deletion protection on the very next `reconcile` — exactly the hazard this whole
|
|
38
|
+
* guard exists to prevent, reached through the one door it left open. Found by a self-review
|
|
39
|
+
* pass (no subagent available in this harness), not by a test; there is now one:
|
|
40
|
+
* repository-ruleset-write-refusals.test.ts's "an omitted boolean rule" case.
|
|
41
|
+
* `required_status_checks` still gets its own, better-worded `RequiredChecksOmitted` from
|
|
42
|
+
* {@link requiredChecksOmissionRefusal} and is excluded here so it is not refused twice.
|
|
43
|
+
*/
|
|
44
|
+
export declare function undeclaredLiveRuleRefusal(input: {
|
|
45
|
+
readonly owner: string;
|
|
46
|
+
readonly repository: string;
|
|
47
|
+
readonly name: string;
|
|
48
|
+
readonly live: RulesetRecord | undefined;
|
|
49
|
+
readonly declaredTypes: ReadonlySet<string>;
|
|
50
|
+
}): UndeclaredLiveRule | undefined;
|
|
51
|
+
/** The wire `type` for every rule key present ON THE DECLARATION OBJECT ITSELF — `Object.hasOwn`,
|
|
52
|
+
* not truthiness, so `{ deletion: false }` (an explicit, deliberate removal) counts as declared
|
|
53
|
+
* and a bare omission does not. Feeds `undeclaredLiveRuleRefusal`'s `declaredTypes`. */
|
|
54
|
+
export declare function declaredRuleTypes(rules: RepositoryRulesetProps['rules']): ReadonlySet<string>;
|
|
55
|
+
/** `requiredStatusChecks: undefined` while the live ruleset HAS one → refused, naming the live
|
|
56
|
+
* contexts. `requiredStatusChecks: false` is the declared removal and never reaches here. */
|
|
57
|
+
export declare function requiredChecksOmissionRefusal(input: {
|
|
58
|
+
readonly owner: string;
|
|
59
|
+
readonly repository: string;
|
|
60
|
+
readonly name: string;
|
|
61
|
+
readonly declared: RepositoryRulesetProps['rules'];
|
|
62
|
+
readonly live: RulesetRecord | undefined;
|
|
63
|
+
}): RequiredChecksOmitted | undefined;
|
|
64
|
+
/** Every context in the declared `requiredStatusChecks` that the LIVE ruleset does not already
|
|
65
|
+
* require — i.e. being added by this plan, the only case a never-reported context can matter. */
|
|
66
|
+
export declare const newlyRequiredContexts: (declared: RepositoryRulesetProps['rules'], live: RulesetRecord | undefined) => readonly string[];
|
|
67
|
+
/** Fails on the first newly-required context that has never reported success on the default
|
|
68
|
+
* branch — checked once here (reconcile's observe step) and again by the standalone checker. */
|
|
69
|
+
export declare const refuseUnreportedContexts: <R = never>(octokit: RulesetOctokit<R>, owner: string, repo: string, contexts: readonly string[]) => Effect.Effect<void, NeverReportedContext | Error, R>;
|
|
70
|
+
//# sourceMappingURL=repository-ruleset-guards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-ruleset-guards.d.ts","sourceRoot":"","sources":["../../src/github/repository-ruleset-guards.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAKnF;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC,cAAc,CAAC,CAAC;IAC1D,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAAC;CAC1C,GAAG,kBAAkB,GAAG,SAAS,CAyBjC;AAKD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC7C,GAAG,kBAAkB,GAAG,SAAS,CAyBjC;AAED;;wFAEwF;AACxF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,CAAC,OAAO,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,CAgB7F;AAED;6FAC6F;AAC7F,wBAAgB,6BAA6B,CAAC,KAAK,EAAE;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC,OAAO,CAAC,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAAC;CAC1C,GAAG,qBAAqB,GAAG,SAAS,CAcpC;AAED;iGACiG;AACjG,eAAO,MAAM,qBAAqB,aACtB,sBAAsB,CAAC,OAAO,CAAC,QACnC,aAAa,GAAG,SAAS,KAC9B,SAAS,MAAM,EAWjB,CAAC;AAEF;gGACgG;AAChG,eAAO,MAAM,wBAAwB,GAAI,CAAC,GAAG,KAAK,WACvC,cAAc,CAAC,CAAC,CAAC,SACnB,MAAM,QACP,MAAM,YACF,SAAS,MAAM,EAAE,KAC1B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,oBAAoB,GAAG,KAAK,EAAE,CAAC,CAQlD,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { GitHubCredentials } from 'alchemy/GitHub';
|
|
2
|
+
import type { RulesetOctokit } from './repository-ruleset-probe.ts';
|
|
3
|
+
export type RealRulesetOctokit = RulesetOctokit<GitHubCredentials>;
|
|
4
|
+
export declare const makeRulesetOctokit: (baseUrl: string | undefined) => RealRulesetOctokit;
|
|
5
|
+
//# sourceMappingURL=repository-ruleset-octokit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-ruleset-octokit.d.ts","sourceRoot":"","sources":["../../src/github/repository-ruleset-octokit.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGnD,OAAO,KAAK,EAAE,cAAc,EAAiC,MAAM,+BAA+B,CAAC;AAEnG,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,iBAAiB,CAAC,CAAC;AAcnE,eAAO,MAAM,kBAAkB,YAAa,MAAM,GAAG,SAAS,KAAG,kBAoG/D,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The name-probe: how this resource finds a ruleset it has no prior state for, and the one
|
|
3
|
+
* place `DuplicateRuleset` is raised. This is the fix for the hazard documented at the top of
|
|
4
|
+
* repository-ruleset.ts — upstream's `Ruleset#reconcile` only ever looks up by the id in prior
|
|
5
|
+
* `output`, so with none it calls `createRepoRuleset` unconditionally (measured in
|
|
6
|
+
* `node_modules/alchemy/src/GitHub/Ruleset.ts`, `reconcile`).
|
|
7
|
+
*
|
|
8
|
+
* `RulesetOctokit` is a small injected seam (mirrors `PgExecutor` in `postgres/database-sql.ts`)
|
|
9
|
+
* so the write-recording and GET-only fakes in the test files implement it directly — no HTTP
|
|
10
|
+
* mocking needed for the resource's own logic. `repository-ruleset.ts` supplies the real
|
|
11
|
+
* implementation, built from `octokitFor`/`GitHubCredentials` exactly as upstream's own
|
|
12
|
+
* `getRuleset`/`createRepoRuleset` calls do.
|
|
13
|
+
*/
|
|
14
|
+
import * as Effect from 'effect/Effect';
|
|
15
|
+
import type { CreateRulesetBody } from './repository-ruleset-constraints.ts';
|
|
16
|
+
import { DuplicateRuleset } from './repository-ruleset-errors.ts';
|
|
17
|
+
export interface RulesetSummary {
|
|
18
|
+
readonly id: number;
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly target?: string | undefined;
|
|
21
|
+
readonly source_type?: string | undefined;
|
|
22
|
+
}
|
|
23
|
+
export interface RulesetRecord extends RulesetSummary {
|
|
24
|
+
readonly node_id?: string | undefined;
|
|
25
|
+
readonly enforcement: string;
|
|
26
|
+
readonly bypass_actors?: readonly Record<string, unknown>[] | undefined;
|
|
27
|
+
readonly conditions?: unknown;
|
|
28
|
+
readonly rules?: readonly Record<string, unknown>[] | undefined;
|
|
29
|
+
readonly created_at?: string | undefined;
|
|
30
|
+
readonly updated_at?: string | undefined;
|
|
31
|
+
}
|
|
32
|
+
/** Every method carries `Error` in its error channel, matching upstream `Ruleset.ts`'s own
|
|
33
|
+
* `catch: (e) => e as Error` — a transport failure is not this resource's to type more
|
|
34
|
+
* precisely than upstream types its own. `R` is the real adapter's ambient requirement
|
|
35
|
+
* (`GitHubCredentials`, via `octokitFor` — see repository-ruleset-octokit.ts); test fakes need
|
|
36
|
+
* none, so they satisfy `RulesetOctokit<never>` — the default — without carrying it. */
|
|
37
|
+
export interface RulesetOctokit<R = never> {
|
|
38
|
+
/** Every ruleset owned directly by this repository (`includes_parents: false`, paginated) —
|
|
39
|
+
* the list endpoint omits `bypass_actors`, so a match is always re-read by id. */
|
|
40
|
+
readonly list: (input: {
|
|
41
|
+
readonly owner: string;
|
|
42
|
+
readonly repo: string;
|
|
43
|
+
}) => Effect.Effect<readonly RulesetSummary[], Error, R>;
|
|
44
|
+
/** `undefined` on a 404. */
|
|
45
|
+
readonly get: (input: {
|
|
46
|
+
readonly owner: string;
|
|
47
|
+
readonly repo: string;
|
|
48
|
+
readonly rulesetId: number;
|
|
49
|
+
}) => Effect.Effect<RulesetRecord | undefined, Error, R>;
|
|
50
|
+
readonly create: (input: {
|
|
51
|
+
readonly owner: string;
|
|
52
|
+
readonly repo: string;
|
|
53
|
+
readonly body: CreateRulesetBody;
|
|
54
|
+
}) => Effect.Effect<RulesetRecord, Error, R>;
|
|
55
|
+
readonly update: (input: {
|
|
56
|
+
readonly owner: string;
|
|
57
|
+
readonly repo: string;
|
|
58
|
+
readonly rulesetId: number;
|
|
59
|
+
readonly body: CreateRulesetBody;
|
|
60
|
+
}) => Effect.Effect<RulesetRecord, Error, R>;
|
|
61
|
+
/** A 404 is success (S11: idempotent delete). */
|
|
62
|
+
readonly delete: (input: {
|
|
63
|
+
readonly owner: string;
|
|
64
|
+
readonly repo: string;
|
|
65
|
+
readonly rulesetId: number;
|
|
66
|
+
}) => Effect.Effect<void, Error, R>;
|
|
67
|
+
/** Whether `context` has ever reported success against the repository's default branch —
|
|
68
|
+
* backs the `NeverReportedContext` guard. */
|
|
69
|
+
readonly hasContextReportedSuccess: (input: {
|
|
70
|
+
readonly owner: string;
|
|
71
|
+
readonly repo: string;
|
|
72
|
+
readonly context: string;
|
|
73
|
+
}) => Effect.Effect<boolean, Error, R>;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* List + filter by name and target, then:
|
|
77
|
+
* - 0 matches → `undefined` (a create is coming).
|
|
78
|
+
* - 1 match → GET it by id (the list omits `bypass_actors`) and return the full record.
|
|
79
|
+
* - `>1` → fail with `DuplicateRuleset`, naming every id, before reading any of them.
|
|
80
|
+
*/
|
|
81
|
+
export declare const probeByName: <R = never>(octokit: RulesetOctokit<R>, input: {
|
|
82
|
+
readonly owner: string;
|
|
83
|
+
readonly repo: string;
|
|
84
|
+
readonly name: string;
|
|
85
|
+
readonly target: string;
|
|
86
|
+
}) => Effect.Effect<RulesetRecord | undefined, DuplicateRuleset | Error, R>;
|
|
87
|
+
//# sourceMappingURL=repository-ruleset-probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-ruleset-probe.d.ts","sourceRoot":"","sources":["../../src/github/repository-ruleset-probe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `reconcile`'s body, apart from repository-ruleset.ts so the wiring there stays readable.
|
|
3
|
+
* One flow (S9): observe, then every plan-time and live-data refusal, then write only on
|
|
4
|
+
* drift (S10 — a matching noop makes zero calls), then an INDEPENDENT readback.
|
|
5
|
+
*/
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import type { RepositoryRulesetAttributes, RepositoryRulesetProps } from './repository-ruleset.ts';
|
|
8
|
+
import { type RepositoryRulesetError, type RulesetConstraintRefused } from './repository-ruleset-errors.ts';
|
|
9
|
+
import { type RulesetOctokit, type RulesetRecord } from './repository-ruleset-probe.ts';
|
|
10
|
+
/**
|
|
11
|
+
* `octokit` is INJECTED, never constructed in here — the real adapter comes from
|
|
12
|
+
* repository-ruleset.ts (`makeRulesetOctokit(news.baseUrl)`), and the write-recording and
|
|
13
|
+
* GET-only fakes in the test files pass their own. Nothing about the flow below depends on
|
|
14
|
+
* which one it is, which is the whole point of the seam (mirrors `reconcileWithClient(pg, …)`
|
|
15
|
+
* in postgres/database.ts taking its `PgExecutor` the same way).
|
|
16
|
+
*/
|
|
17
|
+
export declare const reconcileRuleset: <R = never>(input: {
|
|
18
|
+
readonly octokit: RulesetOctokit<R>;
|
|
19
|
+
readonly news: RepositoryRulesetProps;
|
|
20
|
+
readonly output: RepositoryRulesetAttributes | undefined;
|
|
21
|
+
readonly constraintRefusal: (props: RepositoryRulesetProps) => RulesetConstraintRefused | undefined;
|
|
22
|
+
readonly attrsOf: (r: RulesetRecord) => RepositoryRulesetAttributes;
|
|
23
|
+
}) => Effect.Effect<RepositoryRulesetAttributes, RepositoryRulesetError | Error, R>;
|
|
24
|
+
//# sourceMappingURL=repository-ruleset-reconcile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-ruleset-reconcile.d.ts","sourceRoot":"","sources":["../../src/github/repository-ruleset-reconcile.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEnG,OAAO,EAEL,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC9B,MAAM,gCAAgC,CAAC;AAUxC,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,aAAa,EAEnB,MAAM,+BAA+B,CAAC;AA+CvC;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,GAAG,KAAK,SAAS;IACjD,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,2BAA2B,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,iBAAiB,EAAE,CAC1B,KAAK,EAAE,sBAAsB,KAC1B,wBAAwB,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,2BAA2B,CAAC;CACrE,KAAG,MAAM,CAAC,MAAM,CAAC,2BAA2B,EAAE,sBAAsB,GAAG,KAAK,EAAE,CAAC,CAuF5E,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared plumbing for the write-recording fake tests, split out of
|
|
3
|
+
* repository-ruleset-write.test.ts and repository-ruleset-write-refusals.test.ts purely to keep
|
|
4
|
+
* both under the 250-line file cap — nothing here is a fixture of house-standard VALUES (that
|
|
5
|
+
* is repository-ruleset-fixtures.ts); this is just "run an Effect", "expect it to fail", and one
|
|
6
|
+
* baseline-shaped `RepositoryRulesetProps` for `widgets`.
|
|
7
|
+
*/
|
|
8
|
+
import * as Effect from 'effect/Effect';
|
|
9
|
+
import type { RecordingFake } from './repository-ruleset-fake-octokit.ts';
|
|
10
|
+
import { type RepositoryRulesetProps, type RepositoryRulesetPullRequestRule } from './repository-ruleset.ts';
|
|
11
|
+
import type { RepositoryRulesetError, RulesetConstraintRefused } from './repository-ruleset-errors.ts';
|
|
12
|
+
import type { RulesetOctokit } from './repository-ruleset-probe.ts';
|
|
13
|
+
export declare const run: <A, E>(eff: Effect.Effect<A, E>) => Promise<A>;
|
|
14
|
+
export declare const fails: <A, E>(eff: Effect.Effect<A, E>) => Promise<E>;
|
|
15
|
+
/** Every case across both files expects a TAGGED refusal, never the plain transport `Error` a
|
|
16
|
+
* real fetch failure would carry — narrowing here keeps every test's assertion a one-liner. */
|
|
17
|
+
export declare const tagOf: (error: RepositoryRulesetError | Error) => string;
|
|
18
|
+
export declare const constraintRefusal: () => RulesetConstraintRefused | undefined;
|
|
19
|
+
export declare const BASE_PULL_REQUEST: RepositoryRulesetPullRequestRule;
|
|
20
|
+
export declare const props: (over?: Partial<RepositoryRulesetProps>) => RepositoryRulesetProps;
|
|
21
|
+
/** Reconciles `p` against a `RecordingFake`, with `output` (when given) shaped as a real
|
|
22
|
+
* `RepositoryRulesetAttributes` — every field but `rulesetId` defaulted, since no test here
|
|
23
|
+
* reads `nodeId`/timestamps. */
|
|
24
|
+
export declare const reconcileAgainst: (fake: RecordingFake, p: RepositoryRulesetProps, output?: {
|
|
25
|
+
rulesetId: number;
|
|
26
|
+
}) => Effect.Effect<import("./repository-ruleset.ts").RepositoryRulesetAttributes, Error | RepositoryRulesetError, never>;
|
|
27
|
+
/** For the hand-built fakes in the refusals file, which construct a `RulesetOctokit` directly
|
|
28
|
+
* rather than going through `RecordingFake`. */
|
|
29
|
+
export declare const reconcileWithOctokit: (octokit: RulesetOctokit, p: RepositoryRulesetProps, output?: {
|
|
30
|
+
rulesetId: number;
|
|
31
|
+
}) => Effect.Effect<import("./repository-ruleset.ts").RepositoryRulesetAttributes, Error | RepositoryRulesetError, never>;
|
|
32
|
+
//# sourceMappingURL=repository-ruleset-test-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-ruleset-test-helpers.d.ts","sourceRoot":"","sources":["../../src/github/repository-ruleset-test-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,gCAAgC,EAEtC,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EACV,sBAAsB,EACtB,wBAAwB,EACzB,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAEpE,eAAO,MAAM,GAAG,GAAI,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,KAAG,OAAO,CAAC,CAAC,CAA2B,CAAC;AAC1F,eAAO,MAAM,KAAK,GAAI,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,KAAG,OAAO,CAAC,CAAC,CAC3B,CAAC;AAEtC;+FAC+F;AAC/F,eAAO,MAAM,KAAK,UAAW,sBAAsB,GAAG,KAAK,KAAG,MACA,CAAC;AAE/D,eAAO,MAAM,iBAAiB,QAAsB,wBAAwB,GAAG,SAAS,CAAC;AAEzF,eAAO,MAAM,iBAAiB,EAAE,gCAI/B,CAAC;AAEF,eAAO,MAAM,KAAK,UAAU,OAAO,CAAC,sBAAsB,CAAC,KAAQ,sBAcjE,CAAC;AAEH;;gCAEgC;AAChC,eAAO,MAAM,gBAAgB,SACrB,aAAa,KAChB,sBAAsB,WAChB;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,wHAiB5B,CAAC;AAEL;gDACgD;AAChD,eAAO,MAAM,oBAAoB,YACtB,cAAc,KACpB,sBAAsB,WAChB;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,wHAiB5B,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GitHub.RepositoryRuleset` — a bridge resource for the one thing upstream `GitHub.Ruleset`
|
|
3
|
+
* cannot do: find a ruleset that already exists before creating a second one with the same
|
|
4
|
+
* name.
|
|
5
|
+
*
|
|
6
|
+
* ⛔ THE HAZARD THIS EXISTS TO CLOSE. Read out of `alchemy@2.0.0-beta.79`'s own source
|
|
7
|
+
* (`node_modules/alchemy/src/GitHub/Ruleset.ts`, `reconcile`): `let observed = output ===
|
|
8
|
+
* undefined ? undefined : yield* getRuleset(news, output.rulesetId)`. With no prior state,
|
|
9
|
+
* `observed` stays `undefined` and `createRepoRuleset` runs UNCONDITIONALLY — there is no
|
|
10
|
+
* probe by name. GitHub permits several rulesets with one name on a repository, so nothing
|
|
11
|
+
* errors; the repo quietly ends up with two, both enforcing. `declareRepoPolicy` in this same
|
|
12
|
+
* package (repo-policy.ts) documents the same hazard and tells a caller to check `gh api
|
|
13
|
+
* repos/<owner>/<repo>/rulesets` by hand before every first deploy. This resource makes that
|
|
14
|
+
* check the engine's own job: `read`/`reconcile` list-and-filter by name+target before ever
|
|
15
|
+
* creating (see repository-ruleset-probe.ts).
|
|
16
|
+
*
|
|
17
|
+
* ★ WHY A NEW TYPE STRING, NOT A PATCHED `GitHub.Ruleset`. Upstream's `Ruleset` cannot be
|
|
18
|
+
* edited from here — it ships inside the `alchemy` package. `GitHub.RepositoryRuleset` is a
|
|
19
|
+
* distinct `Provider` (its own `Context.Service` keyed by this type string — see
|
|
20
|
+
* `alchemy/src/Provider.ts#Provider`), so it is declared and merged into a stack's provider
|
|
21
|
+
* layer independently of `GitHub.providers()` — the same way `postgres/database.ts` merges
|
|
22
|
+
* `PostgresDatabaseProvider()` beside it. Nothing about upstream's `GitHub.Providers`
|
|
23
|
+
* collection needs touching for the two to coexist in one stack. Props are a strict superset
|
|
24
|
+
* of upstream's `RulesetProps` (H14: the type string sits inside upstream's own `GitHub`
|
|
25
|
+
* namespace, recorded as house difference H15 below for the client choice).
|
|
26
|
+
*
|
|
27
|
+
* ⛔ H15: CLIENT IS OCTOKIT, NOT DISTILLED — A NAMED DIVERGENCE FROM S23. The house's default is
|
|
28
|
+
* `@distilled.cloud/*` when a vendor SDK exists there, and `@distilled.cloud/github@1.0.0-rc.12`
|
|
29
|
+
* does ship `createRepoRuleset`/`updateRepoRuleset`. But it has NO field for
|
|
30
|
+
* `require_extra_approval_for_unattributed_changes` (measured 2026-09-22: grep of its
|
|
31
|
+
* generated types), and its request bodies are plain `effect/Schema` `S.Struct`s, which strip
|
|
32
|
+
* properties a schema does not declare on encode — REASONED, not measured against distilled
|
|
33
|
+
* itself; repository-ruleset-wire.test.ts measures the Octokit side of the same question
|
|
34
|
+
* instead, because Octokit is the client this file actually uses. That flag is the entire
|
|
35
|
+
* reason this resource exists for the 0-approval, solo-maintainer shape (see
|
|
36
|
+
* repo-policy-guards.ts's `resolveApprovals` for the same story on the upstream-only path):
|
|
37
|
+
* GitHub defaults it to `true` when absent, which blocks the very pull requests a `0` was
|
|
38
|
+
* meant to allow. `octokitFor`/`GitHubCredentials` are upstream's own EXPORTED building
|
|
39
|
+
* blocks (S23's second clause: reuse Alchemy's own client construction), so the client itself
|
|
40
|
+
* is not hand-rolled — only the choice of Octokit over distilled is a recorded divergence.
|
|
41
|
+
*/
|
|
42
|
+
import { Resource } from 'alchemy';
|
|
43
|
+
import type { GitHubCredentials, RulesetProps } from 'alchemy/GitHub';
|
|
44
|
+
import * as Provider from 'alchemy/Provider';
|
|
45
|
+
import { type RulesetRecord } from './repository-ruleset-probe.ts';
|
|
46
|
+
type UpstreamRules = NonNullable<RulesetProps['rules']>;
|
|
47
|
+
export interface RepositoryRulesetReviewerRule {
|
|
48
|
+
readonly filePatterns: readonly string[];
|
|
49
|
+
readonly minimumApprovals: number;
|
|
50
|
+
readonly reviewer: {
|
|
51
|
+
readonly actorId: number;
|
|
52
|
+
readonly actorType: 'Team';
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export interface RepositoryRulesetPullRequestRule extends NonNullable<UpstreamRules['pullRequest']> {
|
|
56
|
+
/** @default every method GitHub allows — the house baseline always pins `['squash']`. */
|
|
57
|
+
readonly allowedMergeMethods?: readonly ('merge' | 'squash' | 'rebase')[];
|
|
58
|
+
readonly requiredReviewers?: readonly RepositoryRulesetReviewerRule[];
|
|
59
|
+
/** `require_extra_approval_for_unattributed_changes` — see H15 above. Only `false` is
|
|
60
|
+
* modeled: sending `true` has no house use, and GitHub already defaults absent to `true`. */
|
|
61
|
+
readonly extraApprovalForUnattributedChanges?: false;
|
|
62
|
+
}
|
|
63
|
+
export interface RepositoryRulesetStatusChecksRule extends NonNullable<UpstreamRules['requiredStatusChecks']> {
|
|
64
|
+
readonly doNotEnforceOnCreate?: boolean;
|
|
65
|
+
}
|
|
66
|
+
export interface RepositoryRulesetRules extends Omit<UpstreamRules, 'pullRequest' | 'requiredStatusChecks'> {
|
|
67
|
+
readonly pullRequest?: RepositoryRulesetPullRequestRule;
|
|
68
|
+
/** `undefined`: no opinion (refused if the live ruleset already has one — see
|
|
69
|
+
* repository-ruleset-guards.ts). `false`: declare its ABSENCE — removes a live one. */
|
|
70
|
+
readonly requiredStatusChecks?: RepositoryRulesetStatusChecksRule | false;
|
|
71
|
+
}
|
|
72
|
+
export interface RepositoryRulesetProps extends Omit<RulesetProps, 'rules'> {
|
|
73
|
+
readonly rules?: RepositoryRulesetRules;
|
|
74
|
+
}
|
|
75
|
+
export interface RepositoryRulesetAttributes {
|
|
76
|
+
readonly rulesetId: number;
|
|
77
|
+
readonly nodeId: string | undefined;
|
|
78
|
+
readonly name: string;
|
|
79
|
+
readonly createdAt: string | undefined;
|
|
80
|
+
readonly updatedAt: string | undefined;
|
|
81
|
+
}
|
|
82
|
+
export interface RepositoryRuleset extends Resource<'GitHub.RepositoryRuleset', RepositoryRulesetProps, RepositoryRulesetAttributes, never, GitHubCredentials> {
|
|
83
|
+
}
|
|
84
|
+
export declare const RepositoryRuleset: import("alchemy").ResourceClass<RepositoryRuleset>;
|
|
85
|
+
export declare const attrsOf: (r: RulesetRecord) => RepositoryRulesetAttributes;
|
|
86
|
+
export declare const repositoryRulesetHandlers: Provider.ProviderService<RepositoryRuleset, GitHubCredentials, never, never, GitHubCredentials, GitHubCredentials, never, never, never>;
|
|
87
|
+
export declare const RepositoryRulesetProvider: () => import("effect/Layer").Layer<Provider.Provider<RepositoryRuleset>, never, GitHubCredentials>;
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=repository-ruleset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-ruleset.d.ts","sourceRoot":"","sources":["../../src/github/repository-ruleset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAQ7C,OAAO,EAAE,KAAK,aAAa,EAAe,MAAM,+BAA+B,CAAC;AAGhF,KAAK,aAAa,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;AAExD,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7E;AAED,MAAM,WAAW,gCAAiC,SAAQ,WAAW,CACnE,aAAa,CAAC,aAAa,CAAC,CAC7B;IACC,yFAAyF;IACzF,QAAQ,CAAC,mBAAmB,CAAC,EAAE,SAAS,CAAC,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC,EAAE,CAAC;IAC1E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,6BAA6B,EAAE,CAAC;IACtE;iGAC6F;IAC7F,QAAQ,CAAC,mCAAmC,CAAC,EAAE,KAAK,CAAC;CACtD;AAED,MAAM,WAAW,iCAAkC,SAAQ,WAAW,CACpE,aAAa,CAAC,sBAAsB,CAAC,CACtC;IACC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CACzC;AAED,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAClD,aAAa,EACb,aAAa,GAAG,sBAAsB,CACvC;IACC,QAAQ,CAAC,WAAW,CAAC,EAAE,gCAAgC,CAAC;IACxD;2FACuF;IACvF,QAAQ,CAAC,oBAAoB,CAAC,EAAE,iCAAiC,GAAG,KAAK,CAAC;CAC3E;AAED,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC;IACzE,QAAQ,CAAC,KAAK,CAAC,EAAE,sBAAsB,CAAC;CACzC;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED,MAAM,WAAW,iBAAkB,SAAQ,QAAQ,CACjD,0BAA0B,EAC1B,sBAAsB,EACtB,2BAA2B,EAC3B,KAAK,EACL,iBAAiB,CAClB;CAAG;AAEJ,eAAO,MAAM,iBAAiB,oDAE5B,CAAC;AAEH,eAAO,MAAM,OAAO,MAAO,aAAa,KAAG,2BAMzC,CAAC;AA4BH,eAAO,MAAM,yBAAyB,yIAkEpC,CAAC;AAEH,eAAO,MAAM,yBAAyB,oGAC0B,CAAC"}
|