GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat: sign git commits in workspaces with the Coder SSH key by matifali · Pull Request #32056 · coder/coder

Conversation

@matifali

@matifali matifali commented Nov 11, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Closes #22371

Adds an opt-in Sign my commits with my Coder SSH key setting on Account > SSH keys, behind the unsafe git-commit-signing experiment. When it's on, every commit and tag made in the user's workspaces is signed with their Coder git SSH key, including commits made by AI agents running in the workspace. Users don't touch their git config, and no key or config file is written in the workspace.

This replaces the registry git-commit-signing module, which writes the private key to ~/.ssh/git-commit-signing/coder and edits the user's global git config.

SSH keys page with the signing checkbox

How it works

  1. The user checks the box. It's stored as a sign_commits_with_ssh_key user preference.
  2. When the agent connects, the manifest carries the user's public key. The agent sets GIT_CONFIG_* env vars in new sessions: commit.gpgsign, tag.gpgsign, gpg.format=ssh, user.signingkey, and gpg.ssh.program pointing at the coder binary.
  3. On git commit, git runs coder -Y sign .... The hidden gitsign-ssh command fetches the key with the same endpoint coder gitssh uses, signs in memory, and writes the .sig file git reads. The private key never touches disk.

Enable with CODER_EXPERIMENTS=git-commit-signing. Requires git 2.34 or later in the workspace.

Diagrams

Signing flow. One-time setup, what happens when the agent connects, and what happens on every commit:

sequenceDiagram
    autonumber
    actor U as User
    participant UI as Coder UI
    participant S as coderd
    participant DB as Database
    participant A as Workspace agent
    participant G as git
    participant C as coder binary (gitsign-ssh)

    rect rgba(127,127,127,0.1)
    Note over U,DB: One-time setup
    U->>UI: Check "Sign my commits with my Coder SSH key"
    UI->>S: PUT /api/v2/users/me/preferences
    S->>DB: Save sign_commits_with_ssh_key = true
    end

    rect rgba(127,127,127,0.1)
    Note over S,A: Each time the agent connects, for example after a restart
    A->>S: GetManifest (dRPC, Agent API v2.17)
    S->>DB: Experiment on? Read preference and public key
    S-->>A: Manifest with git_signing_public_key
    A->>A: Add 5 GIT_CONFIG_* env entries to new sessions
    end

    rect rgba(127,127,127,0.1)
    Note over U,C: Every commit or tag
    U->>G: git commit
    G->>C: coder -Y sign -n git -f PUBKEY -U BUFFER
    C->>S: GET /api/v2/workspaceagents/me/gitsshkey (agent token, same as coder gitssh)
    S-->>C: Key pair
    C->>C: Hash BUFFER with SHA-512 and sign SSHSIG in memory
    C->>G: Write BUFFER.sig
    G->>G: Embed signature in the commit object
    end
Loading

Which sessions sign:

flowchart TD
    start([New session in the workspace]) --> exp{git-commit-signing experiment on?}
    exp -- No --> none[No signing config. git behaves as usual]
    exp -- Yes --> pref{User checked Sign my commits?}
    pref -- No --> none
    pref -- Yes --> sign[GIT_CONFIG_* set: commit.gpgsign, tag.gpgsign, gpg.format=ssh, gpg.ssh.program=coder, user.signingkey]
    sign --> commit[git commit and git tag are signed in the workspace]
Loading
Implementation details
  • Setting: a new sign_commits_with_ssh_key user preference in user_configs (no migration), exposed through the existing preferences API.
  • Manifest: when the experiment and the setting are both on, the agent manifest carries the owner's public key in a new git_signing_public_key field. The Agent API is bumped to v2.17 for it.
  • Agent: agent/agentgitsign injects the config through GIT_CONFIG_COUNT/GIT_CONFIG_KEY_n/GIT_CONFIG_VALUE_n, appended after any count the template already set.
  • No wrapper: gpg.ssh.program is the coder binary itself. Git runs it with ssh-keygen style arguments, and RunWithSubcommands sends any -Y ... invocation to the hidden gitsign-ssh command. No coder command takes -Y.
  • Signing: gitsign-ssh fetches the key pair with the existing GET /api/v2/workspaceagents/me/gitsshkey, parses it, hashes the payload with SHA-512, signs an SSHSIG blob in memory, and writes <payload>.sig. Verification operations pass through to ssh-keygen unchanged, exit code included.
  • UI: the checkbox only appears when the experiment is enabled. The * wildcard only enables safe experiments.
