Calendar Day
Monday, June 9, 2026
Planned Effort
8 story points (one PR) — combines sprint items #1 + #5:
| Sprint item |
Points |
Topic |
| #1 |
5 |
Add linter (ruff) + dependency security scanner (pip-audit) to CI |
| #5 |
3 |
SECURITY.md + vulnerability reporting channel |
Out of scope this issue: macOS matrix (Wednesday #6), TypedDict parse boundary (Tuesday #3), export partial-failure surfacing (Tuesday #2).
Problem
- Verification gap: CI enforces mypy strict mode and 60% coverage but runs no linter and no dependency vulnerability scanner. Style regressions and known-vulnerable packages are not caught automatically.
- Security process gap: Runtime controls are strong (DOMPurify, path guards, debug host guard) but there is no
SECURITY.md and no documented private reporting channel for external researchers.
Goal
One merged PR that:
- Runs
ruff check and pip-audit on every CI run for ubuntu-latest and windows-latest (existing matrix).
- Fixes existing ruff violations without blanket suppressions.
- Publishes
SECURITY.md with GHSA reporting, response timeline, and project-specific scope.
Scope
A — Ruff + pip-audit CI (5 pt)
Touch points: .github/workflows/ci.yml, pyproject.toml, requirements-dev.txt, utils/, routes/
-
Add to requirements-dev.txt:
ruff>=0.9.0
pip-audit>=2.7.0
-
Add [tool.ruff] to pyproject.toml:
[tool.ruff]
target-version = "py312"
[tool.ruff.lint]
select = ["E", "F", "W", "I"]
-
Add CI job (or equivalent steps on matrix jobs):
- run: ruff check .
- run: pip-audit -r requirements.txt
-
Run on ubuntu-latest and windows-latest (same OS dimension as pytest).
-
Fix all existing violations before merge — no file-wide # noqa to bypass the gate.
-
pip-audit targets production requirements.txt (Flask + transitive deps).
B — SECURITY.md + reporting channel (3 pt)
Touch points: SECURITY.md (new), README.md
- Create root
SECURITY.md with:
- Supported versions — pre-release: latest
master only
- Report via GitHub Security Advisories (private) with link to advisories UI
- Response timeline (acknowledge + target fix window)
- In-scope: path traversal (
safe_join), XSS in rendered content, export integrity, local file boundaries, debug exposure
- Out-of-scope: intentional network-facing deployment (local-only tool)
- Enable Private vulnerability reporting on the GitHub repo (or document admin blocker).
- Link
SECURITY.md from README.md.
Acceptance Criteria
Calendar Day
Monday, June 9, 2026
Planned Effort
8 story points (one PR) — combines sprint items #1 + #5:
Out of scope this issue: macOS matrix (Wednesday #6), TypedDict parse boundary (Tuesday #3), export partial-failure surfacing (Tuesday #2).
Problem
SECURITY.mdand no documented private reporting channel for external researchers.Goal
One merged PR that:
ruff checkandpip-auditon every CI run forubuntu-latestandwindows-latest(existing matrix).SECURITY.mdwith GHSA reporting, response timeline, and project-specific scope.Scope
A — Ruff + pip-audit CI (5 pt)
Touch points:
.github/workflows/ci.yml,pyproject.toml,requirements-dev.txt,utils/,routes/Add to
requirements-dev.txt:Add
[tool.ruff]topyproject.toml:Add CI job (or equivalent steps on matrix jobs):
Run on
ubuntu-latestandwindows-latest(same OS dimension as pytest).Fix all existing violations before merge — no file-wide
# noqato bypass the gate.pip-audittargets productionrequirements.txt(Flask + transitive deps).B — SECURITY.md + reporting channel (3 pt)
Touch points:
SECURITY.md(new),README.mdSECURITY.mdwith:masteronlysafe_join), XSS in rendered content, export integrity, local file boundaries, debug exposureSECURITY.mdfromREADME.md.Acceptance Criteria
ruff checkruns in CI on all matrix entries (ubuntu-latest,windows-latest) and passes with zero violationsruffconfiguration inpyproject.tomlwith at least E, F, W, I rulespip-auditruns in CI and fails the build on known-vulnerable production dependenciesnoqa)SECURITY.mdexists with supported versions, reporting path, timeline, and scopeREADME.mdlinks toSECURITY.mdpytest -q,mypy, andnpm testpass in CI