mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-08-11 00:30:12 -04:00
chore(deps): clear every npm audit and pip-audit finding
Frontend:
- react-router/-dom 7.18.1 -> 7.18.2. The RSC-mode CSRF advisory was carried
as a documented exception in the audit gate because its only fix was the
8.3.0 major; upstream backported it, so the exemption lapsed on its own --
an entry only holds while fixAvailable.isSemVerMajor is true. The allowlist
is now empty; the machinery stays for the next one.
- dompurify 3.4.12 -> 3.4.13. Ships in the app, but the path is unreachable:
no hooks registered, IN_PLACE never used.
- js-yaml override ^4.3.0 -> ^5.2.3 (fix not backported below 5.x, so a
major) and nanoid override ^3.3.18. Both dev-only, via eslint and postcss.
eslintrc calls only load(), on the legacy .eslintrc.yml path this repo does
not use; eslint, vite build and 2861 frontend tests pass on it.
Backend:
- cryptography >=48.0.1 -> >=50.0.0, aiohttp >=3.14.0 -> >=3.14.3, pyopenssl
>=26.3.0 -> >=26.4.0. CI resolves from scratch and was already installing
the fixed releases; the floors cover the case CI does not, an existing venv
where >= is satisfied and `pip install -r` upgrades nothing. pyOpenSSL has
to move with cryptography -- each release caps it to a narrow window, so a
stale pyOpenSSL pins cryptography below its own fix line.
This commit is contained in:
parent
34a72fb7c2
commit
7f1e249849
7 changed files with 101 additions and 95 deletions
15
.github/workflows/ci.yml
vendored
15
.github/workflows/ci.yml
vendored
|
|
@ -203,15 +203,12 @@ jobs:
|
|||
vulns = data.get('vulnerabilities', {})
|
||||
# Documented advisory exceptions: high/critical findings whose only offered
|
||||
# 'fix' is a semver-major change and which do not apply to how Bambuddy ships.
|
||||
# Keyed by GHSA id; RE-REVIEW ON EVERY react-router BUMP.
|
||||
# GHSA-qwww-vcr4-c8h2 - React Router RSC-mode CSRF. Bambuddy is a Vite SPA
|
||||
# using BrowserRouter with no RSC runtime (@react-router/server is NOT
|
||||
# installed), so the vulnerable code path is unreachable. No non-major fix
|
||||
# exists (7.18.1 is the most-patched 7.x - it clears 14 other advisories that
|
||||
# older 7.x carry - and the RSC fix landed only in the 8.3.0 major). react-router
|
||||
# /-dom are pinned to 7.18.1 in package.json. If a non-major fix ships, this stops
|
||||
# being exempt (major-only guard below) and the gate fails until we take it.
|
||||
ALLOWLIST = {'GHSA-qwww-vcr4-c8h2'}
|
||||
# Keyed by GHSA id. An entry only holds while the fix stays major-only (see
|
||||
# fix_is_major below) - once upstream backports, the gate fails until we take
|
||||
# the patch. That is what retired the one entry this list used to carry:
|
||||
# GHSA-qwww-vcr4-c8h2 (React Router RSC-mode CSRF) shipped in 7.18.2, so the
|
||||
# pin moved rather than the exception staying.
|
||||
ALLOWLIST = set()
|
||||
def advisory_ids(name, seen=None):
|
||||
seen = seen if seen is not None else set()
|
||||
if name in seen:
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@ All notable changes to Bambuddy will be documented in this file.
|
|||
- **Ukrainian was listed above Russian in the language picker** — Locales appear in the picker in the order they were added, but `uk` had been inserted ahead of `ru` in the import block, the resources map and the list the picker renders. Moved to the end of all three; the alphabetically sorted supported-language list already had it in the right place. Frontend-only, with no behaviour change beyond the row order.
|
||||
- **Setting Spoolman options over the API with a true/false value returned a server error** — `PUT /settings/spoolman` accepts a free-form body, and sending the natural JSON form for a switch — `{"spoolman_enabled": true}` rather than `{"spoolman_enabled": "true"}` — came back as a 500 with nothing useful in it. The shipped UI always sends strings, so this only affected people driving Bambuddy from a script or a Home Assistant `rest_command`, which is exactly where a real boolean is the obvious thing to send. **Root cause.** Settings are stored as text and every reader compares them as text, but the submitted value went in untouched. Deciding whether Spoolman had just been switched on called a string operation on it, which a boolean does not have; and the raw boolean was also written straight to a text column, which SQLite quietly turns into 1/0 while PostgreSQL refuses it outright — so the stored result depended on which database the install used. **Fix.** Boolean-ish settings are now converted to a canonical `true`/`false` on the way in, accepting real booleans, `1`/`0`, and the usual spellings (`True`, `yes`, `on`) case-insensitively, since this is a documented API that scripts talk to. A value with no sensible reading, such as `"banana"`, now returns a 400 naming the field instead of being stored as-is and silently treated as off. Two details are preserved deliberately: a blank value still means "use the default" for the two options that default to on, and reading a stored value stays as strict as it has always been elsewhere in the codebase, so no existing row changes meaning. Text options are checked too, so a JSON object can no longer be stored as its own printed form. One incidental improvement: a value stored as `True` by an earlier API call showed as off in the UI, which compares case-sensitively, while the backend treated it as on — canonical storage removes that disagreement. Covered by tests across the accepted spellings, the rejected values, the blank-means-default behaviour, and the read path.
|
||||
|
||||
### Security
|
||||
- **Patched the build-time frontend dependencies flagged by `npm audit` (GHSA-rgw5-rvv9-x895, GHSA-5p4m-2wfm-xmqj, GHSA-2v37-7h3g-55p8)** — Three transitive dependencies of `eslint` and `postcss`, bumped through the existing `overrides` block. `brace-expansion` goes `^5.0.8` → `^5.0.9` for a denial-of-service via unbounded expansion: the first advisory was answered in 5.0.8 by capping the length of the combined result, but that cap covered only the accumulator the results are merged into and not the two intermediate arrays that feed it, so a small brace pattern could still exhaust the heap — fatally, and beyond the reach of a `try`/`catch` — or stall the event loop for minutes. 5.0.9 bounds both arrays as they are built. `js-yaml` goes `^4.3.0` → `^5.2.3` for quadratic CPU consumption while resolving `!!omap`; that fix was deliberately not backported to 3.x or 4.x, which is what makes this a major, so it was checked rather than assumed — `@eslint/eslintrc` calls exactly one js-yaml API, `load()`, and only on the legacy `.eslintrc.yml` path this repo does not use, and `eslint`, `vite build` and the full frontend test suite all pass on it. `nanoid` is newly pinned at `^3.3.18`, where a custom generator asked for size zero loops forever; the patch stays inside 3.x. All three are build and lint-time tooling — none is part of the shipped app, so no running Bambuddy install was exposed. The pins are needed because `npm audit fix` cannot lift a transitive of `eslint` or `postcss` on its own.
|
||||
- **Took the backported React Router fix and retired the audit exception (GHSA-qwww-vcr4-c8h2)** — `react-router`/`react-router-dom` move from 7.18.1 to **7.18.2**. The RSC-mode CSRF advisory noted in 1.2.5.1 was carried as a documented, fail-closed exception in the CI audit gate, because at the time its only fix was the 8.3.0 major and `react-router-dom` has no 8.x — adopting it would have meant migrating every import to `react-router` plus a React peer bump. Upstream has since backported the patch to the 7.x line, so the pin moves and the exception is gone, leaving the gate's allowlist empty. That happened on its own rather than by anyone remembering to check: an entry only holds while the offered fix is semver-major, so the gate failed the moment the backport shipped instead of quietly carrying a now-fixable advisory. The finding was never reachable here in any case — Bambuddy is a Vite SPA using `BrowserRouter` with no RSC runtime installed. `npm audit fix --force` remains deliberately avoided; its suggested "fix" is a downgrade to 7.11.0, which reintroduces the 14 advisories older 7.x releases carry.
|
||||
- **`dompurify` 3.4.12 → 3.4.13 (GHSA-55q2-fjhq-7xh7)** — Removing a hook mid-sanitisation could leave a detached subtree executable in DOMPurify's `IN_PLACE` mode, an XSS. Unlike the build-time bumps above, DOMPurify does ship in the app — it sanitises MakerWorld-supplied design summaries and project notes before they are rendered — so it is worth being explicit that this particular path was not reachable: Bambuddy registers no DOMPurify hooks and never uses `IN_PLACE`, calling only the string-returning `sanitize()` with an explicit tag and attribute allowlist. The patched release is inside the existing `^3.4.10` range, so this is a lockfile move rather than a new pin.
|
||||
- **Raised the `cryptography`, `pyOpenSSL` and `aiohttp` floors so a resolve cannot pick a vulnerable-but-satisfying version (PYSEC-2026-3552, PYSEC-2026-3545/3546/3547)** — `cryptography>=48.0.1` → `>=50.0.0` and `aiohttp>=3.14.0` → `>=3.14.3`. Neither had gone stale in CI, which resolves from scratch and so was already installing the fixed releases; the floors matter for the case CI does not cover, an existing environment where `>=` is already satisfied and `pip install -r` therefore upgrades nothing. `pyOpenSSL` moves `>=26.3.0` → `>=26.4.0` for a subtler reason worth writing down: every pyOpenSSL release caps `cryptography` to a narrow window (26.3.0 permits `<50`, 26.4.0 permits `<51`), so a stale pyOpenSSL silently holds `cryptography` below its own fix line and pip cannot climb past the cap even when asked for it directly. The two floors have to move together, which the comment in `requirements.txt` now says. Bambuddy's `cryptography` surface is indirect throughout — asyncssh, pyOpenSSL, py-vapid, http_ece, pywebpush — and the 49 → 50 major was verified rather than assumed: the X.509/PKCS#7/EC/RSA entry points and pyftpdlib's `TLS_FTPHandler` all import, `ruff` is clean, and the full backend suite passes unchanged.
|
||||
|
||||
## [1.2.5.1] - 2026-07-27
|
||||
|
||||
### Added
|
||||
|
|
|
|||
43
frontend/package-lock.json
generated
43
frontend/package-lock.json
generated
|
|
@ -33,7 +33,7 @@
|
|||
"react-dom": "^19.2.0",
|
||||
"react-i18next": "^16.3.5",
|
||||
"react-markdown": "^9.1.0",
|
||||
"react-router-dom": "7.18.1",
|
||||
"react-router-dom": "7.18.2",
|
||||
"react-simple-keyboard": "^3.8.164",
|
||||
"recharts": "^3.5.1",
|
||||
"remark-gfm": "^4.0.1",
|
||||
|
|
@ -3173,9 +3173,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz",
|
||||
"integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==",
|
||||
"version": "5.0.9",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
|
||||
"integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^4.0.2"
|
||||
|
|
@ -3778,9 +3778,9 @@
|
|||
"peer": true
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.4.12",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz",
|
||||
"integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.13.tgz",
|
||||
"integrity": "sha512-2vmYIoqjze2d+kakP8S/nS5shfsl587kzwEjcGlTdiksUVgFHnFCsLYDVj/JNqJVOQZGSYBTmuycv0PodwmnMQ==",
|
||||
"optionalDependencies": {
|
||||
"@types/trusted-types": "^2.0.7"
|
||||
}
|
||||
|
|
@ -4913,9 +4913,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz",
|
||||
"integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==",
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.2.3.tgz",
|
||||
"integrity": "sha512-n+mUVyUX5bVv7G/G2zyIHOhdxfuU1dY2NOFzTQUWiMUbFss8b57NFlgCCaggU78wSw5KVS9cllzeLyzyR+n5nw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -4927,12 +4927,11 @@
|
|||
"url": "https://github.com/sponsors/nodeca"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
"js-yaml": "bin/js-yaml.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/jsdom": {
|
||||
|
|
@ -6481,9 +6480,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.16",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
|
||||
"integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
|
||||
"version": "3.3.18",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
|
||||
"integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -7135,9 +7134,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "7.18.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.1.tgz",
|
||||
"integrity": "sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==",
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.2.tgz",
|
||||
"integrity": "sha512-aUVMjFm3GAPTTZL7oYr5E7ETiqfQCHRLH+B+5afnICvf0r7kkK4eR6SMuwbSTJw/7t+12khT/Kahij49fqOCIg==",
|
||||
"dependencies": {
|
||||
"cookie": "^1.0.1",
|
||||
"set-cookie-parser": "^2.6.0"
|
||||
|
|
@ -7156,11 +7155,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "7.18.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.1.tgz",
|
||||
"integrity": "sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==",
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.2.tgz",
|
||||
"integrity": "sha512-AIKJ/jgGlFb3EbfCXk5Gzshiwt+l3mqbCrNjmEWMMjqQxNJ3svBa6bgzFyCC2Sw3RA0VWF1kg3uQf2OFhxb8hw==",
|
||||
"dependencies": {
|
||||
"react-router": "7.18.1"
|
||||
"react-router": "7.18.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
"react-dom": "^19.2.0",
|
||||
"react-i18next": "^16.3.5",
|
||||
"react-markdown": "^9.1.0",
|
||||
"react-router-dom": "7.18.1",
|
||||
"react-router-dom": "7.18.2",
|
||||
"react-simple-keyboard": "^3.8.164",
|
||||
"recharts": "^3.5.1",
|
||||
"remark-gfm": "^4.0.1",
|
||||
|
|
@ -48,9 +48,10 @@
|
|||
},
|
||||
"overrides": {
|
||||
"minimatch": "^10.2.1",
|
||||
"brace-expansion": "^5.0.8",
|
||||
"js-yaml": "^4.3.0",
|
||||
"react-router": "7.18.1"
|
||||
"brace-expansion": "^5.0.9",
|
||||
"js-yaml": "^5.2.3",
|
||||
"nanoid": "^3.3.18",
|
||||
"react-router": "7.18.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.1",
|
||||
|
|
|
|||
|
|
@ -40,14 +40,17 @@ aioftp>=0.22.0
|
|||
|
||||
# Virtual Printer (emulates Bambu printer for slicer uploads)
|
||||
pyftpdlib>=2.0.0
|
||||
# 46.x line has GHSA-537c-gmf6-5ccf; 48.0.1 is the fix release. Upstream's
|
||||
# X.509 / PKCS#7 surface is in our trust path via asyncssh, pyOpenSSL,
|
||||
# py-vapid, http_ece, pywebpush.
|
||||
cryptography>=48.0.1
|
||||
# Transitive of asyncssh / pywebpush. pyopenssl<26.3.0 caps `cryptography<47`
|
||||
# so without this floor the resolver either downgrades cryptography below
|
||||
# the GHSA-537c-gmf6-5ccf fix line or installs an inconsistent pair.
|
||||
pyopenssl>=26.3.0
|
||||
# Upstream's X.509 / PKCS#7 surface is in our trust path via asyncssh,
|
||||
# pyOpenSSL, py-vapid, http_ece, pywebpush, so this floor tracks the current
|
||||
# fix release: 46.x had GHSA-537c-gmf6-5ccf (fixed in 48.0.1), and 49.0.0 has
|
||||
# PYSEC-2026-3552 (fixed in 50.0.0).
|
||||
cryptography>=50.0.0
|
||||
# Transitive of asyncssh / pywebpush, and the gate on the line above: each
|
||||
# pyOpenSSL release caps `cryptography` to a narrow window (26.3.0 allows
|
||||
# <50, 26.4.0 allows <51), so a stale pyOpenSSL silently pins cryptography
|
||||
# below its fix line -- pip cannot upgrade past the cap even when asked.
|
||||
# Raise this floor in the same commit as any cryptography floor.
|
||||
pyopenssl>=26.4.0
|
||||
|
||||
# SpoolBuddy remote SSH updates (pure-Python SSH client; avoids the
|
||||
# OpenSSH `ssh` binary which calls getpwuid() and fails in Docker when
|
||||
|
|
@ -143,13 +146,13 @@ urllib3>=2.7.0
|
|||
# resolver from picking them.
|
||||
starlette>=1.3.1
|
||||
|
||||
# Transitive of pywebpush (unpinned `aiohttp` requirement). aiohttp 3.13.5
|
||||
# has CVE-2026-34993 and CVE-2026-47265, both fixed in 3.14.0. pywebpush
|
||||
# doesn't declare an upper bound either way, so without this pin the
|
||||
# resolver keeps installing the vulnerable 3.13.x line. Our direct usage
|
||||
# in services/external_camera.py (ClientSession, ClientTimeout, ClientError,
|
||||
# iter_chunked) is unaffected by 3.14.0.
|
||||
aiohttp>=3.14.0
|
||||
# Transitive of pywebpush (unpinned `aiohttp` requirement). pywebpush declares
|
||||
# no bound in either direction, so without this floor the resolver happily
|
||||
# installs a vulnerable line: 3.13.5 has CVE-2026-34993 and CVE-2026-47265
|
||||
# (fixed in 3.14.0), and 3.14.1 has PYSEC-2026-3545/3546/3547 (3.14.3 clears
|
||||
# all three). Our direct usage in services/external_camera.py (ClientSession,
|
||||
# ClientTimeout, ClientError, iter_chunked) is unaffected by either bump.
|
||||
aiohttp>=3.14.3
|
||||
|
||||
# Plate Detection (optional - enables build plate empty detection)
|
||||
opencv-python-headless>=4.8.0
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<!-- Splash screens for iOS -->
|
||||
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
|
||||
<script type="module" crossorigin src="/assets/index-DPZgvI9N.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-DjrhopFm.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-C_6BSgrK.css">
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue