1
0
Fork 0
mirror of https://github.com/photostructure/git-ssh-signing-action.git synced 2025-12-26 21:43:32 -05:00
Easy verified commits in GitHub Actions with no GPG hassles https://github.com/marketplace/actions/git-ssh-signing-action
Find a file
2025-12-16 14:03:07 -08:00
.claude chore: update settings for testing and add 'pinact' to cSpell dictionary 2025-08-21 15:10:20 -07:00
.devcontainer Initial commit 2025-06-16 10:47:57 -07:00
.github chore: update CodeQL action versions to v4.31.9 and upload-artifact to v6.0.0 2025-12-16 13:54:01 -08:00
.vscode chore: update settings for testing and add 'pinact' to cSpell dictionary 2025-08-21 15:10:20 -07:00
__fixtures__ chore: remove template files and unused code 2025-06-16 14:14:42 -07:00
__tests__ test: consolidate tests to favor integration over heavy mocking 2025-06-17 12:41:12 -07:00
dist chore(dist): rebuild bundles after dependency updates 2025-12-16 14:03:07 -08:00
doc chore(fmt): whitespace 2025-08-21 15:04:35 -07:00
script Initial commit 2025-06-16 10:47:57 -07:00
src fix(windows): improve Windows SSH key permission handling and error diagnostics 2025-08-27 15:22:38 -07:00
.env.example Initial commit 2025-06-16 10:47:57 -07:00
.gitattributes Initial commit 2025-06-16 10:47:57 -07:00
.gitignore Initial commit 2025-06-16 10:47:57 -07:00
.markdown-lint.yml feat(release): add GitHub Actions workflow for automated tag updates on release 2025-06-18 10:51:52 -07:00
.ncurc.json chore(fmt) 2025-11-12 10:48:34 -08:00
.node-version Initial commit 2025-06-16 10:47:57 -07:00
.prettierignore Initial commit 2025-06-16 10:47:57 -07:00
.prettierrc build: configure TypeScript build and bundling 2025-06-16 14:13:45 -07:00
.yaml-lint.yml Initial commit 2025-06-16 10:47:57 -07:00
action.yml feat(git): add configurable git config scope with local as default 2025-06-17 12:37:51 -07:00
CHANGELOG.md chore(fmt) 2025-12-16 13:52:32 -08:00
CLAUDE.md chore(fmt): whitespace 2025-08-21 15:04:35 -07:00
CONTRIBUTING.md docs: add comprehensive documentation for v0.1.0 2025-06-16 14:14:15 -07:00
eslint.config.mjs chore: update tsconfigRootDir in eslint configuration to use __dirname 2025-08-27 15:15:55 -07:00
jest.config.js feat: support windows 2025-08-27 15:16:07 -07:00
LICENSE docs: add comprehensive documentation for v0.1.0 2025-06-16 14:14:15 -07:00
package-lock.json chore(deps): npm audit fix --force 2025-12-16 13:54:47 -08:00
package.json chore(deps): npm audit fix --force 2025-12-16 13:54:47 -08:00
README.md docs: add configuration details for SSH signing in README 2025-12-10 10:08:59 -08:00
RELEASE.md chore: use v1.2.3 as a better version example 2025-08-21 15:17:47 -07:00
rollup.config.ts build: configure TypeScript build and bundling 2025-06-16 14:13:45 -07:00
SECURITY.md docs: add comprehensive documentation for v0.1.0 2025-06-16 14:14:15 -07:00
TODO.md docs: add comprehensive documentation for v0.1.0 2025-06-16 14:14:15 -07:00
tsconfig.base.json Initial commit 2025-06-16 10:47:57 -07:00
tsconfig.eslint.json build: configure TypeScript build and bundling 2025-06-16 14:13:45 -07:00
tsconfig.json Initial commit 2025-06-16 10:47:57 -07:00

Git SSH Signing Action

Verified

Easy verified commits in GitHub Actions with no GPG hassles

GitHub Marketplace GitHub

Why?

Unsigned commits look suspicious. GitHub shows "Verified" badges on signed commits, proving they're authentic. Signing commits with GPG within CI is tricky. Signing commits with SSH is much simpler.

This action makes it trivial.

Usage

Add this to your workflow (e.g., .github/workflows/release.yml):

steps:
  - uses: actions/checkout@v4 # Must come first!

  - uses: photostructure/git-ssh-signing-action@v1
    with:
      ssh-signing-key: ${{ secrets.SSH_SIGNING_KEY }}
      git-user-name: ${{ secrets.GIT_USER_NAME }}
      git-user-email: ${{ secrets.GIT_USER_EMAIL }}

Important: This action must be placed after actions/checkout because it configures git locally by default.

Configuration Options

Input Required Default Description
ssh-signing-key - SSH private key for signing
git-user-name - Git user name
git-user-email - Git user email
ssh-key-path ~/.ssh/signing_key Where to store the key
git-commit-gpgsign true Sign all commits
git-tag-gpgsign true Sign all tags
git-push-gpgsign if-asked Sign pushes
git-config-scope local Use global to configure git globally

Using Global Configuration

If you need the action to work before checkout or across multiple repositories:

steps:
  - uses: photostructure/git-ssh-signing-action@v1
    with:
      ssh-signing-key: ${{ secrets.SSH_SIGNING_KEY }}
      git-user-name: ${{ secrets.GIT_USER_NAME }}
      git-user-email: ${{ secrets.GIT_USER_EMAIL }}
      git-config-scope: global # Works anywhere in workflow

What Gets Configured

The action automatically configures Git for SSH signing by setting these config values:

Config Key Value Effect
user.name From git-user-name input Sets commit author name
user.email From git-user-email input Sets commit author email
gpg.format ssh Tells Git to use SSH signing instead of GPG
user.signingkey Path to public key Specifies which SSH key to use for signing
commit.gpgsign true (default) Automatically signs all commits
tag.gpgsign true (default) Automatically signs all tags
push.gpgsign if-asked (default) Signs pushes only if requested by remote server
gpg.ssh.allowedSignersFile (optional) Enables local verification of signatures

Important: Once configured, you don't need to add signing flags to git commands:

# These commands will be automatically signed:
git commit -m "feat: add new feature"
git tag v1.0.0

# No need for:
# git commit -S -m "..."  ❌
# git tag -s v1.0.0       ❌

Automatic signing happens because commit.gpgsign and tag.gpgsign are set to true.

Setup (5 Minutes)

1. Generate SSH Key

# Generate Ed25519 key (recommended)
# -N "" creates a passwordless key (required for CI)
# -C must match the GitHub username that will own this key
ssh-keygen -t ed25519 -f ~/.ssh/signing-key -N "" -C "yourproject-bot"

# Copy public key for next step
cat ~/.ssh/signing-key.pub

2. Add to GitHub

  1. Sign in as your machine user account (if using one)
  2. Go to Settings → SSH and GPG keys
  3. Click New SSH key
  4. Critical: For "Key type", select "Signing Key" (⚠️ NOT "Authentication Key")
  5. Title: Repository Release Signing Key
  6. Key: Paste the contents from cat ~/.ssh/signing-key.pub
  7. Click Add SSH key

3. Create Repository Secrets

# Copy private key to clipboard (macOS)
cat ~/.ssh/signing-key | pbcopy

# Copy private key to clipboard (Linux)
cat ~/.ssh/signing-key | xclip -selection clipboard

Repository → Settings → Secrets → Actions:

  • SSH_SIGNING_KEY = private key (paste from clipboard)
  • GIT_USER_NAME = machine user's GitHub username (e.g., yourproject-bot)
  • GIT_USER_EMAIL = machine user's email

4. Clean Up Local Keys

rm ~/.ssh/signing-key ~/.ssh/signing-key.pub

Done! Your commits will now be verified.

Platform Support

This action supports GitHub Actions runners on all major platforms:

Platform Status Notes
Ubuntu Fully Supported Primary development platform
Windows Fully Supported Uses Windows ACLs for file permissions
macOS Fully Supported Standard Unix permissions

Windows-Specific Considerations

On Windows runners, the action automatically handles platform differences:

  • File Permissions: Uses Windows ACLs (icacls) instead of Unix permissions for SSH key security
  • SSH Agent: Handles Git for Windows SSH implementation gracefully with enhanced error messages
  • Path Handling: Uses platform-appropriate path resolution

No additional configuration is needed for Windows compatibility.

Pro Tips

Use a machine user account (commonly called a "bot account") for production.

Why not use your personal account?

  • Security: If CI credentials leak, only the machine user is compromised, not your personal account
  • Persistence: When team members leave, automation continues working
  • Audit trail: Clear distinction between human and automated commits
  • Access control: Machine user permissions can be limited to specific repositories

Steps to set up a machine user:

  1. Create Machine User Account

    • Sign up at github.com/join as yourproject-bot
    • Use a real email (needed for collaborator invite)
    • Enable 2FA (required by many orgs)
  2. Add Machine User as Collaborator

    • Repository Settings → Collaborators → Add people
    • Grant write access (needed for pushes)
    • Machine user must accept invite via email
  3. Generate Machine User's Key

    # IMPORTANT: -C must match your machine user's GitHub username exactly
    ssh-keygen -t ed25519 -f ~/.ssh/machine-user-signing -N "" -C "yourproject-bot"
    
    # Display the public key (you'll need this for GitHub)
    cat ~/.ssh/machine-user-signing.pub
    

    Use this key in your secrets instead.

Troubleshooting

Problem Solution
Commits show "Unverified" Add key as "Signing Key" not "Authentication Key"
Permission denied Give bot write access to repository
Key load failed Check secret has complete private key
Windows permission errors Action handles ACLs automatically - check debug logs
SSH agent warnings Normal on Windows due to SSH implementation differences

Requirements

  • Runners: ubuntu-latest, windows-2025, or macos-latest
  • Git: 2.34+ (for SSH signing)

License

MIT © PhotoStructure


IssuesContributing