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

opendefensecloud / artifact-conduit / 19627303272

24 Nov 2025 08:02AM UTC coverage: 61.662% (+0.1%) from 61.516%
19627303272

push

github

web-flow
rename leftover mentions of fragment and artifacttypedefinition (#71)

Closes #69

1 of 2 new or added lines in 1 file covered. (50.0%)

2 existing lines in 1 file now uncovered.

423 of 686 relevant lines covered (61.66%)

546.74 hits per line

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

87.18
/pkg/controller/artifactworkflow_controller.go
1
// Copyright 2025 BWI GmbH and Artefact Conduit contributors
2
// SPDX-License-Identifier: Apache-2.0
3

4
package controller
5

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

10
        wfv1alpha1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
11
        "github.com/go-logr/logr"
12
        arcv1alpha1 "go.opendefense.cloud/arc/api/arc/v1alpha1"
13
        corev1 "k8s.io/api/core/v1"
14
        apierrors "k8s.io/apimachinery/pkg/api/errors"
15
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16
        "k8s.io/apimachinery/pkg/runtime"
17
        ctrl "sigs.k8s.io/controller-runtime"
18
        "sigs.k8s.io/controller-runtime/pkg/client"
19
        "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
20
)
21

22
const (
23
        artifactWorkflowFinalizer = "arc.bwi.de/artifact-workflow-finalizer"
24
)
25

26
// ArtifactWorkflowReconciler reconciles a ArtifactWorkflow object
27
type ArtifactWorkflowReconciler struct {
28
        client.Client
29
        Scheme *runtime.Scheme
30
}
31

32
//+kubebuilder:rbac:groups=arc.bwi.de,resources=artifacttypes,verbs=get;list;watch
33
//+kubebuilder:rbac:groups=arc.bwi.de,resources=artifactworkflows/status,verbs=get;update;patch
34
//+kubebuilder:rbac:groups=arc.bwi.de,resources=artifactworkflows/finalizers,verbs=update
35
//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete
36
//+kubebuilder:rbac:groups=argoproj.io,resources=workflows,verbs=get;list;watch;create;update;patch;delete
37

38
// Reconcile moves the current state of the cluster closer to the desired state
39
func (r *ArtifactWorkflowReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
1,389✔
40
        log := ctrl.LoggerFrom(ctx)
1,389✔
41

1,389✔
42
        aw := &arcv1alpha1.ArtifactWorkflow{}
1,389✔
43
        if err := r.Get(ctx, req.NamespacedName, aw); err != nil {
1,393✔
44
                if apierrors.IsNotFound(err) {
8✔
45
                        // Object not found, return.
4✔
46
                        return ctrl.Result{}, nil
4✔
47
                }
4✔
48
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to get object")
×
49
        }
50

51
        if !aw.DeletionTimestamp.IsZero() {
1,388✔
52
                log.V(1).Info("ArtifactWorkflow is being deleted")
3✔
53
                // Cleanup workflow, if exists
3✔
54
                wf := wfv1alpha1.Workflow{
3✔
55
                        ObjectMeta: metav1.ObjectMeta{
3✔
56
                                Namespace: aw.Namespace,
3✔
57
                                Name:      aw.Name,
3✔
58
                        },
3✔
59
                }
3✔
60
                if err := r.Delete(ctx, &wf); client.IgnoreNotFound(err) != nil {
3✔
61
                        return ctrl.Result{}, errLogAndWrap(log, err, "workflow deletion failed")
×
62
                }
×
63
                // Remove finalizer
64
                if slices.Contains(aw.Finalizers, artifactWorkflowFinalizer) {
6✔
65
                        log.V(1).Info("Removing finalizer from ArtifactWorkflow")
3✔
66
                        aw.Finalizers = slices.DeleteFunc(aw.Finalizers, func(f string) bool {
6✔
67
                                return f == artifactWorkflowFinalizer
3✔
68
                        })
3✔
69
                        if err := r.Update(ctx, aw); err != nil {
3✔
70
                                return ctrl.Result{}, errLogAndWrap(log, err, "failed to remove finalizer")
×
71
                        }
×
72
                }
73
                return ctrl.Result{}, nil
3✔
74
        }
75

76
        // Add finalizer if not present and not deleting
77
        if aw.DeletionTimestamp.IsZero() {
2,764✔
78
                if !slices.Contains(aw.Finalizers, artifactWorkflowFinalizer) {
1,400✔
79
                        log.V(1).Info("Adding finalizer to ArtifactWorkflow")
18✔
80
                        aw.Finalizers = append(aw.Finalizers, artifactWorkflowFinalizer)
18✔
81
                        if err := r.Update(ctx, aw); err != nil {
18✔
82
                                return ctrl.Result{}, errLogAndWrap(log, err, "failed to add finalizer")
×
83
                        }
×
84
                        // Return without requeue; the Update event will trigger reconciliation again
85
                        return ctrl.Result{}, nil
18✔
86
                }
87
        }
88

89
        if aw.Status.Phase.Completed() {
1,365✔
90
                // TODO: check if message has to be compiled from logs of workflow etc...
1✔
91
                return ctrl.Result{}, nil
1✔
92
        }
1✔
93

94
        if aw.Status.Phase == arcv1alpha1.WorkflowUnknown {
2,114✔
95
                return r.createArgoWorkflow(ctx, log, aw)
751✔
96
        }
751✔
97

98
        if aw.Status.Phase.InProgress() {
1,224✔
99
                return r.checkArgoWorkflow(ctx, log, aw)
612✔
100
        }
612✔
101

102
        return ctrl.Result{}, nil
×
103
}
104

