A developer laptop is a build station. It holds source code, signing material, cloud credentials and tokens that can push to production pipelines. If it is lost or compromised, everything upstream of review is exposed.
This is a checklist you can run in a single day, either alone or as a team session. Each item has a check, a fix, and a way to know you are done.
1. Full-disk encryption
This is the control that matters most when a laptop is lost or stolen, and it is usually already available. Check it rather than assume.
# macOS
fdesetup status
# Linux: look for crypto_LUKS on the root device
lsblk -o NAME,FSTYPE,MOUNTPOINT
# Windows (admin prompt)
manage-bde -status C:
Done when: encryption is on, the recovery key is escrowed somewhere the organisation controls, and the screen locks after a short idle time.
2. Secrets out of dotfiles
Tokens collect in ~/.bashrc, ~/.zshrc, .env files, tool configs under ~/.config, and shell history. Any process running as you can read them, including scripts, extensions and package install hooks.
# Scan home config and shell files with Gitleaks
gitleaks dir ~/.config --no-banner
gitleaks dir ~/.zshrc --no-banner
gitleaks dir ~/.zsh_history --no-banner
# Quick manual pass for exported tokens
grep -nE '^export .*(TOKEN|SECRET|KEY)=' ~/.bashrc ~/.zshrc 2>/dev/null
Move what you find into the OS keychain or your secrets manager and load it on demand. For example, on macOS:
security add-generic-password -a "$USER" -s example-api -w
export EXAMPLE_API_TOKEN="$(security find-generic-password -s example-api -w)"
Done when: a scan of dotfiles and history comes back clean, and any token that was exposed in plain text has been rotated, not just moved.
3. SSH keys with hardware or an agent
An unencrypted id_rsa in ~/.ssh is a portable credential. Prefer a key that cannot leave a hardware token. Most FIDO2 security keys support this with OpenSSH 8.2 or later:
# Hardware-backed key; requires touch for every use
ssh-keygen -t ed25519-sk -O resident -C "laptop-$(hostname)"
# If no hardware key: a passphrase-protected key held in an agent
ssh-keygen -t ed25519 -C "laptop-$(hostname)"
ssh-add --apple-use-keychain ~/.ssh/id_ed25519 # macOS
ssh-add ~/.ssh/id_ed25519 # Linux
Remove old keys from your Git host and servers once the new one works. Avoid agent forwarding to hosts you do not fully trust; use ProxyJump instead.
Done when: no unencrypted private keys remain, and old public keys are gone from every account.
4. Git commit signing
Signing lets reviewers and branch protection rules tell your commits from someone using your name in git config. Git supports SSH keys for signing, so you can reuse the key from step 3.
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519_sk.pub
git config --global commit.gpgsign true
git config --global tag.gpgsign true
# Verify
git commit --allow-empty -m "test signed commit"
git log --show-signature -1
Upload the public key to your Git host as a signing key, then consider requiring signed commits on protected branches.
Done when: new commits show as verified on the Git host.
5. Least-privilege tokens
Classic personal access tokens often carry every scope the user has, never expire, and work on every repository. Replace them.
- Use fine-grained tokens limited to the repositories and permissions a task needs.
- Set an expiry. Short-lived beats convenient.
- Prefer the CLI's own login flow, such as
gh auth login, which stores credentials in the keychain. - For cloud access, use short-lived SSO sessions rather than long-lived access keys in
~/.aws/credentialsor similar files. - Give each tool, script or assistant its own token so you can revoke one without breaking the rest.
Done when: no token in use is older than its expiry policy, and none has broader scope than its job.
Run it as a team
| # | Control | Check | Owner |
|---|---|---|---|
| 1 | Disk encryption on, key escrowed | fdesetup status or equivalent | Each developer |
| 2 | No secrets in dotfiles or history | Gitleaks scan clean | Each developer |
| 3 | SSH keys hardware-backed or protected | No unencrypted keys in ~/.ssh | Each developer |
| 4 | Commits signed | Verified badge on Git host | Each developer, then repo admins |
| 5 | Tokens scoped and expiring | Token list reviewed | Each developer, then platform team |
Book a morning, share this table, and have everyone work through it together. The afternoon is for the stragglers and for turning the checks into something your device management can report on.
Where this sits on the line
In the tower (in development):