Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a3c4d92
Begin isolated HEIC decoder restoration
frathe Sep 15, 2026
b64cca3
Build a reproducible WASI HEIC candidate with validated IPC
frathe Sep 15, 2026
c4a89d1
Add a bounded HEIC helper with verified macOS isolation
frathe Sep 15, 2026
52ed2df
Integrate isolated HEIC services and package qualification
frathe Sep 16, 2026
30f5b10
Reconcile useful HEIC hardening and threat-model omissions
frathe Sep 16, 2026
08a71f2
Withdraw eager WASM allocation after native Linux regression
frathe Sep 16, 2026
7f045be
Fix native HEIC qualification and review findings
frathe Sep 16, 2026
ae1f7f5
Keep the platform boundary table intact
frathe Sep 16, 2026
fa89ab6
Supply the OS profile location for AppContainer startup
frathe Sep 16, 2026
11e0583
Launch pipe-only HEIC helpers without a console
frathe Sep 16, 2026
a86bb35
Pin Windows job buffers across uintptr API wrappers
frathe Sep 16, 2026
6537ac0
Align native Windows token information buffers
frathe Sep 16, 2026
c77d9bd
Keep repository programs outside the Windows signing job
frathe Sep 16, 2026
3973811
Correct the Windows policy probe and expose bounded startup diagnostics
frathe Sep 16, 2026
6021a5f
Verify Windows loopback denial against native isolation policy
frathe Sep 16, 2026
665dd4b
Verify AppContainer loopback exemptions before readiness
frathe Sep 16, 2026
ee5cc67
Gate loopback exemptions in the launcher and drain helper diagnostics
frathe Sep 16, 2026
fad62e6
Record passing native qualification and remaining release gates
frathe Sep 16, 2026
f41fe63
add restart-only experimental HEIC opt-in
frathe Sep 16, 2026
085d185
Fix native HEIC qualification environments and test ownership
frathe Sep 16, 2026
9ea4dde
Fix Linux native analysis setup and Windows qualification exit status
frathe Sep 16, 2026
4aca7be
Preserve live HEIC input limits and launch installed MSIX fixtures di…
frathe Sep 16, 2026
69fef1a
Use owned working directory for installed MSIX qualification
frathe Sep 16, 2026
8aa317a
Record verified HEIC platforms and remaining MSIX qualification blocker
frathe Sep 16, 2026
c1b6890
test: qualify HEIC consumers and packaged failure recovery
frathe Sep 16, 2026
7f5c1da
docs: record resumed HEIC qualification and remaining Windows gates
frathe Sep 16, 2026
98d3895
Qualify installed MSIX under its desktop owner with a fresh standard …
frathe Sep 16, 2026
e8ea7d4
Test installed MSIX with explicit standard-user authentication
frathe Sep 16, 2026
dea62b9
Launch the noninteractive MSIX fixture without a console
frathe Sep 16, 2026
66edeb5
Retain MSIX activation diagnostics and remove unsuccessful launch exp…
frathe Sep 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
11 changes: 9 additions & 2 deletions .github/testshards/internal-ui.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
# baseline-run: 34627413846
# baseline-attempts: 1
# weights: single CI attempt; projected test sums, not measured shard runtimes
# ui-1: 236 entries, 470.520s projected weight sum
# ui-2: 248 entries, 470.530s projected weight sum
# ui-1: 238 entries, 470.520s projected weight sum
# ui-2: 253 entries, 470.530s projected weight sum
# ui-3: 202 entries, 504.870s projected weight sum
# rebalance: 27 whole-test moves; slowest projected sum within 5% of mean
# evidence: finished_refactorings/2026-09-11-ui-shard-rebalance.md
Expand Down Expand Up @@ -117,6 +117,8 @@ TestGlobalFavoriteShortcutOpensStoredFilesThroughViewer ui-1
TestGridBrowseDuringAnalysis ui-1
TestGridHighlight_TitleKeepsTheModePrefixes ui-1
TestGridHighlight_VariantsHoverUpdatesTitleAndHidesMergePrefix ui-1
TestHEICOwnerStopsWithViewer ui-1
TestHEICSourceConsumers ui-1
TestHandleDropBlockedWhileCopyPendingShowsToast ui-1
TestHandleDrop_ClosesOpenGrid ui-1
TestHandleDrop_HidesRestoreLinkEvenWithoutUsingIt ui-1
Expand Down Expand Up @@ -331,6 +333,11 @@ TestE2E_LaunchWithSavedSessionShowsRestoreLink ui-2
TestE2E_SuccessfulDropShowsImage ui-2
TestExifLink_OpensExifWindow ui-2
TestExifNavigationCancelsMetadataBeforeTheNextImageLoads ui-2
TestExperimentalHEICActiveAnalysis ui-2
TestExperimentalHEICAdmission ui-2
TestExperimentalHEICPreviewConsumers ui-2
TestExperimentalHEICRestartOnly ui-2
TestExperimentalHEICStartup ui-2
TestExportAs_CancelWritesNothing ui-2
TestExportAs_ReportsAFailedWrite ui-2
TestExportAs_RotationCorrectsDimensionTagsButNotFilenameOrToast ui-2
Expand Down
135 changes: 135 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ jobs:
- name: Check formatting
run: make fmt-check

