mirror of
https://github.com/argoproj/argo-cd
synced 2026-04-21 17:07:16 +00:00
sibling of ac4ae1779e
This commit is contained in:
parent
d83ef2c224
commit
8b49d21bb3
243 changed files with 7199 additions and 28847 deletions
2
.github/workflows/ci-build.yaml
vendored
2
.github/workflows/ci-build.yaml
vendored
|
|
@ -112,7 +112,7 @@ jobs:
|
|||
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
|
||||
with:
|
||||
# renovate: datasource=go packageName=github.com/golangci/golangci-lint versioning=regex:^v(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)?$
|
||||
version: v2.2.2
|
||||
version: v2.1.6
|
||||
args: --verbose
|
||||
|
||||
test-go:
|
||||
|
|
|
|||
2
.github/workflows/image-reuse.yaml
vendored
2
.github/workflows/image-reuse.yaml
vendored
|
|
@ -73,7 +73,7 @@ jobs:
|
|||
cache: false
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3.9.1
|
||||
uses: sigstore/cosign-installer@fb28c2b6339dcd94da6e4cbcbc5e888961f6f8c3 # v3.9.0
|
||||
|
||||
- uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ release:
|
|||
All Argo CD container images are signed by cosign. A Provenance is generated for container images and CLI binaries which meet the SLSA Level 3 specifications. See the [documentation](https://argo-cd.readthedocs.io/en/stable/operator-manual/signed-release-assets) on how to verify.
|
||||
|
||||
## Release Notes Blog Post
|
||||
For a detailed breakdown of the key changes and improvements in this release, check out the [official blog post](https://blog.argoproj.io/argo-cd-v3-0-release-candidate-a0b933f4e58f)
|
||||
For a detailed breakdown of the key changes and improvements in this release, check out the [official blog post](https://blog.argoproj.io/announcing-argo-cd-v3-1-f4389bc783c8)
|
||||
|
||||
## Upgrading
|
||||
|
||||
|
|
|
|||
|
|
@ -32,9 +32,6 @@ packages:
|
|||
github.com/argoproj/argo-cd/v3/controller/cache:
|
||||
interfaces:
|
||||
LiveStateCache: {}
|
||||
github.com/argoproj/argo-cd/v3/controller/hydrator:
|
||||
interfaces:
|
||||
Dependencies: {}
|
||||
github.com/argoproj/argo-cd/v3/pkg/apiclient/cluster:
|
||||
interfaces:
|
||||
ClusterServiceServer: {}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
ARG BASE_IMAGE=docker.io/library/ubuntu:25.04@sha256:10bb10bb062de665d4dc3e0ea36715270ead632cfcb74d08ca2273712a0dfb42
|
||||
ARG BASE_IMAGE=docker.io/library/ubuntu:24.04@sha256:80dd3c3b9c6cecb9f1667e9290b3bc61b78c2678c02cbdae5f0fea92cc6734ab
|
||||
####################################################################################################
|
||||
# Builder image
|
||||
# Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image
|
||||
|
|
|
|||
1
Makefile
1
Makefile
|
|
@ -604,7 +604,6 @@ install-test-tools-local:
|
|||
.PHONY: install-codegen-tools-local
|
||||
install-codegen-tools-local:
|
||||
./hack/install.sh codegen-tools
|
||||
./hack/install.sh codegen-go-tools
|
||||
|
||||
# Installs all tools required for running codegen (Go packages)
|
||||
.PHONY: install-go-tools-local
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ header:
|
|||
expiration-date: '2024-10-31T00:00:00.000Z' # One year from initial release.
|
||||
last-updated: '2023-10-27'
|
||||
last-reviewed: '2023-10-27'
|
||||
commit-hash: 320f46f06beaf75f9c406e3a47e2e09d36e2047a
|
||||
commit-hash: 226a670fe6b3c6769ff6d18e6839298a58e4577d
|
||||
project-url: https://github.com/argoproj/argo-cd
|
||||
project-release: v3.2.0
|
||||
project-release: v3.1.0
|
||||
changelog: https://github.com/argoproj/argo-cd/releases
|
||||
license: https://github.com/argoproj/argo-cd/blob/master/LICENSE
|
||||
project-lifecycle:
|
||||
|
|
|
|||
3
Tiltfile
3
Tiltfile
|
|
@ -69,7 +69,7 @@ docker_build_with_restart(
|
|||
],
|
||||
platform=platform,
|
||||
live_update=[
|
||||
sync('.tilt-bin/argocd_linux', '/usr/local/bin/argocd'),
|
||||
sync('.tilt-bin/argocd_linux_amd64', '/usr/local/bin/argocd'),
|
||||
],
|
||||
only=[
|
||||
'.tilt-bin',
|
||||
|
|
@ -260,7 +260,6 @@ local_resource(
|
|||
'make lint-local',
|
||||
deps = code_deps,
|
||||
allow_parallel=True,
|
||||
resource_deps=['vendor']
|
||||
)
|
||||
|
||||
local_resource(
|
||||
|
|
|
|||
2
USERS.md
2
USERS.md
|
|
@ -173,7 +173,6 @@ Currently, the following organizations are **officially** using Argo CD:
|
|||
1. [Info Support](https://www.infosupport.com/)
|
||||
1. [InsideBoard](https://www.insideboard.com)
|
||||
1. [Instruqt](https://www.instruqt.com)
|
||||
1. [Intel](https://www.intel.com)
|
||||
1. [Intuit](https://www.intuit.com/)
|
||||
1. [Jellysmack](https://www.jellysmack.com)
|
||||
1. [Joblift](https://joblift.com/)
|
||||
|
|
@ -322,7 +321,6 @@ Currently, the following organizations are **officially** using Argo CD:
|
|||
1. [SEKAI](https://www.sekai.io/)
|
||||
1. [Semgrep](https://semgrep.com)
|
||||
1. [Shield](https://shield.com)
|
||||
1. [Shipfox](https://www.shipfox.io)
|
||||
1. [SI Analytics](https://si-analytics.ai)
|
||||
1. [Sidewalk Entertainment](https://sidewalkplay.com/)
|
||||
1. [Skit](https://skit.ai/)
|
||||
|
|
|
|||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
3.2.0
|
||||
3.1.0-rc3
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ package controllers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
|
|
@ -68,8 +67,6 @@ const (
|
|||
// https://github.com/argoproj-labs/argocd-notifications/blob/33d345fa838829bb50fca5c08523aba380d2c12b/pkg/controller/state.go#L17
|
||||
NotifiedAnnotationKey = "notified.notifications.argoproj.io"
|
||||
ReconcileRequeueOnValidationError = time.Minute * 3
|
||||
ReverseDeletionOrder = "Reverse"
|
||||
AllAtOnceDeletionOrder = "AllAtOnce"
|
||||
)
|
||||
|
||||
var defaultPreservedAnnotations = []string{
|
||||
|
|
@ -77,11 +74,6 @@ var defaultPreservedAnnotations = []string{
|
|||
argov1alpha1.AnnotationKeyRefresh,
|
||||
}
|
||||
|
||||
type deleteInOrder struct {
|
||||
AppName string
|
||||
Step int
|
||||
}
|
||||
|
||||
// ApplicationSetReconciler reconciles a ApplicationSet object
|
||||
type ApplicationSetReconciler struct {
|
||||
client.Client
|
||||
|
|
@ -147,19 +139,6 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
|||
}
|
||||
logCtx.Debugf("ownerReferences referring %s is deleted from generated applications", appsetName)
|
||||
}
|
||||
if isProgressiveSyncDeletionOrderReversed(&applicationSetInfo) {
|
||||
logCtx.Debugf("DeletionOrder is set as Reverse on %s", appsetName)
|
||||
currentApplications, err := r.getCurrentApplications(ctx, applicationSetInfo)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
requeueTime, err := r.performReverseDeletion(ctx, logCtx, applicationSetInfo, currentApplications)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
} else if requeueTime > 0 {
|
||||
return ctrl.Result{RequeueAfter: requeueTime}, err
|
||||
}
|
||||
}
|
||||
controllerutil.RemoveFinalizer(&applicationSetInfo, argov1alpha1.ResourcesFinalizerName)
|
||||
if err := r.Update(ctx, &applicationSetInfo); err != nil {
|
||||
return ctrl.Result{}, err
|
||||
|
|
@ -175,7 +154,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
|||
// Log a warning if there are unrecognized generators
|
||||
_ = utils.CheckInvalidGenerators(&applicationSetInfo)
|
||||
// desiredApplications is the main list of all expected Applications from all generators in this appset.
|
||||
generatedApplications, applicationSetReason, err := template.GenerateApplications(logCtx, applicationSetInfo, r.Generators, r.Renderer, r.Client)
|
||||
desiredApplications, applicationSetReason, err := template.GenerateApplications(logCtx, applicationSetInfo, r.Generators, r.Renderer, r.Client)
|
||||
if err != nil {
|
||||
logCtx.Errorf("unable to generate applications: %v", err)
|
||||
_ = r.setApplicationSetStatusCondition(ctx,
|
||||
|
|
@ -193,7 +172,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
|||
|
||||
parametersGenerated = true
|
||||
|
||||
validateErrors, err := r.validateGeneratedApplications(ctx, generatedApplications, applicationSetInfo)
|
||||
validateErrors, err := r.validateGeneratedApplications(ctx, desiredApplications, applicationSetInfo)
|
||||
if err != nil {
|
||||
// While some generators may return an error that requires user intervention,
|
||||
// other generators reference external resources that may change to cause
|
||||
|
|
@ -246,7 +225,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
|||
appMap[app.Name] = app
|
||||
}
|
||||
|
||||
appSyncMap, err = r.performProgressiveSyncs(ctx, logCtx, applicationSetInfo, currentApplications, generatedApplications, appMap)
|
||||
appSyncMap, err = r.performProgressiveSyncs(ctx, logCtx, applicationSetInfo, currentApplications, desiredApplications, appMap)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, fmt.Errorf("failed to perform progressive sync reconciliation for application set: %w", err)
|
||||
}
|
||||
|
|
@ -254,23 +233,17 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
|||
}
|
||||
|
||||
var validApps []argov1alpha1.Application
|
||||
for i := range generatedApplications {
|
||||
if validateErrors[generatedApplications[i].QualifiedName()] == nil {
|
||||
validApps = append(validApps, generatedApplications[i])
|
||||
for i := range desiredApplications {
|
||||
if validateErrors[i] == nil {
|
||||
validApps = append(validApps, desiredApplications[i])
|
||||
}
|
||||
}
|
||||
|
||||
if len(validateErrors) > 0 {
|
||||
errorApps := make([]string, 0, len(validateErrors))
|
||||
for key := range validateErrors {
|
||||
errorApps = append(errorApps, key)
|
||||
}
|
||||
sort.Strings(errorApps)
|
||||
|
||||
var message string
|
||||
for _, appName := range errorApps {
|
||||
message = validateErrors[appName].Error()
|
||||
logCtx.WithField("application", appName).Errorf("validation error found during application validation: %s", message)
|
||||
for _, v := range validateErrors {
|
||||
message = v.Error()
|
||||
logCtx.Errorf("validation error found during application validation: %s", message)
|
||||
}
|
||||
if len(validateErrors) > 1 {
|
||||
// Only the last message gets added to the appset status, to keep the size reasonable.
|
||||
|
|
@ -325,12 +298,12 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
|||
}
|
||||
|
||||
if utils.DefaultPolicy(applicationSetInfo.Spec.SyncPolicy, r.Policy, r.EnablePolicyOverride).AllowDelete() {
|
||||
err = r.deleteInCluster(ctx, logCtx, applicationSetInfo, generatedApplications)
|
||||
err = r.deleteInCluster(ctx, logCtx, applicationSetInfo, desiredApplications)
|
||||
if err != nil {
|
||||
_ = r.setApplicationSetStatusCondition(ctx,
|
||||
&applicationSetInfo,
|
||||
argov1alpha1.ApplicationSetCondition{
|
||||
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
|
||||
Type: argov1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: err.Error(),
|
||||
Reason: argov1alpha1.ApplicationSetReasonDeleteApplicationError,
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
|
||||
|
|
@ -384,169 +357,120 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (r *ApplicationSetReconciler) performReverseDeletion(ctx context.Context, logCtx *log.Entry, appset argov1alpha1.ApplicationSet, currentApps []argov1alpha1.Application) (time.Duration, error) {
|
||||
requeueTime := 10 * time.Second
|
||||
stepLength := len(appset.Spec.Strategy.RollingSync.Steps)
|
||||
|
||||
// map applications by name using current applications
|
||||
appMap := make(map[string]*argov1alpha1.Application)
|
||||
for _, app := range currentApps {
|
||||
appMap[app.Name] = &app
|
||||
}
|
||||
|
||||
// Get Rolling Sync Step Maps
|
||||
_, appStepMap := r.buildAppDependencyList(logCtx, appset, currentApps)
|
||||
// reverse the AppStepMap to perform deletion
|
||||
var reverseDeleteAppSteps []deleteInOrder
|
||||
for appName, appStep := range appStepMap {
|
||||
reverseDeleteAppSteps = append(reverseDeleteAppSteps, deleteInOrder{appName, stepLength - appStep - 1})
|
||||
}
|
||||
|
||||
sort.Slice(reverseDeleteAppSteps, func(i, j int) bool {
|
||||
return reverseDeleteAppSteps[i].Step < reverseDeleteAppSteps[j].Step
|
||||
})
|
||||
|
||||
for _, step := range reverseDeleteAppSteps {
|
||||
logCtx.Infof("step %v : app %v", step.Step, step.AppName)
|
||||
app := appMap[step.AppName]
|
||||
retrievedApp := argov1alpha1.Application{}
|
||||
if err := r.Get(ctx, types.NamespacedName{Name: app.Name, Namespace: app.Namespace}, &retrievedApp); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
logCtx.Infof("application %s successfully deleted", step.AppName)
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Check if the application is already being deleted
|
||||
if retrievedApp.DeletionTimestamp != nil {
|
||||
logCtx.Infof("application %s has been marked for deletion, but object not removed yet", step.AppName)
|
||||
if time.Since(retrievedApp.DeletionTimestamp.Time) > 2*time.Minute {
|
||||
return 0, errors.New("application has not been deleted in over 2 minutes")
|
||||
}
|
||||
}
|
||||
// The application has not been deleted yet, trigger its deletion
|
||||
if err := r.Delete(ctx, &retrievedApp); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return requeueTime, nil
|
||||
}
|
||||
logCtx.Infof("completed reverse deletion for ApplicationSet %v", appset.Name)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func getParametersGeneratedCondition(parametersGenerated bool, message string) argov1alpha1.ApplicationSetCondition {
|
||||
var parametersGeneratedCondition argov1alpha1.ApplicationSetCondition
|
||||
var paramtersGeneratedCondition argov1alpha1.ApplicationSetCondition
|
||||
if parametersGenerated {
|
||||
parametersGeneratedCondition = argov1alpha1.ApplicationSetCondition{
|
||||
paramtersGeneratedCondition = argov1alpha1.ApplicationSetCondition{
|
||||
Type: argov1alpha1.ApplicationSetConditionParametersGenerated,
|
||||
Message: "Successfully generated parameters for all Applications",
|
||||
Reason: argov1alpha1.ApplicationSetReasonParametersGenerated,
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
|
||||
}
|
||||
} else {
|
||||
parametersGeneratedCondition = argov1alpha1.ApplicationSetCondition{
|
||||
paramtersGeneratedCondition = argov1alpha1.ApplicationSetCondition{
|
||||
Type: argov1alpha1.ApplicationSetConditionParametersGenerated,
|
||||
Message: message,
|
||||
Reason: argov1alpha1.ApplicationSetReasonErrorOccurred,
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusFalse,
|
||||
}
|
||||
}
|
||||
return parametersGeneratedCondition
|
||||
return paramtersGeneratedCondition
|
||||
}
|
||||
|
||||
func (r *ApplicationSetReconciler) setApplicationSetStatusCondition(ctx context.Context, applicationSet *argov1alpha1.ApplicationSet, condition argov1alpha1.ApplicationSetCondition, parametersGenerated bool) error {
|
||||
// Initialize the default condition types that this method evaluates
|
||||
func getResourceUpToDateCondition(errorOccurred bool, message string, reason string) argov1alpha1.ApplicationSetCondition {
|
||||
var resourceUpToDateCondition argov1alpha1.ApplicationSetCondition
|
||||
if errorOccurred {
|
||||
resourceUpToDateCondition = argov1alpha1.ApplicationSetCondition{
|
||||
Type: argov1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: message,
|
||||
Reason: reason,
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusFalse,
|
||||
}
|
||||
} else {
|
||||
resourceUpToDateCondition = argov1alpha1.ApplicationSetCondition{
|
||||
Type: argov1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: "ApplicationSet up to date",
|
||||
Reason: argov1alpha1.ApplicationSetReasonApplicationSetUpToDate,
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
|
||||
}
|
||||
}
|
||||
return resourceUpToDateCondition
|
||||
}
|
||||
|
||||
func (r *ApplicationSetReconciler) setApplicationSetStatusCondition(ctx context.Context, applicationSet *argov1alpha1.ApplicationSet, condition argov1alpha1.ApplicationSetCondition, paramtersGenerated bool) error {
|
||||
// check if error occurred during reconcile process
|
||||
errOccurred := condition.Type == argov1alpha1.ApplicationSetConditionErrorOccurred
|
||||
|
||||
var errOccurredCondition argov1alpha1.ApplicationSetCondition
|
||||
|
||||
if errOccurred {
|
||||
errOccurredCondition = condition
|
||||
} else {
|
||||
errOccurredCondition = argov1alpha1.ApplicationSetCondition{
|
||||
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
|
||||
Message: "Successfully generated parameters for all Applications",
|
||||
Reason: argov1alpha1.ApplicationSetReasonApplicationSetUpToDate,
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusFalse,
|
||||
}
|
||||
}
|
||||
|
||||
paramtersGeneratedCondition := getParametersGeneratedCondition(paramtersGenerated, condition.Message)
|
||||
resourceUpToDateCondition := getResourceUpToDateCondition(errOccurred, condition.Message, condition.Reason)
|
||||
|
||||
evaluatedTypes := map[argov1alpha1.ApplicationSetConditionType]bool{
|
||||
argov1alpha1.ApplicationSetConditionErrorOccurred: true,
|
||||
argov1alpha1.ApplicationSetConditionParametersGenerated: true,
|
||||
argov1alpha1.ApplicationSetConditionErrorOccurred: false,
|
||||
argov1alpha1.ApplicationSetConditionResourcesUpToDate: false,
|
||||
argov1alpha1.ApplicationSetConditionRolloutProgressing: false,
|
||||
argov1alpha1.ApplicationSetConditionResourcesUpToDate: true,
|
||||
}
|
||||
// Evaluate current condition
|
||||
evaluatedTypes[condition.Type] = true
|
||||
newConditions := []argov1alpha1.ApplicationSetCondition{condition}
|
||||
newConditions := []argov1alpha1.ApplicationSetCondition{errOccurredCondition, paramtersGeneratedCondition, resourceUpToDateCondition}
|
||||
|
||||
if !isRollingSyncStrategy(applicationSet) {
|
||||
// Progressing sync is always evaluated so conditions are removed when it is not enabled
|
||||
if progressiveSyncsRollingSyncStrategyEnabled(applicationSet) {
|
||||
evaluatedTypes[argov1alpha1.ApplicationSetConditionRolloutProgressing] = true
|
||||
}
|
||||
|
||||
// Evaluate ParametersGenerated since it is always provided
|
||||
if condition.Type != argov1alpha1.ApplicationSetConditionParametersGenerated {
|
||||
newConditions = append(newConditions, getParametersGeneratedCondition(parametersGenerated, condition.Message))
|
||||
}
|
||||
|
||||
// Evaluate dependencies between conditions.
|
||||
switch condition.Type {
|
||||
case argov1alpha1.ApplicationSetConditionResourcesUpToDate:
|
||||
if condition.Status == argov1alpha1.ApplicationSetConditionStatusTrue {
|
||||
// If the resources are up to date, we know there was no errors
|
||||
evaluatedTypes[argov1alpha1.ApplicationSetConditionErrorOccurred] = true
|
||||
newConditions = append(newConditions, argov1alpha1.ApplicationSetCondition{
|
||||
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusFalse,
|
||||
Reason: condition.Reason,
|
||||
Message: condition.Message,
|
||||
})
|
||||
}
|
||||
case argov1alpha1.ApplicationSetConditionErrorOccurred:
|
||||
if condition.Status == argov1alpha1.ApplicationSetConditionStatusTrue {
|
||||
// If there is an error anywhere in the reconciliation, we cannot consider the resources up to date
|
||||
evaluatedTypes[argov1alpha1.ApplicationSetConditionResourcesUpToDate] = true
|
||||
newConditions = append(newConditions, argov1alpha1.ApplicationSetCondition{
|
||||
Type: argov1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusFalse,
|
||||
Reason: argov1alpha1.ApplicationSetReasonErrorOccurred,
|
||||
Message: condition.Message,
|
||||
})
|
||||
}
|
||||
case argov1alpha1.ApplicationSetConditionRolloutProgressing:
|
||||
if !isRollingSyncStrategy(applicationSet) {
|
||||
// if the condition is a rolling sync and it is disabled, ignore it
|
||||
evaluatedTypes[condition.Type] = false
|
||||
if condition.Type == argov1alpha1.ApplicationSetConditionRolloutProgressing {
|
||||
newConditions = append(newConditions, condition)
|
||||
}
|
||||
}
|
||||
|
||||
// Update the applicationSet conditions
|
||||
previousConditions := applicationSet.Status.Conditions
|
||||
applicationSet.Status.SetConditions(newConditions, evaluatedTypes)
|
||||
|
||||
// Try to not call get/update if nothing has changed
|
||||
needToUpdateConditions := len(applicationSet.Status.Conditions) != len(previousConditions)
|
||||
if !needToUpdateConditions {
|
||||
for i, c := range applicationSet.Status.Conditions {
|
||||
previous := previousConditions[i]
|
||||
if c.Type != previous.Type || c.Reason != previous.Reason || c.Status != previous.Status || c.Message != previous.Message {
|
||||
needToUpdateConditions := false
|
||||
for _, condition := range newConditions {
|
||||
// do nothing if appset already has same condition
|
||||
for _, c := range applicationSet.Status.Conditions {
|
||||
if c.Type == condition.Type && (c.Reason != condition.Reason || c.Status != condition.Status || c.Message != condition.Message) {
|
||||
needToUpdateConditions = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !needToUpdateConditions {
|
||||
return nil
|
||||
}
|
||||
// DefaultRetry will retry 5 times with a backoff factor of 1, jitter of 0.1 and a duration of 10ms
|
||||
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
updatedAppset := &argov1alpha1.ApplicationSet{}
|
||||
if err := r.Get(ctx, types.NamespacedName{Namespace: applicationSet.Namespace, Name: applicationSet.Name}, updatedAppset); err != nil {
|
||||
if client.IgnoreNotFound(err) != nil {
|
||||
return nil
|
||||
if needToUpdateConditions || len(applicationSet.Status.Conditions) < len(newConditions) {
|
||||
// fetch updated Application Set object before updating it
|
||||
// DefaultRetry will retry 5 times with a backoff factor of 1, jitter of 0.1 and a duration of 10ms
|
||||
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
namespacedName := types.NamespacedName{Namespace: applicationSet.Namespace, Name: applicationSet.Name}
|
||||
updatedAppset := &argov1alpha1.ApplicationSet{}
|
||||
if err := r.Get(ctx, namespacedName, updatedAppset); err != nil {
|
||||
if client.IgnoreNotFound(err) != nil {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("error fetching updated application set: %w", err)
|
||||
}
|
||||
return fmt.Errorf("error fetching updated application set: %w", err)
|
||||
}
|
||||
|
||||
updatedAppset.Status.SetConditions(newConditions, evaluatedTypes)
|
||||
updatedAppset.Status.SetConditions(
|
||||
newConditions, evaluatedTypes,
|
||||
)
|
||||
|
||||
// Update the newly fetched object with new set of conditions
|
||||
err := r.Client.Status().Update(ctx, updatedAppset)
|
||||
if err != nil {
|
||||
return err
|
||||
// Update the newly fetched object with new set of conditions
|
||||
err := r.Client.Status().Update(ctx, updatedAppset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedAppset.DeepCopyInto(applicationSet)
|
||||
return nil
|
||||
})
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
return fmt.Errorf("unable to set application set condition: %w", err)
|
||||
}
|
||||
updatedAppset.DeepCopyInto(applicationSet)
|
||||
return nil
|
||||
})
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
return fmt.Errorf("unable to set application set condition: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -554,33 +478,33 @@ func (r *ApplicationSetReconciler) setApplicationSetStatusCondition(ctx context.
|
|||
|
||||
// validateGeneratedApplications uses the Argo CD validation functions to verify the correctness of the
|
||||
// generated applications.
|
||||
func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Context, desiredApplications []argov1alpha1.Application, applicationSetInfo argov1alpha1.ApplicationSet) (map[string]error, error) {
|
||||
errorsByApp := map[string]error{}
|
||||
func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Context, desiredApplications []argov1alpha1.Application, applicationSetInfo argov1alpha1.ApplicationSet) (map[int]error, error) {
|
||||
errorsByIndex := map[int]error{}
|
||||
namesSet := map[string]bool{}
|
||||
for i := range desiredApplications {
|
||||
app := &desiredApplications[i]
|
||||
for i, app := range desiredApplications {
|
||||
if namesSet[app.Name] {
|
||||
errorsByApp[app.QualifiedName()] = fmt.Errorf("ApplicationSet %s contains applications with duplicate name: %s", applicationSetInfo.Name, app.Name)
|
||||
errorsByIndex[i] = fmt.Errorf("ApplicationSet %s contains applications with duplicate name: %s", applicationSetInfo.Name, app.Name)
|
||||
continue
|
||||
}
|
||||
namesSet[app.Name] = true
|
||||
|
||||
appProject := &argov1alpha1.AppProject{}
|
||||
err := r.Get(ctx, types.NamespacedName{Name: app.Spec.Project, Namespace: r.ArgoCDNamespace}, appProject)
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
errorsByApp[app.QualifiedName()] = fmt.Errorf("application references project %s which does not exist", app.Spec.Project)
|
||||
errorsByIndex[i] = fmt.Errorf("application references project %s which does not exist", app.Spec.Project)
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = argoutil.GetDestinationCluster(ctx, app.Spec.Destination, r.ArgoDB); err != nil {
|
||||
errorsByApp[app.QualifiedName()] = fmt.Errorf("application destination spec is invalid: %s", err.Error())
|
||||
errorsByIndex[i] = fmt.Errorf("application destination spec is invalid: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return errorsByApp, nil
|
||||
return errorsByIndex, nil
|
||||
}
|
||||
|
||||
func (r *ApplicationSetReconciler) getMinRequeueAfter(applicationSetInfo *argov1alpha1.ApplicationSet) time.Duration {
|
||||
|
|
@ -808,7 +732,7 @@ func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, logCtx *
|
|||
return fmt.Errorf("error getting current applications: %w", err)
|
||||
}
|
||||
|
||||
m := make(map[string]bool) // will hold the app names in appList for the deletion process
|
||||
m := make(map[string]bool) // Will holds the app names in appList for the deletion process
|
||||
|
||||
for _, app := range desiredApplications {
|
||||
m[app.Name] = true
|
||||
|
|
@ -876,7 +800,7 @@ func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx conte
|
|||
}
|
||||
|
||||
if !matchingCluster {
|
||||
appLog.Warnf("A match for the destination cluster for %s, by server url, couldn't be found", app.Name)
|
||||
appLog.Warnf("A match for the destination cluster for %s, by server url, couldn't be found.", app.Name)
|
||||
}
|
||||
|
||||
validDestination = matchingCluster
|
||||
|
|
@ -1087,11 +1011,6 @@ func progressiveSyncsRollingSyncStrategyEnabled(appset *argov1alpha1.Application
|
|||
return isRollingSyncStrategy(appset) && len(appset.Spec.Strategy.RollingSync.Steps) > 0
|
||||
}
|
||||
|
||||
func isProgressiveSyncDeletionOrderReversed(appset *argov1alpha1.ApplicationSet) bool {
|
||||
// When progressive sync is enabled + deletionOrder is set to Reverse (case-insensitive)
|
||||
return progressiveSyncsRollingSyncStrategyEnabled(appset) && strings.EqualFold(appset.Spec.Strategy.DeletionOrder, ReverseDeletionOrder)
|
||||
}
|
||||
|
||||
func isApplicationHealthy(app argov1alpha1.Application) bool {
|
||||
healthStatusString, syncStatusString, operationPhaseString := statusStrings(app)
|
||||
|
||||
|
|
@ -1221,10 +1140,15 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress
|
|||
|
||||
// if we have no RollingUpdate steps, clear out the existing ApplicationStatus entries
|
||||
if progressiveSyncsRollingSyncStrategyEnabled(applicationSet) {
|
||||
updateCountMap := []int{}
|
||||
totalCountMap := []int{}
|
||||
|
||||
length := len(applicationSet.Spec.Strategy.RollingSync.Steps)
|
||||
|
||||
updateCountMap := make([]int, length)
|
||||
totalCountMap := make([]int, length)
|
||||
for s := 0; s < length; s++ {
|
||||
updateCountMap = append(updateCountMap, 0)
|
||||
totalCountMap = append(totalCountMap, 0)
|
||||
}
|
||||
|
||||
// populate updateCountMap with counts of existing Pending and Progressing Applications
|
||||
for _, appStatus := range applicationSet.Status.ApplicationStatus {
|
||||
|
|
@ -1283,56 +1207,44 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress
|
|||
}
|
||||
|
||||
func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusConditions(ctx context.Context, applicationSet *argov1alpha1.ApplicationSet) []argov1alpha1.ApplicationSetCondition {
|
||||
if !isRollingSyncStrategy(applicationSet) {
|
||||
return applicationSet.Status.Conditions
|
||||
}
|
||||
|
||||
completedWaves := map[string]bool{}
|
||||
appSetProgressing := false
|
||||
for _, appStatus := range applicationSet.Status.ApplicationStatus {
|
||||
if v, ok := completedWaves[appStatus.Step]; !ok {
|
||||
completedWaves[appStatus.Step] = appStatus.Status == "Healthy"
|
||||
} else {
|
||||
completedWaves[appStatus.Step] = v && appStatus.Status == "Healthy"
|
||||
}
|
||||
}
|
||||
|
||||
isProgressing := false
|
||||
progressingStep := ""
|
||||
for i := range applicationSet.Spec.Strategy.RollingSync.Steps {
|
||||
step := strconv.Itoa(i + 1)
|
||||
isCompleted, ok := completedWaves[step]
|
||||
if !ok {
|
||||
// Step has no applications, so it is completed
|
||||
continue
|
||||
}
|
||||
if !isCompleted {
|
||||
isProgressing = true
|
||||
progressingStep = step
|
||||
if appStatus.Status != "Healthy" {
|
||||
appSetProgressing = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if isProgressing {
|
||||
appSetConditionProgressing := false
|
||||
for _, appSetCondition := range applicationSet.Status.Conditions {
|
||||
if appSetCondition.Type == argov1alpha1.ApplicationSetConditionRolloutProgressing && appSetCondition.Status == argov1alpha1.ApplicationSetConditionStatusTrue {
|
||||
appSetConditionProgressing = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if appSetProgressing && !appSetConditionProgressing {
|
||||
_ = r.setApplicationSetStatusCondition(ctx,
|
||||
applicationSet,
|
||||
argov1alpha1.ApplicationSetCondition{
|
||||
Type: argov1alpha1.ApplicationSetConditionRolloutProgressing,
|
||||
Message: "ApplicationSet is performing rollout of step " + progressingStep,
|
||||
Message: "ApplicationSet Rollout Rollout started",
|
||||
Reason: argov1alpha1.ApplicationSetReasonApplicationSetModified,
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
|
||||
}, true,
|
||||
)
|
||||
} else {
|
||||
} else if !appSetProgressing && appSetConditionProgressing {
|
||||
_ = r.setApplicationSetStatusCondition(ctx,
|
||||
applicationSet,
|
||||
argov1alpha1.ApplicationSetCondition{
|
||||
Type: argov1alpha1.ApplicationSetConditionRolloutProgressing,
|
||||
Message: "ApplicationSet Rollout has completed",
|
||||
Message: "ApplicationSet Rollout Rollout complete",
|
||||
Reason: argov1alpha1.ApplicationSetReasonApplicationSetRolloutComplete,
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusFalse,
|
||||
}, true,
|
||||
)
|
||||
}
|
||||
|
||||
return applicationSet.Status.Conditions
|
||||
}
|
||||
|
||||
|
|
@ -1451,17 +1363,17 @@ func (r *ApplicationSetReconciler) setAppSetApplicationStatus(ctx context.Contex
|
|||
}
|
||||
|
||||
if needToUpdateStatus {
|
||||
// sort to make sure the array is always in the same order
|
||||
applicationSet.Status.ApplicationStatus = make([]argov1alpha1.ApplicationSetApplicationStatus, len(applicationStatuses))
|
||||
copy(applicationSet.Status.ApplicationStatus, applicationStatuses)
|
||||
sort.Slice(applicationSet.Status.ApplicationStatus, func(i, j int) bool {
|
||||
return applicationSet.Status.ApplicationStatus[i].Application < applicationSet.Status.ApplicationStatus[j].Application
|
||||
})
|
||||
namespacedName := types.NamespacedName{Namespace: applicationSet.Namespace, Name: applicationSet.Name}
|
||||
|
||||
// rebuild ApplicationStatus from scratch, we don't need any previous status history
|
||||
applicationSet.Status.ApplicationStatus = []argov1alpha1.ApplicationSetApplicationStatus{}
|
||||
for i := range applicationStatuses {
|
||||
applicationSet.Status.SetApplicationStatus(applicationStatuses[i])
|
||||
}
|
||||
// DefaultRetry will retry 5 times with a backoff factor of 1, jitter of 0.1 and a duration of 10ms
|
||||
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
updatedAppset := &argov1alpha1.ApplicationSet{}
|
||||
if err := r.Get(ctx, types.NamespacedName{Namespace: applicationSet.Namespace, Name: applicationSet.Name}, updatedAppset); err != nil {
|
||||
if err := r.Get(ctx, namespacedName, updatedAppset); err != nil {
|
||||
if client.IgnoreNotFound(err) != nil {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1525,7 +1437,7 @@ func syncApplication(application argov1alpha1.Application, prune bool) argov1alp
|
|||
Info: []*argov1alpha1.Info{
|
||||
{
|
||||
Name: "Reason",
|
||||
Value: "ApplicationSet RollingSync triggered a sync of this Application resource",
|
||||
Value: "ApplicationSet RollingSync triggered a sync of this Application resource.",
|
||||
},
|
||||
},
|
||||
Sync: &argov1alpha1.SyncOperation{},
|
||||
|
|
@ -1696,14 +1608,10 @@ func shouldRequeueForApplicationSet(appSetOld, appSetNew *argov1alpha1.Applicati
|
|||
}
|
||||
|
||||
// Requeue if any ApplicationStatus.Status changed for Progressive sync strategy
|
||||
// Requeue if deletionTimestamp added
|
||||
if enableProgressiveSyncs {
|
||||
if !cmp.Equal(appSetOld.Status.ApplicationStatus, appSetNew.Status.ApplicationStatus, cmpopts.EquateEmpty()) {
|
||||
return true
|
||||
}
|
||||
if !cmp.Equal(appSetOld.DeletionTimestamp, appSetNew.DeletionTimestamp, cmpopts.EquateEmpty()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// only compare the applicationset spec, annotations, labels and finalizers, specifically avoiding
|
||||
|
|
|
|||
|
|
@ -1954,15 +1954,14 @@ func TestValidateGeneratedApplications(t *testing.T) {
|
|||
for _, cc := range []struct {
|
||||
name string
|
||||
apps []v1alpha1.Application
|
||||
validationErrors map[string]error
|
||||
validationErrors map[int]error
|
||||
}{
|
||||
{
|
||||
name: "valid app should return true",
|
||||
apps: []v1alpha1.Application{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app",
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "default",
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
|
|
@ -1977,15 +1976,14 @@ func TestValidateGeneratedApplications(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
validationErrors: map[string]error{},
|
||||
validationErrors: map[int]error{},
|
||||
},
|
||||
{
|
||||
name: "can't have both name and server defined",
|
||||
apps: []v1alpha1.Application{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app",
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "default",
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
|
|
@ -2001,15 +1999,14 @@ func TestValidateGeneratedApplications(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
validationErrors: map[string]error{"app": errors.New("application destination spec is invalid: application destination can't have both name and server defined: my-cluster my-server")},
|
||||
validationErrors: map[int]error{0: errors.New("application destination spec is invalid: application destination can't have both name and server defined: my-cluster my-server")},
|
||||
},
|
||||
{
|
||||
name: "project mismatch should return error",
|
||||
apps: []v1alpha1.Application{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app",
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "DOES-NOT-EXIST",
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
|
|
@ -2024,15 +2021,14 @@ func TestValidateGeneratedApplications(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
validationErrors: map[string]error{"app": errors.New("application references project DOES-NOT-EXIST which does not exist")},
|
||||
validationErrors: map[int]error{0: errors.New("application references project DOES-NOT-EXIST which does not exist")},
|
||||
},
|
||||
{
|
||||
name: "valid app should return true",
|
||||
apps: []v1alpha1.Application{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app",
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "default",
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
|
|
@ -2047,15 +2043,14 @@ func TestValidateGeneratedApplications(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
validationErrors: map[string]error{},
|
||||
validationErrors: map[int]error{},
|
||||
},
|
||||
{
|
||||
name: "cluster should match",
|
||||
apps: []v1alpha1.Application{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app",
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "default",
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
|
|
@ -2070,7 +2065,7 @@ func TestValidateGeneratedApplications(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
validationErrors: map[string]error{"app": errors.New("application destination spec is invalid: there are no clusters with this name: nonexistent-cluster")},
|
||||
validationErrors: map[int]error{0: errors.New("application destination spec is invalid: there are no clusters with this name: nonexistent-cluster")},
|
||||
},
|
||||
} {
|
||||
t.Run(cc.name, func(t *testing.T) {
|
||||
|
|
@ -2203,20 +2198,13 @@ func TestSetApplicationSetStatusCondition(t *testing.T) {
|
|||
scheme := runtime.NewScheme()
|
||||
err := v1alpha1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
kubeclientset := kubefake.NewSimpleClientset([]runtime.Object{}...)
|
||||
someTime := &metav1.Time{Time: time.Now().Add(-5 * time.Minute)}
|
||||
existingParameterGeneratedCondition := getParametersGeneratedCondition(true, "")
|
||||
existingParameterGeneratedCondition.LastTransitionTime = someTime
|
||||
|
||||
for _, c := range []struct {
|
||||
name string
|
||||
appset v1alpha1.ApplicationSet
|
||||
condition v1alpha1.ApplicationSetCondition
|
||||
parametersGenerated bool
|
||||
testfunc func(t *testing.T, conditions []v1alpha1.ApplicationSetCondition)
|
||||
testCases := []struct {
|
||||
appset v1alpha1.ApplicationSet
|
||||
conditions []v1alpha1.ApplicationSetCondition
|
||||
testfunc func(t *testing.T, appset v1alpha1.ApplicationSet)
|
||||
}{
|
||||
{
|
||||
name: "has parameters generated condition when false",
|
||||
appset: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
|
|
@ -2233,28 +2221,20 @@ func TestSetApplicationSetStatusCondition(t *testing.T) {
|
|||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
},
|
||||
condition: v1alpha1.ApplicationSetCondition{
|
||||
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: "This is a message",
|
||||
Reason: "test",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusFalse,
|
||||
conditions: []v1alpha1.ApplicationSetCondition{
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: "All applications have been generated successfully",
|
||||
Reason: v1alpha1.ApplicationSetReasonApplicationSetUpToDate,
|
||||
Status: v1alpha1.ApplicationSetConditionStatusTrue,
|
||||
},
|
||||
},
|
||||
parametersGenerated: false,
|
||||
testfunc: func(t *testing.T, conditions []v1alpha1.ApplicationSetCondition) {
|
||||
testfunc: func(t *testing.T, appset v1alpha1.ApplicationSet) {
|
||||
t.Helper()
|
||||
require.Len(t, conditions, 2)
|
||||
|
||||
// Conditions are ordered by type, so the order is deterministic
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionParametersGenerated, conditions[0].Type)
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionStatusFalse, conditions[0].Status)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionResourcesUpToDate, conditions[1].Type)
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionStatusFalse, conditions[1].Status)
|
||||
assert.Equal(t, "test", conditions[1].Reason)
|
||||
assert.Len(t, appset.Status.Conditions, 3)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "parameters generated condition is used when specified",
|
||||
appset: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
|
|
@ -2271,268 +2251,37 @@ func TestSetApplicationSetStatusCondition(t *testing.T) {
|
|||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
},
|
||||
condition: v1alpha1.ApplicationSetCondition{
|
||||
Type: v1alpha1.ApplicationSetConditionParametersGenerated,
|
||||
Message: "This is a message",
|
||||
Reason: "test",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusFalse,
|
||||
conditions: []v1alpha1.ApplicationSetCondition{
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: "All applications have been generated successfully",
|
||||
Reason: v1alpha1.ApplicationSetReasonApplicationSetUpToDate,
|
||||
Status: v1alpha1.ApplicationSetConditionStatusTrue,
|
||||
},
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionRolloutProgressing,
|
||||
Message: "ApplicationSet Rollout Rollout started",
|
||||
Reason: v1alpha1.ApplicationSetReasonApplicationSetUpToDate,
|
||||
Status: v1alpha1.ApplicationSetConditionStatusTrue,
|
||||
},
|
||||
},
|
||||
parametersGenerated: true,
|
||||
testfunc: func(t *testing.T, conditions []v1alpha1.ApplicationSetCondition) {
|
||||
testfunc: func(t *testing.T, appset v1alpha1.ApplicationSet) {
|
||||
t.Helper()
|
||||
require.Len(t, conditions, 1)
|
||||
assert.Len(t, appset.Status.Conditions, 3)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionParametersGenerated, conditions[0].Type)
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionStatusFalse, conditions[0].Status)
|
||||
assert.Equal(t, "test", conditions[0].Reason)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "has parameter conditions when true",
|
||||
appset: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{
|
||||
{List: &v1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{{
|
||||
Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`),
|
||||
}},
|
||||
}},
|
||||
},
|
||||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
},
|
||||
condition: v1alpha1.ApplicationSetCondition{
|
||||
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: "This is a message",
|
||||
Reason: "test",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusFalse,
|
||||
},
|
||||
parametersGenerated: true,
|
||||
testfunc: func(t *testing.T, conditions []v1alpha1.ApplicationSetCondition) {
|
||||
t.Helper()
|
||||
require.Len(t, conditions, 2)
|
||||
isProgressingCondition := false
|
||||
|
||||
// Conditions are ordered by type, so the order is deterministic
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionParametersGenerated, conditions[0].Type)
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionStatusTrue, conditions[0].Status)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionResourcesUpToDate, conditions[1].Type)
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionStatusFalse, conditions[1].Status)
|
||||
assert.Equal(t, "test", conditions[1].Reason)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "resource up to date sets error condition to false",
|
||||
appset: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{
|
||||
{List: &v1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{{
|
||||
Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`),
|
||||
}},
|
||||
}},
|
||||
},
|
||||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
},
|
||||
condition: v1alpha1.ApplicationSetCondition{
|
||||
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: "Completed",
|
||||
Reason: "test",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusTrue,
|
||||
},
|
||||
testfunc: func(t *testing.T, conditions []v1alpha1.ApplicationSetCondition) {
|
||||
t.Helper()
|
||||
require.Len(t, conditions, 3)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionErrorOccurred, conditions[0].Type)
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionStatusFalse, conditions[0].Status)
|
||||
assert.Equal(t, "test", conditions[0].Reason)
|
||||
assert.Equal(t, "Completed", conditions[0].Message)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionParametersGenerated, conditions[1].Type)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionResourcesUpToDate, conditions[2].Type)
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionStatusTrue, conditions[2].Status)
|
||||
assert.Equal(t, "test", conditions[2].Reason)
|
||||
assert.Equal(t, "Completed", conditions[2].Message)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "error condition sets resource up to date to false",
|
||||
appset: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{
|
||||
{List: &v1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{{
|
||||
Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`),
|
||||
}},
|
||||
}},
|
||||
},
|
||||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
},
|
||||
condition: v1alpha1.ApplicationSetCondition{
|
||||
Type: v1alpha1.ApplicationSetConditionErrorOccurred,
|
||||
Message: "Error",
|
||||
Reason: "test",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusTrue,
|
||||
},
|
||||
testfunc: func(t *testing.T, conditions []v1alpha1.ApplicationSetCondition) {
|
||||
t.Helper()
|
||||
require.Len(t, conditions, 3)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionErrorOccurred, conditions[0].Type)
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionStatusTrue, conditions[0].Status)
|
||||
assert.Equal(t, "test", conditions[0].Reason)
|
||||
assert.Equal(t, "Error", conditions[0].Message)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionParametersGenerated, conditions[1].Type)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionResourcesUpToDate, conditions[2].Type)
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionStatusFalse, conditions[2].Status)
|
||||
assert.Equal(t, v1alpha1.ApplicationSetReasonErrorOccurred, conditions[2].Reason)
|
||||
assert.Equal(t, "Error", conditions[2].Message)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "updating an unchanged condition does not mutate existing conditions",
|
||||
appset: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{
|
||||
{List: &v1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{{
|
||||
Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`),
|
||||
}},
|
||||
}},
|
||||
},
|
||||
Strategy: &v1alpha1.ApplicationSetStrategy{
|
||||
Type: "RollingSync",
|
||||
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{},
|
||||
},
|
||||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
Status: v1alpha1.ApplicationSetStatus{
|
||||
Conditions: []v1alpha1.ApplicationSetCondition{
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionErrorOccurred,
|
||||
Message: "existing",
|
||||
LastTransitionTime: someTime,
|
||||
},
|
||||
existingParameterGeneratedCondition,
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: "existing",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusFalse,
|
||||
LastTransitionTime: someTime,
|
||||
},
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionRolloutProgressing,
|
||||
Message: "existing",
|
||||
LastTransitionTime: someTime,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
condition: v1alpha1.ApplicationSetCondition{
|
||||
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: "existing",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusFalse,
|
||||
},
|
||||
parametersGenerated: true,
|
||||
testfunc: func(t *testing.T, conditions []v1alpha1.ApplicationSetCondition) {
|
||||
t.Helper()
|
||||
require.Len(t, conditions, 4)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionErrorOccurred, conditions[0].Type)
|
||||
assert.Equal(t, someTime, conditions[0].LastTransitionTime)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionParametersGenerated, conditions[1].Type)
|
||||
assert.Equal(t, someTime, conditions[1].LastTransitionTime)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionResourcesUpToDate, conditions[2].Type)
|
||||
assert.Equal(t, someTime, conditions[2].LastTransitionTime)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionRolloutProgressing, conditions[3].Type)
|
||||
assert.Equal(t, someTime, conditions[3].LastTransitionTime)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "progressing conditions is removed when AppSet is not configured",
|
||||
appset: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{
|
||||
{List: &v1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{{
|
||||
Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`),
|
||||
}},
|
||||
}},
|
||||
},
|
||||
// Strategy removed
|
||||
// Strategy: &v1alpha1.ApplicationSetStrategy{
|
||||
// Type: "RollingSync",
|
||||
// RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{},
|
||||
// },
|
||||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
Status: v1alpha1.ApplicationSetStatus{
|
||||
Conditions: []v1alpha1.ApplicationSetCondition{
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionErrorOccurred,
|
||||
Message: "existing",
|
||||
LastTransitionTime: someTime,
|
||||
},
|
||||
existingParameterGeneratedCondition,
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: "existing",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusFalse,
|
||||
LastTransitionTime: someTime,
|
||||
},
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionRolloutProgressing,
|
||||
Message: "existing",
|
||||
LastTransitionTime: someTime,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
condition: v1alpha1.ApplicationSetCondition{
|
||||
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: "existing",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusFalse,
|
||||
},
|
||||
parametersGenerated: true,
|
||||
testfunc: func(t *testing.T, conditions []v1alpha1.ApplicationSetCondition) {
|
||||
t.Helper()
|
||||
require.Len(t, conditions, 3)
|
||||
for _, c := range conditions {
|
||||
assert.NotEqual(t, v1alpha1.ApplicationSetConditionRolloutProgressing, c.Type)
|
||||
for _, condition := range appset.Status.Conditions {
|
||||
if condition.Type == v1alpha1.ApplicationSetConditionRolloutProgressing {
|
||||
isProgressingCondition = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
assert.False(t, isProgressingCondition, "no RolloutProgressing should be set for applicationsets that don't have rolling strategy")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "progressing conditions is ignored when AppSet is not configured",
|
||||
appset: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
|
|
@ -2546,126 +2295,84 @@ func TestSetApplicationSetStatusCondition(t *testing.T) {
|
|||
}},
|
||||
}},
|
||||
},
|
||||
// Strategy removed
|
||||
// Strategy: &v1alpha1.ApplicationSetStrategy{
|
||||
// Type: "RollingSync",
|
||||
// RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{},
|
||||
// },
|
||||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
Status: v1alpha1.ApplicationSetStatus{
|
||||
Conditions: []v1alpha1.ApplicationSetCondition{
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionErrorOccurred,
|
||||
Message: "existing",
|
||||
LastTransitionTime: someTime,
|
||||
},
|
||||
existingParameterGeneratedCondition,
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: "existing",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusFalse,
|
||||
LastTransitionTime: someTime,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
condition: v1alpha1.ApplicationSetCondition{
|
||||
Type: v1alpha1.ApplicationSetConditionRolloutProgressing,
|
||||
Message: "do not add me",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusTrue,
|
||||
},
|
||||
parametersGenerated: true,
|
||||
testfunc: func(t *testing.T, conditions []v1alpha1.ApplicationSetCondition) {
|
||||
t.Helper()
|
||||
require.Len(t, conditions, 3)
|
||||
for _, c := range conditions {
|
||||
assert.NotEqual(t, v1alpha1.ApplicationSetConditionRolloutProgressing, c.Type)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "progressing conditions is updated correctly when configured",
|
||||
appset: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{
|
||||
{List: &v1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{{
|
||||
Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`),
|
||||
}},
|
||||
}},
|
||||
},
|
||||
Strategy: &v1alpha1.ApplicationSetStrategy{
|
||||
Type: "RollingSync",
|
||||
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{},
|
||||
},
|
||||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
Status: v1alpha1.ApplicationSetStatus{
|
||||
Conditions: []v1alpha1.ApplicationSetCondition{
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionErrorOccurred,
|
||||
Message: "existing",
|
||||
LastTransitionTime: someTime,
|
||||
},
|
||||
existingParameterGeneratedCondition,
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: "existing",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusFalse,
|
||||
LastTransitionTime: someTime,
|
||||
},
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionRolloutProgressing,
|
||||
Message: "old value",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusTrue,
|
||||
Type: "RollingSync",
|
||||
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{
|
||||
Steps: []v1alpha1.ApplicationSetRolloutStep{
|
||||
{
|
||||
MatchExpressions: []v1alpha1.ApplicationMatchExpression{
|
||||
{
|
||||
Key: "test",
|
||||
Operator: "In",
|
||||
Values: []string{"test"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
condition: v1alpha1.ApplicationSetCondition{
|
||||
Type: v1alpha1.ApplicationSetConditionRolloutProgressing,
|
||||
Message: "new value",
|
||||
Status: v1alpha1.ApplicationSetConditionStatusFalse,
|
||||
conditions: []v1alpha1.ApplicationSetCondition{
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Message: "All applications have been generated successfully",
|
||||
Reason: v1alpha1.ApplicationSetReasonApplicationSetUpToDate,
|
||||
Status: v1alpha1.ApplicationSetConditionStatusTrue,
|
||||
},
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionRolloutProgressing,
|
||||
Message: "ApplicationSet Rollout Rollout started",
|
||||
Reason: v1alpha1.ApplicationSetReasonApplicationSetUpToDate,
|
||||
Status: v1alpha1.ApplicationSetConditionStatusTrue,
|
||||
},
|
||||
},
|
||||
parametersGenerated: true,
|
||||
testfunc: func(t *testing.T, conditions []v1alpha1.ApplicationSetCondition) {
|
||||
testfunc: func(t *testing.T, appset v1alpha1.ApplicationSet) {
|
||||
t.Helper()
|
||||
require.Len(t, conditions, 4)
|
||||
assert.Len(t, appset.Status.Conditions, 4)
|
||||
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionRolloutProgressing, conditions[3].Type)
|
||||
assert.Equal(t, v1alpha1.ApplicationSetConditionStatusFalse, conditions[3].Status)
|
||||
assert.Equal(t, "new value", conditions[3].Message)
|
||||
isProgressingCondition := false
|
||||
|
||||
for _, condition := range appset.Status.Conditions {
|
||||
if condition.Type == v1alpha1.ApplicationSetConditionRolloutProgressing {
|
||||
isProgressingCondition = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
assert.True(t, isProgressingCondition, "RolloutProgressing should be set for rollout strategy appset")
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&c.appset).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).WithStatusSubresource(&c.appset).Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
}
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
Scheme: scheme,
|
||||
Renderer: &utils.Render{},
|
||||
Recorder: record.NewFakeRecorder(1),
|
||||
Generators: map[string]generators.Generator{
|
||||
"List": generators.NewListGenerator(),
|
||||
},
|
||||
ArgoDB: argodb,
|
||||
KubeClientset: kubeclientset,
|
||||
Metrics: metrics,
|
||||
}
|
||||
kubeclientset := kubefake.NewSimpleClientset([]runtime.Object{}...)
|
||||
|
||||
err = r.setApplicationSetStatusCondition(t.Context(), &c.appset, c.condition, c.parametersGenerated)
|
||||
for _, testCase := range testCases {
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&testCase.appset).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).WithStatusSubresource(&testCase.appset).Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
Scheme: scheme,
|
||||
Renderer: &utils.Render{},
|
||||
Recorder: record.NewFakeRecorder(1),
|
||||
Generators: map[string]generators.Generator{
|
||||
"List": generators.NewListGenerator(),
|
||||
},
|
||||
ArgoDB: argodb,
|
||||
KubeClientset: kubeclientset,
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
for _, condition := range testCase.conditions {
|
||||
err = r.setApplicationSetStatusCondition(t.Context(), &testCase.appset, condition, true)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
c.testfunc(t, c.appset.Status.Conditions)
|
||||
})
|
||||
testCase.testfunc(t, testCase.appset)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7106,28 +6813,6 @@ func TestApplicationSetOwnsHandlerUpdate(t *testing.T) {
|
|||
enableProgressiveSyncs: false,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "deletionTimestamp present when progressive sync enabled",
|
||||
appSetOld: buildAppSet(map[string]string{}),
|
||||
appSetNew: &v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
DeletionTimestamp: &metav1.Time{Time: time.Now()},
|
||||
},
|
||||
},
|
||||
enableProgressiveSyncs: true,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "deletionTimestamp present when progressive sync disabled",
|
||||
appSetOld: buildAppSet(map[string]string{}),
|
||||
appSetNew: &v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
DeletionTimestamp: &metav1.Time{Time: time.Now()},
|
||||
},
|
||||
},
|
||||
enableProgressiveSyncs: false,
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
@ -7449,7 +7134,7 @@ func TestSyncApplication(t *testing.T) {
|
|||
Info: []*v1alpha1.Info{
|
||||
{
|
||||
Name: "Reason",
|
||||
Value: "ApplicationSet RollingSync triggered a sync of this Application resource",
|
||||
Value: "ApplicationSet RollingSync triggered a sync of this Application resource.",
|
||||
},
|
||||
},
|
||||
Sync: &v1alpha1.SyncOperation{
|
||||
|
|
@ -7491,7 +7176,7 @@ func TestSyncApplication(t *testing.T) {
|
|||
Info: []*v1alpha1.Info{
|
||||
{
|
||||
Name: "Reason",
|
||||
Value: "ApplicationSet RollingSync triggered a sync of this Application resource",
|
||||
Value: "ApplicationSet RollingSync triggered a sync of this Application resource.",
|
||||
},
|
||||
},
|
||||
Sync: &v1alpha1.SyncOperation{
|
||||
|
|
@ -7513,110 +7198,3 @@ func TestSyncApplication(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsRollingSyncDeletionReversed(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
appset *v1alpha1.ApplicationSet
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "Deletion Order on strategy is set as Reverse",
|
||||
appset: &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Strategy: &v1alpha1.ApplicationSetStrategy{
|
||||
Type: "RollingSync",
|
||||
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{
|
||||
Steps: []v1alpha1.ApplicationSetRolloutStep{
|
||||
{
|
||||
MatchExpressions: []v1alpha1.ApplicationMatchExpression{
|
||||
{
|
||||
Key: "environment",
|
||||
Operator: "In",
|
||||
Values: []string{
|
||||
"dev",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
MatchExpressions: []v1alpha1.ApplicationMatchExpression{
|
||||
{
|
||||
Key: "environment",
|
||||
Operator: "In",
|
||||
Values: []string{
|
||||
"staging",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
DeletionOrder: ReverseDeletionOrder,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Deletion Order on strategy is set as AllAtOnce",
|
||||
appset: &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Strategy: &v1alpha1.ApplicationSetStrategy{
|
||||
Type: "RollingSync",
|
||||
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{
|
||||
Steps: []v1alpha1.ApplicationSetRolloutStep{},
|
||||
},
|
||||
DeletionOrder: AllAtOnceDeletionOrder,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Deletion Order on strategy is set as Reverse but no steps in RollingSync",
|
||||
appset: &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Strategy: &v1alpha1.ApplicationSetStrategy{
|
||||
Type: "RollingSync",
|
||||
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{
|
||||
Steps: []v1alpha1.ApplicationSetRolloutStep{},
|
||||
},
|
||||
DeletionOrder: ReverseDeletionOrder,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Deletion Order on strategy is set as Reverse, but AllAtOnce is explicitly set",
|
||||
appset: &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Strategy: &v1alpha1.ApplicationSetStrategy{
|
||||
Type: "AllAtOnce",
|
||||
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{
|
||||
Steps: []v1alpha1.ApplicationSetRolloutStep{},
|
||||
},
|
||||
DeletionOrder: ReverseDeletionOrder,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Strategy is Nil",
|
||||
appset: &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Strategy: &v1alpha1.ApplicationSetStrategy{},
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := isProgressiveSyncDeletionOrderReversed(tt.appset)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,10 +79,14 @@ func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.Ap
|
|||
return nil, fmt.Errorf("error getting cluster secrets: %w", err)
|
||||
}
|
||||
|
||||
paramHolder := ¶mHolder{isFlatMode: appSetGenerator.Clusters.FlatList}
|
||||
logCtx.Debugf("Using flat mode = %t for cluster generator", paramHolder.isFlatMode)
|
||||
res := []map[string]any{}
|
||||
|
||||
secretsFound := []corev1.Secret{}
|
||||
|
||||
isFlatMode := appSetGenerator.Clusters.FlatList
|
||||
logCtx.Debugf("Using flat mode = %t for cluster generator", isFlatMode)
|
||||
clustersParams := make([]map[string]any, 0)
|
||||
|
||||
for _, cluster := range clustersFromArgoCD {
|
||||
// If there is a secret for this cluster, then it's a non-local cluster, so it will be
|
||||
// handled by the next step.
|
||||
|
|
@ -101,80 +105,72 @@ func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.Ap
|
|||
return nil, fmt.Errorf("error appending templated values for local cluster: %w", err)
|
||||
}
|
||||
|
||||
paramHolder.append(params)
|
||||
if isFlatMode {
|
||||
clustersParams = append(clustersParams, params)
|
||||
} else {
|
||||
res = append(res, params)
|
||||
}
|
||||
|
||||
logCtx.WithField("cluster", "local cluster").Info("matched local cluster")
|
||||
}
|
||||
}
|
||||
|
||||
// For each matching cluster secret (non-local clusters only)
|
||||
for _, cluster := range secretsFound {
|
||||
params := g.getClusterParameters(cluster, appSet)
|
||||
params := map[string]any{}
|
||||
|
||||
params["name"] = string(cluster.Data["name"])
|
||||
params["nameNormalized"] = utils.SanitizeName(string(cluster.Data["name"]))
|
||||
params["server"] = string(cluster.Data["server"])
|
||||
|
||||
project, ok := cluster.Data["project"]
|
||||
if ok {
|
||||
params["project"] = string(project)
|
||||
} else {
|
||||
params["project"] = ""
|
||||
}
|
||||
|
||||
if appSet.Spec.GoTemplate {
|
||||
meta := map[string]any{}
|
||||
|
||||
if len(cluster.Annotations) > 0 {
|
||||
meta["annotations"] = cluster.Annotations
|
||||
}
|
||||
if len(cluster.Labels) > 0 {
|
||||
meta["labels"] = cluster.Labels
|
||||
}
|
||||
|
||||
params["metadata"] = meta
|
||||
} else {
|
||||
for key, value := range cluster.Annotations {
|
||||
params["metadata.annotations."+key] = value
|
||||
}
|
||||
|
||||
for key, value := range cluster.Labels {
|
||||
params["metadata.labels."+key] = value
|
||||
}
|
||||
}
|
||||
|
||||
err = appendTemplatedValues(appSetGenerator.Clusters.Values, params, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error appending templated values for cluster: %w", err)
|
||||
}
|
||||
|
||||
paramHolder.append(params)
|
||||
if isFlatMode {
|
||||
clustersParams = append(clustersParams, params)
|
||||
} else {
|
||||
res = append(res, params)
|
||||
}
|
||||
|
||||
logCtx.WithField("cluster", cluster.Name).Debug("matched cluster secret")
|
||||
}
|
||||
|
||||
return paramHolder.consolidate(), nil
|
||||
}
|
||||
|
||||
type paramHolder struct {
|
||||
isFlatMode bool
|
||||
params []map[string]any
|
||||
}
|
||||
|
||||
func (p *paramHolder) append(params map[string]any) {
|
||||
p.params = append(p.params, params)
|
||||
}
|
||||
|
||||
func (p *paramHolder) consolidate() []map[string]any {
|
||||
if p.isFlatMode {
|
||||
p.params = []map[string]any{
|
||||
{"clusters": p.params},
|
||||
}
|
||||
if isFlatMode {
|
||||
res = append(res, map[string]any{
|
||||
"clusters": clustersParams,
|
||||
})
|
||||
}
|
||||
return p.params
|
||||
}
|
||||
|
||||
func (g *ClusterGenerator) getClusterParameters(cluster corev1.Secret, appSet *argoappsetv1alpha1.ApplicationSet) map[string]any {
|
||||
params := map[string]any{}
|
||||
|
||||
params["name"] = string(cluster.Data["name"])
|
||||
params["nameNormalized"] = utils.SanitizeName(string(cluster.Data["name"]))
|
||||
params["server"] = string(cluster.Data["server"])
|
||||
|
||||
project, ok := cluster.Data["project"]
|
||||
if ok {
|
||||
params["project"] = string(project)
|
||||
} else {
|
||||
params["project"] = ""
|
||||
}
|
||||
|
||||
if appSet.Spec.GoTemplate {
|
||||
meta := map[string]any{}
|
||||
|
||||
if len(cluster.Annotations) > 0 {
|
||||
meta["annotations"] = cluster.Annotations
|
||||
}
|
||||
if len(cluster.Labels) > 0 {
|
||||
meta["labels"] = cluster.Labels
|
||||
}
|
||||
|
||||
params["metadata"] = meta
|
||||
} else {
|
||||
for key, value := range cluster.Annotations {
|
||||
params["metadata.annotations."+key] = value
|
||||
}
|
||||
|
||||
for key, value := range cluster.Labels {
|
||||
params["metadata.labels."+key] = value
|
||||
}
|
||||
}
|
||||
return params
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (g *ClusterGenerator) getSecretsByClusterName(log *log.Entry, appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator) (map[string]corev1.Secret, error) {
|
||||
|
|
|
|||
|
|
@ -222,18 +222,19 @@ func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1al
|
|||
func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []byte, values map[string]string, useGoTemplate bool, goTemplateOptions []string, pathParamPrefix string) ([]map[string]any, error) {
|
||||
objectsFound := []map[string]any{}
|
||||
|
||||
// First, we attempt to parse as a single object.
|
||||
// This will also succeed for empty files.
|
||||
singleObj := map[string]any{}
|
||||
err := yaml.Unmarshal(fileContent, &singleObj)
|
||||
if err == nil {
|
||||
objectsFound = append(objectsFound, singleObj)
|
||||
} else {
|
||||
// If unable to parse as an object, try to parse as an array
|
||||
err = yaml.Unmarshal(fileContent, &objectsFound)
|
||||
// First, we attempt to parse as an array
|
||||
err := yaml.Unmarshal(fileContent, &objectsFound)
|
||||
if err != nil {
|
||||
// If unable to parse as an array, attempt to parse as a single object
|
||||
singleObj := make(map[string]any)
|
||||
err = yaml.Unmarshal(fileContent, &singleObj)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse file: %w", err)
|
||||
}
|
||||
objectsFound = append(objectsFound, singleObj)
|
||||
} else if len(objectsFound) == 0 {
|
||||
// If file is valid but empty, add a default empty item
|
||||
objectsFound = append(objectsFound, map[string]any{})
|
||||
}
|
||||
|
||||
res := []map[string]any{}
|
||||
|
|
|
|||
|
|
@ -825,7 +825,7 @@ func TestGitGenerateParamsFromFiles(t *testing.T) {
|
|||
},
|
||||
repoPathsError: nil,
|
||||
expected: []map[string]any{},
|
||||
expectedError: errors.New("error generating params from git: unable to process file 'cluster-config/production/config.json': unable to parse file: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type []map[string]interface {}"),
|
||||
expectedError: errors.New("error generating params from git: unable to process file 'cluster-config/production/config.json': unable to parse file: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}"),
|
||||
},
|
||||
{
|
||||
name: "test JSON array",
|
||||
|
|
@ -982,16 +982,6 @@ cluster:
|
|||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "test empty YAML array",
|
||||
files: []v1alpha1.GitFileGeneratorItem{{Path: "**/config.yaml"}},
|
||||
repoFileContents: map[string][]byte{
|
||||
"cluster-config/production/config.yaml": []byte(`[]`),
|
||||
},
|
||||
repoPathsError: nil,
|
||||
expected: []map[string]any{},
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range cases {
|
||||
|
|
@ -2070,7 +2060,7 @@ func TestGitGenerateParamsFromFilesGoTemplate(t *testing.T) {
|
|||
},
|
||||
repoPathsError: nil,
|
||||
expected: []map[string]any{},
|
||||
expectedError: errors.New("error generating params from git: unable to process file 'cluster-config/production/config.json': unable to parse file: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type []map[string]interface {}"),
|
||||
expectedError: errors.New("error generating params from git: unable to process file 'cluster-config/production/config.json': unable to parse file: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}"),
|
||||
},
|
||||
{
|
||||
name: "test JSON array",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/gosimple/slug"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services"
|
||||
pullrequest "github.com/argoproj/argo-cd/v3/applicationset/services/pull_request"
|
||||
|
|
@ -19,6 +18,8 @@ import (
|
|||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
var _ Generator = (*PullRequestGenerator)(nil)
|
||||
|
||||
const (
|
||||
DefaultPullRequestRequeueAfter = 30 * time.Minute
|
||||
)
|
||||
|
|
@ -48,10 +49,6 @@ func (g *PullRequestGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alph
|
|||
return DefaultPullRequestRequeueAfter
|
||||
}
|
||||
|
||||
func (g *PullRequestGenerator) GetContinueOnRepoNotFoundError(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) bool {
|
||||
return appSetGenerator.PullRequest.ContinueOnRepoNotFoundError
|
||||
}
|
||||
|
||||
func (g *PullRequestGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate {
|
||||
return &appSetGenerator.PullRequest.Template
|
||||
}
|
||||
|
|
@ -72,15 +69,10 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
|||
}
|
||||
|
||||
pulls, err := pullrequest.ListPullRequests(ctx, svc, appSetGenerator.PullRequest.Filters)
|
||||
params := make([]map[string]any, 0, len(pulls))
|
||||
if err != nil {
|
||||
if pullrequest.IsRepositoryNotFoundError(err) && g.GetContinueOnRepoNotFoundError(appSetGenerator) {
|
||||
log.WithError(err).WithField("generator", g).
|
||||
Warn("Skipping params generation for this repository since it was not found.")
|
||||
return params, nil
|
||||
}
|
||||
return nil, fmt.Errorf("error listing repos: %w", err)
|
||||
}
|
||||
params := make([]map[string]any, 0, len(pulls))
|
||||
|
||||
// In order to follow the DNS label standard as defined in RFC 1123,
|
||||
// we need to limit the 'branch' to 50 to give room to append/suffix-ing it
|
||||
|
|
|
|||
|
|
@ -16,12 +16,11 @@ import (
|
|||
func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
cases := []struct {
|
||||
selectFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error)
|
||||
values map[string]string
|
||||
expected []map[string]any
|
||||
expectedErr error
|
||||
applicationSet argoprojiov1alpha1.ApplicationSet
|
||||
continueOnRepoNotFoundError bool
|
||||
selectFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error)
|
||||
values map[string]string
|
||||
expected []map[string]any
|
||||
expectedErr error
|
||||
applicationSet argoprojiov1alpha1.ApplicationSet
|
||||
}{
|
||||
{
|
||||
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
|
||||
|
|
@ -172,30 +171,6 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
|||
expected: nil,
|
||||
expectedErr: errors.New("error listing repos: fake error"),
|
||||
},
|
||||
{
|
||||
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
|
||||
return pullrequest.NewFakeService(
|
||||
ctx,
|
||||
nil,
|
||||
pullrequest.NewRepositoryNotFoundError(errors.New("repository not found")),
|
||||
)
|
||||
},
|
||||
expected: []map[string]any{},
|
||||
expectedErr: nil,
|
||||
continueOnRepoNotFoundError: true,
|
||||
},
|
||||
{
|
||||
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
|
||||
return pullrequest.NewFakeService(
|
||||
ctx,
|
||||
nil,
|
||||
pullrequest.NewRepositoryNotFoundError(errors.New("repository not found")),
|
||||
)
|
||||
},
|
||||
expected: nil,
|
||||
expectedErr: errors.New("error listing repos: repository not found"),
|
||||
continueOnRepoNotFoundError: false,
|
||||
},
|
||||
{
|
||||
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
|
||||
return pullrequest.NewFakeService(
|
||||
|
|
@ -285,8 +260,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
|||
}
|
||||
generatorConfig := argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
PullRequest: &argoprojiov1alpha1.PullRequestGenerator{
|
||||
Values: c.values,
|
||||
ContinueOnRepoNotFoundError: c.continueOnRepoNotFoundError,
|
||||
Values: c.values,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,10 +10,7 @@ import (
|
|||
"github.com/microsoft/azure-devops-go-api/azuredevops/v7/git"
|
||||
)
|
||||
|
||||
const (
|
||||
AZURE_DEVOPS_DEFAULT_URL = "https://dev.azure.com"
|
||||
AZURE_DEVOPS_PROJECT_NOT_FOUND_ERROR = "The following project does not exist"
|
||||
)
|
||||
const AZURE_DEVOPS_DEFAULT_URL = "https://dev.azure.com"
|
||||
|
||||
type AzureDevOpsClientFactory interface {
|
||||
// Returns an Azure Devops Client interface.
|
||||
|
|
@ -73,22 +70,13 @@ func (a *AzureDevOpsService) List(ctx context.Context) ([]*PullRequest, error) {
|
|||
SearchCriteria: &git.GitPullRequestSearchCriteria{},
|
||||
}
|
||||
|
||||
pullRequests := []*PullRequest{}
|
||||
|
||||
azurePullRequests, err := client.GetPullRequestsByProject(ctx, args)
|
||||
if err != nil {
|
||||
// A standard Http 404 error is not returned for Azure DevOps,
|
||||
// so checking the error message for a specific pattern.
|
||||
// NOTE: Since the repos are filtered later, only existence of the project
|
||||
// is relevant for AzureDevOps
|
||||
if strings.Contains(err.Error(), AZURE_DEVOPS_PROJECT_NOT_FOUND_ERROR) {
|
||||
// return a custom error indicating that the repository is not found,
|
||||
// but also return the empty result since the decision to continue or not in this case is made by the caller
|
||||
return pullRequests, NewRepositoryNotFoundError(err)
|
||||
}
|
||||
return nil, fmt.Errorf("failed to get pull requests by project: %w", err)
|
||||
}
|
||||
|
||||
pullRequests := []*PullRequest{}
|
||||
|
||||
for _, pr := range *azurePullRequests {
|
||||
if pr.Repository == nil ||
|
||||
pr.Repository.Name == nil ||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package pull_request
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/microsoft/azure-devops-go-api/azuredevops/v7/core"
|
||||
|
|
@ -236,36 +235,3 @@ func TestBuildURL(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAzureDevOpsListReturnsRepositoryNotFoundError(t *testing.T) {
|
||||
args := git.GetPullRequestsByProjectArgs{
|
||||
Project: createStringPtr("nonexistent"),
|
||||
SearchCriteria: &git.GitPullRequestSearchCriteria{},
|
||||
}
|
||||
|
||||
pullRequestMock := []git.GitPullRequest{}
|
||||
|
||||
gitClientMock := azureMock.Client{}
|
||||
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
|
||||
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, nil)
|
||||
|
||||
// Mock the GetPullRequestsByProject to return an error containing "404"
|
||||
gitClientMock.On("GetPullRequestsByProject", t.Context(), args).Return(&pullRequestMock,
|
||||
errors.New("The following project does not exist:"))
|
||||
|
||||
provider := AzureDevOpsService{
|
||||
clientFactory: clientFactoryMock,
|
||||
project: "nonexistent",
|
||||
repo: "nonexistent",
|
||||
labels: nil,
|
||||
}
|
||||
|
||||
prs, err := provider.List(t.Context())
|
||||
|
||||
// Should return empty pull requests list
|
||||
assert.Empty(t, prs)
|
||||
|
||||
// Should return RepositoryNotFoundError
|
||||
require.Error(t, err)
|
||||
assert.True(t, IsRepositoryNotFoundError(err), "Expected RepositoryNotFoundError but got: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/ktrysmt/go-bitbucket"
|
||||
)
|
||||
|
|
@ -118,17 +117,8 @@ func (b *BitbucketCloudService) List(_ context.Context) ([]*PullRequest, error)
|
|||
RepoSlug: b.repositorySlug,
|
||||
}
|
||||
|
||||
pullRequests := []*PullRequest{}
|
||||
|
||||
response, err := b.client.Repositories.PullRequests.Gets(opts)
|
||||
if err != nil {
|
||||
// A standard Http 404 error is not returned for Bitbucket Cloud,
|
||||
// so checking the error message for a specific pattern
|
||||
if strings.Contains(err.Error(), "404 Not Found") {
|
||||
// return a custom error indicating that the repository is not found,
|
||||
// but also return the empty result since the decision to continue or not in this case is made by the caller
|
||||
return pullRequests, NewRepositoryNotFoundError(err)
|
||||
}
|
||||
return nil, fmt.Errorf("error listing pull requests for %s/%s: %w", b.owner, b.repositorySlug, err)
|
||||
}
|
||||
|
||||
|
|
@ -152,6 +142,7 @@ func (b *BitbucketCloudService) List(_ context.Context) ([]*PullRequest, error)
|
|||
return nil, fmt.Errorf("error unmarshalling json to type '[]BitbucketCloudPullRequest': %w", err)
|
||||
}
|
||||
|
||||
pullRequests := []*PullRequest{}
|
||||
for _, pull := range pulls {
|
||||
pullRequests = append(pullRequests, &PullRequest{
|
||||
Number: pull.ID,
|
||||
|
|
|
|||
|
|
@ -492,29 +492,3 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
|
|||
TargetBranch: "branch-200",
|
||||
}, *pullRequests[0])
|
||||
}
|
||||
|
||||
func TestBitbucketCloudListReturnsRepositoryNotFoundError(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
|
||||
path := "/repositories/nonexistent/nonexistent/pullrequests/"
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, _ *http.Request) {
|
||||
// Return 404 status to simulate repository not found
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
_, _ = w.Write([]byte(`{"message": "404 Project Not Found"}`))
|
||||
})
|
||||
|
||||
svc, err := NewBitbucketCloudServiceNoAuth(server.URL, "nonexistent", "nonexistent")
|
||||
require.NoError(t, err)
|
||||
|
||||
prs, err := svc.List(t.Context())
|
||||
|
||||
// Should return empty pull requests list
|
||||
assert.Empty(t, prs)
|
||||
|
||||
// Should return RepositoryNotFoundError
|
||||
require.Error(t, err)
|
||||
assert.True(t, IsRepositoryNotFoundError(err), "Expected RepositoryNotFoundError but got: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,11 +72,6 @@ func (b *BitbucketService) List(_ context.Context) ([]*PullRequest, error) {
|
|||
for {
|
||||
response, err := b.client.DefaultApi.GetPullRequestsPage(b.projectKey, b.repositorySlug, paged)
|
||||
if err != nil {
|
||||
if response != nil && response.Response != nil && response.StatusCode == http.StatusNotFound {
|
||||
// return a custom error indicating that the repository is not found,
|
||||
// but also return the empty result since the decision to continue or not in this case is made by the caller
|
||||
return pullRequests, NewRepositoryNotFoundError(err)
|
||||
}
|
||||
return nil, fmt.Errorf("error listing pull requests for %s/%s: %w", b.projectKey, b.repositorySlug, err)
|
||||
}
|
||||
pulls, err := bitbucketv1.GetPullRequestsResponse(response)
|
||||
|
|
|
|||
|
|
@ -510,29 +510,3 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
|||
})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestBitbucketServerListReturnsRepositoryNotFoundError(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
|
||||
path := "/rest/api/1.0/projects/nonexistent/repos/nonexistent/pull-requests?limit=100"
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, _ *http.Request) {
|
||||
// Return 404 status to simulate repository not found
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
_, _ = w.Write([]byte(`{"message": "404 Project Not Found"}`))
|
||||
})
|
||||
|
||||
svc, err := NewBitbucketServiceNoAuth(t.Context(), server.URL, "nonexistent", "nonexistent", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
prs, err := svc.List(t.Context())
|
||||
|
||||
// Should return empty pull requests list
|
||||
assert.Empty(t, prs)
|
||||
|
||||
// Should return RepositoryNotFoundError
|
||||
require.Error(t, err)
|
||||
assert.True(t, IsRepositoryNotFoundError(err), "Expected RepositoryNotFoundError but got: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
package pull_request
|
||||
|
||||
import "errors"
|
||||
|
||||
// RepositoryNotFoundError represents an error when a repository is not found by a pull request provider
|
||||
type RepositoryNotFoundError struct {
|
||||
causingError error
|
||||
}
|
||||
|
||||
func (e *RepositoryNotFoundError) Error() string {
|
||||
return e.causingError.Error()
|
||||
}
|
||||
|
||||
// NewRepositoryNotFoundError creates a new repository not found error
|
||||
func NewRepositoryNotFoundError(err error) error {
|
||||
return &RepositoryNotFoundError{causingError: err}
|
||||
}
|
||||
|
||||
// IsRepositoryNotFoundError checks if the given error is a repository not found error
|
||||
func IsRepositoryNotFoundError(err error) bool {
|
||||
var repoErr *RepositoryNotFoundError
|
||||
return errors.As(err, &repoErr)
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
package pull_request
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRepositoryNotFoundError(t *testing.T) {
|
||||
t.Run("NewRepositoryNotFoundError creates correct error type", func(t *testing.T) {
|
||||
originalErr := errors.New("repository does not exist")
|
||||
repoNotFoundErr := NewRepositoryNotFoundError(originalErr)
|
||||
|
||||
require.Error(t, repoNotFoundErr)
|
||||
assert.Equal(t, "repository does not exist", repoNotFoundErr.Error())
|
||||
})
|
||||
|
||||
t.Run("IsRepositoryNotFoundError identifies RepositoryNotFoundError", func(t *testing.T) {
|
||||
originalErr := errors.New("repository does not exist")
|
||||
repoNotFoundErr := NewRepositoryNotFoundError(originalErr)
|
||||
|
||||
assert.True(t, IsRepositoryNotFoundError(repoNotFoundErr))
|
||||
})
|
||||
|
||||
t.Run("IsRepositoryNotFoundError returns false for regular errors", func(t *testing.T) {
|
||||
regularErr := errors.New("some other error")
|
||||
|
||||
assert.False(t, IsRepositoryNotFoundError(regularErr))
|
||||
})
|
||||
|
||||
t.Run("IsRepositoryNotFoundError returns false for nil error", func(t *testing.T) {
|
||||
assert.False(t, IsRepositoryNotFoundError(nil))
|
||||
})
|
||||
|
||||
t.Run("IsRepositoryNotFoundError works with wrapped errors", func(t *testing.T) {
|
||||
originalErr := errors.New("repository does not exist")
|
||||
repoNotFoundErr := NewRepositoryNotFoundError(originalErr)
|
||||
wrappedErr := errors.New("wrapped: " + repoNotFoundErr.Error())
|
||||
|
||||
// Direct RepositoryNotFoundError should be identified
|
||||
assert.True(t, IsRepositoryNotFoundError(repoNotFoundErr))
|
||||
|
||||
// Wrapped string error should not be identified (this is expected behavior)
|
||||
assert.False(t, IsRepositoryNotFoundError(wrappedErr))
|
||||
})
|
||||
}
|
||||
|
|
@ -52,17 +52,11 @@ func (g *GiteaService) List(ctx context.Context) ([]*PullRequest, error) {
|
|||
State: gitea.StateOpen,
|
||||
}
|
||||
g.client.SetContext(ctx)
|
||||
list := []*PullRequest{}
|
||||
prs, resp, err := g.client.ListRepoPullRequests(g.owner, g.repo, opts)
|
||||
prs, _, err := g.client.ListRepoPullRequests(g.owner, g.repo, opts)
|
||||
if err != nil {
|
||||
if resp != nil && resp.StatusCode == http.StatusNotFound {
|
||||
// return a custom error indicating that the repository is not found,
|
||||
// but also returning the empty result since the decision to continue or not in this case is made by the caller
|
||||
return list, NewRepositoryNotFoundError(err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list := []*PullRequest{}
|
||||
for _, pr := range prs {
|
||||
if !giteaContainLabels(g.labels, pr.Labels) {
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -339,35 +339,3 @@ func TestGetGiteaPRLabelNames(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGiteaListReturnsRepositoryNotFoundError(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
|
||||
// Handle version endpoint that Gitea client calls first
|
||||
mux.HandleFunc("/api/v1/version", func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"version":"1.17.0+dev-452-g1f0541780"}`))
|
||||
})
|
||||
|
||||
path := "/api/v1/repos/nonexistent/nonexistent/pulls?limit=0&page=1&state=open"
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, _ *http.Request) {
|
||||
// Return 404 status to simulate repository not found
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
_, _ = w.Write([]byte(`{"message": "404 Project Not Found"}`))
|
||||
})
|
||||
|
||||
svc, err := NewGiteaService("", server.URL, "nonexistent", "nonexistent", []string{}, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
prs, err := svc.List(t.Context())
|
||||
|
||||
// Should return empty pull requests list
|
||||
assert.Empty(t, prs)
|
||||
|
||||
// Should return RepositoryNotFoundError
|
||||
require.Error(t, err)
|
||||
assert.True(t, IsRepositoryNotFoundError(err), "Expected RepositoryNotFoundError but got: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,11 +64,6 @@ func (g *GithubService) List(ctx context.Context) ([]*PullRequest, error) {
|
|||
for {
|
||||
pulls, resp, err := g.client.PullRequests.List(ctx, g.owner, g.repo, opts)
|
||||
if err != nil {
|
||||
if resp != nil && resp.StatusCode == http.StatusNotFound {
|
||||
// return a custom error indicating that the repository is not found,
|
||||
// but also returning the empty result since the decision to continue or not in this case is made by the caller
|
||||
return pullRequests, NewRepositoryNotFoundError(err)
|
||||
}
|
||||
return nil, fmt.Errorf("error listing pull requests for %s/%s: %w", g.owner, g.repo, err)
|
||||
}
|
||||
for _, pull := range pulls {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
package pull_request
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-github/v69/github"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
|
@ -89,29 +86,3 @@ func TestGetGitHubPRLabelNames(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitHubListReturnsRepositoryNotFoundError(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
|
||||
path := "/repos/nonexistent/nonexistent/pulls"
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, _ *http.Request) {
|
||||
// Return 404 status to simulate repository not found
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
_, _ = w.Write([]byte(`{"message": "404 Project Not Found"}`))
|
||||
})
|
||||
|
||||
svc, err := NewGithubService("", server.URL, "nonexistent", "nonexistent", []string{}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
prs, err := svc.List(t.Context())
|
||||
|
||||
// Should return empty pull requests list
|
||||
assert.Empty(t, prs)
|
||||
|
||||
// Should return RepositoryNotFoundError
|
||||
require.Error(t, err)
|
||||
assert.True(t, IsRepositoryNotFoundError(err), "Expected RepositoryNotFoundError but got: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,11 +76,6 @@ func (g *GitLabService) List(ctx context.Context) ([]*PullRequest, error) {
|
|||
for {
|
||||
mrs, resp, err := g.client.MergeRequests.ListProjectMergeRequests(g.project, opts, gitlab.WithContext(ctx))
|
||||
if err != nil {
|
||||
if resp != nil && resp.StatusCode == http.StatusNotFound {
|
||||
// return a custom error indicating that the repository is not found,
|
||||
// but also returning the empty result since the decision to continue or not in this case is made by the caller
|
||||
return pullRequests, NewRepositoryNotFoundError(err)
|
||||
}
|
||||
return nil, fmt.Errorf("error listing merge requests for project '%s': %w", g.project, err)
|
||||
}
|
||||
for _, mr := range mrs {
|
||||
|
|
|
|||
|
|
@ -191,29 +191,3 @@ func TestListWithStateTLS(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitLabListReturnsRepositoryNotFoundError(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
|
||||
path := "/api/v4/projects/nonexistent/merge_requests"
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, _ *http.Request) {
|
||||
// Return 404 status to simulate repository not found
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
_, _ = w.Write([]byte(`{"message": "404 Project Not Found"}`))
|
||||
})
|
||||
|
||||
svc, err := NewGitLabService("", server.URL, "nonexistent", []string{}, "", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
prs, err := svc.List(t.Context())
|
||||
|
||||
// Should return empty pull requests list
|
||||
assert.Empty(t, prs)
|
||||
|
||||
// Should return RepositoryNotFoundError
|
||||
require.Error(t, err)
|
||||
assert.True(t, IsRepositoryNotFoundError(err), "Expected RepositoryNotFoundError but got: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,5 +30,4 @@ type PullRequestService interface {
|
|||
type Filter struct {
|
||||
BranchMatch *regexp.Regexp
|
||||
TargetBranchMatch *regexp.Regexp
|
||||
TitleMatch *regexp.Regexp
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,12 +25,6 @@ func compileFilters(filters []argoprojiov1alpha1.PullRequestGeneratorFilter) ([]
|
|||
return nil, fmt.Errorf("error compiling TargetBranchMatch regexp %q: %w", *filter.TargetBranchMatch, err)
|
||||
}
|
||||
}
|
||||
if filter.TitleMatch != nil {
|
||||
outFilter.TitleMatch, err = regexp.Compile(*filter.TitleMatch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error compiling TitleMatch regexp %q: %w", *filter.TitleMatch, err)
|
||||
}
|
||||
}
|
||||
outFilters = append(outFilters, outFilter)
|
||||
}
|
||||
return outFilters, nil
|
||||
|
|
@ -43,9 +37,6 @@ func matchFilter(pullRequest *PullRequest, filter *Filter) bool {
|
|||
if filter.TargetBranchMatch != nil && !filter.TargetBranchMatch.MatchString(pullRequest.TargetBranch) {
|
||||
return false
|
||||
}
|
||||
if filter.TitleMatch != nil && !filter.TitleMatch.MatchString(pullRequest.Title) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,110 +137,6 @@ func TestFilterTargetBranchMatch(t *testing.T) {
|
|||
assert.Equal(t, "two", pullRequests[0].Branch)
|
||||
}
|
||||
|
||||
func TestFilterTitleMatch(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
t.Context(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
Title: "PR one - filter",
|
||||
Branch: "one",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name1",
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Title: "PR two - ignore",
|
||||
Branch: "two",
|
||||
TargetBranch: "branch1",
|
||||
HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name2",
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Title: "[filter] PR three",
|
||||
Branch: "three",
|
||||
TargetBranch: "branch2",
|
||||
HeadSHA: "389d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name3",
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Title: "[ignore] PR four",
|
||||
Branch: "four",
|
||||
TargetBranch: "branch3",
|
||||
HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name4",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
)
|
||||
filters := []argoprojiov1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
TitleMatch: strp("\\[filter]"),
|
||||
},
|
||||
}
|
||||
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, "three", pullRequests[0].Branch)
|
||||
}
|
||||
|
||||
func TestMultiFilterOrWithTitle(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
t.Context(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
Title: "PR one - filter",
|
||||
Branch: "one",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name1",
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Title: "PR two - ignore",
|
||||
Branch: "two",
|
||||
TargetBranch: "branch1",
|
||||
HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name2",
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Title: "[filter] PR three",
|
||||
Branch: "three",
|
||||
TargetBranch: "branch2",
|
||||
HeadSHA: "389d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name3",
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Title: "[ignore] PR four",
|
||||
Branch: "four",
|
||||
TargetBranch: "branch3",
|
||||
HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name4",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
)
|
||||
filters := []argoprojiov1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
TitleMatch: strp("\\[filter]"),
|
||||
},
|
||||
{
|
||||
TitleMatch: strp("- filter"),
|
||||
},
|
||||
}
|
||||
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 2)
|
||||
assert.Equal(t, "one", pullRequests[0].Branch)
|
||||
assert.Equal(t, "three", pullRequests[1].Branch)
|
||||
}
|
||||
|
||||
func TestMultiFilterOr(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
t.Context(),
|
||||
|
|
@ -296,7 +192,7 @@ func TestMultiFilterOr(t *testing.T) {
|
|||
assert.Equal(t, "four", pullRequests[2].Branch)
|
||||
}
|
||||
|
||||
func TestMultiFilterOrWithTargetBranchFilterOrWithTitleFilter(t *testing.T) {
|
||||
func TestMultiFilterOrWithTargetBranchFilter(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
t.Context(),
|
||||
[]*PullRequest{
|
||||
|
|
@ -332,14 +228,6 @@ func TestMultiFilterOrWithTargetBranchFilterOrWithTitleFilter(t *testing.T) {
|
|||
HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name4",
|
||||
},
|
||||
{
|
||||
Number: 5,
|
||||
Title: "PR title is different than branch name",
|
||||
Branch: "five",
|
||||
TargetBranch: "branch3",
|
||||
HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name5",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
)
|
||||
|
|
@ -352,21 +240,12 @@ func TestMultiFilterOrWithTargetBranchFilterOrWithTitleFilter(t *testing.T) {
|
|||
BranchMatch: strp("r"),
|
||||
TargetBranchMatch: strp("3"),
|
||||
},
|
||||
{
|
||||
TitleMatch: strp("two"),
|
||||
},
|
||||
{
|
||||
BranchMatch: strp("five"),
|
||||
TitleMatch: strp("PR title is different than branch name"),
|
||||
},
|
||||
}
|
||||
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 3)
|
||||
assert.Len(t, pullRequests, 2)
|
||||
assert.Equal(t, "two", pullRequests[0].Branch)
|
||||
assert.Equal(t, "four", pullRequests[1].Branch)
|
||||
assert.Equal(t, "five", pullRequests[2].Branch)
|
||||
assert.Equal(t, "PR title is different than branch name", pullRequests[2].Title)
|
||||
}
|
||||
|
||||
func TestNoFilters(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import (
|
|||
|
||||
var ErrDisallowedSecretAccess = fmt.Errorf("secret must have label %q=%q", common.LabelKeySecretType, common.LabelValueSecretTypeSCMCreds)
|
||||
|
||||
// GetSecretRef gets the value of the key for the specified Secret resource.
|
||||
// getSecretRef gets the value of the key for the specified Secret resource.
|
||||
func GetSecretRef(ctx context.Context, k8sClient client.Client, ref *argoprojiov1alpha1.SecretRef, namespace string, tokenRefStrictMode bool) (string, error) {
|
||||
if ref == nil {
|
||||
return "", nil
|
||||
|
|
|
|||
37
assets/swagger.json
generated
37
assets/swagger.json
generated
|
|
@ -7260,10 +7260,6 @@
|
|||
"description": "ApplicationSetStrategy configures how generated Applications are updated in sequence.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"deletionOrder": {
|
||||
"type": "string",
|
||||
"title": "DeletionOrder allows specifying the order for deleting generated apps when progressive sync is enabled.\naccepts values \"AllAtOnce\" and \"Reverse\""
|
||||
},
|
||||
"rollingSync": {
|
||||
"$ref": "#/definitions/v1alpha1ApplicationSetRolloutStrategy"
|
||||
},
|
||||
|
|
@ -8639,20 +8635,12 @@
|
|||
"title": "KustomizeOptions are options for kustomize to use when building manifests",
|
||||
"properties": {
|
||||
"binaryPath": {
|
||||
"description": "Deprecated: Use settings.Settings instead. See: settings.Settings.KustomizeVersions.\nIf this field is set, it will be used as the Kustomize binary path.\nOtherwise, Versions is used.",
|
||||
"type": "string",
|
||||
"title": "BinaryPath holds optional path to kustomize binary"
|
||||
},
|
||||
"buildOptions": {
|
||||
"type": "string",
|
||||
"title": "BuildOptions is a string of build parameters to use when calling `kustomize build`"
|
||||
},
|
||||
"versions": {
|
||||
"description": "Versions is a list of Kustomize versions and their corresponding binary paths and build options.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1alpha1KustomizeVersion"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -8716,24 +8704,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"v1alpha1KustomizeVersion": {
|
||||
"type": "object",
|
||||
"title": "KustomizeVersion holds information about additional Kustomize versions",
|
||||
"properties": {
|
||||
"buildOptions": {
|
||||
"type": "string",
|
||||
"title": "BuildOptions that are specific to a Kustomize version"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Name holds Kustomize version name"
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"title": "Path holds the corresponding binary path"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1alpha1ListGenerator": {
|
||||
"type": "object",
|
||||
"title": "ListGenerator include items info",
|
||||
|
|
@ -9055,10 +9025,6 @@
|
|||
"bitbucketServer": {
|
||||
"$ref": "#/definitions/v1alpha1PullRequestGeneratorBitbucketServer"
|
||||
},
|
||||
"continueOnRepoNotFoundError": {
|
||||
"description": "ContinueOnRepoNotFoundError is a flag to continue the ApplicationSet Pull Request generator parameters generation even if the repository is not found.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"filters": {
|
||||
"description": "Filters for which pull requests should be considered.",
|
||||
"type": "array",
|
||||
|
|
@ -9188,9 +9154,6 @@
|
|||
},
|
||||
"targetBranchMatch": {
|
||||
"type": "string"
|
||||
},
|
||||
"titleMatch": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -415,6 +415,7 @@ func reconcileApplications(
|
|||
},
|
||||
settingsMgr,
|
||||
stateCache,
|
||||
projInformer,
|
||||
server,
|
||||
cache,
|
||||
time.Second,
|
||||
|
|
@ -463,7 +464,7 @@ func reconcileApplications(
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions = append(revisions, app.Spec.GetSource().TargetRevision)
|
||||
|
||||
res, err := appStateManager.CompareAppState(&app, proj, revisions, sources, false, false, nil, false)
|
||||
res, err := appStateManager.CompareAppState(&app, proj, revisions, sources, false, false, nil, false, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error comparing app states: %w", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,24 +24,24 @@ func TestRun_SignalHandling_GracefulShutdown(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
var runErr error
|
||||
var err error
|
||||
doneCh := make(chan struct{})
|
||||
go func() {
|
||||
runErr = d.Run(t.Context(), &DashboardConfig{ClientOpts: &apiclient.ClientOptions{}})
|
||||
err = d.Run(t.Context(), &DashboardConfig{ClientOpts: &apiclient.ClientOptions{}})
|
||||
close(doneCh)
|
||||
}()
|
||||
|
||||
// Allow some time for the dashboard to register the signal handler
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
proc, procErr := os.FindProcess(os.Getpid())
|
||||
require.NoErrorf(t, procErr, "failed to find process: %v", procErr)
|
||||
sigErr := proc.Signal(syscall.SIGINT)
|
||||
require.NoErrorf(t, sigErr, "failed to send SIGINT: %v", sigErr)
|
||||
proc, err := os.FindProcess(os.Getpid())
|
||||
require.NoErrorf(t, err, "failed to find process: %v", err)
|
||||
err = proc.Signal(syscall.SIGINT)
|
||||
require.NoErrorf(t, err, "failed to send SIGINT: %v", err)
|
||||
|
||||
select {
|
||||
case <-doneCh:
|
||||
require.NoError(t, runErr)
|
||||
require.NoError(t, err)
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
t.Fatal("timeout: dashboard.Run did not exit after SIGINT")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,7 +185,8 @@ argocd login cd.argoproj.io --core`,
|
|||
command.Flags().StringVar(&password, "password", "", "The password of an account to authenticate")
|
||||
command.Flags().BoolVar(&sso, "sso", false, "Perform SSO login")
|
||||
command.Flags().IntVar(&ssoPort, "sso-port", DefaultSSOLocalPort, "Port to run local OAuth2 login application")
|
||||
command.Flags().BoolVar(&skipTestTLS, "skip-test-tls", false, "Skip testing whether the server is configured with TLS (this can help when the command hangs for no apparent reason)")
|
||||
command.Flags().
|
||||
BoolVar(&skipTestTLS, "skip-test-tls", false, "Skip testing whether the server is configured with TLS (this can help when the command hangs for no apparent reason)")
|
||||
command.Flags().BoolVar(&ssoLaunchBrowser, "sso-launch-browser", true, "Automatically launch the system default browser when performing SSO login")
|
||||
return command
|
||||
}
|
||||
|
|
|
|||
|
|
@ -330,25 +330,6 @@ func NewRepoListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
|||
command := &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List configured repositories",
|
||||
Example: `
|
||||
# List all repositories
|
||||
argocd repo list
|
||||
|
||||
# List repositories in wide format
|
||||
argocd repo list -o wide
|
||||
|
||||
# List repositories in YAML format
|
||||
argocd repo list -o yaml
|
||||
|
||||
# List repositories in JSON format
|
||||
argocd repo list -o json
|
||||
|
||||
# List urls of repositories
|
||||
argocd repo list -o url
|
||||
|
||||
# Force refresh of cached repository connection status
|
||||
argocd repo list --refresh hard
|
||||
`,
|
||||
Run: func(c *cobra.Command, _ []string) {
|
||||
ctx := c.Context()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import (
|
|||
|
||||
grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/retry"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
|
|
@ -45,10 +44,11 @@ func NewConnection(address string) (*grpc.ClientConn, error) {
|
|||
}
|
||||
unaryInterceptors := []grpc.UnaryClientInterceptor{grpc_retry.UnaryClientInterceptor(retryOpts...)}
|
||||
dialOpts := []grpc.DialOption{
|
||||
grpc.WithStreamInterceptor(grpc_util.RetryOnlyForServerStreamInterceptor(retryOpts...)),
|
||||
grpc.WithStreamInterceptor(grpc_retry.StreamClientInterceptor(retryOpts...)),
|
||||
grpc.WithChainUnaryInterceptor(unaryInterceptors...),
|
||||
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(MaxGRPCMessageSize), grpc.MaxCallSendMsgSize(MaxGRPCMessageSize)),
|
||||
grpc.WithStatsHandler(otelgrpc.NewClientHandler()),
|
||||
grpc.WithUnaryInterceptor(grpc_util.OTELUnaryClientInterceptor()),
|
||||
grpc.WithStreamInterceptor(grpc_util.OTELStreamClientInterceptor()),
|
||||
}
|
||||
|
||||
dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
|
|
|
|||
|
|
@ -49,11 +49,13 @@ func NewServer(initConstants plugin.CMPServerInitConstants) (*ArgoCDCMPServer, e
|
|||
|
||||
serverLog := log.NewEntry(log.StandardLogger())
|
||||
streamInterceptors := []grpc.StreamServerInterceptor{
|
||||
otelgrpc.StreamServerInterceptor(), //nolint:staticcheck // TODO: ignore SA1019 for depreciation: see https://github.com/argoproj/argo-cd/issues/18258
|
||||
logging.StreamServerInterceptor(grpc_util.InterceptorLogger(serverLog)),
|
||||
serverMetrics.StreamServerInterceptor(),
|
||||
recovery.StreamServerInterceptor(recovery.WithRecoveryHandler(grpc_util.LoggerRecoveryHandler(serverLog))),
|
||||
}
|
||||
unaryInterceptors := []grpc.UnaryServerInterceptor{
|
||||
otelgrpc.UnaryServerInterceptor(), //nolint:staticcheck // TODO: ignore SA1019 for depreciation: see https://github.com/argoproj/argo-cd/issues/18258
|
||||
logging.UnaryServerInterceptor(grpc_util.InterceptorLogger(serverLog)),
|
||||
serverMetrics.UnaryServerInterceptor(),
|
||||
recovery.UnaryServerInterceptor(recovery.WithRecoveryHandler(grpc_util.LoggerRecoveryHandler(serverLog))),
|
||||
|
|
@ -69,7 +71,6 @@ func NewServer(initConstants plugin.CMPServerInitConstants) (*ArgoCDCMPServer, e
|
|||
MinTime: common.GetGRPCKeepAliveEnforcementMinimum(),
|
||||
},
|
||||
),
|
||||
grpc.StatsHandler(otelgrpc.NewServerHandler()),
|
||||
}
|
||||
|
||||
return &ArgoCDCMPServer{
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/commitserver/apiclient"
|
||||
"github.com/argoproj/argo-cd/v3/common"
|
||||
appv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v3/util/git"
|
||||
"github.com/argoproj/argo-cd/v3/util/io"
|
||||
|
|
@ -25,9 +24,6 @@ import (
|
|||
|
||||
var sprigFuncMap = sprig.GenericFuncMap() // a singleton for better performance
|
||||
|
||||
const gitAttributesContents = `*/README.md linguist-generated=true
|
||||
*/hydrator.metadata linguist-generated=true`
|
||||
|
||||
func init() {
|
||||
// Avoid allowing the user to learn things about the environment.
|
||||
delete(sprigFuncMap, "env")
|
||||
|
|
@ -61,12 +57,6 @@ func WriteForPaths(root *os.Root, repoUrl, drySha string, dryCommitMetadata *app
|
|||
return fmt.Errorf("failed to write top-level hydrator metadata: %w", err)
|
||||
}
|
||||
|
||||
// Write .gitattributes
|
||||
err = writeGitAttributes(root)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write git attributes: %w", err)
|
||||
}
|
||||
|
||||
for _, p := range paths {
|
||||
hydratePath := p.Path
|
||||
if hydratePath == "." {
|
||||
|
|
@ -147,30 +137,6 @@ func writeReadme(root *os.Root, dirPath string, metadata hydratorMetadataFile) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func writeGitAttributes(root *os.Root) error {
|
||||
gitAttributesFile, err := root.Create(".gitattributes")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create git attributes file: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err = gitAttributesFile.Close()
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
common.SecurityField: common.SecurityMedium,
|
||||
common.SecurityCWEField: common.SecurityCWEMissingReleaseOfFileDescriptor,
|
||||
}).Errorf("error closing file %q: %v", gitAttributesFile.Name(), err)
|
||||
}
|
||||
}()
|
||||
|
||||
_, err = gitAttributesFile.WriteString(gitAttributesContents)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write git attributes: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeManifests writes the manifests to the manifest.yaml file, truncating the file if it exists and appending the
|
||||
// manifests in the order they are provided.
|
||||
func writeManifests(root *os.Root, dirPath string, manifests []*apiclient.HydratedManifestDetails) error {
|
||||
|
|
|
|||
|
|
@ -223,16 +223,3 @@ func TestWriteManifests(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
assert.Contains(t, string(manifestBytes), "kind")
|
||||
}
|
||||
|
||||
func TestWriteGitAttributes(t *testing.T) {
|
||||
root := tempRoot(t)
|
||||
|
||||
err := writeGitAttributes(root)
|
||||
require.NoError(t, err)
|
||||
|
||||
gitAttributesPath := filepath.Join(root.Name(), ".gitattributes")
|
||||
gitAttributesBytes, err := os.ReadFile(gitAttributesPath)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, string(gitAttributesBytes), "*/README.md linguist-generated=true")
|
||||
assert.Contains(t, string(gitAttributesBytes), "*/hydrator.metadata linguist-generated=true")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,82 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
inputGitCommit string
|
||||
inputGitTag string
|
||||
inputTreeState string
|
||||
inputVersion string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "Official release with tag and clean state",
|
||||
inputGitCommit: "abcdef123456",
|
||||
inputGitTag: "v1.2.3",
|
||||
inputTreeState: "clean",
|
||||
inputVersion: "1.2.3",
|
||||
expected: "v1.2.3",
|
||||
},
|
||||
{
|
||||
name: "Dirty state with commit",
|
||||
inputGitCommit: "deadbeefcafebabe",
|
||||
inputGitTag: "",
|
||||
inputTreeState: "dirty",
|
||||
inputVersion: "2.0.1",
|
||||
expected: "v2.0.1+deadbee.dirty",
|
||||
},
|
||||
{
|
||||
name: "Clean state with commit, no tag",
|
||||
inputGitCommit: "cafebabedeadbeef",
|
||||
inputGitTag: "",
|
||||
inputTreeState: "clean",
|
||||
inputVersion: "2.1.0",
|
||||
expected: "v2.1.0+cafebab",
|
||||
},
|
||||
{
|
||||
name: "Missing commit and tag",
|
||||
inputGitCommit: "",
|
||||
inputGitTag: "",
|
||||
inputTreeState: "clean",
|
||||
inputVersion: "3.1.0",
|
||||
expected: "v3.1.0+unknown",
|
||||
},
|
||||
{
|
||||
name: "Short commit",
|
||||
inputGitCommit: "abc",
|
||||
inputGitTag: "",
|
||||
inputTreeState: "clean",
|
||||
inputVersion: "4.0.0",
|
||||
expected: "v4.0.0+unknown",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
gitCommit = tt.inputGitCommit
|
||||
gitTag = tt.inputGitTag
|
||||
gitTreeState = tt.inputTreeState
|
||||
version = tt.inputVersion
|
||||
|
||||
buildDate = "2025-06-26"
|
||||
kubectlVersion = "v1.30.0"
|
||||
extraBuildInfo = "test-build"
|
||||
|
||||
got := GetVersion()
|
||||
assert.Equal(t, tt.expected, got.Version)
|
||||
assert.Equal(t, buildDate, got.BuildDate)
|
||||
assert.Equal(t, tt.inputGitCommit, got.GitCommit)
|
||||
assert.Equal(t, tt.inputGitTag, got.GitTag)
|
||||
assert.Equal(t, tt.inputTreeState, got.GitTreeState)
|
||||
assert.Equal(t, runtime.Version(), got.GoVersion)
|
||||
assert.Equal(t, runtime.Compiler, got.Compiler)
|
||||
assert.Equal(t, runtime.GOOS+"/"+runtime.GOARCH, got.Platform)
|
||||
assert.Equal(t, kubectlVersion, got.KubectlVersion)
|
||||
assert.Equal(t, extraBuildInfo, got.ExtraBuildInfo)
|
||||
}
|
||||
}
|
||||
|
|
@ -47,7 +47,6 @@ import (
|
|||
"github.com/argoproj/argo-cd/v3/common"
|
||||
statecache "github.com/argoproj/argo-cd/v3/controller/cache"
|
||||
"github.com/argoproj/argo-cd/v3/controller/hydrator"
|
||||
hydratortypes "github.com/argoproj/argo-cd/v3/controller/hydrator/types"
|
||||
"github.com/argoproj/argo-cd/v3/controller/metrics"
|
||||
"github.com/argoproj/argo-cd/v3/controller/sharding"
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application"
|
||||
|
|
@ -116,7 +115,7 @@ type ApplicationController struct {
|
|||
appOperationQueue workqueue.TypedRateLimitingInterface[string]
|
||||
projectRefreshQueue workqueue.TypedRateLimitingInterface[string]
|
||||
appHydrateQueue workqueue.TypedRateLimitingInterface[string]
|
||||
hydrationQueue workqueue.TypedRateLimitingInterface[hydratortypes.HydrationQueueKey]
|
||||
hydrationQueue workqueue.TypedRateLimitingInterface[hydrator.HydrationQueueKey]
|
||||
appInformer cache.SharedIndexInformer
|
||||
appLister applisters.ApplicationLister
|
||||
projInformer cache.SharedIndexInformer
|
||||
|
|
@ -126,7 +125,7 @@ type ApplicationController struct {
|
|||
statusHardRefreshTimeout time.Duration
|
||||
statusRefreshJitter time.Duration
|
||||
selfHealTimeout time.Duration
|
||||
selfHealBackoff *wait.Backoff
|
||||
selfHealBackOff *wait.Backoff
|
||||
selfHealBackoffCooldown time.Duration
|
||||
syncTimeout time.Duration
|
||||
db db.ArgoDB
|
||||
|
|
@ -199,7 +198,7 @@ func NewApplicationController(
|
|||
projectRefreshQueue: workqueue.NewTypedRateLimitingQueueWithConfig(ratelimiter.NewCustomAppControllerRateLimiter[string](rateLimiterConfig), workqueue.TypedRateLimitingQueueConfig[string]{Name: "project_reconciliation_queue"}),
|
||||
appComparisonTypeRefreshQueue: workqueue.NewTypedRateLimitingQueue(ratelimiter.NewCustomAppControllerRateLimiter[string](rateLimiterConfig)),
|
||||
appHydrateQueue: workqueue.NewTypedRateLimitingQueueWithConfig(ratelimiter.NewCustomAppControllerRateLimiter[string](rateLimiterConfig), workqueue.TypedRateLimitingQueueConfig[string]{Name: "app_hydration_queue"}),
|
||||
hydrationQueue: workqueue.NewTypedRateLimitingQueueWithConfig(ratelimiter.NewCustomAppControllerRateLimiter[hydratortypes.HydrationQueueKey](rateLimiterConfig), workqueue.TypedRateLimitingQueueConfig[hydratortypes.HydrationQueueKey]{Name: "manifest_hydration_queue"}),
|
||||
hydrationQueue: workqueue.NewTypedRateLimitingQueueWithConfig(ratelimiter.NewCustomAppControllerRateLimiter[hydrator.HydrationQueueKey](rateLimiterConfig), workqueue.TypedRateLimitingQueueConfig[hydrator.HydrationQueueKey]{Name: "manifest_hydration_queue"}),
|
||||
db: db,
|
||||
statusRefreshTimeout: appResyncPeriod,
|
||||
statusHardRefreshTimeout: appHardResyncPeriod,
|
||||
|
|
@ -209,7 +208,7 @@ func NewApplicationController(
|
|||
auditLogger: argo.NewAuditLogger(kubeClientset, common.ApplicationController, enableK8sEvent),
|
||||
settingsMgr: settingsMgr,
|
||||
selfHealTimeout: selfHealTimeout,
|
||||
selfHealBackoff: selfHealBackoff,
|
||||
selfHealBackOff: selfHealBackoff,
|
||||
selfHealBackoffCooldown: selfHealBackoffCooldown,
|
||||
syncTimeout: syncTimeout,
|
||||
clusterSharding: clusterSharding,
|
||||
|
|
@ -329,7 +328,7 @@ func NewApplicationController(
|
|||
}
|
||||
}
|
||||
stateCache := statecache.NewLiveStateCache(db, appInformer, ctrl.settingsMgr, ctrl.metricsServer, ctrl.handleObjectUpdated, clusterSharding, argo.NewResourceTracking())
|
||||
appStateManager := NewAppStateManager(db, applicationClientset, repoClientset, namespace, kubectl, ctrl.onKubectlRun, ctrl.settingsMgr, stateCache, ctrl.metricsServer, argoCache, ctrl.statusRefreshTimeout, argo.NewResourceTracking(), persistResourceHealth, repoErrorGracePeriod, serverSideDiff, ignoreNormalizerOpts)
|
||||
appStateManager := NewAppStateManager(db, applicationClientset, repoClientset, namespace, kubectl, ctrl.onKubectlRun, ctrl.settingsMgr, stateCache, projInformer, ctrl.metricsServer, argoCache, ctrl.statusRefreshTimeout, argo.NewResourceTracking(), persistResourceHealth, repoErrorGracePeriod, serverSideDiff, ignoreNormalizerOpts)
|
||||
ctrl.appInformer = appInformer
|
||||
ctrl.appLister = appLister
|
||||
ctrl.projInformer = projInformer
|
||||
|
|
@ -1396,12 +1395,12 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
|
|||
if isOperationInProgress(app) {
|
||||
state = app.Status.OperationState.DeepCopy()
|
||||
terminating = state.Phase == synccommon.OperationTerminating
|
||||
// Failed operation with retry strategy might have be in-progress and has completion time
|
||||
switch {
|
||||
case state.FinishedAt != nil && !terminating:
|
||||
// Failed operation with retry strategy might be in-progress and has completion time
|
||||
retryAt, err := app.Status.OperationState.Operation.Retry.NextRetryAt(state.FinishedAt.Time, state.RetryCount)
|
||||
if err != nil {
|
||||
state.Phase = synccommon.OperationError
|
||||
state.Phase = synccommon.OperationFailed
|
||||
state.Message = err.Error()
|
||||
ctrl.setOperationState(app, state)
|
||||
return
|
||||
|
|
@ -1412,11 +1411,12 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
|
|||
ctrl.requestAppRefresh(app.QualifiedName(), CompareWithLatest.Pointer(), &retryAfter)
|
||||
return
|
||||
}
|
||||
// Get rid of sync results and null out previous operation completion time
|
||||
// This will start the retry attempt
|
||||
// retrying operation. remove previous failure time in app since it is used as a trigger
|
||||
// that previous failed and operation should be retried
|
||||
state.FinishedAt = nil
|
||||
state.SyncResult = nil
|
||||
ctrl.setOperationState(app, state)
|
||||
// Get rid of sync results and null out previous operation completion time
|
||||
state.SyncResult = nil
|
||||
case ctrl.syncTimeout != time.Duration(0) && time.Now().After(state.StartedAt.Add(ctrl.syncTimeout)) && !terminating:
|
||||
state.Phase = synccommon.OperationTerminating
|
||||
state.Message = "operation is terminating due to timeout"
|
||||
|
|
@ -1426,7 +1426,7 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
|
|||
logCtx.Infof("Resuming in-progress operation. phase: %s, message: %s", state.Phase, state.Message)
|
||||
}
|
||||
} else {
|
||||
state = NewOperationState(*app.Operation)
|
||||
state = &appv1.OperationState{Phase: synccommon.OperationRunning, Operation: *app.Operation, StartedAt: metav1.Now()}
|
||||
ctrl.setOperationState(app, state)
|
||||
if ctrl.syncTimeout != time.Duration(0) {
|
||||
// Schedule a check during which the timeout would be checked.
|
||||
|
|
@ -1436,15 +1436,22 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
|
|||
}
|
||||
ts.AddCheckpoint("initial_operation_stage_ms")
|
||||
|
||||
project, err := ctrl.getAppProj(app)
|
||||
if err == nil {
|
||||
// Start or resume the sync
|
||||
ctrl.appStateManager.SyncAppState(app, project, state)
|
||||
// Call GetDestinationCluster to validate the destination cluster.
|
||||
if _, err := argo.GetDestinationCluster(context.Background(), app.Spec.Destination, ctrl.db); err != nil {
|
||||
state.Phase = synccommon.OperationFailed
|
||||
state.Message = err.Error()
|
||||
} else {
|
||||
state.Phase = synccommon.OperationError
|
||||
state.Message = fmt.Sprintf("Failed to load application project: %v", err)
|
||||
ctrl.appStateManager.SyncAppState(app, state)
|
||||
}
|
||||
ts.AddCheckpoint("validate_and_sync_app_state_ms")
|
||||
|
||||
// Check whether application is allowed to use project
|
||||
_, err := ctrl.getAppProj(app)
|
||||
ts.AddCheckpoint("get_app_proj_ms")
|
||||
if err != nil {
|
||||
state.Phase = synccommon.OperationError
|
||||
state.Message = err.Error()
|
||||
}
|
||||
ts.AddCheckpoint("sync_app_state_ms")
|
||||
|
||||
switch state.Phase {
|
||||
case synccommon.OperationRunning:
|
||||
|
|
@ -1452,6 +1459,12 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
|
|||
// to clobber the Terminated state with Running. Get the latest app state to check for this.
|
||||
freshApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace).Get(context.Background(), app.Name, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
// App may have lost permissions to use the project meanwhile.
|
||||
_, err = ctrl.getAppProj(freshApp)
|
||||
if err != nil {
|
||||
state.Phase = synccommon.OperationFailed
|
||||
state.Message = fmt.Sprintf("operation not allowed: %v", err)
|
||||
}
|
||||
if freshApp.Status.OperationState != nil && freshApp.Status.OperationState.Phase == synccommon.OperationTerminating {
|
||||
state.Phase = synccommon.OperationTerminating
|
||||
state.Message = "operation is terminating"
|
||||
|
|
@ -1465,7 +1478,7 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
|
|||
now := metav1.Now()
|
||||
state.FinishedAt = &now
|
||||
if retryAt, err := state.Operation.Retry.NextRetryAt(now.Time, state.RetryCount); err != nil {
|
||||
state.Phase = synccommon.OperationError
|
||||
state.Phase = synccommon.OperationFailed
|
||||
state.Message = fmt.Sprintf("%s (failed to retry: %v)", state.Message, err)
|
||||
} else {
|
||||
state.Phase = synccommon.OperationRunning
|
||||
|
|
@ -1747,7 +1760,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
}
|
||||
|
||||
compareResult, err := ctrl.appStateManager.CompareAppState(app, project, revisions, sources, refreshType == appv1.RefreshTypeHard, comparisonLevel == CompareWithLatestForceResolve, localManifests, hasMultipleSources)
|
||||
compareResult, err := ctrl.appStateManager.CompareAppState(app, project, revisions, sources, refreshType == appv1.RefreshTypeHard, comparisonLevel == CompareWithLatestForceResolve, localManifests, hasMultipleSources, false)
|
||||
|
||||
ts.AddCheckpoint("compare_app_state_ms")
|
||||
|
||||
|
|
@ -1773,7 +1786,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
|||
|
||||
canSync, _ := project.Spec.SyncWindows.Matches(app).CanSync(false)
|
||||
if canSync {
|
||||
syncErrCond, opDuration := ctrl.autoSync(app, compareResult.syncStatus, compareResult.resources, compareResult.revisionsMayHaveChanges)
|
||||
syncErrCond, opDuration := ctrl.autoSync(app, compareResult.syncStatus, compareResult.resources, compareResult.revisionUpdated)
|
||||
setOpDuration = opDuration
|
||||
if syncErrCond != nil {
|
||||
app.Status.SetConditions(
|
||||
|
|
@ -2068,7 +2081,7 @@ func (ctrl *ApplicationController) persistAppStatus(orig *appv1.Application, new
|
|||
}
|
||||
|
||||
// autoSync will initiate a sync operation for an application configured with automated sync
|
||||
func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *appv1.SyncStatus, resources []appv1.ResourceStatus, shouldCompareRevisions bool) (*appv1.ApplicationCondition, time.Duration) {
|
||||
func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *appv1.SyncStatus, resources []appv1.ResourceStatus, revisionUpdated bool) (*appv1.ApplicationCondition, time.Duration) {
|
||||
logCtx := log.WithFields(applog.GetAppLogFields(app))
|
||||
ts := stats.NewTimingStats()
|
||||
defer func() {
|
||||
|
|
@ -2112,66 +2125,65 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
|
|||
}
|
||||
}
|
||||
|
||||
desiredRevisions := []string{syncStatus.Revision}
|
||||
if app.Spec.HasMultipleSources() {
|
||||
desiredRevisions = syncStatus.Revisions
|
||||
selfHeal := app.Spec.SyncPolicy.Automated.SelfHeal
|
||||
// Multi-Source Apps with selfHeal disabled should not trigger an autosync if
|
||||
// the last sync revision and the new sync revision is the same.
|
||||
if app.Spec.HasMultipleSources() && !selfHeal && reflect.DeepEqual(app.Status.Sync.Revisions, syncStatus.Revisions) {
|
||||
logCtx.Infof("Skipping auto-sync: selfHeal disabled and sync caused by object update")
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
desiredCommitSHA := syncStatus.Revision
|
||||
desiredCommitSHAsMS := syncStatus.Revisions
|
||||
alreadyAttempted, attemptPhase := alreadyAttemptedSync(app, desiredCommitSHA, desiredCommitSHAsMS, app.Spec.HasMultipleSources(), revisionUpdated)
|
||||
ts.AddCheckpoint("already_attempted_sync_ms")
|
||||
op := appv1.Operation{
|
||||
Sync: &appv1.SyncOperation{
|
||||
Revision: syncStatus.Revision,
|
||||
Revision: desiredCommitSHA,
|
||||
Prune: app.Spec.SyncPolicy.Automated.Prune,
|
||||
SyncOptions: app.Spec.SyncPolicy.SyncOptions,
|
||||
Revisions: syncStatus.Revisions,
|
||||
Revisions: desiredCommitSHAsMS,
|
||||
},
|
||||
InitiatedBy: appv1.OperationInitiator{Automated: true},
|
||||
Retry: appv1.RetryStrategy{Limit: 5},
|
||||
}
|
||||
|
||||
if app.Spec.SyncPolicy.Retry != nil {
|
||||
op.Retry = *app.Spec.SyncPolicy.Retry
|
||||
}
|
||||
|
||||
// It is possible for manifests to remain OutOfSync even after a sync/kubectl apply (e.g.
|
||||
// auto-sync with pruning disabled). We need to ensure that we do not keep Syncing an
|
||||
// application in an infinite loop. To detect this, we only attempt the Sync if the revision
|
||||
// and parameter overrides are different from our most recent sync operation.
|
||||
alreadyAttempted, lastAttemptedRevisions, lastAttemptedPhase := alreadyAttemptedSync(app, desiredRevisions, shouldCompareRevisions)
|
||||
ts.AddCheckpoint("already_attempted_sync_ms")
|
||||
if alreadyAttempted {
|
||||
if !lastAttemptedPhase.Successful() {
|
||||
logCtx.Warnf("Skipping auto-sync: failed previous sync attempt to %s and will not retry for %s", lastAttemptedRevisions, desiredRevisions)
|
||||
message := fmt.Sprintf("Failed last sync attempt to %s: %s", lastAttemptedRevisions, app.Status.OperationState.Message)
|
||||
if alreadyAttempted && (!selfHeal || !attemptPhase.Successful()) {
|
||||
if !attemptPhase.Successful() {
|
||||
logCtx.Warnf("Skipping auto-sync: failed previous sync attempt to %s", desiredCommitSHA)
|
||||
message := fmt.Sprintf("Failed sync attempt to %s: %s", desiredCommitSHA, app.Status.OperationState.Message)
|
||||
return &appv1.ApplicationCondition{Type: appv1.ApplicationConditionSyncError, Message: message}, 0
|
||||
}
|
||||
if !app.Spec.SyncPolicy.Automated.SelfHeal {
|
||||
logCtx.Infof("Skipping auto-sync: most recent sync already to %s", desiredRevisions)
|
||||
return nil, 0
|
||||
logCtx.Infof("Skipping auto-sync: most recent sync already to %s", desiredCommitSHA)
|
||||
return nil, 0
|
||||
} else if selfHeal {
|
||||
shouldSelfHeal, retryAfter := ctrl.shouldSelfHeal(app, alreadyAttempted)
|
||||
if app.Status.OperationState != nil && app.Status.OperationState.Operation.Sync != nil {
|
||||
op.Sync.SelfHealAttemptsCount = app.Status.OperationState.Operation.Sync.SelfHealAttemptsCount
|
||||
}
|
||||
// Self heal will trigger a new sync operation when the desired state changes and cause the application to
|
||||
// be OutOfSync when it was previously synced Successfully. This means SelfHeal should only ever be attempted
|
||||
// when the revisions have not changed, and where the previous sync to these revision was successful
|
||||
|
||||
// Only carry SelfHealAttemptsCount to be increased when the selfHealBackoffCooldown has not elapsed yet
|
||||
if !ctrl.selfHealBackoffCooldownElapsed(app) {
|
||||
if app.Status.OperationState != nil && app.Status.OperationState.Operation.Sync != nil {
|
||||
op.Sync.SelfHealAttemptsCount = app.Status.OperationState.Operation.Sync.SelfHealAttemptsCount
|
||||
if alreadyAttempted {
|
||||
if !shouldSelfHeal {
|
||||
logCtx.Infof("Skipping auto-sync: already attempted sync to %s with timeout %v (retrying in %v)", desiredCommitSHA, ctrl.selfHealTimeout, retryAfter)
|
||||
ctrl.requestAppRefresh(app.QualifiedName(), CompareWithLatest.Pointer(), &retryAfter)
|
||||
return nil, 0
|
||||
}
|
||||
}
|
||||
|
||||
if remainingTime := ctrl.selfHealRemainingBackoff(app, int(op.Sync.SelfHealAttemptsCount)); remainingTime > 0 {
|
||||
logCtx.Infof("Skipping auto-sync: already attempted sync to %s with timeout %v (retrying in %v)", lastAttemptedRevisions, ctrl.selfHealTimeout, remainingTime)
|
||||
ctrl.requestAppRefresh(app.QualifiedName(), CompareWithLatest.Pointer(), &remainingTime)
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
op.Sync.SelfHealAttemptsCount++
|
||||
for _, resource := range resources {
|
||||
if resource.Status != appv1.SyncStatusCodeSynced {
|
||||
op.Sync.Resources = append(op.Sync.Resources, appv1.SyncOperationResource{
|
||||
Kind: resource.Kind,
|
||||
Group: resource.Group,
|
||||
Name: resource.Name,
|
||||
})
|
||||
op.Sync.SelfHealAttemptsCount++
|
||||
for _, resource := range resources {
|
||||
if resource.Status != appv1.SyncStatusCodeSynced {
|
||||
op.Sync.Resources = append(op.Sync.Resources, appv1.SyncOperationResource{
|
||||
Kind: resource.Kind,
|
||||
Group: resource.Group,
|
||||
Name: resource.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2185,7 +2197,7 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
|
|||
}
|
||||
}
|
||||
if bAllNeedPrune {
|
||||
message := fmt.Sprintf("Skipping sync attempt to %s: auto-sync will wipe out all resources", desiredRevisions)
|
||||
message := fmt.Sprintf("Skipping sync attempt to %s: auto-sync will wipe out all resources", desiredCommitSHA)
|
||||
logCtx.Warn(message)
|
||||
return &appv1.ApplicationCondition{Type: appv1.ApplicationConditionSyncError, Message: message}, 0
|
||||
}
|
||||
|
|
@ -2201,65 +2213,62 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
|
|||
if stderrors.Is(err, argo.ErrAnotherOperationInProgress) {
|
||||
// skipping auto-sync because another operation is in progress and was not noticed due to stale data in informer
|
||||
// it is safe to skip auto-sync because it is already running
|
||||
logCtx.Warnf("Failed to initiate auto-sync to %s: %v", desiredRevisions, err)
|
||||
logCtx.Warnf("Failed to initiate auto-sync to %s: %v", desiredCommitSHA, err)
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
logCtx.Errorf("Failed to initiate auto-sync to %s: %v", desiredRevisions, err)
|
||||
logCtx.Errorf("Failed to initiate auto-sync to %s: %v", desiredCommitSHA, err)
|
||||
return &appv1.ApplicationCondition{Type: appv1.ApplicationConditionSyncError, Message: err.Error()}, setOpTime
|
||||
}
|
||||
ctrl.writeBackToInformer(updatedApp)
|
||||
ts.AddCheckpoint("write_back_to_informer_ms")
|
||||
|
||||
message := fmt.Sprintf("Initiated automated sync to %s", desiredRevisions)
|
||||
var target string
|
||||
if updatedApp.Spec.HasMultipleSources() {
|
||||
target = strings.Join(desiredCommitSHAsMS, ", ")
|
||||
} else {
|
||||
target = desiredCommitSHA
|
||||
}
|
||||
message := fmt.Sprintf("Initiated automated sync to '%s'", target)
|
||||
ctrl.logAppEvent(context.TODO(), app, argo.EventInfo{Reason: argo.EventReasonOperationStarted, Type: corev1.EventTypeNormal}, message)
|
||||
logCtx.Info(message)
|
||||
return nil, setOpTime
|
||||
}
|
||||
|
||||
// alreadyAttemptedSync returns whether the most recently synced revision(s) exactly match the given desiredRevisions
|
||||
// and for the same application source. If the revision(s) have changed or the Application source configuration has been updated,
|
||||
// it will return false, indicating that a new sync should be attempted.
|
||||
// When newRevisionHasChanges is false, due to commits not having direct changes on the application, it will not compare the revision(s), but only the sources.
|
||||
// It also returns the last synced revisions if any, and the result of that last sync operation.
|
||||
func alreadyAttemptedSync(app *appv1.Application, desiredRevisions []string, newRevisionHasChanges bool) (bool, []string, synccommon.OperationPhase) {
|
||||
if app.Status.OperationState == nil {
|
||||
// The operation state may be removed when new operations are triggered
|
||||
return false, []string{}, ""
|
||||
// alreadyAttemptedSync returns whether the most recent sync was performed against the
|
||||
// commitSHA and with the same app source config which are currently set in the app.
|
||||
func alreadyAttemptedSync(app *appv1.Application, commitSHA string, commitSHAsMS []string, hasMultipleSources bool, revisionUpdated bool) (bool, synccommon.OperationPhase) {
|
||||
if app.Status.OperationState == nil || app.Status.OperationState.Operation.Sync == nil || app.Status.OperationState.SyncResult == nil {
|
||||
return false, ""
|
||||
}
|
||||
if app.Status.OperationState.SyncResult == nil {
|
||||
// If the sync has completed without result, it is very likely that an error happened
|
||||
// We don't want to resync with auto-sync indefinitely. We should have retried the configured amount of time already
|
||||
// In this case, a manual action to restore the app may be required
|
||||
log.WithFields(applog.GetAppLogFields(app)).Warn("Already attempted sync: sync does not have any results")
|
||||
return app.Status.OperationState.Phase.Completed(), []string{}, app.Status.OperationState.Phase
|
||||
}
|
||||
|
||||
if newRevisionHasChanges {
|
||||
log.WithFields(applog.GetAppLogFields(app)).Infof("Already attempted sync: comparing synced revisions to %s", desiredRevisions)
|
||||
if app.Spec.HasMultipleSources() {
|
||||
if !reflect.DeepEqual(app.Status.OperationState.SyncResult.Revisions, desiredRevisions) {
|
||||
return false, app.Status.OperationState.SyncResult.Revisions, app.Status.OperationState.Phase
|
||||
if hasMultipleSources {
|
||||
if revisionUpdated {
|
||||
if !reflect.DeepEqual(app.Status.OperationState.SyncResult.Revisions, commitSHAsMS) {
|
||||
return false, ""
|
||||
}
|
||||
} else {
|
||||
if len(desiredRevisions) != 1 || app.Status.OperationState.SyncResult.Revision != desiredRevisions[0] {
|
||||
return false, []string{app.Status.OperationState.SyncResult.Revision}, app.Status.OperationState.Phase
|
||||
}
|
||||
log.WithFields(applog.GetAppLogFields(app)).Debugf("Skipping auto-sync: commitSHA %s has no changes", commitSHA)
|
||||
}
|
||||
} else {
|
||||
log.WithFields(applog.GetAppLogFields(app)).Debugf("Already attempted sync: revisions %s have no changes", desiredRevisions)
|
||||
if revisionUpdated {
|
||||
log.WithFields(applog.GetAppLogFields(app)).Infof("Executing compare of syncResult.Revision and commitSha because manifest changed: %v", commitSHA)
|
||||
if app.Status.OperationState.SyncResult.Revision != commitSHA {
|
||||
return false, ""
|
||||
}
|
||||
} else {
|
||||
log.WithFields(applog.GetAppLogFields(app)).Debugf("Skipping auto-sync: commitSHA %s has no changes", commitSHA)
|
||||
}
|
||||
}
|
||||
|
||||
log.WithFields(applog.GetAppLogFields(app)).Debug("Already attempted sync: comparing sources")
|
||||
if app.Spec.HasMultipleSources() {
|
||||
return reflect.DeepEqual(app.Spec.Sources, app.Status.OperationState.SyncResult.Sources), app.Status.OperationState.SyncResult.Revisions, app.Status.OperationState.Phase
|
||||
if hasMultipleSources {
|
||||
return reflect.DeepEqual(app.Spec.Sources, app.Status.OperationState.SyncResult.Sources), app.Status.OperationState.Phase
|
||||
}
|
||||
return reflect.DeepEqual(app.Spec.GetSource(), app.Status.OperationState.SyncResult.Source), []string{app.Status.OperationState.SyncResult.Revision}, app.Status.OperationState.Phase
|
||||
return reflect.DeepEqual(app.Spec.GetSource(), app.Status.OperationState.SyncResult.Source), app.Status.OperationState.Phase
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) selfHealRemainingBackoff(app *appv1.Application, selfHealAttemptsCount int) time.Duration {
|
||||
func (ctrl *ApplicationController) shouldSelfHeal(app *appv1.Application, alreadyAttempted bool) (bool, time.Duration) {
|
||||
if app.Status.OperationState == nil {
|
||||
return time.Duration(0)
|
||||
return true, time.Duration(0)
|
||||
}
|
||||
|
||||
var timeSinceOperation *time.Duration
|
||||
|
|
@ -2267,41 +2276,34 @@ func (ctrl *ApplicationController) selfHealRemainingBackoff(app *appv1.Applicati
|
|||
timeSinceOperation = ptr.To(time.Since(app.Status.OperationState.FinishedAt.Time))
|
||||
}
|
||||
|
||||
// Reset counter if the prior sync was successful and the cooldown period is over OR if the revision has changed
|
||||
if !alreadyAttempted || (timeSinceOperation != nil && *timeSinceOperation >= ctrl.selfHealBackoffCooldown && app.Status.Sync.Status == appv1.SyncStatusCodeSynced) {
|
||||
app.Status.OperationState.Operation.Sync.SelfHealAttemptsCount = 0
|
||||
}
|
||||
|
||||
var retryAfter time.Duration
|
||||
if ctrl.selfHealBackoff == nil {
|
||||
if ctrl.selfHealBackOff == nil {
|
||||
if timeSinceOperation == nil {
|
||||
retryAfter = ctrl.selfHealTimeout
|
||||
} else {
|
||||
retryAfter = ctrl.selfHealTimeout - *timeSinceOperation
|
||||
}
|
||||
} else {
|
||||
backOff := *ctrl.selfHealBackoff
|
||||
backOff.Steps = selfHealAttemptsCount
|
||||
backOff := *ctrl.selfHealBackOff
|
||||
backOff.Steps = int(app.Status.OperationState.Operation.Sync.SelfHealAttemptsCount)
|
||||
var delay time.Duration
|
||||
steps := backOff.Steps
|
||||
for i := 0; i < steps; i++ {
|
||||
delay = backOff.Step()
|
||||
}
|
||||
|
||||
if timeSinceOperation == nil {
|
||||
retryAfter = delay
|
||||
} else {
|
||||
retryAfter = delay - *timeSinceOperation
|
||||
}
|
||||
}
|
||||
return retryAfter
|
||||
}
|
||||
|
||||
// selfHealBackoffCooldownElapsed returns true when the last successful sync has occurred since longer
|
||||
// than then self heal cooldown. This means that the application has been in sync for long enough to
|
||||
// reset the self healing backoff to its initial state
|
||||
func (ctrl *ApplicationController) selfHealBackoffCooldownElapsed(app *appv1.Application) bool {
|
||||
if app.Status.OperationState == nil || app.Status.OperationState.FinishedAt == nil {
|
||||
// Something is in progress, or about to be. In that case, selfHeal attempt should be zero anyway
|
||||
return true
|
||||
}
|
||||
|
||||
timeSinceLastOperation := time.Since(app.Status.OperationState.FinishedAt.Time)
|
||||
return timeSinceLastOperation >= ctrl.selfHealBackoffCooldown && app.Status.OperationState.Phase.Successful()
|
||||
return retryAfter <= 0, retryAfter
|
||||
}
|
||||
|
||||
// isAppNamespaceAllowed returns whether the application is allowed in the
|
||||
|
|
|
|||
|
|
@ -348,13 +348,10 @@ status:
|
|||
- cccccccccccccccccccccccccccccccccccccccc
|
||||
sources:
|
||||
- path: some/path
|
||||
helm:
|
||||
valueFiles:
|
||||
- $values_test/values.yaml
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps.git
|
||||
- path: some/other/path
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps-fake.git
|
||||
- ref: values_test
|
||||
- path: some/other/path
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps-fake-ref.git
|
||||
`
|
||||
|
||||
|
|
@ -628,13 +625,13 @@ func TestAutoSyncEnabledSetToTrue(t *testing.T) {
|
|||
assert.False(t, app.Operation.Sync.Prune)
|
||||
}
|
||||
|
||||
func TestAutoSyncMultiSourceWithoutSelfHeal(t *testing.T) {
|
||||
func TestMultiSourceSelfHeal(t *testing.T) {
|
||||
// Simulate OutOfSync caused by object change in cluster
|
||||
// So our Sync Revisions and SyncStatus Revisions should deep equal
|
||||
t.Run("ClusterObjectChangeShouldNotTriggerAutoSync", func(t *testing.T) {
|
||||
app := newFakeMultiSourceApp()
|
||||
app.Spec.SyncPolicy.Automated.SelfHeal = false
|
||||
app.Status.OperationState.SyncResult.Revisions = []string{"z", "x", "v"}
|
||||
app.Status.Sync.Revisions = []string{"z", "x", "v"}
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
|
||||
syncStatus := v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
|
|
@ -646,14 +643,15 @@ func TestAutoSyncMultiSourceWithoutSelfHeal(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
assert.Nil(t, app.Operation)
|
||||
})
|
||||
|
||||
t.Run("NewRevisionChangeShouldTriggerAutoSync", func(t *testing.T) {
|
||||
app := newFakeMultiSourceApp()
|
||||
app.Spec.SyncPolicy.Automated.SelfHeal = false
|
||||
app.Status.OperationState.SyncResult.Revisions = []string{"z", "x", "v"}
|
||||
app.Status.Sync.Revisions = []string{"a", "b", "c"}
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
|
||||
syncStatus := v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
Revisions: []string{"a", "b", "c"},
|
||||
Revisions: []string{"z", "x", "v"},
|
||||
}
|
||||
cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{{Name: "guestbook-1", Kind: kube.DeploymentKind, Status: v1alpha1.SyncStatusCodeOutOfSync}}, true)
|
||||
assert.Nil(t, cond)
|
||||
|
|
@ -796,30 +794,6 @@ func TestSkipAutoSync(t *testing.T) {
|
|||
assert.Nil(t, app.Operation)
|
||||
})
|
||||
|
||||
t.Run("PreviousSyncAttemptError", func(t *testing.T) {
|
||||
app := newFakeApp()
|
||||
app.Status.OperationState = &v1alpha1.OperationState{
|
||||
Operation: v1alpha1.Operation{
|
||||
Sync: &v1alpha1.SyncOperation{},
|
||||
},
|
||||
Phase: synccommon.OperationError,
|
||||
SyncResult: &v1alpha1.SyncOperationResult{
|
||||
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
Source: *app.Spec.Source.DeepCopy(),
|
||||
},
|
||||
}
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
|
||||
syncStatus := v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
}
|
||||
cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: v1alpha1.SyncStatusCodeOutOfSync}}, true)
|
||||
assert.NotNil(t, cond)
|
||||
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(t.Context(), "my-app", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, app.Operation)
|
||||
})
|
||||
|
||||
t.Run("NeedsToPruneResourcesOnlyButAutomatedPruneDisabled", func(t *testing.T) {
|
||||
app := newFakeApp()
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
|
||||
|
|
@ -874,78 +848,45 @@ func TestAutoSyncIndicateError(t *testing.T) {
|
|||
|
||||
// TestAutoSyncParameterOverrides verifies we auto-sync if revision is same but parameter overrides are different
|
||||
func TestAutoSyncParameterOverrides(t *testing.T) {
|
||||
t.Run("Single source", func(t *testing.T) {
|
||||
app := newFakeApp()
|
||||
app.Spec.Source.Helm = &v1alpha1.ApplicationSourceHelm{
|
||||
Parameters: []v1alpha1.HelmParameter{
|
||||
{
|
||||
Name: "a",
|
||||
Value: "1",
|
||||
},
|
||||
app := newFakeApp()
|
||||
app.Spec.Source.Helm = &v1alpha1.ApplicationSourceHelm{
|
||||
Parameters: []v1alpha1.HelmParameter{
|
||||
{
|
||||
Name: "a",
|
||||
Value: "1",
|
||||
},
|
||||
}
|
||||
app.Status.OperationState = &v1alpha1.OperationState{
|
||||
Operation: v1alpha1.Operation{
|
||||
Sync: &v1alpha1.SyncOperation{
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
Helm: &v1alpha1.ApplicationSourceHelm{
|
||||
Parameters: []v1alpha1.HelmParameter{
|
||||
{
|
||||
Name: "a",
|
||||
Value: "2", // this value changed
|
||||
},
|
||||
},
|
||||
}
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
|
||||
syncStatus := v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
}
|
||||
app.Status.OperationState = &v1alpha1.OperationState{
|
||||
Operation: v1alpha1.Operation{
|
||||
Sync: &v1alpha1.SyncOperation{
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
Helm: &v1alpha1.ApplicationSourceHelm{
|
||||
Parameters: []v1alpha1.HelmParameter{
|
||||
{
|
||||
Name: "a",
|
||||
Value: "2", // this value changed
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Phase: synccommon.OperationFailed,
|
||||
SyncResult: &v1alpha1.SyncOperationResult{
|
||||
Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
},
|
||||
}
|
||||
syncStatus := v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
},
|
||||
Phase: synccommon.OperationFailed,
|
||||
SyncResult: &v1alpha1.SyncOperationResult{
|
||||
Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
}
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
|
||||
cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: v1alpha1.SyncStatusCodeOutOfSync}}, true)
|
||||
assert.Nil(t, cond)
|
||||
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(t.Context(), "my-app", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, app.Operation)
|
||||
})
|
||||
|
||||
t.Run("Multi sources", func(t *testing.T) {
|
||||
app := newFakeMultiSourceApp()
|
||||
app.Spec.Sources[0].Helm = &v1alpha1.ApplicationSourceHelm{
|
||||
Parameters: []v1alpha1.HelmParameter{
|
||||
{
|
||||
Name: "a",
|
||||
Value: "1",
|
||||
},
|
||||
},
|
||||
}
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
|
||||
app.Status.OperationState.SyncResult.Revisions = []string{"z", "x", "v"}
|
||||
app.Status.OperationState.SyncResult.Sources[0].Helm = &v1alpha1.ApplicationSourceHelm{
|
||||
Parameters: []v1alpha1.HelmParameter{
|
||||
{
|
||||
Name: "a",
|
||||
Value: "2", // this value changed
|
||||
},
|
||||
},
|
||||
}
|
||||
syncStatus := v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
Revisions: []string{"z", "x", "v"},
|
||||
}
|
||||
cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: v1alpha1.SyncStatusCodeOutOfSync}}, true)
|
||||
assert.Nil(t, cond)
|
||||
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(t.Context(), "my-app", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, app.Operation)
|
||||
})
|
||||
},
|
||||
}
|
||||
cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: v1alpha1.SyncStatusCodeOutOfSync}}, true)
|
||||
assert.Nil(t, cond)
|
||||
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(t.Context(), "my-app", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, app.Operation)
|
||||
}
|
||||
|
||||
// TestFinalizeAppDeletion verifies application deletion
|
||||
|
|
@ -1925,7 +1866,7 @@ apps/Deployment:
|
|||
hs = {}
|
||||
hs.status = ""
|
||||
hs.message = ""
|
||||
|
||||
|
||||
if obj.metadata ~= nil then
|
||||
if obj.metadata.labels ~= nil then
|
||||
current_status = obj.metadata.labels["status"]
|
||||
|
|
@ -2122,7 +2063,7 @@ func TestProcessRequestedAppOperation_InvalidDestination(t *testing.T) {
|
|||
ctrl.processRequestedAppOperation(app)
|
||||
|
||||
phase, _, _ := unstructured.NestedString(receivedPatch, "status", "operationState", "phase")
|
||||
assert.Equal(t, string(synccommon.OperationError), phase)
|
||||
assert.Equal(t, string(synccommon.OperationFailed), phase)
|
||||
message, _, _ := unstructured.NestedString(receivedPatch, "status", "operationState", "message")
|
||||
assert.Contains(t, message, "application destination can't have both name and server defined: another-cluster https://localhost:6443")
|
||||
}
|
||||
|
|
@ -2522,71 +2463,35 @@ func TestAppStatusIsReplaced(t *testing.T) {
|
|||
|
||||
func TestAlreadyAttemptSync(t *testing.T) {
|
||||
app := newFakeApp()
|
||||
defaultRevision := app.Status.OperationState.SyncResult.Revision
|
||||
|
||||
t.Run("no operation state", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState = nil
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{defaultRevision}, true)
|
||||
attempted, _ := alreadyAttemptedSync(app, "", []string{}, false, false)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("no sync result for running sync", func(t *testing.T) {
|
||||
t.Run("no sync operation", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult = nil
|
||||
app.Status.OperationState.Phase = synccommon.OperationRunning
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{defaultRevision}, true)
|
||||
app.Status.OperationState.Operation.Sync = nil
|
||||
attempted, _ := alreadyAttemptedSync(app, "", []string{}, false, false)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("no sync result for completed sync", func(t *testing.T) {
|
||||
t.Run("no sync result", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult = nil
|
||||
app.Status.OperationState.Phase = synccommon.OperationError
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{defaultRevision}, true)
|
||||
assert.True(t, attempted)
|
||||
attempted, _ := alreadyAttemptedSync(app, "", []string{}, false, false)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("single source", func(t *testing.T) {
|
||||
t.Run("no revision", func(t *testing.T) {
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{}, true)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("empty revision", func(t *testing.T) {
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{""}, true)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("too many revision", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Revision = "sha"
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha", "sha2"}, true)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("same manifest, same SHA with changes", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Revision = "sha"
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha"}, true)
|
||||
t.Run("same manifest with sync result", func(t *testing.T) {
|
||||
attempted, _ := alreadyAttemptedSync(app, "sha", []string{}, false, false)
|
||||
assert.True(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("same manifest, different SHA with changes", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Revision = "sha1"
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha2"}, true)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("same manifest, different SHA without changes", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Revision = "sha1"
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha2"}, false)
|
||||
assert.True(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("different manifest, same SHA with changes", func(t *testing.T) {
|
||||
t.Run("same manifest with sync result different targetRevision, same SHA", func(t *testing.T) {
|
||||
// This test represents the case where the user changed a source's target revision to a new branch, but it
|
||||
// points to the same revision as the old branch. We currently do not consider this as having been "already
|
||||
// attempted." In the future we may want to short-circuit the auto-sync in these cases.
|
||||
|
|
@ -2594,101 +2499,55 @@ func TestAlreadyAttemptSync(t *testing.T) {
|
|||
app.Status.OperationState.SyncResult.Source = v1alpha1.ApplicationSource{TargetRevision: "branch1"}
|
||||
app.Spec.Source = &v1alpha1.ApplicationSource{TargetRevision: "branch2"}
|
||||
app.Status.OperationState.SyncResult.Revision = "sha"
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha"}, true)
|
||||
attempted, _ := alreadyAttemptedSync(app, "sha", []string{}, false, false)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("different manifest, different SHA with changes", func(t *testing.T) {
|
||||
t.Run("different manifest with sync result, different SHA", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Source = v1alpha1.ApplicationSource{Path: "folder1"}
|
||||
app.Spec.Source = &v1alpha1.ApplicationSource{Path: "folder2"}
|
||||
app.Status.OperationState.SyncResult.Revision = "sha1"
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha2"}, true)
|
||||
attempted, _ := alreadyAttemptedSync(app, "sha2", []string{}, false, true)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("different manifest, different SHA without changes", func(t *testing.T) {
|
||||
t.Run("different manifest with sync result, same SHA", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Source = v1alpha1.ApplicationSource{Path: "folder1"}
|
||||
app.Spec.Source = &v1alpha1.ApplicationSource{Path: "folder2"}
|
||||
app.Status.OperationState.SyncResult.Revision = "sha1"
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha2"}, false)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("different manifest, same SHA without changes", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Source = v1alpha1.ApplicationSource{Path: "folder1"}
|
||||
app.Spec.Source = &v1alpha1.ApplicationSource{Path: "folder2"}
|
||||
app.Status.OperationState.SyncResult.Revision = "sha"
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha"}, false)
|
||||
assert.False(t, attempted)
|
||||
attempted, _ := alreadyAttemptedSync(app, "sha", []string{}, false, true)
|
||||
assert.True(t, attempted)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("multi-source", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Sources = []v1alpha1.ApplicationSource{{Path: "folder1"}, {Path: "folder2"}}
|
||||
app.Spec.Sources = []v1alpha1.ApplicationSource{{Path: "folder1"}, {Path: "folder2"}}
|
||||
|
||||
t.Run("same manifest, same SHAs with changes", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Revisions = []string{"sha_a", "sha_b"}
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha_a", "sha_b"}, true)
|
||||
t.Run("same manifest with sync result", func(t *testing.T) {
|
||||
attempted, _ := alreadyAttemptedSync(app, "", []string{"sha"}, true, false)
|
||||
assert.True(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("same manifest, different SHAs with changes", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Revisions = []string{"sha_a_=", "sha_b_1"}
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha_a_2", "sha_b_2"}, true)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("same manifest, different SHA without changes", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Revisions = []string{"sha_a_=", "sha_b_1"}
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha_a_2", "sha_b_2"}, false)
|
||||
assert.True(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("different manifest, same SHA with changes", func(t *testing.T) {
|
||||
t.Run("same manifest with sync result, different targetRevision, same SHA", func(t *testing.T) {
|
||||
// This test represents the case where the user changed a source's target revision to a new branch, but it
|
||||
// points to the same revision as the old branch. We currently do not consider this as having been "already
|
||||
// attempted." In the future we may want to short-circuit the auto-sync in these cases.
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Sources = []v1alpha1.ApplicationSource{{TargetRevision: "branch1"}, {TargetRevision: "branch2"}}
|
||||
app.Spec.Sources = []v1alpha1.ApplicationSource{{TargetRevision: "branch1"}, {TargetRevision: "branch3"}}
|
||||
app.Status.OperationState.SyncResult.Revisions = []string{"sha_a_2", "sha_b_2"}
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha_a_2", "sha_b_2"}, false)
|
||||
app.Status.OperationState.SyncResult.Sources = []v1alpha1.ApplicationSource{{TargetRevision: "branch1"}}
|
||||
app.Spec.Sources = []v1alpha1.ApplicationSource{{TargetRevision: "branch2"}}
|
||||
app.Status.OperationState.SyncResult.Revisions = []string{"sha"}
|
||||
attempted, _ := alreadyAttemptedSync(app, "", []string{"sha"}, true, false)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("different manifest, different SHA with changes", func(t *testing.T) {
|
||||
t.Run("different manifest with sync result, different SHAs", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Sources = []v1alpha1.ApplicationSource{{Path: "folder1"}, {Path: "folder2"}}
|
||||
app.Spec.Sources = []v1alpha1.ApplicationSource{{Path: "folder1"}, {Path: "folder3"}}
|
||||
app.Status.OperationState.SyncResult.Revisions = []string{"sha_a", "sha_b"}
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha_a", "sha_b_2"}, true)
|
||||
app.Status.OperationState.SyncResult.Revisions = []string{"sha_a_=", "sha_b_1"}
|
||||
attempted, _ := alreadyAttemptedSync(app, "", []string{"sha_a_2", "sha_b_2"}, true, true)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("different manifest, different SHA without changes", func(t *testing.T) {
|
||||
t.Run("different manifest with sync result, same SHAs", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Sources = []v1alpha1.ApplicationSource{{Path: "folder1"}, {Path: "folder2"}}
|
||||
app.Spec.Sources = []v1alpha1.ApplicationSource{{Path: "folder1"}, {Path: "folder3"}}
|
||||
app.Status.OperationState.SyncResult.Revisions = []string{"sha_a", "sha_b"}
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha_a", "sha_b_2"}, false)
|
||||
assert.False(t, attempted)
|
||||
})
|
||||
|
||||
t.Run("different manifest, same SHA without changes", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.SyncResult.Sources = []v1alpha1.ApplicationSource{{Path: "folder1"}, {Path: "folder2"}}
|
||||
app.Spec.Sources = []v1alpha1.ApplicationSource{{Path: "folder1"}, {Path: "folder3"}}
|
||||
app.Status.OperationState.SyncResult.Revisions = []string{"sha_a", "sha_b"}
|
||||
attempted, _, _ := alreadyAttemptedSync(app, []string{"sha_a", "sha_b"}, false)
|
||||
assert.False(t, attempted)
|
||||
attempted, _ := alreadyAttemptedSync(app, "", []string{"sha_a", "sha_b"}, true, true)
|
||||
assert.True(t, attempted)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -2700,13 +2559,14 @@ func assertDurationAround(t *testing.T, expected time.Duration, actual time.Dura
|
|||
assert.LessOrEqual(t, expected, actual+delta)
|
||||
}
|
||||
|
||||
func TestSelfHealRemainingBackoff(t *testing.T) {
|
||||
func TestSelfHealExponentialBackoff(t *testing.T) {
|
||||
ctrl := newFakeController(&fakeData{}, nil)
|
||||
ctrl.selfHealBackoff = &wait.Backoff{
|
||||
ctrl.selfHealBackOff = &wait.Backoff{
|
||||
Factor: 3,
|
||||
Duration: 2 * time.Second,
|
||||
Cap: 2 * time.Minute,
|
||||
}
|
||||
|
||||
app := &v1alpha1.Application{
|
||||
Status: v1alpha1.ApplicationStatus{
|
||||
OperationState: &v1alpha1.OperationState{
|
||||
|
|
@ -2718,112 +2578,109 @@ func TestSelfHealRemainingBackoff(t *testing.T) {
|
|||
}
|
||||
|
||||
testCases := []struct {
|
||||
attempts int
|
||||
attempts int64
|
||||
expectedAttempts int64
|
||||
finishedAt *metav1.Time
|
||||
expectedDuration time.Duration
|
||||
shouldSelfHeal bool
|
||||
alreadyAttempted bool
|
||||
syncStatus v1alpha1.SyncStatusCode
|
||||
}{{
|
||||
attempts: 0,
|
||||
finishedAt: ptr.To(metav1.Now()),
|
||||
expectedDuration: 0,
|
||||
shouldSelfHeal: true,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 0,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 1,
|
||||
finishedAt: ptr.To(metav1.Now()),
|
||||
expectedDuration: 2 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 1,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 2,
|
||||
finishedAt: ptr.To(metav1.Now()),
|
||||
expectedDuration: 6 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 2,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 3,
|
||||
finishedAt: nil,
|
||||
expectedDuration: 18 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 3,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 4,
|
||||
finishedAt: nil,
|
||||
expectedDuration: 54 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 4,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 5,
|
||||
finishedAt: nil,
|
||||
expectedDuration: 120 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 5,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 6,
|
||||
finishedAt: nil,
|
||||
expectedDuration: 120 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 6,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 6,
|
||||
finishedAt: nil,
|
||||
expectedDuration: 0,
|
||||
shouldSelfHeal: true,
|
||||
alreadyAttempted: false,
|
||||
expectedAttempts: 0,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, { // backoff will not reset as finished tme isn't >= cooldown
|
||||
attempts: 6,
|
||||
finishedAt: ptr.To(metav1.Now()),
|
||||
expectedDuration: 120 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
}, {
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 6,
|
||||
syncStatus: v1alpha1.SyncStatusCodeSynced,
|
||||
}, { // backoff will reset as finished time is >= cooldown
|
||||
attempts: 40,
|
||||
finishedAt: &metav1.Time{Time: time.Now().Add(-1 * time.Minute)},
|
||||
expectedDuration: 60 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
finishedAt: &metav1.Time{Time: time.Now().Add(-(1 * time.Minute))},
|
||||
expectedDuration: -60 * time.Second,
|
||||
shouldSelfHeal: true,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 0,
|
||||
syncStatus: v1alpha1.SyncStatusCodeSynced,
|
||||
}}
|
||||
|
||||
for i := range testCases {
|
||||
tc := testCases[i]
|
||||
t.Run(fmt.Sprintf("test case %d", i), func(t *testing.T) {
|
||||
app.Status.OperationState.Operation.Sync.SelfHealAttemptsCount = tc.attempts
|
||||
app.Status.OperationState.FinishedAt = tc.finishedAt
|
||||
duration := ctrl.selfHealRemainingBackoff(app, tc.attempts)
|
||||
shouldSelfHeal := duration <= 0
|
||||
require.Equal(t, tc.shouldSelfHeal, shouldSelfHeal)
|
||||
app.Status.Sync.Status = tc.syncStatus
|
||||
ok, duration := ctrl.shouldSelfHeal(app, tc.alreadyAttempted)
|
||||
require.Equal(t, ok, tc.shouldSelfHeal)
|
||||
require.Equal(t, tc.expectedAttempts, app.Status.OperationState.Operation.Sync.SelfHealAttemptsCount)
|
||||
assertDurationAround(t, tc.expectedDuration, duration)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelfHealBackoffCooldownElapsed(t *testing.T) {
|
||||
cooldown := time.Second * 30
|
||||
ctrl := newFakeController(&fakeData{}, nil)
|
||||
ctrl.selfHealBackoffCooldown = cooldown
|
||||
|
||||
app := &v1alpha1.Application{
|
||||
Status: v1alpha1.ApplicationStatus{
|
||||
OperationState: &v1alpha1.OperationState{
|
||||
Phase: synccommon.OperationSucceeded,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("operation not completed", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.FinishedAt = nil
|
||||
elapsed := ctrl.selfHealBackoffCooldownElapsed(app)
|
||||
assert.True(t, elapsed)
|
||||
})
|
||||
|
||||
t.Run("successful operation finised after cooldown", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.FinishedAt = &metav1.Time{Time: time.Now().Add(-cooldown)}
|
||||
elapsed := ctrl.selfHealBackoffCooldownElapsed(app)
|
||||
assert.True(t, elapsed)
|
||||
})
|
||||
|
||||
t.Run("unsuccessful operation finised after cooldown", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.Phase = synccommon.OperationFailed
|
||||
app.Status.OperationState.FinishedAt = &metav1.Time{Time: time.Now().Add(-cooldown)}
|
||||
elapsed := ctrl.selfHealBackoffCooldownElapsed(app)
|
||||
assert.False(t, elapsed)
|
||||
})
|
||||
|
||||
t.Run("successful operation finised before cooldown", func(t *testing.T) {
|
||||
app := app.DeepCopy()
|
||||
app.Status.OperationState.FinishedAt = &metav1.Time{Time: time.Now()}
|
||||
elapsed := ctrl.selfHealBackoffCooldownElapsed(app)
|
||||
assert.False(t, elapsed)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSyncTimeout(t *testing.T) {
|
||||
testCases := []struct {
|
||||
delta time.Duration
|
||||
|
|
|
|||
100
controller/cache/cache_test.go
vendored
100
controller/cache/cache_test.go
vendored
|
|
@ -1,7 +1,6 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/url"
|
||||
|
|
@ -40,36 +39,6 @@ func (n netError) Error() string { return string(n) }
|
|||
func (n netError) Timeout() bool { return false }
|
||||
func (n netError) Temporary() bool { return false }
|
||||
|
||||
func fixtures(data map[string]string, opts ...func(secret *corev1.Secret)) (*fake.Clientset, *argosettings.SettingsManager) {
|
||||
cm := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: common.ArgoCDConfigMapName,
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "argocd",
|
||||
},
|
||||
},
|
||||
Data: data,
|
||||
}
|
||||
secret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: common.ArgoCDSecretName,
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "argocd",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{},
|
||||
}
|
||||
for i := range opts {
|
||||
opts[i](secret)
|
||||
}
|
||||
kubeClient := fake.NewClientset(cm, secret)
|
||||
settingsManager := argosettings.NewSettingsManager(context.Background(), kubeClient, "default")
|
||||
|
||||
return kubeClient, settingsManager
|
||||
}
|
||||
|
||||
func TestHandleModEvent_HasChanges(_ *testing.T) {
|
||||
clusterCache := &mocks.ClusterCache{}
|
||||
clusterCache.On("Invalidate", mock.Anything, mock.Anything).Return(nil).Once()
|
||||
|
|
@ -776,72 +745,3 @@ func Test_GetVersionsInfo_error_redacted(t *testing.T) {
|
|||
require.Error(t, err)
|
||||
assert.NotContains(t, err.Error(), "password")
|
||||
}
|
||||
|
||||
func TestLoadCacheSettings(t *testing.T) {
|
||||
_, settingsManager := fixtures(map[string]string{
|
||||
"application.instanceLabelKey": "testLabel",
|
||||
"application.resourceTrackingMethod": string(appv1.TrackingMethodLabel),
|
||||
"installationID": "123456789",
|
||||
})
|
||||
ch := liveStateCache{
|
||||
settingsMgr: settingsManager,
|
||||
}
|
||||
label, err := settingsManager.GetAppInstanceLabelKey()
|
||||
require.NoError(t, err)
|
||||
trackingMethod, err := settingsManager.GetTrackingMethod()
|
||||
require.NoError(t, err)
|
||||
res, err := ch.loadCacheSettings()
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, label, res.appInstanceLabelKey)
|
||||
assert.Equal(t, string(appv1.TrackingMethodLabel), trackingMethod)
|
||||
assert.Equal(t, "123456789", res.installationID)
|
||||
|
||||
// By default the values won't be nil
|
||||
assert.NotNil(t, res.resourceOverrides)
|
||||
assert.NotNil(t, res.clusterSettings)
|
||||
assert.True(t, res.ignoreResourceUpdatesEnabled)
|
||||
}
|
||||
|
||||
func Test_ownerRefGV(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input metav1.OwnerReference
|
||||
expected schema.GroupVersion
|
||||
}{
|
||||
{
|
||||
name: "valid API Version",
|
||||
input: metav1.OwnerReference{
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
expected: schema.GroupVersion{
|
||||
Group: "apps",
|
||||
Version: "v1",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom defined version",
|
||||
input: metav1.OwnerReference{
|
||||
APIVersion: "custom-version",
|
||||
},
|
||||
expected: schema.GroupVersion{
|
||||
Version: "custom-version",
|
||||
Group: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty APIVersion",
|
||||
input: metav1.OwnerReference{
|
||||
APIVersion: "",
|
||||
},
|
||||
expected: schema.GroupVersion{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
res := ownerRefGV(tt.input)
|
||||
assert.Equal(t, tt.expected, res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ func (ctrl *ApplicationController) executePostDeleteHooks(app *v1alpha1.Applicat
|
|||
revisions = append(revisions, src.TargetRevision)
|
||||
}
|
||||
|
||||
targets, _, _, err := ctrl.appStateManager.GetRepoObjs(app, app.Spec.GetSources(), appLabelKey, revisions, false, false, false, proj, true)
|
||||
targets, _, _, err := ctrl.appStateManager.GetRepoObjs(app, app.Spec.GetSources(), appLabelKey, revisions, false, false, false, proj, false, true)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,16 +11,12 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
commitclient "github.com/argoproj/argo-cd/v3/commitserver/apiclient"
|
||||
"github.com/argoproj/argo-cd/v3/controller/hydrator/types"
|
||||
appv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v3/reposerver/apiclient"
|
||||
applog "github.com/argoproj/argo-cd/v3/util/app/log"
|
||||
"github.com/argoproj/argo-cd/v3/util/git"
|
||||
utilio "github.com/argoproj/argo-cd/v3/util/io"
|
||||
)
|
||||
|
||||
// RepoGetter is an interface that defines methods for getting repository objects. It's a subset of the DB interface to
|
||||
// avoid granting access to things we don't need.
|
||||
type RepoGetter interface {
|
||||
// GetRepository returns a repository by its URL and project name.
|
||||
GetRepository(ctx context.Context, repoURL, project string) (*appv1.Repository, error)
|
||||
|
|
@ -32,37 +28,16 @@ type RepoGetter interface {
|
|||
type Dependencies interface {
|
||||
// TODO: determine if we actually need to get the app, or if all the stuff we need the app for is done already on
|
||||
// the app controller side.
|
||||
|
||||
// GetProcessableAppProj returns the AppProject for the given application. It should only return projects that are
|
||||
// processable by the controller, meaning that the project is not deleted and the application is in a namespace
|
||||
// permitted by the project.
|
||||
GetProcessableAppProj(app *appv1.Application) (*appv1.AppProject, error)
|
||||
|
||||
// GetProcessableApps returns a list of applications that are processable by the controller.
|
||||
GetProcessableApps() (*appv1.ApplicationList, error)
|
||||
|
||||
// GetRepoObjs returns the repository objects for the given application, source, and revision. It calls the repo-
|
||||
// server and gets the manifests (objects).
|
||||
GetRepoObjs(app *appv1.Application, source appv1.ApplicationSource, revision string, project *appv1.AppProject) ([]*unstructured.Unstructured, *apiclient.ManifestResponse, error)
|
||||
|
||||
// GetWriteCredentials returns the repository credentials for the given repository URL and project. These are to be
|
||||
// sent to the commit server to write the hydrated manifests.
|
||||
GetWriteCredentials(ctx context.Context, repoURL string, project string) (*appv1.Repository, error)
|
||||
|
||||
// RequestAppRefresh requests a refresh of the application with the given name and namespace. This is used to
|
||||
// trigger a refresh after the application has been hydrated and a new commit has been pushed.
|
||||
RequestAppRefresh(appName string, appNamespace string) error
|
||||
|
||||
// PersistAppHydratorStatus persists the application status for the source hydrator.
|
||||
// TODO: only allow access to the hydrator status
|
||||
PersistAppHydratorStatus(orig *appv1.Application, newStatus *appv1.SourceHydratorStatus)
|
||||
|
||||
// AddHydrationQueueItem adds a hydration queue item to the queue. This is used to trigger the hydration process for
|
||||
// a group of applications which are hydrating to the same repo and target branch.
|
||||
AddHydrationQueueItem(key types.HydrationQueueKey)
|
||||
AddHydrationQueueItem(key HydrationQueueKey)
|
||||
}
|
||||
|
||||
// Hydrator is the main struct that implements the hydration logic. It uses the Dependencies interface to access the
|
||||
// app controller's functionality without directly depending on it.
|
||||
type Hydrator struct {
|
||||
dependencies Dependencies
|
||||
statusRefreshTimeout time.Duration
|
||||
|
|
@ -71,9 +46,6 @@ type Hydrator struct {
|
|||
repoGetter RepoGetter
|
||||
}
|
||||
|
||||
// NewHydrator creates a new Hydrator instance with the given dependencies, status refresh timeout, commit clientset,
|
||||
// repo clientset, and repo getter. The refresh timeout determines how often the hydrator checks if an application
|
||||
// needs to be hydrated.
|
||||
func NewHydrator(dependencies Dependencies, statusRefreshTimeout time.Duration, commitClientset commitclient.Clientset, repoClientset apiclient.Clientset, repoGetter RepoGetter) *Hydrator {
|
||||
return &Hydrator{
|
||||
dependencies: dependencies,
|
||||
|
|
@ -84,12 +56,6 @@ func NewHydrator(dependencies Dependencies, statusRefreshTimeout time.Duration,
|
|||
}
|
||||
}
|
||||
|
||||
// ProcessAppHydrateQueueItem processes an application hydrate queue item. It checks if the application needs hydration
|
||||
// and if so, it updates the application's status to indicate that hydration is in progress. It then adds the
|
||||
// hydration queue item to the queue for further processing.
|
||||
//
|
||||
// It's likely that multiple applications will trigger hydration at the same time. The hydration queue key is meant to
|
||||
// dedupe these requests.
|
||||
func (h *Hydrator) ProcessAppHydrateQueueItem(origApp *appv1.Application) {
|
||||
origApp = origApp.DeepCopy()
|
||||
app := origApp.DeepCopy()
|
||||
|
|
@ -123,24 +89,27 @@ func (h *Hydrator) ProcessAppHydrateQueueItem(origApp *appv1.Application) {
|
|||
logCtx.Debug("Successfully processed app hydrate queue item")
|
||||
}
|
||||
|
||||
func getHydrationQueueKey(app *appv1.Application) types.HydrationQueueKey {
|
||||
func getHydrationQueueKey(app *appv1.Application) HydrationQueueKey {
|
||||
destinationBranch := app.Spec.SourceHydrator.SyncSource.TargetBranch
|
||||
if app.Spec.SourceHydrator.HydrateTo != nil {
|
||||
destinationBranch = app.Spec.SourceHydrator.HydrateTo.TargetBranch
|
||||
}
|
||||
key := types.HydrationQueueKey{
|
||||
SourceRepoURL: git.NormalizeGitURLAllowInvalid(app.Spec.SourceHydrator.DrySource.RepoURL),
|
||||
key := HydrationQueueKey{
|
||||
SourceRepoURL: app.Spec.SourceHydrator.DrySource.RepoURL,
|
||||
SourceTargetRevision: app.Spec.SourceHydrator.DrySource.TargetRevision,
|
||||
DestinationBranch: destinationBranch,
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
type HydrationQueueKey struct {
|
||||
SourceRepoURL string
|
||||
SourceTargetRevision string
|
||||
DestinationBranch string
|
||||
}
|
||||
|
||||
// uniqueHydrationDestination is used to detect duplicate hydrate destinations.
|
||||
type uniqueHydrationDestination struct {
|
||||
// sourceRepoURL must be normalized with git.NormalizeGitURL to ensure that two apps with different URL formats
|
||||
// don't end up in two different hydration queue items. Failing to normalize would result in one hydrated commit for
|
||||
// each unique URL.
|
||||
//nolint:unused // used as part of a map key
|
||||
sourceRepoURL string
|
||||
//nolint:unused // used as part of a map key
|
||||
|
|
@ -151,11 +120,7 @@ type uniqueHydrationDestination struct {
|
|||
destinationPath string
|
||||
}
|
||||
|
||||
// ProcessHydrationQueueItem processes a hydration queue item. It retrieves the relevant applications for the given
|
||||
// hydration key, hydrates their latest commit, and updates their status accordingly. If the hydration fails, it marks
|
||||
// the operation as failed and logs the error. If successful, it updates the operation to indicate that hydration was
|
||||
// successful and requests a refresh of the applications to pick up the new hydrated commit.
|
||||
func (h *Hydrator) ProcessHydrationQueueItem(hydrationKey types.HydrationQueueKey) (processNext bool) {
|
||||
func (h *Hydrator) ProcessHydrationQueueItem(hydrationKey HydrationQueueKey) (processNext bool) {
|
||||
logCtx := log.WithFields(log.Fields{
|
||||
"sourceRepoURL": hydrationKey.SourceRepoURL,
|
||||
"sourceTargetRevision": hydrationKey.SourceTargetRevision,
|
||||
|
|
@ -212,7 +177,7 @@ func (h *Hydrator) ProcessHydrationQueueItem(hydrationKey types.HydrationQueueKe
|
|||
return
|
||||
}
|
||||
|
||||
func (h *Hydrator) hydrateAppsLatestCommit(logCtx *log.Entry, hydrationKey types.HydrationQueueKey) ([]*appv1.Application, string, string, error) {
|
||||
func (h *Hydrator) hydrateAppsLatestCommit(logCtx *log.Entry, hydrationKey HydrationQueueKey) ([]*appv1.Application, string, string, error) {
|
||||
relevantApps, err := h.getRelevantAppsForHydration(logCtx, hydrationKey)
|
||||
if err != nil {
|
||||
return nil, "", "", fmt.Errorf("failed to get relevant apps for hydration: %w", err)
|
||||
|
|
@ -226,7 +191,7 @@ func (h *Hydrator) hydrateAppsLatestCommit(logCtx *log.Entry, hydrationKey types
|
|||
return relevantApps, dryRevision, hydratedRevision, nil
|
||||
}
|
||||
|
||||
func (h *Hydrator) getRelevantAppsForHydration(logCtx *log.Entry, hydrationKey types.HydrationQueueKey) ([]*appv1.Application, error) {
|
||||
func (h *Hydrator) getRelevantAppsForHydration(logCtx *log.Entry, hydrationKey HydrationQueueKey) ([]*appv1.Application, error) {
|
||||
// Get all apps
|
||||
apps, err := h.dependencies.GetProcessableApps()
|
||||
if err != nil {
|
||||
|
|
@ -240,7 +205,7 @@ func (h *Hydrator) getRelevantAppsForHydration(logCtx *log.Entry, hydrationKey t
|
|||
continue
|
||||
}
|
||||
|
||||
if !git.SameURL(app.Spec.SourceHydrator.DrySource.RepoURL, hydrationKey.SourceRepoURL) ||
|
||||
if app.Spec.SourceHydrator.DrySource.RepoURL != hydrationKey.SourceRepoURL ||
|
||||
app.Spec.SourceHydrator.DrySource.TargetRevision != hydrationKey.SourceTargetRevision {
|
||||
continue
|
||||
}
|
||||
|
|
@ -265,7 +230,7 @@ func (h *Hydrator) getRelevantAppsForHydration(logCtx *log.Entry, hydrationKey t
|
|||
}
|
||||
|
||||
uniqueDestinationKey := uniqueHydrationDestination{
|
||||
sourceRepoURL: git.NormalizeGitURLAllowInvalid(app.Spec.SourceHydrator.DrySource.RepoURL),
|
||||
sourceRepoURL: app.Spec.SourceHydrator.DrySource.RepoURL,
|
||||
sourceTargetRevision: app.Spec.SourceHydrator.DrySource.TargetRevision,
|
||||
destinationBranch: destinationBranch,
|
||||
destinationPath: app.Spec.SourceHydrator.SyncSource.Path,
|
||||
|
|
|
|||
|
|
@ -4,14 +4,9 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/controller/hydrator/mocks"
|
||||
"github.com/argoproj/argo-cd/v3/controller/hydrator/types"
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
|
|
@ -106,64 +101,3 @@ func Test_appNeedsHydration(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getRelevantAppsForHydration_RepoURLNormalization(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d := mocks.NewDependencies(t)
|
||||
d.On("GetProcessableApps").Return(&v1alpha1.ApplicationList{
|
||||
Items: []v1alpha1.Application{
|
||||
{
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "project",
|
||||
SourceHydrator: &v1alpha1.SourceHydrator{
|
||||
DrySource: v1alpha1.DrySource{
|
||||
RepoURL: "https://example.com/repo.git",
|
||||
TargetRevision: "main",
|
||||
Path: "app1",
|
||||
},
|
||||
SyncSource: v1alpha1.SyncSource{
|
||||
TargetBranch: "main",
|
||||
Path: "app1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "project",
|
||||
SourceHydrator: &v1alpha1.SourceHydrator{
|
||||
DrySource: v1alpha1.DrySource{
|
||||
RepoURL: "https://example.com/repo",
|
||||
TargetRevision: "main",
|
||||
Path: "app2",
|
||||
},
|
||||
SyncSource: v1alpha1.SyncSource{
|
||||
TargetBranch: "main",
|
||||
Path: "app2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil)
|
||||
d.On("GetProcessableAppProj", mock.Anything).Return(&v1alpha1.AppProject{
|
||||
Spec: v1alpha1.AppProjectSpec{
|
||||
SourceRepos: []string{"https://example.com/*"},
|
||||
},
|
||||
}, nil)
|
||||
|
||||
hydrator := &Hydrator{dependencies: d}
|
||||
|
||||
hydrationKey := types.HydrationQueueKey{
|
||||
SourceRepoURL: "https://example.com/repo",
|
||||
SourceTargetRevision: "main",
|
||||
DestinationBranch: "main",
|
||||
}
|
||||
|
||||
logCtx := log.WithField("test", "RepoURLNormalization")
|
||||
relevantApps, err := hydrator.getRelevantAppsForHydration(logCtx, hydrationKey)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, relevantApps, 2, "Expected both apps to be considered relevant despite URL differences")
|
||||
}
|
||||
|
|
|
|||
464
controller/hydrator/mocks/Dependencies.go
generated
464
controller/hydrator/mocks/Dependencies.go
generated
|
|
@ -1,464 +0,0 @@
|
|||
// Code generated by mockery; DO NOT EDIT.
|
||||
// github.com/vektra/mockery
|
||||
// template: testify
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/controller/hydrator/types"
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v3/reposerver/apiclient"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
// NewDependencies creates a new instance of Dependencies. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewDependencies(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *Dependencies {
|
||||
mock := &Dependencies{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
|
||||
// Dependencies is an autogenerated mock type for the Dependencies type
|
||||
type Dependencies struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type Dependencies_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *Dependencies) EXPECT() *Dependencies_Expecter {
|
||||
return &Dependencies_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// AddHydrationQueueItem provides a mock function for the type Dependencies
|
||||
func (_mock *Dependencies) AddHydrationQueueItem(key types.HydrationQueueKey) {
|
||||
_mock.Called(key)
|
||||
return
|
||||
}
|
||||
|
||||
// Dependencies_AddHydrationQueueItem_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddHydrationQueueItem'
|
||||
type Dependencies_AddHydrationQueueItem_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// AddHydrationQueueItem is a helper method to define mock.On call
|
||||
// - key types.HydrationQueueKey
|
||||
func (_e *Dependencies_Expecter) AddHydrationQueueItem(key interface{}) *Dependencies_AddHydrationQueueItem_Call {
|
||||
return &Dependencies_AddHydrationQueueItem_Call{Call: _e.mock.On("AddHydrationQueueItem", key)}
|
||||
}
|
||||
|
||||
func (_c *Dependencies_AddHydrationQueueItem_Call) Run(run func(key types.HydrationQueueKey)) *Dependencies_AddHydrationQueueItem_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 types.HydrationQueueKey
|
||||
if args[0] != nil {
|
||||
arg0 = args[0].(types.HydrationQueueKey)
|
||||
}
|
||||
run(
|
||||
arg0,
|
||||
)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_AddHydrationQueueItem_Call) Return() *Dependencies_AddHydrationQueueItem_Call {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_AddHydrationQueueItem_Call) RunAndReturn(run func(key types.HydrationQueueKey)) *Dependencies_AddHydrationQueueItem_Call {
|
||||
_c.Run(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetProcessableAppProj provides a mock function for the type Dependencies
|
||||
func (_mock *Dependencies) GetProcessableAppProj(app *v1alpha1.Application) (*v1alpha1.AppProject, error) {
|
||||
ret := _mock.Called(app)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetProcessableAppProj")
|
||||
}
|
||||
|
||||
var r0 *v1alpha1.AppProject
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func(*v1alpha1.Application) (*v1alpha1.AppProject, error)); ok {
|
||||
return returnFunc(app)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func(*v1alpha1.Application) *v1alpha1.AppProject); ok {
|
||||
r0 = returnFunc(app)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.AppProject)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func(*v1alpha1.Application) error); ok {
|
||||
r1 = returnFunc(app)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Dependencies_GetProcessableAppProj_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProcessableAppProj'
|
||||
type Dependencies_GetProcessableAppProj_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetProcessableAppProj is a helper method to define mock.On call
|
||||
// - app *v1alpha1.Application
|
||||
func (_e *Dependencies_Expecter) GetProcessableAppProj(app interface{}) *Dependencies_GetProcessableAppProj_Call {
|
||||
return &Dependencies_GetProcessableAppProj_Call{Call: _e.mock.On("GetProcessableAppProj", app)}
|
||||
}
|
||||
|
||||
func (_c *Dependencies_GetProcessableAppProj_Call) Run(run func(app *v1alpha1.Application)) *Dependencies_GetProcessableAppProj_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 *v1alpha1.Application
|
||||
if args[0] != nil {
|
||||
arg0 = args[0].(*v1alpha1.Application)
|
||||
}
|
||||
run(
|
||||
arg0,
|
||||
)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_GetProcessableAppProj_Call) Return(appProject *v1alpha1.AppProject, err error) *Dependencies_GetProcessableAppProj_Call {
|
||||
_c.Call.Return(appProject, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_GetProcessableAppProj_Call) RunAndReturn(run func(app *v1alpha1.Application) (*v1alpha1.AppProject, error)) *Dependencies_GetProcessableAppProj_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetProcessableApps provides a mock function for the type Dependencies
|
||||
func (_mock *Dependencies) GetProcessableApps() (*v1alpha1.ApplicationList, error) {
|
||||
ret := _mock.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetProcessableApps")
|
||||
}
|
||||
|
||||
var r0 *v1alpha1.ApplicationList
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func() (*v1alpha1.ApplicationList, error)); ok {
|
||||
return returnFunc()
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func() *v1alpha1.ApplicationList); ok {
|
||||
r0 = returnFunc()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.ApplicationList)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = returnFunc()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Dependencies_GetProcessableApps_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProcessableApps'
|
||||
type Dependencies_GetProcessableApps_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetProcessableApps is a helper method to define mock.On call
|
||||
func (_e *Dependencies_Expecter) GetProcessableApps() *Dependencies_GetProcessableApps_Call {
|
||||
return &Dependencies_GetProcessableApps_Call{Call: _e.mock.On("GetProcessableApps")}
|
||||
}
|
||||
|
||||
func (_c *Dependencies_GetProcessableApps_Call) Run(run func()) *Dependencies_GetProcessableApps_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_GetProcessableApps_Call) Return(applicationList *v1alpha1.ApplicationList, err error) *Dependencies_GetProcessableApps_Call {
|
||||
_c.Call.Return(applicationList, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_GetProcessableApps_Call) RunAndReturn(run func() (*v1alpha1.ApplicationList, error)) *Dependencies_GetProcessableApps_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetRepoObjs provides a mock function for the type Dependencies
|
||||
func (_mock *Dependencies) GetRepoObjs(app *v1alpha1.Application, source v1alpha1.ApplicationSource, revision string, project *v1alpha1.AppProject) ([]*unstructured.Unstructured, *apiclient.ManifestResponse, error) {
|
||||
ret := _mock.Called(app, source, revision, project)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetRepoObjs")
|
||||
}
|
||||
|
||||
var r0 []*unstructured.Unstructured
|
||||
var r1 *apiclient.ManifestResponse
|
||||
var r2 error
|
||||
if returnFunc, ok := ret.Get(0).(func(*v1alpha1.Application, v1alpha1.ApplicationSource, string, *v1alpha1.AppProject) ([]*unstructured.Unstructured, *apiclient.ManifestResponse, error)); ok {
|
||||
return returnFunc(app, source, revision, project)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func(*v1alpha1.Application, v1alpha1.ApplicationSource, string, *v1alpha1.AppProject) []*unstructured.Unstructured); ok {
|
||||
r0 = returnFunc(app, source, revision, project)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*unstructured.Unstructured)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func(*v1alpha1.Application, v1alpha1.ApplicationSource, string, *v1alpha1.AppProject) *apiclient.ManifestResponse); ok {
|
||||
r1 = returnFunc(app, source, revision, project)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*apiclient.ManifestResponse)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(2).(func(*v1alpha1.Application, v1alpha1.ApplicationSource, string, *v1alpha1.AppProject) error); ok {
|
||||
r2 = returnFunc(app, source, revision, project)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// Dependencies_GetRepoObjs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRepoObjs'
|
||||
type Dependencies_GetRepoObjs_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetRepoObjs is a helper method to define mock.On call
|
||||
// - app *v1alpha1.Application
|
||||
// - source v1alpha1.ApplicationSource
|
||||
// - revision string
|
||||
// - project *v1alpha1.AppProject
|
||||
func (_e *Dependencies_Expecter) GetRepoObjs(app interface{}, source interface{}, revision interface{}, project interface{}) *Dependencies_GetRepoObjs_Call {
|
||||
return &Dependencies_GetRepoObjs_Call{Call: _e.mock.On("GetRepoObjs", app, source, revision, project)}
|
||||
}
|
||||
|
||||
func (_c *Dependencies_GetRepoObjs_Call) Run(run func(app *v1alpha1.Application, source v1alpha1.ApplicationSource, revision string, project *v1alpha1.AppProject)) *Dependencies_GetRepoObjs_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 *v1alpha1.Application
|
||||
if args[0] != nil {
|
||||
arg0 = args[0].(*v1alpha1.Application)
|
||||
}
|
||||
var arg1 v1alpha1.ApplicationSource
|
||||
if args[1] != nil {
|
||||
arg1 = args[1].(v1alpha1.ApplicationSource)
|
||||
}
|
||||
var arg2 string
|
||||
if args[2] != nil {
|
||||
arg2 = args[2].(string)
|
||||
}
|
||||
var arg3 *v1alpha1.AppProject
|
||||
if args[3] != nil {
|
||||
arg3 = args[3].(*v1alpha1.AppProject)
|
||||
}
|
||||
run(
|
||||
arg0,
|
||||
arg1,
|
||||
arg2,
|
||||
arg3,
|
||||
)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_GetRepoObjs_Call) Return(unstructureds []*unstructured.Unstructured, manifestResponse *apiclient.ManifestResponse, err error) *Dependencies_GetRepoObjs_Call {
|
||||
_c.Call.Return(unstructureds, manifestResponse, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_GetRepoObjs_Call) RunAndReturn(run func(app *v1alpha1.Application, source v1alpha1.ApplicationSource, revision string, project *v1alpha1.AppProject) ([]*unstructured.Unstructured, *apiclient.ManifestResponse, error)) *Dependencies_GetRepoObjs_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetWriteCredentials provides a mock function for the type Dependencies
|
||||
func (_mock *Dependencies) GetWriteCredentials(ctx context.Context, repoURL string, project string) (*v1alpha1.Repository, error) {
|
||||
ret := _mock.Called(ctx, repoURL, project)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetWriteCredentials")
|
||||
}
|
||||
|
||||
var r0 *v1alpha1.Repository
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, string, string) (*v1alpha1.Repository, error)); ok {
|
||||
return returnFunc(ctx, repoURL, project)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, string, string) *v1alpha1.Repository); ok {
|
||||
r0 = returnFunc(ctx, repoURL, project)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.Repository)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
|
||||
r1 = returnFunc(ctx, repoURL, project)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Dependencies_GetWriteCredentials_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWriteCredentials'
|
||||
type Dependencies_GetWriteCredentials_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetWriteCredentials is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - repoURL string
|
||||
// - project string
|
||||
func (_e *Dependencies_Expecter) GetWriteCredentials(ctx interface{}, repoURL interface{}, project interface{}) *Dependencies_GetWriteCredentials_Call {
|
||||
return &Dependencies_GetWriteCredentials_Call{Call: _e.mock.On("GetWriteCredentials", ctx, repoURL, project)}
|
||||
}
|
||||
|
||||
func (_c *Dependencies_GetWriteCredentials_Call) Run(run func(ctx context.Context, repoURL string, project string)) *Dependencies_GetWriteCredentials_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 context.Context
|
||||
if args[0] != nil {
|
||||
arg0 = args[0].(context.Context)
|
||||
}
|
||||
var arg1 string
|
||||
if args[1] != nil {
|
||||
arg1 = args[1].(string)
|
||||
}
|
||||
var arg2 string
|
||||
if args[2] != nil {
|
||||
arg2 = args[2].(string)
|
||||
}
|
||||
run(
|
||||
arg0,
|
||||
arg1,
|
||||
arg2,
|
||||
)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_GetWriteCredentials_Call) Return(repository *v1alpha1.Repository, err error) *Dependencies_GetWriteCredentials_Call {
|
||||
_c.Call.Return(repository, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_GetWriteCredentials_Call) RunAndReturn(run func(ctx context.Context, repoURL string, project string) (*v1alpha1.Repository, error)) *Dependencies_GetWriteCredentials_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// PersistAppHydratorStatus provides a mock function for the type Dependencies
|
||||
func (_mock *Dependencies) PersistAppHydratorStatus(orig *v1alpha1.Application, newStatus *v1alpha1.SourceHydratorStatus) {
|
||||
_mock.Called(orig, newStatus)
|
||||
return
|
||||
}
|
||||
|
||||
// Dependencies_PersistAppHydratorStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PersistAppHydratorStatus'
|
||||
type Dependencies_PersistAppHydratorStatus_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// PersistAppHydratorStatus is a helper method to define mock.On call
|
||||
// - orig *v1alpha1.Application
|
||||
// - newStatus *v1alpha1.SourceHydratorStatus
|
||||
func (_e *Dependencies_Expecter) PersistAppHydratorStatus(orig interface{}, newStatus interface{}) *Dependencies_PersistAppHydratorStatus_Call {
|
||||
return &Dependencies_PersistAppHydratorStatus_Call{Call: _e.mock.On("PersistAppHydratorStatus", orig, newStatus)}
|
||||
}
|
||||
|
||||
func (_c *Dependencies_PersistAppHydratorStatus_Call) Run(run func(orig *v1alpha1.Application, newStatus *v1alpha1.SourceHydratorStatus)) *Dependencies_PersistAppHydratorStatus_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 *v1alpha1.Application
|
||||
if args[0] != nil {
|
||||
arg0 = args[0].(*v1alpha1.Application)
|
||||
}
|
||||
var arg1 *v1alpha1.SourceHydratorStatus
|
||||
if args[1] != nil {
|
||||
arg1 = args[1].(*v1alpha1.SourceHydratorStatus)
|
||||
}
|
||||
run(
|
||||
arg0,
|
||||
arg1,
|
||||
)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_PersistAppHydratorStatus_Call) Return() *Dependencies_PersistAppHydratorStatus_Call {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_PersistAppHydratorStatus_Call) RunAndReturn(run func(orig *v1alpha1.Application, newStatus *v1alpha1.SourceHydratorStatus)) *Dependencies_PersistAppHydratorStatus_Call {
|
||||
_c.Run(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// RequestAppRefresh provides a mock function for the type Dependencies
|
||||
func (_mock *Dependencies) RequestAppRefresh(appName string, appNamespace string) error {
|
||||
ret := _mock.Called(appName, appNamespace)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RequestAppRefresh")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if returnFunc, ok := ret.Get(0).(func(string, string) error); ok {
|
||||
r0 = returnFunc(appName, appNamespace)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
return r0
|
||||
}
|
||||
|
||||
// Dependencies_RequestAppRefresh_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestAppRefresh'
|
||||
type Dependencies_RequestAppRefresh_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// RequestAppRefresh is a helper method to define mock.On call
|
||||
// - appName string
|
||||
// - appNamespace string
|
||||
func (_e *Dependencies_Expecter) RequestAppRefresh(appName interface{}, appNamespace interface{}) *Dependencies_RequestAppRefresh_Call {
|
||||
return &Dependencies_RequestAppRefresh_Call{Call: _e.mock.On("RequestAppRefresh", appName, appNamespace)}
|
||||
}
|
||||
|
||||
func (_c *Dependencies_RequestAppRefresh_Call) Run(run func(appName string, appNamespace string)) *Dependencies_RequestAppRefresh_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 string
|
||||
if args[0] != nil {
|
||||
arg0 = args[0].(string)
|
||||
}
|
||||
var arg1 string
|
||||
if args[1] != nil {
|
||||
arg1 = args[1].(string)
|
||||
}
|
||||
run(
|
||||
arg0,
|
||||
arg1,
|
||||
)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_RequestAppRefresh_Call) Return(err error) *Dependencies_RequestAppRefresh_Call {
|
||||
_c.Call.Return(err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Dependencies_RequestAppRefresh_Call) RunAndReturn(run func(appName string, appNamespace string) error) *Dependencies_RequestAppRefresh_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
package types
|
||||
|
||||
// HydrationQueueKey is used to uniquely identify a hydration operation in the queue. If several applications request
|
||||
// hydration, but they have the same queue key, only one hydration operation will be performed.
|
||||
type HydrationQueueKey struct {
|
||||
// SourceRepoURL must be normalized with git.NormalizeGitURL to ensure that we don't double-queue a single hydration
|
||||
// operation because two apps have different URL formats.
|
||||
SourceRepoURL string
|
||||
SourceTargetRevision string
|
||||
DestinationBranch string
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/controller/hydrator/types"
|
||||
"github.com/argoproj/argo-cd/v3/controller/hydrator"
|
||||
appv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v3/reposerver/apiclient"
|
||||
argoutil "github.com/argoproj/argo-cd/v3/util/argo"
|
||||
|
|
@ -50,7 +50,7 @@ func (ctrl *ApplicationController) GetRepoObjs(origApp *appv1.Application, drySo
|
|||
delete(app.Annotations, appv1.AnnotationKeyManifestGeneratePaths)
|
||||
|
||||
// FIXME: use cache and revision cache
|
||||
objs, resp, _, err := ctrl.appStateManager.GetRepoObjs(app, drySources, appLabelKey, dryRevisions, true, true, false, project, false)
|
||||
objs, resp, _, err := ctrl.appStateManager.GetRepoObjs(app, drySources, appLabelKey, dryRevisions, true, true, false, project, false, false)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get repo objects: %w", err)
|
||||
}
|
||||
|
|
@ -85,6 +85,6 @@ func (ctrl *ApplicationController) PersistAppHydratorStatus(orig *appv1.Applicat
|
|||
ctrl.persistAppStatus(orig, status)
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) AddHydrationQueueItem(key types.HydrationQueueKey) {
|
||||
func (ctrl *ApplicationController) AddHydrationQueueItem(key hydrator.HydrationQueueKey) {
|
||||
ctrl.hydrationQueue.AddRateLimited(key)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/common"
|
||||
statecache "github.com/argoproj/argo-cd/v3/controller/cache"
|
||||
|
|
@ -70,9 +71,9 @@ type managedResource struct {
|
|||
|
||||
// AppStateManager defines methods which allow to compare application spec and actual application state.
|
||||
type AppStateManager interface {
|
||||
CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localObjects []string, hasMultipleSources bool) (*comparisonResult, error)
|
||||
SyncAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, state *v1alpha1.OperationState)
|
||||
GetRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject, sendRuntimeState bool) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, bool, error)
|
||||
CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localObjects []string, hasMultipleSources bool, rollback bool) (*comparisonResult, error)
|
||||
SyncAppState(app *v1alpha1.Application, state *v1alpha1.OperationState)
|
||||
GetRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject, rollback, sendRuntimeState bool) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, bool, error)
|
||||
}
|
||||
|
||||
// comparisonResult holds the state of an application after the reconciliation
|
||||
|
|
@ -90,8 +91,7 @@ type comparisonResult struct {
|
|||
timings map[string]time.Duration
|
||||
diffResultList *diff.DiffResultList
|
||||
hasPostDeleteHooks bool
|
||||
// revisionsMayHaveChanges indicates if there are any possibilities that the revisions contain changes
|
||||
revisionsMayHaveChanges bool
|
||||
revisionUpdated bool
|
||||
}
|
||||
|
||||
func (res *comparisonResult) GetSyncStatus() *v1alpha1.SyncStatus {
|
||||
|
|
@ -108,6 +108,7 @@ type appStateManager struct {
|
|||
db db.ArgoDB
|
||||
settingsMgr *settings.SettingsManager
|
||||
appclientset appclientset.Interface
|
||||
projInformer cache.SharedIndexInformer
|
||||
kubectl kubeutil.Kubectl
|
||||
onKubectlRun kubeutil.OnKubectlRunFunc
|
||||
repoClientset apiclient.Clientset
|
||||
|
|
@ -127,7 +128,7 @@ type appStateManager struct {
|
|||
// task to the repo-server. It returns the list of generated manifests as unstructured
|
||||
// objects. It also returns the full response from all calls to the repo server as the
|
||||
// second argument.
|
||||
func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject, sendRuntimeState bool) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, bool, error) {
|
||||
func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject, rollback, sendRuntimeState bool) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, bool, error) {
|
||||
ts := stats.NewTimingStats()
|
||||
helmRepos, err := m.db.ListHelmRepositories(context.Background())
|
||||
if err != nil {
|
||||
|
|
@ -218,12 +219,14 @@ func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alp
|
|||
// Store the map of all sources having ref field into a map for applications with sources field
|
||||
// If it's for a rollback process, the refSources[*].targetRevision fields are the desired
|
||||
// revisions for the rollback
|
||||
refSources, err := argo.GetRefSources(context.Background(), sources, app.Spec.Project, m.db.GetRepository, revisions)
|
||||
refSources, err := argo.GetRefSources(context.Background(), sources, app.Spec.Project, m.db.GetRepository, revisions, rollback)
|
||||
if err != nil {
|
||||
return nil, nil, false, fmt.Errorf("failed to get ref sources: %w", err)
|
||||
}
|
||||
|
||||
revisionsMayHaveChanges := false
|
||||
revisionUpdated := false
|
||||
|
||||
atLeastOneRevisionIsNotPossibleToBeUpdated := false
|
||||
|
||||
keyManifestGenerateAnnotationVal, keyManifestGenerateAnnotationExists := app.Annotations[v1alpha1.AnnotationKeyManifestGeneratePaths]
|
||||
|
||||
|
|
@ -235,6 +238,10 @@ func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alp
|
|||
if err != nil {
|
||||
return nil, nil, false, fmt.Errorf("failed to get repo %q: %w", source.RepoURL, err)
|
||||
}
|
||||
kustomizeOptions, err := kustomizeSettings.GetOptions(source)
|
||||
if err != nil {
|
||||
return nil, nil, false, fmt.Errorf("failed to get Kustomize options for source %d of %d: %w", i+1, len(sources), err)
|
||||
}
|
||||
|
||||
syncedRevision := app.Status.Sync.Revision
|
||||
if app.Spec.HasMultipleSources() {
|
||||
|
|
@ -276,7 +283,7 @@ func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alp
|
|||
return nil, nil, false, fmt.Errorf("failed to compare revisions for source %d of %d: %w", i+1, len(sources), err)
|
||||
}
|
||||
if updateRevisionResult.Changes {
|
||||
revisionsMayHaveChanges = true
|
||||
revisionUpdated = true
|
||||
}
|
||||
|
||||
// Generate manifests should use same revision as updateRevisionForPaths, because HEAD revision may be different between these two calls
|
||||
|
|
@ -284,8 +291,8 @@ func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alp
|
|||
revision = updateRevisionResult.Revision
|
||||
}
|
||||
} else {
|
||||
// revisionsMayHaveChanges is set to true if at least one revision is not possible to be updated
|
||||
revisionsMayHaveChanges = true
|
||||
// revisionUpdated is set to true if at least one revision is not possible to be updated,
|
||||
atLeastOneRevisionIsNotPossibleToBeUpdated = true
|
||||
}
|
||||
|
||||
repos := permittedHelmRepos
|
||||
|
|
@ -311,7 +318,7 @@ func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alp
|
|||
AppName: app.InstanceName(m.namespace),
|
||||
Namespace: appNamespace,
|
||||
ApplicationSource: &source,
|
||||
KustomizeOptions: kustomizeSettings,
|
||||
KustomizeOptions: kustomizeOptions,
|
||||
KubeVersion: serverVersion,
|
||||
ApiVersions: apiVersions,
|
||||
VerifySignature: verifySignature,
|
||||
|
|
@ -346,7 +353,13 @@ func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alp
|
|||
logCtx = logCtx.WithField("time_ms", time.Since(ts.StartTime).Milliseconds())
|
||||
logCtx.Info("GetRepoObjs stats")
|
||||
|
||||
return targetObjs, manifestInfos, revisionsMayHaveChanges, nil
|
||||
// If a revision in any of the sources cannot be updated,
|
||||
// we should trigger self-healing whenever there are changes to the manifests.
|
||||
if atLeastOneRevisionIsNotPossibleToBeUpdated {
|
||||
revisionUpdated = true
|
||||
}
|
||||
|
||||
return targetObjs, manifestInfos, revisionUpdated, nil
|
||||
}
|
||||
|
||||
// ResolveGitRevision will resolve the given revision to a full commit SHA. Only works for git.
|
||||
|
|
@ -529,37 +542,32 @@ func isManagedNamespace(ns *unstructured.Unstructured, app *v1alpha1.Application
|
|||
// CompareAppState compares application git state to the live app state, using the specified
|
||||
// revision and supplied source. If revision or overrides are empty, then compares against
|
||||
// revision and overrides in the app spec.
|
||||
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localManifests []string, hasMultipleSources bool) (*comparisonResult, error) {
|
||||
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localManifests []string, hasMultipleSources bool, rollback bool) (*comparisonResult, error) {
|
||||
ts := stats.NewTimingStats()
|
||||
logCtx := log.WithFields(applog.GetAppLogFields(app))
|
||||
|
||||
// Build initial sync status
|
||||
syncStatus := &v1alpha1.SyncStatus{
|
||||
ComparedTo: v1alpha1.ComparedTo{
|
||||
Destination: app.Spec.Destination,
|
||||
IgnoreDifferences: app.Spec.IgnoreDifferences,
|
||||
},
|
||||
Status: v1alpha1.SyncStatusCodeUnknown,
|
||||
}
|
||||
if hasMultipleSources {
|
||||
syncStatus.ComparedTo.Sources = sources
|
||||
syncStatus.Revisions = revisions
|
||||
} else {
|
||||
if len(sources) > 0 {
|
||||
syncStatus.ComparedTo.Source = sources[0]
|
||||
} else {
|
||||
logCtx.Warn("CompareAppState: sources should not be empty")
|
||||
}
|
||||
if len(revisions) > 0 {
|
||||
syncStatus.Revision = revisions[0]
|
||||
}
|
||||
}
|
||||
|
||||
appLabelKey, resourceOverrides, resFilter, installationID, trackingMethod, err := m.getComparisonSettings()
|
||||
|
||||
ts.AddCheckpoint("settings_ms")
|
||||
|
||||
// return unknown comparison result if basic comparison settings cannot be loaded
|
||||
if err != nil {
|
||||
// return unknown comparison result if basic comparison settings cannot be loaded
|
||||
return &comparisonResult{syncStatus: syncStatus, healthStatus: health.HealthStatusUnknown}, nil
|
||||
if hasMultipleSources {
|
||||
return &comparisonResult{
|
||||
syncStatus: &v1alpha1.SyncStatus{
|
||||
ComparedTo: app.Spec.BuildComparedToStatus(),
|
||||
Status: v1alpha1.SyncStatusCodeUnknown,
|
||||
Revisions: revisions,
|
||||
},
|
||||
healthStatus: health.HealthStatusUnknown,
|
||||
}, nil
|
||||
}
|
||||
return &comparisonResult{
|
||||
syncStatus: &v1alpha1.SyncStatus{
|
||||
ComparedTo: app.Spec.BuildComparedToStatus(),
|
||||
Status: v1alpha1.SyncStatusCodeUnknown,
|
||||
Revision: revisions[0],
|
||||
},
|
||||
healthStatus: health.HealthStatusUnknown,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// When signature keys are defined in the project spec, we need to verify the signature on the Git revision
|
||||
|
|
@ -574,6 +582,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1
|
|||
return nil, err
|
||||
}
|
||||
|
||||
logCtx := log.WithFields(applog.GetAppLogFields(app))
|
||||
logCtx.Infof("Comparing app state (cluster: %s, namespace: %s)", app.Spec.Destination.Server, app.Spec.Destination.Namespace)
|
||||
|
||||
var targetObjs []*unstructured.Unstructured
|
||||
|
|
@ -582,7 +591,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1
|
|||
var manifestInfos []*apiclient.ManifestResponse
|
||||
targetNsExists := false
|
||||
|
||||
var revisionsMayHaveChanges bool
|
||||
var revisionUpdated bool
|
||||
|
||||
if len(localManifests) == 0 {
|
||||
// If the length of revisions is not same as the length of sources,
|
||||
|
|
@ -594,7 +603,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1
|
|||
}
|
||||
}
|
||||
|
||||
targetObjs, manifestInfos, revisionsMayHaveChanges, err = m.GetRepoObjs(app, sources, appLabelKey, revisions, noCache, noRevisionCache, verifySignature, project, true)
|
||||
targetObjs, manifestInfos, revisionUpdated, err = m.GetRepoObjs(app, sources, appLabelKey, revisions, noCache, noRevisionCache, verifySignature, project, rollback, true)
|
||||
if err != nil {
|
||||
targetObjs = make([]*unstructured.Unstructured, 0)
|
||||
msg := "Failed to load target state: " + err.Error()
|
||||
|
|
@ -942,14 +951,32 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1
|
|||
} else if app.HasChangedManagedNamespaceMetadata() {
|
||||
syncCode = v1alpha1.SyncStatusCodeOutOfSync
|
||||
}
|
||||
var revision string
|
||||
|
||||
syncStatus.Status = syncCode
|
||||
|
||||
// Update the initial revision to the resolved manifest SHA
|
||||
if !hasMultipleSources && len(manifestRevisions) > 0 {
|
||||
revision = manifestRevisions[0]
|
||||
}
|
||||
var syncStatus v1alpha1.SyncStatus
|
||||
if hasMultipleSources {
|
||||
syncStatus.Revisions = manifestRevisions
|
||||
} else if len(manifestRevisions) > 0 {
|
||||
syncStatus.Revision = manifestRevisions[0]
|
||||
syncStatus = v1alpha1.SyncStatus{
|
||||
ComparedTo: v1alpha1.ComparedTo{
|
||||
Destination: app.Spec.Destination,
|
||||
Sources: sources,
|
||||
IgnoreDifferences: app.Spec.IgnoreDifferences,
|
||||
},
|
||||
Status: syncCode,
|
||||
Revisions: manifestRevisions,
|
||||
}
|
||||
} else {
|
||||
syncStatus = v1alpha1.SyncStatus{
|
||||
ComparedTo: v1alpha1.ComparedTo{
|
||||
Destination: app.Spec.Destination,
|
||||
Source: app.Spec.GetSource(),
|
||||
IgnoreDifferences: app.Spec.IgnoreDifferences,
|
||||
},
|
||||
Status: syncCode,
|
||||
Revision: revision,
|
||||
}
|
||||
}
|
||||
|
||||
ts.AddCheckpoint("sync_ms")
|
||||
|
|
@ -969,15 +996,15 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1
|
|||
}
|
||||
|
||||
compRes := comparisonResult{
|
||||
syncStatus: syncStatus,
|
||||
healthStatus: healthStatus,
|
||||
resources: resourceSummaries,
|
||||
managedResources: managedResources,
|
||||
reconciliationResult: reconciliation,
|
||||
diffConfig: diffConfig,
|
||||
diffResultList: diffResults,
|
||||
hasPostDeleteHooks: hasPostDeleteHooks,
|
||||
revisionsMayHaveChanges: revisionsMayHaveChanges,
|
||||
syncStatus: &syncStatus,
|
||||
healthStatus: healthStatus,
|
||||
resources: resourceSummaries,
|
||||
managedResources: managedResources,
|
||||
reconciliationResult: reconciliation,
|
||||
diffConfig: diffConfig,
|
||||
diffResultList: diffResults,
|
||||
hasPostDeleteHooks: hasPostDeleteHooks,
|
||||
revisionUpdated: revisionUpdated,
|
||||
}
|
||||
|
||||
if hasMultipleSources {
|
||||
|
|
@ -1035,7 +1062,7 @@ func useDiffCache(noCache bool, manifestInfos []*apiclient.ManifestResponse, sou
|
|||
return false
|
||||
}
|
||||
|
||||
if !specEqualsCompareTo(app.Spec, sources, app.Status.Sync.ComparedTo) {
|
||||
if !specEqualsCompareTo(app.Spec, app.Status.Sync.ComparedTo) {
|
||||
log.WithField("useDiffCache", "false").Debug("specChanged")
|
||||
return false
|
||||
}
|
||||
|
|
@ -1046,11 +1073,11 @@ func useDiffCache(noCache bool, manifestInfos []*apiclient.ManifestResponse, sou
|
|||
|
||||
// specEqualsCompareTo compares the application spec to the comparedTo status. It normalizes the destination to match
|
||||
// the comparedTo destination before comparing. It does not mutate the original spec or comparedTo.
|
||||
func specEqualsCompareTo(spec v1alpha1.ApplicationSpec, sources []v1alpha1.ApplicationSource, comparedTo v1alpha1.ComparedTo) bool {
|
||||
func specEqualsCompareTo(spec v1alpha1.ApplicationSpec, comparedTo v1alpha1.ComparedTo) bool {
|
||||
// Make a copy to be sure we don't mutate the original.
|
||||
specCopy := spec.DeepCopy()
|
||||
compareToSpec := specCopy.BuildComparedToStatus(sources)
|
||||
return reflect.DeepEqual(comparedTo, compareToSpec)
|
||||
currentSpec := specCopy.BuildComparedToStatus()
|
||||
return reflect.DeepEqual(comparedTo, currentSpec)
|
||||
}
|
||||
|
||||
func (m *appStateManager) persistRevisionHistory(
|
||||
|
|
@ -1112,6 +1139,7 @@ func NewAppStateManager(
|
|||
onKubectlRun kubeutil.OnKubectlRunFunc,
|
||||
settingsMgr *settings.SettingsManager,
|
||||
liveStateCache statecache.LiveStateCache,
|
||||
projInformer cache.SharedIndexInformer,
|
||||
metricsServer *metrics.MetricsServer,
|
||||
cache *appstatecache.Cache,
|
||||
statusRefreshTimeout time.Duration,
|
||||
|
|
@ -1131,6 +1159,7 @@ func NewAppStateManager(
|
|||
repoClientset: repoClientset,
|
||||
namespace: namespace,
|
||||
settingsMgr: settingsMgr,
|
||||
projInformer: projInformer,
|
||||
metricsServer: metricsServer,
|
||||
statusRefreshTimeout: statusRefreshTimeout,
|
||||
resourceTracking: resourceTracking,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/common"
|
||||
"github.com/argoproj/argo-cd/v3/controller/testdata"
|
||||
|
|
@ -53,7 +52,7 @@ func TestCompareAppStateEmpty(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -71,18 +70,18 @@ func TestCompareAppStateRepoError(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
assert.Nil(t, compRes)
|
||||
require.EqualError(t, err, ErrCompareStateRepo.Error())
|
||||
|
||||
// expect to still get compare state error to as inside grace period
|
||||
compRes, err = ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err = ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
assert.Nil(t, compRes)
|
||||
require.EqualError(t, err, ErrCompareStateRepo.Error())
|
||||
|
||||
time.Sleep(10 * time.Second)
|
||||
// expect to not get error as outside of grace period, but status should be unknown
|
||||
compRes, err = ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err = ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
assert.NotNil(t, compRes)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, v1alpha1.SyncStatusCodeUnknown, compRes.syncStatus.Status)
|
||||
|
|
@ -117,7 +116,7 @@ func TestCompareAppStateNamespaceMetadataDiffers(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -166,7 +165,7 @@ func TestCompareAppStateNamespaceMetadataDiffersToManifest(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -224,7 +223,7 @@ func TestCompareAppStateNamespaceMetadata(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -283,7 +282,7 @@ func TestCompareAppStateNamespaceMetadataIsTheSame(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -311,7 +310,7 @@ func TestCompareAppStateMissing(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -343,7 +342,7 @@ func TestCompareAppStateExtra(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.Equal(t, v1alpha1.SyncStatusCodeOutOfSync, compRes.syncStatus.Status)
|
||||
|
|
@ -374,7 +373,7 @@ func TestCompareAppStateHook(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.Equal(t, v1alpha1.SyncStatusCodeSynced, compRes.syncStatus.Status)
|
||||
|
|
@ -406,7 +405,7 @@ func TestCompareAppStateSkipHook(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.Equal(t, v1alpha1.SyncStatusCodeSynced, compRes.syncStatus.Status)
|
||||
|
|
@ -437,7 +436,7 @@ func TestCompareAppStateCompareOptionIgnoreExtraneous(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, compRes)
|
||||
|
|
@ -470,7 +469,7 @@ func TestCompareAppStateExtraHook(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, compRes)
|
||||
|
|
@ -499,7 +498,7 @@ func TestAppRevisionsSingleSource(t *testing.T) {
|
|||
app := newFakeApp()
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, app.Spec.HasMultipleSources())
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, app.Spec.HasMultipleSources(), false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -539,7 +538,7 @@ func TestAppRevisionsMultiSource(t *testing.T) {
|
|||
app := newFakeMultiSourceApp()
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, app.Spec.HasMultipleSources())
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, app.Spec.HasMultipleSources(), false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -588,7 +587,7 @@ func TestCompareAppStateDuplicatedNamespacedResources(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, compRes)
|
||||
|
|
@ -625,7 +624,7 @@ func TestCompareAppStateManagedNamespaceMetadataWithLiveNsDoesNotGetPruned(t *te
|
|||
},
|
||||
}
|
||||
ctrl := newFakeController(&data, nil)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, []string{}, app.Spec.Sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, []string{}, app.Spec.Sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, compRes)
|
||||
|
|
@ -679,7 +678,7 @@ func TestCompareAppStateWithManifestGeneratePath(t *testing.T) {
|
|||
ctrl := newFakeController(&data, nil)
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "abc123")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.Equal(t, v1alpha1.SyncStatusCodeSynced, compRes.syncStatus.Status)
|
||||
|
|
@ -715,7 +714,7 @@ func TestSetHealth(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, health.HealthStatusHealthy, compRes.healthStatus)
|
||||
|
|
@ -751,7 +750,7 @@ func TestPreserveStatusTimestamp(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, health.HealthStatusHealthy, compRes.healthStatus)
|
||||
|
|
@ -788,7 +787,7 @@ func TestSetHealthSelfReferencedApp(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, health.HealthStatusHealthy, compRes.healthStatus)
|
||||
|
|
@ -863,7 +862,7 @@ func TestReturnUnknownComparisonStateOnSettingLoadError(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, health.HealthStatusUnknown, compRes.healthStatus)
|
||||
|
|
@ -1012,7 +1011,7 @@ func TestSignedResponseNoSignatureRequired(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -1039,7 +1038,7 @@ func TestSignedResponseNoSignatureRequired(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -1071,7 +1070,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -1098,7 +1097,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "abc123")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -1125,7 +1124,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "abc123")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -1152,7 +1151,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "abc123")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -1182,7 +1181,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "abc123")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &testProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &testProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -1212,7 +1211,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "abc123")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, localManifests, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, localManifests, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -1242,7 +1241,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "abc123")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -1272,7 +1271,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "abc123")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, localManifests, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, localManifests, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
|
|
@ -1482,6 +1481,7 @@ func TestIsLiveResourceManaged(t *testing.T) {
|
|||
|
||||
func TestUseDiffCache(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type fixture struct {
|
||||
testName string
|
||||
noCache bool
|
||||
|
|
@ -1493,6 +1493,7 @@ func TestUseDiffCache(t *testing.T) {
|
|||
expectedUseCache bool
|
||||
serverSideDiff bool
|
||||
}
|
||||
|
||||
manifestInfos := func(revision string) []*apiclient.ManifestResponse {
|
||||
return []*apiclient.ManifestResponse{
|
||||
{
|
||||
|
|
@ -1508,15 +1509,14 @@ func TestUseDiffCache(t *testing.T) {
|
|||
},
|
||||
}
|
||||
}
|
||||
source := func() v1alpha1.ApplicationSource {
|
||||
return v1alpha1.ApplicationSource{
|
||||
RepoURL: "https://some-repo.com",
|
||||
Path: "argocd/httpbin",
|
||||
TargetRevision: "HEAD",
|
||||
}
|
||||
}
|
||||
sources := func() []v1alpha1.ApplicationSource {
|
||||
return []v1alpha1.ApplicationSource{source()}
|
||||
return []v1alpha1.ApplicationSource{
|
||||
{
|
||||
RepoURL: "https://some-repo.com",
|
||||
Path: "argocd/httpbin",
|
||||
TargetRevision: "HEAD",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
app := func(namespace string, revision string, refresh bool, a *v1alpha1.Application) *v1alpha1.Application {
|
||||
|
|
@ -1526,7 +1526,11 @@ func TestUseDiffCache(t *testing.T) {
|
|||
Namespace: namespace,
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Source: ptr.To(source()),
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
RepoURL: "https://some-repo.com",
|
||||
Path: "argocd/httpbin",
|
||||
TargetRevision: "HEAD",
|
||||
},
|
||||
Destination: v1alpha1.ApplicationDestination{
|
||||
Server: "https://kubernetes.default.svc",
|
||||
Namespace: "httpbin",
|
||||
|
|
@ -1544,7 +1548,11 @@ func TestUseDiffCache(t *testing.T) {
|
|||
Sync: v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
ComparedTo: v1alpha1.ComparedTo{
|
||||
Source: source(),
|
||||
Source: v1alpha1.ApplicationSource{
|
||||
RepoURL: "https://some-repo.com",
|
||||
Path: "argocd/httpbin",
|
||||
TargetRevision: "HEAD",
|
||||
},
|
||||
Destination: v1alpha1.ApplicationDestination{
|
||||
Server: "https://kubernetes.default.svc",
|
||||
Namespace: "httpbin",
|
||||
|
|
@ -1569,6 +1577,7 @@ func TestUseDiffCache(t *testing.T) {
|
|||
}
|
||||
return app
|
||||
}
|
||||
|
||||
cases := []fixture{
|
||||
{
|
||||
testName: "will use diff cache",
|
||||
|
|
@ -1585,7 +1594,7 @@ func TestUseDiffCache(t *testing.T) {
|
|||
testName: "will use diff cache with sync policy",
|
||||
noCache: false,
|
||||
manifestInfos: manifestInfos("rev1"),
|
||||
sources: []v1alpha1.ApplicationSource{test.YamlToApplication(testdata.DiffCacheYaml).Status.Sync.ComparedTo.Source},
|
||||
sources: sources(),
|
||||
app: test.YamlToApplication(testdata.DiffCacheYaml),
|
||||
manifestRevisions: []string{"rev1"},
|
||||
statusRefreshTimeout: time.Hour * 24,
|
||||
|
|
@ -1595,15 +1604,8 @@ func TestUseDiffCache(t *testing.T) {
|
|||
{
|
||||
testName: "will use diff cache for multisource",
|
||||
noCache: false,
|
||||
manifestInfos: append(manifestInfos("rev1"), manifestInfos("rev2")...),
|
||||
sources: v1alpha1.ApplicationSources{
|
||||
{
|
||||
RepoURL: "multisource repo1",
|
||||
},
|
||||
{
|
||||
RepoURL: "multisource repo2",
|
||||
},
|
||||
},
|
||||
manifestInfos: manifestInfos("rev1"),
|
||||
sources: sources(),
|
||||
app: app("httpbin", "", false, &v1alpha1.Application{
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Source: nil,
|
||||
|
|
@ -1741,13 +1743,16 @@ func TestUseDiffCache(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
// Given
|
||||
t.Parallel()
|
||||
logger, _ := logrustest.NewNullLogger()
|
||||
log := logrus.NewEntry(logger)
|
||||
|
||||
// When
|
||||
useDiffCache := useDiffCache(tc.noCache, tc.manifestInfos, tc.sources, tc.app, tc.manifestRevisions, tc.statusRefreshTimeout, tc.serverSideDiff, log)
|
||||
|
||||
// Then
|
||||
assert.Equal(t, tc.expectedUseCache, useDiffCache)
|
||||
})
|
||||
|
|
@ -1770,11 +1775,11 @@ func TestCompareAppStateDefaultRevisionUpdated(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
assert.True(t, compRes.revisionsMayHaveChanges)
|
||||
assert.True(t, compRes.revisionUpdated)
|
||||
}
|
||||
|
||||
func TestCompareAppStateRevisionUpdatedWithHelmSource(t *testing.T) {
|
||||
|
|
@ -1793,11 +1798,11 @@ func TestCompareAppStateRevisionUpdatedWithHelmSource(t *testing.T) {
|
|||
sources = append(sources, app.Spec.GetSource())
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
assert.True(t, compRes.revisionsMayHaveChanges)
|
||||
assert.True(t, compRes.revisionUpdated)
|
||||
}
|
||||
|
||||
func Test_normalizeClusterScopeTracking(t *testing.T) {
|
||||
|
|
@ -1845,6 +1850,6 @@ func TestCompareAppState_DoesNotCallUpdateRevisionForPaths_ForOCI(t *testing.T)
|
|||
sources := make([]v1alpha1.ApplicationSource, 0)
|
||||
sources = append(sources, source)
|
||||
|
||||
_, _, _, err := ctrl.appStateManager.GetRepoObjs(app, sources, "abc123", []string{"123456"}, false, false, false, &defaultProj, false)
|
||||
_, _, _, err := ctrl.appStateManager.GetRepoObjs(app, sources, "abc123", []string{"123456"}, false, false, false, &defaultProj, false, false)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import (
|
|||
"github.com/argoproj/argo-cd/v3/controller/metrics"
|
||||
"github.com/argoproj/argo-cd/v3/controller/syncid"
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
listersv1alpha1 "github.com/argoproj/argo-cd/v3/pkg/client/listers/application/v1alpha1"
|
||||
applog "github.com/argoproj/argo-cd/v3/util/app/log"
|
||||
"github.com/argoproj/argo-cd/v3/util/argo"
|
||||
"github.com/argoproj/argo-cd/v3/util/argo/diff"
|
||||
|
|
@ -86,95 +87,123 @@ func (m *appStateManager) getServerSideDiffDryRunApplier(cluster *v1alpha1.Clust
|
|||
return ops, cleanup, nil
|
||||
}
|
||||
|
||||
func NewOperationState(operation v1alpha1.Operation) *v1alpha1.OperationState {
|
||||
return &v1alpha1.OperationState{
|
||||
Phase: common.OperationRunning,
|
||||
Operation: operation,
|
||||
StartedAt: metav1.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
func newSyncOperationResult(app *v1alpha1.Application, op v1alpha1.SyncOperation) *v1alpha1.SyncOperationResult {
|
||||
syncRes := &v1alpha1.SyncOperationResult{}
|
||||
|
||||
if len(op.Sources) > 0 || op.Source != nil {
|
||||
// specific source specified in the SyncOperation
|
||||
if op.Source != nil {
|
||||
syncRes.Source = *op.Source
|
||||
}
|
||||
syncRes.Sources = op.Sources
|
||||
} else {
|
||||
// normal sync case, get sources from the spec
|
||||
syncRes.Sources = app.Spec.Sources
|
||||
syncRes.Source = app.Spec.GetSource()
|
||||
}
|
||||
|
||||
func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha1.OperationState) {
|
||||
// Sync requests might be requested with ambiguous revisions (e.g. master, HEAD, v1.2.3).
|
||||
// This can change meaning when resuming operations (e.g a hook sync). After calculating a
|
||||
// concrete git commit SHA, the revision of the SyncOperationResult will be updated with the SHA
|
||||
syncRes.Revision = op.Revision
|
||||
syncRes.Revisions = op.Revisions
|
||||
return syncRes
|
||||
}
|
||||
// concrete git commit SHA, the SHA is remembered in the status.operationState.syncResult field.
|
||||
// This ensures that when resuming an operation, we sync to the same revision that we initially
|
||||
// started with.
|
||||
|
||||
func (m *appStateManager) SyncAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, state *v1alpha1.OperationState) {
|
||||
syncId, err := syncid.Generate()
|
||||
if err != nil {
|
||||
state.Phase = common.OperationError
|
||||
state.Message = fmt.Sprintf("Failed to generate sync ID: %v", err)
|
||||
return
|
||||
}
|
||||
logEntry := log.WithFields(applog.GetAppLogFields(app)).WithField("syncId", syncId)
|
||||
var revision string
|
||||
var syncOp v1alpha1.SyncOperation
|
||||
var syncRes *v1alpha1.SyncOperationResult
|
||||
var source v1alpha1.ApplicationSource
|
||||
var sources []v1alpha1.ApplicationSource
|
||||
revisions := make([]string, 0)
|
||||
|
||||
if state.Operation.Sync == nil {
|
||||
state.Phase = common.OperationError
|
||||
state.Phase = common.OperationFailed
|
||||
state.Message = "Invalid operation request: no operation specified"
|
||||
return
|
||||
}
|
||||
syncOp = *state.Operation.Sync
|
||||
|
||||
syncOp := *state.Operation.Sync
|
||||
|
||||
if state.SyncResult == nil {
|
||||
state.SyncResult = newSyncOperationResult(app, syncOp)
|
||||
}
|
||||
|
||||
if isBlocked, err := syncWindowPreventsSync(app, project); isBlocked {
|
||||
// If the operation is currently running, simply let the user know the sync is blocked by a current sync window
|
||||
if state.Phase == common.OperationRunning {
|
||||
state.Message = "Sync operation blocked by sync window"
|
||||
if err != nil {
|
||||
state.Message = fmt.Sprintf("%s: %v", state.Message, err)
|
||||
}
|
||||
isMultiSourceRevision := app.Spec.HasMultipleSources()
|
||||
rollback := len(syncOp.Sources) > 0 || syncOp.Source != nil
|
||||
if rollback {
|
||||
// rollback case
|
||||
if len(state.Operation.Sync.Sources) > 0 {
|
||||
sources = state.Operation.Sync.Sources
|
||||
isMultiSourceRevision = true
|
||||
} else {
|
||||
source = *state.Operation.Sync.Source
|
||||
sources = make([]v1alpha1.ApplicationSource, 0)
|
||||
isMultiSourceRevision = false
|
||||
}
|
||||
} else {
|
||||
// normal sync case (where source is taken from app.spec.sources)
|
||||
if app.Spec.HasMultipleSources() {
|
||||
sources = app.Spec.Sources
|
||||
} else {
|
||||
// normal sync case (where source is taken from app.spec.source)
|
||||
source = app.Spec.GetSource()
|
||||
sources = make([]v1alpha1.ApplicationSource, 0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
revisions := state.SyncResult.Revisions
|
||||
sources := state.SyncResult.Sources
|
||||
isMultiSourceSync := len(sources) > 0
|
||||
if !isMultiSourceSync {
|
||||
sources = []v1alpha1.ApplicationSource{state.SyncResult.Source}
|
||||
revisions = []string{state.SyncResult.Revision}
|
||||
if state.SyncResult != nil {
|
||||
syncRes = state.SyncResult
|
||||
revision = state.SyncResult.Revision
|
||||
revisions = append(revisions, state.SyncResult.Revisions...)
|
||||
} else {
|
||||
syncRes = &v1alpha1.SyncOperationResult{}
|
||||
// status.operationState.syncResult.source. must be set properly since auto-sync relies
|
||||
// on this information to decide if it should sync (if source is different than the last
|
||||
// sync attempt)
|
||||
if isMultiSourceRevision {
|
||||
syncRes.Sources = sources
|
||||
} else {
|
||||
syncRes.Source = source
|
||||
}
|
||||
state.SyncResult = syncRes
|
||||
}
|
||||
|
||||
// if we get here, it means we did not remember a commit SHA which we should be syncing to.
|
||||
// This typically indicates we are just about to begin a brand new sync/rollback operation.
|
||||
// Take the value in the requested operation. We will resolve this to a SHA later.
|
||||
if isMultiSourceRevision {
|
||||
if len(revisions) != len(sources) {
|
||||
revisions = syncOp.Revisions
|
||||
}
|
||||
} else {
|
||||
if revision == "" {
|
||||
revision = syncOp.Revision
|
||||
}
|
||||
}
|
||||
|
||||
proj, err := argo.GetAppProject(context.TODO(), app, listersv1alpha1.NewAppProjectLister(m.projInformer.GetIndexer()), m.namespace, m.settingsMgr, m.db)
|
||||
if err != nil {
|
||||
state.Phase = common.OperationError
|
||||
state.Message = fmt.Sprintf("Failed to load application project: %v", err)
|
||||
return
|
||||
} else {
|
||||
isBlocked, err := syncWindowPreventsSync(app, proj)
|
||||
if isBlocked {
|
||||
// If the operation is currently running, simply let the user know the sync is blocked by a current sync window
|
||||
if state.Phase == common.OperationRunning {
|
||||
state.Message = "Sync operation blocked by sync window"
|
||||
if err != nil {
|
||||
state.Message = fmt.Sprintf("%s: %v", state.Message, err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !isMultiSourceRevision {
|
||||
sources = []v1alpha1.ApplicationSource{source}
|
||||
revisions = []string{revision}
|
||||
}
|
||||
|
||||
// ignore error if CompareStateRepoError, this shouldn't happen as noRevisionCache is true
|
||||
compareResult, err := m.CompareAppState(app, project, revisions, sources, false, true, syncOp.Manifests, isMultiSourceSync)
|
||||
compareResult, err := m.CompareAppState(app, proj, revisions, sources, false, true, syncOp.Manifests, isMultiSourceRevision, rollback)
|
||||
if err != nil && !stderrors.Is(err, ErrCompareStateRepo) {
|
||||
state.Phase = common.OperationError
|
||||
state.Message = err.Error()
|
||||
return
|
||||
}
|
||||
|
||||
// We are now guaranteed to have a concrete commit SHA. Save this in the sync result revision so that we remember
|
||||
// We now have a concrete commit SHA. Save this in the sync result revision so that we remember
|
||||
// what we should be syncing to when resuming operations.
|
||||
state.SyncResult.Revision = compareResult.syncStatus.Revision
|
||||
state.SyncResult.Revisions = compareResult.syncStatus.Revisions
|
||||
|
||||
// validates if it should fail the sync on that revision if it finds shared resources
|
||||
syncRes.Revision = compareResult.syncStatus.Revision
|
||||
syncRes.Revisions = compareResult.syncStatus.Revisions
|
||||
|
||||
// validates if it should fail the sync if it finds shared resources
|
||||
hasSharedResource, sharedResourceMessage := hasSharedResourceCondition(app)
|
||||
if syncOp.SyncOptions.HasOption("FailOnSharedResource=true") && hasSharedResource {
|
||||
if syncOp.SyncOptions.HasOption("FailOnSharedResource=true") &&
|
||||
hasSharedResource {
|
||||
state.Phase = common.OperationFailed
|
||||
state.Message = "Shared resource found: " + sharedResourceMessage
|
||||
state.Message = "Shared resource found: %s" + sharedResourceMessage
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -217,8 +246,15 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, project *v1alp
|
|||
return
|
||||
}
|
||||
|
||||
initialResourcesRes := make([]common.ResourceSyncResult, len(state.SyncResult.Resources))
|
||||
for i, res := range state.SyncResult.Resources {
|
||||
syncId, err := syncid.Generate()
|
||||
if err != nil {
|
||||
state.Phase = common.OperationError
|
||||
state.Message = fmt.Sprintf("Failed to generate sync ID: %v", err)
|
||||
return
|
||||
}
|
||||
logEntry := log.WithFields(applog.GetAppLogFields(app)).WithField("syncId", syncId)
|
||||
initialResourcesRes := make([]common.ResourceSyncResult, len(syncRes.Resources))
|
||||
for i, res := range syncRes.Resources {
|
||||
key := kube.ResourceKey{Group: res.Group, Kind: res.Kind, Namespace: res.Namespace, Name: res.Name}
|
||||
initialResourcesRes[i] = common.ResourceSyncResult{
|
||||
ResourceKey: key,
|
||||
|
|
@ -288,7 +324,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, project *v1alp
|
|||
return
|
||||
}
|
||||
if impersonationEnabled {
|
||||
serviceAccountToImpersonate, err := deriveServiceAccountToImpersonate(project, app, destCluster)
|
||||
serviceAccountToImpersonate, err := deriveServiceAccountToImpersonate(proj, app, destCluster)
|
||||
if err != nil {
|
||||
state.Phase = common.OperationError
|
||||
state.Message = fmt.Sprintf("failed to find a matching service account to impersonate: %v", err)
|
||||
|
|
@ -308,11 +344,11 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, project *v1alp
|
|||
sync.WithLogr(logutils.NewLogrusLogger(logEntry)),
|
||||
sync.WithHealthOverride(lua.ResourceHealthOverrides(resourceOverrides)),
|
||||
sync.WithPermissionValidator(func(un *unstructured.Unstructured, res *metav1.APIResource) error {
|
||||
if !project.IsGroupKindPermitted(un.GroupVersionKind().GroupKind(), res.Namespaced) {
|
||||
return fmt.Errorf("resource %s:%s is not permitted in project %s", un.GroupVersionKind().Group, un.GroupVersionKind().Kind, project.Name)
|
||||
if !proj.IsGroupKindPermitted(un.GroupVersionKind().GroupKind(), res.Namespaced) {
|
||||
return fmt.Errorf("resource %s:%s is not permitted in project %s", un.GroupVersionKind().Group, un.GroupVersionKind().Kind, proj.Name)
|
||||
}
|
||||
if res.Namespaced {
|
||||
permitted, err := project.IsDestinationPermitted(destCluster, un.GetNamespace(), func(project string) ([]*v1alpha1.Cluster, error) {
|
||||
permitted, err := proj.IsDestinationPermitted(destCluster, un.GetNamespace(), func(project string) ([]*v1alpha1.Cluster, error) {
|
||||
return m.db.GetProjectClusters(context.TODO(), project)
|
||||
})
|
||||
if err != nil {
|
||||
|
|
@ -320,7 +356,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, project *v1alp
|
|||
}
|
||||
|
||||
if !permitted {
|
||||
return fmt.Errorf("namespace %v is not permitted in project '%s'", un.GetNamespace(), project.Name)
|
||||
return fmt.Errorf("namespace %v is not permitted in project '%s'", un.GetNamespace(), proj.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
@ -422,7 +458,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, project *v1alp
|
|||
logEntry.WithField("duration", time.Since(start)).Info("sync/terminate complete")
|
||||
|
||||
if !syncOp.DryRun && len(syncOp.Resources) == 0 && state.Phase.Successful() {
|
||||
err := m.persistRevisionHistory(app, compareResult.syncStatus.Revision, compareResult.syncStatus.ComparedTo.Source, compareResult.syncStatus.Revisions, compareResult.syncStatus.ComparedTo.Sources, isMultiSourceSync, state.StartedAt, state.Operation.InitiatedBy)
|
||||
err := m.persistRevisionHistory(app, compareResult.syncStatus.Revision, source, compareResult.syncStatus.Revisions, compareResult.syncStatus.ComparedTo.Sources, isMultiSourceRevision, state.StartedAt, state.Operation.InitiatedBy)
|
||||
if err != nil {
|
||||
state.Phase = common.OperationError
|
||||
state.Message = fmt.Sprintf("failed to record sync to history: %v", err)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func TestPersistRevisionHistory(t *testing.T) {
|
|||
opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{
|
||||
Sync: &v1alpha1.SyncOperation{},
|
||||
}}
|
||||
ctrl.appStateManager.SyncAppState(app, defaultProject, opState)
|
||||
ctrl.appStateManager.SyncAppState(app, opState)
|
||||
// Ensure we record spec.source into sync result
|
||||
assert.Equal(t, app.Spec.GetSource(), opState.SyncResult.Source)
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ func TestPersistManagedNamespaceMetadataState(t *testing.T) {
|
|||
opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{
|
||||
Sync: &v1alpha1.SyncOperation{},
|
||||
}}
|
||||
ctrl.appStateManager.SyncAppState(app, defaultProject, opState)
|
||||
ctrl.appStateManager.SyncAppState(app, opState)
|
||||
// Ensure we record spec.syncPolicy.managedNamespaceMetadata into sync result
|
||||
assert.Equal(t, app.Spec.SyncPolicy.ManagedNamespaceMetadata, opState.SyncResult.ManagedNamespaceMetadata)
|
||||
}
|
||||
|
|
@ -139,7 +139,7 @@ func TestPersistRevisionHistoryRollback(t *testing.T) {
|
|||
Source: &source,
|
||||
},
|
||||
}}
|
||||
ctrl.appStateManager.SyncAppState(app, defaultProject, opState)
|
||||
ctrl.appStateManager.SyncAppState(app, opState)
|
||||
// Ensure we record opState's source into sync result
|
||||
assert.Equal(t, source, opState.SyncResult.Source)
|
||||
|
||||
|
|
@ -182,7 +182,7 @@ func TestSyncComparisonError(t *testing.T) {
|
|||
Sync: &v1alpha1.SyncOperation{},
|
||||
}}
|
||||
t.Setenv("ARGOCD_GPG_ENABLED", "true")
|
||||
ctrl.appStateManager.SyncAppState(app, defaultProject, opState)
|
||||
ctrl.appStateManager.SyncAppState(app, opState)
|
||||
|
||||
conditions := app.Status.GetConditions(map[v1alpha1.ApplicationConditionType]bool{v1alpha1.ApplicationConditionComparisonError: true})
|
||||
assert.NotEmpty(t, conditions)
|
||||
|
|
@ -194,7 +194,6 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
|
|||
|
||||
type fixture struct {
|
||||
application *v1alpha1.Application
|
||||
project *v1alpha1.AppProject
|
||||
controller *ApplicationController
|
||||
}
|
||||
|
||||
|
|
@ -236,7 +235,6 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
|
|||
|
||||
return &fixture{
|
||||
application: app,
|
||||
project: project,
|
||||
controller: ctrl,
|
||||
}
|
||||
}
|
||||
|
|
@ -271,7 +269,7 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
|
|||
}}
|
||||
|
||||
// when
|
||||
f.controller.appStateManager.SyncAppState(f.application, f.project, opState)
|
||||
f.controller.appStateManager.SyncAppState(f.application, opState)
|
||||
|
||||
// then
|
||||
assert.Equal(t, synccommon.OperationFailed, opState.Phase)
|
||||
|
|
@ -284,7 +282,6 @@ func TestSyncWindowDeniesSync(t *testing.T) {
|
|||
|
||||
type fixture struct {
|
||||
application *v1alpha1.Application
|
||||
project *v1alpha1.AppProject
|
||||
controller *ApplicationController
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +320,6 @@ func TestSyncWindowDeniesSync(t *testing.T) {
|
|||
|
||||
return &fixture{
|
||||
application: app,
|
||||
project: project,
|
||||
controller: ctrl,
|
||||
}
|
||||
}
|
||||
|
|
@ -343,7 +339,7 @@ func TestSyncWindowDeniesSync(t *testing.T) {
|
|||
Phase: synccommon.OperationRunning,
|
||||
}
|
||||
// when
|
||||
f.controller.appStateManager.SyncAppState(f.application, f.project, opState)
|
||||
f.controller.appStateManager.SyncAppState(f.application, opState)
|
||||
|
||||
// then
|
||||
assert.Equal(t, synccommon.OperationRunning, opState.Phase)
|
||||
|
|
@ -1366,7 +1362,6 @@ func TestDeriveServiceAccountMatchingServers(t *testing.T) {
|
|||
func TestSyncWithImpersonate(t *testing.T) {
|
||||
type fixture struct {
|
||||
application *v1alpha1.Application
|
||||
project *v1alpha1.AppProject
|
||||
controller *ApplicationController
|
||||
}
|
||||
|
||||
|
|
@ -1416,7 +1411,6 @@ func TestSyncWithImpersonate(t *testing.T) {
|
|||
ctrl := newFakeController(&data, nil)
|
||||
return &fixture{
|
||||
application: app,
|
||||
project: project,
|
||||
controller: ctrl,
|
||||
}
|
||||
}
|
||||
|
|
@ -1435,7 +1429,7 @@ func TestSyncWithImpersonate(t *testing.T) {
|
|||
Phase: synccommon.OperationRunning,
|
||||
}
|
||||
// when
|
||||
f.controller.appStateManager.SyncAppState(f.application, f.project, opState)
|
||||
f.controller.appStateManager.SyncAppState(f.application, opState)
|
||||
|
||||
// then, app sync should fail with expected error message in operation state
|
||||
assert.Equal(t, synccommon.OperationError, opState.Phase)
|
||||
|
|
@ -1456,7 +1450,7 @@ func TestSyncWithImpersonate(t *testing.T) {
|
|||
Phase: synccommon.OperationRunning,
|
||||
}
|
||||
// when
|
||||
f.controller.appStateManager.SyncAppState(f.application, f.project, opState)
|
||||
f.controller.appStateManager.SyncAppState(f.application, opState)
|
||||
|
||||
// then app sync should fail with expected error message in operation state
|
||||
assert.Equal(t, synccommon.OperationError, opState.Phase)
|
||||
|
|
@ -1477,7 +1471,7 @@ func TestSyncWithImpersonate(t *testing.T) {
|
|||
Phase: synccommon.OperationRunning,
|
||||
}
|
||||
// when
|
||||
f.controller.appStateManager.SyncAppState(f.application, f.project, opState)
|
||||
f.controller.appStateManager.SyncAppState(f.application, opState)
|
||||
|
||||
// then app sync should not fail
|
||||
assert.Equal(t, synccommon.OperationSucceeded, opState.Phase)
|
||||
|
|
@ -1498,7 +1492,7 @@ func TestSyncWithImpersonate(t *testing.T) {
|
|||
Phase: synccommon.OperationRunning,
|
||||
}
|
||||
// when
|
||||
f.controller.appStateManager.SyncAppState(f.application, f.project, opState)
|
||||
f.controller.appStateManager.SyncAppState(f.application, opState)
|
||||
|
||||
// then application sync should pass using the control plane service account
|
||||
assert.Equal(t, synccommon.OperationSucceeded, opState.Phase)
|
||||
|
|
@ -1523,7 +1517,7 @@ func TestSyncWithImpersonate(t *testing.T) {
|
|||
f.application.Spec.Destination.Name = "minikube"
|
||||
|
||||
// when
|
||||
f.controller.appStateManager.SyncAppState(f.application, f.project, opState)
|
||||
f.controller.appStateManager.SyncAppState(f.application, opState)
|
||||
|
||||
// then app sync should not fail
|
||||
assert.Equal(t, synccommon.OperationSucceeded, opState.Phase)
|
||||
|
|
@ -1536,7 +1530,6 @@ func TestClientSideApplyMigration(t *testing.T) {
|
|||
|
||||
type fixture struct {
|
||||
application *v1alpha1.Application
|
||||
project *v1alpha1.AppProject
|
||||
controller *ApplicationController
|
||||
}
|
||||
|
||||
|
|
@ -1577,7 +1570,6 @@ func TestClientSideApplyMigration(t *testing.T) {
|
|||
|
||||
return &fixture{
|
||||
application: app,
|
||||
project: project,
|
||||
controller: ctrl,
|
||||
}
|
||||
}
|
||||
|
|
@ -1593,7 +1585,7 @@ func TestClientSideApplyMigration(t *testing.T) {
|
|||
Source: &v1alpha1.ApplicationSource{},
|
||||
},
|
||||
}}
|
||||
f.controller.appStateManager.SyncAppState(f.application, f.project, opState)
|
||||
f.controller.appStateManager.SyncAppState(f.application, opState)
|
||||
|
||||
// then
|
||||
assert.Equal(t, synccommon.OperationSucceeded, opState.Phase)
|
||||
|
|
@ -1611,7 +1603,7 @@ func TestClientSideApplyMigration(t *testing.T) {
|
|||
Source: &v1alpha1.ApplicationSource{},
|
||||
},
|
||||
}}
|
||||
f.controller.appStateManager.SyncAppState(f.application, f.project, opState)
|
||||
f.controller.appStateManager.SyncAppState(f.application, opState)
|
||||
|
||||
// then
|
||||
assert.Equal(t, synccommon.OperationSucceeded, opState.Phase)
|
||||
|
|
@ -1629,7 +1621,7 @@ func TestClientSideApplyMigration(t *testing.T) {
|
|||
Source: &v1alpha1.ApplicationSource{},
|
||||
},
|
||||
}}
|
||||
f.controller.appStateManager.SyncAppState(f.application, f.project, opState)
|
||||
f.controller.appStateManager.SyncAppState(f.application, opState)
|
||||
|
||||
// then
|
||||
assert.Equal(t, synccommon.OperationSucceeded, opState.Phase)
|
||||
|
|
|
|||
|
|
@ -133,15 +133,6 @@ spec:
|
|||
- pullRequest:
|
||||
# When using a Pull Request generator, the ApplicationSet controller polls every `requeueAfterSeconds` interval (defaulting to every 30 minutes) to detect changes.
|
||||
requeueAfterSeconds: 1800
|
||||
# When set to true, the ApplicationSet controller will continue to generate Applications even if the repository is not found, and will not enter a failed state.
|
||||
# One example use case is when a pull request generator is combined with a Git generator in a matrix generator.
|
||||
# NOTE, that if a repository exists but is inaccessible due to
|
||||
# access rights, SCM providers usually return a "404 Not Found" error
|
||||
# instead of a "403 Permission Denied" error. Consequently, using this
|
||||
# option may lead to the deletion of Argo CD applications if the SCM
|
||||
# user associated with the token loses access to the repository.
|
||||
|
||||
continueOnRepoNotFoundError: false
|
||||
# See below for provider specific options.
|
||||
# Specify the repository from which to fetch the GitHub Pull requests.
|
||||
github:
|
||||
|
|
@ -334,4 +325,4 @@ spec:
|
|||
jqPathExpressions:
|
||||
- .spec.source.helm.values
|
||||
|
||||
|
||||
|
||||
|
|
@ -283,7 +283,7 @@ data:
|
|||
# Comma delimited list of labels to preserve in generated applications
|
||||
applicationsetcontroller.global.preserved.labels: "acme.com/label1,acme.com/label2"
|
||||
# Enable GitHub API metrics for generators that use GitHub API
|
||||
applicationsetcontroller.enable.github.api.metrics: "false"
|
||||
applicationsetcontroller.enable.github.api.metrics: "true"
|
||||
|
||||
## Argo CD Notifications Controller Properties
|
||||
# Set the logging level. One of: debug|info|warn|error (default "info")
|
||||
|
|
|
|||
|
|
@ -1007,15 +1007,15 @@ Azure cluster secret example using argocd-k8s-auth and [kubelogin](https://githu
|
|||
|Variable Name|Description|
|
||||
|-------------|-----------|
|
||||
|AAD_LOGIN_METHOD|One of devicecode, spn, ropc, msi, azurecli, or workloadidentity|
|
||||
|AZURE_CLIENT_CERTIFICATE_PATH|Path to AAD client cert in pfx. Used in spn login and WorkloadIdentityLogin flow|
|
||||
|AZURE_CLIENT_CERTIFICATE_PASSWORD|Password for the client cert in pfx. Used in spn login|
|
||||
|AZURE_CLIENT_ID|AAD client application ID|
|
||||
|AZURE_CLIENT_SECRET|AAD client application secret|
|
||||
|AAD_SERVICE_PRINCIPAL_CLIENT_CERTIFICATE|AAD client cert in pfx. Used in spn login|
|
||||
|AAD_SERVICE_PRINCIPAL_CLIENT_ID|AAD client application ID|
|
||||
|AAD_SERVICE_PRINCIPAL_CLIENT_SECRET|AAD client application secret|
|
||||
|AAD_USER_PRINCIPAL_NAME|Used in the ropc flow|
|
||||
|AAD_USER_PRINCIPAL_PASSWORD|Used in the ropc flow|
|
||||
|AZURE_TENANT_ID|The AAD tenant ID.|
|
||||
|AZURE_AUTHORITY_HOST|Used in the WorkloadIdentityLogin flow|
|
||||
|AZURE_FEDERATED_TOKEN_FILE|Used in the WorkloadIdentityLogin flow|
|
||||
|AZURE_CLIENT_ID|Used in the WorkloadIdentityLogin flow|
|
||||
|
||||
In addition to the environment variables above, argocd-k8s-auth accepts two extra environment variables to set the AAD environment, and to set the AAD server application ID. The AAD server application ID will default to 6dae42f8-4368-4678-94ff-3960e28e3630 if not specified. See [here](https://github.com/azure/kubelogin#exec-plugin-format) for details.
|
||||
|
||||
|
|
@ -1089,9 +1089,9 @@ stringData:
|
|||
"command": "argocd-k8s-auth",
|
||||
"env": {
|
||||
"AAD_ENVIRONMENT_NAME": "AzurePublicCloud",
|
||||
"AZURE_CLIENT_SECRET": "fill in your service principal client secret",
|
||||
"AAD_SERVICE_PRINCIPAL_CLIENT_SECRET": "fill in your service principal client secret",
|
||||
"AZURE_TENANT_ID": "fill in tenant id",
|
||||
"AZURE_CLIENT_ID": "fill in your service principal client id",
|
||||
"AAD_SERVICE_PRINCIPAL_CLIENT_ID": "fill in your service principal client id",
|
||||
"AAD_LOGIN_METHOD": "spn"
|
||||
},
|
||||
"args": ["azure"],
|
||||
|
|
|
|||
|
|
@ -210,9 +210,8 @@ argocd_cluster_labels{label_environment="production",label_team_name="team3",nam
|
|||
Metrics about API Server API request and response activity (request totals, response codes, etc...).
|
||||
Scraped at the `argocd-server-metrics:8083/metrics` endpoint.
|
||||
|
||||
| Metric | Type | Description
|
||||
|---------------------------------------------------|:---------:|---------------------------------------------------------------------------------------------|
|
||||
| `argocd_login_request_total` | counter | Number of login requests. |
|
||||
| Metric | Type | Description |
|
||||
| ------------------------------------------------- | :-------: | ------------------------------------------------------------------------------------------- |
|
||||
| `argocd_redis_request_duration` | histogram | Redis requests duration. |
|
||||
| `argocd_redis_request_total` | counter | Number of Kubernetes requests executed during application reconciliation. |
|
||||
| `grpc_server_handled_total` | counter | Total number of RPCs completed on the server, regardless of success or failure. |
|
||||
|
|
|
|||
|
|
@ -1,2 +1,5 @@
|
|||
This page is populated for released Argo CD versions. Use the version selector to view this table for a specific
|
||||
version.
|
||||
| Argo CD version | Kubernetes versions |
|
||||
|-----------------|---------------------|
|
||||
| 3.1 | v1.33, v1.32, v1.31, v1.30 |
|
||||
| 3.0 | v1.32, v1.31, v1.30, v1.29 |
|
||||
| 2.14 | v1.31, v1.30, v1.29, v1.28 |
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ most recent minor versions (so 2.14 until 3.2 is released and 2.13 until 3.1 is
|
|||
## Images missing release notes on GitHub
|
||||
|
||||
!!! important
|
||||
Images 3.0.7 - 3.0.10 are missing release notes on GitHub. There was an issue with GoReleaser and building the darwin
|
||||
Images 3.0.7 - 3.0.9 are missing release notes on GitHub. There was an issue with GoReleaser and building the darwin
|
||||
CLI that prevented the release notes from being published. More information can be found
|
||||
on [PR #23507](https://github.com/argoproj/argo-cd/pull/23507)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## No more KubeVersions variable modification
|
||||
|
||||
Until v3.0, Argo CD removed `+` identifier from `kubeVersions` in Helm, Kustomize and Plugins. For example, if Argo CD receive `kubeVersions` as vX.Y.Z+, we convert to vX.Y.Z internally. Starting with v3.1, the internal conversion is entirely removed.
|
||||
Until v3.0, Argo CD removed `+` identifier from `kubeVersions` in Helm, Kustomize and Plugins. For example, if Argo CD receive `kubeVersions` as vX.Y.Z+, we convert to vX.Y.Z internally. Starting with v3.1, the internal conversation is entirely removed.
|
||||
|
||||
### Detection
|
||||
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
# v3.1 to 3.2
|
||||
|
||||
## Argo CD Now Respects Kustomize Version in `.argocd-source.yaml`
|
||||
|
||||
Argo CD provides a way to [override Application `spec.source` values](../../user-guide/parameters.md#store-overrides-in-git)
|
||||
using the `.argocd-source.yaml` file.
|
||||
|
||||
Before Argo CD v3.2, you could set the Kustomize version in the Application's `.spec.source.kustomize.version` field,
|
||||
but you could not set it in the `.argocd-source.yaml` file.
|
||||
|
||||
Starting with Argo CD v3.2, you can now set the Kustomize version in the `.argocd-source.yaml` file like this:
|
||||
|
||||
```yaml
|
||||
kustomize:
|
||||
version: v4.5.7
|
||||
```
|
||||
|
||||
## Deprecated fields in the repo-server GRPC service
|
||||
|
||||
The repo-server's GRPC service is generally considered an internal API and is not recommended for use by external
|
||||
clients. No user-facing services or functionality have changed. However, if you are using the repo-server's GRPC service
|
||||
directly, please note field deprecations in the following messages.
|
||||
|
||||
The `kustomizeOptions.binaryPath` field in the `ManifestRequest` and `RepoServerAppDetailsQuery` messages has been
|
||||
deprecated. Instead of calculating the correct binary path client-side, the client is expected to populate the
|
||||
`kustomizeOptions.versions` field with the [configured Kustomize binary paths](../../user-guide/kustomize.md#custom-kustomize-versions).
|
||||
This allows the repo-server to select the correct binary path based on the Kustomize version configured in the
|
||||
Application's source field as well as any [overrides configured via git](../../user-guide/parameters.md#store-overrides-in-git).
|
||||
|
||||
The `kustomizeOptions.binaryPath` will continue to be respected when `kustomizeOptions.versions` is not set, but this is
|
||||
not recommended. It will prevent overrides configured via git from being respected. The `kustomizeOptions.binaryPath`
|
||||
field will be removed in a future release.
|
||||
|
||||
If the repo-server encounters a request with the `kustomizeOptions.binaryPath` field set, it will log a warning message:
|
||||
|
||||
> kustomizeOptions.binaryPath is deprecated, use KustomizeOptions.versions instead
|
||||
|
||||
The `ManifestRequest` and `RepoServerAppDetailsQuery` messages are used by the following GRPC services:
|
||||
`GenerateManifest`, `GenerateManifestWithFiles`, and `GetAppDetails`.
|
||||
|
|
@ -38,7 +38,6 @@ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/<v
|
|||
|
||||
<hr/>
|
||||
|
||||
- [v3.1 to v3.2](./3.1-3.2.md)
|
||||
- [v3.0 to v3.1](./3.0-3.1.md)
|
||||
- [v2.14 to v3.0](./2.14-3.0.md)
|
||||
- [v2.13 to v2.14](./2.13-2.14.md)
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@
|
|||
requestedIDTokenClaims:
|
||||
groups:
|
||||
essential: true
|
||||
value: "ApplicationGroup"
|
||||
value: "SecurityGroup"
|
||||
requestedScopes:
|
||||
- openid
|
||||
- profile
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ To create the application, do the following:
|
|||
2. Click "Add App".
|
||||
3. Search for "OpenID Connect" in the search field.
|
||||
4. Select the "OpenId Connect (OIDC)" app to create.
|
||||
5. Update the "Display Name" field (could be something like "ArgoCD (Production)").
|
||||
5. Update the "Display Name" field (could be something like "ArgoCD (Production)".
|
||||
6. Click "Save".
|
||||
|
||||
### Configuring OIDC Application Settings
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ mkdocs==1.6.1
|
|||
# Thus pointing to the older version of mkdocs-material.
|
||||
mkdocs-material==7.1.8
|
||||
markdown_include==0.8.1
|
||||
pygments==2.19.2
|
||||
pygments==2.19.1
|
||||
jinja2==3.1.6
|
||||
markdown==3.8.2
|
||||
pymdown-extensions==10.16
|
||||
markdown==3.8.1
|
||||
pymdown-extensions==10.15
|
||||
|
|
@ -18,50 +18,37 @@ recent minor releases.
|
|||
| [dex:v2.43.0](master/ghcr.io_dexidp_dex_v2.43.0.html) | 0 | 0 | 0 | 0 |
|
||||
| [haproxy:3.0.8-alpine](master/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [redis:7.2.7-alpine](master/public.ecr.aws_docker_library_redis_7.2.7-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [argocd:latest](master/quay.io_argoproj_argocd_latest.html) | 0 | 0 | 9 | 7 |
|
||||
| [argocd:latest](master/quay.io_argoproj_argocd_latest.html) | 0 | 0 | 4 | 9 |
|
||||
| [install.yaml](master/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](master/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
|
||||
### v3.1.0-rc3
|
||||
### v3.0.6
|
||||
|
||||
| | Critical | High | Medium | Low |
|
||||
|---:|:--------:|:----:|:------:|:---:|
|
||||
| [go.mod](v3.1.0-rc3/argocd-test.html) | 0 | 0 | 5 | 0 |
|
||||
| [ui/yarn.lock](v3.1.0-rc3/argocd-test.html) | 0 | 0 | 1 | 2 |
|
||||
| [dex:v2.43.0](v3.1.0-rc3/ghcr.io_dexidp_dex_v2.43.0.html) | 0 | 0 | 0 | 0 |
|
||||
| [haproxy:3.0.8-alpine](v3.1.0-rc3/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [redis:7.2.7-alpine](v3.1.0-rc3/public.ecr.aws_docker_library_redis_7.2.7-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [argocd:v3.1.0-rc3](v3.1.0-rc3/quay.io_argoproj_argocd_v3.1.0-rc3.html) | 0 | 0 | 8 | 9 |
|
||||
| [install.yaml](v3.1.0-rc3/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](v3.1.0-rc3/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
| [go.mod](v3.0.6/argocd-test.html) | 0 | 3 | 7 | 0 |
|
||||
| [ui/yarn.lock](v3.0.6/argocd-test.html) | 0 | 1 | 2 | 4 |
|
||||
| [dex:v2.41.1](v3.0.6/ghcr.io_dexidp_dex_v2.41.1.html) | 0 | 1 | 0 | 4 |
|
||||
| [haproxy:3.0.8-alpine](v3.0.6/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [redis:7.2.7-alpine](v3.0.6/public.ecr.aws_docker_library_redis_7.2.7-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [argocd:v3.0.6](v3.0.6/quay.io_argoproj_argocd_v3.0.6.html) | 0 | 0 | 4 | 9 |
|
||||
| [redis:7.2.7-alpine](v3.0.6/redis_7.2.7-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [install.yaml](v3.0.6/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](v3.0.6/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
|
||||
### v3.0.11
|
||||
### v2.14.14
|
||||
|
||||
| | Critical | High | Medium | Low |
|
||||
|---:|:--------:|:----:|:------:|:---:|
|
||||
| [go.mod](v3.0.11/argocd-test.html) | 0 | 3 | 5 | 0 |
|
||||
| [ui/yarn.lock](v3.0.11/argocd-test.html) | 0 | 1 | 2 | 4 |
|
||||
| [dex:v2.41.1](v3.0.11/ghcr.io_dexidp_dex_v2.41.1.html) | 0 | 1 | 0 | 4 |
|
||||
| [haproxy:3.0.8-alpine](v3.0.11/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [redis:7.2.7-alpine](v3.0.11/public.ecr.aws_docker_library_redis_7.2.7-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [argocd:v3.0.11](v3.0.11/quay.io_argoproj_argocd_v3.0.11.html) | 0 | 0 | 8 | 9 |
|
||||
| [redis:7.2.7-alpine](v3.0.11/redis_7.2.7-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [install.yaml](v3.0.11/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](v3.0.11/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
|
||||
### v2.14.15
|
||||
|
||||
| | Critical | High | Medium | Low |
|
||||
|---:|:--------:|:----:|:------:|:---:|
|
||||
| [go.mod](v2.14.15/argocd-test.html) | 0 | 1 | 8 | 0 |
|
||||
| [ui/yarn.lock](v2.14.15/argocd-test.html) | 0 | 0 | 2 | 3 |
|
||||
| [dex:v2.41.1](v2.14.15/ghcr.io_dexidp_dex_v2.41.1.html) | 0 | 1 | 0 | 4 |
|
||||
| [haproxy:2.6.17-alpine](v2.14.15/public.ecr.aws_docker_library_haproxy_2.6.17-alpine.html) | 0 | 1 | 2 | 6 |
|
||||
| [redis:7.0.15-alpine](v2.14.15/public.ecr.aws_docker_library_redis_7.0.15-alpine.html) | 0 | 0 | 0 | 4 |
|
||||
| [argocd:v2.14.15](v2.14.15/quay.io_argoproj_argocd_v2.14.15.html) | 0 | 0 | 21 | 9 |
|
||||
| [redis:7.0.15-alpine](v2.14.15/redis_7.0.15-alpine.html) | 0 | 0 | 0 | 4 |
|
||||
| [install.yaml](v2.14.15/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](v2.14.15/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
| [go.mod](v2.14.14/argocd-test.html) | 0 | 1 | 8 | 0 |
|
||||
| [ui/yarn.lock](v2.14.14/argocd-test.html) | 0 | 0 | 2 | 3 |
|
||||
| [dex:v2.41.1](v2.14.14/ghcr.io_dexidp_dex_v2.41.1.html) | 0 | 1 | 0 | 4 |
|
||||
| [haproxy:2.6.17-alpine](v2.14.14/public.ecr.aws_docker_library_haproxy_2.6.17-alpine.html) | 0 | 1 | 2 | 6 |
|
||||
| [redis:7.0.15-alpine](v2.14.14/public.ecr.aws_docker_library_redis_7.0.15-alpine.html) | 0 | 0 | 0 | 4 |
|
||||
| [argocd:v2.14.14](v2.14.14/quay.io_argoproj_argocd_v2.14.14.html) | 0 | 0 | 4 | 9 |
|
||||
| [redis:7.0.15-alpine](v2.14.14/redis_7.0.15-alpine.html) | 0 | 0 | 0 | 4 |
|
||||
| [install.yaml](v2.14.14/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](v2.14.14/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
|
||||
### v2.13.8
|
||||
|
||||
|
|
@ -72,7 +59,7 @@ recent minor releases.
|
|||
| [dex:v2.41.1](v2.13.8/ghcr.io_dexidp_dex_v2.41.1.html) | 0 | 1 | 0 | 4 |
|
||||
| [haproxy:2.6.17-alpine](v2.13.8/public.ecr.aws_docker_library_haproxy_2.6.17-alpine.html) | 0 | 1 | 2 | 6 |
|
||||
| [redis:7.0.15-alpine](v2.13.8/public.ecr.aws_docker_library_redis_7.0.15-alpine.html) | 0 | 0 | 0 | 4 |
|
||||
| [argocd:v2.13.8](v2.13.8/quay.io_argoproj_argocd_v2.13.8.html) | 0 | 0 | 23 | 9 |
|
||||
| [argocd:v2.13.8](v2.13.8/quay.io_argoproj_argocd_v2.13.8.html) | 0 | 0 | 5 | 9 |
|
||||
| [redis:7.0.15-alpine](v2.13.8/redis_7.0.15-alpine.html) | 0 | 0 | 0 | 4 |
|
||||
| [install.yaml](v2.13.8/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](v2.13.8/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -456,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:26:39 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:25:46 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
|
|
@ -507,7 +507,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 24394
|
||||
Line number: 24380
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -553,7 +553,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 24074
|
||||
Line number: 24060
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -599,7 +599,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 24162
|
||||
Line number: 24148
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -645,7 +645,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 24190
|
||||
Line number: 24176
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -691,7 +691,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 24220
|
||||
Line number: 24206
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -737,7 +737,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 24238
|
||||
Line number: 24224
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -783,7 +783,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 24256
|
||||
Line number: 24242
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -829,7 +829,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 24278
|
||||
Line number: 24264
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -881,7 +881,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25486
|
||||
Line number: 25466
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -933,7 +933,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25805
|
||||
Line number: 25785
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -991,7 +991,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 24981
|
||||
Line number: 24967
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1049,7 +1049,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25282
|
||||
Line number: 25262
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1107,7 +1107,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25230
|
||||
Line number: 25210
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1165,7 +1165,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25344
|
||||
Line number: 25324
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1223,7 +1223,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25457
|
||||
Line number: 25437
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1281,7 +1281,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25481
|
||||
Line number: 25461
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1339,7 +1339,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25805
|
||||
Line number: 25785
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1397,7 +1397,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25540
|
||||
Line number: 25520
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1455,7 +1455,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25892
|
||||
Line number: 25872
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1513,7 +1513,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 26302
|
||||
Line number: 26276
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1565,7 +1565,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25262
|
||||
Line number: 25242
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1617,7 +1617,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 24981
|
||||
Line number: 24967
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1669,7 +1669,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25230
|
||||
Line number: 25210
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1721,7 +1721,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25457
|
||||
Line number: 25437
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1779,7 +1779,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 24981
|
||||
Line number: 24967
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1837,7 +1837,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25230
|
||||
Line number: 25210
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1895,7 +1895,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25282
|
||||
Line number: 25262
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1953,7 +1953,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25344
|
||||
Line number: 25324
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2011,7 +2011,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25457
|
||||
Line number: 25437
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2069,7 +2069,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25481
|
||||
Line number: 25461
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2127,7 +2127,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25805
|
||||
Line number: 25785
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2185,7 +2185,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25540
|
||||
Line number: 25520
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2243,7 +2243,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25892
|
||||
Line number: 25872
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2301,7 +2301,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 26302
|
||||
Line number: 26276
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2357,7 +2357,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25152
|
||||
Line number: 25132
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2413,7 +2413,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25290
|
||||
Line number: 25270
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2469,7 +2469,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25265
|
||||
Line number: 25245
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2525,7 +2525,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25389
|
||||
Line number: 25369
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2581,7 +2581,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25474
|
||||
Line number: 25454
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2637,7 +2637,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25488
|
||||
Line number: 25468
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2693,7 +2693,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25812
|
||||
Line number: 25792
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2749,7 +2749,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 25778
|
||||
Line number: 25758
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2805,7 +2805,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 26201
|
||||
Line number: 26175
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2861,7 +2861,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 26571
|
||||
Line number: 26539
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -456,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:26:49 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:25:58 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
|
|
@ -835,7 +835,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1275
|
||||
Line number: 1269
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -887,7 +887,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1594
|
||||
Line number: 1588
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1003,7 +1003,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1071
|
||||
Line number: 1065
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1061,7 +1061,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1019
|
||||
Line number: 1013
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1119,7 +1119,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1133
|
||||
Line number: 1127
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1177,7 +1177,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1246
|
||||
Line number: 1240
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1235,7 +1235,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1270
|
||||
Line number: 1264
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1293,7 +1293,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1594
|
||||
Line number: 1588
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1351,7 +1351,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1329
|
||||
Line number: 1323
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1409,7 +1409,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1681
|
||||
Line number: 1675
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1467,7 +1467,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 2091
|
||||
Line number: 2079
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1519,7 +1519,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1051
|
||||
Line number: 1045
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1623,7 +1623,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1019
|
||||
Line number: 1013
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1675,7 +1675,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1246
|
||||
Line number: 1240
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1791,7 +1791,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1019
|
||||
Line number: 1013
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1849,7 +1849,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1071
|
||||
Line number: 1065
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1907,7 +1907,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1133
|
||||
Line number: 1127
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -1965,7 +1965,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1246
|
||||
Line number: 1240
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2023,7 +2023,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1270
|
||||
Line number: 1264
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2081,7 +2081,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1594
|
||||
Line number: 1588
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2139,7 +2139,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1329
|
||||
Line number: 1323
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2197,7 +2197,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1681
|
||||
Line number: 1675
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2255,7 +2255,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 2091
|
||||
Line number: 2079
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2311,7 +2311,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 941
|
||||
Line number: 935
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2367,7 +2367,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1079
|
||||
Line number: 1073
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2423,7 +2423,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1054
|
||||
Line number: 1048
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2479,7 +2479,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1178
|
||||
Line number: 1172
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2535,7 +2535,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1263
|
||||
Line number: 1257
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2591,7 +2591,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1277
|
||||
Line number: 1271
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2647,7 +2647,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1601
|
||||
Line number: 1595
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2703,7 +2703,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1567
|
||||
Line number: 1561
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2759,7 +2759,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1990
|
||||
Line number: 1978
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -2815,7 +2815,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 2360
|
||||
Line number: 2342
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:24:27 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:23:32 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
|
|
@ -501,7 +470,7 @@
|
|||
<div class="meta-counts">
|
||||
<div class="meta-count"><span>8</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>28 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>2106</span> <span>dependencies</span></div>
|
||||
<div class="meta-count"><span>2104</span> <span>dependencies</span></div>
|
||||
</div><!-- .meta-counts -->
|
||||
</div><!-- .layout-container--short -->
|
||||
</header><!-- .project__header -->
|
||||
|
|
@ -513,10 +482,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -575,10 +542,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -639,10 +604,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -662,7 +625,7 @@
|
|||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
github.com/argoproj/argo-cd/v3@0.0.0 and github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/argoproj/argo-cd/v3@0.0.0 and github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -677,7 +640,7 @@
|
|||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
|
||||
</span>
|
||||
|
||||
|
|
@ -688,7 +651,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/argoproj/notifications-engine/pkg/services@#87bf0576a872
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
|
||||
</span>
|
||||
|
||||
|
|
@ -697,9 +660,9 @@
|
|||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
gitlab.com/gitlab-org/api/client-go@0.134.0
|
||||
gitlab.com/gitlab-org/api/client-go@0.130.1
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
|
||||
</span>
|
||||
|
||||
|
|
@ -712,7 +675,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/argoproj/notifications-engine/pkg/services@#87bf0576a872
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
|
||||
</span>
|
||||
|
||||
|
|
@ -725,7 +688,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/argoproj/notifications-engine/pkg/services@#87bf0576a872
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
|
||||
</span>
|
||||
|
||||
|
|
@ -738,7 +701,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
|
||||
</span>
|
||||
|
||||
|
|
@ -753,7 +716,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/argoproj/notifications-engine/pkg/services@#87bf0576a872
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
|
||||
</span>
|
||||
|
||||
|
|
@ -768,7 +731,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/argoproj/notifications-engine/pkg/services@#87bf0576a872
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
|
||||
</span>
|
||||
|
||||
|
|
@ -783,7 +746,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
|
||||
</span>
|
||||
|
||||
|
|
@ -798,7 +761,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
|
||||
</span>
|
||||
|
||||
|
|
@ -815,7 +778,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
|
||||
</span>
|
||||
|
||||
|
|
@ -832,7 +795,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
|
||||
</span>
|
||||
|
||||
|
|
@ -856,10 +819,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -880,7 +841,7 @@
|
|||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
|
||||
github.com/argoproj/argo-cd/v3@0.0.0, github.com/hashicorp/go-retryablehttp@0.7.8 and others
|
||||
github.com/argoproj/argo-cd/v3@0.0.0, github.com/hashicorp/go-retryablehttp@0.7.7 and others
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -894,7 +855,7 @@
|
|||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-cleanhttp@0.5.2
|
||||
|
||||
|
|
@ -905,7 +866,7 @@
|
|||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
gitlab.com/gitlab-org/api/client-go@0.134.0
|
||||
gitlab.com/gitlab-org/api/client-go@0.130.1
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-cleanhttp@0.5.2
|
||||
|
||||
|
|
@ -916,9 +877,9 @@
|
|||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
gitlab.com/gitlab-org/api/client-go@0.134.0
|
||||
gitlab.com/gitlab-org/api/client-go@0.130.1
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-cleanhttp@0.5.2
|
||||
|
||||
|
|
@ -933,7 +894,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-cleanhttp@0.5.2
|
||||
|
||||
|
|
@ -950,7 +911,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-cleanhttp@0.5.2
|
||||
|
||||
|
|
@ -967,7 +928,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-cleanhttp@0.5.2
|
||||
|
||||
|
|
@ -986,7 +947,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-cleanhttp@0.5.2
|
||||
|
||||
|
|
@ -1005,7 +966,7 @@
|
|||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-retryablehttp@0.7.8
|
||||
github.com/hashicorp/go-retryablehttp@0.7.7
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/go-cleanhttp@0.5.2
|
||||
|
||||
|
|
@ -1031,10 +992,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1093,10 +1052,8 @@
|
|||
<h2 class="card__title">Regular Expression Denial of Service (ReDoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1240,10 +1197,8 @@
|
|||
<h2 class="card__title">Insecure Randomness</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1312,10 +1267,8 @@
|
|||
<h2 class="card__title">Regular Expression Denial of Service (ReDoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Snyk test report</title>
|
||||
<meta name="description" content="25 known vulnerabilities found in 34 vulnerable dependency paths.">
|
||||
<meta name="description" content="24 known vulnerabilities found in 33 vulnerable dependency paths.">
|
||||
<base target="_blank">
|
||||
<link rel="icon" type="image/png" href="https://res.cloudinary.com/snyk/image/upload/v1468845142/favicon/favicon.png"
|
||||
sizes="194x194">
|
||||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:24:38 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:23:41 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
|
|
@ -500,8 +469,8 @@
|
|||
</div>
|
||||
|
||||
<div class="meta-counts">
|
||||
<div class="meta-count"><span>25</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>34 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>24</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>33 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>1131</span> <span>dependencies</span></div>
|
||||
</div><!-- .meta-counts -->
|
||||
</div><!-- .layout-container--short -->
|
||||
|
|
@ -514,10 +483,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -587,10 +554,8 @@
|
|||
<h2 class="card__title">Server-side Request Forgery (SSRF)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -660,10 +625,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -732,10 +695,8 @@
|
|||
<h2 class="card__title">Asymmetric Resource Consumption (Amplification)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -803,10 +764,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -865,10 +824,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -927,10 +884,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1052,10 +1007,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1123,10 +1076,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1185,10 +1136,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1247,10 +1196,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1318,10 +1265,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1380,10 +1325,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1442,10 +1385,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1504,10 +1445,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1566,10 +1505,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1628,10 +1565,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1690,10 +1625,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1752,10 +1685,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1814,10 +1745,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1876,10 +1805,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1938,10 +1865,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2000,10 +1925,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2062,10 +1985,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2130,77 +2051,6 @@
|
|||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--low" data-snyk-test="low">
|
||||
<h2 class="card__title">Synchronous Access of Remote Resource without Timeout</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: ghcr.io/dexidp/dex:v2.43.0/hairyhenderson/gomplate/v4 <span class="list-paths__item__arrow">›</span> /usr/local/bin/gomplate
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
github.com/hashicorp/vault/api
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
github.com/hairyhenderson/gomplate/v4@* and github.com/hashicorp/vault/api@v1.15.0
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/hairyhenderson/gomplate/v4@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/hashicorp/vault/api@v1.15.0
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Synchronous Access of Remote Resource without Timeout via the <code>rekey</code> and <code>recovery key</code> operations. An attacker can disrupt service availability by triggering uncontrolled cancellation actions during these processes, which can lead to denial of service.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>github.com/hashicorp/vault/api</code> to version 1.20.0 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/hashicorp/vault/commit/318f8582134a4a79a45ee2a6edad3072d865739b">GitHub Commit</a></li>
|
||||
<li><a href="https://github.com/hashicorp/vault/pull/30794">GitHub PR</a></li>
|
||||
<li><a href="https://discuss.hashicorp.com/t/hcsec-2025-11-vault-vulnerable-to-recovery-key-cancellation-denial-of-service/75570">HashiCorp Discuss</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMHASHICORPVAULTAPI-10562144">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
</div><!-- cards -->
|
||||
</div>
|
||||
</main><!-- .layout-stacked__content -->
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:24:43 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:23:46 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:24:48 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:23:51 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -456,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:37:15 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:33:38 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -456,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:37:25 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:33:47 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:35:08 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:31:33 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
|
|
@ -512,10 +481,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -844,10 +811,8 @@
|
|||
<h2 class="card__title">Server-side Request Forgery (SSRF)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -917,10 +882,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1223,10 +1186,8 @@
|
|||
<h2 class="card__title">LGPL-3.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1287,10 +1248,8 @@
|
|||
<h2 class="card__title">Improper Validation of Syntactic Correctness of Input</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1648,7 +1607,7 @@
|
|||
<p><a href="https://pkg.go.dev/golang.org/x/net/html">golang.org/x/net/html</a> is a package that implements an HTML5-compliant tokenizer and parser.</p>
|
||||
<p>Affected versions of this package are vulnerable to Improper Validation of Syntactic Correctness of Input in the tokenizer in <code>token.go</code>, which incorrectly interprets tags as closing tags, allowing malicious input to be incorrectly processed and the DOM to be corrupted.</p>
|
||||
<h2 id="details">Details</h2>
|
||||
<p>Cross-site scripting (or XSS) is a code vulnerability that occurs when an attacker “injects” a malicious script into an otherwise trusted website. The injected script gets downloaded and executed by the end user’s browser when the user interacts with the compromised website.</p>
|
||||
<p>A cross-site scripting attack occurs when the attacker tricks a legitimate web-based application or site to accept a request as originating from a trusted source.</p>
|
||||
<p>This is done by escaping the context of the web application; the web application then delivers that data to its users along with other trusted dynamic content, without validating it. The browser unknowingly executes malicious script on the client side (through client-side languages; usually JavaScript or HTML) in order to perform actions that are otherwise typically blocked by the browser’s Same Origin Policy.</p>
|
||||
<p>Injecting malicious code is the most prevalent manner by which XSS is exploited; for this reason, escaping characters in order to prevent this manipulation is the top method for securing code against this vulnerability.</p>
|
||||
<p>Escaping means that the application is coded to mark key characters, and particularly key characters included in user input, to prevent those characters from being interpreted in a dangerous context. For example, in HTML, <code><</code> can be coded as <code>&lt</code>; and <code>></code> can be coded as <code>&gt</code>; in order to be interpreted and displayed as themselves in text, while within the code itself, they are used for HTML tags. If malicious content is injected into an application that escapes special characters and that malicious content uses <code><</code> and <code>></code> as HTML tags, those characters are nonetheless not interpreted as HTML tags by the browser if they’ve been correctly escaped in the application code and in this way the attempted attack is diverted.</p>
|
||||
|
|
@ -1722,10 +1681,8 @@
|
|||
<h2 class="card__title">Unexpected Status Code or Return Value</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1805,10 +1762,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1867,10 +1822,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1931,10 +1884,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2148,10 +2099,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2323,10 +2272,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2385,10 +2332,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2457,10 +2402,8 @@
|
|||
<h2 class="card__title">Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2550,10 +2493,8 @@
|
|||
<h2 class="card__title">Regular Expression Denial of Service (ReDoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2697,10 +2638,8 @@
|
|||
<h2 class="card__title">Regular Expression Denial of Service (ReDoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -4003,10 +3942,8 @@
|
|||
<h2 class="card__title">Arbitrary Code Injection</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -4080,10 +4017,8 @@
|
|||
<h2 class="card__title">Insufficient Documentation of Error Handling Techniques</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -4157,10 +4092,8 @@
|
|||
<h2 class="card__title">Insecure Randomness</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -4229,10 +4162,8 @@
|
|||
<h2 class="card__title">Regular Expression Denial of Service (ReDoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:35:17 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:31:40 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
|
|
@ -514,10 +483,8 @@
|
|||
<h2 class="card__title">Incorrect Implementation of Authentication Algorithm</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--critical">
|
||||
<span class="label__text">critical severity</span>
|
||||
</div>
|
||||
<div class="label label--critical">
|
||||
<span class="label__text">critical severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -591,10 +558,8 @@
|
|||
<h2 class="card__title">Access of Resource Using Incompatible Type ('Type Confusion')</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -750,10 +715,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -832,10 +795,8 @@
|
|||
<h2 class="card__title">Server-side Request Forgery (SSRF)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -914,10 +875,8 @@
|
|||
<h2 class="card__title">Denial of Service (DoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -999,10 +958,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1071,10 +1028,8 @@
|
|||
<h2 class="card__title">Asymmetric Resource Consumption (Amplification)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1142,10 +1097,8 @@
|
|||
<h2 class="card__title">Insertion of Sensitive Information into Log File</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1212,10 +1165,8 @@
|
|||
<h2 class="card__title">Improper Validation of Syntactic Correctness of Input</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1265,7 +1216,7 @@
|
|||
<p><a href="https://pkg.go.dev/golang.org/x/net/html">golang.org/x/net/html</a> is a package that implements an HTML5-compliant tokenizer and parser.</p>
|
||||
<p>Affected versions of this package are vulnerable to Improper Validation of Syntactic Correctness of Input in the tokenizer in <code>token.go</code>, which incorrectly interprets tags as closing tags, allowing malicious input to be incorrectly processed and the DOM to be corrupted.</p>
|
||||
<h2 id="details">Details</h2>
|
||||
<p>Cross-site scripting (or XSS) is a code vulnerability that occurs when an attacker “injects” a malicious script into an otherwise trusted website. The injected script gets downloaded and executed by the end user’s browser when the user interacts with the compromised website.</p>
|
||||
<p>A cross-site scripting attack occurs when the attacker tricks a legitimate web-based application or site to accept a request as originating from a trusted source.</p>
|
||||
<p>This is done by escaping the context of the web application; the web application then delivers that data to its users along with other trusted dynamic content, without validating it. The browser unknowingly executes malicious script on the client side (through client-side languages; usually JavaScript or HTML) in order to perform actions that are otherwise typically blocked by the browser’s Same Origin Policy.</p>
|
||||
<p>Injecting malicious code is the most prevalent manner by which XSS is exploited; for this reason, escaping characters in order to prevent this manipulation is the top method for securing code against this vulnerability.</p>
|
||||
<p>Escaping means that the application is coded to mark key characters, and particularly key characters included in user input, to prevent those characters from being interpreted in a dangerous context. For example, in HTML, <code><</code> can be coded as <code>&lt</code>; and <code>></code> can be coded as <code>&gt</code>; in order to be interpreted and displayed as themselves in text, while within the code itself, they are used for HTML tags. If malicious content is injected into an application that escapes special characters and that malicious content uses <code><</code> and <code>></code> as HTML tags, those characters are nonetheless not interpreted as HTML tags by the browser if they’ve been correctly escaped in the application code and in this way the attempted attack is diverted.</p>
|
||||
|
|
@ -1339,10 +1290,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1401,10 +1350,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1463,10 +1410,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1588,10 +1533,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1659,10 +1602,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1721,10 +1662,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1783,10 +1722,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1854,10 +1791,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1916,10 +1851,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1978,10 +1911,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2040,10 +1971,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2102,10 +2031,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2164,10 +2091,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2226,10 +2151,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2288,10 +2211,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2350,10 +2271,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2412,10 +2331,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2474,10 +2391,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2536,10 +2451,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2598,10 +2511,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2679,10 +2590,8 @@
|
|||
<h2 class="card__title">CVE-2024-9143</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2844,10 +2753,8 @@
|
|||
<h2 class="card__title">CVE-2024-13176</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -3002,10 +2909,8 @@
|
|||
<h2 class="card__title">CVE-2024-12797</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -3159,10 +3064,8 @@
|
|||
<h2 class="card__title">CVE-2025-26519</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:35:20 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:31:44 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
|
|
@ -520,10 +489,8 @@
|
|||
<h2 class="card__title">Access of Resource Using Incompatible Type ('Type Confusion')</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -712,10 +679,8 @@
|
|||
<h2 class="card__title">Use After Free</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -833,10 +798,8 @@
|
|||
<h2 class="card__title">Use After Free</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -954,10 +917,8 @@
|
|||
<h2 class="card__title">CVE-2024-4741</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1149,10 +1110,8 @@
|
|||
<h2 class="card__title">CVE-2024-5535</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1380,10 +1339,8 @@
|
|||
<h2 class="card__title">CVE-2024-9143</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1578,10 +1535,8 @@
|
|||
<h2 class="card__title">CVE-2024-13176</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1769,10 +1724,8 @@
|
|||
<h2 class="card__title">CVE-2024-12797</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1959,10 +1912,8 @@
|
|||
<h2 class="card__title">CVE-2025-26519</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:35:25 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:31:48 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
|
|
@ -512,10 +481,8 @@
|
|||
<h2 class="card__title">CVE-2024-9143</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -699,10 +666,8 @@
|
|||
<h2 class="card__title">CVE-2024-13176</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -879,10 +844,8 @@
|
|||
<h2 class="card__title">CVE-2024-12797</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1058,10 +1021,8 @@
|
|||
<h2 class="card__title">CVE-2025-26519</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:35:49 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:32:11 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
|
|
@ -512,10 +481,8 @@
|
|||
<h2 class="card__title">CVE-2024-9143</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -699,10 +666,8 @@
|
|||
<h2 class="card__title">CVE-2024-13176</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -879,10 +844,8 @@
|
|||
<h2 class="card__title">CVE-2024-12797</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1058,10 +1021,8 @@
|
|||
<h2 class="card__title">CVE-2025-26519</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -456,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:34:43 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:31:07 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -456,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:34:53 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:31:17 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:32:25 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:28:55 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
|
|
@ -513,10 +482,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -845,10 +812,8 @@
|
|||
<h2 class="card__title">LGPL-3.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -911,10 +876,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -973,10 +936,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1037,10 +998,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1254,10 +1213,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1429,10 +1386,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1491,10 +1446,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1565,10 +1518,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1637,10 +1588,8 @@
|
|||
<h2 class="card__title">Regular Expression Denial of Service (ReDoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1784,10 +1733,8 @@
|
|||
<h2 class="card__title">Regular Expression Denial of Service (ReDoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2125,10 +2072,8 @@
|
|||
<h2 class="card__title">Arbitrary Code Injection</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2202,10 +2147,8 @@
|
|||
<h2 class="card__title">Insecure Randomness</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2274,10 +2217,8 @@
|
|||
<h2 class="card__title">Regular Expression Denial of Service (ReDoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:29:48 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:29:02 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
|
|
@ -514,10 +483,8 @@
|
|||
<h2 class="card__title">Incorrect Implementation of Authentication Algorithm</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--critical">
|
||||
<span class="label__text">critical severity</span>
|
||||
</div>
|
||||
<div class="label label--critical">
|
||||
<span class="label__text">critical severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -591,10 +558,8 @@
|
|||
<h2 class="card__title">Access of Resource Using Incompatible Type ('Type Confusion')</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -750,10 +715,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -832,10 +795,8 @@
|
|||
<h2 class="card__title">Server-side Request Forgery (SSRF)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -914,10 +875,8 @@
|
|||
<h2 class="card__title">Denial of Service (DoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -999,10 +958,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1071,10 +1028,8 @@
|
|||
<h2 class="card__title">Asymmetric Resource Consumption (Amplification)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1142,10 +1097,8 @@
|
|||
<h2 class="card__title">Insertion of Sensitive Information into Log File</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1212,10 +1165,8 @@
|
|||
<h2 class="card__title">Improper Validation of Syntactic Correctness of Input</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1265,7 +1216,7 @@
|
|||
<p><a href="https://pkg.go.dev/golang.org/x/net/html">golang.org/x/net/html</a> is a package that implements an HTML5-compliant tokenizer and parser.</p>
|
||||
<p>Affected versions of this package are vulnerable to Improper Validation of Syntactic Correctness of Input in the tokenizer in <code>token.go</code>, which incorrectly interprets tags as closing tags, allowing malicious input to be incorrectly processed and the DOM to be corrupted.</p>
|
||||
<h2 id="details">Details</h2>
|
||||
<p>Cross-site scripting (or XSS) is a code vulnerability that occurs when an attacker “injects” a malicious script into an otherwise trusted website. The injected script gets downloaded and executed by the end user’s browser when the user interacts with the compromised website.</p>
|
||||
<p>A cross-site scripting attack occurs when the attacker tricks a legitimate web-based application or site to accept a request as originating from a trusted source.</p>
|
||||
<p>This is done by escaping the context of the web application; the web application then delivers that data to its users along with other trusted dynamic content, without validating it. The browser unknowingly executes malicious script on the client side (through client-side languages; usually JavaScript or HTML) in order to perform actions that are otherwise typically blocked by the browser’s Same Origin Policy.</p>
|
||||
<p>Injecting malicious code is the most prevalent manner by which XSS is exploited; for this reason, escaping characters in order to prevent this manipulation is the top method for securing code against this vulnerability.</p>
|
||||
<p>Escaping means that the application is coded to mark key characters, and particularly key characters included in user input, to prevent those characters from being interpreted in a dangerous context. For example, in HTML, <code><</code> can be coded as <code>&lt</code>; and <code>></code> can be coded as <code>&gt</code>; in order to be interpreted and displayed as themselves in text, while within the code itself, they are used for HTML tags. If malicious content is injected into an application that escapes special characters and that malicious content uses <code><</code> and <code>></code> as HTML tags, those characters are nonetheless not interpreted as HTML tags by the browser if they’ve been correctly escaped in the application code and in this way the attempted attack is diverted.</p>
|
||||
|
|
@ -1339,10 +1290,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1401,10 +1350,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1463,10 +1410,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1588,10 +1533,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1659,10 +1602,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1721,10 +1662,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1783,10 +1722,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1854,10 +1791,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1916,10 +1851,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1978,10 +1911,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2040,10 +1971,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2102,10 +2031,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2164,10 +2091,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2226,10 +2151,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2288,10 +2211,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2350,10 +2271,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2412,10 +2331,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2474,10 +2391,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2536,10 +2451,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2598,10 +2511,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2679,10 +2590,8 @@
|
|||
<h2 class="card__title">CVE-2024-9143</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2844,10 +2753,8 @@
|
|||
<h2 class="card__title">CVE-2024-13176</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -3002,10 +2909,8 @@
|
|||
<h2 class="card__title">CVE-2024-12797</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -3159,10 +3064,8 @@
|
|||
<h2 class="card__title">CVE-2025-26519</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:32:39 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:29:07 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
|
|
@ -520,10 +489,8 @@
|
|||
<h2 class="card__title">Access of Resource Using Incompatible Type ('Type Confusion')</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -712,10 +679,8 @@
|
|||
<h2 class="card__title">Use After Free</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -833,10 +798,8 @@
|
|||
<h2 class="card__title">Use After Free</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -954,10 +917,8 @@
|
|||
<h2 class="card__title">CVE-2024-4741</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1149,10 +1110,8 @@
|
|||
<h2 class="card__title">CVE-2024-5535</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1380,10 +1339,8 @@
|
|||
<h2 class="card__title">CVE-2024-9143</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1578,10 +1535,8 @@
|
|||
<h2 class="card__title">CVE-2024-13176</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1769,10 +1724,8 @@
|
|||
<h2 class="card__title">CVE-2024-12797</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1959,10 +1912,8 @@
|
|||
<h2 class="card__title">CVE-2025-26519</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:32:45 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:29:12 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
|
|
@ -512,10 +481,8 @@
|
|||
<h2 class="card__title">CVE-2024-9143</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -699,10 +666,8 @@
|
|||
<h2 class="card__title">CVE-2024-13176</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -879,10 +844,8 @@
|
|||
<h2 class="card__title">CVE-2024-12797</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1058,10 +1021,8 @@
|
|||
<h2 class="card__title">CVE-2025-26519</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:33:11 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:29:36 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
|
|
@ -512,10 +481,8 @@
|
|||
<h2 class="card__title">CVE-2024-9143</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -699,10 +666,8 @@
|
|||
<h2 class="card__title">CVE-2024-13176</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -879,10 +844,8 @@
|
|||
<h2 class="card__title">CVE-2024-12797</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1058,10 +1021,8 @@
|
|||
<h2 class="card__title">CVE-2025-26519</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -456,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:31:53 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:28:26 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
|
|
@ -2861,7 +2861,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 26467
|
||||
Line number: 26461
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -456,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:32:03 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:28:36 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
|
|
@ -2815,7 +2815,7 @@
|
|||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 2354
|
||||
Line number: 2348
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Snyk test report</title>
|
||||
<meta name="description" content="15 known vulnerabilities found in 105 vulnerable dependency paths.">
|
||||
<meta name="description" content="17 known vulnerabilities found in 108 vulnerable dependency paths.">
|
||||
<base target="_blank">
|
||||
<link rel="icon" type="image/png" href="https://res.cloudinary.com/snyk/image/upload/v1468845142/favicon/favicon.png"
|
||||
sizes="194x194">
|
||||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:29:39 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:26:16 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
|
|
@ -499,9 +468,9 @@
|
|||
</div>
|
||||
|
||||
<div class="meta-counts">
|
||||
<div class="meta-count"><span>15</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>105 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>2085</span> <span>dependencies</span></div>
|
||||
<div class="meta-count"><span>17</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>108 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>2079</span> <span>dependencies</span></div>
|
||||
</div><!-- .meta-counts -->
|
||||
</div><!-- .layout-container--short -->
|
||||
</header><!-- .project__header -->
|
||||
|
|
@ -513,10 +482,8 @@
|
|||
<h2 class="card__title">Prototype Pollution</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -681,10 +648,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1031,10 +996,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1262,10 +1225,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1804,15 +1765,158 @@
|
|||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMEXPRLANGEXPRCONF-9460818">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">LGPL-3.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> go.mod
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Module:
|
||||
|
||||
gopkg.in/retry.v1
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
|
||||
github.com/argoproj/argo-cd/v3@0.0.0, github.com/Azure/kubelogin/pkg/token@0.1.9 and others
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/Azure/kubelogin/pkg/token@0.1.9
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/Azure/kubelogin/pkg/internal/token@0.1.9
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
gopkg.in/retry.v1@1.0.3
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<p>LGPL-3.0 license</p>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/snyk:lic:golang:gopkg.in:retry.v1:LGPL-3.0">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">Unexpected Status Code or Return Value</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> go.mod
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
github.com/redis/go-redis/v9
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
github.com/argoproj/argo-cd/v3@0.0.0 and github.com/redis/go-redis/v9@9.7.1
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/redis/go-redis/v9@9.7.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/go-redis/cache/v9@9.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/redis/go-redis/v9@9.7.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Unexpected Status Code or Return Value in <code>initConn()</code>, which causes out of order responses when <code>CLIENT SETINFO</code> times out while establishing a connection.</p>
|
||||
<h2 id="workaround">Workaround</h2>
|
||||
<p>This vulnerability can be avoided by setting <code>DisableIndentity</code> to true when initializing a client.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>github.com/redis/go-redis/v9</code> to version 9.5.5, 9.6.3, 9.7.2 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/redis/go-redis/commit/d236865b0cfa1b752ea4b7da666b1fdcd0acebb6">GitHub Commit</a></li>
|
||||
<li><a href="https://github.com/redis/go-redis/pull/3295">GitHub PR</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMREDISGOREDISV9-9486471">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1871,10 +1975,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1935,10 +2037,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2152,10 +2252,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2327,10 +2425,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2389,10 +2485,8 @@
|
|||
<h2 class="card__title">Regular Expression Denial of Service (ReDoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2536,10 +2630,8 @@
|
|||
<h2 class="card__title">Regular Expression Denial of Service (ReDoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2877,10 +2969,8 @@
|
|||
<h2 class="card__title">Arbitrary Code Injection</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2954,10 +3044,8 @@
|
|||
<h2 class="card__title">Insecure Randomness</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -3026,10 +3114,8 @@
|
|||
<h2 class="card__title">Cross-site Scripting (XSS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -3099,7 +3185,7 @@
|
|||
);
|
||||
</code></pre>
|
||||
<h2 id="details">Details</h2>
|
||||
<p>Cross-site scripting (or XSS) is a code vulnerability that occurs when an attacker “injects” a malicious script into an otherwise trusted website. The injected script gets downloaded and executed by the end user’s browser when the user interacts with the compromised website.</p>
|
||||
<p>A cross-site scripting attack occurs when the attacker tricks a legitimate web-based application or site to accept a request as originating from a trusted source.</p>
|
||||
<p>This is done by escaping the context of the web application; the web application then delivers that data to its users along with other trusted dynamic content, without validating it. The browser unknowingly executes malicious script on the client side (through client-side languages; usually JavaScript or HTML) in order to perform actions that are otherwise typically blocked by the browser’s Same Origin Policy.</p>
|
||||
<p>Injecting malicious code is the most prevalent manner by which XSS is exploited; for this reason, escaping characters in order to prevent this manipulation is the top method for securing code against this vulnerability.</p>
|
||||
<p>Escaping means that the application is coded to mark key characters, and particularly key characters included in user input, to prevent those characters from being interpreted in a dangerous context. For example, in HTML, <code><</code> can be coded as <code>&lt</code>; and <code>></code> can be coded as <code>&gt</code>; in order to be interpreted and displayed as themselves in text, while within the code itself, they are used for HTML tags. If malicious content is injected into an application that escapes special characters and that malicious content uses <code><</code> and <code>></code> as HTML tags, those characters are nonetheless not interpreted as HTML tags by the browser if they’ve been correctly escaped in the application code and in this way the attempted attack is diverted.</p>
|
||||
|
|
@ -3173,10 +3259,8 @@
|
|||
<h2 class="card__title">Regular Expression Denial of Service (ReDoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:32:33 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:26:25 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
|
|
@ -514,10 +483,8 @@
|
|||
<h2 class="card__title">Incorrect Implementation of Authentication Algorithm</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--critical">
|
||||
<span class="label__text">critical severity</span>
|
||||
</div>
|
||||
<div class="label label--critical">
|
||||
<span class="label__text">critical severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -591,10 +558,8 @@
|
|||
<h2 class="card__title">Access of Resource Using Incompatible Type ('Type Confusion')</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -750,10 +715,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -832,10 +795,8 @@
|
|||
<h2 class="card__title">Server-side Request Forgery (SSRF)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -914,10 +875,8 @@
|
|||
<h2 class="card__title">Denial of Service (DoS)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -999,10 +958,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1071,10 +1028,8 @@
|
|||
<h2 class="card__title">Asymmetric Resource Consumption (Amplification)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1142,10 +1097,8 @@
|
|||
<h2 class="card__title">Insertion of Sensitive Information into Log File</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1212,10 +1165,8 @@
|
|||
<h2 class="card__title">Improper Validation of Syntactic Correctness of Input</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1265,7 +1216,7 @@
|
|||
<p><a href="https://pkg.go.dev/golang.org/x/net/html">golang.org/x/net/html</a> is a package that implements an HTML5-compliant tokenizer and parser.</p>
|
||||
<p>Affected versions of this package are vulnerable to Improper Validation of Syntactic Correctness of Input in the tokenizer in <code>token.go</code>, which incorrectly interprets tags as closing tags, allowing malicious input to be incorrectly processed and the DOM to be corrupted.</p>
|
||||
<h2 id="details">Details</h2>
|
||||
<p>Cross-site scripting (or XSS) is a code vulnerability that occurs when an attacker “injects” a malicious script into an otherwise trusted website. The injected script gets downloaded and executed by the end user’s browser when the user interacts with the compromised website.</p>
|
||||
<p>A cross-site scripting attack occurs when the attacker tricks a legitimate web-based application or site to accept a request as originating from a trusted source.</p>
|
||||
<p>This is done by escaping the context of the web application; the web application then delivers that data to its users along with other trusted dynamic content, without validating it. The browser unknowingly executes malicious script on the client side (through client-side languages; usually JavaScript or HTML) in order to perform actions that are otherwise typically blocked by the browser’s Same Origin Policy.</p>
|
||||
<p>Injecting malicious code is the most prevalent manner by which XSS is exploited; for this reason, escaping characters in order to prevent this manipulation is the top method for securing code against this vulnerability.</p>
|
||||
<p>Escaping means that the application is coded to mark key characters, and particularly key characters included in user input, to prevent those characters from being interpreted in a dangerous context. For example, in HTML, <code><</code> can be coded as <code>&lt</code>; and <code>></code> can be coded as <code>&gt</code>; in order to be interpreted and displayed as themselves in text, while within the code itself, they are used for HTML tags. If malicious content is injected into an application that escapes special characters and that malicious content uses <code><</code> and <code>></code> as HTML tags, those characters are nonetheless not interpreted as HTML tags by the browser if they’ve been correctly escaped in the application code and in this way the attempted attack is diverted.</p>
|
||||
|
|
@ -1339,10 +1290,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1401,10 +1350,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1463,10 +1410,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1588,10 +1533,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1659,10 +1602,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1721,10 +1662,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1783,10 +1722,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1854,10 +1791,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1916,10 +1851,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -1978,10 +1911,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2040,10 +1971,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2102,10 +2031,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2164,10 +2091,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2226,10 +2151,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2288,10 +2211,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2350,10 +2271,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2412,10 +2331,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2474,10 +2391,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2536,10 +2451,8 @@
|
|||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2598,10 +2511,8 @@
|
|||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2679,10 +2590,8 @@
|
|||
<h2 class="card__title">CVE-2024-9143</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -2844,10 +2753,8 @@
|
|||
<h2 class="card__title">CVE-2024-13176</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -3002,10 +2909,8 @@
|
|||
<h2 class="card__title">CVE-2024-12797</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -3159,10 +3064,8 @@
|
|||
<h2 class="card__title">CVE-2025-26519</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
<div class="label label--low">
|
||||
<span class="label__text">low severity</span>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -141,7 +141,7 @@
|
|||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
background-color: #4b45a9;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
|
|
@ -201,15 +201,6 @@
|
|||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
|
|
@ -267,7 +258,10 @@
|
|||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
.card--vuln .label {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
|
|
@ -303,30 +296,6 @@
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
|
|
@ -487,7 +456,7 @@
|
|||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">July 13th 2025, 12:29:51 am (UTC+00:00)</p>
|
||||
<p class="timestamp">June 15th 2025, 12:26:28 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue