mirror of
https://github.com/pnpm/pnpm.git
synced 2026-06-28 09:55:39 -04:00
## What Implements the **auth half** of [#12199](https://github.com/pnpm/pnpm/issues/12199) (phase 3) — making pnpr's remaining per-instance state pluggable so the registry can run as stateless, horizontally-scaled replicas. ### Auth records behind config-selected backends Users + tokens now sit behind narrow async `UserBackend` / `TokenBackend` traits, built once at startup into `Arc<dyn …>` handles (the same build-once pattern #12198 used for the hosted store). Three implementations: - **Local** (default) — today's htpasswd file + SQLite token DB, or in-memory when no file is configured. Unchanged behavior. - **Networked SQLite (libsql / Turso)** — `LibsqlAuth` stores **both** records in one shared database, so several stateless replicas observe a consistent set of users and tokens. The `tokens` table DDL is shared verbatim with the local backend (a DB can migrate between them); users — which the local backend keeps in htpasswd — move into a `users` table. Selected via a new top-level YAML block: ```yaml backend: libsql: url: ${PNPR_LIBSQL_URL} authToken: ${PNPR_LIBSQL_TOKEN} # optional embedded replica for local-fast hot-path reads: replicaPath: ./auth-replica.db syncIntervalSecs: 60 ``` When the block is absent, auth stays on local disk exactly as before. ### Embedded-replica read acceleration Token lookups are on the request hot path, so against a remote primary every read would be a network round-trip. With `replicaPath` set, `LibsqlAuth` builds a libsql **embedded replica**: reads hit a local file that libsql keeps current in the background; writes go to the primary. `syncIntervalSecs` is the freshness knob that bounds token-revocation lag. ### Async access path `identify` / `enforce_access` are now async (a networked lookup is async). `enforce_access` is split into an async `resolve_identity` + a sync `authorize`, so the search endpoint resolves the caller once and authorizes each candidate synchronously (no async-in-`retain`). ### Concurrent-publish guard (cross-cutting follow-up from the issue) Closes the same-instance lost-update window in the three read-modify-write packument flows (publish, dist-tag change, partial-unpublish): a striped per-package lock serializes same-package writers on one instance while letting different packages proceed in parallel. The **cross-replica** half (S3 `If-Match` / ETag CAS) is documented in-code as the remaining piece — the issue files it under "fix when we get there," and it belongs with the multi-writer S3 publish work, not this auth branch. ## Tests All green — `cargo test -p pnpr`: - **176 lib unit tests** incl. new `LibsqlAuth` tests (run against an in-memory libsql DB — same driver + SQL, no server) and `backend.libsql` config-parsing tests (incl. the replica options). - New `concurrent_publishes_of_distinct_versions_all_survive` integration test for the publish guard. - Existing auth_persistence / auth_user_endpoints / auth_publish / server / s3_backend suites pass. - Clean under `cargo fmt`, `clippy`, `RUSTDOCFLAGS=-D warnings cargo doc`, **Dylint perfectionist**, and `taplo`. ## Docs `backend.libsql` (incl. embedded replica) documented in the bundled `config.yaml` and the `pnpr` npm README, mirroring how the S3 backend was documented in #12198.
403 lines
6.2 KiB
JSON
403 lines
6.2 KiB
JSON
{
|
|
"words": [
|
|
"adduser",
|
|
"adipiscing",
|
|
"agentkeepalive",
|
|
"agentkeepalive's",
|
|
"amet",
|
|
"andreineculau",
|
|
"appdata",
|
|
"applyq",
|
|
"archy",
|
|
"argumentless",
|
|
"armv",
|
|
"autocheckpoint",
|
|
"autocompleting",
|
|
"autofix",
|
|
"autofixed",
|
|
"autoinstalled",
|
|
"autozoom",
|
|
"babek",
|
|
"Backblaze",
|
|
"badheaders",
|
|
"behaviour",
|
|
"blabla",
|
|
"Bluesky",
|
|
"brasileiro",
|
|
"bryntum",
|
|
"buildx",
|
|
"cafile",
|
|
"cafs",
|
|
"camelcase",
|
|
"canonicalizer",
|
|
"cantopen",
|
|
"canva",
|
|
"cerbos",
|
|
"certfile",
|
|
"clonedeep",
|
|
"cmds",
|
|
"Codeberg",
|
|
"codeload",
|
|
"codenames",
|
|
"codesign",
|
|
"colorterm",
|
|
"comver",
|
|
"copyfiles",
|
|
"corejs",
|
|
"corepack",
|
|
"corge",
|
|
"cowsay",
|
|
"Creds",
|
|
"cryptiles",
|
|
"cves",
|
|
"cwsay",
|
|
"cyclonedx",
|
|
"deburr",
|
|
"dedup",
|
|
"denoland",
|
|
"denolib",
|
|
"deptype",
|
|
"desugared",
|
|
"desugars",
|
|
"devextreme",
|
|
"devowl",
|
|
"dgimuvys",
|
|
"didyoumean",
|
|
"dirtyforms",
|
|
"diskusage",
|
|
"dislink",
|
|
"dpkg",
|
|
"drivelist",
|
|
"duplexify",
|
|
"eagain",
|
|
"ebadplatform",
|
|
"ebusy",
|
|
"eexist",
|
|
"ehrkoext",
|
|
"eintegrity",
|
|
"eisdir",
|
|
"elifecycle",
|
|
"elit",
|
|
"embedder",
|
|
"emfile",
|
|
"enametoolong",
|
|
"endregion",
|
|
"eneedauth",
|
|
"enoent",
|
|
"enotempty",
|
|
"enten",
|
|
"eotp",
|
|
"eperm",
|
|
"epipe",
|
|
"errcode",
|
|
"esac",
|
|
"etamponi",
|
|
"exdev",
|
|
"execa",
|
|
"exploitability",
|
|
"fakehash",
|
|
"fellback",
|
|
"fetchings",
|
|
"filenamify",
|
|
"filesystem",
|
|
"filesystems",
|
|
"fnumber",
|
|
"foobarqar",
|
|
"foofoo",
|
|
"footgun",
|
|
"forgejo",
|
|
"fsevents",
|
|
"gabor",
|
|
"garply",
|
|
"gcttmf",
|
|
"getattr",
|
|
"ghes",
|
|
"ghsa",
|
|
"ghsas",
|
|
"gitea",
|
|
"globalconfig",
|
|
"globstar",
|
|
"gpgsign",
|
|
"grault",
|
|
"gruntfile",
|
|
"gwhitney",
|
|
"haptics",
|
|
"hardlink",
|
|
"hardlinked",
|
|
"hardlinking",
|
|
"hardlinks",
|
|
"hashbang",
|
|
"highmaps",
|
|
"hikljmi",
|
|
"hoistable",
|
|
"homepath",
|
|
"hosters",
|
|
"htpasswd",
|
|
"hyperdrive",
|
|
"idempotency",
|
|
"imagetools",
|
|
"imurmurhash",
|
|
"invalidformat",
|
|
"ionicons",
|
|
"isexe",
|
|
"istvan",
|
|
"italiano",
|
|
"jega",
|
|
"jhcg",
|
|
"jnbpamcxayl",
|
|
"junyi",
|
|
"kebabcase",
|
|
"kevva",
|
|
"keyfile",
|
|
"keyid",
|
|
"keytype",
|
|
"killcb",
|
|
"kochan",
|
|
"koorchik",
|
|
"ldid",
|
|
"ldni",
|
|
"leniolabs",
|
|
"libc",
|
|
"libnpmpublish",
|
|
"libnpx",
|
|
"libsql",
|
|
"libzip",
|
|
"licence",
|
|
"licences",
|
|
"lifecycles",
|
|
"linuxstatic",
|
|
"localappdata",
|
|
"lockfiles",
|
|
"loglevel",
|
|
"logstream",
|
|
"longlink",
|
|
"longpaths",
|
|
"luca",
|
|
"martensson",
|
|
"maxtimeout",
|
|
"mdast",
|
|
"metafile",
|
|
"millis",
|
|
"minioadmin",
|
|
"mintimeout",
|
|
"mmap",
|
|
"monorepolint",
|
|
"moonrepo",
|
|
"mountpoint",
|
|
"msgpack",
|
|
"msgpackr",
|
|
"msvc",
|
|
"msys",
|
|
"mycomp",
|
|
"mycompany",
|
|
"myorg",
|
|
"mypackage",
|
|
"mytoken",
|
|
"ndjson",
|
|
"nerfed",
|
|
"newversion",
|
|
"nistp",
|
|
"NOASSERTION",
|
|
"nodetouch",
|
|
"noent",
|
|
"nonexec",
|
|
"noninjected",
|
|
"nonvulnerable",
|
|
"nopadding",
|
|
"noproxy",
|
|
"nosystem",
|
|
"nothrow",
|
|
"npmcli",
|
|
"npmignore",
|
|
"npmjs",
|
|
"npmx",
|
|
"ntfs",
|
|
"nushell",
|
|
"ofjergrg",
|
|
"onclickoutside",
|
|
"oomol",
|
|
"ossl",
|
|
"outfile",
|
|
"overrider",
|
|
"packlist",
|
|
"packr",
|
|
"packument",
|
|
"packuments",
|
|
"pacquet",
|
|
"paralleljs",
|
|
"parallelly",
|
|
"parseable",
|
|
"partialmatch",
|
|
"pathext",
|
|
"pegjs",
|
|
"pidtree",
|
|
"pify",
|
|
"pkgname",
|
|
"pkgs",
|
|
"plotly",
|
|
"plugh",
|
|
"pnpmfile",
|
|
"pnpmfiles",
|
|
"pnpmjs",
|
|
"pnpmrc",
|
|
"pnpmtest",
|
|
"pnpr",
|
|
"polyfilling",
|
|
"português",
|
|
"posix",
|
|
"postbuild",
|
|
"postfoo",
|
|
"postpack",
|
|
"postprepare",
|
|
"postpublish",
|
|
"postrestart",
|
|
"postshrinkwrap",
|
|
"poststart",
|
|
"poststop",
|
|
"posttest",
|
|
"postuninstall",
|
|
"postversion",
|
|
"preact",
|
|
"prebuild",
|
|
"prefoo",
|
|
"prefs",
|
|
"preinstall",
|
|
"premajor",
|
|
"preminor",
|
|
"prepatch",
|
|
"prepublish",
|
|
"prereleases",
|
|
"prerestart",
|
|
"preshrinkwrap",
|
|
"prestart",
|
|
"prestop",
|
|
"preuninstall",
|
|
"preversion",
|
|
"prioritizer",
|
|
"promisified",
|
|
"proxied",
|
|
"pwsh",
|
|
"qrcode",
|
|
"quux",
|
|
"rcompare",
|
|
"redownload",
|
|
"refclone",
|
|
"refetched",
|
|
"reflattened",
|
|
"reflink",
|
|
"reflinked",
|
|
"reflinks",
|
|
"rehoist",
|
|
"reimagining",
|
|
"reka",
|
|
"Rekor",
|
|
"relinks",
|
|
"renderable",
|
|
"replit",
|
|
"reqheaders",
|
|
"rescopable",
|
|
"rescope",
|
|
"rescoped",
|
|
"rescopes",
|
|
"rescoping",
|
|
"rimrafed",
|
|
"rmgr",
|
|
"rpmdevtools",
|
|
"rpmlint",
|
|
"rstacruz",
|
|
"rushstack",
|
|
"rustup",
|
|
"safecrlf",
|
|
"scopeless",
|
|
"sdiff",
|
|
"searchexclude",
|
|
"searchlimit",
|
|
"searchopts",
|
|
"searchstaleness",
|
|
"sels",
|
|
"semistrict",
|
|
"serp",
|
|
"serverjs",
|
|
"shasums",
|
|
"sheetjs",
|
|
"shlex",
|
|
"sigstore",
|
|
"sindresorhus",
|
|
"sirv",
|
|
"SLSA",
|
|
"soporan",
|
|
"sopts",
|
|
"spdxdocs",
|
|
"SPDXID",
|
|
"sqld",
|
|
"srcset",
|
|
"ssri",
|
|
"stackblitz",
|
|
"stacktracey",
|
|
"stdtype",
|
|
"streamsearch",
|
|
"stringifying",
|
|
"subcmd",
|
|
"subdep",
|
|
"subdependencies",
|
|
"subdependency",
|
|
"subdeps",
|
|
"subdir",
|
|
"subdirs",
|
|
"subpkg",
|
|
"subresource",
|
|
"supercede",
|
|
"syml",
|
|
"syncer",
|
|
"syscall",
|
|
"syscalls",
|
|
"szia",
|
|
"tabtab",
|
|
"taffydb",
|
|
"tarballtemplate",
|
|
"teambit",
|
|
"tempy",
|
|
"testcase",
|
|
"tlog",
|
|
"TLSV",
|
|
"toctou",
|
|
"todomvc",
|
|
"toplevel",
|
|
"TOTP",
|
|
"tsgo",
|
|
"tsparticles",
|
|
"turso",
|
|
"typecheck",
|
|
"unallowed",
|
|
"undeprecate",
|
|
"underperformance",
|
|
"undollar",
|
|
"unextractable",
|
|
"uninstallation",
|
|
"unnest",
|
|
"unparseable",
|
|
"unreviewed",
|
|
"unskip",
|
|
"unstar",
|
|
"usecase",
|
|
"userconfig",
|
|
"userprofile",
|
|
"ustar",
|
|
"uuidv",
|
|
"valign",
|
|
"vuln",
|
|
"webauth",
|
|
"webcontainer",
|
|
"winst",
|
|
"workleap",
|
|
"worktree",
|
|
"worktrees",
|
|
"wrappy",
|
|
"xmarw",
|
|
"yazl",
|
|
"zkochan",
|
|
"zoli",
|
|
"zoltan"
|
|
]
|
|
}
|