Project · Contributing
Contributing
Patches, tests, doc fixes, distro updates, bug reports — all welcome. Read this first so your contribution lands on the first review.
On this page
First-time setup
- Fork & clone:
gh repo fork DaxxSec/SecVF --clone # or git clone https://github.com/<you>/SecVF.git cd SecVF git remote add upstream https://github.com/DaxxSec/SecVF.git - Build:
open SecVF.xcodeproj, pick the SecVF scheme, hit ⌘R. - Run tests: ⌘U in Xcode, or
xcodebuild test -scheme SecVF -destination 'platform=macOS'. - Build the CLI:
cd SecVF/cli && swift build. - Optional but nice: install SwiftFormat (
brew install swiftformat) and the project's pre-commit hook (./scripts/install-hooks.shif present).
PR workflow
- Open an issue first for non-trivial changes — saves you from building something we won't merge.
- Branch from main:
git checkout -b feature/your-change. Conventional branch prefixes:feature/,fix/,docs/,test/,refactor/. - Keep commits atomic. One logical change per commit. Squash before PR if you have noise.
- Conventional commits:
feat:,fix:,docs:,test:,refactor:,chore:. First line ≤72 chars. Body explains why, not what. - Rebase, don't merge. Keep history linear:
git pull --rebase upstream main. - Open the PR against
main. Fill the template. Link the issue. - Address review. Push fixups; we'll squash on merge.
Coding conventions
Swift style
- 4-space indent. SwiftFormat applied.
- Match existing patterns before introducing new ones. Three similar lines is better than a premature abstraction.
- UI classes are
@MainActor. Domain singletons are@MainActor. Internal mutating state hides behind serial queues. - Errors are typed (
SecVFError), notNSError. Add a new case with aLocalizedErrorrecovery suggestion. - Prefer protocols at boundaries (
any VMManagerProtocol) over concrete types — keeps tests easy.
Comments
Comment why, never what. A well-named function doesn't need a doc comment that paraphrases its body. Comment when:
- The code is a workaround for a specific bug — link the issue or PR.
- There's a hidden invariant a future reader would miss.
- You did something non-obvious for performance — explain the alternative you rejected.
File organization
One main type per file. Filename matches the type. Group MARK:-delimited sections inside large files. Don't refactor file structure as part of a feature PR — that's a separate PR.
Tests
Tests use XCTest. Convention: Given-When-Then. Each test name reads as a sentence.
func test_givenStoppedVM_whenStarted_thenStateBecomesRunning() async throws {
// Given
let manager = MockVMManager()
let vm = TestHelpers.makeMockVM(name: "test", state: .stopped)
manager.addVM(vm)
// When
try await manager.startVM(name: "test")
// Then
XCTAssertEqual(manager.vm(named: "test")?.state, .running)
}
Use TestHelpers.swift for mock construction. Add helpers there rather than duplicating fixtures.
Required test coverage per PR:
- New domain method → at least one happy-path test, one failure-path test.
- Bug fix → a test that fails without the fix and passes with it. Commit the test first if you can.
- UI change → if a logic path is added; pure visual changes don't need tests.
- CLI command → one functional test invoking through the protocol mock.
PR checklist
Copy this into your PR description and tick off:
- [ ] Linked the issue this addresses (or explained why no issue).
- [ ] Tests added/updated; all green.
- [ ] No new public API without a docstring.
- [ ] Followed `@MainActor` rules for UI and domain singletons.
- [ ] Logs the right severity for new events (INFO / WARNING / CRITICAL).
- [ ] CHANGELOG.md updated (under "Unreleased").
- [ ] No GPL-licensed code introduced (see §License).
- [ ] No new third-party dependencies without discussion in the issue.
- [ ] If you touched network/security code: tagged the maintainer.
- [ ] Self-reviewed the diff — no debug prints, no commented-out blocks.
License & CLA
The repo is MIT-licensed. By submitting a PR, you agree your contribution is offered under the same license. There's no separate CLA to sign.
The GPL trap — please read
SecVF dual-distributes (free direct download + Mac App Store). The App Store path is incompatible with GPL/LGPL/AGPL — Apple's EULA imposes restrictions that conflict with GPL §6.
Do not:
- Submit code copied or adapted from GPL'd projects.
- Add Swift Package Manager dependencies on GPL'd libraries.
- Port a GPL-licensed plugin or dissector.
If you have something you adapted from a GPL'd source — even at the design level — flag it in the PR. We'll figure out whether the design alone is okay (often it is) or whether we need to rewrite from a different reference.
For the full reasoning see docs/LICENSE-REVIEW.md.
Trademark
MIT covers code, not branding. The name SecVF and the shield logo are not granted by the source license.
- Forking is fine. You can fork, distribute, and modify the source.
- Renaming when distributing is mandatory. If you publish a fork, rename it. Don't call your fork "SecVF" or use the logo without permission.
- App Store branding as "SecVF" is reserved for the canonical maintainer (this is the lever that lets the App Store version stay the recognizable product even though the source is open).
This is standard practice — see UTM, VLC, WireGuard for how other projects handle the same line.
Easy first contributions
Want to dip a toe in? Pick one of these — small, useful, learns the codebase.
- Add a Linux distro to
Resources/distros.json. The schema is documented inline. Test by creating a VM with your new distro. - Write a test for an uncovered method. Run
xcodebuild -showCoverage; pick something at 0% coverage. - Wiki improvements — typos, clarifications, new troubleshooting entries. The whole wiki is in
website/wiki/as plain HTML. - CLI ergonomics — short-flag aliases, better error messages on common mistakes.
- A new helper command on the router VM — extend
scripts/kali-router-setup.sh. Add a doc entry on Router VM § helpers.
Browse issues tagged good first issue for curated starter tasks.