Repository navigation
Expand file tree
/
Copy pathacceptance_gate_test.go
More file actions
147 lines (124 loc) · 5.27 KB
/
Copy pathacceptance_gate_test.go
File metadata and controls
147 lines (124 loc) · 5.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// SPDX-License-Identifier: Apache-2.0
package git
import (
"context"
"os"
"path/filepath"
"testing"
gogit "github.com/go-git/go-git/v6"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
v1alpha3 "github.com/ConfigButler/gitops-reverser/api/v1alpha3"
"github.com/ConfigButler/gitops-reverser/internal/manifestanalyzer"
"github.com/ConfigButler/gitops-reverser/internal/types"
)
const hardKustomizeYAML = "apiVersion: kustomize.config.k8s.io/v1beta1\n" +
"kind: Kustomization\n" +
"resources:\n - cm.yaml\n" +
"patches:\n - path: patch.yaml\n"
const plainKustomizeYAML = "apiVersion: kustomize.config.k8s.io/v1beta1\n" +
"kind: Kustomization\n" +
"resources:\n - cm.yaml\n"
// cmYAML is the resource plainKustomizeYAML points at. It has to be there: the
// analyzer now builds every render root with kustomize, and a dangling resources:
// entry fails the build.
const cmYAML = "apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: seeded\n namespace: default\ndata:\n k: v\n"
// A GitTarget subtree holding a kustomization.yaml that uses an unsupported feature is
// refused: the live flush returns an *AcceptanceRefusedError naming the file and writes
// nothing, so the operator never edits a folder it cannot safely manage.
func TestPlanFlush_RefusesUnsupportedKustomizeFolder(t *testing.T) {
writer := newContentWriter(types.SensitiveResourcePolicy{})
worktree := newWorktreeForTest(t)
root := worktree.Filesystem().Root()
seedPlacedManifest(t, worktree, "kustomization.yaml", hardKustomizeYAML)
w := &BranchWorker{contentWriter: writer}
event := cmEvent("CREATE", "fresh", "green")
_, err := w.flushEventsToWorktree(
context.Background(),
worktree,
"",
[]Event{event},
nil,
namespacePolicy{},
v1alpha3.PruneOnEvent,
)
var refused *manifestanalyzer.AcceptanceRefusedError
require.ErrorAs(t, err, &refused, "flush must refuse with *AcceptanceRefusedError")
assert.Contains(t, refused.Error(), "kustomization.yaml", "the refusal must name the offending file")
// Nothing was written: the built-in ConfigMap path must not exist.
builtinFull := filepath.Join(root, writer.filePathForIdentifier(event.Identifier))
_, statErr := os.Stat(builtinFull)
assert.True(t, os.IsNotExist(statErr), "a refused folder must not be written into")
}
// A plain kustomization (namespace/resources only) is auxiliary input, never a refusal:
// it is retained and the writer keeps editing the managed resources beside it.
func TestPlanFlush_AcceptsPlainKustomizeFolder(t *testing.T) {
writer := newContentWriter(types.SensitiveResourcePolicy{})
worktree := newWorktreeForTest(t)
// cm.yaml must actually exist: a render root whose resources: entry does not
// resolve is refused now (kustomize cannot build it, so neither can Flux).
seedPlacedManifest(t, worktree, "cm.yaml", cmYAML)
seedPlacedManifest(t, worktree, "kustomization.yaml", plainKustomizeYAML)
w := &BranchWorker{contentWriter: writer}
create := []Event{cmEvent("CREATE", "fresh", "green")}
changed, err := w.flushEventsToWorktree(
context.Background(),
worktree,
"",
create,
nil,
namespacePolicy{},
v1alpha3.PruneOnEvent,
)
require.NoError(t, err, "a plain kustomization must not be refused")
assert.True(t, changed, "the ConfigMap must be written beside the retained kustomization")
}
// The operator's own bootstrap artifact (.sops.yaml creation rules) is non-KRM YAML, but
// it is the writer's own file and must never trip the acceptance gate.
func TestPlanFlush_DoesNotRefuseOwnSopsConfig(t *testing.T) {
writer := newContentWriter(types.SensitiveResourcePolicy{})
worktree := newWorktreeForTest(t)
seedPlacedManifest(t, worktree, ".sops.yaml", "creation_rules:\n - path_regex: .*\n")
w := &BranchWorker{contentWriter: writer}
create := []Event{cmEvent("CREATE", "fresh", "green")}
changed, err := w.flushEventsToWorktree(
context.Background(),
worktree,
"",
create,
nil,
namespacePolicy{},
v1alpha3.PruneOnEvent,
)
require.NoError(t, err, ".sops.yaml is the operator's own config and must not be refused")
assert.True(t, changed, "the ConfigMap must still be written beside .sops.yaml")
}
func TestResyncRefusal_DoesNotStageSOPSBootstrap(t *testing.T) {
writer := newContentWriter(types.SensitiveResourcePolicy{})
worktree := newWorktreeForTest(t)
root := worktree.Filesystem().Root()
repo, err := gogit.PlainOpen(root)
require.NoError(t, err)
seedPlacedManifest(t, worktree, "apps/kustomization.yaml", hardKustomizeYAML)
w := &BranchWorker{contentWriter: writer, mapper: configMapMapper()}
pending := PendingWrite{
Kind: PendingWriteResync,
GitTargetName: "target-a",
GitTargetNamespace: "default",
Targets: map[pendingTargetKey]ResolvedTargetMetadata{
{Name: "target-a", Namespace: "default"}: {
Name: "target-a",
Namespace: "default",
Path: "apps",
BootstrapOptions: buildBootstrapOptions(&ResolvedEncryptionConfig{
AgeRecipients: []string{"age1testrecipient"},
}),
},
},
}
_, err = w.executeResyncPendingWrite(context.Background(), repo, worktree, &pending)
var refused *manifestanalyzer.AcceptanceRefusedError
require.ErrorAs(t, err, &refused)
_, statErr := os.Stat(filepath.Join(root, "apps", ".sops.yaml"))
assert.True(t, os.IsNotExist(statErr), "a refused resync must not stage bootstrap .sops.yaml")
}