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.
- package/CHANGELOG.md +10 -1
- package/MIGRATIONS.md +82 -5
- package/README.md +16 -42
- package/action.yml +2 -2
- package/dist/cascade.d.ts +1 -1
- package/dist/cascade.js +2 -2
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +7 -383
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +6 -55
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -32
- package/dist/config.js.map +1 -1
- package/dist/publish.d.ts +0 -10
- package/dist/publish.d.ts.map +1 -1
- package/dist/publish.js +6 -52
- package/dist/publish.js.map +1 -1
- package/dist/types.d.ts +1 -21
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -2
- package/dist/auth.d.ts +0 -68
- package/dist/auth.d.ts.map +0 -1
- package/dist/auth.js +0 -285
- package/dist/auth.js.map +0 -1
- package/dist/doctor.d.ts +0 -115
- package/dist/doctor.d.ts.map +0 -1
- package/dist/doctor.js +0 -292
- package/dist/doctor.js.map +0 -1
- package/dist/keyring.d.ts +0 -35
- package/dist/keyring.d.ts.map +0 -1
- package/dist/keyring.js +0 -88
- package/dist/keyring.js.map +0 -1
- package/dist/oidc-policy.d.ts +0 -145
- package/dist/oidc-policy.d.ts.map +0 -1
- package/dist/oidc-policy.js +0 -388
- package/dist/oidc-policy.js.map +0 -1
- package/dist/preflight-run.d.ts +0 -47
- package/dist/preflight-run.d.ts.map +0 -1
- package/dist/preflight-run.js +0 -197
- package/dist/preflight-run.js.map +0 -1
- package/dist/registries/crates-trust.d.ts +0 -69
- package/dist/registries/crates-trust.d.ts.map +0 -1
- package/dist/registries/crates-trust.js +0 -95
- package/dist/registries/crates-trust.js.map +0 -1
- package/dist/release.d.ts +0 -36
- package/dist/release.d.ts.map +0 -1
- package/dist/release.js +0 -102
- package/dist/release.js.map +0 -1
- package/dist/token-scope.d.ts +0 -65
- package/dist/token-scope.d.ts.map +0 -1
- package/dist/token-scope.js +0 -163
- package/dist/token-scope.js.map +0 -1
- package/dist/token.d.ts +0 -211
- package/dist/token.d.ts.map +0 -1
- package/dist/token.js +0 -719
- package/dist/token.js.map +0 -1
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* crates.io trusted-publishing read API.
|
|
3
|
-
*
|
|
4
|
-
* Issue #189. crates.io exposes `GET /api/v1/trusted_publishing/github_configs?crate=<name>`
|
|
5
|
-
* that returns each registered GitHub trust-policy config — enough to
|
|
6
|
-
* diff against a local `[package.trust_policy]` declaration and catch
|
|
7
|
-
* the `release.yml → patch-release.yml` rename landmine before it
|
|
8
|
-
* breaks a live publish.
|
|
9
|
-
*
|
|
10
|
-
* PyPI and npm do NOT have a usable read API from CI: PyPI has no
|
|
11
|
-
* current-policy endpoint (only past provenance via PEP 740), and
|
|
12
|
-
* npm's equivalent requires 2FA/OTP on every call and rejects
|
|
13
|
-
* bypass-2FA tokens. See `docs/guide/auth.md` for the full matrix.
|
|
14
|
-
*/
|
|
15
|
-
/** One `GitHubConfig` entry from crates.io's trust-policy API. */
|
|
16
|
-
export interface CratesGithubConfig {
|
|
17
|
-
id: number;
|
|
18
|
-
repository_owner: string;
|
|
19
|
-
repository_name: string;
|
|
20
|
-
workflow_filename: string;
|
|
21
|
-
environment: string | null;
|
|
22
|
-
}
|
|
23
|
-
export type CratesTrustFetchResult = {
|
|
24
|
-
kind: 'ok';
|
|
25
|
-
configs: CratesGithubConfig[];
|
|
26
|
-
}
|
|
27
|
-
/** Transient failure — timeout, network error, or 5xx. Neutral-skip in doctor. */
|
|
28
|
-
| {
|
|
29
|
-
kind: 'skip-transient';
|
|
30
|
-
reason: string;
|
|
31
|
-
}
|
|
32
|
-
/** Token rejected (401). Fails the phase; user must fix the token. */
|
|
33
|
-
| {
|
|
34
|
-
kind: 'auth-failed';
|
|
35
|
-
reason: string;
|
|
36
|
-
};
|
|
37
|
-
export interface FetchOptions {
|
|
38
|
-
/** Override for tests; defaults to `API_BASE`. */
|
|
39
|
-
apiBase?: string;
|
|
40
|
-
/** Override for tests; defaults to `AbortSignal.timeout(5000)`. */
|
|
41
|
-
signal?: AbortSignal;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Fetches the crates.io trust-policy configs for a crate. Wraps the
|
|
45
|
-
* network call in a 5s timeout; transient failures (timeout, 5xx,
|
|
46
|
-
* network error) return `skip-transient` so `doctor` doesn't turn red
|
|
47
|
-
* because crates.io is having a bad minute. A 401 returns
|
|
48
|
-
* `auth-failed` — the token is the user's responsibility to fix.
|
|
49
|
-
*/
|
|
50
|
-
export declare function fetchCratesTrustPolicy(crate: string, token: string, opts?: FetchOptions): Promise<CratesTrustFetchResult>;
|
|
51
|
-
/** Issue emitted when a declared trust policy disagrees with crates.io. */
|
|
52
|
-
export interface CratesTrustMismatch {
|
|
53
|
-
crate: string;
|
|
54
|
-
field: 'workflow_filename' | 'environment' | 'repository';
|
|
55
|
-
declared: string;
|
|
56
|
-
registered: string | null;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Compare a `[package.trust_policy]` declaration against each registered
|
|
60
|
-
* crates.io config for the same crate. Returns one mismatch per field
|
|
61
|
-
* per config; empty when every field agrees across every registered
|
|
62
|
-
* config.
|
|
63
|
-
*/
|
|
64
|
-
export declare function diffCratesTrust(crate: string, declared: {
|
|
65
|
-
workflow: string;
|
|
66
|
-
environment?: string | undefined;
|
|
67
|
-
repository?: string | undefined;
|
|
68
|
-
}, configs: readonly CratesGithubConfig[]): CratesTrustMismatch[];
|
|
69
|
-
//# sourceMappingURL=crates-trust.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"crates-trust.d.ts","sourceRoot":"","sources":["../../src/registries/crates-trust.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,kEAAkE;AAClE,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,MAAM,sBAAsB,GAC9B;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,kBAAkB,EAAE,CAAA;CAAE;AAC/C,kFAAkF;GAChF;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAC5C,sEAAsE;GACpE;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5C,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,sBAAsB,CAAC,CA8BjC;AAED,2EAA2E;AAC3E,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,mBAAmB,GAAG,aAAa,GAAG,YAAY,CAAC;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,EACjG,OAAO,EAAE,SAAS,kBAAkB,EAAE,GACrC,mBAAmB,EAAE,CAgCvB"}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* crates.io trusted-publishing read API.
|
|
3
|
-
*
|
|
4
|
-
* Issue #189. crates.io exposes `GET /api/v1/trusted_publishing/github_configs?crate=<name>`
|
|
5
|
-
* that returns each registered GitHub trust-policy config — enough to
|
|
6
|
-
* diff against a local `[package.trust_policy]` declaration and catch
|
|
7
|
-
* the `release.yml → patch-release.yml` rename landmine before it
|
|
8
|
-
* breaks a live publish.
|
|
9
|
-
*
|
|
10
|
-
* PyPI and npm do NOT have a usable read API from CI: PyPI has no
|
|
11
|
-
* current-policy endpoint (only past provenance via PEP 740), and
|
|
12
|
-
* npm's equivalent requires 2FA/OTP on every call and rejects
|
|
13
|
-
* bypass-2FA tokens. See `docs/guide/auth.md` for the full matrix.
|
|
14
|
-
*/
|
|
15
|
-
import { USER_AGENT } from '../version.js';
|
|
16
|
-
const API_BASE = 'https://crates.io';
|
|
17
|
-
/**
|
|
18
|
-
* Fetches the crates.io trust-policy configs for a crate. Wraps the
|
|
19
|
-
* network call in a 5s timeout; transient failures (timeout, 5xx,
|
|
20
|
-
* network error) return `skip-transient` so `doctor` doesn't turn red
|
|
21
|
-
* because crates.io is having a bad minute. A 401 returns
|
|
22
|
-
* `auth-failed` — the token is the user's responsibility to fix.
|
|
23
|
-
*/
|
|
24
|
-
export async function fetchCratesTrustPolicy(crate, token, opts = {}) {
|
|
25
|
-
const base = opts.apiBase ?? API_BASE;
|
|
26
|
-
const url = `${base}/api/v1/trusted_publishing/github_configs?crate=${encodeURIComponent(crate)}`;
|
|
27
|
-
const signal = opts.signal ?? AbortSignal.timeout(5000);
|
|
28
|
-
let res;
|
|
29
|
-
try {
|
|
30
|
-
res = await fetch(url, {
|
|
31
|
-
method: 'GET',
|
|
32
|
-
headers: {
|
|
33
|
-
'user-agent': USER_AGENT,
|
|
34
|
-
authorization: `Bearer ${token}`,
|
|
35
|
-
},
|
|
36
|
-
signal,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
catch (err) {
|
|
40
|
-
/* v8 ignore next -- fetch always throws an Error; the String(err) fallback is defensive */
|
|
41
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
42
|
-
return { kind: 'skip-transient', reason: message };
|
|
43
|
-
}
|
|
44
|
-
if (res.status === 401) {
|
|
45
|
-
return { kind: 'auth-failed', reason: 'crates.io rejected CRATES_IO_DOCTOR_TOKEN (401)' };
|
|
46
|
-
}
|
|
47
|
-
if (res.status >= 500) {
|
|
48
|
-
return { kind: 'skip-transient', reason: `crates.io returned HTTP ${res.status}` };
|
|
49
|
-
}
|
|
50
|
-
if (res.status !== 200) {
|
|
51
|
-
return { kind: 'skip-transient', reason: `crates.io returned unexpected HTTP ${res.status}` };
|
|
52
|
-
}
|
|
53
|
-
const body = (await res.json());
|
|
54
|
-
return { kind: 'ok', configs: body.github_configs ?? [] };
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Compare a `[package.trust_policy]` declaration against each registered
|
|
58
|
-
* crates.io config for the same crate. Returns one mismatch per field
|
|
59
|
-
* per config; empty when every field agrees across every registered
|
|
60
|
-
* config.
|
|
61
|
-
*/
|
|
62
|
-
export function diffCratesTrust(crate, declared, configs) {
|
|
63
|
-
const out = [];
|
|
64
|
-
for (const cfg of configs) {
|
|
65
|
-
if (cfg.workflow_filename !== declared.workflow) {
|
|
66
|
-
out.push({
|
|
67
|
-
crate,
|
|
68
|
-
field: 'workflow_filename',
|
|
69
|
-
declared: declared.workflow,
|
|
70
|
-
registered: cfg.workflow_filename,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
if (declared.environment !== undefined && cfg.environment !== declared.environment) {
|
|
74
|
-
out.push({
|
|
75
|
-
crate,
|
|
76
|
-
field: 'environment',
|
|
77
|
-
declared: declared.environment,
|
|
78
|
-
registered: cfg.environment,
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
if (declared.repository !== undefined) {
|
|
82
|
-
const registeredRepo = `${cfg.repository_owner}/${cfg.repository_name}`;
|
|
83
|
-
if (registeredRepo !== declared.repository) {
|
|
84
|
-
out.push({
|
|
85
|
-
crate,
|
|
86
|
-
field: 'repository',
|
|
87
|
-
declared: declared.repository,
|
|
88
|
-
registered: registeredRepo,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return out;
|
|
94
|
-
}
|
|
95
|
-
//# sourceMappingURL=crates-trust.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"crates-trust.js","sourceRoot":"","sources":["../../src/registries/crates-trust.ts"],"names":[],"mappings":"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"}
|
package/dist/release.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GitHub Release creation.
|
|
3
|
-
*
|
|
4
|
-
* After a successful tag push (§13.6), create a Release on GitHub so
|
|
5
|
-
* the new version shows up in the repo's Releases UI with body notes
|
|
6
|
-
* generated from the commit history since the previous tag.
|
|
7
|
-
*
|
|
8
|
-
* No external action dependency -- uses the GitHub REST API via
|
|
9
|
-
* fetch with the caller-supplied GITHUB_TOKEN (or the default
|
|
10
|
-
* GITHUB_TOKEN available to every Actions run).
|
|
11
|
-
*
|
|
12
|
-
* Issue #26. Plan: §15.
|
|
13
|
-
*/
|
|
14
|
-
export interface CreateReleaseOptions {
|
|
15
|
-
tag: string;
|
|
16
|
-
title: string;
|
|
17
|
-
body: string;
|
|
18
|
-
/** Override for tests. Defaults to global fetch. */
|
|
19
|
-
fetchFn?: typeof fetch;
|
|
20
|
-
}
|
|
21
|
-
export interface ReleaseResult {
|
|
22
|
-
url: string;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Generate release notes from `git log <prev_tag>..<this_tag>` subject
|
|
26
|
-
* lines. If no prior tag exists for this package, falls back to the
|
|
27
|
-
* full history (first release).
|
|
28
|
-
*
|
|
29
|
-
* The filter is subject-only -- commit bodies add noise and are
|
|
30
|
-
* already available on the tag itself.
|
|
31
|
-
*/
|
|
32
|
-
export declare function generateReleaseNotes(packageName: string, tagName: string, opts: {
|
|
33
|
-
cwd: string;
|
|
34
|
-
}): string;
|
|
35
|
-
export declare function createGitHubRelease(opts: CreateReleaseOptions): Promise<ReleaseResult | null>;
|
|
36
|
-
//# sourceMappingURL=release.d.ts.map
|
package/dist/release.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../src/release.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GACpB,MAAM,CAKR;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAiC/B"}
|
package/dist/release.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GitHub Release creation.
|
|
3
|
-
*
|
|
4
|
-
* After a successful tag push (§13.6), create a Release on GitHub so
|
|
5
|
-
* the new version shows up in the repo's Releases UI with body notes
|
|
6
|
-
* generated from the commit history since the previous tag.
|
|
7
|
-
*
|
|
8
|
-
* No external action dependency -- uses the GitHub REST API via
|
|
9
|
-
* fetch with the caller-supplied GITHUB_TOKEN (or the default
|
|
10
|
-
* GITHUB_TOKEN available to every Actions run).
|
|
11
|
-
*
|
|
12
|
-
* Issue #26. Plan: §15.
|
|
13
|
-
*/
|
|
14
|
-
import { execFileSync } from 'node:child_process';
|
|
15
|
-
/**
|
|
16
|
-
* Generate release notes from `git log <prev_tag>..<this_tag>` subject
|
|
17
|
-
* lines. If no prior tag exists for this package, falls back to the
|
|
18
|
-
* full history (first release).
|
|
19
|
-
*
|
|
20
|
-
* The filter is subject-only -- commit bodies add noise and are
|
|
21
|
-
* already available on the tag itself.
|
|
22
|
-
*/
|
|
23
|
-
export function generateReleaseNotes(packageName, tagName, opts) {
|
|
24
|
-
const prev = findPreviousTag(packageName, tagName, opts.cwd);
|
|
25
|
-
const range = prev ? `${prev}..${tagName}` : tagName;
|
|
26
|
-
const out = runGit(['log', range, '--format=- %s', '--no-merges'], opts.cwd);
|
|
27
|
-
return out.trim();
|
|
28
|
-
}
|
|
29
|
-
export async function createGitHubRelease(opts) {
|
|
30
|
-
const token = process.env.GITHUB_TOKEN;
|
|
31
|
-
const repository = process.env.GITHUB_REPOSITORY;
|
|
32
|
-
if (!token || !repository) {
|
|
33
|
-
// Local runs (putitoutthere doctor, operator on laptop) don't have
|
|
34
|
-
// these. Silent-skip so we don't confuse operators with a failure
|
|
35
|
-
// that doesn't matter outside Actions.
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
const fetchFn = opts.fetchFn ?? fetch;
|
|
39
|
-
const url = `https://api.github.com/repos/${repository}/releases`;
|
|
40
|
-
const res = await fetchFn(url, {
|
|
41
|
-
method: 'POST',
|
|
42
|
-
headers: {
|
|
43
|
-
authorization: `Bearer ${token}`,
|
|
44
|
-
'content-type': 'application/json',
|
|
45
|
-
accept: 'application/vnd.github+json',
|
|
46
|
-
'user-agent': 'putitoutthere',
|
|
47
|
-
},
|
|
48
|
-
body: JSON.stringify({
|
|
49
|
-
tag_name: opts.tag,
|
|
50
|
-
name: opts.title,
|
|
51
|
-
body: opts.body,
|
|
52
|
-
draft: false,
|
|
53
|
-
prerelease: isPrerelease(opts.tag),
|
|
54
|
-
}),
|
|
55
|
-
});
|
|
56
|
-
if (!res.ok) {
|
|
57
|
-
const msg = await res.text().catch(() => '');
|
|
58
|
-
throw new Error(`GitHub release API ${res.status}: ${msg}`);
|
|
59
|
-
}
|
|
60
|
-
const data = (await res.json());
|
|
61
|
-
return { url: data.html_url ?? '' };
|
|
62
|
-
}
|
|
63
|
-
/* ------------------------------ internals ------------------------------ */
|
|
64
|
-
function isPrerelease(tag) {
|
|
65
|
-
return /-(rc|beta|alpha)(\.|$)/.test(tag);
|
|
66
|
-
}
|
|
67
|
-
function runGit(args, cwd) {
|
|
68
|
-
try {
|
|
69
|
-
return execFileSync('git', args, { cwd, encoding: 'utf8' });
|
|
70
|
-
/* v8 ignore start -- defensive wrap */
|
|
71
|
-
}
|
|
72
|
-
catch (err) {
|
|
73
|
-
const stderr = err.stderr?.toString('utf8') ?? '';
|
|
74
|
-
throw new Error(`git ${args.join(' ')} failed: ${stderr.trim()}`, { cause: err });
|
|
75
|
-
}
|
|
76
|
-
/* v8 ignore stop */
|
|
77
|
-
}
|
|
78
|
-
function findPreviousTag(packageName, currentTag, cwd) {
|
|
79
|
-
const prefix = `${packageName}-v`;
|
|
80
|
-
const tags = runGit(['tag', '-l', `${prefix}*.*.*`], cwd)
|
|
81
|
-
.split('\n')
|
|
82
|
-
.filter((t) => t && t !== currentTag)
|
|
83
|
-
.sort(compareSemverTags(prefix));
|
|
84
|
-
return tags.length > 0 ? tags[tags.length - 1] : null;
|
|
85
|
-
}
|
|
86
|
-
function compareSemverTags(prefix) {
|
|
87
|
-
return (a, b) => {
|
|
88
|
-
const [am, an, ap] = parseVer(a.slice(prefix.length));
|
|
89
|
-
const [bm, bn, bp] = parseVer(b.slice(prefix.length));
|
|
90
|
-
if (am !== bm)
|
|
91
|
-
return am - bm;
|
|
92
|
-
if (an !== bn)
|
|
93
|
-
return an - bn;
|
|
94
|
-
return ap - bp;
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
function parseVer(v) {
|
|
98
|
-
const parts = v.split('.').map((n) => parseInt(n, 10));
|
|
99
|
-
/* v8 ignore next -- tag-glob filter already enforces x.y.z shape */
|
|
100
|
-
return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];
|
|
101
|
-
}
|
|
102
|
-
//# sourceMappingURL=release.js.map
|
package/dist/release.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"release.js","sourceRoot":"","sources":["../src/release.ts"],"names":[],"mappings":"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"}
|
package/dist/token-scope.d.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Token scope checking — compares what a token is allowed to publish
|
|
3
|
-
* against what `putitoutthere.toml` says the package is.
|
|
4
|
-
*
|
|
5
|
-
* Runs as a deep extension of `doctor` (#110) and as an opt-in gate in
|
|
6
|
-
* `publish --preflight-check`. Per registry:
|
|
7
|
-
*
|
|
8
|
-
* - PyPI: project-name macaroon caveats. Full-scope tokens pass; any
|
|
9
|
-
* restriction list that excludes the package name is a hard
|
|
10
|
-
* mismatch.
|
|
11
|
-
* - npm: granular `pkg:<name>` scopes on the matched tokens row. A
|
|
12
|
-
* bare `@scope` grant still counts when the package name lives
|
|
13
|
-
* under that scope. Legacy (non-granular) tokens are treated as
|
|
14
|
-
* full-scope (`match: 'ok'`, note surfaced).
|
|
15
|
-
* - crates.io: the bearer row is not identifiable, so we can never
|
|
16
|
-
* prove mismatch. Always `match: 'unknown'` — callers that need a
|
|
17
|
-
* block/warn decision should treat `unknown` as warn-only.
|
|
18
|
-
*
|
|
19
|
-
* Never logs or returns token values. Digests are threaded through from
|
|
20
|
-
* `inspect` for traceability.
|
|
21
|
-
*/
|
|
22
|
-
import type { InspectOptions, InspectResult } from './token.js';
|
|
23
|
-
import type { Package } from './config.js';
|
|
24
|
-
import type { Kind } from './types.js';
|
|
25
|
-
export type ScopeMatch = 'ok' | 'mismatch' | 'unknown' | 'error';
|
|
26
|
-
export interface DeepCheckRow {
|
|
27
|
-
package: string;
|
|
28
|
-
kind: Kind;
|
|
29
|
-
scope: string;
|
|
30
|
-
match: ScopeMatch;
|
|
31
|
-
/** Populated on mismatch or error; omitted when `ok` / `unknown`. */
|
|
32
|
-
detail?: string;
|
|
33
|
-
}
|
|
34
|
-
export type InspectFn = (opts: InspectOptions) => Promise<InspectResult>;
|
|
35
|
-
/**
|
|
36
|
-
* Registry-facing publish name. Handlers use the override field when
|
|
37
|
-
* present; we mirror that so the scope check talks about the same name
|
|
38
|
-
* the upload will use.
|
|
39
|
-
*/
|
|
40
|
-
export declare function publishNameFor(pkg: Package): string;
|
|
41
|
-
export interface ScopeFromResult {
|
|
42
|
-
scope: string;
|
|
43
|
-
match: ScopeMatch;
|
|
44
|
-
detail?: string;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Translate an `InspectResult` + the package it's meant to publish into
|
|
48
|
-
* a scope display + match verdict. Pure; never hits the network.
|
|
49
|
-
*/
|
|
50
|
-
export declare function scopeFromInspect(result: InspectResult, pkg: Package): ScopeFromResult;
|
|
51
|
-
export interface DeepCheckOptions {
|
|
52
|
-
packages: readonly Package[];
|
|
53
|
-
/** envVar-per-package mapping, as computed by preflight.checkAuth. */
|
|
54
|
-
envVarForPackage: Map<string, string>;
|
|
55
|
-
env?: NodeJS.ProcessEnv;
|
|
56
|
-
/** Override for tests; defaults to the real `inspect`. */
|
|
57
|
-
inspect?: InspectFn;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Call `inspect` for every package that has a resolvable token in the
|
|
61
|
-
* env, and return one `DeepCheckRow` per package. Packages whose env
|
|
62
|
-
* var is absent or empty are emitted with `match: 'error'`.
|
|
63
|
-
*/
|
|
64
|
-
export declare function deepCheck(opts: DeepCheckOptions): Promise<DeepCheckRow[]>;
|
|
65
|
-
//# sourceMappingURL=token-scope.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"token-scope.d.ts","sourceRoot":"","sources":["../src/token-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAGd,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC;AAEjE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,UAAU,CAAC;IAClB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;AAEzE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAInD;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,GAAG,eAAe,CASrF;AAyFD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7B,sEAAsE;IACtE,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA6B/E"}
|
package/dist/token-scope.js
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Token scope checking — compares what a token is allowed to publish
|
|
3
|
-
* against what `putitoutthere.toml` says the package is.
|
|
4
|
-
*
|
|
5
|
-
* Runs as a deep extension of `doctor` (#110) and as an opt-in gate in
|
|
6
|
-
* `publish --preflight-check`. Per registry:
|
|
7
|
-
*
|
|
8
|
-
* - PyPI: project-name macaroon caveats. Full-scope tokens pass; any
|
|
9
|
-
* restriction list that excludes the package name is a hard
|
|
10
|
-
* mismatch.
|
|
11
|
-
* - npm: granular `pkg:<name>` scopes on the matched tokens row. A
|
|
12
|
-
* bare `@scope` grant still counts when the package name lives
|
|
13
|
-
* under that scope. Legacy (non-granular) tokens are treated as
|
|
14
|
-
* full-scope (`match: 'ok'`, note surfaced).
|
|
15
|
-
* - crates.io: the bearer row is not identifiable, so we can never
|
|
16
|
-
* prove mismatch. Always `match: 'unknown'` — callers that need a
|
|
17
|
-
* block/warn decision should treat `unknown` as warn-only.
|
|
18
|
-
*
|
|
19
|
-
* Never logs or returns token values. Digests are threaded through from
|
|
20
|
-
* `inspect` for traceability.
|
|
21
|
-
*/
|
|
22
|
-
import { inspect as realInspect, isError } from './token.js';
|
|
23
|
-
/**
|
|
24
|
-
* Registry-facing publish name. Handlers use the override field when
|
|
25
|
-
* present; we mirror that so the scope check talks about the same name
|
|
26
|
-
* the upload will use.
|
|
27
|
-
*/
|
|
28
|
-
export function publishNameFor(pkg) {
|
|
29
|
-
if (pkg.kind === 'pypi')
|
|
30
|
-
return pkg.pypi ?? pkg.name;
|
|
31
|
-
if (pkg.kind === 'npm')
|
|
32
|
-
return pkg.npm ?? pkg.name;
|
|
33
|
-
return pkg.crate ?? pkg.name;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Translate an `InspectResult` + the package it's meant to publish into
|
|
37
|
-
* a scope display + match verdict. Pure; never hits the network.
|
|
38
|
-
*/
|
|
39
|
-
export function scopeFromInspect(result, pkg) {
|
|
40
|
-
if (isError(result)) {
|
|
41
|
-
return { scope: '(inspect failed)', match: 'error', detail: result.error };
|
|
42
|
-
}
|
|
43
|
-
if (result.registry === 'pypi')
|
|
44
|
-
return scopeFromPypi(result, pkg);
|
|
45
|
-
if (result.registry === 'npm')
|
|
46
|
-
return scopeFromNpm(result, pkg);
|
|
47
|
-
// crates.io: we can't prove mismatch.
|
|
48
|
-
return { scope: 'unknown (see account tokens)', match: 'unknown' };
|
|
49
|
-
}
|
|
50
|
-
function scopeFromPypi(result, pkg) {
|
|
51
|
-
const allowed = collectPypiProjectNames(result);
|
|
52
|
-
if (allowed === null) {
|
|
53
|
-
return { scope: '(full-scope)', match: 'ok' };
|
|
54
|
-
}
|
|
55
|
-
const want = publishNameFor(pkg);
|
|
56
|
-
if (allowed.includes(want)) {
|
|
57
|
-
return { scope: `projects=[${allowed.join(', ')}]`, match: 'ok' };
|
|
58
|
-
}
|
|
59
|
-
return {
|
|
60
|
-
scope: `projects=[${allowed.join(', ')}]`,
|
|
61
|
-
match: 'mismatch',
|
|
62
|
-
detail: `PyPI token restricted to [${allowed.join(', ')}] but config publishes '${want}'`,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
function collectPypiProjectNames(result) {
|
|
66
|
-
const names = [];
|
|
67
|
-
let sawProjectRestriction = false;
|
|
68
|
-
for (const r of result.restrictions) {
|
|
69
|
-
if (r.type === 'ProjectNames') {
|
|
70
|
-
sawProjectRestriction = true;
|
|
71
|
-
for (const n of r.names)
|
|
72
|
-
names.push(n);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return sawProjectRestriction ? dedupe(names) : null;
|
|
76
|
-
}
|
|
77
|
-
function scopeFromNpm(result, pkg) {
|
|
78
|
-
const want = publishNameFor(pkg);
|
|
79
|
-
const row = result.scope_row;
|
|
80
|
-
if (row === null) {
|
|
81
|
-
// Legacy UUID or non-granular token: we can't introspect scope.
|
|
82
|
-
// Treat as full-scope ok; doctor will still flag via note.
|
|
83
|
-
return { scope: `(${result.format}; no scope row)`, match: 'ok' };
|
|
84
|
-
}
|
|
85
|
-
const allowedPkgs = row.packages ?? [];
|
|
86
|
-
const allowedScopes = (row.scopes ?? []).map((s) => (s.startsWith('@') ? s : `@${s}`));
|
|
87
|
-
const allowedOrgs = row.orgs ?? [];
|
|
88
|
-
const noRestrictions = allowedPkgs.length === 0 && allowedScopes.length === 0 && allowedOrgs.length === 0;
|
|
89
|
-
if (noRestrictions) {
|
|
90
|
-
return { scope: '(account-wide)', match: 'ok' };
|
|
91
|
-
}
|
|
92
|
-
if (allowedPkgs.includes(want)) {
|
|
93
|
-
return { scope: renderNpmScope(row), match: 'ok' };
|
|
94
|
-
}
|
|
95
|
-
const atScope = scopeOf(want);
|
|
96
|
-
if (atScope !== null && allowedScopes.includes(atScope)) {
|
|
97
|
-
return { scope: renderNpmScope(row), match: 'ok' };
|
|
98
|
-
}
|
|
99
|
-
// Orgs aren't a pre-publish allowlist at the name level (npm doesn't
|
|
100
|
-
// bind "org:foo" to a package name directly), so we don't use them to
|
|
101
|
-
// prove a match. We still render them for visibility.
|
|
102
|
-
return {
|
|
103
|
-
scope: renderNpmScope(row),
|
|
104
|
-
match: 'mismatch',
|
|
105
|
-
detail: `npm token allowlist [${[...allowedPkgs, ...allowedScopes].join(', ')}] does not include '${want}'`,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
function renderNpmScope(row) {
|
|
109
|
-
const parts = [];
|
|
110
|
-
if (row.packages && row.packages.length > 0)
|
|
111
|
-
parts.push(`pkgs=[${row.packages.join(', ')}]`);
|
|
112
|
-
if (row.scopes && row.scopes.length > 0)
|
|
113
|
-
parts.push(`scopes=[${row.scopes.join(', ')}]`);
|
|
114
|
-
if (row.orgs && row.orgs.length > 0)
|
|
115
|
-
parts.push(`orgs=[${row.orgs.join(', ')}]`);
|
|
116
|
-
/* v8 ignore next -- caller only invokes this when at least one list is populated */
|
|
117
|
-
return parts.length === 0 ? '(empty)' : parts.join(' ');
|
|
118
|
-
}
|
|
119
|
-
function scopeOf(name) {
|
|
120
|
-
if (!name.startsWith('@'))
|
|
121
|
-
return null;
|
|
122
|
-
const slash = name.indexOf('/');
|
|
123
|
-
/* v8 ignore next -- scoped npm names always carry a slash separator */
|
|
124
|
-
return slash === -1 ? null : name.slice(0, slash);
|
|
125
|
-
}
|
|
126
|
-
function dedupe(arr) {
|
|
127
|
-
return Array.from(new Set(arr));
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Call `inspect` for every package that has a resolvable token in the
|
|
131
|
-
* env, and return one `DeepCheckRow` per package. Packages whose env
|
|
132
|
-
* var is absent or empty are emitted with `match: 'error'`.
|
|
133
|
-
*/
|
|
134
|
-
export async function deepCheck(opts) {
|
|
135
|
-
const env = opts.env ?? process.env;
|
|
136
|
-
const inspectFn = opts.inspect ?? realInspect;
|
|
137
|
-
const rows = [];
|
|
138
|
-
for (const pkg of opts.packages) {
|
|
139
|
-
const envVar = opts.envVarForPackage.get(pkg.name);
|
|
140
|
-
const tokenValue = envVar !== undefined ? env[envVar] : undefined;
|
|
141
|
-
if (tokenValue === undefined || tokenValue.trim() === '') {
|
|
142
|
-
rows.push({
|
|
143
|
-
package: pkg.name,
|
|
144
|
-
kind: pkg.kind,
|
|
145
|
-
scope: '(no token resolved)',
|
|
146
|
-
match: 'error',
|
|
147
|
-
detail: `no token value found in ${envVar ?? '<unknown env var>'}`,
|
|
148
|
-
});
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
const result = await inspectFn({ token: tokenValue, registry: pkg.kind });
|
|
152
|
-
const verdict = scopeFromInspect(result, pkg);
|
|
153
|
-
rows.push({
|
|
154
|
-
package: pkg.name,
|
|
155
|
-
kind: pkg.kind,
|
|
156
|
-
scope: verdict.scope,
|
|
157
|
-
match: verdict.match,
|
|
158
|
-
...(verdict.detail !== undefined ? { detail: verdict.detail } : {}),
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
return rows;
|
|
162
|
-
}
|
|
163
|
-
//# sourceMappingURL=token-scope.js.map
|
package/dist/token-scope.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"token-scope.js","sourceRoot":"","sources":["../src/token-scope.ts"],"names":[],"mappings":"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"}
|