Skip to main content

Contributing Guide

Thank you for your interest in contributing to FIDO Bridge! This document provides guidelines for contributing to the project.

Code of Conduct

Be respectful and constructive in all interactions. We're building this together!

Expected Behavior:

  • Be welcoming to newcomers
  • Provide constructive feedback
  • Focus on what's best for the community
  • Show empathy toward others

Unacceptable Behavior:

  • Harassment or discriminatory language
  • Personal attacks or trolling
  • Publishing others' private information
  • Any conduct that would be inappropriate in a professional setting

How to Contribute

Reporting Bugs

Before submitting a bug report:

  1. Check the troubleshooting guide
  2. Search existing GitHub issues
  3. Test with latest version from main branch

When submitting a bug report, include:

  • Title: Clear, descriptive summary
  • Description: What happened vs. what you expected
  • Steps to reproduce: Minimal steps to trigger the bug
  • Environment:
    • OS and version
    • Rust version (rustc --version)
    • Flutter version (flutter --version)
    • YubiKey model
  • Logs: Debug logs showing the error (sanitize secrets!)
  • Screenshots: If relevant (UI bugs)

Template:

## Bug Description
[Clear description of the bug]

## Steps to Reproduce
1. Start Linux client with `sudo ./target/release/client`
2. Pair Android device
3. Attempt WebAuthn authentication on https://webauthn.io
4. Error occurs: [describe error]

## Expected Behavior
[What should have happened]

## Actual Behavior
[What actually happened]

## Environment
- OS: Ubuntu 24.04 LTS
- Rust: 1.75.0
- Flutter: 3.16.0
- YubiKey: YubiKey 5 NFC (firmware 5.4.3)

## Logs

[Paste relevant logs here]


## Screenshots
[If applicable]

Suggesting Features

Before suggesting a feature:

  1. Search existing issues to avoid duplicates
  2. Consider if it fits FIDO Bridge's scope
  3. Think about implementation complexity

When suggesting a feature, describe:

  • Use case: Why is this needed?
  • Proposed solution: How would it work?
  • Alternatives: Other ways to achieve the same goal?
  • Complexity: Simple enhancement or major change?

Label: Use enhancement label on GitHub

Contributing Code

1. Find an Issue

  • Browse good first issues
  • Or create an issue for what you want to work on
  • Comment on the issue to claim it (avoids duplicate work)

2. Fork and Clone

# Fork on GitHub, then:
git clone https://github.com/YOUR_USERNAME/fido-bridge.git
cd fido-bridge
git remote add upstream https://github.com/0xC9C3/fido-bridge.git

3. Create a Branch

# Feature branch
git checkout -b feature/my-feature-name

# Bugfix branch
git checkout -b fix/issue-123-bug-description

Branch naming:

  • feature/description for new features
  • fix/issue-number-description for bug fixes
  • docs/description for documentation changes
  • refactor/description for code refactoring

4. Make Changes

Follow the code style guidelines below.

5. Write Tests

  • Add tests for new functionality
  • Ensure existing tests pass: cargo test && cd app && flutter test
  • Aim for 80%+ test coverage on new code

6. Update Documentation

  • Update relevant .md files in /docs/docs/
  • Add inline code comments (WHY, not WHAT)
  • Update CHANGELOG.md (if applicable)

7. Commit Changes

We use conventional commits for all commits. The repository has tooling to help you create properly formatted commits automatically.

Using the interactive commit tool (recommended):

# Use commitizen for an interactive prompt
npm run commit

This will guide you through creating a properly formatted commit message.

Manual commits:

# Format: type(scope): description
git commit -m "feat(client): add session cache for ClientPIN"
git commit -m "fix(android): resolve NFC timeout on Pixel devices"
git commit -m "docs(guides): add troubleshooting for pairing timeout"

Note: Commit messages are automatically validated using commitlint via a git hook.

Commit types:

  • feat: New feature (triggers minor version bump)
  • fix: Bug fix (triggers patch version bump)
  • perf: Performance improvement (triggers patch version bump)
  • refactor: Code refactoring (triggers patch version bump)
  • build: Build system changes (triggers patch version bump)
  • revert: Revert previous change (triggers patch version bump)
  • docs: Documentation changes (no release)
  • style: Code style changes (no release)
  • test: Adding or updating tests (no release)
  • ci: CI/CD changes (no release)
  • chore: Maintenance tasks (no release)

Commit message guidelines:

  • Use present tense ("add feature" not "added feature")
  • Keep first line under 100 characters
  • Provide detailed description in body (if needed)
  • Reference issues: Fixes #123 or Closes #456
  • Add BREAKING CHANGE: in footer for breaking changes (triggers major version bump)

