Skip to content

Commit 4249f55

Browse files
committed
e2e: add insecure deployment test
This adds a basic E2E test for the insecure runtimes.
1 parent 33beaf6 commit 4249f55

5 files changed

Lines changed: 149 additions & 2 deletions

File tree

.github/workflows/e2e_manual.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ on:
1919
- gpu
2020
- imagepuller-auth
2121
- imagestore
22+
- insecure
2223
- kds-pcs-downtime
2324
- memdump
2425
- multi-runtime-class

e2e/insecure/insecure_test.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright 2026 Edgeless Systems GmbH
2+
// SPDX-License-Identifier: BUSL-1.1
3+
4+
//go:build e2e
5+
6+
package insecure
7+
8+
import (
9+
"context"
10+
"flag"
11+
"os"
12+
"strings"
13+
"testing"
14+
"time"
15+
16+
"github.com/edgelesssys/contrast/e2e/internal/contrasttest"
17+
"github.com/edgelesssys/contrast/internal/kuberesource"
18+
"github.com/edgelesssys/contrast/internal/manifest"
19+
"github.com/edgelesssys/contrast/internal/platforms"
20+
"github.com/stretchr/testify/assert"
21+
"github.com/stretchr/testify/require"
22+
)
23+
24+
const (
25+
secureDeployment = "secure-pod"
26+
insecureDeployment = "insecure-pod"
27+
)
28+
29+
// TestInsecure deploys a secure and an insecure pod side by side and verifies
30+
// that only the secure pod runs inside a TEE.
31+
func TestInsecure(t *testing.T) {
32+
platform, err := platforms.FromString(contrasttest.Flags.PlatformStr)
33+
require.NoError(t, err)
34+
35+
insecurePlatform := platform.InsecureVariant()
36+
if insecurePlatform == platforms.Unknown {
37+
t.Skip("no insecure variant for platform", platform)
38+
}
39+
40+
// The generate and verify commands require this env var for insecure platforms.
41+
t.Setenv("CONTRAST_ALLOW_INSECURE_RUNTIMES", "1")
42+
43+
ct := contrasttest.New(t)
44+
ct.Platform = insecurePlatform // Required so RunGenerate/RunVerify pass --INSECURE.
45+
46+
secureHandler, err := manifest.RuntimeHandler(platform)
47+
require.NoError(t, err)
48+
insecureHandler, err := manifest.RuntimeHandler(insecurePlatform)
49+
require.NoError(t, err)
50+
51+
resources := kuberesource.CoordinatorBundle()
52+
// Patch the coordinator with the insecure runtime handler.
53+
resources = kuberesource.PatchRuntimeHandlers(resources, insecureHandler)
54+
resources = kuberesource.AddPortForwarders(resources)
55+
56+
// Add deployments *after* PatchRuntimeHandlers to retain control over the RuntimeClassNames.
57+
resources = append(resources, kuberesource.DeploymentWithRuntimeClass(secureDeployment, secureHandler))
58+
resources = append(resources, kuberesource.DeploymentWithRuntimeClass(insecureDeployment, insecureHandler))
59+
60+
ct.Init(t, resources)
61+
require.True(t, t.Run("generate", ct.Generate), "contrast generate needs to succeed for subsequent tests")
62+
require.True(t, t.Run("apply", ct.Apply), "Kubernetes resources need to be applied for subsequent tests")
63+
require.True(t, t.Run("set", ct.Set), "contrast set needs to succeed for subsequent tests")
64+
require.True(t, t.Run("contrast verify", ct.Verify), "contrast verify needs to succeed for subsequent tests")
65+
66+
t.Run("pods use correct runtime classes", func(t *testing.T) {
67+
ctx, cancel := context.WithTimeout(t.Context(), ct.FactorPlatformTimeout(2*time.Minute))
68+
defer cancel()
69+
require := require.New(t)
70+
71+
securePods, err := ct.Kubeclient.PodsFromDeployment(ctx, ct.Namespace, secureDeployment)
72+
require.NoError(err)
73+
require.Len(securePods, 1)
74+
assert.True(t, strings.HasPrefix(*securePods[0].Spec.RuntimeClassName, secureHandler))
75+
76+
insecurePods, err := ct.Kubeclient.PodsFromDeployment(ctx, ct.Namespace, insecureDeployment)
77+
require.NoError(err)
78+
require.Len(insecurePods, 1)
79+
assert.True(t, strings.HasPrefix(*insecurePods[0].Spec.RuntimeClassName, insecureHandler))
80+
})
81+
82+
t.Run("pods start", func(t *testing.T) {
83+
ctx, cancel := context.WithTimeout(t.Context(), ct.FactorPlatformTimeout(2*time.Minute))
84+
defer cancel()
85+
require := require.New(t)
86+
87+
require.NoError(ct.Kubeclient.WaitForDeployment(ctx, ct.Namespace, secureDeployment))
88+
require.NoError(ct.Kubeclient.WaitForDeployment(ctx, ct.Namespace, insecureDeployment))
89+
})
90+
91+
t.Run("secure pod runs in TEE", func(t *testing.T) {
92+
ctx, cancel := context.WithTimeout(t.Context(), ct.FactorPlatformTimeout(1*time.Minute))
93+
defer cancel()
94+
require := require.New(t)
95+
96+
stdout, stderr, err := ct.Kubeclient.ExecDeployment(ctx, ct.Namespace, secureDeployment, []string{
97+
"/usr/local/bin/bash", "-c", "dmesg | grep -i -E 'tdx|sev|snp'",
98+
})
99+
require.NoError(err, "stderr: %q", stderr)
100+
require.NotEmpty(strings.TrimSpace(stdout), "expected TEE-related dmesg output in secure pod")
101+
})
102+
103+
t.Run("insecure pod does not run in TEE", func(t *testing.T) {
104+
ctx, cancel := context.WithTimeout(t.Context(), ct.FactorPlatformTimeout(1*time.Minute))
105+
defer cancel()
106+
107+
// grep exits with 1 when no lines match, so we expect an error here.
108+
stdout, _, _ := ct.Kubeclient.ExecDeployment(ctx, ct.Namespace, insecureDeployment, []string{
109+
"/usr/local/bin/bash", "-c", "dmesg | grep -i -E 'tdx|sev|snp'",
110+
})
111+
assert.Empty(t, strings.TrimSpace(stdout), "expected no TEE-related dmesg output in insecure pod")
112+
})
113+
}
114+
115+
func TestMain(m *testing.M) {
116+
contrasttest.RegisterFlags()
117+
flag.Parse()
118+
119+
os.Exit(m.Run())
120+
}

