Skip to content

feat: add GPG/OpenPGP signing support module (bindings/go/gpg)#2560

Merged
jakobmoellerdev merged 22 commits into
open-component-model:mainfrom
jakobmoellerdev:feat/gpg-signing-support-module
May 28, 2026
Merged

feat: add GPG/OpenPGP signing support module (bindings/go/gpg)#2560
jakobmoellerdev merged 22 commits into
open-component-model:mainfrom
jakobmoellerdev:feat/gpg-signing-support-module

Conversation

@jakobmoellerdev

Copy link
Copy Markdown
Member

Summary

Adds the bindings/go/gpg module implementing GPG/OpenPGP signing support for OCM component versions.

Closes open-component-model/ocm#1544

  • New standalone Go module ocm.software/open-component-model/bindings/go/gpg
  • Uses github.com/ProtonMail/go-crypto (already a transitive dep in CLI)
  • Passphrase-protected private keys supported; key decrypted in-memory only, never written to disk
  • Signatures stored as ASCII-armored OpenPGP detached signatures (application/vnd.ocm.signature.gpg)
  • Credential consumer identity type: GPG/v1alpha1
  • Credential keys: private_key_pgp, private_key_pgp_file, passphrase, public_key_pgp, public_key_pgp_file
  • Includes ADR-0015 documenting the design decision
  • Follows RSA handler pattern exactly — no core changes required

CLI integration (registering the handler as a built-in plugin) will follow in a separate PR once this module is tagged.

Credential Config Example

# signing
- type: credentials.config.ocm.software
  consumers:
  - identity:
      type: GPG/v1alpha1
      signature: default
    credentials:
    - type: Credentials/v1
      properties:
        private_key_pgp_file: /path/to/signing-key.asc
        passphrase: my-secret-passphrase

Test plan

  • Unit Tests (bindings/go/gpg) passes — round-trip sign/verify, passphrase protection, wrong passphrase, wrong public key, missing key cases
  • golangci-lint (bindings/go/gpg) passes
  • Spellcheck passes (wordlist updated for new prose words)
  • DCO passes (Signed-off-by present)
  • reuse passes (no new files without license headers — Go files inherit module license)

@netlify

netlify Bot commented May 18, 2026

Copy link
Copy Markdown

Deploy Preview for ocm-website ready!

Name Link
🔨 Latest commit 18bd758
🔍 Latest deploy log https://app.netlify.com/projects/ocm-website/deploys/6a182573377f840007f878ea
😎 Deploy Preview https://deploy-preview-2560--ocm-website.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds native GPG/OpenPGP signing: a Go signing.Handler (Sign/Verify), typed GPG credentials and identity, signing configuration and schemas, credential loaders, comprehensive tests, module/Taskfile wiring, wordlist updates, and an ADR documenting design and usage.

Changes

GPG/OpenPGP Signing Feature

Layer / File(s) Summary
All change checkpoints (single reviewer path)
docs/adr/0023_gpg_signing.md, .github/config/wordlist.txt, Taskfile.yml, bindings/go/gpg/Taskfile.yml, bindings/go/gpg/go.mod, bindings/go/gpg/...
Adds ADR documenting native GPG handler, expands spellcheck wordlist (decrypt*, env, openbao, openpgp, protonmail, unencrypted), Taskfile/include and per-binding Taskfile, new Go module bindings/go/gpg, typed GPG credentials/identity/signing config and JSON schemas, credential-loading utilities, the signing Handler (Sign/Verify), conversion helpers, extensive tests, and website go-import metadata.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • frewilhelm
  • morri-son
  • fabianburth

Poem

🐰 I nibble keys by lantern-light, so spry,
I hum a tune to watch the signatures fly.
Armored bytes and passphrases snug and tight,
I hop through code to set the signatures right.
A joyful thump — release secure tonight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main feature being added: GPG/OpenPGP signing support module for bindings/go/gpg.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the module's purpose, feature set, dependencies, credential config, and linking to the closed issue.
Linked Issues check ✅ Passed The PR fully implements the requirement from issue #1544 to support passphrase-protected GPG key signing, providing a complete handler implementation with in-memory decryption and credential support.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing GPG/OpenPGP signing support: new bindings/go/gpg module, credentials/signing specs, handlers, tests, wordlist updates, and documentation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gitguardian

gitguardian Bot commented May 18, 2026