- name: Verify isolated HEIC development artifact
run: make heic-check-provenance heic-check-imports

- name: Check search review controls
run: |
node --version
Expand Down Expand Up @@ -152,6 +155,135 @@ jobs:
if-no-files-found: error
retention-days: 14

heic-linux:
name: Linux ${{ matrix.arch }} HEIC native guards (attempt ${{ github.run_attempt }})
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-latest
arch: amd64
- runner: ubuntu-24.04-arm
arch: arm64
runs-on: ${{ matrix.runner }}
steps:
- name: Check out code
uses: actions/checkout@v7
- name: Set up Go
uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache-dependency-path: go.sum
- name: Install Linux application fixture dependencies
run: |
sudo apt-get update
sudo apt-get install -y gcc libgl1-mesa-dev xorg-dev libwayland-dev libxkbcommon-dev
- name: Qualify HEIC native isolation and address-space ceiling
run: go run ./scripts/nativeguards -suite heic-linux -capture "${{ runner.temp }}/native-guards-heic-linux.json"
- name: Upload native guard events
if: always()
uses: actions/upload-artifact@v7
with:
name: native-guards-Linux-${{ matrix.arch }}-${{ github.run_id }}-attempt-${{ github.run_attempt }}
path: ${{ runner.temp }}/native-guards-heic-linux.json
if-no-files-found: error
retention-days: 14

heic-windows:
name: Windows ${{ matrix.arch }} HEIC sandbox and pipe guards (attempt ${{ github.run_attempt }})
env:
# The shipped Windows helper is pure Go; ARM runners lack a native C compiler.
CGO_ENABLED: '0'
strategy:
fail-fast: false
matrix:
include:
- runner: windows-latest
arch: amd64
- runner: windows-11-arm
arch: arm64
runs-on: ${{ matrix.runner }}
steps:
- name: Check out code
uses: actions/checkout@v7
- name: Set up Go
uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache-dependency-path: go.sum
- name: Qualify HEIC as a disposable standard user
shell: pwsh
run: ./packaging/heic/qualify-windows.ps1 -Scenario standalone -EvidenceDirectory "${{ runner.temp }}/heic-standard-user"
- name: Upload native guard events
if: always()
uses: actions/upload-artifact@v7
with:
name: native-guards-Windows-HEIC-${{ matrix.arch }}-${{ github.run_id }}-attempt-${{ github.run_attempt }}
path: ${{ runner.temp }}/heic-standard-user/
if-no-files-found: error
retention-days: 14

heic-msix-build:
name: Build complete HEIC test-MSIX inputs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache-dependency-path: go.sum
- name: Build Store-managed applications for both native targets
run: make package-windows-store
- uses: actions/upload-artifact@v7
with:
name: heic-qualification-store-executables
path: bin/picfetch-microsoft-store-*.exe
if-no-files-found: error
retention-days: 14

heic-msix:
name: Installed MSIX ${{ matrix.arch }} HEIC activation (attempt ${{ github.run_attempt }})
needs: heic-msix-build
env:
CGO_ENABLED: '0'
strategy:
fail-fast: false
matrix:
include:
- runner: windows-latest
arch: amd64
runtime: x64
- runner: windows-11-arm
arch: arm64
runtime: arm64
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache-dependency-path: go.sum
- uses: actions/download-artifact@v8
with:
name: heic-qualification-store-executables
path: dist/executables
- name: Fetch the build-time pinned runtime package
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
Invoke-WebRequest -Uri 'https://github.com/microsoft/onnxruntime/releases/download/v1.29.0/onnxruntime-win-${{ matrix.runtime }}-1.29.0.zip' -OutFile dist/runtime.zip
- name: Install and activate the disposable test-MSIX as a standard user
shell: pwsh
run: ./packaging/heic/qualify-windows.ps1 -Scenario msix -Executable dist/executables/picfetch-microsoft-store-${{ matrix.arch }}.exe -RuntimeArchive dist/runtime.zip -EvidenceDirectory "${{ runner.temp }}/heic-installed-msix"
- name: Upload installed activation and provisioning evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: native-guards-Windows-MSIX-${{ matrix.arch }}-${{ github.run_id }}-attempt-${{ github.run_attempt }}
path: ${{ runner.temp }}/heic-installed-msix/
if-no-files-found: error
retention-days: 14

