@komatikai/trailhead 3.0.3 → 4.2.2

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.
@@ -0,0 +1,308 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { checkNameMatches } from "./ci-core.js";
4
+ import { parseRepoConfigContent } from "./config-core.js";
5
+ import { resolveCheckName } from "./release-ready.js";
6
+ const CONFIG_CANDIDATES = [".trailhead.yml", ".deployguard.yml"];
7
+ export function findConfigPath(cwd) {
8
+ for (const name of CONFIG_CANDIDATES) {
9
+ const candidate = path.join(cwd, name);
10
+ if (fs.existsSync(candidate))
11
+ return candidate;
12
+ }
13
+ return null;
14
+ }
15
+ export function loadRepoConfig(cwd) {
16
+ const configPath = findConfigPath(cwd);
17
+ if (!configPath) {
18
+ return {
19
+ configPath: null,
20
+ config: null,
21
+ error: "No .trailhead.yml or .deployguard.yml found",
22
+ };
23
+ }
24
+ const content = fs.readFileSync(configPath, "utf8");
25
+ const config = parseRepoConfigContent(content);
26
+ if (!config) {
27
+ return {
28
+ configPath,
29
+ config: null,
30
+ error: `Failed to parse ${path.basename(configPath)} — check YAML structure and schema fields`,
31
+ };
32
+ }
33
+ return { configPath, config };
34
+ }
35
+ export function collectConfiguredChecks(config) {
36
+ const names = new Set();
37
+ for (const context of config.contexts) {
38
+ for (const name of context.ci?.required_checks ?? []) {
39
+ names.add(name);
40
+ }
41
+ for (const name of context.ci?.optional_checks ?? []) {
42
+ names.add(name);
43
+ }
44
+ }
45
+ return [...names];
46
+ }
47
+ export function validateConfigStructure(config, configPath) {
48
+ const findings = [];
49
+ const fileName = path.basename(configPath);
50
+ const gateMode = config.gate.mode;
51
+ if (gateMode !== "risk-only" && config.schema_version < 2) {
52
+ findings.push({
53
+ severity: "warn",
54
+ code: "schema_version",
55
+ message: `${fileName} uses schema_version ${config.schema_version} with gate.mode=${gateMode} — consider schema_version: 2 and contexts[]`,
56
+ });
57
+ }
58
+ const risk = config.thresholds.risk;
59
+ const warn = config.thresholds.warn;
60
+ if (risk !== undefined && warn !== undefined && warn >= risk) {
61
+ findings.push({
62
+ severity: "warn",
63
+ code: "threshold_order",
64
+ message: `warn threshold (${warn}) should be lower than risk threshold (${risk})`,
65
+ });
66
+ }
67
+ if (gateMode !== "risk-only") {
68
+ if (config.contexts.length === 0) {
69
+ findings.push({
70
+ severity: "error",
71
+ code: "missing_contexts",
72
+ message: "release-ready/advisory mode requires at least one contexts[] entry with ci.required_checks",
73
+ });
74
+ }
75
+ for (const context of config.contexts) {
76
+ const required = context.ci?.required_checks ?? [];
77
+ if (required.length === 0) {
78
+ findings.push({
79
+ severity: "warn",
80
+ code: "empty_required_checks",
81
+ message: `Context "${context.name}" has no ci.required_checks — release-ready may not wait for CI`,
82
+ });
83
+ }
84
+ }
85
+ }
86
+ const gateCheck = resolveCheckName(gateMode, config.gate.check_name);
87
+ if (gateMode !== "risk-only" && !gateCheck.includes("Release Ready")) {
88
+ findings.push({
89
+ severity: "info",
90
+ code: "custom_check_name",
91
+ message: `Branch protection should require check name "${gateCheck}"`,
92
+ });
93
+ }
94
+ return findings;
95
+ }
96
+ export function compareConfiguredChecks(configuredChecks, observedChecks) {
97
+ if (observedChecks.length === 0) {
98
+ return [];
99
+ }
100
+ const findings = [];
101
+ const observed = [...new Set(observedChecks)];
102
+ for (const configured of configuredChecks) {
103
+ const matched = observed.some((actual) => checkNameMatches(configured, actual));
104
+ if (!matched) {
105
+ findings.push({
106
+ severity: "warn",
107
+ code: "unknown_check_name",
108
+ message: `Configured check "${configured}" did not match any recent GitHub check run`,
109
+ });
110
+ }
111
+ }
112
+ const selfChecks = new Set([
113
+ "Trailhead",
114
+ "Trailhead — Release Ready",
115
+ resolveCheckName("release-ready"),
116
+ resolveCheckName("risk-only"),
117
+ ]);
118
+ for (const actual of observed) {
119
+ if (selfChecks.has(actual))
120
+ continue;
121
+ const referenced = configuredChecks.some((configured) => checkNameMatches(configured, actual));
122
+ if (!referenced) {
123
+ findings.push({
124
+ severity: "info",
125
+ code: "unconfigured_check",
126
+ message: `GitHub check "${actual}" is not referenced in contexts[].ci (optional unless required)`,
127
+ });
128
+ }
129
+ }
130
+ return findings;
131
+ }
132
+ export function parseRepoRef(input) {
133
+ const match = input.match(/^([^/]+)\/([^/]+)$/);
134
+ if (!match)
135
+ return null;
136
+ return { owner: match[1], repo: match[2] };
137
+ }
138
+ async function githubRequest(token, url) {
139
+ const response = await fetch(url, {
140
+ headers: {
141
+ Accept: "application/vnd.github+json",
142
+ Authorization: `Bearer ${token}`,
143
+ "X-GitHub-Api-Version": "2022-11-28",
144
+ },
145
+ });
146
+ if (!response.ok) {
147
+ const body = await response.text().catch(() => "");
148
+ return {
149
+ ok: false,
150
+ status: response.status,
151
+ message: body || response.statusText,
152
+ };
153
+ }
154
+ return { ok: true, data: (await response.json()) };
155
+ }
156
+ async function resolveCommitSha(token, repoRef, ref) {
157
+ if (ref)
158
+ return ref;
159
+ const pulls = await githubRequest(token, `https://api.github.com/repos/${repoRef.owner}/${repoRef.repo}/pulls?state=open&per_page=1`);
160
+ if (pulls.ok && pulls.data[0]?.head.sha) {
161
+ return pulls.data[0].head.sha;
162
+ }
163
+ const repo = await githubRequest(token, `https://api.github.com/repos/${repoRef.owner}/${repoRef.repo}`);
164
+ if (!repo.ok)
165
+ return null;
166
+ const branch = await githubRequest(token, `https://api.github.com/repos/${repoRef.owner}/${repoRef.repo}/branches/${encodeURIComponent(repo.data.default_branch)}`);
167
+ return branch.ok ? branch.data.commit.sha : null;
168
+ }
169
+ export async function fetchObservedCheckNames(options) {
170
+ const sha = await resolveCommitSha(options.token, options.repo, options.ref);
171
+ if (!sha) {
172
+ return { checks: [], error: "Could not resolve a commit SHA for check lookup" };
173
+ }
174
+ const names = new Set();
175
+ let page = 1;
176
+ while (true) {
177
+ const result = await githubRequest(options.token, `https://api.github.com/repos/${options.repo.owner}/${options.repo.repo}/commits/${sha}/check-runs?per_page=100&page=${page}`);
178
+ if (!result.ok) {
179
+ return {
180
+ checks: [],
181
+ error: `GitHub Checks API failed (HTTP ${result.status})`,
182
+ };
183
+ }
184
+ for (const run of result.data.check_runs) {
185
+ names.add(run.name);
186
+ }
187
+ if (result.data.check_runs.length < 100)
188
+ break;
189
+ page += 1;
190
+ }
191
+ return { checks: [...names].sort() };
192
+ }
193
+ export async function runDoctor(options = {}) {
194
+ const cwd = options.cwd ?? process.cwd();
195
+ const loaded = loadRepoConfig(cwd);
196
+ const findings = [];
197
+ if (!loaded.configPath || !loaded.config) {
198
+ findings.push({
199
+ severity: "error",
200
+ code: "config_missing",
201
+ message: loaded.error ?? "Configuration file not found",
202
+ });
203
+ return {
204
+ configPath: loaded.configPath,
205
+ configValid: false,
206
+ gateMode: "risk-only",
207
+ expectedCheckName: "Trailhead",
208
+ configuredChecks: [],
209
+ observedChecks: [],
210
+ findings,
211
+ ok: false,
212
+ };
213
+ }
214
+ const config = loaded.config;
215
+ const gateMode = config.gate.mode;
216
+ const expectedCheckName = resolveCheckName(gateMode, config.gate.check_name);
217
+ const configuredChecks = collectConfiguredChecks(config);
218
+ findings.push(...validateConfigStructure(config, loaded.configPath));
219
+ let observedChecks = [];
220
+ if (!options.offline) {
221
+ const token = options.githubToken ?? process.env.GITHUB_TOKEN ?? "";
222
+ const repoInput = options.repo ?? process.env.GITHUB_REPOSITORY ?? "";
223
+ const repoRef = parseRepoRef(repoInput);
224
+ if (!token) {
225
+ findings.push({
226
+ severity: "info",
227
+ code: "offline_checks",
228
+ message: "Set GITHUB_TOKEN (or pass --token) to compare configured checks against GitHub",
229
+ });
230
+ }
231
+ else if (!repoRef) {
232
+ findings.push({
233
+ severity: "info",
234
+ code: "offline_checks",
235
+ message: "Set GITHUB_REPOSITORY (or pass --repo owner/name) to compare checks against GitHub",
236
+ });
237
+ }
238
+ else {
239
+ const observed = await fetchObservedCheckNames({
240
+ token,
241
+ repo: repoRef,
242
+ ref: options.ref,
243
+ });
244
+ observedChecks = observed.checks;
245
+ if (observed.error) {
246
+ findings.push({
247
+ severity: "warn",
248
+ code: "github_checks",
249
+ message: observed.error,
250
+ });
251
+ }
252
+ else if (configuredChecks.length > 0) {
253
+ findings.push(...compareConfiguredChecks(configuredChecks, observedChecks));
254
+ }
255
+ }
256
+ }
257
+ const ok = !findings.some((finding) => finding.severity === "error");
258
+ return {
259
+ configPath: loaded.configPath,
260
+ configValid: true,
261
+ gateMode,
262
+ expectedCheckName,
263
+ configuredChecks,
264
+ observedChecks,
265
+ findings,
266
+ ok,
267
+ };
268
+ }
269
+ export function formatDoctorReport(report) {
270
+ const lines = [];
271
+ lines.push("Trailhead Doctor");
272
+ lines.push("================");
273
+ lines.push("");
274
+ if (report.configPath) {
275
+ lines.push(`Config: ${report.configPath}`);
276
+ }
277
+ else {
278
+ lines.push("Config: (not found)");
279
+ }
280
+ lines.push(`Gate mode: ${report.gateMode}`);
281
+ lines.push(`Expected branch protection check: ${report.expectedCheckName}`);
282
+ if (report.configuredChecks.length > 0) {
283
+ lines.push(`Configured CI checks: ${report.configuredChecks.join(", ")}`);
284
+ }
285
+ if (report.observedChecks.length > 0) {
286
+ lines.push(`Observed GitHub checks: ${report.observedChecks.join(", ")}`);
287
+ }
288
+ if (report.findings.length === 0) {
289
+ lines.push("");
290
+ lines.push("No issues found.");
291
+ return lines.join("\n");
292
+ }
293
+ lines.push("");
294
+ for (const finding of report.findings) {
295
+ const label = finding.severity === "error"
296
+ ? "ERROR"
297
+ : finding.severity === "warn"
298
+ ? "WARN"
299
+ : "INFO";
300
+ lines.push(`${label} [${finding.code}] ${finding.message}`);
301
+ }
302
+ lines.push("");
303
+ lines.push(report.ok
304
+ ? "Result: OK (review warnings before release-ready rollout)"
305
+ : "Result: FAILED");
306
+ return lines.join("\n");
307
+ }
308
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/shared/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { CiSummary, GateDecision, GateEvaluation, GateMode } from "./types.js";
2
+ export interface ReleaseReadyInput {
3
+ gateMode: GateMode;
4
+ gateDecision: GateDecision;
5
+ riskScore: number;
6
+ riskThreshold: number;
7
+ healthScore: number;
8
+ healthChecksConfigured: boolean;
9
+ ciSummary?: CiSummary | null;
10
+ freezeActive: boolean;
11
+ freezeMessage?: string;
12
+ policyFindings?: string[];
13
+ requireSecurityClear?: boolean;
14
+ securityBlocked?: boolean;
15
+ }
16
+ export interface ReleaseReadyResult {
17
+ releaseReady: boolean;
18
+ reasons: string[];
19
+ }
20
+ /**
21
+ * Composite release readiness decision (ADR-006).
22
+ */
23
+ export declare function computeReleaseReady(input: ReleaseReadyInput): ReleaseReadyResult;
24
+ export declare function applyReleaseReadyToEvaluation(evaluation: GateEvaluation, result: ReleaseReadyResult, gateMode: GateMode): GateEvaluation;
25
+ export declare function checkConclusionForEvaluation(evaluation: GateEvaluation): "success" | "neutral" | "failure";
26
+ export declare function shouldBlockMerge(evaluation: GateEvaluation): boolean;
27
+ export declare function resolveCheckName(gateMode: GateMode, configuredName?: string): string;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Composite release readiness decision (ADR-006).
3
+ */
4
+ export function computeReleaseReady(input) {
5
+ const reasons = [];
6
+ if (input.gateMode === "risk-only") {
7
+ if (input.gateDecision === "block") {
8
+ reasons.push("Risk/policy gate decision is BLOCK");
9
+ }
10
+ else if (input.gateDecision === "warn") {
11
+ reasons.push("Risk/policy gate decision is WARN (non-blocking in risk-only mode)");
12
+ }
13
+ return {
14
+ releaseReady: input.gateDecision !== "block",
15
+ reasons,
16
+ };
17
+ }
18
+ if (input.ciSummary) {
19
+ if (!input.ciSummary.allRequiredPassed) {
20
+ const failed = input.ciSummary.checks.filter((c) => c.required &&
21
+ (c.status === "fail" || c.status === "missing" || c.status === "stale"));
22
+ for (const check of failed) {
23
+ reasons.push(`Required CI check "${check.name}" is ${check.status.toUpperCase()}`);
24
+ }
25
+ }
26
+ if (input.ciSummary.pendingCount > 0) {
27
+ reasons.push(`${input.ciSummary.pendingCount} required CI check(s) still pending`);
28
+ }
29
+ }
30
+ if (input.gateDecision === "block") {
31
+ reasons.push("Risk/policy gate decision is BLOCK");
32
+ }
33
+ if (input.riskScore > input.riskThreshold) {
34
+ reasons.push(`Risk score ${input.riskScore} exceeds threshold ${input.riskThreshold}`);
35
+ }
36
+ if (input.freezeActive) {
37
+ reasons.push(`Release freeze active${input.freezeMessage ? `: ${input.freezeMessage}` : ""}`);
38
+ }
39
+ if (input.healthChecksConfigured && input.healthScore < 50) {
40
+ reasons.push(`Health score ${input.healthScore} below minimum (50)`);
41
+ }
42
+ if (input.requireSecurityClear && input.securityBlocked) {
43
+ reasons.push("Security gate requires clearance — blocking alerts present");
44
+ }
45
+ const blockingFindings = (input.policyFindings ?? []).filter((f) => /blocking|requires|exceeds|configured to block/i.test(f));
46
+ if (blockingFindings.length > 0 && input.gateDecision === "block") {
47
+ for (const finding of blockingFindings.slice(0, 3)) {
48
+ if (!reasons.includes(finding))
49
+ reasons.push(finding);
50
+ }
51
+ }
52
+ const releaseReady = reasons.length === 0;
53
+ return { releaseReady, reasons };
54
+ }
55
+ export function applyReleaseReadyToEvaluation(evaluation, result, gateMode) {
56
+ return {
57
+ ...evaluation,
58
+ releaseReady: result.releaseReady,
59
+ releaseReadyReasons: result.reasons.length > 0 ? result.reasons : undefined,
60
+ gateMode,
61
+ };
62
+ }
63
+ export function checkConclusionForEvaluation(evaluation) {
64
+ const mode = evaluation.gateMode ?? "risk-only";
65
+ if (mode === "advisory") {
66
+ return "neutral";
67
+ }
68
+ if (mode === "release-ready") {
69
+ return evaluation.releaseReady ? "success" : "failure";
70
+ }
71
+ switch (evaluation.gateDecision) {
72
+ case "allow":
73
+ return "success";
74
+ case "warn":
75
+ return "neutral";
76
+ case "block":
77
+ return "failure";
78
+ default: {
79
+ const _exhaustive = evaluation.gateDecision;
80
+ return "failure";
81
+ }
82
+ }
83
+ }
84
+ export function shouldBlockMerge(evaluation) {
85
+ const mode = evaluation.gateMode ?? "risk-only";
86
+ if (mode === "advisory")
87
+ return false;
88
+ if (mode === "release-ready")
89
+ return evaluation.releaseReady === false;
90
+ return evaluation.gateDecision === "block";
91
+ }
92
+ export function resolveCheckName(gateMode, configuredName) {
93
+ if (gateMode === "risk-only")
94
+ return "Trailhead";
95
+ return configuredName ?? "Trailhead — Release Ready";
96
+ }
97
+ //# sourceMappingURL=release-ready.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-ready.js","sourceRoot":"","sources":["../../src/shared/release-ready.ts"],"names":[],"mappings":"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"}