feat: retarget ConfuserEx from .NET Framework 4.6.1 to .NET 10 - #71
Conversation
- LangVersion 7.3 → latest - Conditionalize AutoGenerateBindingRedirects to net48 only - Remove redundant NuGet packages (System.Threading, System.ValueTuple, System.Runtime.Extensions) - Delete obsolete appveyor.yml (replaced by GitHub Actions) - Update RepositoryUrl to mcpolo99/ConfuserExx
- Core, Protections, Renamer, DynCipher, MSBuild.Tasks: net461 → net48 - Update conditional references (Runtime, System.Web) to check net48 - Update MSBuild.Tasks NuGet packaging paths to net48 - Build verified: all library projects compile for both net48 and netstandard2.0
- ConfuserEx.csproj: net461 → net10.0-windows, SDK → Microsoft.NET.Sdk - MvvmLightLibs 5.4.1.1 → CommunityToolkit.Mvvm 8.x - 7 files: GalaSoft.MvvmLight.CommandWpf → CommunityToolkit.Mvvm.Input - RaiseCanExecuteChanged → NotifyCanExecuteChanged - DragDropCommand subclass removed (RelayCommand<T> is sealed in CommunityToolkit) - Ookii.Dialogs.Wpf 4.0.0 → 5.x - ComponentDiscovery: AppDomain → collectible AssemblyLoadContext - PluginLoadContext defers Confuser.Core/dnlib to default context for type identity - CrossDomainContext (MarshalByRefObject) deleted - AboutTabVM: Process.Start(url) → ProcessStartInfo with UseShellExecute=true - Build verified: 0 errors, 0 warnings
- Confuser.CLI.csproj: net461 → net10.0 - Guard Console.Title get/set with OperatingSystem.IsWindows() for cross-platform support - Build verified: 0 errors, 0 warnings
- CI: switch from VS MSBuild to dotnet CLI (MSBuild 18+ required by .NET 10 SDK) - CI: add actions/setup-dotnet for .NET 10 SDK, remove MSBuild setup step - CI: update packaging paths from net461 to net10.0/net10.0-windows - CI: add dotnet test step - global.json: pin .NET 10 SDK with latestMinor rollForward - Confuser.UnitTest: multi-target net462;net10.0 (integration tests need Framework) - Integration test projects: net461 → net462 (xunit.runner.visualstudio 2.8+ minimum) - Confuser.Core.Test, Confuser.Renamer.Test: net461 → net10.0, Moq 4.17 → 4.20 - Confuser.UnitTest: xunit 2.4.1 → 2.9, Microsoft.NET.Test.Sdk 17.0 → 17.12 - Microsoft.Build.Tasks.Core: 15.9 → 17.x - Build verified: 70 projects succeed, 2 pre-existing failures (C++ project, sn.exe)
…pport (#53) - Switch all jobs from windows-2022 to windows-2025 (VS2026 / MSBuild 18) - MSBuild 18 supports .NET 10 SDK natively — no hybrid build needed - Single msbuild call builds all projects: .NET 10, Framework, C++/CLI - Fix 118_EnhancedStrongName: resolve sn.exe via registry fallback when SDK40ToolsPath is not set (dotnet CLI environments)
- 244_ClrProtection.vcxproj: TargetFrameworkVersion v4.6.1 → v4.8 - windows-2025 runner does not include 4.6.1 targeting pack - Consistent with library TFM migration (all Framework targets → net48)
…ility (#53) - dotnet test on the full solution fails because vcxproj can't be loaded - Instead, enumerate *.Test.csproj files and test each individually - Gives proper per-project test reporting and exit code
- Obfuscate_SampleApp_ProducesRunnableOutput: builds a net461 sample app, runs Confuser.CLI with rename protection, verifies output exists, differs from original, and the obfuscated exe runs correctly (START/Hello/END, exit 42) - Cli_NoArgs_ReturnsNonZeroAndShowsUsage: verifies CLI shows usage on no args - SampleApp fixture pre-built via MSBuild target (avoids SDK version conflicts) - Confuser.Runtime.dll copied to test output for protection pipeline
- .NET 10 SDK, .NET Framework 4.8 Developer Pack, VS 2025+ with C++ workload - Build commands for full solution (MSBuild 18) and .NET-only (dotnet CLI) - TFM table showing net48, netstandard2.0, net10.0, net10.0-windows, net20
- SampleApp.csproj: net461 → net48 (windows-2025 lacks 4.6.1 targeting pack) - 244_ClrProtection.Test: net462 → net48 (match C++/CLI project TFM, eliminates MSB3274 warning)
#53) - Tests/Directory.Build.props: auto-inject coverlet.collector into all *.Test projects - CI test step: collect XPlat Code Coverage (Cobertura XML) per test project - CI report step: generate HTML + text summary via ReportGenerator - Upload coverage-report artifact (downloadable HTML with per-file drill-down) - Coverage summary printed to CI log for quick visibility
) GUI smoke tests (FlaUI.UIA3): - Gui_Launches_ShowsMainWindow: verifies GUI starts, title shows project name - Gui_LoadProject_ShowsModules: opens .crproj, verifies modules appear in list - Gui_ProtectSampleApp_ShowsSuccess: full protect cycle through UI, verifies obfuscated exe exists, runs correctly with expected output Runtime deployment fix: - ConfuserEx.csproj + Confuser.CLI.csproj: add CopyConfuserRuntime target to copy Confuser.Runtime.dll (net20) to output after build - Protection pipeline requires Runtime.dll at the same path as Confuser.Core.dll - Previously worked on net461 via transitive project reference, but net10.0 doesn't copy net20 assemblies automatically
- Add MarkdownSummaryGithub report type to ReportGenerator - Post coverage table to GitHub Actions job summary (visible in run's Summary tab) - Post sticky coverage comment on PRs via marocchino/sticky-pull-request-comment - Add pull-requests: write permission to build job for PR comment access - Coverage table shows per-assembly line/branch % directly in the PR
SummarySummary
CoverageConfuser.CLI - 53.3%
Confuser.Core - 25.7%
Confuser.DynCipher - 0.2%
Confuser.Protections - 4.9%
Confuser.Renamer - 42%
Confuser.UnitTest - 0%
|
#53) - ci.yml: build + package + release only (lean, ~3 min) - test.yml: tests + coverage + PR comment + HTML report (separate pipeline) - Both triggered on same events, run in parallel - CONTRIBUTING.md: testing policy, coverage targets, ratchet strategy, test types, how to write integration/unit tests, commit conventions
- Run dotnet format on all 280 source files for consistent style - Fix import ordering (System.* first, then project namespaces) - Fix missing final newlines - Fix merge-conflict markers left by dotnet format in multi-TFM projects - Add .github/workflows/format.yml: checks formatting on PRs, reports which files need fixing if violations found - All formatting rules enforced via existing .editorconfig
|
Nice one! I've got a bunch of other fixes locally, but they're going to conflict pretty heavily with the formatting changes here. Currently the line endings are pretty inconsitent too. I'd propose adding something like the following in .gitattributes: Then: |
- Normalize text files to native line endings on checkout - Force CRLF for project files (.sln, .csproj, .vcxproj, etc.) - Mark binary files (dll, exe, ico, snk, otf) as binary - Run git add --renormalize to fix existing inconsistencies - Addresses review feedback on PR #71
|
Good suggestion — added Also added Ran Regarding your local fixes conflicting with the formatting — the formatting commit ( |
17 new tests covering obfuscation across all supported .NET frameworks: Console (7 tests): - net20, net35, net40, net48: obfuscate + run + verify output - net6.0, net8.0, net10.0: obfuscate .dll (apphost .exe is not managed) WinForms (4 tests): - net35, net40, net48: obfuscate + run with --verify + verify output - net10.0-windows: obfuscate .dll WPF (4 tests): - net35, net40: code-only WPF (no XAML codegen for old TFMs) - net48: XAML + code-behind (tests BAML renaming) - net10.0-windows: obfuscate .dll Class Library (2 tests): - netstandard2.0, net8.0: obfuscate DLL with public API surface Infrastructure: - TestBase.Run() now accepts processArguments parameter - Each test uses unique outputDirSuffix to prevent parallel conflicts - Confuser.Runtime.dll copied to test output - All old TFMs use Microsoft.NETFramework.ReferenceAssemblies for CI compat
#73) - WinForms: net6.0-windows, net8.0-windows (obfuscate .dll) - Library: net48, net6.0 (obfuscate DLL with public API surface) - Total: 21 cross-framework tests (was 17)
Root cause: Coverlet instruments all assemblies in the test output with RecordHit() calls. ConfuserEx then obfuscates the subjects (renaming RecordHit), and the obfuscated exe crashes at runtime with: MissingMethodException: Method not found 'Void ???.RecordHit(Int32)' Fix: add shared coverlet.runsettings that limits coverage collection to Confuser.* assemblies only, excluding test subjects (CrossFramework.*, *.Test, xunit, Moq). Applied globally via Directory.Build.props.
windows-2025 runner only has .NET 8/9/10 pre-installed. .NET 6.0 is EOL but we test it for backward compatibility. The WinForms_Net6 test failed with TypeResolveException because System.Runtime 6.0.0 wasn't available for assembly resolution.
…rix (#73) Full coverage now: 24 tests across all supported frameworks and app types. Added: - WPF: net6.0-windows, net8.0-windows (obfuscate .dll) - Library: net10.0 (obfuscate DLL) Complete matrix: | App Type | net20 | net35 | net40 | net48 | net6 | net8 | net10 | netstd2.0 | |----------|-------|-------|-------|-------|------|------|-------|-----------| | Console | x | x | x | x | x | x | x | | | WinForms | | x | x | x | x | x | x | | | WPF | | x | x | x | x | x | x | | | Library | | | | x | x | x | x | x |
test: cross-framework integration tests (Console, WinForms, WPF, Library)
i also decided to be messy and added some general testing to make sure all is actually working :D |
All good! Nice to get this stuff fixed early to make things easier in the long run 👍 |
…ent (#53) - Tests continue on failure — all projects run, nothing skipped - Per-project result table posted to PR comment (passed/failed/skipped counts) - Failed test names listed individually under the table - Combined PR comment: test results + coverage report in one sticky comment - Job summary also shows both test results and coverage - Final step fails the job if any tests failed (after all reporting is done)
Test Results
Cross-Framework Test Details (click to expand)
SummarySummary
CoverageConfuser.CLI - 53.3%
Confuser.Core - 25.7%
Confuser.DynCipher - 0.2%
Confuser.Protections - 4.9%
Confuser.Renamer - 42%
Confuser.UnitTest - 0%
|
…kdown (#53) - Switch from regex parsing to TRX XML parsing for accurate test counts (fixes net462 integration tests showing 0/0/0) - Add collapsible Cross-Framework Test Details section showing each framework test individually with TFM and app type columns - Failed tests show first line of error message - Upload TRX files as test-results artifact for debugging - Coverage collected to separate directory from TRX results
…il (#53) dotnet test was called with --results-directory twice (once for coverage, once for TRX). .NET 10 SDK rejects this with "expects a single argument but 2 were provided". Consolidated to a single results directory per project.
- Add actions/cache@v4 for NuGet global packages folder - Set NUGET_PACKAGES to workspace-relative path for reliable caching - Cache key hashes all .csproj and .vcxproj files - Fallback restore-key reuses partial cache on package changes - Applied to both ci and test workflows - First run populates cache, subsequent runs skip most of restore
if you are willing to take a look you are free to do, will leave it for today. the majority of the changes is just formatting, or we just squash merge and take it as a pre-release test and take it as it comes. |
|
It's hard to evaluate in conjunction with the formatting changes, I can say at least that it runs OK and the obfuscated app still works. The best bit is that it's roughly 2x faster at obfuscating 😎 Looking forward to using it for real. Great work! |
|
LGTM 👍 |
was not expecting the speed improvements but that is just a bonus i guess! will merge into pre-release branch so a pre release package will be made🙌 |
* feat: retarget ConfuserEx from .NET Framework 4.6.1 to .NET 10 (#71) * perf(ci): eliminate duplicate build — test workflow reuses CI build output (#78) Before: ci.yml and test.yml each did a full MSBuild restore + build (~4 min each) After: ci.yml builds + uploads artifacts, test.yml downloads and runs tests only Changes: - ci.yml: add build-output artifact upload (1-day retention) - ci.yml: add paths-ignore (skip on docs-only changes) - ci.yml: add concurrency (cancel in-progress on new push) - test.yml: trigger on workflow_run (waits for CI completion) - test.yml: download build-output instead of building - test.yml: no more restore/build steps - format.yml: only trigger when .cs/.vb/.editorconfig files change Saves ~4 min of Windows runner time per push by not building twice. All 3 workflows remain separate with their own status checks. Co-authored-by: RandomCrocodile <mawi@polosab.com> * fix(ci): update CodeQL to windows-2025 for MSBuild 18 / .NET 10 support CodeQL was still on windows-2022 (MSBuild 17) which can't resolve .NET 10 SDK from global.json. Also removed obsolete .NET 4.6.1 targeting pack install (net48 doesn't need it) and bumped checkout to v5. * chore: update repo references from mkaring to mcpolo99/ConfuserExx - Issue template config: point discussions to our repo, add Ideas + General links - CODEOWNERS: mkaring → mcpolo99 - FUNDING.yml: mkaring → mcpolo99 - MSBuild.Tasks PackageProjectUrl: point to our repo - Test [Trait("Issue")] attributes kept as upstream attribution (historical) * fix(ci): revert test workflow to direct triggers for reliable PR comments workflow_run doesn't associate with PRs reliably — test results and coverage comments were not posted on PR #79. Reverted to direct push/pull_request triggers with its own build step. Still optimized with: - paths-ignore (skip on docs-only changes) - concurrency (cancel in-progress on new push) - NuGet cache (shared cache key with ci.yml) - Removed build-output artifact from ci.yml (no longer needed) --------- Co-authored-by: RandomCrocodile <mawi@polosab.com>
* feat: retarget ConfuserEx from .NET Framework 4.6.1 to .NET 10 (#71) * perf(ci): eliminate duplicate build — test workflow reuses CI build output (#78) Before: ci.yml and test.yml each did a full MSBuild restore + build (~4 min each) After: ci.yml builds + uploads artifacts, test.yml downloads and runs tests only Changes: - ci.yml: add build-output artifact upload (1-day retention) - ci.yml: add paths-ignore (skip on docs-only changes) - ci.yml: add concurrency (cancel in-progress on new push) - test.yml: trigger on workflow_run (waits for CI completion) - test.yml: download build-output instead of building - test.yml: no more restore/build steps - format.yml: only trigger when .cs/.vb/.editorconfig files change Saves ~4 min of Windows runner time per push by not building twice. All 3 workflows remain separate with their own status checks. Co-authored-by: RandomCrocodile <mawi@polosab.com> * fix(ci): update CodeQL to windows-2025 for MSBuild 18 / .NET 10 support CodeQL was still on windows-2022 (MSBuild 17) which can't resolve .NET 10 SDK from global.json. Also removed obsolete .NET 4.6.1 targeting pack install (net48 doesn't need it) and bumped checkout to v5. * chore: update repo references from mkaring to mcpolo99/ConfuserExx - Issue template config: point discussions to our repo, add Ideas + General links - CODEOWNERS: mkaring → mcpolo99 - FUNDING.yml: mkaring → mcpolo99 - MSBuild.Tasks PackageProjectUrl: point to our repo - Test [Trait("Issue")] attributes kept as upstream attribution (historical) * fix(ci): revert test workflow to direct triggers for reliable PR comments workflow_run doesn't associate with PRs reliably — test results and coverage comments were not posted on PR #79. Reverted to direct push/pull_request triggers with its own build step. Still optimized with: - paths-ignore (skip on docs-only changes) - concurrency (cancel in-progress on new push) - NuGet cache (shared cache key with ci.yml) - Removed build-output artifact from ci.yml (no longer needed) * chore: adopt GitHub branch conventions — master→main, pre-release→develop (#82) * chore: rename master→main, pre-release→develop, adopt GitHub branch conventions Branch renames: - master → main (default branch) - pre-release → develop (integration branch) All references updated: - ci.yml: triggers, release jobs, dev-release job (was pre-release) - test.yml, format.yml, codeql-analysis.yml: branch triggers - dependabot.yml: target branch - README.md: contributing section, CI badge - CONTRIBUTING.md: branch naming convention, PR target New branch naming convention (documented in CONTRIBUTING.md): - Issue-linked: {number}-{slug} via gh issue develop - Feature: feature/{description} - Chore: chore/{description} - Docs: docs/{description} - Hotfix: hotfix/{description} (from main) - Experiment: experiment/{description} * feat(ci): lightweight lint on push, full CI on PR only (#81) New workflow layout: - lint.yml (NEW): every push + PR — format + style + Roslyn analyzers without building. Posts results to PR comment or issue comment (parses issue number from branch name). ~2 min. - ci.yml: PR + main/develop push only — full build + package - test.yml: PR only — full build + test + coverage - codeql: weekly (Mon 3am, skips if no commits) + manual trigger - format.yml: DELETED — replaced by lint.yml Cost per event: - Feature branch push: ~2 min (was ~9 min) — 77% reduction - PR: ~11 min (lint + ci + test, unchanged) - Merge to main: ~5 min (ci only) - CodeQL: weekly conditional, not on every push/PR --------- Co-authored-by: RandomCrocodile <mawi@polosab.com> * docs: update commit convention to match branch naming — full words, no scopes --------- Co-authored-by: RandomCrocodile <mawi@polosab.com>
Summary
Retargets ConfuserEx from .NET Framework 4.6.1 (EOL April 2022) to .NET 10 LTS (supported until Nov 2028).
Fixes #53
TFM Changes
Breaking Changes
What Changed (5 commits)
Build Result
Test plan