github.com/Racer159/jackal@v0.32.7-0.20240401174413-0bd2339e4f2e/src/test/e2e/25_helm_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // SPDX-FileCopyrightText: 2021-Present The Jackal Authors
     3  
     4  // Package test provides e2e tests for Jackal.
     5  package test
     6  
     7  import (
     8  	"fmt"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  var helmChartsPkg string
    17  
    18  func TestHelm(t *testing.T) {
    19  	t.Log("E2E: Helm chart")
    20  	e2e.SetupWithCluster(t)
    21  
    22  	helmChartsPkg = filepath.Join("build", fmt.Sprintf("jackal-package-helm-charts-%s-0.0.1.tar.zst", e2e.Arch))
    23  
    24  	testHelmUninstallRollback(t)
    25  
    26  	testHelmAdoption(t)
    27  
    28  	t.Run("helm charts example", testHelmChartsExample)
    29  
    30  	t.Run("helm escaping", testHelmEscaping)
    31  }
    32  
    33  func testHelmChartsExample(t *testing.T) {
    34  	t.Parallel()
    35  	t.Log("E2E: Helm chart example")
    36  	tmpdir := t.TempDir()
    37  
    38  	// Create a package that has a tarball as a local chart
    39  	localTgzChartPath := filepath.Join("src", "test", "packages", "25-local-tgz-chart")
    40  	stdOut, stdErr, err := e2e.Jackal("package", "create", localTgzChartPath, "--tmpdir", tmpdir, "--confirm")
    41  	require.NoError(t, err, stdOut, stdErr)
    42  	defer e2e.CleanFiles(fmt.Sprintf("jackal-package-helm-charts-local-tgz-%s-0.0.1.tar.zst", e2e.Arch))
    43  
    44  	// Create a package that needs dependencies
    45  	evilChartDepsPath := filepath.Join("src", "test", "packages", "25-evil-chart-deps")
    46  	stdOut, stdErr, err = e2e.Jackal("package", "create", evilChartDepsPath, "--tmpdir", tmpdir, "--confirm")
    47  	require.Error(t, err, stdOut, stdErr)
    48  	require.Contains(t, e2e.StripMessageFormatting(stdErr), "could not download https://charts.jetstack.io/charts/cert-manager-v1.11.1.tgz")
    49  	require.FileExists(t, filepath.Join(evilChartDepsPath, "good-chart", "charts", "gitlab-runner-0.55.0.tgz"))
    50  
    51  	// Create a package with a chart name that doesn't exist in a repo
    52  	evilChartLookupPath := filepath.Join("src", "test", "packages", "25-evil-chart-lookup")
    53  	stdOut, stdErr, err = e2e.Jackal("package", "create", evilChartLookupPath, "--tmpdir", tmpdir, "--confirm")
    54  	require.Error(t, err, stdOut, stdErr)
    55  	require.Contains(t, e2e.StripMessageFormatting(stdErr), "chart \"asdf\" version \"6.4.0\" not found")
    56  	require.Contains(t, e2e.StripMessageFormatting(stdErr), "Available charts and versions from \"https://stefanprodan.github.io/podinfo\":")
    57  
    58  	// Create a test package (with a registry override (host+subpath to host+subpath) to test that as well)
    59  	stdOut, stdErr, err = e2e.Jackal("package", "create", "examples/helm-charts", "-o", "build", "--registry-override", "ghcr.io/stefanprodan=docker.io/stefanprodan", "--tmpdir", tmpdir, "--confirm")
    60  	require.NoError(t, err, stdOut, stdErr)
    61  
    62  	// Create a test package (with a registry override (host to host+subpath) to test that as well)
    63  	// expect to fail as ghcr.io is overridden and the expected final image doesn't exist but the override works well based on the error message in the output
    64  	stdOut, stdErr, err = e2e.Jackal("package", "create", "examples/helm-charts", "-o", "build", "--registry-override", "ghcr.io=localhost:555/noway", "--tmpdir", tmpdir, "--confirm")
    65  	require.Error(t, err, stdOut, stdErr)
    66  	require.Contains(t, string(stdErr), "localhost:555/noway")
    67  
    68  	// Create a test package (with a registry override (host+subpath to host) to test that as well)
    69  	// works same as the above failing test
    70  	stdOut, stdErr, err = e2e.Jackal("package", "create", "examples/helm-charts", "-o", "build", "--registry-override", "ghcr.io/stefanprodan=localhost:555", "--tmpdir", tmpdir, "--confirm")
    71  	require.Error(t, err, stdOut, stdErr)
    72  	require.Contains(t, string(stdErr), "localhost:555")
    73  
    74  	// Create the package (with a registry override (host to host) to test that as well)
    75  	stdOut, stdErr, err = e2e.Jackal("package", "create", "examples/helm-charts", "-o", "build", "--registry-override", "ghcr.io=docker.io", "--tmpdir", tmpdir, "--confirm")
    76  	require.NoError(t, err, stdOut, stdErr)
    77  
    78  	// Deploy the example package.
    79  	stdOut, stdErr, err = e2e.Jackal("package", "deploy", helmChartsPkg, "--confirm")
    80  	require.NoError(t, err, stdOut, stdErr)
    81  	require.Contains(t, string(stdErr), "registryOverrides", "registry overrides was not saved to build data")
    82  	require.Contains(t, string(stdErr), "docker.io", "docker.io not found in registry overrides")
    83  
    84  	// Remove the example package.
    85  	stdOut, stdErr, err = e2e.Jackal("package", "remove", "helm-charts", "--confirm")
    86  	require.NoError(t, err, stdOut, stdErr)
    87  }
    88  
    89  func testHelmEscaping(t *testing.T) {
    90  	t.Parallel()
    91  	t.Log("E2E: Helm chart escaping")
    92  
    93  	// Create the package.
    94  	stdOut, stdErr, err := e2e.Jackal("package", "create", "src/test/packages/25-evil-templates/", "--confirm")
    95  	require.NoError(t, err, stdOut, stdErr)
    96  
    97  	path := fmt.Sprintf("jackal-package-evil-templates-%s.tar.zst", e2e.Arch)
    98  
    99  	// Deploy the package.
   100  	stdOut, stdErr, err = e2e.Jackal("package", "deploy", path, "--confirm")
   101  	require.NoError(t, err, stdOut, stdErr)
   102  
   103  	// Verify the configmap was deployed, escaped, and contains all of its data
   104  	kubectlOut, _ := exec.Command("kubectl", "describe", "cm", "dont-template-me").Output()
   105  	require.Contains(t, string(kubectlOut), `alert: OOMKilled {{ "{{ \"random.Values\" }}" }}`)
   106  	require.Contains(t, string(kubectlOut), "backtick1: \"content with backticks `some random things`\"")
   107  	require.Contains(t, string(kubectlOut), "backtick2: \"nested templating with backticks {{` random.Values `}}\"")
   108  	require.Contains(t, string(kubectlOut), `description: Pod {{$labels.pod}} in {{$labels.namespace}} got OOMKilled`)
   109  	require.Contains(t, string(kubectlOut), `TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIG`)
   110  
   111  	// Remove the package.
   112  	stdOut, stdErr, err = e2e.Jackal("package", "remove", "evil-templates", "--confirm")
   113  	require.NoError(t, err, stdOut, stdErr)
   114  }
   115  
   116  func testHelmUninstallRollback(t *testing.T) {
   117  	t.Log("E2E: Helm Uninstall and Rollback")
   118  
   119  	goodPath := fmt.Sprintf("build/jackal-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch)
   120  	evilPath := fmt.Sprintf("jackal-package-dos-games-%s.tar.zst", e2e.Arch)
   121  
   122  	// Create the evil package (with the bad service).
   123  	stdOut, stdErr, err := e2e.Jackal("package", "create", "src/test/packages/25-evil-dos-games/", "--skip-sbom", "--confirm")
   124  	require.NoError(t, err, stdOut, stdErr)
   125  
   126  	// Deploy the evil package.
   127  	stdOut, stdErr, err = e2e.Jackal("package", "deploy", evilPath, "--timeout", "10s", "--confirm")
   128  	require.Error(t, err, stdOut, stdErr)
   129  
   130  	// This package contains SBOMable things but was created with --skip-sbom
   131  	require.Contains(t, string(stdErr), "This package does NOT contain an SBOM.")
   132  
   133  	// Ensure that this does not leave behind a dos-games chart
   134  	helmOut, err := exec.Command("helm", "list", "-n", "dos-games").Output()
   135  	require.NoError(t, err)
   136  	require.NotContains(t, string(helmOut), "jackal-f53a99d4a4dd9a3575bedf59cd42d48d751ae866")
   137  
   138  	// Deploy the good package.
   139  	stdOut, stdErr, err = e2e.Jackal("package", "deploy", goodPath, "--confirm")
   140  	require.NoError(t, err, stdOut, stdErr)
   141  
   142  	// Ensure that this does create a dos-games chart
   143  	helmOut, err = exec.Command("helm", "list", "-n", "dos-games").Output()
   144  	require.NoError(t, err)
   145  	require.Contains(t, string(helmOut), "jackal-f53a99d4a4dd9a3575bedf59cd42d48d751ae866")
   146  
   147  	// Deploy the evil package.
   148  	stdOut, stdErr, err = e2e.Jackal("package", "deploy", evilPath, "--timeout", "10s", "--confirm")
   149  	require.Error(t, err, stdOut, stdErr)
   150  
   151  	// Ensure that we rollback properly
   152  	helmOut, err = exec.Command("helm", "history", "-n", "dos-games", "jackal-f53a99d4a4dd9a3575bedf59cd42d48d751ae866", "--max", "1").Output()
   153  	require.NoError(t, err)
   154  	require.Contains(t, string(helmOut), "Rollback to 1")
   155  
   156  	// Deploy the evil package (again to ensure we check full history)
   157  	stdOut, stdErr, err = e2e.Jackal("package", "deploy", evilPath, "--timeout", "10s", "--confirm")
   158  	require.Error(t, err, stdOut, stdErr)
   159  
   160  	// Ensure that we rollback properly
   161  	helmOut, err = exec.Command("helm", "history", "-n", "dos-games", "jackal-f53a99d4a4dd9a3575bedf59cd42d48d751ae866", "--max", "1").Output()
   162  	require.NoError(t, err)
   163  	require.Contains(t, string(helmOut), "Rollback to 5")
   164  
   165  	// Remove the package.
   166  	stdOut, stdErr, err = e2e.Jackal("package", "remove", "dos-games", "--confirm")
   167  	require.NoError(t, err, stdOut, stdErr)
   168  }
   169  
   170  func testHelmAdoption(t *testing.T) {
   171  	t.Log("E2E: Helm Adopt a Deployment")
   172  
   173  	packagePath := fmt.Sprintf("build/jackal-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch)
   174  	deploymentManifest := "src/test/packages/25-manifest-adoption/deployment.yaml"
   175  
   176  	// Deploy dos-games manually into the cluster without Jackal
   177  	kubectlOut, _, _ := e2e.Kubectl("apply", "-f", deploymentManifest)
   178  	require.Contains(t, string(kubectlOut), "deployment.apps/game created")
   179  
   180  	// Deploy dos-games into the cluster with Jackal
   181  	stdOut, stdErr, err := e2e.Jackal("package", "deploy", packagePath, "--confirm", "--adopt-existing-resources")
   182  	require.NoError(t, err, stdOut, stdErr)
   183  
   184  	// Ensure that this does create a dos-games chart
   185  	helmOut, err := exec.Command("helm", "list", "-n", "dos-games").Output()
   186  	require.NoError(t, err)
   187  	require.Contains(t, string(helmOut), "jackal-f53a99d4a4dd9a3575bedf59cd42d48d751ae866")
   188  
   189  	// Remove the package.
   190  	stdOut, stdErr, err = e2e.Jackal("package", "remove", "dos-games", "--confirm")
   191  	require.NoError(t, err, stdOut, stdErr)
   192  }