chore: update devcontainer documentation to clarify signing setup and lifecycle hooks

This commit is contained in:
Denys Vuika
2026-07-08 14:40:24 +00:00
parent b40dfdd1f3
commit 38bab90cd7
2 changed files with 34 additions and 48 deletions
+4 -7
View File
@@ -25,7 +25,9 @@ Rebuild (**Dev Containers: Rebuild Container**) after changing
- **Chromium** for Karma / `ChromeHeadless` tests (`CHROME_BIN` is preset) - **Chromium** for Karma / `ChromeHeadless` tests (`CHROME_BIN` is preset)
- **GitHub CLI** (`gh`) via the `github-cli` dev container feature - **GitHub CLI** (`gh`) via the `github-cli` dev container feature
- **gnupg2** so the host `gpg-agent` can be forwarded for signed commits - **gnupg2** so the host `gpg-agent` can be forwarded for signed commits
- Persistent pnpm store volume and warm Nx daemon (`NX_DAEMON=true`) - Persistent pnpm store and bash history volumes
- Script-based lifecycle hooks: `.devcontainer/post-create.sh` and `.devcontainer/post-start.sh`
- Warm Nx daemon (`NX_DAEMON=true`)
## GitHub CLI ## GitHub CLI
@@ -110,7 +112,7 @@ The host `gpg-agent` forwarding is still required for actual signing operations.
``` ```
3. Rebuild the container. If the host pubring is mounted, signing should work 3. Rebuild the container. If the host pubring is mounted, signing should work
without export/import. If it is not mounted, the `postStartCommand` imports without export/import. If it is not mounted, `postStartCommand` imports
`.git/signing.pub` when available. `.git/signing.pub` when available.
The helper auto-selects `gpg2`/`gpg` based on where your key is visible, which The helper auto-selects `gpg2`/`gpg` based on where your key is visible, which
@@ -119,11 +121,6 @@ avoids host setups where the two binaries use different keyrings.
If you rotate keys, rebuild so the mounted pubring reflects host changes. If you If you rotate keys, rebuild so the mounted pubring reflects host changes. If you
use the fallback export/import path, run the export helper again before rebuild. use the fallback export/import path, run the export helper again before rebuild.
Expected behavior after rebuild:
- Signing keeps working when host forwarding/import and `.git/signing.pub` are in sync.
- If signing breaks after rebuild (especially after key rotation), regenerate `.git/signing.pub` with the helper and rebuild again.
After **Rebuild Container** (or next container start), verify in the container: After **Rebuild Container** (or next container start), verify in the container:
```bash ```bash
+30 -41
View File
@@ -9,6 +9,8 @@ This repository includes a Dev Container configuration to provide a consistent l
- pnpm provisioned by Corepack from `package.json#packageManager` (single source of truth) - pnpm provisioned by Corepack from `package.json#packageManager` (single source of truth)
- Non-root development user configuration (node) - Non-root development user configuration (node)
- Persistent pnpm store volume for faster reinstall times - Persistent pnpm store volume for faster reinstall times
- Persistent bash history volume
- Script-based lifecycle hooks (`.devcontainer/post-create.sh`, `.devcontainer/post-start.sh`)
## Daily Workflow ## Daily Workflow
@@ -65,12 +67,12 @@ The VS Code Dev Containers extension automatically handles part of this:
(the actual signing). (the actual signing).
- Your host SSH agent is forwarded, so `git push` over SSH uses your host keys. - Your host SSH agent is forwarded, so `git push` over SSH uses your host keys.
**Important**: VS Code forwards the host agent socket but does **not** automatically By default this devcontainer bind-mounts the host public keyring file
copy the host GPG public keyring into the container. GPG needs both a public key (`${localEnv:HOME}/.gnupg/pubring.kbx`) into the container at
entry in the local keyring (to select which key to use) and the forwarded agent `/home/node/.gnupg/pubring.kbx` (read-only), so you usually do not need
socket (to perform the signing). If the public key is missing from the container export/import for rebuilds.
keyring, `gpg --clearsign` will fail with `No secret key` even though the host
agent is reachable and the forwarding is active. The host `gpg-agent` forwarding is still required for the actual signing step.
This is the one-time host-side setup: This is the one-time host-side setup:
@@ -81,7 +83,8 @@ This is the one-time host-side setup:
git config --global commit.gpgsign true git config --global commit.gpgsign true
``` ```
2. Export your public key so the container can import it on startup: 2. Optional fallback: export your public key so the container can import it on
startup when the host pubring mount is unavailable:
```bash ```bash
./.devcontainer/export-signing-key.sh ./.devcontainer/export-signing-key.sh
@@ -93,24 +96,19 @@ This is the one-time host-side setup:
.\.devcontainer\export-signing-key.ps1 .\.devcontainer\export-signing-key.ps1
``` ```
3. Rebuild the container. The `postStartCommand` auto-imports `.git/signing.pub` 3. Rebuild the container. If the host pubring is mounted, signing should work
on every container start, so signing survives restarts and rebuilds without without export/import. If it is not mounted, `postStartCommand` imports
re-running the export script. `.git/signing.pub` when available.
Then verify inside the container: Then verify inside the container:
```bash ```bash
gpg --list-secret-keys --keyid-format=long # should list your key gpg --list-secret-keys --keyid-format=long # should list your key
git commit -S -m "your message" # -S optional when commit.gpgsign is true git commit -S -m "test signed commit" # -S optional when commit.gpgsign is true
git push
``` ```
If you rotate keys, run the export helper again on the host before the next rebuild. If you rotate keys, rebuild so the mounted pubring reflects host changes. If you
use the fallback export/import path, run the export helper again before rebuild.
Expected behavior after rebuild:
- Signing keeps working when the host agent forwarding and `.git/signing.pub` import are in sync.
- If signing breaks after rebuild (especially after key rotation), regenerate `.git/signing.pub` with the helper and rebuild again.
If signing still fails, follow [Signing (GPG/PGP) Troubleshooting](#signing-gpgpgp-troubleshooting). If signing still fails, follow [Signing (GPG/PGP) Troubleshooting](#signing-gpgpgp-troubleshooting).
@@ -119,19 +117,12 @@ If signing still fails, follow [Signing (GPG/PGP) Troubleshooting](#signing-gpgp
> `@devcontainers/cli`, mount `~/.gnupg`, `~/.gitconfig`, and the agent sockets > `@devcontainers/cli`, mount `~/.gnupg`, `~/.gitconfig`, and the agent sockets
> yourself. > yourself.
### Option B: Sign Commits on Host ### Alternatives
Policy alternative for strongest key isolation: If your team prefers a different signing model, use one of these:
- Keep private signing keys only on the host. - **Host-only signing**: do development in the container, then commit/sign from a host terminal.
- Do development in the container, then commit from a host terminal. - **CI/host merge signing**: allow unsigned local commits, enforce signing at merge/release time.
### Option C: Unsigned Commits in Container, Signed Merge in CI/Host
Policy alternative for simpler contributor setup:
- Commit in container without local signing.
- Enforce signing at merge/release time in host/CI controls.
### Practical Daily Pattern ### Practical Daily Pattern
@@ -172,14 +163,21 @@ Useful files to inspect:
If `git commit -S` fails in the container: If `git commit -S` fails in the container:
1. Confirm host signing config: 1. Check host signing config:
```bash ```bash
git config --global user.signingkey git config --global user.signingkey
git config --global commit.gpgsign git config --global commit.gpgsign
``` ```
2. Refresh the rebuild-safe public key file on the host: 2. Rebuild the container, then test in-container:
```bash
gpg --list-secret-keys --keyid-format=long
git commit -S -m "test signed commit"
```
3. If key lookup still fails, use fallback public-key export on the host, then rebuild:
```bash ```bash
./.devcontainer/export-signing-key.sh ./.devcontainer/export-signing-key.sh
@@ -191,16 +189,7 @@ If `git commit -S` fails in the container:
.\.devcontainer\export-signing-key.ps1 .\.devcontainer\export-signing-key.ps1
``` ```
3. Rebuild the container. 4. If signing still fails, restart host agent forwarding and rebuild:
4. Verify inside container:
```bash
gpg --list-secret-keys --keyid-format=long
git commit -S -m "test signed commit"
```
5. If it still fails, restart host agent forwarding and rebuild:
```bash ```bash
gpgconf --launch gpg-agent gpgconf --launch gpg-agent