@oscharko-dev/keiko-tools 0.2.7 → 0.2.9
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/.tsbuildinfo +1 -1
- package/dist/git-commit-intent-node.d.ts +7 -0
- package/dist/git-commit-intent-node.d.ts.map +1 -0
- package/dist/git-commit-intent-node.js +42 -0
- package/dist/git-merge-gateway.d.ts +95 -0
- package/dist/git-merge-gateway.d.ts.map +1 -0
- package/dist/git-merge-gateway.js +536 -0
- package/dist/git-merge-node.d.ts +17 -0
- package/dist/git-merge-node.d.ts.map +1 -0
- package/dist/git-merge-node.js +243 -0
- package/dist/git-mutation-adapter.d.ts +51 -0
- package/dist/git-mutation-adapter.d.ts.map +1 -0
- package/dist/git-mutation-adapter.js +207 -0
- package/dist/git-mutation-evidence.d.ts +23 -0
- package/dist/git-mutation-evidence.d.ts.map +1 -0
- package/dist/git-mutation-evidence.js +283 -0
- package/dist/git-mutation-node.d.ts +22 -0
- package/dist/git-mutation-node.d.ts.map +1 -0
- package/dist/git-mutation-node.js +145 -0
- package/dist/git-mutation-orchestrator.d.ts +92 -0
- package/dist/git-mutation-orchestrator.d.ts.map +1 -0
- package/dist/git-mutation-orchestrator.js +321 -0
- package/dist/git-mutation-preflight.d.ts +35 -0
- package/dist/git-mutation-preflight.d.ts.map +1 -0
- package/dist/git-mutation-preflight.js +226 -0
- package/dist/git-mutation-taxonomy.d.ts +15 -0
- package/dist/git-mutation-taxonomy.d.ts.map +1 -0
- package/dist/git-mutation-taxonomy.js +102 -0
- package/dist/git-pr-gateway.d.ts +101 -0
- package/dist/git-pr-gateway.d.ts.map +1 -0
- package/dist/git-pr-gateway.js +487 -0
- package/dist/git-pr-node.d.ts +17 -0
- package/dist/git-pr-node.d.ts.map +1 -0
- package/dist/git-pr-node.js +173 -0
- package/dist/git-publish-gateway.d.ts +72 -0
- package/dist/git-publish-gateway.d.ts.map +1 -0
- package/dist/git-publish-gateway.js +423 -0
- package/dist/git-publish-node.d.ts +17 -0
- package/dist/git-publish-node.d.ts.map +1 -0
- package/dist/git-publish-node.js +107 -0
- package/dist/git-worktree-adapter.d.ts +78 -0
- package/dist/git-worktree-adapter.d.ts.map +1 -0
- package/dist/git-worktree-adapter.js +300 -0
- package/dist/git-worktree-snapshot-node.d.ts +31 -0
- package/dist/git-worktree-snapshot-node.d.ts.map +1 -0
- package/dist/git-worktree-snapshot-node.js +189 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -0
- package/package.json +9 -5
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
// Governed Git mutation EVIDENCE builder (Issue #474, Epic #470). Projects the #472 kernel's
|
|
2
|
+
// GitMutationLifecycleResult into the content-free, redacted-by-construction GitDeliveryEvidenceRecord
|
|
3
|
+
// the keiko-contracts evidence atom defines. This is the producer the orchestrator's idempotency
|
|
4
|
+
// journal comment anticipates ("a durable journal — the evidence ledger, #474"), except it records
|
|
5
|
+
// EVERY terminal outcome (succeeded, blocked, rejected, failed, recovery-required, approval-required),
|
|
6
|
+
// not only succeeded retries.
|
|
7
|
+
//
|
|
8
|
+
// PURE: a deterministic function of (lifecycle result, content-free snapshot, correlation, injected
|
|
9
|
+
// deps). No IO, no clock, no randomness — the clock and the hash are injected. Hashing uses the
|
|
10
|
+
// shared keiko-security sha256Hex so remote identifiers, the provider external id, and the repository
|
|
11
|
+
// identity become opaque hashes (AC2) rather than raw artifacts. Local branch names are retained as
|
|
12
|
+
// content-free repository context, consistent with the #473 action-sheet projection.
|
|
13
|
+
//
|
|
14
|
+
// The kernel's lifecycle-phase and outcome vocabularies are mapped onto the contract's self-contained
|
|
15
|
+
// mirrors with exhaustive switches/tables, so a divergence between the kernel and the contract is a
|
|
16
|
+
// compile error here rather than a silent audit gap.
|
|
17
|
+
import { GIT_DELIVERY_EVIDENCE_SCHEMA_VERSION, GIT_DELIVERY_RISK_CLASS_SEVERITY, gitDeliveryRecoveryDispositionForBlockReason, gitDeliveryRecoveryDispositionForExecutionError, gitDeliveryRiskClassForInputs, } from "@oscharko-dev/keiko-contracts";
|
|
18
|
+
import { sha256Hex } from "@oscharko-dev/keiko-security";
|
|
19
|
+
// ─── Phase + outcome-class mapping (exhaustive) ────────────────────────────────────────────────
|
|
20
|
+
function mapLifecyclePhase(phase) {
|
|
21
|
+
switch (phase) {
|
|
22
|
+
case "resolve":
|
|
23
|
+
return "resolve";
|
|
24
|
+
case "preflight":
|
|
25
|
+
return "preflight";
|
|
26
|
+
case "preview":
|
|
27
|
+
return "preview";
|
|
28
|
+
case "policy":
|
|
29
|
+
return "policy";
|
|
30
|
+
case "execute":
|
|
31
|
+
return "execute";
|
|
32
|
+
case "result":
|
|
33
|
+
return "result";
|
|
34
|
+
default:
|
|
35
|
+
return assertNever(phase);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function outcomeClassFor(outcome) {
|
|
39
|
+
switch (outcome.status) {
|
|
40
|
+
case "succeeded":
|
|
41
|
+
return "succeeded";
|
|
42
|
+
case "approval-required":
|
|
43
|
+
return "approval-required";
|
|
44
|
+
case "blocked":
|
|
45
|
+
return "blocked";
|
|
46
|
+
case "recovery-required":
|
|
47
|
+
return "recovery-required";
|
|
48
|
+
case "failed":
|
|
49
|
+
// A provider rejection is a "rejected" attempt; every other failure (network, timeout,
|
|
50
|
+
// internal) is a transient "failed" attempt.
|
|
51
|
+
return outcome.executionResult.errorCode === "provider-rejected" ? "rejected" : "failed";
|
|
52
|
+
default:
|
|
53
|
+
return assertNever(outcome);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// ─── Recovery-metadata derivation (AC3) ─────────────────────────────────────────────────────────
|
|
57
|
+
// Action hints REUSE the #473 GitDeliveryRecoveryActionHint vocabulary. Every table is exhaustive
|
|
58
|
+
// over its closed contract/kernel vocabulary, so a new code forces an explicit classification here.
|
|
59
|
+
const ACTION_HINT_BY_BLOCK_REASON = {
|
|
60
|
+
"policy-pack-blocked": "adjust-policy-target",
|
|
61
|
+
"protected-branch": "adjust-policy-target",
|
|
62
|
+
"provider-capability-absent": "adjust-policy-target",
|
|
63
|
+
"approval-expired": "request-approval",
|
|
64
|
+
"risk-class-ceiling": "adjust-policy-target",
|
|
65
|
+
"no-applicable-rule": "adjust-policy-target",
|
|
66
|
+
};
|
|
67
|
+
const ACTION_HINT_BY_EXECUTION_ERROR = {
|
|
68
|
+
// A provider rejection is most often a diverged/non-fast-forward ref; resolving the divergence is
|
|
69
|
+
// the operator's fix. The provider execution slices (#477/#478) may refine this.
|
|
70
|
+
"provider-rejected": "resolve-conflicts",
|
|
71
|
+
"network-failure": "wait-for-provider",
|
|
72
|
+
conflict: "resolve-conflicts",
|
|
73
|
+
"precondition-failed": "resolve-conflicts",
|
|
74
|
+
timeout: "retry",
|
|
75
|
+
"internal-error": "retry",
|
|
76
|
+
};
|
|
77
|
+
const ACTION_HINT_BY_PREFLIGHT_FINDING = {
|
|
78
|
+
"detached-head": "recover-via-strategy",
|
|
79
|
+
"branch-already-exists": "retry",
|
|
80
|
+
"base-branch-missing": "retry",
|
|
81
|
+
"switch-target-missing": "retry",
|
|
82
|
+
"no-changes-to-stage": "stage-changes",
|
|
83
|
+
"nothing-staged-to-unstage": "stage-changes",
|
|
84
|
+
"nothing-staged-to-commit": "stage-changes",
|
|
85
|
+
"untracked-files-impacted": "stage-changes",
|
|
86
|
+
"no-upstream-configured": "configure-upstream",
|
|
87
|
+
"nothing-to-push": "retry",
|
|
88
|
+
"non-fast-forward": "resolve-conflicts",
|
|
89
|
+
"remote-alias-missing": "configure-upstream",
|
|
90
|
+
"remote-unreachable": "wait-for-provider",
|
|
91
|
+
"operation-in-progress": "abort-in-progress-operation",
|
|
92
|
+
"no-operation-to-abort": "retry",
|
|
93
|
+
"recovery-target-unset": "recover-via-strategy",
|
|
94
|
+
"dirty-worktree-impacts-recovery": "recover-via-strategy",
|
|
95
|
+
};
|
|
96
|
+
function recoveryForBlockReason(reason) {
|
|
97
|
+
return {
|
|
98
|
+
disposition: gitDeliveryRecoveryDispositionForBlockReason(reason),
|
|
99
|
+
actionHint: ACTION_HINT_BY_BLOCK_REASON[reason],
|
|
100
|
+
blockReason: reason,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function recoveryForPreflight(findings) {
|
|
104
|
+
// A blocked-by-preflight attempt is user-fixable: the operator changes the named repository
|
|
105
|
+
// condition. The dominant (first, deterministic order) blocking finding names the action.
|
|
106
|
+
const code = findings[0]?.code;
|
|
107
|
+
return {
|
|
108
|
+
disposition: "user-fixable",
|
|
109
|
+
...(code !== undefined ? { actionHint: ACTION_HINT_BY_PREFLIGHT_FINDING[code] } : {}),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function recoveryForExecution(result) {
|
|
113
|
+
const code = result.errorCode ?? "internal-error";
|
|
114
|
+
return {
|
|
115
|
+
disposition: gitDeliveryRecoveryDispositionForExecutionError(code),
|
|
116
|
+
actionHint: ACTION_HINT_BY_EXECUTION_ERROR[code],
|
|
117
|
+
...(result.errorCode !== undefined ? { executionErrorCode: result.errorCode } : {}),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function recoveryForRecoveryRequired(result, inputs) {
|
|
121
|
+
const strategy = inputs.kind === "recovery" ? inputs.recoveryStrategyHint : undefined;
|
|
122
|
+
return {
|
|
123
|
+
disposition: "user-fixable",
|
|
124
|
+
actionHint: "recover-via-strategy",
|
|
125
|
+
...(result.errorCode !== undefined ? { executionErrorCode: result.errorCode } : {}),
|
|
126
|
+
...(strategy !== undefined ? { suggestedRecoveryStrategy: strategy } : {}),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function recoveryFor(outcome, inputs) {
|
|
130
|
+
switch (outcome.status) {
|
|
131
|
+
case "succeeded":
|
|
132
|
+
return { disposition: "none" };
|
|
133
|
+
case "approval-required":
|
|
134
|
+
return { disposition: "user-fixable", actionHint: "request-approval" };
|
|
135
|
+
case "blocked":
|
|
136
|
+
return outcome.category === "policy-block"
|
|
137
|
+
? recoveryForBlockReason(outcome.blockReason)
|
|
138
|
+
: recoveryForPreflight(outcome.findings);
|
|
139
|
+
case "failed":
|
|
140
|
+
return recoveryForExecution(outcome.executionResult);
|
|
141
|
+
case "recovery-required":
|
|
142
|
+
return recoveryForRecoveryRequired(outcome.executionResult, inputs);
|
|
143
|
+
default:
|
|
144
|
+
return assertNever(outcome);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// ─── Section projections ─────────────────────────────────────────────────────────────────────
|
|
148
|
+
// Branch names are echoed raw into the audit record (they are git refs, not secrets). Strip
|
|
149
|
+
// bidirectional/zero-width/BOM format characters so a crafted ref cannot visually spoof which branch
|
|
150
|
+
// an audit row refers to when the export is rendered. Mirrors the action-sheet route's boundary
|
|
151
|
+
// scanner; git ref rules already bar C0/C1 controls and spaces, so only the format-char set is removed.
|
|
152
|
+
const UNSAFE_FORMAT_CHARS = new RegExp("[\\u200B-\\u200F\\u202A-\\u202E\\u2060-\\u2064\\u2066-\\u206F\\uFEFF]", "gu");
|
|
153
|
+
function sanitizeRef(value) {
|
|
154
|
+
return value.replace(UNSAFE_FORMAT_CHARS, "");
|
|
155
|
+
}
|
|
156
|
+
function approvalFor(approval) {
|
|
157
|
+
if (!approval.required) {
|
|
158
|
+
return { required: false };
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
required: true,
|
|
162
|
+
approvalTokenHash: approval.approvalTokenHash,
|
|
163
|
+
approvedByUserId: approval.approvedByUserId,
|
|
164
|
+
approvedAtMs: approval.approvedAtMs,
|
|
165
|
+
...(approval.expiresAtMs !== undefined ? { expiresAtMs: approval.expiresAtMs } : {}),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function previewFor(preview) {
|
|
169
|
+
if (preview === undefined) {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
...(preview.affectedBranchName !== undefined
|
|
174
|
+
? { affectedBranchName: sanitizeRef(preview.affectedBranchName) }
|
|
175
|
+
: {}),
|
|
176
|
+
...(preview.estimatedFileCount !== undefined
|
|
177
|
+
? { estimatedFileCount: preview.estimatedFileCount }
|
|
178
|
+
: {}),
|
|
179
|
+
...(preview.estimatedBytesDelta !== undefined
|
|
180
|
+
? { estimatedBytesDelta: preview.estimatedBytesDelta }
|
|
181
|
+
: {}),
|
|
182
|
+
wouldCreateRemoteBranch: preview.wouldCreateRemoteBranch,
|
|
183
|
+
wouldTriggerChecks: preview.wouldTriggerChecks,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function executionFor(result, hash) {
|
|
187
|
+
if (result === undefined) {
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
outcome: result.outcome,
|
|
192
|
+
durationMs: result.durationMs,
|
|
193
|
+
...(result.errorCode !== undefined ? { errorCode: result.errorCode } : {}),
|
|
194
|
+
...(result.partialDetail !== undefined
|
|
195
|
+
? {
|
|
196
|
+
attemptedUnitCount: result.partialDetail.attemptedUnitCount,
|
|
197
|
+
succeededUnitCount: result.partialDetail.succeededUnitCount,
|
|
198
|
+
}
|
|
199
|
+
: {}),
|
|
200
|
+
...(result.externalId !== undefined ? { externalIdHash: hash(result.externalId) } : {}),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function repoContextFor(inputs, snapshot, repoId, hash) {
|
|
204
|
+
const target = inputs.kind === "branch-create" ? inputs.branchName : snapshot.currentBranchName;
|
|
205
|
+
return {
|
|
206
|
+
...(repoId !== undefined ? { repoIdHash: hash(repoId) } : {}),
|
|
207
|
+
...(target !== undefined ? { targetBranchName: sanitizeRef(target) } : {}),
|
|
208
|
+
headDetached: snapshot.headDetached,
|
|
209
|
+
stagedFileCount: snapshot.stagedFileCount,
|
|
210
|
+
unstagedFileCount: snapshot.unstagedFileCount,
|
|
211
|
+
untrackedFileCount: snapshot.untrackedFileCount,
|
|
212
|
+
...(inputs.kind === "push"
|
|
213
|
+
? { remoteRefHash: hash(`${inputs.remoteAlias}/${inputs.remoteBranchName}`) }
|
|
214
|
+
: {}),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function effectiveBlockReason(envelope, outcome) {
|
|
218
|
+
if (outcome.status === "blocked" && outcome.category === "policy-block") {
|
|
219
|
+
return outcome.blockReason;
|
|
220
|
+
}
|
|
221
|
+
// The kernel evaluates policy eagerly (prepareLifecycle) even when preflight halts the lifecycle
|
|
222
|
+
// first, so a preflight-blocked envelope can still carry a "blocked" policyDecision that was never
|
|
223
|
+
// the terminal enforcement. Recording that policy reason here would contradict the preflight
|
|
224
|
+
// disposition, so a preflight-blocked attempt (the only remaining "blocked" category) carries no
|
|
225
|
+
// policy block reason — its cause is a preflight finding, reflected in recovery.actionHint and
|
|
226
|
+
// phaseReached === "preflight".
|
|
227
|
+
if (outcome.status === "blocked") {
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
return envelope.policyDecision.outcome === "blocked" ? envelope.policyDecision.reason : undefined;
|
|
231
|
+
}
|
|
232
|
+
function effectiveApprovers(envelope, outcome) {
|
|
233
|
+
if (envelope.policyDecision.outcome === "approval-gated") {
|
|
234
|
+
return envelope.policyDecision.requiredApprovers;
|
|
235
|
+
}
|
|
236
|
+
return outcome.status === "approval-required" ? outcome.requiredApprovers : undefined;
|
|
237
|
+
}
|
|
238
|
+
function policyFieldsFor(envelope, outcome) {
|
|
239
|
+
const blockReason = effectiveBlockReason(envelope, outcome);
|
|
240
|
+
const requiredApprovers = effectiveApprovers(envelope, outcome);
|
|
241
|
+
return {
|
|
242
|
+
...(blockReason !== undefined ? { blockReason } : {}),
|
|
243
|
+
...(requiredApprovers !== undefined ? { requiredApprovers } : {}),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
// ─── Entry point ─────────────────────────────────────────────────────────────────────────────
|
|
247
|
+
export function buildGitDeliveryEvidenceRecord(input, deps) {
|
|
248
|
+
const hash = deps.hash ?? sha256Hex;
|
|
249
|
+
const { envelope, outcome, phaseReached } = input.result;
|
|
250
|
+
const inputs = envelope.resolvedInputs;
|
|
251
|
+
const riskClass = gitDeliveryRiskClassForInputs(inputs);
|
|
252
|
+
const workflowRunIdHash = hash(input.workflowRunId);
|
|
253
|
+
const evidenceId = `gde-${hash(`${workflowRunIdHash}:${envelope.actionId}`).slice(0, 40)}`;
|
|
254
|
+
const correlation = {
|
|
255
|
+
workflowRunIdHash,
|
|
256
|
+
actionId: envelope.actionId,
|
|
257
|
+
...(input.attemptSequence !== undefined ? { attemptSequence: input.attemptSequence } : {}),
|
|
258
|
+
};
|
|
259
|
+
const preview = previewFor(envelope.preview);
|
|
260
|
+
const execution = executionFor(envelope.executionResult, hash);
|
|
261
|
+
return {
|
|
262
|
+
schemaVersion: GIT_DELIVERY_EVIDENCE_SCHEMA_VERSION,
|
|
263
|
+
evidenceId,
|
|
264
|
+
actionKind: envelope.kind,
|
|
265
|
+
riskClass,
|
|
266
|
+
riskSeverity: GIT_DELIVERY_RISK_CLASS_SEVERITY[riskClass],
|
|
267
|
+
outcomeClass: outcomeClassFor(outcome),
|
|
268
|
+
phaseReached: mapLifecyclePhase(phaseReached),
|
|
269
|
+
policyOutcome: envelope.policyDecision.outcome,
|
|
270
|
+
...policyFieldsFor(envelope, outcome),
|
|
271
|
+
correlation,
|
|
272
|
+
approval: approvalFor(envelope.approvalRequirement),
|
|
273
|
+
...(preview !== undefined ? { preview } : {}),
|
|
274
|
+
...(execution !== undefined ? { execution } : {}),
|
|
275
|
+
repoContext: repoContextFor(inputs, input.snapshot, input.repoId, hash),
|
|
276
|
+
recovery: recoveryFor(outcome, inputs),
|
|
277
|
+
recordedAtMs: deps.now(),
|
|
278
|
+
...(input.evidenceRef !== undefined ? { evidenceRef: input.evidenceRef } : {}),
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
function assertNever(value) {
|
|
282
|
+
throw new Error(`unhandled git mutation evidence variant: ${JSON.stringify(value)}`);
|
|
283
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { WorkspaceInfo } from "@oscharko-dev/keiko-workspace";
|
|
2
|
+
import { type GitLocalMutationAdapter } from "./git-mutation-adapter.js";
|
|
3
|
+
import { type ExecutableResolver, type HomeProvider, type SpawnFn } from "./exec.js";
|
|
4
|
+
import { type SandboxPolicy } from "./types.js";
|
|
5
|
+
export interface NodeGitMutationAdapterDeps {
|
|
6
|
+
readonly workspace: WorkspaceInfo;
|
|
7
|
+
readonly processEnv?: NodeJS.ProcessEnv | undefined;
|
|
8
|
+
readonly now?: (() => number) | undefined;
|
|
9
|
+
readonly spawn?: SpawnFn | undefined;
|
|
10
|
+
readonly policy?: SandboxPolicy | undefined;
|
|
11
|
+
readonly resolveExecutable?: ExecutableResolver | undefined;
|
|
12
|
+
readonly home?: HomeProvider | undefined;
|
|
13
|
+
readonly signal?: AbortSignal | undefined;
|
|
14
|
+
readonly timeoutMs?: number | undefined;
|
|
15
|
+
}
|
|
16
|
+
export declare function createNodeGitMutationAdapter(deps: NodeGitMutationAdapterDeps): GitLocalMutationAdapter;
|
|
17
|
+
export { GIT_WORKTREE_READ_COMMAND_RULES, GitWorktreeReadError, readGitWorktreeSnapshot, readStagedPaths, type NodeGitWorktreeReaderDeps, } from "./git-worktree-snapshot-node.js";
|
|
18
|
+
export { buildAddExistingBranchArgv, buildAddWorktreeArgv, buildListWorktreesArgv, buildLocalBranchExistsArgv, buildPruneWorktreesArgv, buildRefResolvesArgv, buildRemoveWorktreeArgv, buildShowToplevelArgv, buildWorktreeStatusArgv, createNodeGitWorktreeAdapter, GIT_WORKTREE_COMMAND_RULES, GitWorktreeOperandError, GitWorktreeSpawnError, isSafeGitRefName, isSafeWorktreePathOperand, parseWorktreeListPorcelain, type AddExistingBranchOperands, type AddWorktreeOperands, type GitWorktreeAdapter, type NodeGitWorktreeAdapterDeps, type RemoveWorktreeOperands, type WorktreeListEntry, type WorktreeOperationResult, type WorktreeStatusResult, } from "./git-worktree-adapter.js";
|
|
19
|
+
export { createNodeGitPublishAdapter, type NodeGitPublishAdapterDeps } from "./git-publish-node.js";
|
|
20
|
+
export { createNodeGitPullRequestAdapter, type NodeGitPullRequestAdapterDeps, } from "./git-pr-node.js";
|
|
21
|
+
export { createNodeGitMergeAdapter, type NodeGitMergeAdapterDeps } from "./git-merge-node.js";
|
|
22
|
+
//# sourceMappingURL=git-mutation-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-mutation-node.d.ts","sourceRoot":"","sources":["../src/git-mutation-node.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAKnE,OAAO,EASL,KAAK,uBAAuB,EAE7B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,YAAY,EAEjB,KAAK,OAAO,EACb,MAAM,WAAW,CAAC;AACnB,OAAO,EAA8C,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5F,MAAM,WAAW,0BAA0B;IAEzC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,UAAU,GAAG,SAAS,CAAC;IACpD,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAErC,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC5D,QAAQ,CAAC,IAAI,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAEzC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AA4HD,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,0BAA0B,GAC/B,uBAAuB,CAWzB;AAKD,OAAO,EACL,+BAA+B,EAC/B,oBAAoB,EACpB,uBAAuB,EACvB,eAAe,EACf,KAAK,yBAAyB,GAC/B,MAAM,iCAAiC,CAAC;AAQzC,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,EACvB,qBAAqB,EACrB,uBAAuB,EACvB,4BAA4B,EAC5B,0BAA0B,EAC1B,uBAAuB,EACvB,qBAAqB,EACrB,gBAAgB,EAChB,yBAAyB,EACzB,0BAA0B,EAC1B,KAAK,yBAAyB,EAC9B,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,GAC1B,MAAM,2BAA2B,CAAC;AAKnC,OAAO,EAAE,2BAA2B,EAAE,KAAK,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAMpG,OAAO,EACL,+BAA+B,EAC/B,KAAK,6BAA6B,GACnC,MAAM,kBAAkB,CAAC;AAM1B,OAAO,EAAE,yBAAyB,EAAE,KAAK,uBAAuB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// Node implementation of the narrow local Git mutation adapter (Issue #472, Epic #470) — AC3.
|
|
2
|
+
//
|
|
3
|
+
// This is the ONLY place governed local Git writes actually execute. Each typed adapter method
|
|
4
|
+
// builds a fixed argv plan from the pure builders (git-mutation-adapter.ts) and runs it through the
|
|
5
|
+
// single keiko-tools no-shell spawn boundary (`runCommand`, exec.ts) with a dedicated mutation
|
|
6
|
+
// allowlist. There is no method that accepts an arbitrary command string, and no parallel
|
|
7
|
+
// child_process path: the deny-by-default allowlist, env isolation, redaction, and cancellation of
|
|
8
|
+
// the shared boundary apply to every governed mutation exactly as they do to every other tool.
|
|
9
|
+
//
|
|
10
|
+
// Lives on the `./internal/git-mutation` subpath (mirroring `./internal/exec` and `./internal/writer`)
|
|
11
|
+
// because it carries the Node execution effect; the pure port, builders, and rules it implements are
|
|
12
|
+
// re-exported from the package's main barrel.
|
|
13
|
+
import { GIT_DELIVERY_SCHEMA_VERSION, } from "@oscharko-dev/keiko-contracts";
|
|
14
|
+
import { buildAbortArgv, buildBranchCreateArgv, buildBranchSwitchArgv, buildCommitArgv, buildRecoveryArgv, buildStageArgv, buildUnstageArgv, GIT_MUTATION_COMMAND_RULES, } from "./git-mutation-adapter.js";
|
|
15
|
+
import { CommandCancelledError, CommandTimeoutError } from "./errors.js";
|
|
16
|
+
import { nodeSpawnFn, runCommand, } from "./exec.js";
|
|
17
|
+
import { DEFAULT_SANDBOX_POLICY } from "./types.js";
|
|
18
|
+
function executionResult(outcome, durationMs, extra) {
|
|
19
|
+
return {
|
|
20
|
+
schemaVersion: GIT_DELIVERY_SCHEMA_VERSION,
|
|
21
|
+
outcome,
|
|
22
|
+
durationMs: Math.max(0, Math.trunc(durationMs)),
|
|
23
|
+
...extra,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// A non-zero git exit at execution time means a precondition that the preflight snapshot did not
|
|
27
|
+
// capture failed against the live repository (a time-of-check/time-of-use gap) — classified as
|
|
28
|
+
// `precondition-failed`, which the taxonomy routes to recovery-required. When part of a multi-step
|
|
29
|
+
// plan already partially applied, the result is `partial` with the attempted/succeeded counts.
|
|
30
|
+
function failureFromExit(durationMs, stepIndex) {
|
|
31
|
+
if (stepIndex > 0) {
|
|
32
|
+
return executionResult("partial", durationMs, {
|
|
33
|
+
errorCode: "precondition-failed",
|
|
34
|
+
partialDetail: { attemptedUnitCount: stepIndex + 1, succeededUnitCount: stepIndex },
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return executionResult("failed", durationMs, { errorCode: "precondition-failed" });
|
|
38
|
+
}
|
|
39
|
+
function failureFromThrow(error, durationMs, stepIndex) {
|
|
40
|
+
const partial = stepIndex > 0
|
|
41
|
+
? { partialDetail: { attemptedUnitCount: stepIndex + 1, succeededUnitCount: stepIndex } }
|
|
42
|
+
: {};
|
|
43
|
+
if (error instanceof CommandTimeoutError) {
|
|
44
|
+
return executionResult(stepIndex > 0 ? "partial" : "failed", durationMs, {
|
|
45
|
+
errorCode: "timeout",
|
|
46
|
+
...partial,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
if (error instanceof CommandCancelledError) {
|
|
50
|
+
return executionResult("aborted", durationMs, partial);
|
|
51
|
+
}
|
|
52
|
+
// A denied command (our own argv hit the allowlist), an argv-construction fault, or any other
|
|
53
|
+
// throw is an internal kernel error — it never means the user's repository is at fault.
|
|
54
|
+
return executionResult(stepIndex > 0 ? "partial" : "failed", durationMs, {
|
|
55
|
+
errorCode: "internal-error",
|
|
56
|
+
...partial,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function runOne(ctx, argv) {
|
|
60
|
+
return runCommand({ command: "git", args: argv, cwd: undefined, timeoutMs: ctx.timeoutMs, signal: ctx.signal }, ctx.runDeps);
|
|
61
|
+
}
|
|
62
|
+
async function runPlan(ctx, plan) {
|
|
63
|
+
let totalDuration = 0;
|
|
64
|
+
for (const [stepIndex, argv] of plan.entries()) {
|
|
65
|
+
let result;
|
|
66
|
+
try {
|
|
67
|
+
result = await runOne(ctx, argv);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
return failureFromThrow(error, totalDuration, stepIndex);
|
|
71
|
+
}
|
|
72
|
+
totalDuration += result.durationMs;
|
|
73
|
+
if (result.exitCode !== 0) {
|
|
74
|
+
return failureFromExit(totalDuration, stepIndex);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return executionResult("succeeded", totalDuration);
|
|
78
|
+
}
|
|
79
|
+
// Builds the argv plan, then runs it. A builder throw (invalid operand) is an internal error that
|
|
80
|
+
// never reaches a spawn.
|
|
81
|
+
async function execPlan(ctx, build) {
|
|
82
|
+
let plan;
|
|
83
|
+
try {
|
|
84
|
+
plan = build();
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return executionResult("failed", 0, { errorCode: "internal-error" });
|
|
88
|
+
}
|
|
89
|
+
return runPlan(ctx, plan);
|
|
90
|
+
}
|
|
91
|
+
function buildRunContext(deps) {
|
|
92
|
+
return {
|
|
93
|
+
runDeps: {
|
|
94
|
+
workspace: deps.workspace,
|
|
95
|
+
policy: deps.policy ?? DEFAULT_SANDBOX_POLICY,
|
|
96
|
+
commandRules: GIT_MUTATION_COMMAND_RULES,
|
|
97
|
+
spawn: deps.spawn ?? nodeSpawnFn,
|
|
98
|
+
processEnv: deps.processEnv ?? process.env,
|
|
99
|
+
now: deps.now ?? Date.now,
|
|
100
|
+
...(deps.resolveExecutable !== undefined
|
|
101
|
+
? { resolveExecutable: deps.resolveExecutable }
|
|
102
|
+
: {}),
|
|
103
|
+
...(deps.home !== undefined ? { home: deps.home } : {}),
|
|
104
|
+
},
|
|
105
|
+
signal: deps.signal ?? new AbortController().signal,
|
|
106
|
+
timeoutMs: deps.timeoutMs,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function createNodeGitMutationAdapter(deps) {
|
|
110
|
+
const ctx = buildRunContext(deps);
|
|
111
|
+
return {
|
|
112
|
+
createBranch: (req) => execPlan(ctx, () => buildBranchCreateArgv(req)),
|
|
113
|
+
switchBranch: (req) => execPlan(ctx, () => buildBranchSwitchArgv(req)),
|
|
114
|
+
stage: (req) => execPlan(ctx, () => buildStageArgv(req)),
|
|
115
|
+
unstage: (req) => execPlan(ctx, () => buildUnstageArgv(req)),
|
|
116
|
+
commit: (req) => execPlan(ctx, () => buildCommitArgv(req)),
|
|
117
|
+
abort: (req) => execPlan(ctx, () => buildAbortArgv(req)),
|
|
118
|
+
recover: (req) => execPlan(ctx, () => buildRecoveryArgv(req)),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// The read-only worktree snapshot reader (Issue #475) carries the same Node spawn effect as this
|
|
122
|
+
// adapter, so it is exposed on the SAME `./internal/git-mutation` subpath rather than the pure barrel.
|
|
123
|
+
// Its inspection allowlist is structurally separate from the mutation rules.
|
|
124
|
+
export { GIT_WORKTREE_READ_COMMAND_RULES, GitWorktreeReadError, readGitWorktreeSnapshot, readStagedPaths, } from "./git-worktree-snapshot-node.js";
|
|
125
|
+
// The narrow managed-worktree lifecycle adapter (Issue #445, Epic #443) carries the same Node spawn
|
|
126
|
+
// effect through the same governed `runCommand` boundary with its OWN dedicated allowlist
|
|
127
|
+
// (`GIT_WORKTREE_COMMAND_RULES`: worktree/rev-parse/show-ref only — structurally separate from the
|
|
128
|
+
// mutation, read-inspection, publish, PR, and merge rule sets). It is exposed on the SAME
|
|
129
|
+
// `./internal/git-mutation` subpath. The pure argv builders, operand validators, and porcelain parser
|
|
130
|
+
// are re-exported alongside the node factory so the server can pre-validate operands without spawning.
|
|
131
|
+
export { buildAddExistingBranchArgv, buildAddWorktreeArgv, buildListWorktreesArgv, buildLocalBranchExistsArgv, buildPruneWorktreesArgv, buildRefResolvesArgv, buildRemoveWorktreeArgv, buildShowToplevelArgv, buildWorktreeStatusArgv, createNodeGitWorktreeAdapter, GIT_WORKTREE_COMMAND_RULES, GitWorktreeOperandError, GitWorktreeSpawnError, isSafeGitRefName, isSafeWorktreePathOperand, parseWorktreeListPorcelain, } from "./git-worktree-adapter.js";
|
|
132
|
+
// The Node remote publish executor (Issue #476) carries the same Node spawn effect and a DEDICATED
|
|
133
|
+
// push allowlist; it is exposed on the SAME `./internal/git-mutation` subpath. Its allowlist is
|
|
134
|
+
// structurally separate from both the mutation and the read-only inspection rules.
|
|
135
|
+
export { createNodeGitPublishAdapter } from "./git-publish-node.js";
|
|
136
|
+
// The Node GitHub pull request executor (Issue #477) shells `gh api` through the same spawn boundary
|
|
137
|
+
// with its OWN dedicated PR allowlist (create / update / draft-toggle GraphQL — no merge, no delete);
|
|
138
|
+
// it is exposed on the SAME `./internal/git-mutation` subpath. The GitHub token is read by gh itself,
|
|
139
|
+
// never by Keiko.
|
|
140
|
+
export { createNodeGitPullRequestAdapter, } from "./git-pr-node.js";
|
|
141
|
+
// The Node governed merge executor (Issue #478) shells `gh api` through the same spawn boundary with its
|
|
142
|
+
// OWN dedicated merge allowlist (the merge PUT, the readiness GETs, and the guarded branch DELETE — no
|
|
143
|
+
// generic exec); it is exposed on the SAME `./internal/git-mutation` subpath. The GitHub token is read by
|
|
144
|
+
// gh itself, never by Keiko.
|
|
145
|
+
export { createNodeGitMergeAdapter } from "./git-merge-node.js";
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { GitDeliveryAbortableOperation, GitDeliveryActionEnvelope, GitDeliveryApprovalRequirement, GitDeliveryBlockReason, GitDeliveryExecutionResult, GitDeliveryOrgPolicyPack, GitDeliveryProviderCapability, GitDeliveryRecoveryStrategyHint, GitDeliveryRepoPolicyPack } from "@oscharko-dev/keiko-contracts";
|
|
2
|
+
import type { GitLocalMutationAdapter } from "./git-mutation-adapter.js";
|
|
3
|
+
import type { GitPreflightFinding, GitPreflightReport, GitWorktreeSnapshot } from "./git-mutation-preflight.js";
|
|
4
|
+
import type { GitMutationFailureCategory, GitMutationLifecyclePhase } from "./git-mutation-taxonomy.js";
|
|
5
|
+
export interface GitBranchCreateCommand {
|
|
6
|
+
readonly kind: "branch-create";
|
|
7
|
+
readonly branchName: string;
|
|
8
|
+
readonly baseBranchName: string;
|
|
9
|
+
readonly startPointRefHash: string;
|
|
10
|
+
}
|
|
11
|
+
export interface GitBranchSwitchCommand {
|
|
12
|
+
readonly kind: "branch-switch";
|
|
13
|
+
readonly branchName: string;
|
|
14
|
+
}
|
|
15
|
+
export interface GitStageCommand {
|
|
16
|
+
readonly kind: "stage";
|
|
17
|
+
readonly pathspecs: readonly string[];
|
|
18
|
+
readonly includeUntracked: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface GitUnstageCommand {
|
|
21
|
+
readonly kind: "unstage";
|
|
22
|
+
readonly pathspecs: readonly string[];
|
|
23
|
+
}
|
|
24
|
+
export interface GitCommitCommand {
|
|
25
|
+
readonly kind: "commit";
|
|
26
|
+
readonly message: string;
|
|
27
|
+
readonly allowEmpty: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface GitAbortCommand {
|
|
30
|
+
readonly kind: "abort";
|
|
31
|
+
readonly operationToAbort: GitDeliveryAbortableOperation;
|
|
32
|
+
readonly preserveIndexChanges: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface GitRecoveryCommand {
|
|
35
|
+
readonly kind: "recovery";
|
|
36
|
+
readonly recoveryStrategyHint: GitDeliveryRecoveryStrategyHint;
|
|
37
|
+
readonly targetRefHash: string;
|
|
38
|
+
readonly affectedPathspecs: readonly string[];
|
|
39
|
+
}
|
|
40
|
+
export type GitMutationCommand = GitBranchCreateCommand | GitBranchSwitchCommand | GitStageCommand | GitUnstageCommand | GitCommitCommand | GitAbortCommand | GitRecoveryCommand;
|
|
41
|
+
export interface GitMutationRequest {
|
|
42
|
+
readonly command: GitMutationCommand;
|
|
43
|
+
readonly approval: GitDeliveryApprovalRequirement;
|
|
44
|
+
readonly idempotencyKey?: string | undefined;
|
|
45
|
+
}
|
|
46
|
+
export interface GitMutationJournal {
|
|
47
|
+
lookup(idempotencyKey: string): GitMutationLifecycleResult | undefined;
|
|
48
|
+
record(idempotencyKey: string, result: GitMutationLifecycleResult): void;
|
|
49
|
+
}
|
|
50
|
+
export interface GitMutationOrchestratorDeps {
|
|
51
|
+
readonly adapter: GitLocalMutationAdapter;
|
|
52
|
+
readonly snapshot: GitWorktreeSnapshot;
|
|
53
|
+
readonly orgPolicyPack?: GitDeliveryOrgPolicyPack | undefined;
|
|
54
|
+
readonly repoPolicyPack?: GitDeliveryRepoPolicyPack | undefined;
|
|
55
|
+
readonly activeProviderCapabilities?: readonly GitDeliveryProviderCapability[] | undefined;
|
|
56
|
+
readonly now: () => number;
|
|
57
|
+
readonly newActionId: () => string;
|
|
58
|
+
readonly journal?: GitMutationJournal | undefined;
|
|
59
|
+
}
|
|
60
|
+
export type GitMutationOutcome = {
|
|
61
|
+
readonly status: "succeeded";
|
|
62
|
+
readonly executionResult: GitDeliveryExecutionResult;
|
|
63
|
+
} | {
|
|
64
|
+
readonly status: "approval-required";
|
|
65
|
+
readonly requiredApprovers: readonly string[];
|
|
66
|
+
} | {
|
|
67
|
+
readonly status: "blocked";
|
|
68
|
+
readonly category: "policy-block";
|
|
69
|
+
readonly blockReason: GitDeliveryBlockReason;
|
|
70
|
+
} | {
|
|
71
|
+
readonly status: "blocked";
|
|
72
|
+
readonly category: "preflight-block";
|
|
73
|
+
readonly findings: readonly GitPreflightFinding[];
|
|
74
|
+
} | {
|
|
75
|
+
readonly status: "failed";
|
|
76
|
+
readonly category: "execution-failure" | "provider-failure";
|
|
77
|
+
readonly executionResult: GitDeliveryExecutionResult;
|
|
78
|
+
} | {
|
|
79
|
+
readonly status: "recovery-required";
|
|
80
|
+
readonly category: "recovery-required";
|
|
81
|
+
readonly executionResult: GitDeliveryExecutionResult;
|
|
82
|
+
};
|
|
83
|
+
export interface GitMutationLifecycleResult {
|
|
84
|
+
readonly envelope: GitDeliveryActionEnvelope;
|
|
85
|
+
readonly outcome: GitMutationOutcome;
|
|
86
|
+
readonly phaseReached: GitMutationLifecyclePhase;
|
|
87
|
+
readonly preflight: GitPreflightReport;
|
|
88
|
+
}
|
|
89
|
+
export declare function gitMutationOutcomeFailureCategory(outcome: GitMutationOutcome): GitMutationFailureCategory | undefined;
|
|
90
|
+
export declare function runGitMutation(request: GitMutationRequest, deps: GitMutationOrchestratorDeps): Promise<GitMutationLifecycleResult>;
|
|
91
|
+
export declare function createInMemoryGitMutationJournal(): GitMutationJournal;
|
|
92
|
+
//# sourceMappingURL=git-mutation-orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-mutation-orchestrator.d.ts","sourceRoot":"","sources":["../src/git-mutation-orchestrator.ts"],"names":[],"mappings":"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"}
|