ci: scan dependencies for new advisories and stop handing out a write token
Two things, both about not finding out late. No workflow declared `permissions`, so all eighteen jobs across the four workflows ran on a token with the default full repository scope. Every one of them only checks out code, and deploy reaches the cluster over SSH with the deploy key, and Renovate writes through its own bot PAT rather than the Actions token. So `contents: read` is all any of them needed. The panel image ships 15 known advisories and nothing was looking. Add a scan-deps job that fails on anything new, and record the eight current ones by ID in the workflow. It is a list rather than a baseline count so that the diff that accepts an advisory says so in words, and it lives in our workflow instead of the package manifest so a subtree sync from forust/userbot cannot quietly widen the exemption. Both halves were checked to fail on a regression, not just to pass today: removing one --ignore-vuln turns the Python step red, and dropping --audit-level to moderate turns the npm one red on the devalue advisory. npm audits production dependencies only. All seven findings in the full tree are build- or test-time: the esbuild advisory needs a vite dev server exposed to the internet, and nanoid's infinite loop needs a custom generator called with size 0, which postcss does not do. None are in the 91 kB bundle the panel serves, so failing on them would be noise that trains people to ignore the job. The starlette entries are the reason the job is not "fail on everything": fastapi 0.115.12 pins starlette<0.47.0 and the last four fixes need 0.49.1 through 1.3.1, so clearing them is a jump to fastapi 0.141.x and is upstream's call, not a drive-by. Four of the seven are reachable in principle, which the comment on the job sets out. The panel answers only on userbot.workstation.internal with no public route, which is what keeps those four from being an internet-facing DoS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
30995ee009
commit
baedea504d
8 files changed
+110
-1
No files matched your search
@@ -7,6 +7,12 @@ on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
# Every job here is checkout plus local tools. The token needs to read the tree
|
||||
# and nothing else, and saying so keeps a future step that reaches for the API
|
||||
# from quietly holding a token that can write to the repository.
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||
@@ -191,6 +197,70 @@ jobs:
|
||||
|
||||
hadolint -c .hadolint.yaml "${dockerfiles[@]}"
|
||||
|
||||
# Known, accepted, and recorded. Each line is a real advisory against a
|
||||
# package we build into the panel image, kept in this workflow rather than in
|
||||
# the package manifest so that a subtree sync from forust/userbot cannot
|
||||
# silently widen the exemption.
|
||||
#
|
||||
# starlette is the reason this job is not simply "fail on everything":
|
||||
# fastapi 0.115.12 pins `starlette<0.47.0`, and the fixes for the last four
|
||||
# below need 0.49.1 through 1.3.1, so clearing them means a jump from fastapi
|
||||
# 0.115.12 to 0.141.x. That is upstream's call, not a drive-by in a lint
|
||||
# commit. Of the seven, four are reachable here in principle: 1942 is a
|
||||
# crafted Range header hitting FileResponse, and the panel serves its built
|
||||
# SPA through exactly that; 249 is request.form() ignoring max_fields for
|
||||
# x-www-form-urlencoded, which is the login form; 1941 is a large multipart
|
||||
# body blocking the event loop; 161 and 248 are unvalidated Host and request
|
||||
# path reaching request.url. 2280 needs HTTPEndpoint, which the panel does
|
||||
# not use, and 2281 is Windows-only, and this deploys on Linux.
|
||||
#
|
||||
# The panel answers on userbot.workstation.internal and has no public
|
||||
# forust.xyz route, which is what keeps the four reachable ones from being
|
||||
# an internet-facing DoS. It still manages Telegram credentials.
|
||||
#
|
||||
# Deleting an entry here is how you accept a new advisory, so the diff says
|
||||
# so out loud.
|
||||
scan-deps:
|
||||
runs-on: [self-hosted, linux, arch, homelab]
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
|
||||
- name: Audit the Python dependencies that ship in the image
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tools_dir="$(bash .gitea/workflows/install-ci-tools.sh pip-audit)"
|
||||
export PATH="$tools_dir:$PATH"
|
||||
# requirements.txt, not requirements-dev.txt: this is what the image
|
||||
# installs, and the test tooling is not a shipped attack surface.
|
||||
pip-audit -r userbot/panel/backend/requirements.txt --strict \
|
||||
--ignore-vuln CVE-2025-67720 \
|
||||
--ignore-vuln PYSEC-2026-161 \
|
||||
--ignore-vuln PYSEC-2026-1941 \
|
||||
--ignore-vuln PYSEC-2026-1942 \
|
||||
--ignore-vuln PYSEC-2026-2280 \
|
||||
--ignore-vuln PYSEC-2026-2281 \
|
||||
--ignore-vuln PYSEC-2026-248 \
|
||||
--ignore-vuln PYSEC-2026-249
|
||||
|
||||
# devDependencies are excluded on purpose. `npm audit` on the full tree
|
||||
# reports 7 findings, and every one of them is a build- or test-time
|
||||
# package: the esbuild CORS advisory needs a vite dev server serving to
|
||||
# the internet, and nanoid's infinite loop needs a custom generator
|
||||
# called with size 0, which postcss does not do. None of them are in the
|
||||
# 91 kB bundle the panel serves. The one production finding, devalue
|
||||
# via svelte, is moderate, which is where --audit-level draws the line;
|
||||
# this fails on the next high or critical one.
|
||||
- name: Audit the production npm dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd userbot/panel/frontend
|
||||
npm ci
|
||||
npm audit --omit=dev --audit-level=high
|
||||
|
||||
test-backend:
|
||||
runs-on: [self-hosted, linux, arch, homelab]
|
||||
timeout-minutes: 15
|
||||
|
||||
Reference in new issue
Block a user