From 3119cb43f2e84d9aeb669da8cc627c8347358584 Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Mon, 13 Jul 2026 17:39:07 +0800 Subject: [PATCH] test(e2e): add admission module e2e test suite Verify service-level admission control gating by client source IP, in both whitelist and blacklist modes. Contrasts a loopback client (curl inside the gost container) against an external client (curl inside the echo container) to exercise both admit and deny paths. --- tests/e2e/admission_test.go | 111 ++++++++++++++++++++ tests/e2e/testdata/admission/blacklist.yaml | 17 +++ tests/e2e/testdata/admission/whitelist.yaml | 18 ++++ 3 files changed, 146 insertions(+) create mode 100644 tests/e2e/admission_test.go create mode 100644 tests/e2e/testdata/admission/blacklist.yaml create mode 100644 tests/e2e/testdata/admission/whitelist.yaml diff --git a/tests/e2e/admission_test.go b/tests/e2e/admission_test.go new file mode 100644 index 0000000..2a6897c --- /dev/null +++ b/tests/e2e/admission_test.go @@ -0,0 +1,111 @@ +package e2e + +import ( + "context" + "fmt" + "io" + "testing" + + "github.com/stretchr/testify/suite" + "github.com/testcontainers/testcontainers-go" +) + +// AdmissionSuite verifies service-level admission control, which gates +// connections by the client's source address. It contrasts a loopback client +// (curl run inside the gost container, source 127.0.0.1) against an external +// client (curl run inside the echo container, source = its container IP). +type AdmissionSuite struct { + suite.Suite + ctx context.Context + echoC testcontainers.Container + echoIP string +} + +func (s *AdmissionSuite) SetupSuite() { + s.ctx = context.Background() + + echoC, err := RunEchoContainer(s.ctx, SharedNetworkName) + s.Require().NoError(err) + s.echoC = echoC + + echoIP, err := echoC.ContainerIP(s.ctx) + s.Require().NoError(err) + s.echoIP = echoIP +} + +func (s *AdmissionSuite) TearDownSuite() { + if s.echoC != nil { + s.echoC.Terminate(s.ctx) + } +} + +// curlIn runs curl inside the given container, proxying through the gost proxy +// at proxyAddr to the echo server, and returns the response body. An admitted +// request returns "hello-gost"; a denied connection returns an empty body. +func (s *AdmissionSuite) curlIn(c testcontainers.Container, proxyAddr string) string { + cmd := []string{ + "curl", "-s", + "-x", fmt.Sprintf("http://%s", proxyAddr), + fmt.Sprintf("http://%s:5678", s.echoIP), + } + _, out, err := c.Exec(s.ctx, cmd) + s.Require().NoError(err) + + body, err := io.ReadAll(out) + s.Require().NoError(err) + return string(body) +} + +// TestWhitelistAdmitLoopback verifies that a whitelisted source (127.0.0.1, +// a loopback client inside the gost container) is admitted and reaches the +// echo server. +func (s *AdmissionSuite) TestWhitelistAdmitLoopback() { + gostC, err := RunGostContainerWithOptions(s.ctx, SharedNetworkName, + "testdata/admission/whitelist.yaml", []string{"gost-proxy"}, []string{"8080/tcp"}) + s.Require().NoError(err) + defer gostC.Terminate(s.ctx) + + body := s.curlIn(gostC, "127.0.0.1:8080") + s.Require().Contains(body, "hello-gost") +} + +// TestWhitelistDenyExternal verifies that a non-whitelisted source (an external +// container, not 127.0.0.1) is denied, so the request never reaches the echo +// server. +func (s *AdmissionSuite) TestWhitelistDenyExternal() { + gostC, err := RunGostContainerWithOptions(s.ctx, SharedNetworkName, + "testdata/admission/whitelist.yaml", []string{"gost-proxy"}, []string{"8080/tcp"}) + s.Require().NoError(err) + defer gostC.Terminate(s.ctx) + + body := s.curlIn(s.echoC, "gost-proxy:8080") + s.Require().NotContains(body, "hello-gost") +} + +// TestBlacklistDenyLoopback verifies that a blacklisted source (127.0.0.1, +// a loopback client inside the gost container) is denied. +func (s *AdmissionSuite) TestBlacklistDenyLoopback() { + gostC, err := RunGostContainerWithOptions(s.ctx, SharedNetworkName, + "testdata/admission/blacklist.yaml", []string{"gost-proxy"}, []string{"8080/tcp"}) + s.Require().NoError(err) + defer gostC.Terminate(s.ctx) + + body := s.curlIn(gostC, "127.0.0.1:8080") + s.Require().NotContains(body, "hello-gost") +} + +// TestBlacklistAdmitExternal verifies that a source outside the blacklist (an +// external container, not 127.0.0.1) is admitted and reaches the echo server. +func (s *AdmissionSuite) TestBlacklistAdmitExternal() { + gostC, err := RunGostContainerWithOptions(s.ctx, SharedNetworkName, + "testdata/admission/blacklist.yaml", []string{"gost-proxy"}, []string{"8080/tcp"}) + s.Require().NoError(err) + defer gostC.Terminate(s.ctx) + + body := s.curlIn(s.echoC, "gost-proxy:8080") + s.Require().Contains(body, "hello-gost") +} + +func TestAdmissionSuite(t *testing.T) { + suite.Run(t, new(AdmissionSuite)) +} diff --git a/tests/e2e/testdata/admission/blacklist.yaml b/tests/e2e/testdata/admission/blacklist.yaml new file mode 100644 index 0000000..2c5e60b --- /dev/null +++ b/tests/e2e/testdata/admission/blacklist.yaml @@ -0,0 +1,17 @@ +# HTTP proxy gated by a blacklist admission rule: clients whose source address +# is 127.0.0.1 are denied; everything else is admitted. A loopback client (curl +# inside the gost container) is denied; an external client (a different +# container) is admitted and reaches the echo server. +services: + - name: proxy + addr: ":8080" + admission: admission-0 + handler: + type: http + listener: + type: tcp + +admissions: + - name: admission-0 + matchers: + - 127.0.0.1 diff --git a/tests/e2e/testdata/admission/whitelist.yaml b/tests/e2e/testdata/admission/whitelist.yaml new file mode 100644 index 0000000..9702681 --- /dev/null +++ b/tests/e2e/testdata/admission/whitelist.yaml @@ -0,0 +1,18 @@ +# HTTP proxy gated by a whitelist admission rule: only clients whose source +# address is 127.0.0.1 are admitted. A loopback client (curl inside the gost +# container) is admitted and reaches the echo server; an external client (a +# different container) is denied at accept time. +services: + - name: proxy + addr: ":8080" + admission: admission-0 + handler: + type: http + listener: + type: tcp + +admissions: + - name: admission-0 + whitelist: true + matchers: + - 127.0.0.1