Copy link
Copy Markdown

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@github-actions github-actions Bot added kind/feature new feature, enhancement, improvement, extension component/github-actions Changes on GitHub Actions or within `.github/` directory area/documentation Documentation related labels May 18, 2026
@jakobmoellerdev jakobmoellerdev force-pushed the feat/gpg-signing-support-module branch 7 times, most recently from 78ded31 to 691d4ef Compare May 19, 2026 07:21
@jakobmoellerdev jakobmoellerdev marked this pull request as ready for review May 19, 2026 16:26
@jakobmoellerdev jakobmoellerdev requested a review from a team as a code owner May 19, 2026 16:26
Comment thread bindings/go/gpg/spec/credentials/v1alpha1/gpg_credentials.go Outdated
Comment thread docs/adr/0023_gpg_signing.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
bindings/go/gpg/spec/signing/v1alpha1/schemas/Config.schema.json (1)

13-16: ⚡ Quick win

Enforce keyFingerprint format in schema.

The description constrains accepted values, but the schema currently accepts any string. Add a regex pattern so validation matches the documented contract.

Suggested diff
     "keyFingerprint": {
       "type": "string",
+      "pattern": "^(?:[A-Fa-f0-9]{40}|[A-Fa-f0-9]{16})$",
       "description": "KeyFingerprint pins which key in the keyring to use when signing or verifying.\nWhen empty the first available key is used.\nAccepts a full 40-hex-character v4 fingerprint or a 16-hex-character long key ID."
     },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bindings/go/gpg/spec/signing/v1alpha1/schemas/Config.schema.json` around
lines 13 - 16, Update the Config.schema.json schema for the keyFingerprint
property to enforce the documented formats by adding a regex pattern to the
"keyFingerprint" definition; the pattern should allow either a 40-hex-character
v4 fingerprint or a 16-hex-character key ID (and permit empty string if empty
values are allowed), e.g. use a pattern like
"^(?:[0-9a-fA-F]{40}|[0-9a-fA-F]{16})?$" so validation matches the description
for keyFingerprint.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bindings/go/gpg/signing/handler/handler.go`:
- Around line 61-74: The code calls gpgcredentials.PrivateEntityFromCredentials
which returns a single entity and then runs selectEntityByFingerprint against a
one-element list, so fingerprint selection never finds non-first keys; change
the flow to load all private entities from the credentials (e.g., a function
that returns an openpgp.EntityList or iterate the keyring in the parsed armored
block) instead of a single entity, then call selectEntityByFingerprint against
that EntityList (or loop entities and compare fingerprints) and return
ErrMissingPrivateKey if no matching entity is found; update uses of the local
variable entity and the fingerprint branch (sigCfg.GetKeyFingerprint()) to
operate on the selected entity from the multi-entity list and preserve existing
error wrapping.

In `@bindings/go/gpg/signing/handler/internal/credentials/credentials.go`:
- Around line 21-22: The exported helpers PrivateEntityFromCredentials and
PublicEntityFromCredentials currently dereference the input pointer immediately
and will panic on nil; add a nil guard at the start of each function (check if
creds == nil) and return a clear error (e.g., fmt.Errorf("nil credentials"))
before any use of creds, then proceed to call loadBytes and the rest of the
logic—update both PrivateEntityFromCredentials and PublicEntityFromCredentials
accordingly.

In `@docs/adr/0023_gpg_signing.md`:
- Around line 46-47: The ADR claims the new Go module
ocm.software/open-component-model/bindings/go/gpg is already registered/shipped
in the ocm CLI; change those statements (the sentences describing the gpg
signing.Handler registration and shipping) to clearly mark them as
future/planned integration (e.g., "will be registered" or "planned to be
registered in the ocm CLI after module tagging and the follow-up PR"), and apply
the same rephrasing to the other similar occurrence referring to CLI shipping;
keep references to the module and ProtonMail OpenPGP library but avoid asserting
the registration is already shipped.
- Line 61: Replace the inconsistent CLI example that uses "componentversion"
with the actual command name "component-version" so all examples match and
copy/paste correctly; update the examples where the string "ocm sign
componentversion --signer-spec ./gpg.yaml" (and any other occurrences of
"componentversion") appears to "ocm sign component-version --signer-spec
./gpg.yaml", ensuring the examples at the earlier example and the ones currently
showing "ocm sign component-version --signer-spec ./gpg.yaml" are consistent.

---

