Repository navigation
feat(windows): make every conversion work in a per-user Windows installer - #6
Conversation
CNV-10 Make every conversion work in the Windows build
ProblemOn Windows 11 the CLI builds and most conversions work: PNG to JPG, PNG to WebP, JPG to AVIF, SVG to PNG, MP4 and MOV to WebM, MP4 to MP3, WAV to FLAC, and a two-page PDF to PNG. Two kinds fail with
The Windows release payload can't be built either. GoalA Windows build where every conversion the Mac and Linux builds offer works, packaged as an installer. Acceptance criteria
How to verifyOn a Windows 11 machine, build with |
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 2 advisory finding(s) below merit a look before merge.
Graphify review — findings
Enables executable document packs on Windows by replacing the "not supported" bail with fail-closed ACL ownership checks (windows_acl::trusted) on the pack root, its ancestors, and the parent of any missing component; a bundle:documents.tar.gz source now resolves to a pack shipped next to the executable. Restricts libheif's dependent DLL search to its own directory plus System32, so the working directory and PATH are never consulted. Passes LibreOffice a proper file URL for its private profile and an absolute input path, so concurrent jobs can't fall back to the shared default profile; release dry runs call build.ps1 -VerificationOnly.
Worth a look
- Bundled document-pack URL built by string formatting instead of a proper file URL —
crates/convt-engines/src/packs.rs:31· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- TrustedInstaller owner exception is not applied to ACL allow ACEs —
crates/convt-engines/src/windows_acl.rs:184· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Review partial — this diff was larger than one review pass covers, so later files were not reviewed; some findings may be missing.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 285 functions depend on the 277 functions this change touches.
Health — this change adds coupling hotspots:
- new:
install_at_with()— 5 callers, 14 callees - new:
validate()— 5 callers, 6 callees - new:
remove_at()— 4 callers, 7 callees - new:
encoded_fixture()— 6 callers, 3 callees - new:
encode_depth()— 2 callers, 7 callees - new:
rgb_to_srgb_matrix()— 3 callers, 4 callees - new:
pack()— 1 callers, 6 callees - new:
full_matrix()— 0 callers, 10 callees - …and 6 more — each is listed as a finding
Verification — 285 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 285 function(s) in the blast radius were not formally verified this run
Risky patterns (advisory)
- medium
no-stderr-to-stdoutinpackaging/windows/build.ps1:31: stderr redirected to stdout: $BuildConfig = & "$Out/ffmpeg.exe" -buildconf 2>&1
Docs that may be stale (advisory)
.agents/skills/test-convt-cli/SKILL.md§ Automated tests (lines 200-237): references changed symbolstrusteddocs/update-integration.md§ Use the offline update verifier in P8 (lines 1-21): references changed symbolstrustedpackaging/release/macos-source-notes.md§ AV1 decoder rebuild (lines 30-49): references changed symbolstrusted
· 14 more finding(s) on lines outside this diff (see the check run).
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A low-integrity process can write to an object labelled low even when its DACL names only our user, so the pack check now reads the mandatory label too and refuses anything below medium. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d2f41c7 to
bb5dd6b
Compare
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| & $CMake -S (Join-Path $Source $Subdir) -B $Build -G $Generator -A x64 "-DCMAKE_INSTALL_PREFIX=$Prefix" "-DCMAKE_PREFIX_PATH=$Prefix" -DCMAKE_INSTALL_LIBDIR=lib @Options | ||
| if ($LASTEXITCODE -ne 0) { throw "Configure $Name" } |
There was a problem hiding this comment.
If cmake.exe on PATH is CMake 4, this configure step fails on the pinned x265 3.5 source. It selects old policies that CMake 4 removed. The Linux and macOS recipes already fix those policies, but this recipe omits that fix and CMAKE_POLICY_VERSION_MINIMUM. The build stops before producing the payload or MSI.
Apply the same compatibility changes, or explicitly require CMake 3 before starting the build. Certainty: 4/5.
| archive.addfile(info, stream) | ||
| else: | ||
| archive.addfile(info) | ||
| print(hashlib.file_digest(output.open('rb'), 'sha256').hexdigest()) |
There was a problem hiding this comment.
If the builder runs with Python 3.10, hashlib.file_digest raises AttributeError after writing the archive. That function requires Python 3.11, but the Windows instructions only require Python 3. build.ps1 then stops without compiling the app or producing an MSI.
Use a digest loop that works on the supported Python versions, or require and check Python 3.11 before starting the build. Certainty: 5/5.
| print(hashlib.file_digest(output.open('rb'), 'sha256').hexdigest()) | |
| digest = hashlib.sha256() | |
| with output.open('rb') as stream: | |
| for chunk in iter(lambda: stream.read(1024 * 1024), b''): | |
| digest.update(chunk) | |
| print(digest.hexdigest()) |
| .or_else(|| { | ||
| (name == "python3") | ||
| .then(|| which::which("python").ok()) | ||
| .flatten() | ||
| }) |
There was a problem hiding this comment.
Python 2 breaks optional tests
If a host has only Python 2 under the name python, the new fallback makes tool("python3") succeed instead of letting the matrix skip its Python-dependent checks. The fixture's f-strings fail to parse, and native_validators then panics during discovery.
This is a non-blocking test issue. Check the fallback's Python version before returning it so hosts without Python 3 still skip these checks. Certainty: 5/5.
| .or_else(|| { | |
| (name == "python3") | |
| .then(|| which::which("python").ok()) | |
| .flatten() | |
| }) | |
| .or_else(|| { | |
| (name == "python3") | |
| .then(|| which::which("python").ok()) | |
| .flatten() | |
| .filter(|path| { | |
| Command::new(path) | |
| .args([ | |
| "-c", | |
| "import sys; sys.exit(0 if sys.version_info >= (3, 6) else 1)", | |
| ]) | |
| .status() | |
| .is_ok_and(|status| status.success()) | |
| }) | |
| }) |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ow checks ACLs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
On Windows, HEIC and Office files failed with
no_route: libheif wasn't shipped, and the document pack refused to install because its ownership checks only understood Unix permissions. There was also no installer, becausebuild.ps1stopped on an empty input lock. This branch pins every native input, builds a per-user MSI, and gets every conversion working from the installed app.Evidence
All of this was run on a Windows 11 PC (leopc), against the MSI built from this branch, with nothing on PATH except the installed app.
heic -> jpganddocx -> pdfexited 1 withno_route;build.ps1threwWindows release blocked;installer.ps1threwBuild audited payload first.msiexec /i(per-user, no elevation): exit 0.convt engineslistsimage, svg, libheif, ffmpeg, pdfium, libreoffice.cargo test -p convt-engines --test matrix full_matrixagainst the installed CLI: 421 of 421 cases, 0 errors (161 image, 192 video, 42 audio, 13 SVG, 13 PDF), including HEIC in and out, multi-page PDF, and transparent PNG to JPG on white..doc,.odt,.docx,.pptxand.xlsxeach produced a valid%PDF-file.convt targets --menu:docx: pdf txt,pptx: pdf,xlsx: pdf csv.msiexec /x: exit 0. The CLI, app, Start menu shortcut and registry key are gone; user data and the document pack are kept.windows_acl::tests6/6 (including a new test that marks a file low-integrity withicacls /setintegritylevel low) andpacks::20/20.cargo test -p convt-core -p convt-engines -p convt-clipasses andbun run rs:checkis clean.A GPT-6.1 Sol review found one blocker: pack files labelled below medium integrity were accepted, so a sandboxed low-integrity process could swap a DLL that LibreOffice then loads. It's fixed in 26100c7. The real installed pack still passes the check and converts DOCX to PDF.
Not tested:
Merge Danger
Door: two-way. Nothing is published or signed; reverting removes the Windows packaging.
Blast radius: Windows builds and the document-pack checks.
packs.rsis shared, but its Unix path is unchanged and the Linux pack tests pass. The FFmpeg input is gyan.dev's GPLv3 "essentials" build, so the release licence and source-closure work tracked separately still has to clear it before public distribution. The MSI is unsigned.Fixes CNV-10
Created with Claude Opus 5.5 in Claude Code.