Known limitations
  • Key exposure: signing happens in the workspace with the same key the agent can already fetch for git push/pull. This adds no new exposure, but it doesn't keep the key out of the workspace either; that would need a separate signing key no endpoint returns.
  • Precedence: environment config overrides the user's own signing config, including commit.gpgsign=false. This is acceptable for an opt-in setting.
  • Timing: the agent reads the setting when it connects, so turning it on or off takes effect after the next agent connect, for example a workspace restart.
  • Key rotation: rotating the key (coder publickey --reset) means new commits need the new key registered with the git provider.
  • Windows: expected to work, since nothing in the path is OS-specific, but untested.
  • Docs: none, because unsafe experiments don't need docs under docs/.style/content-guidelines.md.
Testing
  • Signer: agent/agentgitsign SSHSIG signatures verify with ssh-keygen -Y verify for ed25519, ECDSA and RSA. A signature made for git is rejected under another namespace.
  • CLI: tests cover signing end to end against the existing gitsshkey endpoint (verified with ssh-keygen), verification pass-through, argument parsing and -Y dispatch.
  • Manifest: tests cover gating on the experiment and the setting.
  • Agent: tests check the env block and that an existing GIT_CONFIG_COUNT is preserved.
  • Frontend: a Vitest test for the toggle, plus Storybook stories.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@matifali
matifali temporarily deployed to main November 11, 2026 15:13 — with GitHub Actions Inactive
@matifali
matifali temporarily deployed to main November 11, 2026 15:13 — with GitHub Actions Inactive
@github-actions github-actions Bot assigned matifali Nov 11, 2026
@matifali
matifali temporarily deployed to main November 11, 2026 15:24 — with GitHub Actions Inactive
@matifali
matifali temporarily deployed to main November 11, 2026 15:47 — with GitHub Actions Inactive
@matifali
matifali temporarily deployed to main November 11, 2026 15:47 — with GitHub Actions Inactive
@matifali
matifali temporarily deployed to main November 11, 2026 15:51 — with GitHub Actions Inactive
@matifali
matifali temporarily deployed to main November 11, 2026 15:54 — with GitHub Actions Inactive
@matifali
matifali temporarily deployed to main November 11, 2026 16:23 — with GitHub Actions Inactive
@matifali
matifali temporarily deployed to main November 11, 2026 16:23 — with GitHub Actions Inactive
@matifali matifali added the experimental Changes that might not necessarily be merged, until its approved to proceed with. label Nov 12, 2026
@matifali
matifali temporarily deployed to main November 12, 2026 05:00 — with GitHub Actions Inactive
@matifali
matifali marked this pull request as ready for review November 12, 2026 05:00
@matifali
matifali requested review from a team, mafredri and spikecurtis as code owners November 12, 2026 05:00
@matifali
matifali temporarily deployed to main November 12, 2026 05:00 — with GitHub Actions Inactive
matifali added 5 commits November 12, 2026 10:01
@matifali
feat: sign git commits in workspaces with the Coder SSH key
d7828fd
Add an opt-in "Sign my commits with my Coder SSH key" setting on
Account > SSH keys, behind the unsafe git-commit-signing experiment.

When enabled, the agent configures commit and tag signing through
GIT_CONFIG_* environment variables and points gpg.ssh.program at the
coder binary. `coder gitsign-ssh` hashes the payload and asks a new
agent-only endpoint, POST /api/v2/workspaceagents/me/experimental/gitsign,
to sign the digest with the owner's git SSH key on the server. No file is
written in the workspace.
@matifali
fix: check GIT_CONFIG_COUNT parse error and fix import order
1a9e640
@matifali
feat: skip Coder commit signing in SSH sessions that forward an agent
732f439
Sessions opened with ssh -A or coder ssh -A bring the user's own keys, so the agent strips its GIT_CONFIG_* signing entries there and the user's git config applies. Also bump the Agent API to v2.17 for the git_signing_public_key manifest field.
@matifali
chore: remove leftovers from earlier commit signing iterations
b805503
Correct comments that claimed the private key never reaches the workspace, note the experiment gate on the manifest field, and drop a preference setup the signing endpoint no longer reads.
@matifali
refactor: sign git commits in the workspace instead of on the server
26de19b
Remove the experimental gitsign endpoint and its SDK types. coder
gitsign-ssh now fetches the key pair with the existing agent gitsshkey
endpoint, as coder gitssh does, and signs the SSHSIG blob in memory, so
the private key is never written to disk. The signer moves to
agent/agentgitsign.

