@faable/auth-sdk 2.6.1 → 2.6.3
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.
|
@@ -31,3 +31,8 @@ jobs:
|
|
|
31
31
|
- run: npm run release
|
|
32
32
|
env:
|
|
33
33
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
34
|
+
# Proves the RESULT: downloads what was just published and fails if the
|
|
35
|
+
# sentinels survived. test:pack checks they are present before the
|
|
36
|
+
# release; only this catches something rebuilding dist/ in between —
|
|
37
|
+
# which is exactly how 2.6.0 shipped as `auth-sdk/0.0.0-dev`.
|
|
38
|
+
- run: npm run verify:published
|
package/dist/version.js
CHANGED
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
// login pages could not import the SDK at all. Same pattern as auth-js.
|
|
10
10
|
//
|
|
11
11
|
// The sentinels MUST stay byte-identical to the `from` values in `.releaserc`.
|
|
12
|
-
export const version = "
|
|
12
|
+
export const version = "2.6.3";
|
|
13
13
|
// Short git SHA of the released commit. The version dates a build; this names
|
|
14
14
|
// the exact tree, so a canonical log line or an audit entry leads straight to
|
|
15
15
|
// `git show <sha>`. Deliberately NOT hex: an unreleased build (dev, a local
|
|
16
16
|
// link) cannot be mistaken for a real commit — auth only records values that
|
|
17
17
|
// look like a SHA, and this one never will.
|
|
18
|
-
export const commit = "
|
|
18
|
+
export const commit = "d9f3c35";
|
|
19
19
|
// What this SDK writes in `x-faable-client`. Exported for a consumer that
|
|
20
20
|
// builds a strategy on its own (outside `FaableAuthApi`) and still wants the
|
|
21
21
|
// token request attributed — a bare `authClientCredentials` stamps only what
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faable/auth-sdk",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.3",
|
|
4
4
|
"author": "Marc Pomar <marc@faable.com>",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"gentypes": "openapi-typescript ${AUTH_OPENAPI:-spec/openapi.json} -o src/api/types.ts && node scripts/gen-client.mjs",
|
|
31
31
|
"build": "rimraf dist && tsc",
|
|
32
32
|
"prebuild": "npm run gentypes",
|
|
33
|
-
"prepublishOnly": "npm run build",
|
|
34
33
|
"test": "ava",
|
|
35
34
|
"release": "semantic-release",
|
|
36
|
-
"test:pack": "node tests/pack/verify-pack.mjs"
|
|
35
|
+
"test:pack": "node tests/pack/verify-pack.mjs",
|
|
36
|
+
"verify:published": "node tests/pack/verify-published.mjs"
|
|
37
37
|
},
|
|
38
38
|
"resolutions": {
|
|
39
39
|
"npm/chalk": "^4.1.2"
|
|
@@ -30,6 +30,7 @@ console.log("→ Building dist/");
|
|
|
30
30
|
run("npm run build", { cwd: ROOT });
|
|
31
31
|
|
|
32
32
|
// 1. Sentinels, verbatim, straight from .releaserc so the two cannot drift.
|
|
33
|
+
const pkgScripts = JSON.parse(readFileSync(join(ROOT, "package.json"), "utf8")).scripts ?? {};
|
|
33
34
|
const releaserc = JSON.parse(readFileSync(join(ROOT, ".releaserc"), "utf8"));
|
|
34
35
|
const replacePlugin = releaserc.plugins.find(
|
|
35
36
|
(p) => Array.isArray(p) && p[0] === "semantic-release-replace-plugin",
|
|
@@ -43,6 +44,23 @@ for (const { from } of replacePlugin[1].replacements) {
|
|
|
43
44
|
}
|
|
44
45
|
console.log("✓ sentinels present in dist/version.js");
|
|
45
46
|
|
|
47
|
+
// The sentinels being here is only half the story: anything that rebuilds
|
|
48
|
+
// dist/ AFTER semantic-release's replacement and BEFORE the upload undoes it.
|
|
49
|
+
// `npm pack` fires `prepack`, never `prepublishOnly`, so this guard cannot
|
|
50
|
+
// observe that hook — it refuses to let one exist instead. (2.6.0 shipped
|
|
51
|
+
// anonymous exactly this way.) The release workflow builds explicitly, so no
|
|
52
|
+
// publish-time rebuild hook is needed.
|
|
53
|
+
const REBUILD_HOOKS = ["prepublishOnly", "prepublish", "prepack", "prepare"];
|
|
54
|
+
const offending = REBUILD_HOOKS.filter((hook) => pkgScripts[hook]);
|
|
55
|
+
if (offending.length) {
|
|
56
|
+
fail(
|
|
57
|
+
`package.json defines ${offending.join(", ")} — npm runs these around publish, ` +
|
|
58
|
+
"and a rebuild there would overwrite the version semantic-release just injected. " +
|
|
59
|
+
"Build in the workflow instead.",
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
console.log("✓ no publish-time rebuild hook");
|
|
63
|
+
|
|
46
64
|
// 2. Browser-safety: no node: specifiers anywhere in the published JS.
|
|
47
65
|
const jsFiles = (dir) =>
|
|
48
66
|
readdirSync(dir, { withFileTypes: true }).flatMap((e) =>
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Post-publish guard: download the version that was just published and fail if
|
|
3
|
+
// it still carries the release sentinels.
|
|
4
|
+
//
|
|
5
|
+
// `verify-pack.mjs` checks the OPPOSITE — that the sentinels ARE in dist/, so
|
|
6
|
+
// the replacement has something to hit. Both are needed, and only this one
|
|
7
|
+
// proves the result: 2.6.0 shipped anonymous because `prepublishOnly` ran
|
|
8
|
+
// `rimraf dist && tsc` between the replacement and the upload, and `npm pack`
|
|
9
|
+
// (which the pre-publish guard uses) never fires that hook.
|
|
10
|
+
import { execSync } from "node:child_process";
|
|
11
|
+
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
import { join, resolve } from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
|
|
16
|
+
const ROOT = resolve(fileURLToPath(import.meta.url), "../../..");
|
|
17
|
+
const pkg = JSON.parse(readFileSync(join(ROOT, "package.json"), "utf8"));
|
|
18
|
+
const version = pkg.version;
|
|
19
|
+
|
|
20
|
+
// semantic-release writes the released version into package.json during
|
|
21
|
+
// `prepare`. Still the dev placeholder ⇒ no release was cut on this run.
|
|
22
|
+
if (version === "0.0.0-dev") {
|
|
23
|
+
console.log("→ No release cut on this run; nothing to verify.");
|
|
24
|
+
process.exit(0);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const sentinels = JSON.parse(readFileSync(join(ROOT, ".releaserc"), "utf8"))
|
|
28
|
+
.plugins.find((p) => Array.isArray(p) && p[0] === "semantic-release-replace-plugin")[1]
|
|
29
|
+
.replacements.map((r) => r.from);
|
|
30
|
+
|
|
31
|
+
// Ask the registry itself rather than `npm pack`: the packument is what
|
|
32
|
+
// propagates first, and npm's own cache on a runner can report a
|
|
33
|
+
// just-published version as missing for a while (2.6.2 was live and this
|
|
34
|
+
// guard still called it "never available"). Up to 5 minutes, because
|
|
35
|
+
// propagation is the only thing being waited on here.
|
|
36
|
+
const fetchTarballUrl = async () => {
|
|
37
|
+
const url = `https://registry.npmjs.org/${pkg.name.replace("/", "%2F")}`;
|
|
38
|
+
for (let attempt = 1; attempt <= 30; attempt++) {
|
|
39
|
+
try {
|
|
40
|
+
const res = await fetch(url, { headers: { "cache-control": "no-cache" } });
|
|
41
|
+
if (res.ok) {
|
|
42
|
+
const doc = await res.json();
|
|
43
|
+
const tarball = doc.versions?.[version]?.dist?.tarball;
|
|
44
|
+
if (tarball) return tarball;
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
// network blip — keep waiting
|
|
48
|
+
}
|
|
49
|
+
console.log(`→ ${pkg.name}@${version} not served yet (attempt ${attempt}/30)`);
|
|
50
|
+
await new Promise((r) => setTimeout(r, 10_000));
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const tmp = mkdtempSync(join(tmpdir(), "faable-auth-sdk-published-"));
|
|
56
|
+
try {
|
|
57
|
+
const tarballUrl = await fetchTarballUrl();
|
|
58
|
+
if (!tarballUrl) {
|
|
59
|
+
console.error(`✖ ${pkg.name}@${version} never became available on the registry`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
const tarball = "published.tgz";
|
|
63
|
+
execSync(`curl -sfL "${tarballUrl}" -o ${tarball}`, { cwd: tmp });
|
|
64
|
+
execSync(`tar xzf ${tarball}`, { cwd: tmp });
|
|
65
|
+
const published = readFileSync(join(tmp, "package/dist/version.js"), "utf8");
|
|
66
|
+
for (const sentinel of sentinels) {
|
|
67
|
+
if (published.includes(sentinel)) {
|
|
68
|
+
console.error(
|
|
69
|
+
`✖ ${pkg.name}@${version} was published with the sentinel "${sentinel}" intact — ` +
|
|
70
|
+
"every consumer will report as that. Something between the replacement and the " +
|
|
71
|
+
"upload rebuilt dist/ (a `prepublishOnly`/`prepack` hook is the usual culprit).",
|
|
72
|
+
);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (!published.includes(version)) {
|
|
77
|
+
console.error(`✖ ${pkg.name}@${version} does not carry its own version in dist/version.js`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
console.log(`✓ ${pkg.name}@${version} reports itself correctly on the wire`);
|
|
81
|
+
} finally {
|
|
82
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
83
|
+
}
|