All commits to linuxboot/heads must be:
git commit -S -s -m "component: short description"-S— GPG-sign the commit (required; see CONTRIBUTING.md)-s— addSigned-off-by:trailer for DCO compliance (required; CI enforces this)
Git allows repository-local config to override your global config. Verify and enforce signing in this clone during onboarding:
# Require cryptographic commit signatures in this repository
git config commit.gpgsign true
# Confirm effective values and where they come from
git config --show-origin --get-all commit.gpgsign
git config --show-origin --get-all user.signingkeyUse the full 40-hex fingerprint (not a short key ID) and ensure the UID email matches your Git commit email.
# List secret keys with full fingerprints
gpg --list-secret-keys --keyid-format=long
# Show your configured commit email
git config user.emailChoose the fingerprint for the key whose UID matches git config user.email,
then configure Git to use that exact fingerprint:
# Use the full fingerprint shown by gpg
git config user.signingkey <FULL_40_HEX_FINGERPRINT>
# Optional: set globally instead of repo-local
git config --global user.signingkey <FULL_40_HEX_FINGERPRINT>Verify the effective configuration and signature status:
git config --show-origin --get-all user.signingkey
git commit --allow-empty -S -s -m "test: verify signing setup"
git log -1 --show-signatureOEM Factory Reset / Re-Ownership already exports a public key to USB for you:
- In-memory key backup path: public partition contains
pubkey.asc - Separate USB export path: file is named
<fingerprint>.asc
Import that exported public key into your developer workstation keyring, then point Git signing at the same fingerprint used by the corresponding private key material (dongle or restored backup keyring):
# Import the exported ownership key
gpg --import /path/to/pubkey.asc
# Confirm full fingerprint and UID
gpg --list-keys --fingerprint --keyid-format=long
# Use the full 40-hex fingerprint shown above
git config user.signingkey <FULL_40_HEX_FINGERPRINT>
git config commit.gpgsign trueFor repeated development/contribution cycles on new systems, reuse the exported public key file from ownership provisioning as your canonical reference, and verify with:
git log -1 --show-signatureExpected output for commit.gpgsign should include true for .git/config
or for your global config, and must not include false.
If you already created unsigned commits, rewrite them before opening a PR:
# Re-sign all commits ahead of upstream/master (keeps Signed-off-by trailers)
git rebase -S --rebase-merges origin/mastercomponent: short imperative description (72 chars max)
Optional body explaining the why, not the what. Wrap at 72 chars.
Reference issues or PRs with #NNN.
Signed-off-by: Your Name <email@example.com>
- Subject line: imperative mood ("fix", "add", "remove", not "fixed"/"adds")
- Component prefix: the file or subsystem changed (
oem-factory-reset,tpmr,gui-init,Makefile,doc, etc.) - Body: explain motivation and context; the diff shows what changed
Add a Co-Authored-By: trailer only on commits whose primary content is
collaborative documentation (doc/*.md writing). Never add it to code
fixes, features, or refactors.
Co-Authored-By: Name <email@example.com>
| Location | Purpose | Signing required |
|---|---|---|
doc/*.md in this repo |
Developer-facing: architecture, patterns, internals, build conventions | Yes (same as all commits) |
linuxboot/heads-wiki |
User-facing: installation, configuration, how-to guides published at osresearch.net | No (lower bar for contribution) |
Content should live in doc/*.md when it describes how the code works or how
to build/develop. Content should live in heads-wiki when it describes how a
user installs, configures, or operates a Heads-equipped device.
Over time, doc/*.md and the wiki may overlap; the canonical user-facing
source is the wiki.
For CI internals, cache layering, and workspace-vs-cache behavior, see
circleci.md.
Use the maintainer checklist there when changing .circleci/config.yml.
See build-artifacts.md for the full ROM filename convention. Quick reference:
# Release build (clean tag, e.g. v0.2.1):
heads-x230-v0.2.1.rom
# Development build (any other state):
heads-x230-20260327-202007-my-feature-branch-v0.2.1-42-g0b9d8e4-dirty.rom
# ^timestamp ^branch name ^git describeThe timestamp sorts builds chronologically. The branch name identifies which PR or feature a binary corresponds to without consulting git.
When testing a development build, the ROM filename is your primary build identifier — include it verbatim in bug reports and PR comments.
When touching provisioning code (oem-factory-reset, seal-hotpkey,
gui-init):
- Run a full OEM Factory Reset / Re-Ownership with custom identity (name + email)
- Verify
gpg --card-statusreflects cardholder name and login data - Verify dongle branding shows correctly for the attached device
- Verify TOTP/HOTP sealing succeeds after reset
- Check
/bootsigning succeeds with the new GPG key
When touching the Makefile or build system:
- Verify dev build filename includes timestamp + branch
- Verify a locally-tagged clean commit produces the short filename
- Verify
.zippackage extracts andsha256sum -cpasses - If changing
.circleci/config.yml, verify the documented cache/workspace behavior in circleci.md still matches the pipeline
- All user-visible output through logging helpers:
STATUS,STATUS_OK,INFO,NOTE,WARN,ERROR,DEBUG(see logging.md) - Interactive prompts via
INPUTonly — never rawread - All interactive text output routed through
>"${HEADS_TTY:-/dev/stderr}"to avoid interleaving withDO_WITH_DEBUGbuffered stdout - Terminology: passphrase for TPM/LUKS secrets; PIN for GPG smartcard (OpenPGP spec); never "password" in user-facing text
- Diceware references when prompting users to choose passphrases
See ux-patterns.md for INPUT, STATUS/STATUS_OK,
DO_WITH_DEBUG, HEADS_TTY routing, and PIN caching conventions.