8. Push and Create Pull Request

git push origin feature/my-feature-name

On GitHub:

  1. Click "Create Pull Request"
  2. Fill out the PR template
  3. Link related issues
  4. Request review from maintainers

Pull Request Guidelines

PR Title: Follow conventional commits format

feat(client): add support for biometric authentication
fix(android): resolve NFC communication timeout
docs(architecture): add PRF extension documentation

PR Description should include:

  • What: What changes does this PR make?
  • Why: Why are these changes needed?
  • How: How were the changes implemented?
  • Testing: How was this tested?
  • Related Issues: Fixes #123 or Relates to #456
  • Screenshots: If UI changes

Template:

## Summary
[Brief description of changes]

## Changes
- [Change 1]
- [Change 2]

## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests pass
- [ ] Manual testing performed
- [ ] E2E test scenario: [describe]

## Checklist
- [ ] Code follows style guidelines
- [ ] Tests added for new functionality
- [ ] Documentation updated
- [ ] Commit messages follow conventional commits
- [ ] No breaking changes (or clearly documented)

## Related Issues
Fixes #123
Relates to #456

Review Process:

  1. Automated CI checks must pass (tests, linting)
  2. At least one maintainer approval required
  3. Address feedback in new commits (don't force-push during review)
  4. Maintainer will squash-merge when approved

Code Style Guidelines

Rust Code Style

Use rustfmt:

cargo fmt --all

Use clippy:

cargo clippy --all-targets --all-features -- -D warnings

Conventions:

  • Function names: snake_case
  • Type names: PascalCase
  • Constants: SCREAMING_SNAKE_CASE
  • Max line length: 100 characters (soft limit)
  • Imports: Group by std, external crates, internal modules

Comment Style:

// WHY: Explain *why* code exists, not *what* it does
// Good:
// Session cache reduces NFC taps during multi-step ClientPIN flows
let session_cache_ttl = Duration::from_secs(30);

// Bad:
// Set timeout to 30 seconds
let session_cache_ttl = Duration::from_secs(30);

Error Handling:

// Use Result types, not panic!()
pub fn parse_ctap_response(data: &[u8]) -> Result<CtapResponse, Error> {
if data.len() < 2 {
return Err(Error::InvalidResponse("Too short".to_string()));
}
// ...
}

// Document error conditions
/// Parse CTAP2 response from raw bytes
///
/// # Errors
/// Returns `Error::InvalidResponse` if data is too short or malformed
pub fn parse_ctap_response(data: &[u8]) -> Result<CtapResponse, Error> {
// ...
}

Async Style:

// Prefer async/await over manual futures
async fn send_message(&self, msg: Message) -> Result<(), Error> {
let response = self.client.post("/api/messages")
.json(&msg)
.send()
.await?;

response.error_for_status()?;
Ok(())
}

Dart/Flutter Code Style

Use dart format:

cd app
dart format lib test

Use dart analyze:

dart analyze

Conventions:

  • Class names: PascalCase
  • Function/variable names: camelCase
  • Private members: _leadingUnderscore
  • Constants: lowerCamelCase (unless const class)

Widget Structure:

class MyWidget extends StatelessWidget {
const MyWidget({
super.key,
required this.title,
this.subtitle,
});

final String title;
final String? subtitle;


Widget build(BuildContext context) {
return Column(
children: [
Text(title),
if (subtitle != null) Text(subtitle!),
],
);
}
}

State Management (Riverpod):

// Use Riverpod providers for state
final pairedDevicesProvider = StateNotifierProvider<PairedDevicesNotifier, List<Device>>((ref) {
return PairedDevicesNotifier();
});

// Consume in widgets
class DeviceList extends ConsumerWidget {

Widget build(BuildContext context, WidgetRef ref) {
final devices = ref.watch(pairedDevicesProvider);
return ListView(children: devices.map((d) => DeviceTile(d)).toList());
}
}

Kotlin Code Style

Use Android Studio formatter (Ctrl+Alt+L)

Conventions:

class NfcHandler(private val context: Context) {
fun handleTag(tag: Tag): ByteArray {
val isoDep = IsoDep.get(tag)
isoDep.connect()

try {
return transceiveApdu(isoDep, SELECT_FIDO_APPLET)
} finally {
isoDep.close()
}
}

private fun transceiveApdu(isoDep: IsoDep, command: ByteArray): ByteArray {
// Implementation
}
}

Documentation Guidelines

Inline Documentation

Rust:

/// Parse a CTAP2 GetInfo response from CBOR-encoded bytes.
///
/// # Arguments
/// * `data` - Raw CBOR response from authenticator
///
/// # Returns
/// Parsed `GetInfoResponse` containing authenticator capabilities
///
/// # Errors
/// Returns `Error::InvalidResponse` if CBOR parsing fails or required fields are missing
///
/// # Example
/// ```
/// let response_bytes = vec![0xa6, 0x01, 0x58, ...];
/// let info = parse_getinfo_response(&response_bytes)?;
/// assert!(info.versions.contains(&"FIDO_2_0".to_string()));
/// ```
pub fn parse_getinfo_response(data: &[u8]) -> Result<GetInfoResponse, Error> {
// Implementation
}

Dart:

/// Sends an APDU command to the YubiKey via NFC.
///
/// The command is transmitted using ISO 14443A protocol. Throws a
/// [NfcException] if communication fails or timeout occurs.
///
/// Example:
/// ```dart
/// final response = await sendApduCommand([0x00, 0xA4, 0x04, 0x00]);
/// if (response.last == 0x90 && response[response.length - 2] == 0x00) {
/// print('Command successful');
/// }
/// ```
Future<Uint8List> sendApduCommand(List<int> command) async {
// Implementation
}

Markdown Documentation

  • Use ATX-style headings (# not ===)
  • One sentence per line (easier diffs)
  • Code blocks with language tags: ```rust
  • Use relative links for internal docs: [link](../other-doc.md)

Testing Requirements

For New Features

  • Unit tests: Cover new functions/methods
  • Integration tests: Cover interactions with existing code
  • Documentation: Update relevant docs
  • Changelog: Add entry to CHANGELOG.md

For Bug Fixes

  • Regression test: Add test that would have caught the bug
  • Verify fix: Ensure test passes with fix, fails without
  • Update docs: If bug was due to unclear documentation

Test Coverage Expectations

  • Cryptographic code: 100% coverage (security-critical)
  • Protocol parsing: 90%+ coverage
  • UI code: 50%+ coverage (focus on logic, not layout)
  • Overall: 80%+ coverage

Run coverage:

# Rust
cargo tarpaulin --out Html

# Flutter
cd app && flutter test --coverage

Security Contributions

Security Code Reviews

All PRs touching cryptographic code or authentication flows will receive extra scrutiny:

  • Multiple maintainer reviews required
  • Security-focused testing required
  • Potential external security audit

Security-sensitive areas:

  • /crates/transport/src/pairing/crypto.rs (SPAKE2, cryptographic primitives)
  • /crates/transport/src/secure_channel.rs (X25519 ECDH, AES-GCM encryption)
  • /crates/client/src/storage.rs (Paired device credential storage)
  • Any PIN or secret handling code

Project Workflow

Branching Strategy

  • main: Stable, production-ready code
  • develop: Integration branch for features (optional, if used)
  • Feature branches: Short-lived branches for individual features/fixes

Release Process

  1. Version bump: Update version in Cargo.toml and pubspec.yaml
  2. Changelog: Update CHANGELOG.md with release notes
  3. Tag: Create git tag vX.Y.Z
  4. Build: Create release builds for all platforms
  5. Publish: GitHub release with binaries and APK

Versioning: We follow Semantic Versioning:

  • MAJOR: Breaking changes
  • MINOR: New features (backward-compatible)
  • PATCH: Bug fixes (backward-compatible)

Continuous Integration

All PRs must pass CI checks:

  • Rust tests: cargo test --all-features
  • Rust linting: cargo clippy -- -D warnings
  • Rust formatting: cargo fmt --check
  • Flutter tests: flutter test
  • Flutter analysis: flutter analyze
  • Build check: Ensure all components build successfully

CI runs on GitHub Actions (see .github/workflows/).

Communication

Preferred Channels

  • GitHub Issues: Bug reports, feature requests
  • GitHub Discussions: General questions, ideas
  • Pull Requests: Code contributions

Response Times

We aim to:

  • Acknowledge issues within 7 days
  • Review PRs within 14 days (sooner for small/urgent changes)
  • Security issues acknowledged within 48 hours

Recognition

Contributors will be:

  • Listed in CONTRIBUTORS.md
  • Credited in release notes
  • Thanked in project documentation

Significant contributions may receive:

  • Maintainer status
  • Invitation to project discussions
  • Recognition in project README

Getting Help

New to contributing?

Stuck on something?

  • Comment on the relevant issue or PR
  • Ask in GitHub Discussions
  • Reach out to maintainers

We're here to help! Everyone was a beginner once.

License

By contributing to FIDO Bridge, you agree that your contributions will be licensed under the project's dual MIT OR Apache-2.0 license.

See LICENSE-MIT and LICENSE-APACHE for details.

Thank You!

Thank you for contributing to FIDO Bridge and helping make secure authentication accessible to everyone!