1package deployment
2
3import (
4 "context"
5 "strings"
6 "testing"
7
8 "github.com/bnema/zerowrap"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/require"
11
12 outmocks "github.com/bnema/gordon/internal/boundaries/out/mocks"
13 "github.com/bnema/gordon/internal/domain"
14)
15
16func imagePolicyService(policy domain.ImageSourcePolicy) *Service {
17 return NewService(Deps{ImagePolicy: policy}, zerowrap.Default())
18}
19
20// TestValidateImageSource_RejectsPrivateRegistryDigest proves the image
21// policy runs on the shared preflight path used by deploy, boot, restart,
22// and recovery, so a digest-pinned local/private reference is refused
23// before any pull.
24func TestValidateImageSource_RejectsPrivateRegistryDigest(t *testing.T) {
25 digest := "sha256:" + strings.Repeat("a", 64)
26 svc := imagePolicyService(domain.ImageSourcePolicy{
27 AllowedRegistries: []string{"registry.example.com"},
28 InstallationRegistry: "gordon.example.com",
29 })
30
31 assert.ErrorIs(t, svc.validateImageSource("127.0.0.1:12345/private", digest), domain.ErrAppImageNotAllowed)
32 assert.ErrorIs(t, svc.validateImageSource("169.254.169.254/metadata", digest), domain.ErrAppImageNotAllowed)
33 assert.ErrorIs(t, svc.validateImageSource("other.example.com/team/app", digest), domain.ErrAppImageNotAllowed)
34 require.NoError(t, svc.validateImageSource("registry.example.com/team/app", digest))
35 require.NoError(t, svc.validateImageSource("gordon.example.com/blog/web", digest))
36}
37
38func TestPullImage_RechecksRegistryPolicyImmediatelyBeforePull(t *testing.T) {
39 runtime := outmocks.NewMockContainerRuntime(t)
40 svc := NewService(Deps{
41 Runtime: runtime,
42 Registry: RegistryConfig{Domain: "gordon.example.com"},
43 ImagePolicy: domain.ImageSourcePolicy{InstallationRegistry: "gordon.example.com"},
44 }, zerowrap.Default())
45
46 _, err := svc.pullImage(context.Background(), "registry.example.com/team/app@sha256:"+strings.Repeat("a", 64))
47
48 assert.ErrorIs(t, err, domain.ErrAppImageNotAllowed)
49}
50
51func TestValidateImageSource_RequireDigestAppliesToAllRegistries(t *testing.T) {
52 digest := "sha256:" + strings.Repeat("a", 64)
53 svc := imagePolicyService(domain.ImageSourcePolicy{
54 AllowedRegistries: []string{"registry.example.com"},
55 RequireDigest: true,
56 InstallationRegistry: "gordon.example.com",
57 })
58 assert.ErrorIs(t, svc.validateImageSource("registry.example.com/team/app:1.0", ""), domain.ErrAppImageNotAllowed)
59 assert.ErrorIs(t, svc.validateImageSource("gordon.example.com/team/app:1.0", ""), domain.ErrAppImageNotAllowed)
60 require.NoError(t, svc.validateImageSource("registry.example.com/team/app", digest))
61 require.NoError(t, svc.validateImageSource("gordon.example.com/team/app", digest))
62}
63
64func TestPreflightImage_RejectsMalformedResolvedDigestBeforePull(t *testing.T) {
65 runtime := outmocks.NewMockContainerRuntime(t)
66 svc := NewService(Deps{
67 Runtime: runtime,
68 Registry: RegistryConfig{Domain: "gordon.example.com"},
69 ImagePolicy: domain.ImageSourcePolicy{InstallationRegistry: "gordon.example.com"},
70 }, zerowrap.Default())
71
72 _, err := svc.preflightImage(context.Background(), "gordon.example.com/team/app:1.0", "sha256:short")
73
74 assert.ErrorIs(t, err, domain.ErrAppImageUnresolvable)
75}