Contributions of any kind are welcome. For bugfixes and unit tests, you can submit a PR directly. For larger changes, please open an issue first to discuss the approach.
- Fork the repository
- Create a branch from
develop(see naming conventions below) - Make your changes and ensure CI passes
- Open a PR targeting
develop
See README.md for build prerequisites.
Use GitHub's built-in branch creation:
gh issue develop 42 --checkout
# → creates branch: 42-fix-samba-timeout (auto-sanitized by GitHub)| Scenario | Pattern | Example |
|---|---|---|
| Feature | feature/{description} |
feature/add-symbol-server |
| Chore | chore/{description} |
chore/update-dependencies |
| Documentation | docs/{description} |
docs/add-plugin-guide |
| Hotfix (urgent) | hotfix/{description} |
hotfix/crash-on-startup |
| Experiment | experiment/{description} |
experiment/avalonia-port |
Slug rules: lowercase, words separated by -, no special characters, max ~50 chars.
All branches target develop except hotfix/ which branches from and merges to main.
Every PR must maintain or improve test coverage. We use a ratchet strategy — coverage only goes up, never down.
| Assembly | Current Goal | Long-term Goal |
|---|---|---|
| Confuser.Core | 40% | 70% |
| Confuser.CLI | 50% | 70% |
| Confuser.Protections | 30% | 60% |
| Confuser.Renamer | 30% | 60% |
| Confuser.DynCipher | 20% | 50% |
These targets will be raised as coverage improves. CI reports coverage on every PR — check the comment.
Always test:
- New protection implementations (integration test: obfuscate + run + verify)
- Bug fixes (regression test proving the fix works)
- Assembly resolution and path handling logic
- CLI argument parsing and error handling
- Project file (
.crproj) parsing edge cases
Don't need tests:
- Simple property getters/setters
- WPF UI layout or styling changes
- Third-party library behavior (dnlib, CommunityToolkit)
| Type | Location | Framework | Purpose |
|---|---|---|---|
| Unit tests | Tests/Confuser.Core.Test/ |
xunit + Moq | Test individual classes in isolation |
| Unit tests | Tests/Confuser.Renamer.Test/ |
xunit + Moq | Test renaming logic |
| CLI e2e | Tests/Confuser.CLI.Test/ |
xunit | End-to-end CLI obfuscation |
| GUI smoke | Tests/Confuser.GUI.Test/ |
xunit + FlaUI | WPF UI automation |
| Integration | Tests/*_*.Test/ |
xunit | Obfuscate sample app, run it, verify output |
Each integration test has two projects:
- Subject (
Tests/MyFeature/): Small .NET Framework console app that printsSTART, some output,END, and returns exit code42 - Test (
Tests/MyFeature.Test/): ReferencesConfuser.UnitTestand the subject, callsRun()with the desired protections
public class MyFeatureTest : TestBase {
public MyFeatureTest(ITestOutputHelper outputHelper) : base(outputHelper) { }
[Fact]
public Task MyProtection_SampleApp_RunsCorrectly() =>
Run("MyFeature.exe",
new[] { "expected output line" },
new SettingItem<Protection>("my-protection-id"));
}[Fact]
public void MethodName_Condition_ExpectedResult() {
// Arrange
var sut = new MyService();
// Act
var result = sut.DoSomething(input);
// Assert
Assert.Equal(expected, result);
}Test names follow MethodName_Condition_ExpectedResult convention.
# All tests
dotnet test Confuser2.sln -c Release
# Specific test project
dotnet test Tests/Confuser.CLI.Test/Confuser.CLI.Test.csproj -c Release
# With coverage
dotnet test Tests/Confuser.CLI.Test/Confuser.CLI.Test.csproj -c Release --collect:"XPlat Code Coverage"Every PR receives an automatic coverage comment showing per-assembly line and branch coverage. The full HTML drill-down report is downloadable as the coverage-report artifact from the test workflow.
We use Conventional Commits:
feat(scope): add new feature
fix(scope): fix a bug
test(scope): add or update tests
refactor(scope): code change that doesn't fix a bug or add a feature
chore(scope): build, CI, dependency updates
docs(scope): documentation changes
Always reference the issue number: fix(renamer): handle FnPtr types (#6)
- PRs target
develop, notmain - CI must pass (build + tests + coverage)
- Coverage must not decrease
- Only include files that are part of your change — no unrelated modifications
- Reference the issue in the PR description
- If fixing a community-reported issue, tag the reporter to test
- Push fixes to the same branch — never close and create a replacement PR
- Roslyn analyzers (NetAnalyzers + Roslynator) run during build — resolve all warnings
- No
ResolveThrowcalls in new code — use null-safeResolve+ handle null - Follow existing code style (tabs, braces on same line, etc.)