Skip to content

Commit d801faa

Browse files
[deckhouse-cli] Skip database pulling when they don't exist (#327)
Signed-off-by: Roman Berezkin <roman.berezkin@flant.com>
1 parent df5a627 commit d801faa

2 files changed

Lines changed: 72 additions & 41 deletions

File tree

internal/mirror/security/security.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -103,37 +103,39 @@ func NewService(
103103
// PullSecurity pulls the security databases
104104
// It validates access to the registry and pulls the security database images
105105
func (svc *Service) PullSecurity(ctx context.Context) error {
106-
err := svc.validateSecurityAccess(ctx)
106+
available, err := svc.securityDatabasesAvailable(ctx)
107107
if err != nil {
108-
return fmt.Errorf("validate security access: %w", err)
108+
return fmt.Errorf("check security databases availability: %w", err)
109109
}
110110

111-
err = svc.pullSecurityDatabases(ctx)
112-
if err != nil {
111+
if !available {
112+
return nil
113+
}
114+
115+
if err := svc.pullSecurityDatabases(ctx); err != nil {
113116
return fmt.Errorf("pull security databases: %w", err)
114117
}
115118

116119
return nil
117120
}
118121

119-
// validateSecurityAccess validates access to the security registry
120-
// It checks if the security database image exists in the source registry
121-
func (svc *Service) validateSecurityAccess(ctx context.Context) error {
122-
svc.logger.Debug("Validating access to the security registry")
122+
// securityDatabasesAvailable checks if security database images exist in the source registry.
123+
// Returns false for editions that do not include security databases (e.g. CE, BE, SE).
124+
func (svc *Service) securityDatabasesAvailable(ctx context.Context) (bool, error) {
125+
svc.logger.Debug("Checking if security databases are available in registry")
123126

124-
// For specific tags, check if the tag exists
125127
err := svc.securityService.Security(internal.SecurityTrivyDBSegment).CheckImageExists(ctx, "2")
126128
if errors.Is(err, client.ErrImageNotFound) {
127-
svc.userLogger.Warnf("Skipping pull of security databases: %v", err)
129+
svc.userLogger.WarnLn("Security databases are not available in this edition, skipping")
128130

129-
return nil
131+
return false, nil
130132
}
131133

132134
if err != nil {
133-
return fmt.Errorf("failed to check security database tag %q in registry: %w", "2", err)
135+
return false, fmt.Errorf("failed to check security database tag %q in registry: %w", "2", err)
134136
}
135137

136-
return nil
138+
return true, nil
137139
}
138140

139141
func (svc *Service) pullSecurityDatabases(ctx context.Context) error {

internal/mirror/security/security_test.go

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@ package security
66
import (
77
"context"
88
"log/slog"
9+
"os"
910
"testing"
1011

1112
"github.com/stretchr/testify/require"
1213

1314
dkplog "github.com/deckhouse/deckhouse/pkg/log"
15+
upfake "github.com/deckhouse/deckhouse/pkg/registry/fake"
1416

1517
"github.com/deckhouse/deckhouse-cli/internal"
18+
"github.com/deckhouse/deckhouse-cli/pkg"
1619
"github.com/deckhouse/deckhouse-cli/pkg/libmirror/util/log"
17-
registryservice "github.com/deckhouse/deckhouse-cli/pkg/registry/service"
18-
upfake "github.com/deckhouse/deckhouse/pkg/registry/fake"
1920
pkgclient "github.com/deckhouse/deckhouse-cli/pkg/registry/client"
21+
registryservice "github.com/deckhouse/deckhouse-cli/pkg/registry/service"
2022
)
2123

2224
func newTestSecurityService(
@@ -32,11 +34,11 @@ func newTestSecurityService(
3234
}
3335
}
3436

35-
func TestService_validateSecurityAccess(t *testing.T) {
37+
func TestService_securityDatabasesAvailable(t *testing.T) {
3638
logger := dkplog.NewLogger(dkplog.WithLevel(slog.LevelWarn))
3739
userLogger := log.NewSLogger(slog.LevelWarn)
3840

39-
t.Run("trivy-db tag 2 exists – no error", func(t *testing.T) {
41+
t.Run("trivy-db tag 2 exists – available", func(t *testing.T) {
4042
reg := upfake.NewRegistry("registry.example.com")
4143
trivyImg := upfake.NewImageBuilder().MustBuild()
4244
reg.MustAddImage("security/trivy-db", "2", trivyImg)
@@ -46,25 +48,27 @@ func TestService_validateSecurityAccess(t *testing.T) {
4648
securityService := registryservice.NewSecurityServices("security", securityClient, logger)
4749

4850
svc := newTestSecurityService(securityService, logger, userLogger)
49-
err := svc.validateSecurityAccess(context.Background())
51+
available, err := svc.securityDatabasesAvailable(context.Background())
5052
require.NoError(t, err)
53+
require.True(t, available)
5154
})
5255

53-
t.Run("trivy-db tag 2 absent – no error (graceful skip)", func(t *testing.T) {
56+
t.Run("trivy-db tag 2 absent – not available (graceful skip)", func(t *testing.T) {
5457
reg := upfake.NewRegistry("registry.example.com")
5558
stubClient := pkgclient.Adapt(upfake.NewClient(reg))
5659
securityClient := stubClient.WithSegment("security")
5760
securityService := registryservice.NewSecurityServices("security", securityClient, logger)
5861

5962
svc := newTestSecurityService(securityService, logger, userLogger)
60-
err := svc.validateSecurityAccess(context.Background())
63+
available, err := svc.securityDatabasesAvailable(context.Background())
6164
require.NoError(t, err)
65+
require.False(t, available)
6266
})
6367
}
6468

65-
// TestService_validateSecurityAccess_MultipleDatabases verifies that when all
66-
// security databases are present the service reports no error.
67-
func TestService_validateSecurityAccess_MultipleDatabases(t *testing.T) {
69+
// TestService_securityDatabasesAvailable_MultipleDatabases verifies that when all
70+
// security databases are present the service reports available.
71+
func TestService_securityDatabasesAvailable_MultipleDatabases(t *testing.T) {
6872
logger := dkplog.NewLogger(dkplog.WithLevel(slog.LevelWarn))
6973
userLogger := log.NewSLogger(slog.LevelWarn)
7074

@@ -85,25 +89,26 @@ func TestService_validateSecurityAccess_MultipleDatabases(t *testing.T) {
8589
securityService := registryservice.NewSecurityServices("security", securityClient, logger)
8690

8791
svc := newTestSecurityService(securityService, logger, userLogger)
88-
err := svc.validateSecurityAccess(context.Background())
92+
available, err := svc.securityDatabasesAvailable(context.Background())
8993
require.NoError(t, err)
94+
require.True(t, available)
9095
}
9196

92-
// TestService_validateSecurityAccess_PerDatabase exercises validateSecurityAccess
93-
// for each known security database variant. Only trivy-db is checked during
94-
// access validation; the others are handled with AllowMissingTags in the puller.
95-
func TestService_validateSecurityAccess_PerDatabase(t *testing.T) {
97+
// TestService_securityDatabasesAvailable_PerDatabase exercises securityDatabasesAvailable
98+
// for each known security database variant. Only trivy-db:2 is checked during
99+
// the availability check; the others are handled with AllowMissingTags in the puller.
100+
func TestService_securityDatabasesAvailable_PerDatabase(t *testing.T) {
96101
logger := dkplog.NewLogger(dkplog.WithLevel(slog.LevelWarn))
97102
userLogger := log.NewSLogger(slog.LevelWarn)
98103

99104
databases := []struct {
100-
segment string
101-
wantErr bool
105+
segment string
106+
wantAvailable bool
102107
}{
103-
{internal.SecurityTrivyDBSegment, false},
104-
{internal.SecurityTrivyBDUSegment, false},
105-
{internal.SecurityTrivyJavaDBSegment, false},
106-
{internal.SecurityTrivyChecksSegment, false},
108+
{internal.SecurityTrivyDBSegment, true}, // trivy-db:2 exists - available
109+
{internal.SecurityTrivyBDUSegment, false}, // only trivy-bdu:2 added, but check looks for trivy-db:2
110+
{internal.SecurityTrivyJavaDBSegment, false}, // same - trivy-db:2 not present
111+
{internal.SecurityTrivyChecksSegment, false}, // same - trivy-db:2 not present
107112
}
108113

109114
for _, db := range databases {
@@ -117,13 +122,37 @@ func TestService_validateSecurityAccess_PerDatabase(t *testing.T) {
117122
securityService := registryservice.NewSecurityServices("security", securityClient, logger)
118123

119124
svc := newTestSecurityService(securityService, logger, userLogger)
120-
err := svc.validateSecurityAccess(context.Background())
121-
122-
if db.wantErr {
123-
require.Error(t, err)
124-
} else {
125-
require.NoError(t, err)
126-
}
125+
available, err := svc.securityDatabasesAvailable(context.Background())
126+
require.NoError(t, err)
127+
require.Equal(t, db.wantAvailable, available)
127128
})
128129
}
129130
}
131+
132+
// TestPullSecurity_SkipsWhenDatabasesNotAvailable verifies the full PullSecurity flow
133+
// (not dry-run) when security databases don't exist in the registry.
134+
// This simulates CE/BE/SE editions where security images are not published.
135+
// Expected: PullSecurity returns nil (no error), and security.tar is NOT created.
136+
func TestPullSecurity_SkipsWhenDatabasesNotAvailable(t *testing.T) {
137+
workingDir := t.TempDir()
138+
// bundleDir - where security.tar would be written if pull proceeded (but it shouldn't in this test)
139+
bundleDir := t.TempDir()
140+
141+
logger := dkplog.NewLogger(dkplog.WithLevel(slog.LevelWarn))
142+
userLogger := log.NewSLogger(slog.LevelWarn)
143+
144+
// Empty registry - no security images (trivy-db, trivy-bdu, etc.)
145+
reg := upfake.NewRegistry("registry.example.com")
146+
stubClient := pkgclient.Adapt(upfake.NewClient(reg))
147+
148+
regSvc := registryservice.NewService(stubClient, pkg.FEEdition, logger)
149+
securitySvc := NewService(regSvc, workingDir, &Options{BundleDir: bundleDir}, logger, userLogger)
150+
151+
err := securitySvc.PullSecurity(context.Background())
152+
require.NoError(t, err)
153+
154+
// bundleDir must be empty when databases are not available - security.tar should not be created.
155+
entries, err := os.ReadDir(bundleDir)
156+
require.NoError(t, err)
157+
require.Empty(t, entries, "security.tar should not be created when databases are not available")
158+
}

0 commit comments

Comments
 (0)