105
func (r *ArtifactWorkflowReconciler) createArgoWorkflow(ctx context.Context, log logr.Logger, aw *arcv1alpha1.ArtifactWorkflow) (ctrl.Result, error) {
751✔
106
        artifactType := arcv1alpha1.ArtifactType{}
751✔
107
        if err := r.Get(ctx, namespacedName("", aw.Spec.Type), &artifactType); err != nil {
887✔
108
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to retrieve artifact type")
136✔
109
        }
136✔
110

111
        srcSecret := corev1.Secret{}
615✔
112
        if aw.Spec.SrcSecretRef.Name != "" {
1,100✔
113
                if err := r.Get(ctx, namespacedName(aw.Namespace, aw.Spec.SrcSecretRef.Name), &srcSecret); err != nil {
485✔
114
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to fetch secret for source")
×
115
                }
×
116
        }
117

118
        dstSecret := corev1.Secret{}
615✔
119
        if aw.Spec.DstSecretRef.Name != "" {
1,100✔
120
                if err := r.Get(ctx, namespacedName(aw.Namespace, aw.Spec.DstSecretRef.Name), &dstSecret); err != nil {
485✔
121
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to fetch secret for destination")
×
122
                }
×
123
        }
124

125
        wf := r.hydrateArgoWorkflow(aw, &artifactType, &srcSecret, &dstSecret)
615✔
126

615✔
127
        if err := controllerutil.SetControllerReference(aw, wf, r.Scheme); err != nil {
615✔
128
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to set controller reference")
×
129
        }
×
130

131
        if err := r.Create(ctx, wf); client.IgnoreAlreadyExists(err) != nil {
620✔
132
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to create argo workflow")
5✔
133
        }
5✔
134

135
        aw.Status.Phase = arcv1alpha1.WorkflowPending
610✔
136
        if err := r.Status().Update(ctx, aw); err != nil {
610✔
UNCOV
137
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to update status")
×
UNCOV
138
        }
×
139
        return ctrl.Result{}, nil
610✔
140
}
141