windows-test:
name: Windows tests (attempt ${{ github.run_attempt }})
runs-on: windows-latest
Expand Down Expand Up @@ -206,6 +338,9 @@ jobs:
- name: Check Explorer runtime selection and worker exit
run: go test ./internal/ort ./internal/similarity ./scripts/explorereval -count=1

- name: Qualify signed HEIC App Sandbox helper
run: go run ./scripts/nativeguards -suite heic-macos -capture "${{ runner.temp }}/native-guards-heic-macos.json"

- name: Qualify Intel Explorer download and offline inference
if: matrix.arch == 'amd64'
run: make explorer-install-test
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/microsoft-store.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ jobs:
if ($LASTEXITCODE -ne 0) { throw 'Staging the x64 package or pinned runtime failed.' }
go run -tags no_emoji,nodynamic ./scripts/msixstage -arch arm64 -exe dist/executables/picfetch-microsoft-store-arm64.exe -runtime-archive dist/onnxruntime-win-arm64.zip -out dist/stage-arm64
if ($LASTEXITCODE -ne 0) { throw 'Staging the ARM64 package failed.' }
go run ./scripts/heicpackage -os windows -arch amd64 -out dist/stage-x64
if ($LASTEXITCODE -ne 0) { throw 'Staging the x64 HEIC helper failed.' }
go run ./scripts/heicpackage -os windows -arch arm64 -out dist/stage-arm64
if ($LASTEXITCODE -ne 0) { throw 'Staging the ARM64 HEIC helper failed.' }

- name: Ensure Desktop C++ framework for local certification
shell: pwsh
Expand Down
43 changes: 35 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ jobs:
# name already carries the arch, and that is what users unpacked
# before Windows gained a second architecture.
for arch in amd64 arm64; do
cp "picfetch-windows-$arch.exe" "picfetch.exe"
zip "picfetch-windows-$arch.zip" "picfetch.exe" ../LICENSE ../THIRD-PARTY-NOTICES.md ../PRIVACY.md -j
rm "picfetch.exe"
cp "picfetch-windows-$arch.exe" "heic-windows-$arch/picfetch.exe"
cp ../LICENSE ../THIRD-PARTY-NOTICES.md ../PRIVACY.md "heic-windows-$arch/"
(cd "heic-windows-$arch" && zip -r "../picfetch-windows-$arch.zip" picfetch.exe heic LICENSE THIRD-PARTY-NOTICES.md PRIVACY.md)
done
for arch in amd64 arm64; do
tar -czf "picfetch-linux-$arch.tar.gz" "picfetch-linux-$arch" -C .. LICENSE THIRD-PARTY-NOTICES.md PRIVACY.md
tar -czf "picfetch-linux-$arch.tar.gz" "picfetch-linux-$arch" -C "heic-linux-$arch" heic -C "$GITHUB_WORKSPACE" LICENSE THIRD-PARTY-NOTICES.md PRIVACY.md
done