Drop the carve-out that skipped signing in sessions that forward an SSH
agent, and correct the minimum git version for SSH signing to 2.34.
@matifali
matifali temporarily deployed to main November 12, 2026 05:27 — with GitHub Actions Inactive
@matifali
chore: regenerate API docs after rebase
b53a124
@matifali
matifali force-pushed the feat/git-commit-signing branch from dfb88b6 to b53a124 Compare November 12, 2026 05:30
@matifali
matifali temporarily deployed to main November 12, 2026 05:30 — with GitHub Actions Inactive
@matifali
matifali marked this pull request as draft November 12, 2026 15:42
coderagents[bot]
coderagents Bot reviewed Nov 12, 2026
View reviewed changes

@coderagents coderagents Bot left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation check for this round of commits. The git-commit-signing experiment is unsafe, and the only docs touched are auto-generated API reference, so review focuses on the Go source comment that generates it.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread codersdk/users.go
CollapseAssistantSteps bool `json:"collapse_assistant_steps"`
AgentChatSendShortcut AgentChatSendShortcut `json:"agent_chat_send_shortcut"`
// SignCommitsWithSSHKey signs git commits and tags in the user's
// workspaces with their Coder git SSH key.

@coderagents coderagents Bot Nov 12, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generated API description says the setting "signs git commits and tags" unconditionally, but it only has an effect when the unsafe git-commit-signing experiment is enabled: coderd/agentapi/manifest.go only reads this preference and puts the public key on the manifest when a.Experiments.Enabled(codersdk.ExperimentGitCommitSigning), and agent/agent.go only appends the GIT_CONFIG_* signing entries when manifest.GitSigningPublicKey != "". A reader of the API reference (docs/reference/api/schemas.md) could enable the flag on a deployment without the experiment and wrongly conclude commits are now signed. (Fact Checker, Newcomer)

Suggested change
// workspaces with their Coder git SSH key.
// SignCommitsWithSSHKey signs git commits and tags in the user's
// workspaces with their Coder git SSH key when the git-commit-signing
// experiment is enabled.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread codersdk/users.go
CollapseAssistantSteps bool `json:"collapse_assistant_steps"`
AgentChatSendShortcut AgentChatSendShortcut `json:"agent_chat_send_shortcut"`
// SignCommitsWithSSHKey signs git commits and tags in the user's
// workspaces with their Coder git SSH key.

@coderagents coderagents Bot Nov 12, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: This names the key "Coder git SSH key" (lowercase "git"), but every other docs page that names the same key calls it "Coder Git SSH key" (capital "Git"): docs/admin/external-auth.md:152 ("View your Coder Git SSH key:") and docs/workspaces/shared-workspaces.md:150,200. Per docs/.style/style-guide/word-choice.md#one-term-per-concept (One term per concept), pick one name for the thing and use it everywhere. This generated description introduces a second casing for the same key. (Continuity Editor)

Suggested change
// workspaces with their Coder git SSH key.
// workspaces with their Coder Git SSH key.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

This branch was previously deployed

1 inactive deployment
main — b53a1241 Deployed Nov 12, 2026 by matifali via cla #254728
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@spikecurtis spikecurtis Awaiting requested review from spikecurtis spikecurtis is a code owner
@mafredri mafredri Awaiting requested review from mafredri mafredri is a code owner
1 more reviewer
@coderagents coderagents[bot] coderagents[bot] left review comments
Reviewers whose approvals may not affect merge requirements

At least 1 approving review is required to merge this pull request.

Uh oh!

There was an error while loading. Please reload this page.

Assignees

@matifali matifali

Labels

experimental Changes that might not necessarily be merged, until its approved to proceed with.

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

feat: native opt-in git commit signing using Coder SSH key

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@matifali
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.