Nitpick comments:
In `@bindings/go/gpg/spec/signing/v1alpha1/schemas/Config.schema.json`:
- Around line 13-16: Update the Config.schema.json schema for the keyFingerprint
property to enforce the documented formats by adding a regex pattern to the
"keyFingerprint" definition; the pattern should allow either a 40-hex-character
v4 fingerprint or a 16-hex-character key ID (and permit empty string if empty
values are allowed), e.g. use a pattern like
"^(?:[0-9a-fA-F]{40}|[0-9a-fA-F]{16})?$" so validation matches the description
for keyFingerprint.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b787964b-ef8a-44d7-a985-40577932d834

📥 Commits

Reviewing files that changed from the base of the PR and between 03c8a87 and c394f4a.

⛔ Files ignored due to path filters (1)
  • bindings/go/gpg/go.sum is excluded by !**/*.sum
📒 Files selected for processing (29)
  • .github/config/wordlist.txt
  • Taskfile.yml
  • bindings/go/gpg/Taskfile.yml
  • bindings/go/gpg/go.mod
  • bindings/go/gpg/signing/handler/handler.go
  • bindings/go/gpg/signing/handler/handler_test.go
  • bindings/go/gpg/signing/handler/internal/credentials/credentials.go
  • bindings/go/gpg/signing/handler/internal/credentials/credentials_test.go
  • bindings/go/gpg/spec/credentials/v1alpha1/gpg_credentials.go
  • bindings/go/gpg/spec/credentials/v1alpha1/gpg_credentials_test.go
  • bindings/go/gpg/spec/credentials/v1alpha1/schemas/GPGCredentials.schema.json
  • bindings/go/gpg/spec/credentials/v1alpha1/zz_generated.deepcopy.go
  • bindings/go/gpg/spec/credentials/v1alpha1/zz_generated.ocm_jsonschema.go
  • bindings/go/gpg/spec/credentials/v1alpha1/zz_generated.ocm_type.go
  • bindings/go/gpg/spec/identity/v1alpha1/register.go
  • bindings/go/gpg/spec/identity/v1alpha1/schemas/GPGIdentity.schema.json
  • bindings/go/gpg/spec/identity/v1alpha1/type.go
  • bindings/go/gpg/spec/identity/v1alpha1/type_test.go
  • bindings/go/gpg/spec/identity/v1alpha1/zz_generated.deepcopy.go
  • bindings/go/gpg/spec/identity/v1alpha1/zz_generated.ocm_jsonschema.go
  • bindings/go/gpg/spec/identity/v1alpha1/zz_generated.ocm_type.go
  • bindings/go/gpg/spec/signing/v1alpha1/algorithm.go
  • bindings/go/gpg/spec/signing/v1alpha1/config.go
  • bindings/go/gpg/spec/signing/v1alpha1/group_version.go
  • bindings/go/gpg/spec/signing/v1alpha1/schemas/Config.schema.json
  • bindings/go/gpg/spec/signing/v1alpha1/zz_generated.deepcopy.go
  • bindings/go/gpg/spec/signing/v1alpha1/zz_generated.ocm_jsonschema.go
  • bindings/go/gpg/spec/signing/v1alpha1/zz_generated.ocm_type.go
  • docs/adr/0023_gpg_signing.md

Comment thread bindings/go/gpg/signing/handler/handler.go Outdated
Comment thread bindings/go/gpg/signing/handler/internal/credentials/credentials.go
Comment thread docs/adr/0023_gpg_signing.md Outdated
Comment thread docs/adr/0023_gpg_signing.md Outdated
@jakobmoellerdev jakobmoellerdev force-pushed the feat/gpg-signing-support-module branch 2 times, most recently from e33de5c to 58948c2 Compare May 20, 2026 06:59

@frewilhelm frewilhelm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment thread docs/adr/0023_gpg_signing.md Outdated
Comment thread docs/adr/0023_gpg_signing.md Outdated
Comment thread cli/cmd/setup/versioncheck.go
Comment thread bindings/go/gpg/spec/credentials/v1alpha1/gpg_credentials.go Outdated
Comment thread bindings/go/gpg/signing/handler/internal/credentials/credentials.go Outdated
Comment thread bindings/go/gpg/signing/handler/internal/credentials/credentials.go
Comment thread bindings/go/gpg/signing/handler/handler.go Outdated
@jakobmoellerdev

Copy link
Copy Markdown
Member Author

Does it make sense to already add the module to the website https://github.com/open-component-model/open-component-model/tree/main/website/static/open-component-model/bindings/go?

I would like to do this together with the CLI integration as otherwise the bindings are unusable

@frewilhelm

Copy link
Copy Markdown
Contributor

Does it make sense to already add the module to the website https://github.com/open-component-model/open-component-model/tree/main/website/static/open-component-model/bindings/go?

I would like to do this together with the CLI integration as otherwise the bindings are unusable

Don't you need to import the module for the CLI integration? I believed we need the change on the website to make the module visible for go's dependency management.

@jakobmoellerdev

Copy link
Copy Markdown
Member Author

Does it make sense to already add the module to the website https://github.com/open-component-model/open-component-model/tree/main/website/static/open-component-model/bindings/go?

I would like to do this together with the CLI integration as otherwise the bindings are unusable

Don't you need to import the module for the CLI integration? I believed we need the change on the website to make the module visible for go's dependency management.

These are 2 PRs. There is bindings/go/gpg , and then there is cli. If i wanna push this here, I would have to create docs without having it ready and use a go.work with a draft PR.

@jakobmoellerdev jakobmoellerdev force-pushed the feat/gpg-signing-support-module branch 4 times, most recently from 11f777b to 8abc01d Compare May 20, 2026 14:51
@jakobmoellerdev jakobmoellerdev force-pushed the feat/gpg-signing-support-module branch from 68cf355 to b5131ab Compare May 27, 2026 06:50
Comment thread bindings/go/gpg/spec/credentials/v1alpha1/gpg_credentials.go Outdated
Aligns with RSA credential pattern: move key name constants to private
and extract FromDirectCredentials into a separate convert.go file.
Tests use string literals instead of exported constants.

Signed-off-by: Jakob Möller <contact@jakob-moeller.com>
On-behalf-of: @SAP <jakob.moeller@sap.com>
Comment thread bindings/go/gpg/signing/handler/handler.go Outdated
Comment thread bindings/go/gpg/signing/handler/handler.go Outdated
- Update Sign/Verify to accept runtime.Typed credentials (matches signing.Handler interface from gate 7 migration)
- Add ConvertToGPGCredentials with fast-path type assertion before scheme lookup
- Rewrite handler tests to use *gpgcredentialsv1.GPGCredentials directly
- Add bindings/go/credentials as direct dependency

Signed-off-by: Jakob Möller <contact@jakob-moeller.com>
On-behalf-of: @SAP <jakob.moeller@sap.com>
@jakobmoellerdev jakobmoellerdev force-pushed the feat/gpg-signing-support-module branch from 3beb3a7 to b97020f Compare May 27, 2026 10:42
Comment thread bindings/go/gpg/spec/credentials/v1alpha1/convert.go Outdated
Comment thread bindings/go/gpg/spec/credentials/v1alpha1/convert.go
Signed-off-by: Jakob Möller <contact@jakob-moeller.com>
On-behalf-of: @SAP <jakob.moeller@sap.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bindings/go/gpg/spec/credentials/v1alpha1/convert.go (1)

12-16: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Credential property keys appear to violate the documented contract.

These constants use camelCase (privateKeyPGP, etc.), while the PR contract defines snake_case keys (private_key_pgp, private_key_pgp_file, public_key_pgp, public_key_pgp_file, passphrase). If users provide the documented keys, conversion on Lines 67-71 will silently yield empty fields.

Proposed fix
-	credentialKeyPrivateKeyPGP     = "privateKeyPGP"
-	credentialKeyPrivateKeyPGPFile = "privateKeyPGPFile"
-	credentialKeyPublicKeyPGP      = "publicKeyPGP"
-	credentialKeyPublicKeyPGPFile  = "publicKeyPGPFile"
+	credentialKeyPrivateKeyPGP     = "private_key_pgp"
+	credentialKeyPrivateKeyPGPFile = "private_key_pgp_file"
+	credentialKeyPublicKeyPGP      = "public_key_pgp"
+	credentialKeyPublicKeyPGPFile  = "public_key_pgp_file"
 	credentialKeyPassphrase        = "passphrase"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bindings/go/gpg/spec/credentials/v1alpha1/convert.go` around lines 12 - 16,
The credential key constants (credentialKeyPrivateKeyPGP,
credentialKeyPrivateKeyPGPFile, credentialKeyPublicKeyPGP,
credentialKeyPublicKeyPGPFile, credentialKeyPassphrase) currently hold camelCase
strings but must use the documented snake_case keys; update their string values
to "private_key_pgp", "private_key_pgp_file", "public_key_pgp",
"public_key_pgp_file", and "passphrase" respectively so the conversion logic
that reads those keys produces the expected non-empty fields and remains
consistent across the codebase.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bindings/go/gpg/spec/credentials/v1alpha1/convert.go`:
- Around line 33-40: The ConvertToGPGCredentials function can panic when creds
is nil because it calls creds.GetType(); add a nil guard at the start of
ConvertToGPGCredentials to check if creds == nil and return a clear typed error
(e.g., fmt.Errorf("nil credentials provided")) instead of proceeding; then
continue with the existing type assertion and
convertScheme.NewObject(creds.GetType()) logic unchanged so downstream code
never dereferences a nil creds.

---

Outside diff comments:
In `@bindings/go/gpg/spec/credentials/v1alpha1/convert.go`:
- Around line 12-16: The credential key constants (credentialKeyPrivateKeyPGP,
credentialKeyPrivateKeyPGPFile, credentialKeyPublicKeyPGP,
credentialKeyPublicKeyPGPFile, credentialKeyPassphrase) currently hold camelCase
strings but must use the documented snake_case keys; update their string values
to "private_key_pgp", "private_key_pgp_file", "public_key_pgp",
"public_key_pgp_file", and "passphrase" respectively so the conversion logic
that reads those keys produces the expected non-empty fields and remains
consistent across the codebase.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1a6cf8c5-e407-40d5-8424-a5cb1468d2f0

📥 Commits

Reviewing files that changed from the base of the PR and between d985982 and c787a71.

⛔ Files ignored due to path filters (1)
  • bindings/go/gpg/go.sum is excluded by !**/*.sum
