Skip to content

[core] Use native stored ZIPs for support bundles and profile backups#3206

Merged
ten9876 merged 1 commit into
aethersdr:mainfrom
jensenpat:codex/support-bundle-native-zip
May 27, 2026
Merged

[core] Use native stored ZIPs for support bundles and profile backups#3206
ten9876 merged 1 commit into
aethersdr:mainfrom
jensenpat:codex/support-bundle-native-zip

Conversation

@jensenpat

@jensenpat jensenpat commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Extract the profile transfer ZIP reader/writer into a shared ZipArchive helper.
  • Write support bundles as native uncompressed .zip files using the shared stored-ZIP writer instead of launching PowerShell Compress-Archive or tar.
  • Add a focused ZIP round-trip/corruption test for the shared helper.

Validation

  • Configured and built with MSVC via scripts/enter-msvc.ps1 -Arch x64 and Ninja using 8 jobs.
  • Built build_opus, zip_archive_test, profile_transfer_test, and AetherSDR.
  • Ran profile_transfer_test and zip_archive_test separately with Qt on PATH; both passed.
  • Ran windeployqt on the built app for manual testing.
  • Scanned the built executable/deployed executable: no powershell, Compress-Archive, or .tar.gz support-bundle path remains.
  • Checked direct process-launch imports with dumpbin; no direct CreateProcess/ShellExecute import was found.

Co-authored-by: Codex <noreply@openai.com>
@jensenpat jensenpat changed the title Use native stored ZIPs for support bundles [core] Use native stored ZIPs for support bundles and profile backups May 27, 2026
@jensenpat jensenpat marked this pull request as ready for review May 27, 2026 05:46
@jensenpat jensenpat requested review from a team as code owners May 27, 2026 05:46

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jensenpat — clean extraction. The ZipArchive helper is a straight lift-and-shift of the existing reader/writer with two small upgrades (explicit numeric_limits overflow guards for entry count / sizes / offsets, and static_cast<uInt> on the crc32 size argument), and the support-bundle path drops the QProcess/powershell/tar shell-out in favor of in-process ZIP writing via QSaveFile. Nice removal of an external-process dependency — and QSaveFile::commit() gives atomic replace semantics the old shell-out couldn't.

A few small notes for your consideration, none blockers:

1. Linux/macOS support bundle file extension change (worth a CHANGELOG entry)

src/core/SupportBundle.cpp:202 previously produced support-bundle-*.tar.gz on non-Windows and .zip on Windows. After this PR, all platforms produce .zip. I grepped the tree and found no consumer of support-bundle-*.tar.gz (the only hit was the line being removed), so this is safe. Worth a brief note in CHANGELOG.md since existing Linux/macOS users with scripts or muscle memory expecting .tar.gz will be surprised.

2. collectSupportBundleEntries is flat-only by design

QDir::Files + no QDirIterator means subdirectories under the temp bundle dir are silently dropped. Today SupportBundle::createBundle writes only top-level files (logs, JSONs, settings.xml, enabled-categories.txt — all flat), so this matches current behavior. Worth a one-line comment in collectSupportBundleEntries noting the flat-only invariant so a future contributor who adds, say, a crashdumps/ subdir doesn't end up with a silently-empty section in the bundle.

3. Stored-only ZIP and uncompressed log size

The shared helper only writes stored (method 0) ZIPs, so a support bundle now uncompresses to roughly the sum of input file sizes plus headers, where the old tar czf deflated logs. AetherSDR logs are rotated small so this is unlikely to be a real problem in practice, but if a user has logs in the tens of MB the bundle is now noticeably larger. The PR title is explicit ("native stored ZIPs") so this is presumably intentional — flagging in case it's worth a follow-up to wire deflate into writeStoredZip later (the reader already handles method 8).

4. uncompressedSize is dead in the stored-method branch

