Skip to content

Commit 7c76bb2

Browse files
Implement RegisterEntity consistently across providers, with test (#6047)
* Implement RegisterEntity consistently across providers, with test * Fix lint errors
1 parent 1117522 commit 7c76bb2

File tree

13 files changed

+197
-337
lines changed

13 files changed

+197
-337
lines changed

internal/providers/dockerhub/dockerhub.go

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,14 @@ func (*dockerHubImageLister) SupportsEntity(_ minderv1.Entity) bool {
194194
}
195195

196196
// RegisterEntity implements the Provider interface
197-
func (*dockerHubImageLister) RegisterEntity(
198-
_ context.Context, _ minderv1.Entity, _ *properties.Properties,
197+
func (d *dockerHubImageLister) RegisterEntity(
198+
_ context.Context, entType minderv1.Entity, props *properties.Properties,
199199
) (*properties.Properties, error) {
200-
// TODO: implement
201-
return nil, nil
200+
if !d.SupportsEntity(entType) {
201+
return nil, provifv1.ErrUnsupportedEntity
202+
}
203+
// we don't need to do any explicit registration
204+
return props, nil
202205
}
203206

204207
// DeregisterEntity implements the Provider interface
@@ -209,14 +212,6 @@ func (*dockerHubImageLister) DeregisterEntity(
209212
return nil
210213
}
211214

212-
// ReregisterEntity implements the Provider interface
213-
func (*dockerHubImageLister) ReregisterEntity(
214-
_ context.Context, _ minderv1.Entity, _ *properties.Properties,
215-
) error {
216-
// TODO: implement
217-
return nil
218-
}
219-
220215
// PropertiesToProtoMessage implements the Provider interface
221216
func (*dockerHubImageLister) PropertiesToProtoMessage(
222217
_ minderv1.Entity, _ *properties.Properties) (protoreflect.ProtoMessage, error) {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// SPDX-FileCopyrightText: Copyright 2026 The Minder Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package dockerhub
5+
6+
import (
7+
"testing"
8+
9+
testhelper "github.com/mindersec/minder/pkg/providers/v1/testing"
10+
)
11+
12+
func TestRegistration(t *testing.T) {
13+
t.Parallel()
14+
// We don't need a full constructor here, so we're naughty
15+
dh := &dockerHubImageLister{}
16+
testhelper.CheckRegistrationExcept(t, dh)
17+
}

internal/providers/github/entities.go

Lines changed: 20 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/mindersec/minder/internal/util/ptr"
2020
minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1"
2121
"github.com/mindersec/minder/pkg/entities/properties"
22+
provifv1 "github.com/mindersec/minder/pkg/providers/v1"
2223
)
2324

2425
var (
@@ -49,12 +50,28 @@ func (c *GitHub) SupportsEntity(entType minderv1.Entity) bool {
4950
func (c *GitHub) RegisterEntity(
5051
ctx context.Context, entityType minderv1.Entity, props *properties.Properties,
5152
) (*properties.Properties, error) {
52-
// We only need explicit registration steps for repositories
53-
// The rest of the entities are originated from them.
54-
if entityType != minderv1.Entity_ENTITY_REPOSITORIES {
53+
if !c.SupportsEntity(entityType) {
54+
return nil, provifv1.ErrUnsupportedEntity
55+
}
56+
57+
//nolint:exhaustive
58+
switch entityType {
59+
case minderv1.Entity_ENTITY_PULL_REQUESTS:
60+
fallthrough
61+
case minderv1.Entity_ENTITY_ARTIFACTS:
62+
fallthrough
63+
case minderv1.Entity_ENTITY_RELEASE:
64+
// Nothing to do, accept:
5565
return props, nil
66+
case minderv1.Entity_ENTITY_REPOSITORIES:
67+
return c.registerRepoWebhook(ctx, props)
68+
default:
69+
return nil, provifv1.ErrUnsupportedEntity
5670
}
71+
}
5772

73+
func (c *GitHub) registerRepoWebhook(ctx context.Context, props *properties.Properties,
74+
) (*properties.Properties, error) {
5875
webhookURLProvider, err := url.JoinPath(
5976
c.webhookConfig.ExternalWebhookURL,
6077
url.PathEscape(string(db.ProviderTypeGithub)),
@@ -147,57 +164,6 @@ func (c *GitHub) DeregisterEntity(ctx context.Context, entityType minderv1.Entit
147164
return nil
148165
}
149166

150-
// ReregisterEntity implements the Provider interface
151-
func (c *GitHub) ReregisterEntity(
152-
ctx context.Context, entityType minderv1.Entity, props *properties.Properties,
153-
) error {
154-
// We only need explicit registration steps for repositories
155-
// The rest of the entities are originated from them.
156-
if entityType != minderv1.Entity_ENTITY_REPOSITORIES {
157-
return nil
158-
}
159-
160-
repoNameP := props.GetProperty(ghprop.RepoPropertyName)
161-
if repoNameP == nil {
162-
return errors.New("repo name property not found")
163-
}
164-
165-
repoOwnerP := props.GetProperty(ghprop.RepoPropertyOwner)
166-
if repoOwnerP == nil {
167-
return errors.New("repo owner property not found")
168-
}
169-
170-
hookIDP := props.GetProperty(ghprop.RepoPropertyHookId)
171-
if hookIDP == nil {
172-
return errors.New("hook ID property not found")
173-
}
174-
175-
hookURL := props.GetProperty(ghprop.RepoPropertyHookUrl)
176-
if hookURL == nil {
177-
return errors.New("hook URL property not found")
178-
}
179-
180-
ping := c.webhookConfig.ExternalPingURL
181-
182-
secret, err := c.webhookConfig.GetWebhookSecret()
183-
if err != nil {
184-
return fmt.Errorf("error getting webhook secret for github provider: %w", err)
185-
}
186-
187-
repoName := repoNameP.GetString()
188-
repoOwner := repoOwnerP.GetString()
189-
hookID := hookIDP.GetInt64()
190-
191-
hook := getGitHubWebhook(hookURL.GetString(), ping, secret)
192-
_, err = c.EditHook(ctx, repoOwner, repoName, hookID, hook)
193-
if err != nil {
194-
zerolog.Ctx(ctx).Error().Err(err).Msg("unable to update hook")
195-
return fmt.Errorf("unable to update hook: %w", err)
196-
}
197-
198-
return nil
199-
}
200-
201167
func (c *GitHub) cleanupStaleHooks(
202168
ctx context.Context,
203169
repoOwner string,

internal/providers/github/ghcr/ghcr.go

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,14 @@ func (*ImageLister) SupportsEntity(_ minderv1.Entity) bool {
155155
}
156156

157157
// RegisterEntity implements the Provider interface
158-
func (*ImageLister) RegisterEntity(
159-
_ context.Context, _ minderv1.Entity, _ *properties.Properties,
158+
func (i *ImageLister) RegisterEntity(
159+
_ context.Context, entType minderv1.Entity, props *properties.Properties,
160160
) (*properties.Properties, error) {
161-
// TODO: implement
162-
return nil, nil
161+
if !i.SupportsEntity(entType) {
162+
return nil, provifv1.ErrUnsupportedEntity
163+
}
164+
// we don't need to do any explicit registration
165+
return props, nil
163166
}
164167

165168
// DeregisterEntity implements the Provider interface
@@ -168,13 +171,6 @@ func (*ImageLister) DeregisterEntity(_ context.Context, _ minderv1.Entity, _ *pr
168171
return nil
169172
}
170173

171-
// ReregisterEntity implements the Provider interface
172-
func (*ImageLister) ReregisterEntity(
173-
_ context.Context, _ minderv1.Entity, _ *properties.Properties,
174-
) error {
175-
return nil
176-
}
177-
178174
// PropertiesToProtoMessage implements the Provider interface
179175
func (*ImageLister) PropertiesToProtoMessage(_ minderv1.Entity, _ *properties.Properties) (protoreflect.ProtoMessage, error) {
180176
// TODO: Implement
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// SPDX-FileCopyrightText: Copyright 2026 The Minder Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package ghcr
5+
6+
import (
7+
"testing"
8+
9+
testhelper "github.com/mindersec/minder/pkg/providers/v1/testing"
10+
)
11+
12+
func TestRegistration(t *testing.T) {
13+
t.Parallel()
14+
// We don't need a full constructor here, so we're naughty
15+
il := &ImageLister{}
16+
testhelper.CheckRegistrationExcept(t, il)
17+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-FileCopyrightText: Copyright 2026 The Minder Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package github
5+
6+
import (
7+
"testing"
8+
9+
"github.com/mindersec/minder/internal/providers/github/properties"
10+
minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1"
11+
testhelper "github.com/mindersec/minder/pkg/providers/v1/testing"
12+
)
13+
14+
func TestRegistration(t *testing.T) {
15+
t.Parallel()
16+
// We don't need a full constructor here, so we're naughty
17+
gh := &GitHub{
18+
propertyFetchers: properties.NewPropertyFetcherFactory(),
19+
}
20+
// Repositories do a bunch of special registration, so skip them
21+
// in this test -- we test them in common_test.go.
22+
testhelper.CheckRegistrationExcept(t, gh, minderv1.Entity_ENTITY_REPOSITORIES)
23+
}

internal/providers/gitlab/registration.go

Lines changed: 2 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ import (
2020
"github.com/mindersec/minder/internal/util/ptr"
2121
minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1"
2222
"github.com/mindersec/minder/pkg/entities/properties"
23+
provifv1 "github.com/mindersec/minder/pkg/providers/v1"
2324
)
2425

2526
// RegisterEntity implements the Provider interface
2627
func (c *gitlabClient) RegisterEntity(
2728
ctx context.Context, entType minderv1.Entity, props *properties.Properties,
2829
) (*properties.Properties, error) {
2930
if !c.SupportsEntity(entType) {
30-
return nil, errors.New("unsupported entity type")
31+
return nil, provifv1.ErrUnsupportedEntity
3132
}
3233

3334
if entType != minderv1.Entity_ENTITY_REPOSITORIES {
@@ -88,32 +89,6 @@ func (c *gitlabClient) DeregisterEntity(
8889
return nil
8990
}
9091

91-
// ReregisterEntity implements the Provider interface
92-
func (c *gitlabClient) ReregisterEntity(
93-
ctx context.Context, entType minderv1.Entity, props *properties.Properties,
94-
) error {
95-
if !c.SupportsEntity(entType) {
96-
return errors.New("unsupported entity type")
97-
}
98-
99-
upstreamID := props.GetProperty(properties.PropertyUpstreamID).GetString()
100-
if upstreamID == "" {
101-
return errors.New("missing upstream ID")
102-
}
103-
104-
hookID := props.GetProperty(RepoPropertyHookID).GetString()
105-
if hookID == "" {
106-
return errors.New("missing hook ID")
107-
}
108-
109-
hookURL := props.GetProperty(RepoPropertyHookURL).GetString()
110-
if hookURL == "" {
111-
return errors.New("missing hook URL")
112-
}
113-
114-
return c.updateWebhook(ctx, upstreamID, hookID, hookURL)
115-
}
116-
11792
func (c *gitlabClient) createWebhook(ctx context.Context, upstreamID string) (*properties.Properties, error) {
11893
createHookPath, err := url.JoinPath("projects", upstreamID, "hooks")
11994
if err != nil {
@@ -236,64 +211,3 @@ func (c *gitlabClient) cleanUpStaleWebhooks(ctx context.Context, upstreamID stri
236211

237212
return nil
238213
}
239-
240-
func (c *gitlabClient) updateWebhook(ctx context.Context, upstreamID, hookID string, hookURL string) error {
241-
// We don't need to update the webhook URL, as it's unique for each
242-
// registration. We only need to update the secret.
243-
updateHookPath, err := url.JoinPath("projects", upstreamID, "hooks", hookID)
244-
if err != nil {
245-
return fmt.Errorf("failed to join URL path for hook: %w", err)
246-
}
247-
248-
hookURLParsed, err := url.Parse(hookURL)
249-
if err != nil {
250-
return fmt.Errorf("failed to parse hook URL: %w", err)
251-
}
252-
253-
// We need to extract the UUID from the webhook URL. The UUID is
254-
// the last part of the path.
255-
hookMinderUUID := hookURLParsed.Path[strings.LastIndex(hookURLParsed.Path, "/")+1:]
256-
257-
sec, err := webhooksecret.New(c.currentWebhookSecret, hookMinderUUID)
258-
if err != nil {
259-
return fmt.Errorf("failed to create webhook secret: %w", err)
260-
}
261-
262-
trve := ptr.Ptr(true)
263-
hreq := &gitlab.EditProjectHookOptions{
264-
URL: &hookURL,
265-
Token: &sec,
266-
PushEvents: trve,
267-
TagPushEvents: trve,
268-
MergeRequestsEvents: trve,
269-
ReleasesEvents: trve,
270-
EnableSSLVerification: trve,
271-
}
272-
273-
if err := c.doUpdateWebhook(ctx, updateHookPath, hreq); err != nil {
274-
return fmt.Errorf("failed to update webhook: %w", err)
275-
}
276-
277-
return nil
278-
}
279-
280-
func (c *gitlabClient) doUpdateWebhook(
281-
ctx context.Context, updateHookPath string, hreq *gitlab.EditProjectHookOptions,
282-
) error {
283-
req, err := c.NewRequest(http.MethodPut, updateHookPath, hreq)
284-
if err != nil {
285-
return fmt.Errorf("failed to create request: %w", err)
286-
}
287-
288-
resp, err := c.Do(ctx, req)
289-
if err != nil {
290-
return fmt.Errorf("failed to get projects: %w", err)
291-
}
292-
defer resp.Body.Close()
293-
294-
if resp.StatusCode != http.StatusOK {
295-
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
296-
}
297-
298-
return nil
299-
}

0 commit comments

Comments
 (0)