📒 Files selected for processing (5)
  • bindings/go/gpg/go.mod
  • bindings/go/gpg/signing/handler/handler.go
  • bindings/go/gpg/signing/handler/handler_test.go
  • bindings/go/gpg/spec/credentials/v1alpha1/convert.go
  • website/static/open-component-model/bindings/go/gpg
🚧 Files skipped from review as they are similar to previous changes (3)
  • bindings/go/gpg/go.mod
  • bindings/go/gpg/signing/handler/handler_test.go
  • bindings/go/gpg/signing/handler/handler.go

Comment thread bindings/go/gpg/spec/credentials/v1alpha1/convert.go
No external callers — only used in same-package test.

Signed-off-by: Jakob Möller <contact@jakob-moeller.com>
On-behalf-of: @SAP <jakob.moeller@sap.com>
Signed-off-by: Jakob Möller <contact@jakob-moeller.com>
On-behalf-of: @SAP <jakob.moeller@sap.com>
matthiasbruns
matthiasbruns previously approved these changes May 28, 2026
Signed-off-by: Jakob Möller <contact@jakob-moeller.com>
On-behalf-of: @SAP <jakob.moeller@sap.com>
@jakobmoellerdev jakobmoellerdev enabled auto-merge (squash) May 28, 2026 11:23
@jakobmoellerdev jakobmoellerdev merged commit 9cd4df8 into open-component-model:main May 28, 2026
27 checks passed
ocmbot Bot pushed a commit that referenced this pull request May 28, 2026
## Summary