src/core/ZipArchive.cpp:142 reads uncompressedSize but it's only consumed inside the method == 8 branch. Pre-existing — moved verbatim from ProfileTransfer.cpp — but since you're touching this code, a [[maybe_unused]] or restructuring the read to live inside the deflate branch would be cleaner. Skip if you'd rather keep the lift truly verbatim.

Otherwise this looks good — the round-trip + corruption test in tests/zip_archive_test.cpp covers the contract well, and routing ProfileTransfer through the same helper means the existing profile_transfer_test exercises the writer too. Thanks again.


🤖 aethersdr-agent · cost: $8.6056 · model: claude-opus-4-7

@ten9876 ten9876 merged commit d01bb83 into aethersdr:main May 27, 2026
5 checks passed
@ten9876

ten9876 commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Claude here — merged, thanks @jensenpat. Clean refactor + the WACK "Blocked executables" finding is gone. The null-safe error setter and numeric_limits overflow guards you layered into the shared writeStoredZip are strictly better than the inline version we had before; nice cleanup tucked into the move.

Filed #3218 to track adding deflate compression as a follow-up. Confirmed nothing in Store policy or WACK objects to runtime deflate — the rule was about subprocess imports, which this PR resolved. Switching back to compressed bundles is purely a UX win for users hitting Discord/email size limits.

73, Jeremy KK7GWY & Claude (AI dev partner)

ten9876 added a commit that referenced this pull request Jun 21, 2026
## Summary

Closes #3218. Support bundles are log-dominated and compress ~5–10×, but
the in-process ZIP writer from #3206 only emitted **stored**
(uncompressed) entries — a user with 50 MB of logs produced a 50 MB
bundle, hitting Discord/email/GitHub attachment limits much sooner.

Adds a **raw-DEFLATE** writer using the **same bundled zlib** that
already powers the inflate-on-read path (negative window bits → no zlib
header, which ZIP doesn't use). No new dependency, no subprocess, no new
MSIX content — **all of #3206's Store-compliance wins are preserved**.

## Changes
- `ZipArchive`: `writeStoredZip` and the new `writeDeflatedZip` now
share one `writeZipImpl(entries, compress)` — method field + independent
compressed/uncompressed sizes; CRC is always over the **uncompressed**
data.
- `SupportBundle::writeSupportBundleZip` → `writeDeflatedZip`.
`ProfileTransfer` stays stored (tiny payloads).
- `zip_archive_test`: new deflated round-trip asserting method-8
framing, smaller-than-raw output, and a clean round-trip **through the
existing reader** (writer/reader cross-check, since `readZipEntries`
already handles method 8).

## Why it's not RFC-gated
Internal storage-format change with no UX/behavior change (bundles are
still ZIPs, just smaller); the file is never inside the MSIX so WACK's
archive rules don't apply.

## Test plan
- [x] `zip_archive_test` passes (stored + deflated round-trips, method
byte, size check)
- [x] Full app builds clean

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
G6PWY-Chris pushed a commit to G6PWY-Chris/AetherSDR that referenced this pull request Jun 22, 2026
…aethersdr#3206)

## Summary
- Extract the profile transfer ZIP reader/writer into a shared
`ZipArchive` helper.
- Write support bundles as native uncompressed `.zip` files using the
shared stored-ZIP writer instead of launching PowerShell
`Compress-Archive` or `tar`.
- Add a focused ZIP round-trip/corruption test for the shared helper.

## Validation
- Configured and built with MSVC via `scripts/enter-msvc.ps1 -Arch x64`
and Ninja using 8 jobs.
- Built `build_opus`, `zip_archive_test`, `profile_transfer_test`, and
`AetherSDR`.
- Ran `profile_transfer_test` and `zip_archive_test` separately with Qt
on `PATH`; both passed.
- Ran `windeployqt` on the built app for manual testing.
- Scanned the built executable/deployed executable: no `powershell`,
`Compress-Archive`, or `.tar.gz` support-bundle path remains.
- Checked direct process-launch imports with `dumpbin`; no direct
`CreateProcess`/`ShellExecute` import was found.

Co-authored-by: Codex <noreply@openai.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants