putitoutthere 0.1.44 → 0.1.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +10 -1
  2. package/MIGRATIONS.md +82 -5
  3. package/README.md +16 -42
  4. package/action.yml +2 -2
  5. package/dist/cascade.d.ts +1 -1
  6. package/dist/cascade.js +2 -2
  7. package/dist/cli.d.ts +5 -0
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +7 -383
  10. package/dist/cli.js.map +1 -1
  11. package/dist/config.d.ts +6 -55
  12. package/dist/config.d.ts.map +1 -1
  13. package/dist/config.js +1 -32
  14. package/dist/config.js.map +1 -1
  15. package/dist/publish.d.ts +0 -10
  16. package/dist/publish.d.ts.map +1 -1
  17. package/dist/publish.js +6 -52
  18. package/dist/publish.js.map +1 -1
  19. package/dist/types.d.ts +1 -21
  20. package/dist/types.d.ts.map +1 -1
  21. package/dist/types.js.map +1 -1
  22. package/package.json +3 -2
  23. package/dist/auth.d.ts +0 -68
  24. package/dist/auth.d.ts.map +0 -1
  25. package/dist/auth.js +0 -285
  26. package/dist/auth.js.map +0 -1
  27. package/dist/doctor.d.ts +0 -115
  28. package/dist/doctor.d.ts.map +0 -1
  29. package/dist/doctor.js +0 -292
  30. package/dist/doctor.js.map +0 -1
  31. package/dist/keyring.d.ts +0 -35
  32. package/dist/keyring.d.ts.map +0 -1
  33. package/dist/keyring.js +0 -88
  34. package/dist/keyring.js.map +0 -1
  35. package/dist/oidc-policy.d.ts +0 -145
  36. package/dist/oidc-policy.d.ts.map +0 -1
  37. package/dist/oidc-policy.js +0 -388
  38. package/dist/oidc-policy.js.map +0 -1
  39. package/dist/preflight-run.d.ts +0 -47
  40. package/dist/preflight-run.d.ts.map +0 -1
  41. package/dist/preflight-run.js +0 -197
  42. package/dist/preflight-run.js.map +0 -1
  43. package/dist/registries/crates-trust.d.ts +0 -69
  44. package/dist/registries/crates-trust.d.ts.map +0 -1
  45. package/dist/registries/crates-trust.js +0 -95
  46. package/dist/registries/crates-trust.js.map +0 -1
  47. package/dist/release.d.ts +0 -36
  48. package/dist/release.d.ts.map +0 -1
  49. package/dist/release.js +0 -102
  50. package/dist/release.js.map +0 -1
  51. package/dist/token-scope.d.ts +0 -65
  52. package/dist/token-scope.d.ts.map +0 -1
  53. package/dist/token-scope.js +0 -163
  54. package/dist/token-scope.js.map +0 -1
  55. package/dist/token.d.ts +0 -211
  56. package/dist/token.d.ts.map +0 -1
  57. package/dist/token.js +0 -719
  58. package/dist/token.js.map +0 -1
