Level 2: Firecracker Contributor Onboarding

Level 1 gave you a Firecracker you can build with tools/devtool, a passing test suite, and a microVM you booted by hand. This level turns that capability into merged pull requests. You will learn how Firecracker is actually contributed to: the GitHub fork-and-pull model against main, the DCO Signed-off-by sign-off that replaces a CLA, the CHANGELOG.md convention, the one-logical-change-per-commit discipline, the tools/devtool quality gates that are the CI gates, the bot/CI checks on every PR, and the label taxonomy you use to find work. By the end you will have walked a trivial change end to end, fixed a realistic good-first-issue class, and reviewed a flawed PR from the maintainer's side of the table.

This is deliberately a workflow level. The contributions are surgical — a doc fix, a clearer error message, a missing test. Nothing here will surprise a reviewer, and that is the point. Firecracker maintainers reject sloppy mechanics reflexively: an unsigned commit, a missing CHANGELOG entry, or a clippy warning never even reaches the substance of your change. You drill the mechanics now so that Levels 3–9 can be about the VMM.

This curriculum will not hold your hand. It points you at the real files — CONTRIBUTING.md, the PR template, CHANGELOG.md, tools/devtool — and makes you run every gate yourself, because a contributor who has never seen tools/devtool checkbuild --all go red has not yet earned a reviewer's time. Where this level names a check or a file, it gives you the command to find and run it on your own checkout.


Learning Objectives

By the end of Level 2 you must be able to:

  1. Describe the Firecracker contribution model end to end: issue → fork → branch off main → signed commit(s) → PR → CI/bots → ≥2 maintainer approvals → maintainer merge.
  2. Make a clean, signed commit (git commit -s) whose Signed-off-by trailer passes the DCO bot, and repair history that lacks it (--amend -s, rebase --signoff).
  3. Add a correct CHANGELOG.md entry under the unreleased heading in the right Added/Changed/ Fixed/Removed/Deprecated/Security section.
  4. Run the local quality gates — tools/devtool fmt, tools/devtool checkstyle, tools/devtool checkbuild --all — and explain which CI check each one mirrors.
  5. Structure a change as one logical change per commit, each commit passing the build, and explain why Firecracker requires integration tests for new functionality.
  6. Find and qualify a good first issue using gh issue list label filters without stepping on another contributor, and read the Type:/Status:/Priority:/Kani label taxonomy.
  7. Review a PR like a maintainer — correctness, tests, compatibility, security/attack-surface, style — and write constructive, specific review comments.

The Firecracker Contribution Model

