Skip to content

Commit 313eee8

Browse files
committed
chore: add e2e tests
Signed-off-by: Arjun Raja Yogidas <[email protected]>
1 parent 50f6d5d commit 313eee8

File tree

5 files changed

+167
-22
lines changed

5 files changed

+167
-22
lines changed

.github/workflows/ci.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,13 @@ jobs:
109109
run: sudo bin/finch-daemon --debug --socket-owner $UID &
110110
- name: Run e2e test
111111
run: sudo make test-e2e
112+
- name: Clean up Daemon socket
113+
run: sudo rm /var/run/finch.sock && sudo rm /run/finch.pid
114+
- name: Verify Rego file presence
115+
run: ls -l ${{ github.workspace }}/sample.rego
116+
- name: Set Rego file path
117+
run: echo "REGO_FILE_PATH=${{ github.workspace }}/sample.rego" >> $GITHUB_ENV
118+
- name: Start finch-daemon with opa Authz
119+
run: sudo bin/finch-daemon --debug --enable-opa --rego-file ${{ github.workspace }}/sample.rego --socket-owner $UID &
120+
- name: Run opa e2e tests
121+
run: sudo -E make test-e2e-opa

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,14 @@ test-e2e: linux
114114
TEST_E2E=1 \
115115
$(GINKGO) $(GFLAGS) ./e2e/...
116116

117+
.PHONY: test-e2e-opa
118+
test-e2e-opa: linux
119+
DOCKER_HOST="unix:///run/finch.sock" \
120+
DOCKER_API_VERSION="v1.43" \
121+
OPA_E2E=1 \
122+
TEST_E2E=1 \
123+
$(GINKGO) $(GFLAGS) ./e2e/...
124+
117125
.PHONY: licenses
118126
licenses:
119127
PATH=$(BIN):$(PATH) go-licenses report --template="scripts/third-party-license.tpl" --ignore github.com/runfinch ./... > THIRD_PARTY_LICENSES

cmd/finch-daemon/main.go

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,16 @@ func run(options *DaemonOptions) error {
200200

201201
defer func() {
202202
if options.regoFileLock != nil {
203+
// unlock the rego file upon daemon exit
203204
if err := options.regoFileLock.Unlock(); err != nil {
204205
logrus.Errorf("failed to unlock Rego file: %v", err)
205206
}
206207
logger.Infof("rego file unlocked")
207-
// todo : chmod to read-write permissions
208+
209+
// make rego file editable upon daemon exit
210+
if err := os.Chmod(options.regoFilePath, 0600); err != nil {
211+
logrus.Errorf("failed to change file permissions of rego file: %v", err)
212+
}
208213
}
209214
}()
210215

@@ -293,39 +298,26 @@ func defineDockerConfig(uid int) error {
293298
})
294299
}
295300

301+
// checkRegoFileValidity verifies that the given rego file exists and has the right file extension
296302
func checkRegoFileValidity(filePath string) error {
297-
fmt.Println("checking file validity.....")
298303
if _, err := os.Stat(filePath); os.IsNotExist(err) {
299304
return fmt.Errorf("provided Rego file path does not exist: %s", filePath)
300305
}
301306

302-
// Check if the file has a valid extension (.rego, .yaml, or .json)
303-
// validExtensions := []string{".rego", ".yaml", ".yml", ".json"}
307+
// Check if the file has a valid extension (.rego)
304308
fileExt := strings.ToLower(filepath.Ext(options.regoFilePath))
305309

306310
if fileExt != ".rego" {
307311
return fmt.Errorf("invalid file extension for Rego file. Only .rego files are supported")
308312
}
309313

310-
// isValidExtension := false
311-
// for _, ext := range validExtensions {
312-
// if fileExt == ext {
313-
// isValidExtension = true
314-
// break
315-
// }
316-
// }
317-
318-
// if !isValidExtension {
319-
// return fmt.Errorf("Invalid file extension for Rego file. Allowed extensions are: %v", validExtensions)
320-
// }
321-
322-
fmt.Println(" file valid!")
323314
return nil
324315
}
325316

