Summary
CI/CD attestations signed with ephemeral keys are cryptographically verifiable via auths verify-commit, but GitHub's web UI will not display a "Verified" badge because GitHub does not recognize the ephemeral SSH public key. This is a UX gap that blocks adoption: developers expect green checkmarks in GitHub UI.
Future work (v2): Auto-upload ephemeral SSH public key to GitHub before signing, then auto-delete after signing. This gives the ephemeral key a registered presence on GitHub, allowing commits to show as "Verified" in the UI while maintaining the ephemeral key guarantee (never persisted to CI runner disk, single-use only).
Context
fn-85 (Machine Identity via OIDC, v1) creates ephemeral KERI identities in CI with OIDC token binding. Commits signed with these ephemeral keys are verifiable via:
auths verify-commit --ref HEAD
# ✓ Signature valid
# ✓ OIDC token binding verified (GitHub Actions, commit SHA abc123, actor octocat)
# ✓ Timestamp proof valid (Sigstore TSA)
However, in GitHub's web UI:
[Unverified] This commit was signed with an unrecognized key.
Why: GitHub only recognizes SSH keys registered to user accounts or GitHub Apps. The ephemeral key exists only in CI runner memory, never uploaded to GitHub.
Why it matters for adoption: Enterprise users expect visual feedback in GitHub UI. The "Verified" badge is a compliance requirement for many organizations. Without it, the feature is perceived as incomplete even though the cryptographic verification is more secure than GitHub's centralized model.
Proposed Solution (v2)
Extend auths init --profile ci to:
-
Before signing (same job step or automatically before first auths sign):
- Generate ephemeral Ed25519 keypair (already done)
- Extract public key in OpenSSH wire format
- Call GitHub API (like fn-84):
POST /user/ssh_signing_keys with Bearer token
- Store returned key ID in identity metadata
- Log: "Registered ephemeral SSH key abc123def... to GitHub"
-
During signing (existing flow):
- Sign commits/artifacts as normal with ephemeral key
- GitHub recognizes the signature (key is registered)
- Commits appear as "Verified" in UI ✓
-
After job completion (cleanup):
- Delete SSH key from GitHub via API:
DELETE /user/ssh_signing_keys/{key_id}
- Log: "Deleted ephemeral SSH key from GitHub"
- Key is gone; cannot be reused
Technical Approach
Reuse from fn-84
HttpGitHubSshKeyUploader trait (already implemented)
- Pre-flight GET to detect duplicate keys (idempotent)
- Error handling for 401 (invalid token), 403 (missing scope), 429 (rate limit)
- Exponential backoff with jitter
New Code
- Extend
CiIdentityConfig with auto_register_ssh_key: bool flag (default: true)
- Add CI job lifecycle hooks:
before_signing(): upload SSH key
after_job(): delete SSH key
- Error handling: non-fatal (don't block signing if upload fails)
- Logging: clear messages on success/failure
Config Example
# .github/workflows/sign.yml
- name: Initialize CI signing identity
run: auths init --profile ci --auto-register-ssh-key
# Auto-uploads ephemeral SSH key, signs commits, then auto-deletes
- name: Sign commit
run: |
git config user.signingKey $(auths key-id)
git commit --allow-empty -m "auto-signed" -S
# Commit shows as Verified in GitHub UI ✓
- name: Cleanup (auto-deletes SSH key)
if: always()
run: auths cleanup --delete-ssh-keys
Acceptance Criteria
Dependencies
- fn-85 (Machine Identity via OIDC) must be shipped first
- fn-84 (SSH key upload to GitHub) already implemented; can reuse code
- GitHub API:
/user/ssh_signing_keys endpoint
- On-exit hooks or cleanup command for key deletion
Security Considerations
- Key lifetime: Ephemeral key exists only for the duration of the CI job (5-15 min max)
- Isolation: Key is per-run, not shared across jobs
- Cleanup: Ensure key is deleted even if job fails (use GitHub Actions
if: always())
- Token scope: Requires
write:ssh_signing_key scope (same as fn-84)
- Revocation: If cleanup fails, key remains on GitHub for its lifetime; acceptable risk (short-lived OIDC binding limits blast radius)
Open Questions
-
Should this be automatic (default: true) or opt-in (default: false)?
- Recommendation: Automatic. Most users want the green badge. Opt-out with
--no-auto-register-ssh-key if paranoid about API calls.
-
Should we support GitLab and CircleCI auto-registration too (v2+1)?
- Recommendation: Start with GitHub (highest adoption). GitLab/CircleCI can follow.
-
What if the cleanup fails and the key remains on GitHub?
- Mitigation: Key is tied to OIDC binding (short lifetime). Document the risk. Add monitoring/alerting for leaked ephemeral keys.
Related Issues
- Fixes UX gap reported in fn-85 acceptance testing
- Related to fn-84 (SSH key upload patterns)
- Related to fn-85 (Machine Identity via OIDC)
Note: This is future work (v2), not part of fn-85 (v1). v1 ships with cryptographic verification via auths verify-commit. v2 adds the GitHub UI verification badge for enterprise adoption.
Summary
CI/CD attestations signed with ephemeral keys are cryptographically verifiable via
auths verify-commit, but GitHub's web UI will not display a "Verified" badge because GitHub does not recognize the ephemeral SSH public key. This is a UX gap that blocks adoption: developers expect green checkmarks in GitHub UI.Future work (v2): Auto-upload ephemeral SSH public key to GitHub before signing, then auto-delete after signing. This gives the ephemeral key a registered presence on GitHub, allowing commits to show as "Verified" in the UI while maintaining the ephemeral key guarantee (never persisted to CI runner disk, single-use only).
Context
fn-85 (Machine Identity via OIDC, v1) creates ephemeral KERI identities in CI with OIDC token binding. Commits signed with these ephemeral keys are verifiable via:
However, in GitHub's web UI:
Why: GitHub only recognizes SSH keys registered to user accounts or GitHub Apps. The ephemeral key exists only in CI runner memory, never uploaded to GitHub.
Why it matters for adoption: Enterprise users expect visual feedback in GitHub UI. The "Verified" badge is a compliance requirement for many organizations. Without it, the feature is perceived as incomplete even though the cryptographic verification is more secure than GitHub's centralized model.
Proposed Solution (v2)
Extend
auths init --profile cito:Before signing (same job step or automatically before first
auths sign):POST /user/ssh_signing_keyswith Bearer tokenDuring signing (existing flow):
After job completion (cleanup):
DELETE /user/ssh_signing_keys/{key_id}Technical Approach
Reuse from fn-84
HttpGitHubSshKeyUploadertrait (already implemented)New Code
CiIdentityConfigwithauto_register_ssh_key: boolflag (default: true)before_signing(): upload SSH keyafter_job(): delete SSH keyConfig Example
Acceptance Criteria
--auto-register-ssh-key(default: true)Dependencies
/user/ssh_signing_keysendpointSecurity Considerations
if: always())write:ssh_signing_keyscope (same as fn-84)Open Questions
Should this be automatic (default: true) or opt-in (default: false)?
--no-auto-register-ssh-keyif paranoid about API calls.Should we support GitLab and CircleCI auto-registration too (v2+1)?
What if the cleanup fails and the key remains on GitHub?
Related Issues
Note: This is future work (v2), not part of fn-85 (v1). v1 ships with cryptographic verification via
auths verify-commit. v2 adds the GitHub UI verification badge for enterprise adoption.