Adds the `bindings/go/gpg` module implementing GPG/OpenPGP signing
support for OCM component versions.

Closes open-component-model/ocm#1544

- New standalone Go module
`ocm.software/open-component-model/bindings/go/gpg`
- Uses `github.com/ProtonMail/go-crypto` (already a transitive dep in
CLI)
- Passphrase-protected private keys supported; key decrypted in-memory
only, never written to disk
- Signatures stored as ASCII-armored OpenPGP detached signatures
(`application/vnd.ocm.signature.gpg`)
- Credential consumer identity type: `GPG/v1alpha1`
- Credential keys: `private_key_pgp`, `private_key_pgp_file`,
`passphrase`, `public_key_pgp`, `public_key_pgp_file`
- Includes ADR-0015 documenting the design decision
- Follows RSA handler pattern exactly — no core changes required

CLI integration (registering the handler as a built-in plugin) will
follow in a separate PR once this module is tagged.

### Credential Config Example

```yaml
# signing
- type: credentials.config.ocm.software
  consumers:
  - identity:
      type: GPG/v1alpha1
      signature: default
    credentials:
    - type: Credentials/v1
      properties:
        private_key_pgp_file: /path/to/signing-key.asc
        passphrase: my-secret-passphrase
```

## Test plan

- [ ] `Unit Tests (bindings/go/gpg)` passes — round-trip sign/verify,
passphrase protection, wrong passphrase, wrong public key, missing key
cases
- [ ] `golangci-lint (bindings/go/gpg)` passes
- [ ] `Spellcheck` passes (wordlist updated for new prose words)
- [ ] `DCO` passes (Signed-off-by present)
- [ ] `reuse` passes (no new files without license headers — Go files
inherit module license)