package/dist/doctor.js DELETED
@@ -1,292 +0,0 @@
1
- /**
2
- * `putitoutthere doctor` — pre-flight validator.
3
- *
4
- * Validates: config parses; every package has a resolvable kind; every
5
- * package has usable credentials (OIDC or per-kind token). Returns a
6
- * structured report rather than throwing so the CLI can render it as
7
- * a table.
8
- *
9
- * When `checkArtifacts` is on, also walks the plan and checks each
10
- * expected artifact directory. Silent-skips when plan can't run (no
11
- * git state / no commits) so `doctor` stays useful in contexts that
12
- * don't have a release history yet.
13
- *
14
- * Issue #23. Plan: §21.1, §16.4.7. Artifact check: #89.
15
- */
16
- import { existsSync } from 'node:fs';
17
- import { join } from 'node:path';
18
- import { expectedLayout } from './completeness.js';
19
- import { loadConfig } from './config.js';
20
- import { checkEnvironment, checkPermissions, checkPublishInvocation, diffEnvironment, diffWorkflowFilename, findPublishWorkflows, inferFromGithubWorkflowRef, } from './oidc-policy.js';
21
- import { diffCratesTrust, fetchCratesTrustPolicy, } from './registries/crates-trust.js';
22
- import { plan } from './plan.js';
23
- import { checkAuth } from './preflight.js';
24
- import { deepCheck } from './token-scope.js';
25
- export async function doctor(opts) {
26
- const issues = [];
27
- let config = null;
28
- /* v8 ignore next -- tests always pass an explicit cwd */
29
- const cfgPath = opts.configPath ?? `${opts.cwd.replace(/\/+$/, '')}/putitoutthere.toml`;
30
- try {
31
- config = loadConfig(cfgPath);
32
- /* v8 ignore start -- non-Error catch fallback path */
33
- }
34
- catch (err) {
35
- issues.push(`config: ${err instanceof Error ? err.message : String(err)}`);
36
- }
37
- /* v8 ignore stop */
38
- const packages = [];
39
- if (config) {
40
- const auth = checkAuth(config.packages);
41
- for (const pkg of config.packages) {
42
- const row = auth.results.find((r) => r.package === pkg.name);
43
- /* v8 ignore next -- every cascaded package has a row in checkAuth */
44
- const via = row?.via ?? 'missing';
45
- packages.push({ name: pkg.name, kind: pkg.kind, auth: via });
46
- if (via === 'missing') {
47
- issues.push(`auth: ${pkg.name} (${pkg.kind}) needs ${row?.acceptedEnvVars.join(' or ') ?? '<env-var>'} or OIDC`);
48
- }
49
- }
50
- if (opts.deep) {
51
- const scopable = config.packages.filter((p) => {
52
- const r = auth.results.find((x) => x.package === p.name);
53
- return r !== undefined && r.via === 'token';
54
- });
55
- const envVarForPackage = new Map();
56
- for (const p of scopable) {
57
- const r = auth.results.find((x) => x.package === p.name);
58
- /* v8 ignore next -- filter above guarantees a row */
59
- if (r !== undefined)
60
- envVarForPackage.set(p.name, r.envVar);
61
- }
62
- const rows = await deepCheck({
63
- packages: scopable,
64
- envVarForPackage,
65
- ...(opts.inspectFn !== undefined ? { inspect: opts.inspectFn } : {}),
66
- });
67
- for (const row of rows) {
68
- const pkgEntry = packages.find((p) => p.name === row.package);
69
- /* v8 ignore next -- deepCheck rows always correspond to a scoped package */
70
- if (pkgEntry === undefined)
71
- continue;
72
- pkgEntry.scope = row.scope;
73
- pkgEntry.scope_match = row.match;
74
- if (row.match === 'mismatch' || row.match === 'error') {
75
- issues.push(`scope: ${row.package} (${row.kind}) — ${row.detail ?? 'token scope does not match config'}`);
76
- }
77
- }
78
- }
79
- }
80
- const artifacts = opts.checkArtifacts && config
81
- ? await checkArtifacts(opts, cfgPath, issues)
82
- : undefined;
83
- const workflows = findPublishWorkflows(opts.cwd);
84
- const trustPolicy = checkTrustPolicyLocal(workflows, issues);
85
- const trustPolicyDeclared = config
86
- ? checkTrustPolicyDeclared(config.packages, workflows, issues)
87
- : undefined;
88
- const trustPolicyCratesIo = config
89
- ? await checkTrustPolicyCratesIo(config.packages, issues, opts.cratesIoFetch)
90
- : undefined;
91
- return {
92
- ok: issues.length === 0,
93
- issues,
94
- packages,
95
- ...(artifacts !== undefined ? { artifacts } : {}),
96
- ...(trustPolicy !== undefined ? { trustPolicy } : {}),
97
- ...(trustPolicyDeclared !== undefined ? { trustPolicyDeclared } : {}),
98
- ...(trustPolicyCratesIo !== undefined ? { trustPolicyCratesIo } : {}),
99
- };
100
- }
101
- /**
102
- * Trust-policy (local) phase. Additive; runs after auth-availability.
103
- * Deferred to a follow-up: filename-vs-registry diff and environment-
104
- * name-vs-registry diff (Option C of #162).
105
- */
106
- function checkTrustPolicyLocal(workflows, issues) {
107
- if (workflows.length === 0)
108
- return undefined;
109
- const report = { workflows: [] };
110
- for (const wf of workflows) {
111
- const wfIssues = [];
112
- const invocation = checkPublishInvocation(wf);
113
- if (invocation !== null) {
114
- wfIssues.push(`trust-policy: ${wf.filename}: no clearly-identifiable publish step (commented out?)`);
115
- }
116
- const perms = checkPermissions(wf);
117
- for (const p of perms) {
118
- wfIssues.push(`trust-policy: ${wf.filename}: job \`${p.job}\` is missing \`${p.permission}\` permission — add it to the job or to workflow-level \`permissions:\``);
119
- }
120
- const env = checkEnvironment(wf);
121
- if (env !== null) {
122
- wfIssues.push(`trust-policy: ${wf.filename}: job \`${env.job}\` has no \`environment:\` key — many trust policies pin an environment; add one (e.g. \`environment: release\`) matching the registry registration`);
123
- }
124
- for (const line of wfIssues)
125
- issues.push(line);
126
- report.workflows.push({
127
- filename: wf.filename,
128
- permissions_ok: perms.length === 0,
129
- environment_ok: env === null,
130
- invocation_ok: invocation === null,
131
- issues: wfIssues,
132
- });
133
- }
134
- return report;
135
- }
136
- /**
137
- * Exported for CLI rendering: the explicit "what's NOT checked" line
138
- * we surface below the trust-policy phase so a green doctor output
139
- * doesn't imply the filename landmine is caught.
140
- */
141
- export const TRUST_POLICY_SCOPE_NOTE = 'note: declare `[package.trust_policy]` to have `doctor` diff workflow + environment against the config. Registry cross-check is crates.io-only (set `CRATES_IO_DOCTOR_TOKEN`); PyPI and npm are declaration-only.';
142
- /**
143
- * Declared-diff phase (#189). For each package with a `[package.trust_policy]`
144
- * block, diffs the declaration against:
145
- * - the local workflow file that `findPublishWorkflows` identified
146
- * - `GITHUB_WORKFLOW_REF` when running inside Actions
147
- * Returns `undefined` when no package has a declaration.
148
- */
149
- function checkTrustPolicyDeclared(packages, workflows, issues) {
150
- const declared = packages.filter((p) => p.trust_policy !== undefined);
151
- if (declared.length === 0)
152
- return undefined;
153
- const report = { packages: [] };
154
- const localWorkflow = workflows[0]?.filename;
155
- const inferred = inferFromGithubWorkflowRef();
156
- for (const pkg of declared) {
157
- const policy = pkg.trust_policy;
158
- /* v8 ignore next -- filter guarantees trust_policy is set */
159
- if (policy === undefined)
160
- continue;
161
- const pkgIssues = [];
162
- let workflowOk = true;
163
- let environmentOk = true;
164
- let refOk = true;
165
- if (localWorkflow !== undefined) {
166
- const mismatch = diffWorkflowFilename(policy.workflow, localWorkflow);
167
- if (mismatch !== null) {
168
- workflowOk = false;
169
- pkgIssues.push(renderWorkflowMismatch(pkg.name, mismatch));
170
- }
171
- }
172
- if (policy.environment !== undefined) {
173
- for (const wf of workflows) {
174
- const envMismatch = diffEnvironment(policy.environment, wf);
175
- if (envMismatch !== null) {
176
- environmentOk = false;
177
- pkgIssues.push(renderEnvironmentMismatch(pkg.name, envMismatch));
178
- break;
179
- }
180
- }
181
- }
182
- if (inferred !== null && inferred.workflow !== policy.workflow) {
183
- refOk = false;
184
- pkgIssues.push(`trust-policy: ${pkg.name}: GITHUB_WORKFLOW_REF says the running workflow is ${inferred.workflow}, but [package.trust_policy].workflow is ${policy.workflow}`);
185
- }
186
- for (const line of pkgIssues)
187
- issues.push(line);
188
- report.packages.push({
189
- name: pkg.name,
190
- workflow_ok: workflowOk,
191
- environment_ok: environmentOk,
192
- ref_ok: refOk,
193
- issues: pkgIssues,
194
- });
195
- }
196
- return report;
197
- }
198
- function renderWorkflowMismatch(pkgName, m) {
199
- return `trust-policy: ${pkgName}: declared workflow ${m.declared} does not match local workflow ${m.actual} — update [package.trust_policy].workflow or rename the workflow file back`;
200
- }
201
- function renderEnvironmentMismatch(pkgName, m) {
202
- const actual = m.actual ?? '(none)';
203
- return `trust-policy: ${pkgName}: declared environment ${m.declared} does not match workflow ${m.workflow}'s environment ${actual}`;
204
- }
205
- /**
206
- * Opt-in crates.io cross-check (#189). Silent-skip when
207
- * `CRATES_IO_DOCTOR_TOKEN` is unset. For each `kind = "crates"` package
208
- * with a declared `trust_policy`, fetches the registered configs and
209
- * diffs against the declaration. Transient failures are neutral-skipped
210
- * so a bad crates.io minute doesn't turn doctor red; 401 fails.
211
- */
212
- async function checkTrustPolicyCratesIo(packages, issues, fetchFn = fetchCratesTrustPolicy) {
213
- const crates = packages.filter((p) => p.kind === 'crates' && p.trust_policy !== undefined);
214
- if (crates.length === 0)
215
- return undefined;
216
- const token = process.env.CRATES_IO_DOCTOR_TOKEN;
217
- if (token === undefined || token.length === 0) {
218
- return {
219
- status: 'skipped',
220
- reason: 'set CRATES_IO_DOCTOR_TOKEN to enable crates.io trust-policy cross-check',
221
- crates: [],
222
- };
223
- }
224
- const report = { status: 'ran', crates: [] };
225
- for (const pkg of crates) {
226
- const crateName = pkg.name;
227
- const result = await fetchFn(crateName, token);
228
- if (result.kind === 'skip-transient') {
229
- report.crates.push({ name: crateName, status: 'skip-transient', reason: result.reason });
230
- continue;
231
- }
232
- if (result.kind === 'auth-failed') {
233
- report.crates.push({ name: crateName, status: 'auth-failed', reason: result.reason });
234
- issues.push(`trust-policy: ${crateName}: ${result.reason}`);
235
- continue;
236
- }
237
- const policy = pkg.trust_policy;
238
- const mismatches = diffCratesTrust(crateName, {
239
- workflow: policy.workflow,
240
- ...(policy.environment !== undefined ? { environment: policy.environment } : {}),
241
- ...(policy.repository !== undefined ? { repository: policy.repository } : {}),
242
- }, result.configs);
243
- if (mismatches.length === 0) {
244
- report.crates.push({ name: crateName, status: 'ok' });
245
- }
246
- else {
247
- report.crates.push({ name: crateName, status: 'mismatch', mismatches });
248
- for (const m of mismatches) {
249
- issues.push(`trust-policy: ${crateName}: crates.io has ${m.field} = ${m.registered ?? '(none)'}, config declares ${m.declared}`);
250
- }
251
- }
252
- }
253
- return report;
254
- }
255
- async function checkArtifacts(opts, cfgPath, issues) {
256
- let matrix;
257
- try {
258
- matrix = (await plan({ cwd: opts.cwd, configPath: cfgPath }));
259
- }
260
- catch (err) {
261
- // Plan needs a git repo with at least one commit. In a scratch
262
- // checkout (no git state yet) we can't walk the plan at all, so
263
- // we note it as a soft issue and move on.
264
- /* v8 ignore next -- non-Error catch fallback path */
265
- const message = err instanceof Error ? err.message : String(err);
266
- issues.push(`artifacts: cannot walk plan (${message})`);
267
- return [];
268
- }
269
- const root = join(opts.cwd, 'artifacts');
270
- const rows = [];
271
- for (const row of matrix) {
272
- // Vanilla npm publishes from the source tree; there's no separate
273
- // artifact dir to check. Mirrors completeness.ts's carve-out.
274
- if (row.kind === 'npm' && row.target === 'noarch')
275
- continue;
276
- const dir = join(root, row.artifact_name);
277
- const present = existsSync(dir);
278
- const expected = expectedLayout(row);
279
- rows.push({
280
- package: row.name,
281
- target: row.target,
282
- artifact_name: row.artifact_name,
283
- present,
284
- expected,
285
- });
286
- if (!present) {
287
- issues.push(`artifacts: ${row.name} (${row.target}) missing; expected ${expected}`);
288
- }
289
- }
290
- return rows;
291
- }
292
- //# sourceMappingURL=doctor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAkB,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAgB,MAAM,aAAa,CAAC;AACvD,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,0BAA0B,GAI3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,eAAe,EACf,sBAAsB,GAEvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAmB,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAqC,MAAM,kBAAkB,CAAC;AA6FhF,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAmB;IAC9C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,MAAM,GAAmC,IAAI,CAAC;IAElD,yDAAyD;IACzD,MAAM,OAAO,GACX,IAAI,CAAC,UAAU,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,qBAAqB,CAAC;IAE1E,IAAI,CAAC;QACH,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAC7B,sDAAsD;IACxD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CACT,WAAW,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC9D,CAAC;IACJ,CAAC;IACD,oBAAoB;IAEpB,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAE9C,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YAClC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC;YAC7D,qEAAqE;YACrE,MAAM,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI,SAAS,CAAC;YAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;YAC7D,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,MAAM,CAAC,IAAI,CACT,SAAS,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,WAAW,GAAG,EAAE,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,WAAW,UAAU,CACpG,CAAC;YACJ,CAAC;QACH,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;gBACzD,OAAO,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC;YAC9C,CAAC,CAAC,CAAC;YACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAkB,CAAC;YACnD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACzB,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;gBACzD,qDAAqD;gBACrD,IAAI,CAAC,KAAK,SAAS;oBAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;YAC9D,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC;gBAC3B,QAAQ,EAAE,QAAQ;gBAClB,gBAAgB;gBAChB,GAAG,CAAC,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrE,CAAC,CAAC;YACH,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC9D,4EAA4E;gBAC5E,IAAI,QAAQ,KAAK,SAAS;oBAAE,SAAS;gBACrC,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;gBAC3B,QAAQ,CAAC,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC;gBACjC,IAAI,GAAG,CAAC,KAAK,KAAK,UAAU,IAAI,GAAG,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;oBACtD,MAAM,CAAC,IAAI,CACT,UAAU,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,MAAM,IAAI,mCAAmC,EAAE,CAC7F,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,IAAI,MAAM;QAC7C,CAAC,CAAC,MAAM,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC;QAC7C,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,SAAS,GAAG,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,qBAAqB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC7D,MAAM,mBAAmB,GAAG,MAAM;QAChC,CAAC,CAAC,wBAAwB,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC;QAC9D,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,mBAAmB,GAAG,MAAM;QAChC,CAAC,CAAC,MAAM,wBAAwB,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC;QAC7E,CAAC,CAAC,SAAS,CAAC;IAEd,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QACvB,MAAM;QACN,QAAQ;QACR,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,mBAAmB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,GAAG,CAAC,mBAAmB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtE,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,qBAAqB,CAC5B,SAAkC,EAClC,MAAgB;IAEhB,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAE7C,MAAM,MAAM,GAAsB,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACpD,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,MAAM,UAAU,GAAG,sBAAsB,CAAC,EAAE,CAAC,CAAC;QAC9C,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,QAAQ,CAAC,IAAI,CACX,iBAAiB,EAAE,CAAC,QAAQ,yDAAyD,CACtF,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAC;QACnC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,QAAQ,CAAC,IAAI,CACX,iBAAiB,EAAE,CAAC,QAAQ,WAAW,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,UAAU,yEAAyE,CACrJ,CAAC;QACJ,CAAC;QAED,MAAM,GAAG,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAC;QACjC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,QAAQ,CAAC,IAAI,CACX,iBAAiB,EAAE,CAAC,QAAQ,WAAW,GAAG,CAAC,GAAG,qJAAqJ,CACpM,CAAC;QACJ,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,QAAQ;YAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC;YACpB,QAAQ,EAAE,EAAE,CAAC,QAAQ;YACrB,cAAc,EAAE,KAAK,CAAC,MAAM,KAAK,CAAC;YAClC,cAAc,EAAE,GAAG,KAAK,IAAI;YAC5B,aAAa,EAAE,UAAU,KAAK,IAAI;YAClC,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAClC,mNAAmN,CAAC;AAEtN;;;;;;GAMG;AACH,SAAS,wBAAwB,CAC/B,QAA4B,EAC5B,SAAkC,EAClC,MAAgB;IAEhB,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC;IACtE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5C,MAAM,MAAM,GAA8B,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC3D,MAAM,aAAa,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC;IAC7C,MAAM,QAAQ,GAAG,0BAA0B,EAAE,CAAC;IAC9C,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC;QAChC,6DAA6D;QAC7D,IAAI,MAAM,KAAK,SAAS;YAAE,SAAS;QACnC,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,IAAI,UAAU,GAAG,IAAI,CAAC;QACtB,IAAI,aAAa,GAAG,IAAI,CAAC;QACzB,IAAI,KAAK,GAAG,IAAI,CAAC;QACjB,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;YACtE,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACtB,UAAU,GAAG,KAAK,CAAC;gBACnB,SAAS,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QACD,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACrC,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;gBAC3B,MAAM,WAAW,GAAG,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;gBAC5D,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;oBACzB,aAAa,GAAG,KAAK,CAAC;oBACtB,SAAS,CAAC,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;oBACjE,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC/D,KAAK,GAAG,KAAK,CAAC;YACd,SAAS,CAAC,IAAI,CACZ,iBAAiB,GAAG,CAAC,IAAI,sDAAsD,QAAQ,CAAC,QAAQ,4CAA4C,MAAM,CAAC,QAAQ,EAAE,CAC9J,CAAC;QACJ,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,SAAS;YAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YACnB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,WAAW,EAAE,UAAU;YACvB,cAAc,EAAE,aAAa;YAC7B,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,SAAS;SAClB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,sBAAsB,CAAC,OAAe,EAAE,CAA2B;IAC1E,OAAO,iBAAiB,OAAO,uBAAuB,CAAC,CAAC,QAAQ,kCAAkC,CAAC,CAAC,MAAM,4EAA4E,CAAC;AACzL,CAAC;AAED,SAAS,yBAAyB,CAAC,OAAe,EAAE,CAAsB;IACxE,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,IAAI,QAAQ,CAAC;IACpC,OAAO,iBAAiB,OAAO,0BAA0B,CAAC,CAAC,QAAQ,4BAA4B,CAAC,CAAC,QAAQ,kBAAkB,MAAM,EAAE,CAAC;AACtI,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,wBAAwB,CACrC,QAA4B,EAC5B,MAAgB,EAChB,UAAyC,sBAAsB;IAE/D,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAC5B,CAAC,CAAC,EAAyF,EAAE,CAC3F,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,YAAY,KAAK,SAAS,CACtD,CAAC;IACF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;IACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9C,OAAO;YACL,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,yEAAyE;YACjF,MAAM,EAAE,EAAE;SACX,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAA8B,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACxE,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC/C,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YACzF,SAAS;QACX,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YACtF,MAAM,CAAC,IAAI,CAAC,iBAAiB,SAAS,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YAC5D,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC;QAChC,MAAM,UAAU,GAAG,eAAe,CAChC,SAAS,EACT;YACE,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChF,GAAG,CAAC,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9E,EACD,MAAM,CAAC,OAAO,CACf,CAAC;QACF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;YACxE,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;gBAC3B,MAAM,CAAC,IAAI,CACT,iBAAiB,SAAS,mBAAmB,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,UAAU,IAAI,QAAQ,qBAAqB,CAAC,CAAC,QAAQ,EAAE,CACpH,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAKD,KAAK,UAAU,cAAc,CAC3B,IAAmB,EACnB,OAAe,EACf,MAAgB;IAEhB,IAAI,MAAmB,CAAC;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAgB,CAAC;IAC/E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,+DAA+D;QAC/D,gEAAgE;QAChE,0CAA0C;QAC1C,qDAAqD;QACrD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,CAAC,IAAI,CAAC,gCAAgC,OAAO,GAAG,CAAC,CAAC;QACxD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACzC,MAAM,IAAI,GAA2C,EAAE,CAAC;IACxD,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,kEAAkE;QAClE,8DAA8D;QAC9D,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ;YAAE,SAAS;QAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC;YACR,OAAO,EAAE,GAAG,CAAC,IAAI;YACjB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,aAAa,EAAE,GAAG,CAAC,aAAa;YAChC,OAAO;YACP,QAAQ;SACT,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,MAAM,uBAAuB,QAAQ,EAAE,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
package/dist/keyring.d.ts DELETED
@@ -1,35 +0,0 @@
1
- /**
2
- * Keyring — persistent storage for the user access token obtained
3
- * through `auth login`.
4
- *
5
- * Ships with a file-backed implementation (chmod 0600 in an XDG-
6
- * compliant config dir). The `Keyring` interface is the seam for
7
- * swapping in an OS keychain binding (e.g. `keytar`) later; see #105.
8
- *
9
- * Token values are never logged. Callers pass the whole `StoredAuth`
10
- * in and out; this module does not expose a "read just the access
11
- * token" affordance that could encourage stringification.
12
- */
13
- export interface StoredAuth {
14
- /** GitHub login of the account that approved the Device Flow. */
15
- account: string;
16
- access_token: string;
17
- refresh_token: string;
18
- /** Epoch seconds. */
19
- access_token_expires_at: number;
20
- /** Epoch seconds. */
21
- refresh_token_expires_at: number;
22
- }
23
- export interface Keyring {
24
- get(): Promise<StoredAuth | null>;
25
- set(auth: StoredAuth): Promise<void>;
26
- delete(): Promise<void>;
27
- }
28
- export interface FileKeyringOptions {
29
- /** Override the resolved config dir. Tests inject a tmp path. */
30
- dir?: string;
31
- }
32
- export declare function fileKeyring(opts?: FileKeyringOptions): Keyring;
33
- /** Returned for production callers. */
34
- export declare function defaultKeyring(): Keyring;
35
- //# sourceMappingURL=keyring.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"keyring.d.ts","sourceRoot":"","sources":["../src/keyring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAaH,MAAM,WAAW,UAAU;IACzB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,qBAAqB;IACrB,uBAAuB,EAAE,MAAM,CAAC;IAChC,qBAAqB;IACrB,wBAAwB,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,OAAO;IACtB,GAAG,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAClC,GAAG,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,WAAW,CAAC,IAAI,GAAE,kBAAuB,GAAG,OAAO,CA4BlE;AAED,uCAAuC;AACvC,wBAAgB,cAAc,IAAI,OAAO,CAExC"}
package/dist/keyring.js DELETED
@@ -1,88 +0,0 @@
1
- /**
2
- * Keyring — persistent storage for the user access token obtained
3
- * through `auth login`.
4
- *
5
- * Ships with a file-backed implementation (chmod 0600 in an XDG-
6
- * compliant config dir). The `Keyring` interface is the seam for
7
- * swapping in an OS keychain binding (e.g. `keytar`) later; see #105.
8
- *
9
- * Token values are never logged. Callers pass the whole `StoredAuth`
10
- * in and out; this module does not expose a "read just the access
11
- * token" affordance that could encourage stringification.
12
- */
13
- import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, } from 'node:fs';
14
- import { homedir } from 'node:os';
15
- import { join } from 'node:path';
16
- export function fileKeyring(opts = {}) {
17
- const dir = opts.dir ?? defaultConfigDir();
18
- const path = join(dir, 'auth.json');
19
- return {
20
- get() {
21
- if (!existsSync(path))
22
- return Promise.resolve(null);
23
- const raw = readFileSync(path, 'utf8');
24
- return Promise.resolve(tryParse(raw));
25
- },
26
- set(auth) {
27
- if (!existsSync(dir)) {
28
- mkdirSync(dir, { recursive: true, mode: 0o700 });
29
- }
30
- else {
31
- // Best-effort tighten; harmless if we don't own the dir.
32
- /* v8 ignore next -- catch only fires when another process owns the dir; not reachable in unit tests. */
33
- try {
34
- chmodSync(dir, 0o700);
35
- }
36
- catch { /* ignore */ }
37
- }
38
- writeFileSync(path, JSON.stringify(auth, null, 2) + '\n', { mode: 0o600 });
39
- // writeFileSync honors `mode` only on create. Re-chmod to catch
40
- // the overwrite-an-existing-file case where the old mode sticks.
41
- chmodSync(path, 0o600);
42
- return Promise.resolve();
43
- },
44
- delete() {
45
- if (existsSync(path))
46
- rmSync(path);
47
- return Promise.resolve();
48
- },
49
- };
50
- }
51
- /** Returned for production callers. */
52
- export function defaultKeyring() {
53
- return fileKeyring();
54
- }
55
- /* v8 ignore next 5 -- resolves the user's config dir; tests inject `dir` directly so this branch is only taken in production. */
56
- function defaultConfigDir() {
57
- const xdg = process.env.XDG_CONFIG_HOME;
58
- if (xdg && xdg.length > 0)
59
- return join(xdg, 'putitoutthere');
60
- return join(homedir(), '.config', 'putitoutthere');
61
- }
62
- function tryParse(raw) {
63
- let v;
64
- try {
65
- v = JSON.parse(raw);
66
- }
67
- catch {
68
- return null;
69
- }
70
- if (!v || typeof v !== 'object')
71
- return null;
72
- const o = v;
73
- if (typeof o.account !== 'string' ||
74
- typeof o.access_token !== 'string' ||
75
- typeof o.refresh_token !== 'string' ||
76
- typeof o.access_token_expires_at !== 'number' ||
77
- typeof o.refresh_token_expires_at !== 'number') {
78
- return null;
79
- }
80
- return {
81
- account: o.account,
82
- access_token: o.access_token,
83
- refresh_token: o.refresh_token,
84
- access_token_expires_at: o.access_token_expires_at,
85
- refresh_token_expires_at: o.refresh_token_expires_at,
86
- };
87
- }
88
- //# sourceMappingURL=keyring.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"keyring.js","sourceRoot":"","sources":["../src/keyring.ts"],"names":[],"mappings":"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"}
@@ -1,145 +0,0 @@
1
- /**
2
- * OIDC trust-policy local validation.
3
- *
4
- * `doctor` uses this module to check the locally-knowable structural
5
- * prerequisites of OIDC trusted publishing:
6
- *
7
- * 1. At least one `.github/workflows/*.yml` file invokes either
8
- * `putitoutthere publish` (as a `run:` command) or the composite
9
- * action `thekevinscott/putitoutthere@...` with a `command:`
10
- * input that implies publishing.
11
- * 2. That workflow's publishing job has `permissions: id-token: write`
12
- * and `contents: write` (either job-level or workflow-level).
13
- * 3. The publishing job has an `environment:` key set. We cannot
14
- * validate the *value* against the registry's trust policy — that
15
- * requires a registry-policy-read API per registry, which is
16
- * deferred (Option C, see follow-up to #162).
17
- * 4. A clearly-identifiable publish step exists — defends against
18
- * edge cases like commented-out steps slipping past (1).
19
- *
20
- * The parser is intentionally regex/line-based rather than a full YAML
21
- * parse: the four checks above all reduce to substring/indentation
22
- * matches within a single jobs block. Adding a YAML dependency would
23
- * buy us very little here. If the check set grows beyond this (e.g.
24
- * "validate the environment value against a registry's trust policy"),
25
- * revisit.
26
- *
27
- * Issue #162 — Option D (locally-knowable checks only).
28
- */
29
- export interface WorkflowFile {
30
- /** Absolute path to the workflow file on disk. */
31
- path: string;
32
- /** Basename, e.g. `release.yml`. */
33
- filename: string;
34
- /** Full file contents. */
35
- source: string;
36
- /** Parsed jobs (best-effort; top-level job keys + their raw bodies). */
37
- jobs: WorkflowJob[];
38
- /** Workflow-level `permissions:` block contents (empty if none). */
39
- workflowPermissions: string;
40
- }
41
- export interface WorkflowJob {
42
- /** Job key, e.g. `publish`. */
43
- name: string;
44
- /** Raw source of just that job block (everything indented under it). */
45
- source: string;
46
- }
47
- export interface PermissionIssue {
48
- kind: 'missing-permission';
49
- workflow: string;
50
- job: string;
51
- permission: 'id-token: write' | 'contents: write';
52
- }
53
- export interface EnvironmentIssue {
54
- kind: 'missing-environment';
55
- workflow: string;
56
- job: string;
57
- }
58
- export interface InvocationIssue {
59
- kind: 'no-publish-step';
60
- workflow: string;
61
- }
62
- /** Issue: declared `trust_policy.workflow` does not match the workflow we found. */
63
- export interface WorkflowFilenameMismatch {
64
- kind: 'workflow-filename-mismatch';
65
- declared: string;
66
- actual: string;
67
- /** Where `actual` came from — used to refine the error message. */
68
- source: 'local-workflow' | 'github-workflow-ref';
69
- }
70
- /** Issue: declared `trust_policy.environment` does not match the workflow. */
71
- export interface EnvironmentMismatch {
72
- kind: 'environment-mismatch';
73
- workflow: string;
74
- declared: string;
75
- actual: string | null;
76
- }
77
- /**
78
- * Scan `.github/workflows/*.yml` and `*.yaml` for workflows that invoke
79
- * `putitoutthere publish` or the composite action in a publish mode.
80
- *
81
- * Permissive by design: if a workflow *mentions* piot in any way that
82
- * looks like publishing, include it. Downstream checks then report
83
- * specifically. The cost of a false-positive is a spurious pass/fail
84
- * line in `doctor`; the cost of a false-negative is silently missing
85
- * the user's real publish workflow.
86
- */
87
- export declare function findPublishWorkflows(repoRoot: string): WorkflowFile[];
88
- /**
89
- * Best-effort jobs parser. Finds the top-level `jobs:` block and
90
- * extracts each direct-child key + its body. We use the two-space
91
- * indent convention GitHub Actions workflows follow. Workflows that
92
- * deviate (tabs, four-space) would miss — but `init` emits two-space,
93
- * which is what we're validating.
94
- */
95
- export declare function parseJobs(source: string): WorkflowJob[];
96
- /**
97
- * Check that the publishing job has (or inherits) the two permissions
98
- * that OIDC trusted publishing requires. The permissions may be set at
99
- * workflow level (top-level `permissions:`) and/or job level; this
100
- * function reports a missing permission only if *neither* scope
101
- * declares it. `write-all` satisfies both.
102
- */
103
- export declare function checkPermissions(workflow: WorkflowFile): PermissionIssue[];
104
- /**
105
- * Return `{ kind: 'missing' }` when the publish job lacks an
106
- * `environment:` key. Does NOT inspect the value — diff-vs-registry is
107
- * Option C.
108
- */
109
- export declare function checkEnvironment(workflow: WorkflowFile): EnvironmentIssue | null;
110
- /**
111
- * Sanity check: confirm the workflow has at least one clearly-
112
- * identifiable publish step. `findPublishWorkflows` already filters,
113
- * but this catches weird states like a `run:` that's been edited into
114
- * a comment while the composite-action `uses:` line still matches.
115
- */
116
- export declare function checkPublishInvocation(workflow: WorkflowFile): InvocationIssue | null;
117
- /**
118
- * Compare `trust_policy.workflow` against the filename of the workflow
119
- * that `findPublishWorkflows` identified. The declaration is always a
120
- * bare filename (Zod enforces that at parse time); the comparison is
121
- * case-sensitive. Returns `null` on match.
122
- */
123
- export declare function diffWorkflowFilename(declared: string, workflowFilename: string): WorkflowFilenameMismatch | null;
124
- /**
125
- * Compare `trust_policy.environment` against the workflow's job-level
126
- * `environment:` value. Absence of a declared environment is not an
127
- * error — the caller decides whether to invoke this. Returns `null` on
128
- * match.
129
- */
130
- export declare function diffEnvironment(declared: string, workflow: WorkflowFile): EnvironmentMismatch | null;
131
- /**
132
- * Read `process.env.GITHUB_WORKFLOW_REF` (populated by GitHub Actions)
133
- * and parse out the workflow filename. Shape:
134
- *
135
- * `owner/repo/.github/workflows/release.yml@refs/heads/main`
136
- *
137
- * Returns `null` when the env var is absent (we're not running inside
138
- * Actions) OR when the value doesn't parse — we'd rather neutral-skip
139
- * the check than false-positive on an unexpected shape.
140
- */
141
- export declare function inferFromGithubWorkflowRef(env?: NodeJS.ProcessEnv): {
142
- workflow: string;
143
- repository: string;
144
- } | null;
145
- //# sourceMappingURL=oidc-policy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"oidc-policy.d.ts","sourceRoot":"","sources":["../src/oidc-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAKH,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,oEAAoE;IACpE,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,oBAAoB,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,iBAAiB,GAAG,iBAAiB,CAAC;CACnD;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,qBAAqB,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,oFAAoF;AACpF,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,4BAA4B,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,MAAM,EAAE,gBAAgB,GAAG,qBAAqB,CAAC;CAClD;AAED,8EAA8E;AAC9E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CA8BrE;AAsBD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,EAAE,CA6BvD;AA0BD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,GAAG,eAAe,EAAE,CAyB1E;AASD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,GAAG,gBAAgB,GAAG,IAAI,CAShF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,YAAY,GAAG,eAAe,GAAG,IAAI,CAiBrF;AAeD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,MAAM,GACvB,wBAAwB,GAAG,IAAI,CASjC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,YAAY,GACrB,mBAAmB,GAAG,IAAI,CAS5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUjD"}