Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1198495e0 | ||
|
|
6336e16350 | ||
|
|
c817e4bec0 | ||
|
|
ad806be70a |
@@ -91,8 +91,27 @@ jobs:
|
||||
# advisory, the same fail-on-vulnerability stance as cargo-audit above; triage a finding by
|
||||
# bumping the dep (or, if genuinely unfixable + inapplicable, pinning a resolution and
|
||||
# noting why here).
|
||||
#
|
||||
# web carries two ignores, the ONLY ones in a blocking tree — both image-size advisories
|
||||
# (GHSA-w3rx-r6r6-pgpr ICNS, GHSA-5p2g-fcmc-qvqq JXL/HEIF infinite-loop DoS). They are
|
||||
# unfixable AND unreachable:
|
||||
# * unfixable — the vulnerable range is `<= 2.0.2` and 2.0.2 IS latest; upstream has
|
||||
# published no patched release, so no override can clear them.
|
||||
# * unreachable — image-size rides in under `@unom/ui › @payloadcms/richtext-lexical ›
|
||||
# … › payload`, and @payloadcms/richtext-lexical is a PEER of @unom/ui that only its
|
||||
# `./richtext` export needs. The console imports section/toast/button/card/dialog/
|
||||
# form/*/material/tabs — never `./richtext` — so payload is auto-installed peer weight
|
||||
# that no bundle, and no request path, ever touches.
|
||||
# Drop these the moment image-size ships a fix, or @unom/ui marks that peer optional
|
||||
# (peerDependenciesMeta) and the chain leaves web/bun.lock entirely — either one makes the
|
||||
# bare `bun audit` green again. Scoped per-tree so sdk/plugin-kit stay strictly fail-on-any.
|
||||
- name: bun audit
|
||||
run: bun audit
|
||||
run: |
|
||||
if [ "${{ matrix.tree }}" = "web" ]; then
|
||||
bun audit --ignore=GHSA-w3rx-r6r6-pgpr --ignore=GHSA-5p2g-fcmc-qvqq
|
||||
else
|
||||
bun audit
|
||||
fi
|
||||
|
||||
# Kept OUT of the bun-audit matrix so this tree's known-advisory state can't normalize failure
|
||||
# in a shipping tree. Non-blocking via a step-level `||` (NOT job-level continue-on-error, which
|
||||
|
||||
@@ -12,6 +12,36 @@ with the version table of the release you are moving to, then read **Breaking ch
|
||||
|
||||
---
|
||||
|
||||
## v0.27.1 — in development
|
||||
|
||||
### NixOS + KDE — session detection, the other half
|
||||
|
||||
🛑 **v0.27.0's NixOS session-detection fix did not reach a stock NixOS + Plasma 6 box.** It resolved
|
||||
the nixpkgs wrapper decoration through `/proc/<pid>/exe` (below) — and on that exact box the kernel
|
||||
refuses to let us read that link. Reading `/proc/<pid>/exe` is not gated on owning the process: it
|
||||
goes through `cap_ptrace_access_check`, which requires the reader's effective set to be a superset
|
||||
of the target's **permitted** set. NixOS's own Plasma module ships
|
||||
`security.wrappers.kwin_wayland = { capabilities = "cap_sys_nice+ep"; }`, so KWin holds a capability
|
||||
and the host — which must stay uncapped, because a capability is exactly what makes it
|
||||
unidentifiable to KWin (v0.27.0, above) — gets `EACCES`. The two traps compose: the name *needs*
|
||||
`exe` because nixpkgs wrapped the binary, and `exe` is *denied* because NixOS capped it. Detection
|
||||
went straight back to `ActiveKind::None`, `wayland` to `-`, and every connect to
|
||||
`no usable compositor`. It presents identically to the v0.27.0 bug, which is why a box that had been
|
||||
worked around with a decoy process broke again the moment the decoy was removed.
|
||||
|
||||
Name resolution now falls through to `argv[0]` (`/proc/<pid>/cmdline`) when the kernel refuses `exe`.
|
||||
That reads correctly for the same reason `ps` does: make-wrapper's wrapper `exec -a "$0"`s the hidden
|
||||
binary, so `argv[0]` survives the decoration `comm` does not. Measured on Linux 6.x against a capped
|
||||
target, for a file capability and for the ambient form `security.wrappers` uses, identically: the
|
||||
`/proc/<pid>` directory keeps its real owner (so the uid filter was never the problem), `comm` and
|
||||
`cmdline` stay readable, and only `exe` fails. `argv[0]` is consulted **last** and never overrides a
|
||||
readable `exe` — it is the process's own claim about itself, and a same-uid process can set it to
|
||||
anything; the worst a spoof achieves is aiming detection at a backend that then fails its own
|
||||
availability probe. The `comm` fast path is still one read for every ordinary distro.
|
||||
|
||||
Also reached by the same rung: `gamescope` carries `cap_sys_nice` on a number of distros, so a
|
||||
*wrapped and capped* gamescope was equally invisible to the foreign-gamescope probe.
|
||||
|
||||
## v0.27.0
|
||||
|
||||
87 commits since v0.26.0.
|
||||
|
||||
@@ -135,7 +135,37 @@ const COMM_MAX: usize = 15;
|
||||
///
|
||||
/// The `comm` fast path is kept for every ordinary distro: one read, no readlink. Only a name that
|
||||
/// *could* be decorated or truncated — it starts with `.`, or it is exactly [`COMM_MAX`] bytes —
|
||||
/// is re-resolved through `/proc/<pid>/exe`, which carries the full, untruncated file name.
|
||||
/// is re-resolved, first through `/proc/<pid>/exe` and then, when the kernel refuses that link,
|
||||
/// through `argv[0]`.
|
||||
///
|
||||
/// 🛑 **That last rung is not defensive padding — without it this resolver misses the exact box it
|
||||
/// was written for.** Reading `/proc/<pid>/exe` is *not* merely a matter of owning the process: the
|
||||
/// kernel gates it behind `cap_ptrace_access_check`, which demands the reader's effective set be a
|
||||
/// superset of the target's PERMITTED set. A compositor holding a capability is therefore opaque to
|
||||
/// our (deliberately uncapped — see the KWin identification note in `pf-encode`) host, same uid or
|
||||
/// not. And NixOS's own Plasma module ships exactly that:
|
||||
/// `security.wrappers.kwin_wayland = { capabilities = "cap_sys_nice+ep"; }`. So on NixOS + KDE the
|
||||
/// two traps compose — the name needs `exe` *because* nixpkgs wrapped it, and `exe` is denied
|
||||
/// *because* NixOS capped it — and the session probe went straight back to
|
||||
/// [`crate::ActiveKind::None`] on a running desktop.
|
||||
///
|
||||
/// Measured (Linux 6.x, same-uid reader, target holding `cap_sys_nice`), for a file capability and
|
||||
/// for the ambient-capability form `security.wrappers` actually uses, identically:
|
||||
///
|
||||
/// | probe | capped target |
|
||||
/// |---|---|
|
||||
/// | `/proc/<pid>` owner | ✅ still the real uid — the uid filter upstream is unaffected |
|
||||
/// | `comm` | ✅ readable (decorated/truncated, so still unusable on its own) |
|
||||
/// | `exe` | ❌ **EACCES** |
|
||||
/// | `cmdline` (`argv[0]`) | ✅ readable |
|
||||
///
|
||||
/// `argv[0]` is only consulted when the kernel has refused the authoritative answer, because it is
|
||||
/// the process's own claim about itself rather than the kernel's: a same-uid process can set it to
|
||||
/// anything. The exposure that buys is small and one-directional — the worst a spoof achieves is
|
||||
/// aiming detection at a compositor backend that then fails its own availability probe — whereas
|
||||
/// without the rung a capped compositor is simply invisible. It reads correctly here for the same
|
||||
/// reason `ps` does: make-wrapper's generated wrapper `exec -a "$0"`s the hidden binary, so
|
||||
/// `argv[0]` survives the decoration that `comm` does not.
|
||||
///
|
||||
/// `pid_path` is a `/proc/<pid>` directory. `None` when the process vanished mid-scan.
|
||||
#[cfg(target_os = "linux")]
|
||||
@@ -146,20 +176,48 @@ pub(crate) fn match_name(pid_path: &std::path::Path) -> Option<String> {
|
||||
if !comm.starts_with('.') && comm.len() < COMM_MAX {
|
||||
return Some(comm.to_string());
|
||||
}
|
||||
// Reading our OWN uid's `/proc/<pid>/exe` needs no privilege (every caller filters on uid
|
||||
// first), but it is still absent for a kernel thread and for a process exiting under us —
|
||||
// in which case the truncated `comm` is the best that exists.
|
||||
match std::fs::read_link(pid_path.join("exe"))
|
||||
.ok()
|
||||
// The authoritative rung: the kernel's own record of the executed file, untruncated. Absent for
|
||||
// a kernel thread and for a process exiting under us, and REFUSED for a capability-holding one.
|
||||
let exe = std::fs::read_link(pid_path.join("exe")).ok();
|
||||
if let Some(full) = exe
|
||||
.as_deref()
|
||||
.and_then(|p| p.file_name())
|
||||
.and_then(|n| n.to_str())
|
||||
{
|
||||
Some(full) => Some(undecorate(full).to_string()),
|
||||
return Some(undecorate(full).to_string());
|
||||
}
|
||||
// Refused or gone: fall back to what the process calls itself, then to the truncated `comm`.
|
||||
match argv0_name(pid_path) {
|
||||
Some(name) => {
|
||||
tracing::debug!(
|
||||
comm = %comm,
|
||||
resolved = %name,
|
||||
"/proc/<pid>/exe unreadable (a capability-holding process refuses it); \
|
||||
identified via argv[0]"
|
||||
);
|
||||
Some(name)
|
||||
}
|
||||
None => Some(comm.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// The file name in `argv[0]`, with nixpkgs decoration undone — the last rung of [`match_name`].
|
||||
///
|
||||
/// `/proc/<pid>/cmdline` is NUL-separated, so the first field is `argv[0]` whole, with no splitting
|
||||
/// on whitespace to get wrong. `None` when it is unreadable or empty, which is the normal state for
|
||||
/// a kernel thread and for a zombie.
|
||||
#[cfg(target_os = "linux")]
|
||||
fn argv0_name(pid_path: &std::path::Path) -> Option<String> {
|
||||
let raw = std::fs::read(pid_path.join("cmdline")).ok()?;
|
||||
let argv0 = raw.split(|b| *b == 0).next()?;
|
||||
// A process that rewrote its own argv (setproctitle-style) can leave anything here, including
|
||||
// something that is not a path at all — `file_name` simply yields it unchanged and it fails to
|
||||
// match any compositor name, which is the correct outcome.
|
||||
let argv0 = std::str::from_utf8(argv0).ok()?;
|
||||
let name = std::path::Path::new(argv0).file_name()?.to_str()?;
|
||||
(!name.is_empty()).then(|| undecorate(name).to_string())
|
||||
}
|
||||
|
||||
/// Strip nixpkgs `wrapProgram` decoration: `.<name>-wrapped`, plus the `_` suffixes make-wrapper
|
||||
/// appends when that hidden name is already taken (a doubly-wrapped app — Qt *and* GApps).
|
||||
///
|
||||
@@ -366,8 +424,12 @@ mod name_tests {
|
||||
use super::*;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// A fake `/proc/<pid>` directory: a `comm` file and, optionally, the `exe` symlink. Removed on
|
||||
/// drop.
|
||||
/// A fake `/proc/<pid>` directory: a `comm` file and, optionally, the `exe` symlink and a
|
||||
/// `cmdline`. Removed on drop.
|
||||
///
|
||||
/// An absent `exe` stands in for **both** ways the real link yields nothing: a process exiting
|
||||
/// under the scan, and — the case that matters here — a capability-holding one, whose link the
|
||||
/// kernel refuses with EACCES. `match_name` cannot tell those apart and does not need to.
|
||||
struct FakePid {
|
||||
dir: PathBuf,
|
||||
}
|
||||
@@ -375,6 +437,12 @@ mod name_tests {
|
||||
impl FakePid {
|
||||
/// `comm` is written exactly as the kernel would report it — i.e. already truncated.
|
||||
fn new(tag: &str, comm: &str, exe: Option<&str>) -> FakePid {
|
||||
FakePid::with_cmdline(tag, comm, exe, None)
|
||||
}
|
||||
|
||||
/// `cmdline` is the NUL-separated argument vector the kernel exposes; the fixture is given
|
||||
/// just `argv[0]` and appends the terminator, as a real one carries.
|
||||
fn with_cmdline(tag: &str, comm: &str, exe: Option<&str>, argv0: Option<&str>) -> FakePid {
|
||||
let dir = std::env::temp_dir().join(format!("pf-vd-name-{tag}-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
std::fs::create_dir_all(&dir).expect("fixture dir");
|
||||
@@ -388,6 +456,9 @@ mod name_tests {
|
||||
)
|
||||
.expect("exe symlink");
|
||||
}
|
||||
if let Some(argv0) = argv0 {
|
||||
std::fs::write(dir.join("cmdline"), format!("{argv0}\0--session\0")).expect("cmd");
|
||||
}
|
||||
FakePid { dir }
|
||||
}
|
||||
fn path(&self) -> &Path {
|
||||
@@ -505,14 +576,87 @@ mod name_tests {
|
||||
assert_eq!(match_name(p.path()).as_deref(), Some("kwin_wayland"));
|
||||
}
|
||||
|
||||
/// A decorated-or-truncated name whose `exe` cannot be read (a kernel thread, or a process
|
||||
/// exiting under the scan) degrades to the truncated `comm` instead of failing the whole entry.
|
||||
/// A decorated-or-truncated name with neither `exe` nor `cmdline` to fall back on (a kernel
|
||||
/// thread, or a process exiting under the scan) degrades to the truncated `comm` instead of
|
||||
/// failing the whole entry.
|
||||
#[test]
|
||||
fn an_unreadable_exe_falls_back_to_comm() {
|
||||
let p = FakePid::new("noexe", ".kwin_wayland-w", None);
|
||||
assert_eq!(match_name(p.path()).as_deref(), Some(".kwin_wayland-w"));
|
||||
}
|
||||
|
||||
/// **The NixOS + KDE field bug in one assertion.** nixpkgs wraps the binary, so `comm` is
|
||||
/// `.kwin_wayland-w` and only `exe` carries the real name — and NixOS's own Plasma module hands
|
||||
/// KWin `cap_sys_nice+ep` through `security.wrappers`, so the kernel refuses that link to our
|
||||
/// uncapped host. Both traps at once is not a hypothetical combination: it is the default
|
||||
/// install. `argv[0]` is what survives, because make-wrapper's wrapper `exec -a "$0"`s the
|
||||
/// hidden binary.
|
||||
#[test]
|
||||
fn a_capped_wrapped_compositor_is_identified_by_argv0() {
|
||||
for (tag, comm, argv0, want) in [
|
||||
// Plasma's own startup execs the wrapper by absolute path.
|
||||
(
|
||||
"capkwin",
|
||||
".kwin_wayland-w",
|
||||
"/run/wrappers/bin/kwin_wayland",
|
||||
"kwin_wayland",
|
||||
),
|
||||
// …and a bare name is just as ordinary.
|
||||
("capbare", ".kwin_wayland-w", "kwin_wayland", "kwin_wayland"),
|
||||
// gamescope carries `cap_sys_nice` on a great many distros, wrapped or not.
|
||||
(
|
||||
"capgame",
|
||||
".gamescope-wrap",
|
||||
"/nix/store/aaaa-gamescope/bin/gamescope",
|
||||
"gamescope",
|
||||
),
|
||||
// A wrapper that passes the hidden path through as `argv[0]` still undecorates.
|
||||
(
|
||||
"capraw",
|
||||
".kwin_wayland-w",
|
||||
"/nix/store/eeee-kwin/bin/.kwin_wayland-wrapped",
|
||||
"kwin_wayland",
|
||||
),
|
||||
] {
|
||||
let p = FakePid::with_cmdline(tag, comm, None, Some(argv0));
|
||||
assert_eq!(
|
||||
match_name(p.path()).as_deref(),
|
||||
Some(want),
|
||||
"a capped, wrapped {want} must still be identified from argv[0]"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// `exe` outranks `argv[0]` whenever the kernel allows it: `argv[0]` is the process's own claim
|
||||
/// about itself and a same-uid process can set it to anything, so it may never override the
|
||||
/// kernel's answer — only stand in when there is none.
|
||||
#[test]
|
||||
fn a_readable_exe_outranks_a_lying_argv0() {
|
||||
let p = FakePid::with_cmdline(
|
||||
"liar",
|
||||
".gamescope-wrap",
|
||||
Some(".gamescope-wrapped"),
|
||||
Some("kwin_wayland"),
|
||||
);
|
||||
assert_eq!(match_name(p.path()).as_deref(), Some("gamescope"));
|
||||
}
|
||||
|
||||
/// A zombie's `cmdline` is empty, and `argv[0]` can be an empty string even when it is not —
|
||||
/// neither may yield an empty name (which would then be compared against, and could match, a
|
||||
/// compositor name only by accident).
|
||||
#[test]
|
||||
fn an_empty_cmdline_does_not_produce_a_name() {
|
||||
for (tag, cmdline) in [("zombie", ""), ("nulls", "\0\0")] {
|
||||
let dir = std::env::temp_dir().join(format!("pf-vd-name-{tag}-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
std::fs::create_dir_all(&dir).expect("fixture dir");
|
||||
std::fs::write(dir.join("comm"), ".kwin_wayland-w\n").expect("comm");
|
||||
std::fs::write(dir.join("cmdline"), cmdline).expect("cmdline");
|
||||
assert_eq!(match_name(&dir).as_deref(), Some(".kwin_wayland-w"));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
}
|
||||
|
||||
/// A pid directory that does not exist yields `None`, not a bogus name — the scans `continue`.
|
||||
#[test]
|
||||
fn a_vanished_process_yields_none() {
|
||||
@@ -520,8 +664,10 @@ mod name_tests {
|
||||
}
|
||||
|
||||
/// The one thing a fixture cannot establish: that reading `/proc/<pid>/exe` is actually
|
||||
/// *permitted* for a process of our own uid, which the whole resolver depends on. Checked
|
||||
/// against the only such process guaranteed to be running — this one.
|
||||
/// *permitted* for a process of our own uid. Checked against the only such process guaranteed
|
||||
/// to be running — this one. ⚠ It holds because *we* are uncapped, and says nothing about the
|
||||
/// processes being scanned: a capped target refuses this same link, which is what
|
||||
/// [`match_name`]'s `argv[0]` rung exists for.
|
||||
#[test]
|
||||
fn our_own_exe_link_is_readable() {
|
||||
let me = Path::new("/proc/self");
|
||||
|
||||
@@ -315,7 +315,11 @@ pub fn detect_active_session() -> ActiveSession {
|
||||
// exactly, `pkill -x` style — but resolved through [`crate::proc::match_name`], NOT a raw
|
||||
// `comm` read: on NixOS every one of these binaries is a nixpkgs wrapper whose real ELF is
|
||||
// `.<name>-wrapped`, so a raw `comm` says `.kwin_wayland-w` and this whole probe answered
|
||||
// `None` on a running KDE desktop.
|
||||
// `None` on a running KDE desktop. ⚠ Nor is `/proc/<pid>/exe` alone enough to undo that: NixOS
|
||||
// caps KWin (`security.wrappers.kwin_wayland`, `cap_sys_nice+ep`) and the kernel refuses that
|
||||
// link to an uncapped reader — see `match_name`, which falls through to `argv[0]` for exactly
|
||||
// this box. The uid filter below is unaffected: a capped process's `/proc/<pid>` keeps its
|
||||
// real owner (measured).
|
||||
let mut kind = ActiveKind::None;
|
||||
let mut best = 0u8;
|
||||
// The winning compositor's PID — kept so a same-kind compositor RESTART (a new PID) bumps the
|
||||
|
||||
+6
-5
@@ -47,11 +47,12 @@
|
||||
},
|
||||
"overrides": {
|
||||
"brace-expansion": "^5.0.9",
|
||||
"dompurify": "^3.4.12",
|
||||
"dompurify": "^3.4.13",
|
||||
"fast-uri": "^3.1.5",
|
||||
"immutable": "^4.3.9",
|
||||
"js-yaml": "^4.3.0",
|
||||
"js-yaml": "^4.3.1",
|
||||
"linkify-it": "^5.0.2",
|
||||
"nanoid": "^3.3.18",
|
||||
"postcss": "^8.5.25",
|
||||
"sharp": "^0.35.3",
|
||||
"tar": "^7.5.21",
|
||||
@@ -1304,7 +1305,7 @@
|
||||
|
||||
"dom-helpers": ["dom-helpers@5.2.1", "", { "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA=="],
|
||||
|
||||
"dompurify": ["dompurify@3.4.12", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg=="],
|
||||
"dompurify": ["dompurify@3.4.13", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-2vmYIoqjze2d+kakP8S/nS5shfsl587kzwEjcGlTdiksUVgFHnFCsLYDVj/JNqJVOQZGSYBTmuycv0PodwmnMQ=="],
|
||||
|
||||
"dot-prop": ["dot-prop@10.2.0", "", { "dependencies": { "type-fest": "^5.0.0" } }, "sha512-BTJ9aZYL3vCfZlZOBLy9v8TUqWGQ0pzFnygKwFZt5udj6viBoFIBviKPUoZLDCPn1FoXffv6McQFDenrm5Krfw=="],
|
||||
|
||||
@@ -1580,7 +1581,7 @@
|
||||
|
||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||
|
||||
"js-yaml": ["js-yaml@4.3.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q=="],
|
||||
"js-yaml": ["js-yaml@4.3.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ=="],
|
||||
|
||||
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
|
||||
|
||||
@@ -1774,7 +1775,7 @@
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.16", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q=="],
|
||||
"nanoid": ["nanoid@3.3.18", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w=="],
|
||||
|
||||
"next": ["next@16.2.11", "", { "dependencies": { "@next/env": "16.2.11", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.2.11", "@next/swc-darwin-x64": "16.2.11", "@next/swc-linux-arm64-gnu": "16.2.11", "@next/swc-linux-arm64-musl": "16.2.11", "@next/swc-linux-x64-gnu": "16.2.11", "@next/swc-linux-x64-musl": "16.2.11", "@next/swc-win32-arm64-msvc": "16.2.11", "@next/swc-win32-x64-msvc": "16.2.11", "sharp": "^0.34.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-B339zaqbyK8cmxhoAvLrcwoabwCP1wz21zSzfqxqXAemTu2BXnH7tQnfcglKv1vnMUIDBc+Hth7XODQriTZiRQ=="],
|
||||
|
||||
|
||||
+9
-9
@@ -2619,9 +2619,9 @@
|
||||
url = "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz";
|
||||
hash = "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==";
|
||||
};
|
||||
"dompurify@3.4.12" = fetchurl {
|
||||
url = "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz";
|
||||
hash = "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==";
|
||||
"dompurify@3.4.13" = fetchurl {
|
||||
url = "https://registry.npmjs.org/dompurify/-/dompurify-3.4.13.tgz";
|
||||
hash = "sha512-2vmYIoqjze2d+kakP8S/nS5shfsl587kzwEjcGlTdiksUVgFHnFCsLYDVj/JNqJVOQZGSYBTmuycv0PodwmnMQ==";
|
||||
};
|
||||
"dot-prop@10.2.0" = fetchurl {
|
||||
url = "https://registry.npmjs.org/dot-prop/-/dot-prop-10.2.0.tgz";
|
||||
@@ -3219,9 +3219,9 @@
|
||||
url = "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz";
|
||||
hash = "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==";
|
||||
};
|
||||
"js-yaml@4.3.0" = fetchurl {
|
||||
url = "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz";
|
||||
hash = "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==";
|
||||
"js-yaml@4.3.1" = fetchurl {
|
||||
url = "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz";
|
||||
hash = "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==";
|
||||
};
|
||||
"jsesc@3.1.0" = fetchurl {
|
||||
url = "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz";
|
||||
@@ -3671,9 +3671,9 @@
|
||||
url = "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz";
|
||||
hash = "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==";
|
||||
};
|
||||
"nanoid@3.3.16" = fetchurl {
|
||||
url = "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz";
|
||||
hash = "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==";
|
||||
"nanoid@3.3.18" = fetchurl {
|
||||
url = "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz";
|
||||
hash = "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==";
|
||||
};
|
||||
"napi-wasm@1.1.3" = fetchurl {
|
||||
url = "https://registry.npmjs.org/napi-wasm/-/napi-wasm-1.1.3.tgz";
|
||||
|
||||
+3
-2
@@ -62,14 +62,15 @@
|
||||
},
|
||||
"overrides": {
|
||||
"tar": "^7.5.21",
|
||||
"dompurify": "^3.4.12",
|
||||
"dompurify": "^3.4.13",
|
||||
"linkify-it": "^5.0.2",
|
||||
"sharp": "^0.35.3",
|
||||
"fast-uri": "^3.1.5",
|
||||
"immutable": "^4.3.9",
|
||||
"undici": "^7.29.0",
|
||||
"postcss": "^8.5.25",
|
||||
"js-yaml": "^4.3.0",
|
||||
"nanoid": "^3.3.18",
|
||||
"js-yaml": "^4.3.1",
|
||||
"brace-expansion": "^5.0.9"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user