Changelog¶
0.1.7 - 2026-08-23 - Security audit (static + dynamic, cross-checked with Codex CLI)¶
Findings from a fresh audit, verified with hands-on repro (not just static review) and cross-checked against an independent codex exec review; see individual items below.
- Engine: fixed an algorithmic-complexity DoS in text diffing — a PDF page repeating a handful of short tokens tens of thousands of times took 77s in
_changed_words'sdifflib.SequenceMatchercall (measured); a crafted few-hundred-KB upload could pin a CPU core well past the request timeout. Fixed with a cost-aware junk filter (_bounded_isjunkintext_diff.py) that closes this without reintroducing the CJK-diff-quality regressionautojunk=Truewould cause. - Engine: text extraction (
_page_words) no longer forces PyMuPDF to decode every image on the page (TEXT_PRESERVE_IMAGES) just to discard it — a PDF reusing one large image across many pages took 5.7s/132MB per comparison, 0.01s after the fix (measured, 568x), with no change to the extracted text. - Engine:
_scrub_active_contentnow also strips/OpenAction//AAfrom the document catalog, every page, and every form-field widget (doc.scrub()'sjavascript=Trueonly clears the action type on indirect objects it walks, not a direct/inline action dict or page-/widget-level additional-actions), and dropsjavascript:-scheme link URIs. New tests reproduce each gap directly (and fail against the pre-fix code). - Dependencies: raised floors to exclude versions with known CVEs reachable through kogo's own code paths —
PyMuPDF>=1.27.1(CVE-2026-3308, heap out-of-bounds write via crafted PDF image data),python-multipart>=0.0.30(three DoS advisories in multipart/querystring parsing), and an explicitstarlette>=0.40,<2floor (CVE-2024-47874, unbounded multipart form-field buffering) for what was previously an undeclared transitive dependency. - Web app: the
/api/compareconcurrency limit is now enforced by middleware, before Starlette parses the multipart upload, instead of after — previously, arbitrarily many concurrent requests could each buffer close to the request-size limit beforeMAX_CONCURRENT_JOBSever applied. - Web app:
MAX_RENDER_PIXELSlowered from 40M to 24M pixels, so two concurrent worst-case visual diffs leave comfortable headroom underdocker-compose.yml's default 2 GB memory limit. - Web app: the operator-set
KOGO_SOURCE_URLis now HTML-escaped before being templated into the footer link (hardening; not attacker-reachable in the normal threat model). - Project: added
ROADMAP.mditem for a global job-storage quota;MAX_PAGES/timeout/thread-abandonment limitations noted in earlier releases and ROADMAP item 12 remain tracked as-is — this pass's engine fixes remove the two cheapest ways to create a long-running job in the first place. - CI/CD: added
pip-audit(0 findings against kogo's actual dependencies), a Trivy container scan, CodeQL, anddependency-review-actionon PRs — no AI-based tooling, all traditional static analysis / CVE database lookups. Releases now attach a CycloneDX SBOM. Enabled Dependabot vulnerability alerts (were off)..trivyignoredocuments the first scan's non-actionable findings (a metadata artifact and a vulnerability vendored inside pip's own bundled wheel, neither reachable via kogo, plus base-image OS packages with no fix published upstream yet) with an expiry date to force periodic re-review rather than ignoring them permanently.
0.1.6 - 2026-08-23 - Library API round-out & project infrastructure¶
- Library API:
compare_pdfsreturn type is now the typedComparisonResult(and nestedFiles/Settings/Summary/Legend/Artifacts/ArtifactInfo/Row/RowChanges/PageRef)TypedDicts, exported fromkogofor IDE/type-checker support. Runtime shape is unchanged. - Library API: new
artifacts: bool = Truekeyword — set toFalseto skip baking/saving the marked PDFs (and_comparison_pdf) when only the JSON summary is needed, e.g. in a CI step;result["artifacts"]isNonein that case. - Library API: new
on_progresskeyword — an optional(phase, current, total)callback invoked as a comparison runs ("aligned","comparing"per row,"rendering","previews").kogo diffnow shows row-by-row progress on stderr when not run with--json. - Project: added GitHub issue/PR templates,
CODE_OF_CONDUCT.md, enabled Discussions, and set the repo homepage. - Project: added a documentation site (
docs-src/, mkdocs-material + mkdocstrings) published at kogo.tatu-sec.dev/manual/, alongside the existing docstrings and README.
0.1.5 - 2026-08-23 - Maintainability & supply-chain hardening¶
- Internal: split engine.py into the kogo.engine package (words/alignment/text_diff/visual_diff/annotations/render/compare). Public API unchanged.
- Dockerfile: base images pinned by digest (node:26-alpine, python:3.14-slim)
- Dependencies: major-version upper bounds added (PyMuPDF<2, numpy<3, opencv-python-headless<5, fastapi<1, uvicorn<1, python-multipart<1)
0.1.4 - 2026-08-23 - Security hardening release¶
Findings from an internal security/code audit; see individual items below.
- Active PDF content (JavaScript,
/OpenAction, embedded/attached files, andLaunch/GoToR-class link actions) is now stripped from both input documents before any processing, so a malicious uploaded PDF can no longer be re-baked and redistributed through the output PDFs (A1) /api/comparenow rejects oversized request bodies byContent-Lengthbefore Starlette buffers them, and wraps the comparison in a configurable wall-clock timeout (JOB_TIMEOUT_SECONDS, default 900s) so a pathological upload can no longer permanently exhaust the concurrency semaphore (A2)- Page rendering (visual diff and previews) is now clamped to a 40-megapixel budget, mirroring the existing page-signature safeguard, preventing multi-gigabyte allocations from PDFs with oversized page boxes (A3)
docker-compose.ymlnow setsmem_limit,cpus, andpids_limitas a resource backstop for the native PDF/image parsers (A4)kogo fetch-viewernow verifies a pinned SHA-256 checksum of the downloadedpdfjs-disttarball and rejects any tar member that would extract outside the destination directory (A5)- The web app footer and
kogo servestartup banner now read the "Source code" link fromKOGO_SOURCE_URL, so operators of a modified deployment can point it at their own fork to satisfy AGPL-3.0 §13 (A6) - Added baseline security response headers (
X-Content-Type-Options,Referrer-Policy,Content-Security-Policy) to every response (A7) - Job directories are now created after acquiring the processing semaphore rather than before (A8)
- GitHub Actions in
ci.yml/pages.yml/publish.ymlare now pinned to commit SHAs instead of mutable tags - Removed the dead, unused
_text_differenceshelper fromengine.py - New tests: oversized-page render clamping, active-content scrubbing regression,
fetch-viewerpath-traversal rejection, artifact allowlist rejection, and security headers presence
0.1.3 - 2026-08-23 - Library documentation¶
- Full docstring for
kogo.compare_pdfs(usable viahelp()and IDEs) py.typedmarker: the package is now PEP 561 typed- Project site: API result-structure table added (EN/JA)
0.1.2 - 2026-08-23 - Project site, PyPI page fix¶
- Project website published (GitHub Pages): https://portfolio.tatu-sec.dev/kogo/
- README screenshot now uses an absolute URL so it renders on the PyPI project page
0.1.1 - 2026-08-22 - Library API¶
- Export
compare_pdfsandComparisonErrorfrom the top-levelkogopackage soimport kogois enough to use the diff engine as a library compare_pdfsold_name/new_nameare now optional and default to the input file names
0.1.0 - 2026-08-22 - Initial release¶
Initial release of kogo. The project was formerly prototyped under the name "byobu"; it was renamed before PyPI publication to avoid collision with the existing byobu terminal multiplexer.
- Word-level text diff for Latin text, character-level diff for CJK text (including rare kanji across CJK Extensions B-J), with reading order reconstructed from page layout
- Similarity-based page alignment tolerant of inserted or removed pages
- Visual diff for figures, equations, and layout, with text areas masked out and registration for scanned pages
- Detection of added or removed highlights, comments, and ink annotations
- Style-change detection (bold, italic, font-size changes on otherwise-unchanged text)
- Markers baked into output PDFs so they show up in any viewer
- Web app with a selectable-text PDF.js preview, page-by-page diff view, and downloadable marked-up PDFs
- CLI (
kogo diff) for scripted comparisons - Docker image bundling the PDF.js viewer assets