Skip to content

Commit

Permalink
Initial Vault HCP Library commit
Browse files Browse the repository at this point in the history
  • Loading branch information
biazmoreira committed Oct 31, 2023
1 parent fef77cb commit 34c6b1c
Show file tree
Hide file tree
Showing 17 changed files with 3,842 additions and 245 deletions.
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,9 @@ fmtcheck:

.PHONY: fmt
fmt:
gofumpt -l -w .
gofumpt -l -w .

mocks:
go install github.com/vektra/mockery/[email protected]
mockery --srcpkg github.com/hashicorp/hcp-sdk-go/clients/cloud-resource-manager/stable/2019-12-10/client/organization_service --name=ClientService
mockery --srcpkg github.com/hashicorp/hcp-sdk-go/clients/cloud-resource-manager/stable/2019-12-10/client/project_service --name=ClientService
32 changes: 0 additions & 32 deletions cmd/vault-plugin-scaffolding/main.go

This file was deleted.

18 changes: 18 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package vaulthcplib

import "github.com/mitchellh/cli"

func InitHCPCommand(ui cli.Ui) map[string]cli.CommandFactory {
return map[string]cli.CommandFactory{
"hcp connect": func() (cli.Command, error) {
return &HCPConnectCommand{
Ui: ui,
}, nil
},
"hcp disconnect": func() (cli.Command, error) {
return &HCPDisconnectCommand{
Ui: ui,
}, nil
},
}
}
15 changes: 15 additions & 0 deletions command_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package vaulthcplib

import (
"testing"

"github.com/mitchellh/cli"
"github.com/stretchr/testify/assert"
)

func Test_InitHCPCommand(t *testing.T) {
cmdMap := InitHCPCommand(&cli.MockUi{})

assert.Contains(t, cmdMap, "hcp connect")
assert.Contains(t, cmdMap, "hcp disconnect")
}
155 changes: 155 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package vaulthcplib

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"time"

"github.com/hashicorp/hcp-sdk-go/config"
)

const (
defaultDirectory = ".config/hcp/hvd"
testDirectory = "hcptest"
fileName = "hvd_proxy_config.json"
directoryPermissions = 0755

envVarCacheTestMode = "HCP_CACHE_TEST_MODE"
)

type HCPToken struct {
AccessToken string `json:"access_token,omitempty"`
AccessTokenExpiry time.Time `json:"access_token_expiry,omitempty"`
ProxyAddr string `json:"proxy_addr,omitempty"`
}

func GetHCPToken() (*HCPToken, error) {
configCache, err := readConfig()
if err != nil {
return nil, err
}
if configCache == nil {
return nil, nil
}

// this will either get from a cache file or
opts := []config.HCPConfigOption{
config.WithoutLogging(),
config.WithoutBrowserLogin(),
config.FromEnv(),
}
if configCache.ClientID != "" && configCache.SecretID != "" {
opts = append(opts, config.WithClientCredentials(configCache.ClientID, configCache.SecretID))
}
hcp, err := config.NewHCPConfig(opts...)

tk, err := hcp.Token()
if err != nil {
return nil, fmt.Errorf("failed to retrieve the HCP token: %w", err)
}

return &HCPToken{
AccessToken: tk.AccessToken,
AccessTokenExpiry: tk.Expiry,
ProxyAddr: configCache.ProxyAddr,
}, nil
}

type HCPConfigCache struct {
ClientID string
SecretID string
ProxyAddr string
}

// Write saves HCP auth data in a common location in the home directory.
func writeConfig(addr string, clientID string, secretID string) error {
credentialPath, credentialDirectory, err := getConfigPaths()
if err != nil {
return fmt.Errorf("failed to retrieve credential path and directory: %v", err)
}

err = os.MkdirAll(credentialDirectory, directoryPermissions)
if err != nil {
return fmt.Errorf("failed to create credential directory: %v", err)
}

cache := &HCPConfigCache{
ClientID: clientID,
SecretID: secretID,
ProxyAddr: addr,
}
cacheJSON, err := json.Marshal(cache)
if err != nil {
return fmt.Errorf("failed to marshal the struct to json: %v", err)
}

err = os.WriteFile(credentialPath, cacheJSON, directoryPermissions)
if err != nil {
return fmt.Errorf("failed to write config to the cache file: %v", err)
}

return nil
}

// readConfig opens the saved HCP auth data and returns the token.
func readConfig() (*HCPConfigCache, error) {
configPath, _, err := getConfigPaths()
if err != nil {
return nil, fmt.Errorf("failed to retrieve config path and directory: %v", err)
}

var cache HCPConfigCache
if _, err = os.Stat(configPath); os.IsNotExist(err) {
return nil, nil
}

rawJSON, err := os.ReadFile(configPath)
if err != nil {
return nil, fmt.Errorf("failed to read file from user's config path: %v", err)
}

err = json.Unmarshal(rawJSON, &cache)
if err != nil {
return nil, err
}
return &cache, nil
}

func eraseConfig() error {
_, credentialDirectory, err := getConfigPaths()
if err != nil {
return fmt.Errorf("failed to retrieve credential path and directory: %v", err)
}

err = os.RemoveAll(credentialDirectory)
if err != nil {
return fmt.Errorf("failed to remove config directory: %v", err)
}

return nil
}

// getCredentialPaths returns the complete credential path and directory.
func getConfigPaths() (configPath string, configDirectory string, err error) {
// Get the user's home directory.
userHome, err := os.UserHomeDir()
if err != nil {
return "", "", fmt.Errorf("failed to retrieve user's home directory path: %v", err)
}

directoryName := defaultDirectory
// If in test mode, use test directory.
if testMode, ok := os.LookupEnv(envVarCacheTestMode); ok {
if testMode == "true" {
directoryName = testDirectory
}
}

// Determine absolute path to config file and directory.
configDirectory = filepath.Join(userHome, directoryName)
configPath = filepath.Join(userHome, directoryName, fileName)

return configPath, configDirectory, nil
}
52 changes: 52 additions & 0 deletions config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package vaulthcplib

import (
"os"
"testing"

"github.com/stretchr/testify/assert"
)

func Test_GetHCPConfiguration(t *testing.T) {
cases := map[string]struct {
Valid bool
}{
"valid hcp configuration": {
Valid: true,
},
"empty hcp configuration": {
Valid: false,
},
}

for n, tst := range cases {
t.Run(n, func(t *testing.T) {
CacheSetup(t, tst.Valid)

tk, err := GetHCPToken()

assert.NoError(t, err)

if tst.Valid {
assert.Equal(t, "https://hcp-proxy.addr:8200", tk.ProxyAddr)
assert.Contains(t, tk.AccessToken, "Test.Access.Token")
assert.NotEmpty(t, tk.AccessTokenExpiry)
} else {
assert.Nil(t, tk)
assert.Nil(t, err)
}

})
}
}

func Test_GetHCPConfiguration_EraseConfig(t *testing.T) {
err := os.Setenv(envVarCacheTestMode, "true")
assert.NoError(t, err)

err = eraseConfig()
assert.NoError(t, err)

_, err = GetHCPToken()
assert.NoError(t, err)
}
Loading

0 comments on commit 34c6b1c

Please sign in to comment.