• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

opendefensecloud / artifact-conduit / 23895603772

02 Apr 2026 10:16AM UTC coverage: 83.836% (-0.9%) from 84.698%
23895603772

push

github

web-flow
Lower minimum cron schedule interval for e2e tests and refactor e2e tests (#258)

* Improve e2e test to fail fast

* Add renovate config for auto updates in example workflows

* Change latest for fixed version tags in example workflows
  Notice that cosign has still latest tag since it's a chainguard free image.

* Fix ocm example

* Add dedicated order resources for e2e tests
  This reduces the possibility of cve's making the tests fail. And
improves performance since only one of each type gets ordered.
  (We can add multiple of one as a dedicated test case)

778 of 928 relevant lines covered (83.84%)

1648.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.45
/pkg/controller/workflow_handler.go
1
// Copyright 2025 BWI GmbH and Artifact Conduit contributors
2
// SPDX-License-Identifier: Apache-2.0
3

4
package controller
5

6
import (
7
        "context"
8
        "fmt"
9

10
        wfv1alpha1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
11
        "github.com/go-logr/logr"
12
        "github.com/jastBytes/sprint"
13
        corev1 "k8s.io/api/core/v1"
14
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15
        "sigs.k8s.io/controller-runtime/pkg/client"
16
        "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
17

18
        arcv1alpha1 "go.opendefense.cloud/arc/api/arc/v1alpha1"
19
)
20

21
type WorkflowHandler interface {
22
        DeleteArgoResources(ctx context.Context) error
23
        CreateArgoResources(ctx context.Context) error
24
        CheckArgoResources(ctx context.Context) error
25
}
26

27
var _ WorkflowHandler = &SingleWorkflowHandler{}
28

29
type SingleWorkflowHandler struct {
30
        *ArtifactWorkflowReconciler
31
        log logr.Logger
32
        aw  *arcv1alpha1.ArtifactWorkflow
33
}
34

35
func NewSingleWorkflowHandler(r *ArtifactWorkflowReconciler, log logr.Logger, aw *arcv1alpha1.ArtifactWorkflow) *SingleWorkflowHandler {
3,122✔
36
        return &SingleWorkflowHandler{r, log, aw}
3,122✔
37
}
3,122✔
38

39
func (h *SingleWorkflowHandler) DeleteArgoResources(ctx context.Context) error {
8✔
40
        wf := wfv1alpha1.Workflow{
8✔
41
                ObjectMeta: metav1.ObjectMeta{
8✔
42
                        Namespace: h.aw.Namespace,
8✔
43
                        Name:      h.aw.Name,
8✔
44
                },
8✔
45
        }
8✔
46
        if err := h.Delete(ctx, &wf); client.IgnoreNotFound(err) != nil {
8✔
47
                h.Recorder.Eventf(h.aw, nil, corev1.EventTypeWarning, "DeletionFailed", "Delete", fmt.Sprintf("Failed to delete associated workflow '%s': %v", h.aw.Name, err))
×
48
                return errLogAndWrap(h.log, err, "workflow deletion failed")
×
49
        }
×
50
        h.Recorder.Eventf(h.aw, nil, corev1.EventTypeNormal, "Deleted", "Delete", fmt.Sprintf("Deleted workflow '%s'", h.aw.Name))
8✔
51

8✔
52
        return nil
8✔
53
}
54

55
func (h *SingleWorkflowHandler) CreateArgoResources(ctx context.Context) error {
1,645✔
56
        srcSecret, dstSecret, err := h.retrieveSecrets(ctx, h.aw)
1,645✔
57
        if err != nil {
1,645✔
58
                return errLogAndWrap(h.log, err, "failed to fetch secrets for artifact workflow")
×
59
        }
×
60

61
        wf := hydrateArgoWorkflow(h.aw, srcSecret, dstSecret)
1,645✔
62

1,645✔
63
        if err := controllerutil.SetControllerReference(h.aw, wf, h.Scheme); err != nil {
1,645✔
64
                return errLogAndWrap(h.log, err, "failed to set controller reference")
×
65
        }
×
66

67
        if err := h.Create(ctx, wf); client.IgnoreAlreadyExists(err) != nil {
1,852✔
68
                h.Recorder.Eventf(h.aw, nil, corev1.EventTypeWarning, "CreationFailed", "Create", fmt.Sprintf("Failed to create workflow '%s': %v", wf.GetName(), err))
207✔
69
                return errLogAndWrap(h.log, err, "failed to create argo workflow")
207✔
70
        }
207✔
71
        h.Recorder.Eventf(h.aw, nil, corev1.EventTypeNormal, "Created", "Create", fmt.Sprintf("Created workflow '%s'", wf.GetName()))
1,438✔
72

1,438✔
73
        h.aw.Status.Phase = arcv1alpha1.WorkflowPending
1,438✔
74
        if err := h.Status().Update(ctx, h.aw); err != nil {
1,443✔
75
                return errLogAndWrap(h.log, err, "failed to update status")
5✔
76
        }
5✔
77

78
        return nil
1,433✔
79
}
80

81
func (h *SingleWorkflowHandler) CheckArgoResources(ctx context.Context) error {
1,434✔
82
        wf := wfv1alpha1.Workflow{}
1,434✔
83
        if err := h.Get(ctx, namespacedName(h.aw.Namespace, h.aw.Name), &wf); err != nil {
1,434✔
84
                return errLogAndWrap(h.log, err, "failed to get workflow")
×
85
        }
×
86

87
        if updated := h.setStatusFromWorkflow(ctx, h.log, h.aw, &wf); !updated {
1,437✔
88
                return nil // nothing updated
3✔
89
        }
3✔
90

91
        if err := h.Status().Update(ctx, h.aw); err != nil {
1,431✔
92
                return errLogAndWrap(h.log, err, "failed to update status")
×
93
        }
×
94

95
        return nil
1,431✔
96
}
97

98
var _ WorkflowHandler = &CronWorkflowHandler{}
99

100
type CronWorkflowHandler struct {
101
        *ArtifactWorkflowReconciler
102
        log logr.Logger
103
        aw  *arcv1alpha1.ArtifactWorkflow
104
}
105

106
func NewCronWorkflowHandler(r *ArtifactWorkflowReconciler, log logr.Logger, aw *arcv1alpha1.ArtifactWorkflow) *CronWorkflowHandler {
19✔
107
        return &CronWorkflowHandler{r, log, aw}
19✔
108
}
19✔
109

110
func (h *CronWorkflowHandler) DeleteArgoResources(ctx context.Context) error {
×
111
        cwf := wfv1alpha1.CronWorkflow{
×
112
                ObjectMeta: metav1.ObjectMeta{
×
113
                        Namespace: h.aw.Namespace,
×
114
                        Name:      h.aw.Name,
×
115
                },
×
116
        }
×
117
        if err := h.Delete(ctx, &cwf); client.IgnoreNotFound(err) != nil {
×
118
                h.Recorder.Eventf(h.aw, nil, corev1.EventTypeWarning, "DeletionFailed", "Delete", fmt.Sprintf("Failed to delete associated cron workflow '%s': %v", h.aw.Name, err))
×
119
                return errLogAndWrap(h.log, err, "cron workflow deletion failed")
×
120
        }
×
121
        h.Recorder.Eventf(h.aw, nil, corev1.EventTypeNormal, "Deleted", "Delete", fmt.Sprintf("Deleted cron workflow '%s'", h.aw.Name))
×
122

×
123
        return nil
×
124
}
125

126
func (h *CronWorkflowHandler) CreateArgoResources(ctx context.Context) error {
2✔
127
        srcSecret, dstSecret, err := h.retrieveSecrets(ctx, h.aw)
2✔
128
        if err != nil {
2✔
129
                return errLogAndWrap(h.log, err, "failed to fetch secrets for artifact workflow")
×
130
        }
×
131

132
        cwf := hydrateArgoCronWorkflow(h.aw, srcSecret, dstSecret)
2✔
133

2✔
134
        if err := controllerutil.SetControllerReference(h.aw, cwf, h.Scheme); err != nil {
2✔
135
                return errLogAndWrap(h.log, err, "failed to set controller reference")
×
136
        }
×
137

138
        if err := h.Create(ctx, cwf); err != nil {
2✔
139
                if client.IgnoreAlreadyExists(err) != nil {
×
140
                        h.Recorder.Eventf(h.aw, nil, corev1.EventTypeWarning, "CreationFailed", "Create", fmt.Sprintf("Failed to create cron workflow '%s': %v", cwf.GetName(), err))
×
141
                        return errLogAndWrap(h.log, err, "failed to create argo cron workflow")
×
142
                }
×
143
        } else {
2✔
144
                h.Recorder.Eventf(h.aw, nil, corev1.EventTypeNormal, "Created", "Create", fmt.Sprintf("Created cron workflow '%s'", cwf.GetName()))
2✔
145
        }
2✔
146

147
        h.aw.Status.Phase = arcv1alpha1.WorkflowPending
2✔
148
        if err := h.Status().Update(ctx, h.aw); err != nil {
2✔
149
                return errLogAndWrap(h.log, err, "failed to update status")
×
150
        }
×
151

152
        return nil
2✔
153
}
154

155
func (h *CronWorkflowHandler) CheckArgoResources(ctx context.Context) error {
15✔
156
        cwf := wfv1alpha1.CronWorkflow{}
15✔
157
        if err := h.Get(ctx, namespacedName(h.aw.Namespace, h.aw.Name), &cwf); err != nil {
15✔
158
                return errLogAndWrap(h.log, err, "failed to get cron workflow")
×
159
        }
×
160

161
        updated := false
15✔
162

15✔
163
        if !h.aw.Status.LastScheduled.Equal(cwf.Status.LastScheduledTime) {
16✔
164
                h.aw.Status.LastScheduled = cwf.Status.LastScheduledTime
1✔
165
                updated = true
1✔
166
        }
1✔
167
        if h.aw.Status.Failed != cwf.Status.Failed {
16✔
168
                h.aw.Status.Failed = cwf.Status.Failed
1✔
169
                updated = true
1✔
170
        }
1✔
171
        if h.aw.Status.Succeeded != cwf.Status.Succeeded {
16✔
172
                h.aw.Status.Succeeded = cwf.Status.Succeeded
1✔
173
                updated = true
1✔
174
        }
1✔
175

176
        // If the active workflow is not the same as the current one, update the reference
177
        if len(cwf.Status.Active) > 0 {
27✔
178
                // Should only contain a single element at most (expected to be in the same namespace!)
12✔
179
                ref := cwf.Status.Active[len(cwf.Status.Active)-1]
12✔
180

12✔
181
                if h.aw.Status.ActiveWorkflowRef.Name != ref.Name {
21✔
182
                        h.log.V(1).Info("Updating reference for cron workflow", "cronWorkflow", cwf.Name, "activeWorkflow", ref.Name)
9✔
183

9✔
184
                        // Get the active workflow
9✔
185
                        wf := wfv1alpha1.Workflow{}
9✔
186
                        if err := h.Get(ctx, namespacedName(h.aw.Namespace, ref.Name), &wf); err != nil {
9✔
187
                                return errLogAndWrap(h.log, err, "failed to fetch active workflow")
×
188
                        }
×
189

190
                        h.aw.Status.ActiveWorkflowRef = corev1.LocalObjectReference{
9✔
191
                                Name: wf.Name,
9✔
192
                        }
9✔
193
                        h.aw.Status.Message = ""
9✔
194
                        h.aw.Status.Phase = arcv1alpha1.WorkflowActive
9✔
195

9✔
196
                        updated = updated || h.setStatusFromWorkflow(ctx, h.log, h.aw, &wf)
9✔
197
                }
198
        }
199

200
        // If there is an active workflow, check its status
201
        if h.aw.Status.ActiveWorkflowRef.Name != "" {
27✔
202
                wf := wfv1alpha1.Workflow{}
12✔
203
                if err := h.Get(ctx, namespacedName(h.aw.Namespace, h.aw.Status.ActiveWorkflowRef.Name), &wf); err != nil {
12✔
204
                        return errLogAndWrap(h.log, err, "failed to fetch active workflow")
×
205
                }
×
206

207
                updated = updated || h.setStatusFromWorkflow(ctx, h.log, h.aw, &wf)
12✔
208

12✔
209
                if wf.Status.Phase.Completed() {
21✔
210
                        h.aw.Status.ActiveWorkflowRef.Name = ""
9✔
211
                        updated = true
9✔
212
                }
9✔
213
        }
214

215
        if !updated {
19✔
216
                return nil
4✔
217
        }
4✔
218

219
        h.log.V(1).Info("Updating status from active workflow", "cronWorkflow", cwf.Name)
11✔
220

11✔
221
        if err := h.Status().Update(ctx, h.aw); err != nil {
11✔
222
                return errLogAndWrap(h.log, err, "failed to update status")
×
223
        }
×
224

225
        return nil
11✔
226
}
227

228
func hydrateArgoWorkflowSpec(aw *arcv1alpha1.ArtifactWorkflow, srcSecret *corev1.Secret, dstSecret *corev1.Secret) wfv1alpha1.WorkflowSpec {
1,647✔
229
        srcVolume := corev1.Volume{
1,647✔
230
                Name: "src-secret-vol",
1,647✔
231
                VolumeSource: corev1.VolumeSource{
1,647✔
232
                        EmptyDir: &corev1.EmptyDirVolumeSource{},
1,647✔
233
                },
1,647✔
234
        }
1,647✔
235
        if srcSecret.Name != "" {
3,011✔
236
                srcVolume.VolumeSource = corev1.VolumeSource{
1,364✔
237
                        Secret: &corev1.SecretVolumeSource{
1,364✔
238
                                SecretName: srcSecret.Name,
1,364✔
239
                        },
1,364✔
240
                }
1,364✔
241
        }
1,364✔
242

243
        dstVolume := corev1.Volume{
1,647✔
244
                Name: "dst-secret-vol",
1,647✔
245
                VolumeSource: corev1.VolumeSource{
1,647✔
246
                        EmptyDir: &corev1.EmptyDirVolumeSource{},
1,647✔
247
                },
1,647✔
248
        }
1,647✔
249
        if dstSecret.Name != "" {
3,011✔
250
                dstVolume.VolumeSource = corev1.VolumeSource{
1,364✔
251
                        Secret: &corev1.SecretVolumeSource{
1,364✔
252
                                SecretName: dstSecret.Name,
1,364✔
253
                        },
1,364✔
254
                }
1,364✔
255
        }
1,364✔
256

257
        parameters := []wfv1alpha1.Parameter{}
1,647✔
258
        for _, p := range aw.Spec.Parameters {
13,142✔
259
                parameters = append(parameters, wfv1alpha1.Parameter{
11,495✔
260
                        Name:  p.Name,
11,495✔
261
                        Value: (*wfv1alpha1.AnyString)(&p.Value),
11,495✔
262
                })
11,495✔
263
        }
11,495✔
264

265
        return wfv1alpha1.WorkflowSpec{
1,647✔
266
                WorkflowTemplateRef: &wfv1alpha1.WorkflowTemplateRef{
1,647✔
267
                        Name:         aw.Spec.WorkflowTemplateRef.Name,
1,647✔
268
                        ClusterScope: aw.Spec.WorkflowTemplateRef.ClusterScope,
1,647✔
269
                },
1,647✔
270
                Volumes: []corev1.Volume{
1,647✔
271
                        srcVolume,
1,647✔
272
                        dstVolume,
1,647✔
273
                },
1,647✔
274
                Arguments: wfv1alpha1.Arguments{
1,647✔
275
                        Parameters: parameters,
1,647✔
276
                },
1,647✔
277
        }
1,647✔
278
}
279

280
func hydrateArgoWorkflow(aw *arcv1alpha1.ArtifactWorkflow, srcSecret *corev1.Secret, dstSecret *corev1.Secret) *wfv1alpha1.Workflow {
1,645✔
281
        return &wfv1alpha1.Workflow{
1,645✔
282
                ObjectMeta: workflowObjectMeta(aw),
1,645✔
283
                Spec:       hydrateArgoWorkflowSpec(aw, srcSecret, dstSecret),
1,645✔
284
        }
1,645✔
285
}
1,645✔
286

287
func hydrateArgoCronWorkflow(aw *arcv1alpha1.ArtifactWorkflow, srcSecret *corev1.Secret, dstSecret *corev1.Secret) *wfv1alpha1.CronWorkflow {
2✔
288
        om := workflowObjectMeta(aw)
2✔
289
        wf := &wfv1alpha1.CronWorkflow{
2✔
290
                ObjectMeta: om,
2✔
291
                Spec: wfv1alpha1.CronWorkflowSpec{
2✔
292
                        WorkflowSpec:               hydrateArgoWorkflowSpec(aw, srcSecret, dstSecret),
2✔
293
                        Schedules:                  aw.Spec.Cron.Schedules,
2✔
294
                        ConcurrencyPolicy:          wfv1alpha1.ReplaceConcurrent,
2✔
295
                        StartingDeadlineSeconds:    aw.Spec.Cron.StartingDeadlineSeconds,
2✔
296
                        Timezone:                   aw.Spec.Cron.Timezone,
2✔
297
                        When:                       aw.Spec.Cron.When,
2✔
298
                        SuccessfulJobsHistoryLimit: sprint.ToPointer(int32(1)),
2✔
299
                        FailedJobsHistoryLimit:     sprint.ToPointer(int32(1)),
2✔
300
                        WorkflowMetadata:           &om,
2✔
301
                },
2✔
302
        }
2✔
303

2✔
304
        return wf
2✔
305
}
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc