package-registry-manager 0.23.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -1
- package/package.json +2 -2
- package/src/cli-main.mjs +15 -6
- package/src/crates-api.mjs +1 -1
- package/src/flows.mjs +2 -2
- package/src/setup.mjs +41 -2
package/CHANGELOG.md
CHANGED
|
@@ -24,9 +24,16 @@ currently shares its release version with the Rust implementation.
|
|
|
24
24
|
variables and secret, `packages: write`, and package linking (#5).
|
|
25
25
|
- `setup --browser default|automated` chooses where sign-in and approval URLs
|
|
26
26
|
open; `default`, the default, uses the user's default browser (#9).
|
|
27
|
+
- An npm first publish stops before the sign-in when the packed tarball
|
|
28
|
+
contains repository development directories such as `.github/` or `tests/`,
|
|
29
|
+
which a package.json without a `files` allowlist lets in.
|
|
27
30
|
|
|
28
31
|
### Changed
|
|
29
32
|
|
|
33
|
+
- `setup` stays signed in by default: the npm session token and the crates.io
|
|
34
|
+
sign-in in the automated profile are kept, so the next run (npm: within two
|
|
35
|
+
hours) skips the sign-in. `--sign-out` signs out at the end instead;
|
|
36
|
+
`--keep-session` is still accepted and is now the default.
|
|
30
37
|
- npm web-auth URLs (`npm login`, `npm publish` 2FA, `npm trust`) open in the
|
|
31
38
|
user's default browser (`open`, `xdg-open`, or the Windows URL handler),
|
|
32
39
|
where they are usually already signed in. The automated browser profile is
|
|
@@ -35,7 +42,7 @@ currently shares its release version with the Rust implementation.
|
|
|
35
42
|
outside any repository (`~/Library/Application Support` on macOS,
|
|
36
43
|
`$XDG_STATE_HOME` or `~/.local/state` on Linux, `%LOCALAPPDATA%` on Windows,
|
|
37
44
|
each followed by `package-registry-manager/browser-profile`) (#8).
|
|
38
|
-
- `browser-commander` is required at `^0.
|
|
45
|
+
- `browser-commander` is required at `^0.34.0`, its latest release (#28). A
|
|
39
46
|
launch still names its channel (`chrome` by default), so the upstream switch
|
|
40
47
|
of channel-less launches to Chrome for Testing does not change which browser
|
|
41
48
|
opens.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "package-registry-manager",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Inspect repositories and guide secure package-registry setup",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@link-foundation/gh-manager": "https://codeload.github.com/link-foundation/gh-manager/tar.gz/29808e088ac8fd8374361920bbebab07a4d63ac6",
|
|
44
|
-
"browser-commander": "^0.
|
|
44
|
+
"browser-commander": "^0.34.0",
|
|
45
45
|
"command-stream": "^2.4.0",
|
|
46
46
|
"playwright": "^1.63.0",
|
|
47
47
|
"selenium-webdriver": "^4.50.0"
|
package/src/cli-main.mjs
CHANGED
|
@@ -68,10 +68,12 @@ Setup options:
|
|
|
68
68
|
--manual crates.io: create, use, and revoke the
|
|
69
69
|
first-publish token by hand instead of
|
|
70
70
|
through the crates.io API
|
|
71
|
-
--
|
|
72
|
-
session
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
--sign-out Sign out at the end of setup: npm logout
|
|
72
|
+
for the npm session this run signed in, and
|
|
73
|
+
removal of the crates.io sign-in it brought
|
|
74
|
+
into the automated profile. Without it the
|
|
75
|
+
next run reuses both sessions; npm ends its
|
|
76
|
+
session token after two hours
|
|
75
77
|
--browser <default|automated> Open sign-in and approval pages in your
|
|
76
78
|
default browser, or in the automated profile;
|
|
77
79
|
npm reuses the automated profile
|
|
@@ -132,6 +134,7 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
132
134
|
yes: { type: "boolean", default: false },
|
|
133
135
|
"no-browser": { type: "boolean", default: false },
|
|
134
136
|
"open-with": { type: "string" },
|
|
137
|
+
"sign-out": { type: "boolean", default: false },
|
|
135
138
|
"keep-session": { type: "boolean", default: false },
|
|
136
139
|
manual: { type: "boolean", default: false },
|
|
137
140
|
browser: { type: "string", default: "default" },
|
|
@@ -249,6 +252,9 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
249
252
|
if (values["open-with"] !== undefined && values["no-browser"]) {
|
|
250
253
|
throw new Error("--open-with and --no-browser are mutually exclusive");
|
|
251
254
|
}
|
|
255
|
+
if (values["sign-out"] && values["keep-session"]) {
|
|
256
|
+
throw new Error("--sign-out and --keep-session are mutually exclusive");
|
|
257
|
+
}
|
|
252
258
|
if (!browserOptions.attach) {
|
|
253
259
|
browserOptions.import ??= { browser: "auto", profile: null };
|
|
254
260
|
}
|
|
@@ -276,7 +282,7 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
276
282
|
defaultBrowserProfile({ channel: browserOptions.channel }),
|
|
277
283
|
),
|
|
278
284
|
openWith: nonEmpty(values["open-with"], "--open-with"),
|
|
279
|
-
keepSession: values["
|
|
285
|
+
keepSession: !values["sign-out"],
|
|
280
286
|
planOptions: {
|
|
281
287
|
workflow: values.workflow,
|
|
282
288
|
publisherEnvironment: values.environment,
|
|
@@ -364,6 +370,9 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
364
370
|
if (values["open-with"] !== undefined && values["no-browser"]) {
|
|
365
371
|
throw new Error("--open-with and --no-browser are mutually exclusive");
|
|
366
372
|
}
|
|
373
|
+
if (values["sign-out"] && values["keep-session"]) {
|
|
374
|
+
throw new Error("--sign-out and --keep-session are mutually exclusive");
|
|
375
|
+
}
|
|
367
376
|
|
|
368
377
|
const plans = buildPlans(inspection, registries, planOptions);
|
|
369
378
|
const selected = values.all
|
|
@@ -381,7 +390,7 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
381
390
|
yes: values.yes,
|
|
382
391
|
noBrowser: values["no-browser"],
|
|
383
392
|
openWith: nonEmpty(values["open-with"], "--open-with"),
|
|
384
|
-
keepSession: values["
|
|
393
|
+
keepSession: !values["sign-out"],
|
|
385
394
|
secretName: values["secret-name"],
|
|
386
395
|
rotateToken,
|
|
387
396
|
migrate: values.migrate,
|
package/src/crates-api.mjs
CHANGED
|
@@ -407,7 +407,7 @@ export async function runCratesApiStep(session, step) {
|
|
|
407
407
|
case "crates-sign-out":
|
|
408
408
|
if (options.keepSession) {
|
|
409
409
|
console.log(
|
|
410
|
-
`Keeping the ${domains.join(" / ")} sign-in in the automated profile
|
|
410
|
+
`Keeping the ${domains.join(" / ")} sign-in in the automated profile; the next run reuses it. No token is kept.`,
|
|
411
411
|
);
|
|
412
412
|
} else if (page.clearCookies) {
|
|
413
413
|
await page.clearCookies(domains);
|
package/src/flows.mjs
CHANGED
|
@@ -477,7 +477,7 @@ export function npmFlow(packageInfo, context) {
|
|
|
477
477
|
"sign-out",
|
|
478
478
|
"Sign out of npm",
|
|
479
479
|
"command",
|
|
480
|
-
"
|
|
480
|
+
"With --sign-out, revoke the session token created by the web login now; otherwise the next run reuses it and npm ends it after two hours.",
|
|
481
481
|
{ command: command("npm", ["logout"]), when: "tool-signed-in" },
|
|
482
482
|
),
|
|
483
483
|
removeWorktreeStep(),
|
|
@@ -555,7 +555,7 @@ function apiCratesFlow(packageInfo, context) {
|
|
|
555
555
|
"crates-sign-out",
|
|
556
556
|
"Sign the automated browser out of crates.io",
|
|
557
557
|
"api",
|
|
558
|
-
"
|
|
558
|
+
"With --sign-out, remove the sign-in this run brought into the automated profile; otherwise the next run reuses it. No token outlives the run either way.",
|
|
559
559
|
{ when: "crates-signed-in" },
|
|
560
560
|
),
|
|
561
561
|
removeWorktreeStep(),
|
package/src/setup.mjs
CHANGED
|
@@ -107,14 +107,14 @@ export class SetupSession {
|
|
|
107
107
|
) {
|
|
108
108
|
if (step.id === "sign-out" && this.keepsSession(step)) {
|
|
109
109
|
console.log(
|
|
110
|
-
"Keeping the npm session for reuse;
|
|
110
|
+
"Keeping the npm session for reuse; npm ends it after two hours, npm logout sooner.",
|
|
111
111
|
);
|
|
112
112
|
} else {
|
|
113
113
|
deferred.push(step);
|
|
114
114
|
}
|
|
115
115
|
} else if (step.id === "sign-out" && this.keepsSession(step)) {
|
|
116
116
|
console.log(
|
|
117
|
-
"Keeping the npm session for reuse:
|
|
117
|
+
"Keeping the npm session for reuse: the next run within two hours skips the sign-in while npm whoami succeeds. npm ends the session token after two hours; npm logout ends it now.",
|
|
118
118
|
);
|
|
119
119
|
} else if (this.conditions.has(step.when) && step.kind === "api") {
|
|
120
120
|
this.log(`==> ${step.title}`);
|
|
@@ -608,6 +608,12 @@ export class SetupSession {
|
|
|
608
608
|
console.log(
|
|
609
609
|
` ${packed.filename}: ${packed.size} bytes packed, ${packed.unpackedSize} bytes unpacked, ${packed.entryCount} files`,
|
|
610
610
|
);
|
|
611
|
+
const development = developmentDirectories(packed);
|
|
612
|
+
if (development.length > 0) {
|
|
613
|
+
throw new Error(
|
|
614
|
+
`the package would publish repository development files (${development.join(", ")}); add a "files" allowlist to package.json, commit it to the published ref, and re-run. Nothing was published.`,
|
|
615
|
+
);
|
|
616
|
+
}
|
|
611
617
|
this.values.tarball = path.join(
|
|
612
618
|
this.values.pack_destination,
|
|
613
619
|
packed.filename,
|
|
@@ -882,6 +888,39 @@ export function packedEntry(output) {
|
|
|
882
888
|
return packed;
|
|
883
889
|
}
|
|
884
890
|
|
|
891
|
+
/**
|
|
892
|
+
* Top-level repository directories of development files: CI, tests, and
|
|
893
|
+
* editor and build state, which belong in no published package.
|
|
894
|
+
*/
|
|
895
|
+
const DEVELOPMENT_DIRECTORIES = new Set([
|
|
896
|
+
".changeset",
|
|
897
|
+
".github",
|
|
898
|
+
".husky",
|
|
899
|
+
".idea",
|
|
900
|
+
".vscode",
|
|
901
|
+
"__tests__",
|
|
902
|
+
"coverage",
|
|
903
|
+
"experiments",
|
|
904
|
+
"target",
|
|
905
|
+
"test",
|
|
906
|
+
"tests",
|
|
907
|
+
]);
|
|
908
|
+
|
|
909
|
+
/**
|
|
910
|
+
* The development directories a packed tarball contains, as `name/`, which
|
|
911
|
+
* a package.json without a `files` allowlist lets in.
|
|
912
|
+
*/
|
|
913
|
+
export function developmentDirectories(packed) {
|
|
914
|
+
const found = new Set();
|
|
915
|
+
for (const file of packed.files ?? []) {
|
|
916
|
+
const [top, ...rest] = String(file.path).split("/");
|
|
917
|
+
if (rest.length > 0 && DEVELOPMENT_DIRECTORIES.has(top)) {
|
|
918
|
+
found.add(`${top}/`);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
return [...found].sort();
|
|
922
|
+
}
|
|
923
|
+
|
|
885
924
|
function reportPackWarnings(stderr) {
|
|
886
925
|
const warnings = packWarnings(stderr);
|
|
887
926
|
if (warnings.length === 0) {
|