Firecracker development happens entirely on GitHub at github.com/firecracker-microvm/firecracker. There is no JIRA, no patch files emailed to a list, and crucially no CLA. If you came from an Apache project (the Tez curriculum's JIRA + .patch flow), unlearn that here — Firecracker is a fork-and-pull-request project secured by the Developer Certificate of Origin, not a contributor agreement.

Read the source of truth first. These files are short and they are the rules; do not work from this page's summary alone:

FileWhat to extractConfirm it exists
CONTRIBUTING.mdThe full PR workflow, DCO requirement, commit hygiene, the ≥2-approval rule, the devtool gates, integration-test requirement.ls CONTRIBUTING.md
.github/PULL_REQUEST_TEMPLATE.mdThe checklist auto-filled into every PR body.find .github -iname '*pull_request*'
CHANGELOG.mdThe Keep-a-Changelog format and the current unreleased heading.ls CHANGELOG.md
MAINTAINERS.mdWho can approve and merge (you need two of them).ls MAINTAINERS.md
SECURITY.mdWhy a vulnerability is never a public issue.ls SECURITY.md
# Confirm the governing documents exist on your branch, and read them.
ls CONTRIBUTING.md CHANGELOG.md MAINTAINERS.md SECURITY.md
find .github -iname '*pull_request*' -o -iname '*PULL_REQUEST*'

Note: The exact wording of CONTRIBUTING.md (commit-title length, the precise list of devtool gates, whether two or three approvals) is version-sensitive (verify on your branch). When this page states a number, treat CONTRIBUTING.md as authoritative if they ever disagree.

The pieces you must internalize:

ArtifactWhat it isWhere
IssueA bug, enhancement, or task — the unit of "what should change."GitHub Issues, labeled (good first issue, Type: Bug, …).
Pull RequestYour proposed change, against main, from your fork's branch.GitHub PRs.
DCODeveloper Certificate of Origin. Replaces a CLA. Asserted by a Signed-off-by line, per commit.git commit -s. Enforced by the DCO bot.
CHANGELOG.mdA human-readable, Keep-a-Changelog log; every user-facing PR adds a line.Under the unreleased heading.
PR template.github/PULL_REQUEST_TEMPLATE.md — the checklist your PR must satisfy.Auto-filled into the PR body.
tools/devtoolThe Docker-wrapped build/test/lint harness; its gates are the CI gates.tools/devtool at repo root.

DCO, not CLA

The DCO is a lightweight, legally-meaningful assertion. By signing off you certify — under the text in the DCO itself — that you wrote the change or otherwise have the right to submit it under the project's Apache-2.0 license. You assert it per commit:

git commit -s -m "Your message"

-s appends a trailer to the commit message:

Signed-off-by: Your Name <your.email@example.com>

The name and email must match your git config user.name / user.email. The DCO bot checks every commit on the PR; a single commit without a valid Signed-off-by blocks the merge. There is no separate agreement to sign — this trailer is the agreement. You will do this for real in Lab 2.2, including how to repair a branch you forgot to sign.

The CHANGELOG entry

Firecracker keeps a CHANGELOG.md in Keep-a-Changelog style. Almost every user-facing PR adds a line under the unreleased heading, in the correct subsection. Check the real headings on your branch rather than trusting this example:

# What are the current sections? Don't guess — read them.
rg -n '^###? ' CHANGELOG.md | head -n 25
## [Unreleased]

### Added

- New `foo` field on `machine-config` ([#5000](https://github.com/firecracker-microvm/firecracker/pull/5000))

### Changed

### Fixed

- Corrected a misleading error message when `vcpu_count` exceeds the maximum
  ([#5001](https://github.com/firecracker-microvm/firecracker/pull/5001))

### Deprecated

### Removed

A change that affects users — behavior, the API, an error message, a default — needs an entry. A purely internal refactor or a test-only change may not; when in doubt, add one and let the reviewer tell you to drop it. A missing CHANGELOG entry is the single most common reason a first PR earns a "please add a changelog entry" comment and a wasted review round.

One logical change per commit

This is where Firecracker is stricter than many projects. The rule, from CONTRIBUTING.md (verify the exact wording on your branch):

  • One logical change per commit. If your PR does two things — a fix and a rename — that is two commits, or two PRs.
  • Every commit must build and pass tests on its own. A reviewer (or git bisect) may check out any single commit; a commit that doesn't compile poisons the history.
  • Commit title ≤ ~72 characters, imperative mood, explaining what and why, not how.
  • New functionality requires integration tests, and you must not lower existing coverage.

Tip: Firecracker does not squash-merge the way some projects do; your commit history is part of the deliverable. Curate it. git rebase -i to split, reorder, and reword before you ask for review — and re-sign with --signoff if you rewrite.


The PR Lifecycle

flowchart TD
    A["Find/claim an issue (good first issue)"] --> B["Fork firecracker-microvm/firecracker"]
    B --> C["clone fork; add upstream remote"]
    C --> D["git checkout -b fix/short-description (off main)"]
    D --> E["Make one logical change per commit"]
    E --> F["Add a CHANGELOG.md entry"]
    F --> G["tools/devtool fmt"]
    G --> H["tools/devtool checkstyle"]
    H --> I["tools/devtool checkbuild --all + the relevant tests"]
    I --> J["git commit -s  (DCO sign-off, each commit)"]
    J --> K["git push origin fix/short-description"]
    K --> L["Open PR vs main; complete the template"]
    L --> M["Bots + CI: DCO, fmt/clippy, build matrix, tests, Kani"]
    M -->|red| H
    M -->|green| N["Maintainer review"]
    N -->|changes requested| O["Amend / add commits; force-push the branch"]
    O --> M
    N -->|2+ approvals| P["A maintainer merges to main"]

The state machine in words:

  1. Fork the repo; clone your fork; add the canonical repo as the upstream remote so you can keep main current.
  2. Branch off an up-to-date main (fix/... or feat/...). You never branch off a release tag.
  3. Change exactly what the issue asks, split into one-logical-change commits.
  4. CHANGELOG: add a line under the unreleased heading if the change is user-facing.
  5. Gate locally: tools/devtool fmt, then checkstyle, then checkbuild --all, then the tests for what you touched. (From Lab 1.2.)
  6. Commit with -s on every commit so the DCO bot passes.
  7. Push and open a PR vs main; complete the template honestly.
  8. CI + bots run. Green is required before review converges.
  9. Review: maintainers (from MAINTAINERS.md) review. Address every comment by amending the relevant commit and force-pushing — Firecracker reviewers expect a clean history, not a pile of "address review" commits.
  10. Merge: after ≥2 maintainer approvals, a maintainer merges. You do not merge your own PR.

The bots and CI checks you will see

CheckWhat it verifiesLocal equivalent
DCO botEvery commit has a valid Signed-off-by matching the author.git commit -s / git rebase --signoff
fmt / clippycargo fmt --check clean; cargo clippy … -D warnings clean (warnings are errors).tools/devtool fmt then tools/devtool checkstyle
build matrixThe workspace builds on x86_64 and aarch64, debug and release, musl and gnu.tools/devtool checkbuild --all
unit + integration testscargo test plus the pytest integration suite in tests/.tools/devtool test
style / coverage / miscLicense headers, Python lint (black/isort), markdown, coverage thresholds.tools/devtool checkstyle
Kani (on relevant PRs)Formal/model-checking proofs over flagged code (the Kani label).tools/devtool Kani target (verify)

Note: tools/devtool fmt does more than cargo fmt: it runs cargo fmt, clippy --fix, cargo sort, and Python/markdown formatters (black/isort/mdformat). Run it first; it fixes most of what checkstyle would otherwise flag. (Verify the exact tool list on your branch with rg -n 'fmt|clippy|black|isort|sort' tools/devtool.)

Clippy as warnings-as-errors is the trap that catches the most first PRs. The CI command is cargo clippy --all --all-targets --all-features -- -D warnings. A single clippy::needless_return turns the whole job red. CONTRIBUTING.md recommends wiring these as git pre-push hooks; do it.


The Label Taxonomy

You navigate Firecracker's issues by labels. Learn the families:

Label familyExamplesUse
Onboardinggood first issueCurated, scoped, low-risk. Your starting point this level.
Type:Type: Bug, Type: Enhancement, Type: Documentation, Type: QuestionWhat kind of change.
Status:Status: Awaiting review, Status: Blocked, Status: ParkedWhere it is in the pipeline.
Priority:Priority: High, Priority: Medium, Priority: LowTriage urgency.
KaniKaniTouches code under formal verification; expect a Kani CI proof.
Roadmap:Roadmap: …Tied to a tracked roadmap item — usually too large for Level 2.
# The exact label set drifts; list it from the repo rather than trusting this table.
gh label list --repo firecracker-microvm/firecracker --limit 100

# Find your starting work.
gh issue list --repo firecracker-microvm/firecracker \
  --label "good first issue" --state open --limit 30

You learn to find and qualify these issues in Lab 2.3. The etiquette rule is absolute: do not grab an issue assigned to someone else, and comment your intent before you start.


Source Areas You Will Touch at This Level

You are not writing VMM internals yet, but a good-first-issue fix often lands in one of these. Map them now so the labs move fast:

AreaPathWhy Level-2 work lands here
Repo governanceCONTRIBUTING.md, CHANGELOG.md, docs/Doc and process fixes.
Error/validation stringssrc/vmm/src/vmm_config/, src/firecracker/src/api_server/Clearer messages, validation gaps.
The CLI / help textsrc/firecracker/src/, src/jailer/src/Help-string and argument fixes.
Teststests/ (pytest), per-crate #[cfg(test)] modulesThe integration test you must add.
The devtool harnesstools/devtool, tools/Build/lint plumbing fixes (rare for newcomers).
# Where do user-facing strings and validation live? Learn to find them by role.
rg -n 'fn validate' src/vmm/src/vmm_config/
rg -n 'format!\(|write!\(' src/firecracker/src/ | head -n 20

You produce a complete module map of the workspace in Lab 2.1.


GitHub Issue Categories for Level 2

CategoryLooks likeLabel filter
DocumentationA stale command in docs/, a wrong default, a broken link.good first issue, Type: Documentation
Error-message clarityA format! that says "invalid" without saying why.good first issue, Type: Enhancement
Small validation gapAn accepted value that should be rejected pre-boot.good first issue, Type: Bug
Help/usage textA misleading CLI flag description in firecracker/jailer.good first issue
Test clarityAn under-asserted test or a missing edge case.good first issue

Anything touching the vCPU run loop, virtio devices, snapshot compatibility, seccomp, or the wire API is not Level-2 work — those are Levels 4, 7, 9 and the issue roadmap.


Deliverables

Demonstrate all of the following before advancing to Level 3:

  • A fork of firecracker-microvm/firecracker with upstream configured, and a topic branch off an up-to-date main (Lab 2.1, Lab 2.2).
  • A complete module map of the src/ workspace and the vmm internals (Lab 2.1).
  • A signed commit whose Signed-off-by trailer matches your git identity (a passing DCO check).
  • A correct CHANGELOG.md entry under the unreleased heading.
  • A clean local tools/devtool fmt, checkstyle, and checkbuild --all (Lab 2.2).
  • A walked good-first-issue fix with a test (Lab 2.3).
  • A completed review of the flawed example PR — every issue a maintainer would flag, found and written up (Lab 2.4).
  • A written explanation of why Firecracker requires ≥2 approvals and integration tests.

Common Mistakes

MistakeConsequenceFix
Forgetting -s on a commitDCO bot fails; PR blockedgit commit --amend -s (last commit) or git rebase --signoff <base> (all); force-push.
Signed-off-by email ≠ git emailDCO bot failsgit config user.email to match; re-sign.
No CHANGELOG.md entryExtra review roundAdd one line under the unreleased heading.
Skipping tools/devtool fmtclippy/fmt CI redRun fmt then checkstyle before committing.
Treating clippy warnings as warningsCI is -D warnings; one lint fails the jobFix every clippy lint; never #[allow] to silence without justification.
Many tiny "address review" commitsReviewers ask you to clean historyAmend the relevant commit and force-push; one logical change per commit.
New behavior, no integration testReviewer blocks; coverage gate may failAdd a pytest integration test in tests/.
Grabbing an assigned issueDuplicate work, community frictionCheck assignee and linked PRs; comment intent first.
Adding device/API surface "because QEMU has it"Rejected on the minimal-device-model principleArgue from the threat model, not feature parity.

How to Verify Success

# 1. Your fork and remotes are wired.
git remote -v   # origin = your fork; upstream = firecracker-microvm/firecracker

# 2. Your identity will produce a valid sign-off.
git config user.name; git config user.email

# 3. The local gates are green on a clean checkout.
tools/devtool fmt
tools/devtool checkstyle
tools/devtool checkbuild --all

# 4. A demo signed commit shows the trailer.
git commit -s --allow-empty -m "chore: verify dco sign-off"
git log -1 --format=full | rg 'Signed-off-by'
git reset --hard HEAD~1   # discard the demo commit

If all four pass, you have the mechanics. The labs add the judgment.


PR Profile: Level 2 Graduate

A Level 2 graduate can credibly open these PRs end to end, with green CI and a clean signed history on the first or second push:

PR typeExampleTest requirement
Doc fixCorrect a stale curl/tools/devtool command or a wrong default in docs/.None — docs only; still needs DCO + (often) CHANGELOG.
Error-message fixMake a vmm_config validation error state the actual constraint and the offending value.A unit/integration test asserting the new message.
Help/usage textFix a misleading --flag description in firecracker/jailer.Usually a CLI integration test in tests/.
Small validation gapReject a pre-boot config that was silently accepted.An integration test for the rejection path.
Test improvementAdd a missing assertion or an edge-case case to an existing test.Re-run the affected test.

You are not yet ready to submit changes to the vCPU run loop, virtio device emulation, the boot path, snapshot format/compatibility, seccomp filters, the jailer, or the wire API — those are Levels 3–9. What you are ready for is the thing most new contributors get wrong: a clean, focused, properly-signed, well-tested PR with a CHANGELOG entry that two maintainers can approve without a five-round back-and-forth.

Next: Lab 2.1 — Navigate the Firecracker Repository.