From ce2f1fddb9e6e9a1862e04adbd4cae12a37ca2e9 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Fri, 29 Sep 2023 18:43:28 +0200 Subject: [PATCH] =?UTF-8?q?=E2=AD=90=EF=B8=8F=20create=20unique=20terrafor?= =?UTF-8?q?m=20platform=20id=20for=20terraform=20when=20used=20with=20git?= =?UTF-8?q?=20(#1983)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- providers/terraform/provider/detector.go | 70 ++++++++++++++----- providers/terraform/provider/detector_test.go | 25 +++++++ 2 files changed, 79 insertions(+), 16 deletions(-) create mode 100644 providers/terraform/provider/detector_test.go diff --git a/providers/terraform/provider/detector.go b/providers/terraform/provider/detector.go index 7c6e8effdc..0f67b443f2 100644 --- a/providers/terraform/provider/detector.go +++ b/providers/terraform/provider/detector.go @@ -6,6 +6,8 @@ package provider import ( "crypto/sha256" "encoding/hex" + "errors" + "fmt" "os" "path" "path/filepath" @@ -48,26 +50,37 @@ func (s *Service) detect(asset *inventory.Asset, conn *connection.Connection) er } asset.Platform = p - projectPath := asset.Connections[0].Options["path"] - absPath, _ := filepath.Abs(projectPath) - h := sha256.New() - h.Write([]byte(absPath)) - hash := hex.EncodeToString(h.Sum(nil)) - platformID := "//platformid.api.mondoo.app/runtime/terraform/hash/" + hash - asset.Connections[0].PlatformId = platformID - asset.PlatformIds = []string{platformID} + // we always prefer the git url since it is more reliable + url, ok := asset.Connections[0].Options["ssh-url"] + if ok { + domain, org, repo, err := parseSSHURL(url) + if err != nil { + return err + } + platformID := "//platformid.api.mondoo.app/runtime/terraform/domain/" + domain + "/org/" + org + "/repo/" + repo + asset.Connections[0].PlatformId = platformID + asset.PlatformIds = []string{platformID} + asset.Name = "Terraform Static Analysis " + org + "/" + repo + return nil + } - name := "" - if projectPath != "" { - // manifest parent directory name - name = projectNameFromPath(projectPath) + projectPath, ok := asset.Connections[0].Options["path"] + if ok { + absPath, _ := filepath.Abs(projectPath) + h := sha256.New() + h.Write([]byte(absPath)) + hash := hex.EncodeToString(h.Sum(nil)) + platformID := "//platformid.api.mondoo.app/runtime/terraform/hash/" + hash + asset.Connections[0].PlatformId = platformID + asset.PlatformIds = []string{platformID} + asset.Name = "Terraform Static Analysis " + parseNameFromPath(projectPath) + return nil } - asset.Name = "Terraform Static Analysis " + name - return nil + return errors.New("could not determine platform id for Terraform asset") } -func projectNameFromPath(file string) string { +func parseNameFromPath(file string) string { // if it is a local file (which may not be true) name := "" fi, err := os.Stat(file) @@ -92,9 +105,34 @@ func projectNameFromPath(file string) string { if name == "." { abspath, err := filepath.Abs(name) if err == nil { - name = projectNameFromPath(abspath) + name = parseNameFromPath(abspath) } } return name } + +func parseSSHURL(url string) (string, string, string, error) { + parts := strings.Split(url, "@") + if len(parts) != 2 { + return "", "", "", fmt.Errorf("malformed URL") + } + + // Get the provider + providerParts := strings.Split(parts[1], ":") + if len(providerParts) != 2 { + return "", "", "", fmt.Errorf("malformed URL") + } + provider := providerParts[0] + + // Now split the second part at the slash to separate the org and repo + orgRepoParts := strings.Split(providerParts[1], "/") + if len(orgRepoParts) != 2 { + return "", "", "", fmt.Errorf("malformed URL") + } + + // The repo name includes .git, so we remove that + repo := strings.TrimSuffix(orgRepoParts[1], ".git") + + return provider, orgRepoParts[0], repo, nil +} diff --git a/providers/terraform/provider/detector_test.go b/providers/terraform/provider/detector_test.go new file mode 100644 index 0000000000..bc10b17fbc --- /dev/null +++ b/providers/terraform/provider/detector_test.go @@ -0,0 +1,25 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package provider + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDetectNameFromFile(t *testing.T) { + name := parseNameFromPath("/test/path/nested/terraform.tfstate") + assert.Equal(t, "nested", name) +} + +func TestDetectNameFromSsh(t *testing.T) { + url := "git@gitlab.com:exampleorg/example-gitlab.git" + domain, org, repo, err := parseSSHURL(url) + require.NoError(t, err) + assert.Equal(t, "gitlab.com", domain) + assert.Equal(t, "exampleorg", org) + assert.Equal(t, "example-gitlab", repo) +}