---------

Signed-off-by: Jakob Möller <contact@jakob-moeller.com>
Co-authored-by: Matthias Bruns <github@matthiasbruns.com> 9cd4df8
jakobmoellerdev added a commit to jakobmoellerdev/open-component-model that referenced this pull request May 28, 2026
Registers the GPG/OpenPGP signing handler (from bindings/go/gpg, merged
in open-component-model#2560) as a built-in CLI plugin alongside RSA and Sigstore.

- cli/internal/plugin/builtin/gpg/register.go: new registration shim
- cli/internal/plugin/builtin/builtin.go: register GPG plugin at startup
- cli/go.mod: add direct dep on bindings/go/gpg
- cli/integration/signing_gpg_integration_test.go: CLI-level round-trip
  test covering happy path, dry-run, and wrong-key verification failure
- website/content/docs/tutorials/signing/gpg.md: tutorial mirroring
  plain.md structure, covering key generation, export, config, and
  sign/verify workflow

Closes the CLI integration gap deferred by open-component-model#2560.

On-behalf-of: @SAP <jakob.moeller@sap.com>
Signed-off-by: Jakob Möller <contact@jakob-moeller.com>
On-behalf-of: @SAP <jakob.moeller@sap.com>
jakobmoellerdev added a commit that referenced this pull request May 29, 2026
## Summary

Registers the GPG/OpenPGP signing handler (added in #2560) as a built-in
CLI plugin alongside RSA and Sigstore.

PR #2560 explicitly deferred CLI integration to a follow-up — this is
that follow-up.

- New `cli/internal/plugin/builtin/gpg/register.go` — registration shim
mirroring the RSA pattern
- `cli/internal/plugin/builtin/builtin.go` — registers GPG plugin at CLI
startup
- `cli/go.mod` — adds direct dependency on `bindings/go/gpg`
- `cli/integration/signing_gpg_integration_test.go` — CLI-level
round-trip integration test covering:
  - Happy path: sign then verify
- Dry-run: verify must fail after `--dry-run`, then succeed after real
sign
  - Wrong key: verify with a different public key must fail
- `website/content/docs/tutorials/signing/gpg.md` — tutorial (weight 30,
after plain.md/pem.md) covering GPG key generation, export, credential
config, and sign/verify workflow

## Test plan

- [ ] `Build (cli)` passes — `go build ./...` in `cli/`
- [ ] `golangci-lint (cli)` passes
- [ ] `Integration Tests (cli)` passes — `Test_Integration_Signing_GPG`
round-trip with live OCI registry
- [ ] `Spellcheck` passes
- [ ] `DCO` passes

---------

Signed-off-by: Jakob Möller <contact@jakob-moeller.com>
ocmbot Bot pushed a commit that referenced this pull request May 29, 2026
## Summary

Registers the GPG/OpenPGP signing handler (added in #2560) as a built-in
CLI plugin alongside RSA and Sigstore.

PR #2560 explicitly deferred CLI integration to a follow-up — this is
that follow-up.

- New `cli/internal/plugin/builtin/gpg/register.go` — registration shim
mirroring the RSA pattern
- `cli/internal/plugin/builtin/builtin.go` — registers GPG plugin at CLI
startup
- `cli/go.mod` — adds direct dependency on `bindings/go/gpg`
- `cli/integration/signing_gpg_integration_test.go` — CLI-level
round-trip integration test covering:
  - Happy path: sign then verify
- Dry-run: verify must fail after `--dry-run`, then succeed after real
sign
  - Wrong key: verify with a different public key must fail
- `website/content/docs/tutorials/signing/gpg.md` — tutorial (weight 30,
after plain.md/pem.md) covering GPG key generation, export, credential
config, and sign/verify workflow

## Test plan

- [ ] `Build (cli)` passes — `go build ./...` in `cli/`
- [ ] `golangci-lint (cli)` passes
- [ ] `Integration Tests (cli)` passes — `Test_Integration_Signing_GPG`
round-trip with live OCI registry
- [ ] `Spellcheck` passes
- [ ] `DCO` passes

---------

Signed-off-by: Jakob Möller <contact@jakob-moeller.com> f6930ce
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/documentation Documentation related component/github-actions Changes on GitHub Actions or within `.github/` directory kind/feature new feature, enhancement, improvement, extension size/l Large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Signing with passphrase protected GPG Keys

3 participants