Skip to content

Commit 9ba3663

Browse files
feat(plugin): introduce signing handler plugin support (#885)
#### What this does - Added a new `SigningRegistry` to manage signing handler plugins. - Integrated signing handler support into the plugin manager and registries. - Updated dependencies in `go.mod` and `go.sum` to include the signing library. - Adjusted test cases to align with the new signing plugin functionality. _Note: I have made it so that Signing and Verification expect the same Config Type right now. Technically this is a bit of a conflict with the SigStore ADR Proposal because it would have two different configs for signing and verifications but I think having one type that can be used with different fields would also work, and its significantly easier to implement here_ #### Why this change is needed - Expands the plugin framework capabilities to include signing handlers for enhanced security and verification processes. part of adopting the RSA handler implemented for open-component-model/ocm-project#648 in #859. It would be registered as an internal handler via `RegisterInternalComponentSignatureHandler` in the CLI --------- Signed-off-by: Jakob Möller <jakob.moeller@sap.com>
1 parent 73f9667 commit 9ba3663

17 files changed

Lines changed: 1559 additions & 20 deletions

File tree

bindings/go/plugin/Taskfile.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ tasks:
1313
- go build -o tmp/testdata/test-plugin-input internal/testplugin-input/main.go
1414
- go build -o tmp/testdata/test-plugin-digester internal/testplugin-digester/main.go
1515
- go build -o tmp/testdata/test-plugin-blobtransformer internal/testplugin-blobtransformer/main.go
16+
- go build -o tmp/testdata/test-plugin-signinghandler internal/testplugin-signinghandler/main.go
1617
test:
1718
cmds:
1819
- go test -v -coverprofile=tmp/coverage.out ./...
1920
deps:
2021
- tmp
21-
- build
22+
- build

bindings/go/plugin/go.mod

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ require (
99
golang.org/x/sync v0.17.0
1010
ocm.software/open-component-model/bindings/go/blob v0.0.9
1111
ocm.software/open-component-model/bindings/go/configuration v0.0.8
12-
ocm.software/open-component-model/bindings/go/constructor v0.0.0-20250909064434-e1a06fe74668
13-
ocm.software/open-component-model/bindings/go/credentials v0.0.1
14-
ocm.software/open-component-model/bindings/go/descriptor/runtime v0.0.0-20250909064434-e1a06fe74668
12+
ocm.software/open-component-model/bindings/go/constructor v0.0.0-20250915165427-710b0c881b3c
13+
ocm.software/open-component-model/bindings/go/credentials v0.0.2
14+
ocm.software/open-component-model/bindings/go/descriptor/runtime v0.0.0-20250915165427-710b0c881b3c
1515
ocm.software/open-component-model/bindings/go/descriptor/v2 v2.0.1-alpha3
16-
ocm.software/open-component-model/bindings/go/repository v0.0.0-20250909064434-e1a06fe74668
16+
ocm.software/open-component-model/bindings/go/repository v0.0.0-20250915165427-710b0c881b3c
1717
ocm.software/open-component-model/bindings/go/runtime v0.0.2
18+
ocm.software/open-component-model/bindings/go/signing v0.0.0-20250915165427-710b0c881b3c
1819
)
1920

2021
require (
@@ -26,9 +27,10 @@ require (
2627
github.com/opencontainers/go-digest v1.0.0 // indirect
2728
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
2829
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
29-
go.yaml.in/yaml/v2 v2.4.2 // indirect
30+
go.yaml.in/yaml/v2 v2.4.3 // indirect
3031
golang.org/x/text v0.29.0 // indirect
3132
gopkg.in/yaml.v3 v3.0.1 // indirect
3233
ocm.software/open-component-model/bindings/go/dag v0.0.4 // indirect
34+
ocm.software/open-component-model/bindings/go/descriptor/normalisation v0.0.0-20250912092813-396078c6d574 // indirect
3335
sigs.k8s.io/yaml v1.6.0 // indirect
3436
)

bindings/go/plugin/go.sum

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
2+
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
13
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
24
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
35
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
@@ -6,8 +8,10 @@ github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 h
68
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
79
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
810
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
9-
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
10-
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
11+
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
12+
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
13+
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
14+
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
1115
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
1216
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
1317
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
@@ -18,8 +22,12 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
1822
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
1923
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
2024
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
25+
github.com/nlepage/go-tarfs v1.2.1 h1:o37+JPA+ajllGKSPfy5+YpsNHDjZnAoyfvf5GsUa+Ks=
26+
github.com/nlepage/go-tarfs v1.2.1/go.mod h1:rno18mpMy9aEH1IiJVftFsqPyIpwqSUiAOpJYjlV2NA=
2127
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
2228
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
29+
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
30+
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
2331
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
2432
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
2533
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
@@ -30,16 +38,18 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
3038
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
3139
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
3240
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
41+
github.com/veqryn/slog-context v0.8.0 h1:lDhwAgjwx52K5StqqQzi5d0Y/F4SNyGZbsXGd8MtucM=
42+
github.com/veqryn/slog-context v0.8.0/go.mod h1:8rsT72p0kzzN9lmkwtabIhxg7ZkpnKblt9x3Eix8Tc0=
3343
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
3444
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
35-
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
36-
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
45+
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
46+
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
3747
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
3848
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
3949
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
4050
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
41-
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
42-
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
51+
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
52+
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
4353
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
4454
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
4555
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -51,19 +61,29 @@ ocm.software/open-component-model/bindings/go/blob v0.0.9 h1:XNK04PnqvsE6KHx/04m
5161
ocm.software/open-component-model/bindings/go/blob v0.0.9/go.mod h1:BjErnbAzzY4mJ6cO/hIFj8Gf/v9zerkIQ1Y1XQEOB5M=
5262
ocm.software/open-component-model/bindings/go/configuration v0.0.8 h1:IH5ARqAwUJIV8U3l7Mv/txmjh7HbSwYMGSk9V8QlTVo=
5363
ocm.software/open-component-model/bindings/go/configuration v0.0.8/go.mod h1:VZ8jQ3a6oTWyOpY09C7V3L0CfzKe9i1/Z4uJjLAVjN4=
54-
ocm.software/open-component-model/bindings/go/constructor v0.0.0-20250909064434-e1a06fe74668 h1:ePvbeL8lISx4sqo0kEZbSq3id2dm+2BWVViGILLb+9Q=
55-
ocm.software/open-component-model/bindings/go/constructor v0.0.0-20250909064434-e1a06fe74668/go.mod h1:fLBedpjfl42v2XO4gHeTKii77xH+zU0d/yCKtCneuLg=
56-
ocm.software/open-component-model/bindings/go/credentials v0.0.1 h1:iT2RlZthTfy8mMP6s7BF/gr8EV/HWvTcFijvRc4YUFw=
57-
ocm.software/open-component-model/bindings/go/credentials v0.0.1/go.mod h1:eLLVJAztmxMPJMd15XcJXJ8u3cKNNmGvVexTKn0WCIk=
64+
ocm.software/open-component-model/bindings/go/constructor v0.0.0-20250915165427-710b0c881b3c h1:kSORPW3ZNipMowEoy+AthuFc8YnldVJfnLDCEnaksnE=
65+
ocm.software/open-component-model/bindings/go/constructor v0.0.0-20250915165427-710b0c881b3c/go.mod h1:YHHse9b0cE/rD/3tnIBGQcfppbjafhoeJC1IljgywoQ=
66+
ocm.software/open-component-model/bindings/go/credentials v0.0.2 h1:PYCu8QYgY7+KcOVLCc0TYJ5PLhXgU7+lbfcrgA0zjyE=
67+
ocm.software/open-component-model/bindings/go/credentials v0.0.2/go.mod h1:B1RJDS5dV59Z+PBw2bddP8Ks63dr43QrNB7SkNEr6cg=
68+
ocm.software/open-component-model/bindings/go/ctf v0.2.0 h1:BGZ+irknUVjZkOjL5j5bK5shmGWbOjpszfuETkPndVw=
69+
ocm.software/open-component-model/bindings/go/ctf v0.2.0/go.mod h1:L9JjTdoWDybr2YY9zXCsCAtNLracxW3aMK2f2TrqYZo=
5870
ocm.software/open-component-model/bindings/go/dag v0.0.4 h1:V77o/AUjkmEDQPktKPpKTkrFIFHIPJG32TKmtJXh8t8=
5971
ocm.software/open-component-model/bindings/go/dag v0.0.4/go.mod h1:Qr/gPg19CLloGSVqVyxyKiPUPctFMkwNa5qpnvvBbZc=
60-
ocm.software/open-component-model/bindings/go/descriptor/runtime v0.0.0-20250909064434-e1a06fe74668 h1:5cepIdT9AQKObFaxRw9m+qbtZp/j3dtPf5JsXlwl84c=
61-
ocm.software/open-component-model/bindings/go/descriptor/runtime v0.0.0-20250909064434-e1a06fe74668/go.mod h1:mQepbkWCdzm8W8/In1Q5QqQDibvimAt5eKtH0wvS72E=
72+
ocm.software/open-component-model/bindings/go/descriptor/normalisation v0.0.0-20250912092813-396078c6d574 h1:XzI9l5+9NNp2XRsICQRnRT6cpjs5+FYKGu9HDydvwD0=
73+
ocm.software/open-component-model/bindings/go/descriptor/normalisation v0.0.0-20250912092813-396078c6d574/go.mod h1:qBvCDn909Pkwr3EDAnzvnJOV0jSsl2+Ab3Rs22quMv4=
74+
ocm.software/open-component-model/bindings/go/descriptor/runtime v0.0.0-20250915165427-710b0c881b3c h1:Zge0CA+uRIg4yKHNa1H6Vs4Wq4NdSnJu3ByJ88JgtKo=
75+
ocm.software/open-component-model/bindings/go/descriptor/runtime v0.0.0-20250915165427-710b0c881b3c/go.mod h1:mQepbkWCdzm8W8/In1Q5QqQDibvimAt5eKtH0wvS72E=
6276
ocm.software/open-component-model/bindings/go/descriptor/v2 v2.0.1-alpha3 h1:daGC2XnJEJkukGdhvKxobUH+vF5TKYPlVQ6nl5ASdFM=
6377
ocm.software/open-component-model/bindings/go/descriptor/v2 v2.0.1-alpha3/go.mod h1:nnLzPfpD2zy9YUgIuQxA3vCmUUKFQqSCl6jFAQXVE8M=
64-
ocm.software/open-component-model/bindings/go/repository v0.0.0-20250909064434-e1a06fe74668 h1:W+W0JCbfK9VHuAPFYPMztitiKgDhZqgLk1fEBTqla24=
65-
ocm.software/open-component-model/bindings/go/repository v0.0.0-20250909064434-e1a06fe74668/go.mod h1:SBR5IbnJ+r7ggJ0X6LIXsi3l6cGe/FT+j2KZLJ/xsds=
78+
ocm.software/open-component-model/bindings/go/oci v0.0.7 h1:ognKj/Y7q1fDijU65pvBjP0p6OIuZS5uk/ySRZyzqgw=
79+
ocm.software/open-component-model/bindings/go/oci v0.0.7/go.mod h1:Q/y/aIlp9PV/fxRuCeqyoPczgSudw7/9D17s4CYaPlI=
80+
ocm.software/open-component-model/bindings/go/repository v0.0.0-20250915165427-710b0c881b3c h1:xkJZe9AD2uawXJF2F764MM0kRnX1dqHZx3K2c7EVFkY=
81+
ocm.software/open-component-model/bindings/go/repository v0.0.0-20250915165427-710b0c881b3c/go.mod h1:VvTUl90bjymXixw9YqYhHWC/rjY+3wOj1MtldgUWa7Y=
6682
ocm.software/open-component-model/bindings/go/runtime v0.0.2 h1:YA20enOxMsk4gDWF+Anltwkc616dXebfgPz/0Bl0EKE=
6783
ocm.software/open-component-model/bindings/go/runtime v0.0.2/go.mod h1:9qeyWvvxkua6NyDVGxeQV6B022WqoAfdU/JnuImm1ws=
84+
ocm.software/open-component-model/bindings/go/signing v0.0.0-20250915165427-710b0c881b3c h1:293h1NwrjXXg2+zNDUCVhd+Gn7tNGx7wt8qCKJmw9wM=
85+
ocm.software/open-component-model/bindings/go/signing v0.0.0-20250915165427-710b0c881b3c/go.mod h1:RwFu7vYYDxh0N8WIJLwxi0xdAZS3Y5ZagaJUIgZNNWU=
86+
oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc=
87+
oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o=
6888
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
6989
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"flag"
7+
"fmt"
8+
"log/slog"
9+
"os"
10+
11+
v2 "ocm.software/open-component-model/bindings/go/descriptor/v2"
12+
plugin "ocm.software/open-component-model/bindings/go/plugin/client/sdk"
13+
"ocm.software/open-component-model/bindings/go/plugin/internal/dummytype"
14+
dummyv1 "ocm.software/open-component-model/bindings/go/plugin/internal/dummytype/v1"
15+
v1 "ocm.software/open-component-model/bindings/go/plugin/manager/contracts/signing/v1"
16+
"ocm.software/open-component-model/bindings/go/plugin/manager/endpoints"
17+
"ocm.software/open-component-model/bindings/go/plugin/manager/registries/signinghandler"
18+
"ocm.software/open-component-model/bindings/go/plugin/manager/types"
19+
"ocm.software/open-component-model/bindings/go/runtime"
20+
)
21+
22+
type TestSigningPlugin struct{}
23+
24+
func (m *TestSigningPlugin) GetSignerIdentity(ctx context.Context, req *v1.GetSignerIdentityRequest[*dummyv1.Repository]) (*v1.IdentityResponse, error) {
25+
return &v1.IdentityResponse{Identity: map[string]string{"id": "signer"}}, nil
26+
}
27+
28+
func (m *TestSigningPlugin) Sign(ctx context.Context, request *v1.SignRequest[*dummyv1.Repository], credentials map[string]string) (*v1.SignResponse, error) {
29+
return &v1.SignResponse{Signature: &v2.SignatureInfo{Algorithm: "rsa", Value: "sig", MediaType: "text/plain"}}, nil
30+
}
31+
32+
func (m *TestSigningPlugin) GetVerifierIdentity(ctx context.Context, req *v1.GetVerifierIdentityRequest[*dummyv1.Repository]) (*v1.IdentityResponse, error) {
33+
return &v1.IdentityResponse{Identity: map[string]string{"id": "verifier"}}, nil
34+
}
35+
36+
func (m *TestSigningPlugin) Verify(ctx context.Context, request *v1.VerifyRequest[*dummyv1.Repository], credentials map[string]string) (*v1.VerifyResponse, error) {
37+
return &v1.VerifyResponse{}, nil
38+
}
39+
40+
func (m *TestSigningPlugin) Ping(_ context.Context) error { return nil }
41+
42+
var _ v1.SignatureHandlerContract[*dummyv1.Repository] = &TestSigningPlugin{}
43+
44+
func main() {
45+
args := os.Args[1:]
46+
// log messages are shared over stderr by convention established by the plugin manager.
47+
logger := slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug}))
48+
49+
scheme := runtime.NewScheme()
50+
dummytype.MustAddToScheme(scheme)
51+
capabilities := endpoints.NewEndpoints(scheme)
52+
53+
if err := signinghandler.RegisterPlugin(&dummyv1.Repository{}, &TestSigningPlugin{}, capabilities); err != nil {
54+
logger.Error("failed to register test signing plugin", "error", err.Error())
55+
os.Exit(1)
56+
}
57+
58+
if len(args) > 0 && args[0] == "capabilities" {
59+
content, err := json.Marshal(capabilities)
60+
if err != nil {
61+
logger.Error("failed to marshal capabilities", "error", err)
62+
os.Exit(1)
63+
}
64+
if _, err := fmt.Fprintln(os.Stdout, string(content)); err != nil {
65+
logger.Error("failed print capabilities", "error", err)
66+
os.Exit(1)
67+
}
68+
os.Exit(0)
69+
}
70+
71+
// Parse command-line arguments
72+
configData := flag.String("config", "", "Plugin config.")
73+
flag.Parse()
74+
if configData == nil || *configData == "" {
75+
logger.Error("missing required flag --config")
76+
os.Exit(1)
77+
}
78+
79+
conf := types.Config{}
80+
if err := json.Unmarshal([]byte(*configData), &conf); err != nil {
81+
logger.Error("failed to unmarshal config", "error", err)
82+
os.Exit(1)
83+
}
84+
if conf.ID == "" {
85+
logger.Error("plugin config has no ID")
86+
os.Exit(1)
87+
}
88+
89+
separateContext := context.Background()
90+
ocmPlugin := plugin.NewPlugin(separateContext, logger, conf, os.Stdout)
91+
if err := ocmPlugin.RegisterHandlers(capabilities.GetHandlers()...); err != nil {
92+
logger.Error("failed to register handlers", "error", err)
93+
os.Exit(1)
94+
}
95+
if err := ocmPlugin.Start(context.Background()); err != nil {
96+
logger.Error("failed to start plugin", "error", err)
97+
os.Exit(1)
98+
}
99+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package v1
2+
3+
import (
4+
"context"
5+
6+
"ocm.software/open-component-model/bindings/go/plugin/manager/contracts"
7+
"ocm.software/open-component-model/bindings/go/runtime"
8+
)
9+
10+
type SignerPluginContract[T runtime.Typed] interface {
11+
contracts.PluginBase
12+
GetSignerIdentity(ctx context.Context, typ *GetSignerIdentityRequest[T]) (*IdentityResponse, error)
13+
Sign(ctx context.Context, request *SignRequest[T], credentials map[string]string) (*SignResponse, error)
14+
}
15+
16+
type VerifierPluginContract[T runtime.Typed] interface {
17+
contracts.PluginBase
18+
GetVerifierIdentity(ctx context.Context, typ *GetVerifierIdentityRequest[T]) (*IdentityResponse, error)
19+
Verify(ctx context.Context, request *VerifyRequest[T], credentials map[string]string) (*VerifyResponse, error)
20+
}
21+
22+
type SignatureHandlerContract[T runtime.Typed] interface {
23+
SignerPluginContract[T]
24+
VerifierPluginContract[T]
25+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Package v1 contains the contracts and types for OCM plugins.
2+
//
3+
// It defines interfaces for interacting with OCM repositories and resources,
4+
// enabling plugins to read from and write to them.
5+
//
6+
// The contracts are categorized based on their functionality:
7+
//
8+
// - SignerPluginContract: Defines methods for signing digests
9+
// - VerifierPluginContract: Defines methods for verifying signatures
10+
//
11+
// The types define the request and response structures used by these contracts.
12+
package v1
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package v1
2+
3+
import (
4+
v2 "ocm.software/open-component-model/bindings/go/descriptor/v2"
5+
"ocm.software/open-component-model/bindings/go/runtime"
6+
)
7+
8+
type SignRequest[T runtime.Typed] struct {
9+
// Digest that should be signed.
10+
Digest *v2.Digest `json:"digest"`
11+
Config T `json:"config"`
12+
}
13+
type SignResponse struct {
14+
Signature *v2.SignatureInfo `json:"signature"`
15+
}
16+
17+
type VerifyRequest[T runtime.Typed] struct {
18+
Signature *v2.Signature `json:"signature"`
19+
Config T `json:"config"`
20+
}
21+
22+
type VerifyResponse struct{}
23+
24+
type GetSignerIdentityRequest[T runtime.Typed] struct {
25+
SignRequest[T] `json:",inline"`
26+
Name string `json:"name"`
27+
}
28+
29+
type GetVerifierIdentityRequest[T runtime.Typed] struct {
30+
VerifyRequest[T] `json:",inline"`
31+
}
32+
33+
type IdentityResponse struct {
34+
Identity map[string]string `json:"identity"`
35+
}

bindings/go/plugin/manager/manager.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"ocm.software/open-component-model/bindings/go/plugin/manager/registries/digestprocessor"
2323
"ocm.software/open-component-model/bindings/go/plugin/manager/registries/input"
2424
"ocm.software/open-component-model/bindings/go/plugin/manager/registries/resource"
25+
"ocm.software/open-component-model/bindings/go/plugin/manager/registries/signinghandler"
2526
mtypes "ocm.software/open-component-model/bindings/go/plugin/manager/types"
2627
)
2728