- name: Upload unsigned Windows artifacts for signing
Expand Down Expand Up @@ -119,6 +119,7 @@ jobs:
permissions:
contents: read
steps:
# No checkout, repository programs or build toolchain may run with the signer.
- name: Download unsigned Windows artifacts
uses: actions/download-artifact@v8
with:
Expand Down Expand Up @@ -178,12 +179,38 @@ jobs:
if ($LASTEXITCODE -ne 0) {
throw "Signing failed for $($archive.Name)."
}
& $signtool.FullName verify /pa /all /v /tw $executable
if ($LASTEXITCODE -ne 0) {
throw "Signature verification failed for $($archive.Name)."
$helper = Join-Path $unpacked 'heic/picfetch-heic-worker.exe'
if (-not (Test-Path -LiteralPath $helper -PathType Leaf)) { throw 'The HEIC helper is missing.' }
& $signtool.FullName sign /fd sha256 /tr http://time.certum.pl /td sha256 /sha1 $env:CERTUM_CERT_THUMBPRINT /v $helper
if ($LASTEXITCODE -ne 0) { throw 'HEIC helper signing failed.' }
$arch = if ($archive.BaseName.EndsWith('-amd64')) { 'amd64' } else { 'arm64' }

# Only fixed data operations run after authentication. Never execute
# repository code here, even to refresh a post-signing digest.
$manifestPath = Join-Path $unpacked 'heic/manifest.json'
if ((Get-Item -LiteralPath $manifestPath -ErrorAction Stop).Length -gt 4096) {
throw 'The HEIC manifest is too large.'
}
$manifest = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json -AsHashtable
if ($manifest.version -ne 1 -or $manifest.goos -cne 'windows' -or $manifest.goarch -cne $arch -or
$manifest.guestSHA256 -cnotmatch '^[0-9a-f]{64}$' -or $manifest.guestSHA256 -ceq ('0' * 64)) {
throw 'The HEIC manifest target or guest digest is invalid.'
}
$finalManifest = [ordered]@{
version = 1
goos = 'windows'
goarch = $arch
executableSHA256 = (Get-FileHash -LiteralPath $helper -Algorithm SHA256).Hash.ToLowerInvariant()
guestSHA256 = $manifest.guestSHA256
}
$finalManifest | ConvertTo-Json | Set-Content -LiteralPath $manifestPath -Encoding utf8NoBOM

foreach ($signedFile in @($executable, $helper)) {
& $signtool.FullName verify /pa /all /v /tw $signedFile
if ($LASTEXITCODE -ne 0) { throw "Final signature verification failed: $signedFile" }
}

$packageFiles = @($executable)
$packageFiles = @($executable, (Join-Path $unpacked 'heic'))
foreach ($name in @('LICENSE', 'THIRD-PARTY-NOTICES.md', 'PRIVACY.md')) {
$notice = Join-Path $unpacked $name
if (-not (Test-Path -LiteralPath $notice -PathType Leaf)) {
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ bin/
coverage/
.DS_Store
fyne-cross/
/fyne_metadata_init.go
internal/ui/testdata/failed/
.idea
.vscode
Expand Down
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ precedence over its default handoff procedure.
- Use `internal/uitest` for synthetic image formats, temp URIs, approximate comparisons, and OS seam stubs. UI tests should build through `newTestUI`/`newTestViewer`, which mirror production startup.
- `CanvasObject.Visible()` is the object's own hidden flag, not a statement about the tree it is in: a widget that was built and then left out of its container still reports `true`. A test that asserts only `Visible()` therefore passes on a widget that never reaches the screen. When the fact under test is "this is *in* the surface", walk the container from its root — see `infoview`'s `inCard` in `card_test.go`. `Visible()` alone is enough only for a widget already known to be in the tree whose show/hide is what moves.
- Keep platform-specific behavior in existing build-tag pairs and preserve no-cgo AVIF decoding through `gen2brain` WASM; Fyne itself still requires a C/OpenGL toolchain.
- **HEIC source changes:** Read [the maintained-source record](third_party/h265/PICFETCH.md) before changing the decoder or its build. Preserve local hardening until equivalent upstream checks are verified. HEIC parsing belongs only in the separate WASI guest; keep the native import guard and fail-closed application boundary. `make test-h265` covers ordinary WASI fixtures, not the historical full decoder suite.
- **Security-boundary changes:** Reconcile [THREAT-MODEL.md](THREAT-MODEL.md) when parser ownership, worker permissions, memory limits, sensitive persistence or update authority changes; distinguish implemented controls from platform qualification.

## Build and Verification

Expand All @@ -118,7 +120,7 @@ precedence over its default handoff procedure.
- Direct Go commands that import imaging require `-tags no_emoji,nodynamic`; Make targets supply them. The build guard rejects missing `nodynamic` or enabled `wasm2go` before decoder initialization.
- `make package-mac` runs `go run -tags no_emoji,nodynamic ./scripts/plistdoctypes` to derive the packaged app's `CFBundleTypeExtensions` from `imaging.SupportedExtensions()`; it no longer depends on `python3`.
- Match CI before handoff with `make verify`: formatting/TUF checks, vet and build run from the repository root, and the race suite runs through the same Linux/amd64 Docker path as `make test`.
- **HEIC/HEIF support is disabled** pending decoder distribution and security qualification. See [the removal record](finished_refactorings/2026-09-14-remove-heic-decoder.md) before considering restoration.
- **HEIC/HEIF is default-off and restart-only** through Experimental Settings. Before changing activation or packaging, read [the activation record](docs/heic/experimental-opt-in.md) for complete-package requirements and unverified native/release gates. Retain every sandbox, identity and resource check.
- Run focused tests while iterating, e.g. `go test -tags no_emoji,nodynamic -run TestE2E -v ./internal/ui/...`; the complete suite remains the final check.
- **GoLand inspections before feature completion:** Inspect every changed code file with GoLand, review all findings (including weak warnings), and fix confirmed issues before finalizing a feature. Document and mitigate confirmed false positives with narrowly scoped suppressions or exclusions. Re-run inspections after fixes or mitigations, and report unavailable or incomplete inspection results as unverified.
- Golden screenshots are under `internal/ui/testdata/`. Regenerate only with `make golden` (Docker linux/amd64), inspect `internal/ui/testdata/failed/*.png`, and never commit failed renders.
Expand Down
Loading
Loading