142
func (r *ArtifactWorkflowReconciler) hydrateArgoWorkflow(aw *arcv1alpha1.ArtifactWorkflow, artifactType *arcv1alpha1.ArtifactType, srcSecret *corev1.Secret, dstSecret *corev1.Secret) *wfv1alpha1.Workflow {
615✔
143

615✔
144
        srcVolume := corev1.Volume{
615✔
145
                Name: "src-secret-vol",
615✔
146
                VolumeSource: corev1.VolumeSource{
615✔
147
                        EmptyDir: &corev1.EmptyDirVolumeSource{},
615✔
148
                },
615✔
149
        }
615✔
150
        if srcSecret.Name != "" {
1,100✔
151
                srcVolume.VolumeSource = corev1.VolumeSource{
485✔
152
                        Secret: &corev1.SecretVolumeSource{
485✔
153
                                SecretName: srcSecret.Name,
485✔
154
                        },
485✔
155
                }
485✔
156
        }
485✔
157

158
        dstVolume := corev1.Volume{
615✔
159
                Name: "dst-secret-vol",
615✔
160
                VolumeSource: corev1.VolumeSource{
615✔
161
                        EmptyDir: &corev1.EmptyDirVolumeSource{},
615✔
162
                },
615✔
163
        }
615✔
164
        if dstSecret.Name != "" {
1,100✔
165
                dstVolume.VolumeSource = corev1.VolumeSource{
485✔
166
                        Secret: &corev1.SecretVolumeSource{
485✔
167
                                SecretName: dstSecret.Name,
485✔
168
                        },
485✔
169
                }
485✔
170
        }
485✔
171

172
        parameters := []wfv1alpha1.Parameter{}
615✔
173
        for _, p := range aw.Spec.Parameters {
3,489✔
174
                parameters = append(parameters, wfv1alpha1.Parameter{
2,874✔
175
                        Name:  p.Name,
2,874✔
176
                        Value: (*wfv1alpha1.AnyString)(&p.Value),
2,874✔
177
                })
2,874✔
178
        }
2,874✔
179
        for _, p := range artifactType.Spec.Parameters {
1,230✔
180
                parameters = append(parameters, wfv1alpha1.Parameter{
615✔
181
                        Name:  p.Name,
615✔
182
                        Value: (*wfv1alpha1.AnyString)(&p.Value),
615✔
183
                })
615✔
184
        }
615✔
185

186
        wf := &wfv1alpha1.Workflow{
615✔
187
                ObjectMeta: metav1.ObjectMeta{
615✔
188
                        Name:      aw.Name,
615✔
189
                        Namespace: aw.Namespace,
615✔
190
                },
615✔
191
                Spec: wfv1alpha1.WorkflowSpec{
615✔
192
                        WorkflowTemplateRef: &wfv1alpha1.WorkflowTemplateRef{
615✔
193
                                Name:         artifactType.Spec.WorkflowTemplateRef.Name,
615✔
194
                                ClusterScope: true,
615✔
195
                        },
615✔
196
                        Volumes: []corev1.Volume{
615✔
197
                                srcVolume,
615✔
198
                                dstVolume,
615✔
199
                        },
615✔
200
                        Arguments: wfv1alpha1.Arguments{
615✔
201
                                Parameters: parameters,
615✔
202
                        },
615✔
203
                },
615✔
204
        }
615✔
205

615✔
206
        return wf
615✔
207
}
208

209
func (r *ArtifactWorkflowReconciler) checkArgoWorkflow(ctx context.Context, log logr.Logger, aw *arcv1alpha1.ArtifactWorkflow) (ctrl.Result, error) {
612✔
210
        wf := wfv1alpha1.Workflow{}
612✔
211
        if err := r.Get(ctx, namespacedName(aw.Namespace, aw.Name), &wf); err != nil {
612✔
212
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to get workflow")
×
213
        }
×
214

215
        aw.Status.Phase = arcv1alpha1.WorkflowPhase(wf.Status.Phase)
612✔
216
        if err := r.Status().Update(ctx, aw); err != nil {
612✔
217
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to update status")
×
218
        }
×
219
        return ctrl.Result{}, nil
612✔
220
}
221

222
// SetupWithManager sets up the controller with the Manager.
223
func (r *ArtifactWorkflowReconciler) SetupWithManager(mgr ctrl.Manager) error {
1✔
224
        return ctrl.NewControllerManagedBy(mgr).
1✔
225
                For(&arcv1alpha1.ArtifactWorkflow{}).
1✔
226
                Owns(&wfv1alpha1.Workflow{}).
1✔
227
                Complete(r)
1✔
228
}
1✔
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