fix: mitigate Windows Defender false positive on APM binary#490
Merged
danielmeppiel merged 2 commits intoMar 30, 2026
Merged
Conversation
c065505 to
76b8a5b
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Mitigates Windows Defender heuristic false positives for the PyInstaller-built Windows APM binary by adding Windows PE version metadata and ensuring UPX is not used on Windows, with accompanying troubleshooting documentation and regression tests around the spec helpers.
Changes:
- Add
should_use_upx()and Windows PEVSVersionInfoembedding (auto-reading version frompyproject.toml) in the PyInstaller spec. - Add unit tests that compile and AST-extract the helper functions from
build/apm.specwithout executing PyInstaller globals. - Document Windows AV false-positive troubleshooting steps and add corresponding changelog entries.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
build/apm.spec |
Disables UPX on Windows and embeds Windows PE version info using a version read from pyproject.toml. |
tests/unit/test_build_spec.py |
Adds hermetic tests that validate spec syntax and behavior of extracted helper functions. |
docs/src/content/docs/getting-started/installation.md |
Adds Windows Defender / antivirus false-positive troubleshooting guidance. |
CHANGELOG.md |
Adds Unreleased entries for the mitigation and docs update. |
uv.lock |
Updates the locked package version to 0.8.6. |
76b8a5b to
28ec940
Compare
danielmeppiel
requested changes
Mar 30, 2026
…t#487) - Add PE version info (VSVersionInfo) to Windows binary via build/apm.spec - Disable UPX compression on Windows builds (AV heuristic trigger) - Add AV false-positive troubleshooting section to installation docs - Update CHANGELOG with fix and documentation entries Closes microsoft#487 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
28ec940 to
762625a
Compare
danielmeppiel
approved these changes
Mar 30, 2026
Merged
sergio-sisternes-epam
added a commit
that referenced
this pull request
May 19, 2026
) - Add PE version info (VSVersionInfo) to Windows binary via build/apm.spec - Disable UPX compression on Windows builds (AV heuristic trigger) - Add AV false-positive troubleshooting section to installation docs - Update CHANGELOG with fix and documentation entries Closes #487 Co-authored-by: Sergio Sisternes <sergio.sisternes@epam.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Daniel Meppiel <51440732+danielmeppiel@users.noreply.github.com>
danielmeppiel
added a commit
that referenced
this pull request
May 22, 2026
…1450) Reverts the optimize=2 -> optimize=1 change from #1307 (shipped in v0.14.0) that re-embedded ~1.4 MB / +14% of marshalled docstring text into the PyInstaller PYZ blob. That string surface is the most plausible winget submission and breaking 'irm aka.ms/apm-windows | iex' on a growing number of Defender installations (see #1407 and the winget-pkgs #376283 validation log: 'Detection: Trojan:Script/Wacatac.H!ml, Defender Security Intelligence 1.449.698.0'). Same family precedent in this repo: #487/#490 already had to disable UPX heuristic that latched onto a feature surface change in the PE. The right fix for unsigned PyInstaller binaries is (a) minimise classifier input surface and (b) Authenticode-sign. This PR does (a); signing via Azure Trusted Signing is the durable follow-up. #1307 lowered optimize to keep Click command __doc__ as a help-text fallback because 'apm view' (and earlier 'apm outdated', #1216) had shipped without an explicit help= kwarg. That was the wrong fix: optimize=1 made the docstring-fallback bug invisible by keeping every docstring in the binary, but the binary is the wrong place to carry prose. The right fix is to require every Click command to set help= explicitly, and to fail CI when one doesn't. Changes: - build/apm.spec: optimize=1 -> optimize=2 with a comment pointing at the new silent-drift guard so future contributors don't repeat #1307. - src/apm_cli/commands/view.py: lift the help body out of the docstring into a module-level _VIEW_HELP string and pass it as help= plus a short_help= for the top-level command index. The hidden 'apm info' alias in cli.py reads view_cmd.help, so it is fixed automatically. - tests/unit/test_cli_consistency.py: new test_every_registered_command_has_explicit_help walks every command and sub-command reachable under the top-level cli group and asserts cmd.help (or cmd.short_help) is non-empty. Hidden alias commands are skipped because they inherit help from their source. This is the permanent regression trap for #1298 / #1407. - tests/unit/test_build_spec.py: new test_pyinstaller_optimize_is_2 AST-parses build/apm.spec, locates the Analysis(...) call, and asserts optimize=2. Pins the trade-off so a future PR cannot quietly lower it again to paper over a missing help= kwarg. Validation: - All 7 CI Lint checks green (ruff, format, yaml guard, file length, portable_relpath, pylint R0801, auth-signals). - tests/unit/: 14905 passed, 1 skipped. - PYTHONOPTIMIZE=2 python -m apm_cli.cli view --help and PYTHONOPTIMIZE=2 python -m apm_cli.cli --help both render the new explicit help correctly (smoke-test for the -OO code path). Not in scope: - Authenticode signing via Azure Trusted Signing. Tracked separately; this PR is the smallest change that unblocks the v0.14.x release and installs ASAP. - Re-submitting v0.14.0 to https://www.microsoft.com/wdsi/filesubmission for false-positive review. Manual step, post-merge. Refs: #1407, #1298, #487, #490, winget-pkgs#376283 Reverts the binary-surface effect of: #1307 Co-authored-by: danielmeppiel <danielmeppiel@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
Description
Mitigates Windows Defender false-positive detection (
Trojan:Win32/Bearfoos.B!ml) on the APM binary by addressing the root causes identified in the issue analysis.Fixes #487
Type of change
Changes
build/apm.specVSVersionInfoblock that embeds company, product, version, and copyright metadata into the Windows PE header. AV heuristic models use this metadata as a positive trust signal.should_use_upx()wrapper that disables UPX compression on Windows. UPX-packed binaries are a classic AV red flag. Non-Windows platforms continue to use UPX when available._read_version_from_pyproject()reads the version frompyproject.tomlso the PE header stays in sync automatically.tests/unit/test_build_spec.pyshould_use_upx()platform behavior, and_read_version_from_pyproject()parsing (valid, missing, malformed, prerelease).CHANGELOG.md[Unreleased] > Fixedfor the mitigation.Testing
Tier 2/3 follow-ups (out of scope)