326-
// todo : rename this function to be more descriptve
317+
// sanitizeRegoFile validates and prepares the Rego policy file for use.
318+
// It checks validates the file, acquires a file lock,
319+
// and sets rego file to be read-only.
327320
func sanitizeRegoFile(options *DaemonOptions) (string, error) {
328-
fmt.Println("sanitizeRegoFile called.....")
329321
if options.regoFilePath != "" {
330322
if !options.enableOpa {
331323
return "", fmt.Errorf("rego file path was provided without the --enable-opa flag, please provide the --enable-opa flag") // todo, can we default to setting this flag ourselves is this better UX?
@@ -351,7 +343,7 @@ func sanitizeRegoFile(options *DaemonOptions) (string, error) {
351343
}
352344

353345
// Change file permissions to read-only
354-
err = os.Chmod(options.regoFilePath, 0444) // read-only for all users
346+
err = os.Chmod(options.regoFilePath, 0400)
355347
if err != nil {
356348
fileLock.Unlock()
357349
return "", fmt.Errorf("error changing rego file permissions: %v", err)

e2e/e2e_test.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package e2e
55

66
import (
77
"flag"
8+
"fmt"
89
"log"
910
"os"
1011
"strings"
@@ -25,8 +26,12 @@ var SubjectPrefix = flag.String("daemon-context-subject-prefix", "", `A string w
2526
var PrefixedSubjectEnv = flag.String("daemon-context-subject-env", "", `Environment to add when running a prefixed subject, in the form of a string like "EXAMPLE=foo EXAMPLE2=bar"`)
2627

2728
func TestRun(t *testing.T) {
28-
if os.Getenv("TEST_E2E") != "1" {
29-
t.Skip("E2E tests skipped. Set TEST_E2E=1 to run these tests")
29+
if os.Getenv("OPA_E2E") == "1" {
30+
runOPATests(t)
31+
} else if os.Getenv("TEST_E2E") == "1" {
32+
runE2ETests(t)
33+
} else {
34+
t.Skip("E2E tests skipped. Set TEST_E2E=1 to run regular E2E tests or OPA_E2E=1 to run OPA middleware tests")
3035
}
3136

3237
if err := parseTestFlags(); err != nil {
@@ -35,6 +40,34 @@ func TestRun(t *testing.T) {
3540
}
3641

3742
opt, _ := option.New([]string{*Subject, "--namespace", "finch"})
43+
}
44+
45+
func runOPATests(t *testing.T) {
46+
opt, _ := option.New([]string{*Subject, "--namespace", "finch"})
47+
48+
ginkgo.SynchronizedBeforeSuite(func() []byte {
49+
tests.SetupLocalRegistry(opt)
50+
return nil
51+
}, func(bytes []byte) {})
52+
53+
ginkgo.SynchronizedAfterSuite(func() {
54+
tests.CleanupLocalRegistry(opt)
55+
// clean up everything after the local registry is cleaned up
56+
command.RemoveAll(opt)
57+
}, func() {})
58+
59+
const description = "Finch Daemon OPA E2E Tests"
60+
ginkgo.Describe(description, func() {
61+
tests.OpaMiddlewareTest(opt)
62+
fmt.Print(opt)
63+
})
64+
65+
gomega.RegisterFailHandler(ginkgo.Fail)
66+
ginkgo.RunSpecs(t, description)
67+
}
68+
69+
func runE2ETests(t *testing.T) {
70+
opt, _ := option.New([]string{*Subject, "--namespace", "finch"})
3871

3972
ginkgo.SynchronizedBeforeSuite(func() []byte {
4073
tests.SetupLocalRegistry(opt)

e2e/tests/opa_middleware.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package tests
5+
6+
import (
7+
"bytes"
8+
"encoding/json"
9+
"fmt"
10+
"net/http"
11+
"os"
12+
13+
. "github.com/onsi/ginkgo/v2"
14+
. "github.com/onsi/gomega"
15+
"github.com/runfinch/common-tests/command"
16+
"github.com/runfinch/common-tests/option"
17+
18+
"github.com/runfinch/finch-daemon/api/types"
19+
"github.com/runfinch/finch-daemon/e2e/client"
20+
)
21+
22+
// OpaMiddlewareTest tests the OPA functionality.
23+
func OpaMiddlewareTest(opt *option.Option) {
24+
Describe("test opa middleware functionality", func() {
25+
var (
26+
uClient *http.Client
27+
version string
28+
wantContainerName string
29+
options types.ContainerCreateRequest
30+
createUrl string
31+
)
32+
BeforeEach(func() {
33+
// create a custom client to use http over unix sockets
34+
uClient = client.NewClient(GetDockerHostUrl())
35+
// get the docker api version that will be tested
36+
version = GetDockerApiVersion()
37+
wantContainerName = fmt.Sprintf("/%s", testContainerName)
38+
// set default container options
39+
options = types.ContainerCreateRequest{}
40+
options.Image = defaultImage
41+
createUrl = client.ConvertToFinchUrl(version, "/containers/create")
42+
})
43+
AfterEach(func() {
44+
command.RemoveAll(opt)
45+
})
46+
It("should allow GET version API request", func() {
47+
res, err := uClient.Get(client.ConvertToFinchUrl("", "/version"))
48+
Expect(err).ShouldNot(HaveOccurred())
49+
jd := json.NewDecoder(res.Body)
50+
var v types.VersionInfo
51+
err = jd.Decode(&v)
52+
Expect(err).ShouldNot(HaveOccurred())
53+
Expect(v.Version).ShouldNot(BeNil())
54+
Expect(v.ApiVersion).Should(Equal("1.43"))
55+
fmt.Println(version)
56+
})
57+
58+
It("shold allow GET containers API request", func() {
59+
id := command.StdoutStr(opt, "run", "-d", "--name", testContainerName, defaultImage, "sleep", "infinity")
60+
want := []types.ContainerListItem{
61+
{
62+
Id: id[:12],
63+
Names: []string{wantContainerName},
64+
},
65+
}
66+
67+
res, err := uClient.Get(client.ConvertToFinchUrl(version, "/containers/json"))
68+
Expect(err).Should(BeNil())
69+
Expect(res.StatusCode).Should(Equal(http.StatusOK))
70+
var got []types.ContainerListItem
71+
err = json.NewDecoder(res.Body).Decode(&got)
72+
Expect(err).Should(BeNil())
73+
Expect(len(got)).Should(Equal(2))
74+
got = filterContainerList(got)
75+
Expect(got).Should(ContainElements(want))
76+
})
77+
78+
It("shold disallow POST containers/create API request", func() {
79+
options.Cmd = []string{"echo", "hello world"}
80+
81+
reqBody, err := json.Marshal(options)
82+
Expect(err).Should(BeNil())
83+
84+
fmt.Println("createUrl = ", createUrl)
85+
res, _ := uClient.Post(createUrl, "application/json", bytes.NewReader(reqBody))
86+
87+
Expect(res.StatusCode).Should(Equal(http.StatusForbidden))
88+
})
89+
90+
It("should not allow updates to the rego file", func() {
91+
regoFilePath := os.Getenv("REGO_FILE_PATH")
92+
Expect(regoFilePath).NotTo(BeEmpty(), "REGO_FILE_PATH environment variable should be set")
93+
94+
fileInfo, err := os.Stat(regoFilePath)
95+
Expect(err).NotTo(HaveOccurred(), "Failed to get Rego file info")
96+
97+
// Check file permissions
98+
mode := fileInfo.Mode()
99+
Expect(mode.Perm()).To(Equal(os.FileMode(0400)), "Rego file should be read-only (0400)")
100+
})
101+
})
102+
}

0 commit comments

Comments
 (0)