Repository navigation
Version 2.1.0; macOS package runs on every Apple Silicon chip (M1 to M5 and later) - #23
Merged
Merged
Conversation
- images_to_pdf: compute the image rect ourselves (PyMuPDF's keep_proportion stretched square images over the A4 box) and add a placement option: fit / fill (crop) / stretch / original size. - Tool grid: tint tools usable on the selection pastel green, move them and their groups to the front, row-major layout; user-pinned favourites row. - Shortcuts dialog: up to four columns so it fits on screen. - SchemaForm: show_if accepts a list of values. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
- Files and jobs belong to an owner (this machine, or one paired device); other devices get 404. Owner ids are hashes, never the session cookie. - A loopback request carrying proxy forwarding headers is treated as remote, so a local reverse proxy cannot make the LAN 'local'. - Pairing: keys under 12 characters refused at start-up, a global attempt limit on top of the per-client one, bounded limiter memory, sessions expire after 30 days and are capped. - LibreOffice runs with a throwaway hardened profile: no macros or active content, links never updated, no recalculation on load, all network traffic sent to a dead proxy (tests cover SSRF and local file includes). - API responses are no-store; extra security headers; uvicorn Server header off; /api/docs off unless APT_API_DOCS=true. - Storage cap (APT_MAX_STORAGE_MB, 507) and per-owner pending job cap (429); the sweeper no longer expires inputs of running jobs. - Docker trusts only the bridge gateway (APT_TRUSTED_NETWORKS=gateway), never in LAN mode; CI token is read-only. - pdfjs-dist 6.4.299 (GHSA-hq66-cqwq-w95j). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
Optionally rebuild the redacted document from page images only (no text, fonts, objects, annotations, attachments or metadata survive), so nothing under a treatment can be recovered by any tool. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
- HTTPS on by default with the server's own name-constrained local CA (private addresses and local names only, so a leaked key cannot vouch for real websites); the server certificate follows LAN address changes. TLS 1.2+, ECDHE + AEAD ciphers; HSTS only for DNS names. - Clients outside the local network (public addresses) are always refused; APT_TRUSTED_NETWORKS may only list local ranges. - --trust-ca and a one-time OS trust prompt on desktop start; public /api/session/ca.crt for devices; 'Connect device' dialog on the server PC with a pairing QR code (segno) and the CA fingerprint. - Mobile: compact header, scrollable viewer modes, KVKK findings usable on phones, no keyboard hints on touch, 40 px touch targets, no iOS zoom on input focus; opaque KVKK preview boxes. - Docker health check, CI and release smoke tests over verified HTTPS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
The Windows package now ships Tesseract with tur/eng/osd data in ocr/, so OCR works on PCs whose network blocks downloads. Sources are pinned in scripts/ocr/sources.json (SHA-256 enforced when set) and the installer's signature is reported at build time; ocr/manifest.json records the SHA-256 of every bundled file, the app re-checks it before use and refuses a damaged or altered bundle. 'OCR Onar (Windows).bat' repairs language data only with files matching those hashes; install-ocr-windows.ps1 verifies pinned hashes too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
- AdminPDFToolkit.exe (C# 5 WinForms, built with the Windows csc): ticks off every component via python -m adminpdf.selfcheck, starts the server with no console window, shows addresses and the certificate fingerprint, network-sharing switch, notification-area icon. Version info and asInvoker manifest; Authenticode signing when the WINDOWS_SIGN_PFX secret is set. .bat files move to scripts\. - python -m adminpdf.updater: optional update check; installs only releases whose Ed25519-signed SHA256SUMS verifies, matching hash, never a downgrade, zip-slip safe; data\ is kept. Release workflow writes SHA256SUMS(.sig) and release-manifest.json (scripts/release_signing.py). - Ghostscript bundled in gs\; Tesseract and Ghostscript resolved to their newest release at build time and verified against GitHub's published SHA-256; Ghostscript's source tarball is published with the release. - CI compiles the launcher on Windows with /warnaserror. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
- Certificates: cap the common name at 64 characters (long computer names broke certificate creation, seen on macOS runners). - Tests: no POSIX mode check on Windows; a LibreOffice that refuses the crafted documents outright also passes (nothing leaks). - Windows package: unpack the Tesseract / Ghostscript NSIS installers with 7-Zip instead of a silent install (which re-launched elevated and returned before any file existed); pin Tesseract to its newest release v5.4.0.20240606 by SHA-256. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
The start-up banner contains Turkish letters that cp1252 cannot encode; the server died before listening when started from a .bat on such a PC. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
- python -m adminpdf.launcher: the Windows launcher's window in Tk — component checklist, server without a terminal (own process group), network sharing, update notice, data in the user's folder (macOS may run downloaded apps from a read-only location). - scripts/build_unix_portable.py: python-build-standalone (SHA-256 checked) + the app; Linux x86_64 tar.gz with a menu-entry script, macOS arm64 AdminPDFToolkit.app, ad-hoc signed (no paid Apple account; 'Open Anyway' once). Release CI builds and smoke-tests both. - Updater looks for the package of the running system; in-place install stays Windows-only. Self-check shows brew / apt / dnf commands for a missing Tesseract or Ghostscript. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
- In-app "Hakkında ve Lisanslar / About & Licences" dialog with separate Turkish and English tabs: supported systems, first-start warnings, every installed Python package (direct and transitive, from metadata), web bundle npm packages, bundled tool files with SHA-256 sources, programs, runtimes, fonts, data, build tools and methods (/api/about). - scripts/third_party.py replaces python_licenses.py and writes THIRD_PARTY_LICENSES.md as a full Turkish part then a full English part. - Windows SmartScreen, certificate prompt, firewall, macOS Gatekeeper, keychain and browser/phone certificate warnings documented on the README main page, release notes, OKUBENI files and in the app. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
- scripts/virustotal.py (standard library): uploads the packages and the launcher exe to VirusTotal with a free API key (secret VIRUSTOTAL_API_KEY), or looks them up by SHA-256; paces itself to the free 4-per-minute limit; writes a TR/EN Markdown table and virustotal.json. Skips without a key and never fails the release. - release.yml: virustotal job between the builds and publish; its table goes into the release notes and the step summary, virustotal.json is published with the release. - README: "Güvenlik / Security" badge row (VirusTotal results of the latest release via shields.io, HTTPS, LAN only, signed updates, verified bundles, CSP, code signing). SECURITY.md and CHANGELOG. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
…ut a web build - mypy: named function instead of a lambda returning CompletedProcess; the os.startfile ignore is no longer unused on Windows. - test_stream_json_runs_the_selfcheck: CI has no web build, so the self-check is not "ready" there; assert the exit code matches the streamed result instead of requiring 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
…Brand links - Highlights (TR/EN): extra-secure KVKK PDF, image-to-PDF page size and placement, HTTPS + LAN-only + per-device isolation, green/first tools and favourites, phone/tablet QR, in-app About & Licences. - Phones/tablets: the launcher's Network sharing switch (the old 'Baslat - Ag Paylasimi (Windows).bat' no longer exists). - English install: macOS / Linux packages; launcher row in the stack; 350+ tests, VirusTotal and signed SHA256SUMS; APT_OCR_DIR/APT_GS_DIR. - Roadmap: portable packages, HTTPS/LAN pairing, signed updates and VirusTotal done; MSI installer left open. D Brand: public sibling repos. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
…arning - README Installation: numbered macOS steps with the exact Gatekeeper message (incl. macOS 15 wording), Done (not Move to Trash) > Privacy & Security > Open Anyway, xattr alternative, keychain password, brew; numbered Linux steps with the browser certificate import and apt/dnf. Same in the English part. - Launcher menu names as they are in the app. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
- security.default_gateway reads /proc/net/route with Path.read_text (file always closed). - launcher: say why each ignored OSError is safe to ignore. - selfcheck: one import style for importlib. - third_party / virustotal: explicit parentheses around intentionally joined strings in lists. - test_security: requests made before the assert, not inside it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
On a slow macOS runner the server had not printed its banner after 6 s. Read stdout line by line in a thread and wait up to 90 s for the banner (or the process ending); stderr goes to a file so the pipe cannot fill. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
…ter) The arm64 package is the same for all Apple Silicon Macs; "M1–M4" read as if M5 were unsupported. README, release notes, OKUBENI, About page and THIRD_PARTY_LICENSES.md now say M1 and later. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
v2.0.0 is already published; everything since (HTTPS and local-network only, self-contained Windows / macOS / Linux packages with launchers, signed updates, VirusTotal, About & Licences) becomes 2.1.0. Version in config.py, pyproject.toml, web/package.json (npm version), README badge; CHANGELOG [Unreleased] -> [2.1.0] with compare links. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
AmrasElessar
enabled auto-merge (squash)
October 26, 2026 11:47
Twice today a Linux server job sat for 20+ minutes in 'System tools (Linux)' while the same step took 20 s on its siblings. Each apt call now has a timeout and network timeouts, up to three attempts (dpkg repaired between them), the man-db rebuild is skipped, the step is capped at 20 minutes, and it ends by checking that every tool is installed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
The release workflow signs SHA256SUMS with RELEASE_SIGNING_KEY; the app now carries the matching Ed25519 public key, so a verified update can be installed in place instead of only being announced. Checked with a throwaway SHA256SUMS signed by the new private key. Tests: the "no key configured" case clears the key explicitly; new test that the built-in key is a valid Ed25519 public key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
- The Ubuntu mirror served LibreOffice at a few tens of KB/s and three 6-minute attempts were not enough. Downloaded .deb files now go into the Actions cache (one key per runner image), downloads are kept between attempts, and each attempt may take up to 15 minutes. - pytest-xdist: one test worker per CPU (pytest -n auto). Locally the suite drops from 3 min 21 s to about 1 min, all 349 tests passing in three runs; the macOS job took 19 minutes serially. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
The runners' azure mirror served packages at ~100 KB/s and a 43 MB LibreOffice part did not finish in 6 minutes. LibreOffice is now installed only in the Python 3.13 Linux job (its tests skip elsewhere, as on Windows and macOS), the apt sources point at archive.ubuntu.com, and the package cache key includes the Python version so each job keeps its own package set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary / Özet
v2.0.0zaten yayımlı; o zamandan beri gelenler (HTTPS ve yalnızca yerel ağ, Windows / macOS / Linux paketleri ve başlatıcılar, imzalı güncellemeler, VirusTotal, Hakkında ve Lisanslar) 2.1.0 olur.config.py,pyproject.toml,web/package.json(+ lock,npm version), README rozeti; CHANGELOG[Unreleased]→[2.1.0].v2.0.0 is already published; everything since becomes 2.1.0, so the release workflow can publish a new tag.
arm64) tüm Apple Silicon çiplerinde aynıdır; "M1–M4" yerine "M1 ve sonrası (M5 dahil)": README, sürüm notları, OKUBENI, Hakkında sayfası, THIRD_PARTY_LICENSES.md.The arm64 package is the same for every Apple Silicon Mac; the docs now say M1 and later.
After merging: Actions ▸ Release ▸ Run workflow on
mainwith publish ticked createsv2.1.0.Type of change / Değişiklik tipi
Checklist
cd server && ruff check . && ruff format --check . && mypy adminpdf && pytest) — 348 passed / 11 skipped locallycd web && npm run check && npm run build) — only the version field changedCHANGELOG.mdunder[Unreleased]Field(tr=, en=)/t("tr", "en"))README.mdif applicable)Linked issues / Bağlı issue'lar
—
Screenshots (UI changes only)
—
Test plan / Test planı
scripts/release_notes.py 2.1.0prints the 2.1.0 CHANGELOG section; THIRD_PARTY_LICENSES.md up to date (--check).🤖 Generated with Claude Code
https://claude.ai/code/session_01SgNH4tzUdde2tgUEgsfWxD