@@ -38,6 +39,7 @@ type PluginManager struct {
3839
DigestProcessorRegistry *digestprocessor.RepositoryRegistry
3940
ResourcePluginRegistry *resource.ResourceRegistry
4041
BlobTransformerRegistry *blobtransformer.Registry
42+
SigningRegistry *signinghandler.SigningRegistry
4143

4244
mu sync.Mutex
4345

@@ -58,6 +60,7 @@ func NewPluginManager(ctx context.Context) *PluginManager {
5860
DigestProcessorRegistry: digestprocessor.NewDigestProcessorRegistry(ctx),
5961
ResourcePluginRegistry: resource.NewResourceRegistry(ctx),
6062
BlobTransformerRegistry: blobtransformer.NewBlobTransformerRegistry(ctx),
63+
SigningRegistry: signinghandler.NewSigningRegistry(ctx),
6164
baseCtx: ctx,
6265
}
6366
}
@@ -156,6 +159,7 @@ func (pm *PluginManager) Shutdown(ctx context.Context) error {
156159
pm.DigestProcessorRegistry.Shutdown(ctx),
157160
pm.ResourcePluginRegistry.Shutdown(ctx),
158161
pm.BlobTransformerRegistry.Shutdown(ctx),
162+
pm.SigningRegistry.Shutdown(ctx),
159163
)
160164

161165
return errs
@@ -278,6 +282,11 @@ func (pm *PluginManager) addPlugin(ctx context.Context, ocmConfig *genericv1.Con
278282
if err := pm.BlobTransformerRegistry.AddPlugin(plugin, typs[0].Type); err != nil {
279283
return fmt.Errorf("failed to register plugin %s: %w", plugin.ID, err)
280284
}
285+
case mtypes.SigningHandlerPluginType:
286+
slog.DebugContext(ctx, "adding signing plugin", "id", plugin.ID)
287+
if err := pm.SigningRegistry.AddPlugin(plugin, typs[0].Type); err != nil {
288+
return fmt.Errorf("failed to register plugin %s: %w", plugin.ID, err)
289+
}
281290
}
282291
}
283292

0 commit comments

Comments
 (0)