e2e/internal/contrasttest/contrasttest.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ func (ct *ContrastTest) RunGenerate(ctx context.Context) error {
231231
if Flags.GenpolicyCachePath != "" {
232232
args = append(args, "--genpolicy-cache-path", Flags.GenpolicyCachePath)
233233
}
234+
if platforms.IsInsecure(ct.Platform) {
235+
args = append(args, "--INSECURE")
236+
}
234237
args = append(args, ct.WorkDir)
235238

236239
generate := cmd.NewGenerateCmd()
@@ -365,7 +368,11 @@ func (ct *ContrastTest) RunVerify(ctx context.Context) error {
365368
ctx, cancel := context.WithTimeout(ctx, 3*time.Minute)
366369
defer cancel()
367370

368-
if err := ct.runAgainstCoordinator(ctx, cmd.NewVerifyCmd()); err != nil {
371+
var verifyArgs []string
372+
if platforms.IsInsecure(ct.Platform) {
373+
verifyArgs = append(verifyArgs, "--INSECURE")
374+
}
375+
if err := ct.runAgainstCoordinator(ctx, cmd.NewVerifyCmd(), verifyArgs...); err != nil {
369376
return err
370377
}
371378

@@ -569,7 +576,8 @@ func (ct *ContrastTest) runAgainstCoordinator(ctx context.Context, cmd *cobra.Co
569576
// Baseline is AKS.
570577
func (ct *ContrastTest) FactorPlatformTimeout(timeout time.Duration) time.Duration {
571578
switch ct.Platform {
572-
case platforms.MetalQEMUSNP, platforms.MetalQEMUTDX, platforms.MetalQEMUSNPGPU, platforms.MetalQEMUTDXGPU:
579+
case platforms.MetalQEMUSNP, platforms.MetalQEMUTDX, platforms.MetalQEMUSNPGPU, platforms.MetalQEMUTDXGPU,
580+
platforms.MetalQEMUSNPInsecure, platforms.MetalQEMUTDXInsecure, platforms.MetalQEMUSNPGPUInsecure, platforms.MetalQEMUTDXGPUInsecure:
573581
return 2 * timeout
574582
default:
575583
panic(fmt.Sprintf("FactorPlatformTimeout not configured for platform %q", ct.Platform))

internal/platforms/platforms.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,23 @@ func (p Platform) String() string {
7575
}
7676
}
7777

78+
// InsecureVariant returns the insecure (non-CC) variant of the
79+
// platform, or Unknown if there is no such variant.
80+
func (p Platform) InsecureVariant() Platform {
81+
switch p {
82+
case MetalQEMUSNP:
83+
return MetalQEMUSNPInsecure
84+
case MetalQEMUTDX:
85+
return MetalQEMUTDXInsecure
86+
case MetalQEMUSNPGPU:
87+
return MetalQEMUSNPGPUInsecure
88+
case MetalQEMUTDXGPU:
89+
return MetalQEMUTDXGPUInsecure
90+
default:
91+
return Unknown
92+
}
93+
}
94+
7895
// MarshalJSON marshals a Platform type to a JSON string.
7996
func (p Platform) MarshalJSON() ([]byte, error) {
8097
return fmt.Appendf(nil, `"%s"`, p.String()), nil

packages/by-name/contrast/e2e/package.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ buildGoModule {
7171
"e2e/gpu"
7272
"e2e/imagepuller-auth"
7373
"e2e/imagestore"
74+
"e2e/insecure"
7475
"e2e/kds-pcs-downtime"
7576
"e2e/memdump"
7677
"e2e/multi-runtime-class"

0 commit comments

Comments
 (0)