fix: harden admin actions, search, sanitization and repo hygiene
CI / check (push) Successful in 1m21s
CI / deploy (push) Successful in 1m25s

- Split approve/dismiss application workflows with distinct audit logs,
  rate-limited guards and real error logging
- Validate article status/date/id input and stop resetting publishedAt
  on every update
- Validate guild updates (state, forum enums, non-empty name) behind
  rate-limited guard
- Fix scheduled-article publishing (ignore NULL dates, set updatedAt,
  type-safe predicates)
- Harden admin search API (LIKE escaping, query cap, per-user
  rate limit, round-robin result cap) and fix search dialog
  abort/res.ok/loading races
- Lock down HTML sanitizer to an allowlist profile and add XSS tests
- Improve mobile nav accessibility (unique id, dialog role, focus
  management, scroll lock, outside close)
- Log swallowed server errors instead of silent catch blocks
- Remove dead eslint config, drop unused dompurify deps, restore knip
  CI step, add Playwright config with smoke spec
This commit is contained in:
openhands committed 2026-09-04 13:04:08 +02:00
1 parent 61769e355b
commit 399c047515
20 files changed
+435 -147

No files matched your search

+47 -22
View File
@@ -52,9 +52,6 @@ importers:
croner:
specifier: 10.0.1
version: 10.0.1
dompurify:
specifier: 3.4.14
version: 3.4.14
drizzle-orm:
specifier: 0.45.2
version: 0.45.2([email protected](@types/[email protected]))
@@ -96,13 +93,13 @@ importers:
version: 3.24.2(@types/[email protected])
next:
specifier: 16.3.4
version: 16.3.4(@types/[email protected])([email protected]([email protected]))([email protected])
version: 16.3.4(@playwright/[email protected])(@types/[email protected])([email protected]([email protected]))([email protected])
next-auth:
specifier: 5.0.0-beta.32
version: 5.0.0-beta.32([email protected](@types/[email protected])([email protected]([email protected]))([email protected]))([email protected])
version: 5.0.0-beta.32([email protected](@playwright/[email protected])(@types/[email protected])([email protected]([email protected]))([email protected]))([email protected])
next-intl:
specifier: 4.14.1
version: 4.14.1(@swc/[email protected])([email protected](@types/[email protected])([email protected]([email protected]))([email protected]))([email protected])
version: 4.14.1(@swc/[email protected])([email protected](@playwright/[email protected])(@types/[email protected])([email protected]([email protected]))([email protected]))([email protected])
otplib:
specifier: 13.5.0
version: 13.5.0
@@ -140,6 +137,9 @@ importers:
'@biomejs/biome':
specifier: 2.5.11
version: 2.5.11
'@playwright/test':
specifier: ^1.62.1
version: 1.62.1
'@tailwindcss/forms':
specifier: 0.5.11
version: 0.5.11([email protected])
@@ -149,9 +149,6 @@ importers:
'@tailwindcss/typography':
specifier: 0.5.20
version: 0.5.20([email protected])
'@types/dompurify':
specifier: ^3.2.0
version: 3.2.0
'@types/node':
specifier: 26.4.0
version: 26.4.0
@@ -1283,6 +1280,11 @@ packages:
'@pinojs/[email protected]':
resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==}
'@playwright/[email protected]':
resolution: {integrity: sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==}
engines: {node: '>=20'}
hasBin: true
'@radix-ui/[email protected]':
resolution: {integrity: sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==}
@@ -1782,10 +1784,6 @@ packages:
'@types/[email protected]':
resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
'@types/[email protected]':
resolution: {integrity: sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==}
deprecated: This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed.
'@types/[email protected]':
resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}
@@ -2243,6 +2241,11 @@ packages:
react-dom:
optional: true
[email protected]:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
[email protected]:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -2739,6 +2742,16 @@ packages:
resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==}
hasBin: true
[email protected]:
resolution: {integrity: sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==}
engines: {node: '>=20'}
hasBin: true
[email protected]:
resolution: {integrity: sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==}
engines: {node: '>=20'}
hasBin: true
[email protected]:
resolution: {integrity: sha512-NdTrKgh0oO7+y+RFX8KKhOB438x/j94UGXEFzl/7pHH0JjWSn42iJ9tgmPksIO6n1JKDHmNDcejPJfKspljB9g==}
@@ -3920,6 +3933,10 @@ snapshots:
'@pinojs/[email protected]': {}
'@playwright/[email protected]':
dependencies:
playwright: 1.62.1
'@radix-ui/[email protected]': {}
'@radix-ui/[email protected](@types/[email protected])([email protected])':
@@ -4287,10 +4304,6 @@ snapshots:
'@types/[email protected]': {}
'@types/[email protected]':
dependencies:
dompurify: 3.4.14
'@types/[email protected]': {}
'@types/[email protected]':
@@ -4615,6 +4628,9 @@ snapshots:
react: 19.2.8
react-dom: 19.2.8([email protected])
[email protected]:
optional: true
[email protected]:
optional: true
@@ -4970,15 +4986,15 @@ snapshots:
dependencies:
content-type: 2.1.0
[email protected]([email protected](@types/[email protected])([email protected]([email protected]))([email protected]))([email protected]):
[email protected]([email protected](@playwright/[email protected])(@types/[email protected])([email protected]([email protected]))([email protected]))([email protected]):
dependencies:
'@auth/core': 0.41.3
next: 16.3.4(@types/[email protected])([email protected]([email protected]))([email protected])
next: 16.3.4(@playwright/[email protected])(@types/[email protected])([email protected]([email protected]))([email protected])
react: 19.2.8
[email protected]: {}
[email protected](@swc/[email protected])([email protected](@types/[email protected])([email protected]([email protected]))([email protected]))([email protected]):
[email protected](@swc/[email protected])([email protected](@playwright/[email protected])(@types/[email protected])([email protected]([email protected]))([email protected]))([email protected]):
dependencies:
'@eloqnt/config': 0.0.2
'@eloqnt/format-json': 0.0.3
@@ -4988,14 +5004,14 @@ snapshots:
'@swc/core': 1.16.1(@swc/[email protected])
icu-minify: 4.14.1
negotiator: 1.1.0
next: 16.3.4(@types/[email protected])([email protected]([email protected]))([email protected])
next: 16.3.4(@playwright/[email protected])(@types/[email protected])([email protected]([email protected]))([email protected])
next-intl-swc-plugin-extractor: 4.14.1
react: 19.2.8
use-intl: 4.14.1([email protected])
transitivePeerDependencies:
- '@swc/helpers'
[email protected](@types/[email protected])([email protected]([email protected]))([email protected]):
[email protected](@playwright/[email protected])(@types/[email protected])([email protected]([email protected]))([email protected]):
dependencies:
'@next/env': 16.3.4
'@swc/helpers': 0.5.23
@@ -5014,6 +5030,7 @@ snapshots:
'@next/swc-linux-x64-musl': 16.3.4
'@next/swc-win32-arm64-msvc': 16.3.4
'@next/swc-win32-x64-msvc': 16.3.4
'@playwright/test': 1.62.1
sharp: 0.35.4(@types/[email protected])
transitivePeerDependencies:
- '@babel/core'
@@ -5137,6 +5154,14 @@ snapshots:
sonic-boom: 4.2.1
thread-stream: 4.2.0
[email protected]: {}
[email protected]:
dependencies:
playwright-core: 1.62.1
optionalDependencies:
fsevents: 2.3.2
[email protected]: {}
[email protected]: {}