Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 7 additions & 31 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,57 +1,33 @@
SHELL := /bin/bash
PROJECT := github.com/bwhaley/ssmsh
PKGS := $(shell go list ./... | grep -v /vendor)
EXECUTABLE := ssmsh
PKG := ssmsh
GIT_COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null)

.PHONY: build test golint docs $(PROJECT) $(PKGS) vendor
.PHONY: build test

VERSION := $(shell echo ${SSMSH_VERSION})
ifeq "$(VERSION)" ""
VERSION="auto-build"
endif

GOVERSION := $(shell go version | grep 1.17)
ifeq "$(GOVERSION)" ""
$(error must be running Go version 1.17.x)
endif

ifndef $(GOPATH)
GOPATH=$(shell go env GOPATH)
export GOPATH
endif

all: test build

FGT := $(GOPATH)/bin/fgt
$(FGT):
go get github.com/GeertJohan/fgt

GOLINT := $(GOPATH)/bin/golint
$(GOLINT):
go get golang.org/x/lint

DEP := $(GOPATH)/bin/dep
$(DEP):
go get -u github.com/golang/dep

GO_LDFLAGS := -X $(shell go list ./$(PACKAGE)).GitCommit=$(GIT_COMMIT) -X main.Version=${VERSION}

test: $(PKGS)

$(PKGS): $(GOLINT)
test:
@echo "FORMATTING"
go fmt $@
go fmt ./...
@echo "VETTING"
go vet -v ./...
@echo "LINTING"
golint $@
@echo "Vetting"
go vet -v $@
golangci-lint run ./...
@echo "TESTING"
go test -v $@

vendor: $(DEP)
$(DEP) ensure
go test -v ./...

build:
go build -ldflags "$(GO_LDFLAGS)" -o $(GOPATH)/bin/$(EXECUTABLE) $(PROJECT)
Expand Down
23 changes: 13 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ nix-env -i ssmsh

## Configuration

Set up [AWS credentials](http://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials).
Set up [AWS credentials](https://aws.github.io/aws-sdk-go-v2/docs/configuring-sdk/#specifying-credentials).

You can set up a `.ssmshrc` to configure `ssmsh`. By default, `ssmsh` will load `~/.ssmshrc` if it exists. Use the `-config` argument to set a different path.

Expand All @@ -55,7 +55,7 @@ A few notes on configuration:
* When setting the region, the `AWS_REGION` env var takes top priority, followed by the setting in `.ssmshrc`, followed by the value set in the AWS profile (if configured)
* When setting the profile, the `AWS_PROFILE` env var takes top priority, followed by the setting in `.ssmshrc`
* If you set a KMS key, it will only work in the region where that key is located. You can use the `key` command while in the shell to change the key.
* If the configuration file has `output=json`, the results of the `get` and `history` commands will be printed in JSON. The fields of the JSON results will be the same as in the respective Go structs. See the [`Parameter`](https://docs.aws.amazon.com/sdk-for-go/api/service/ssm/#Parameter) and [`ParameterHistory`](https://docs.aws.amazon.com/sdk-for-go/api/service/ssm/#ParameterHistory) docs.
* If the configuration file has `output=json`, the results of the `get` and `history` commands will be printed in JSON. The fields of the JSON results will be the same as in the respective Go structs. See the [`Parameter`](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/ssm/types#Parameter) and [`ParameterHistory`](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/ssm/types#ParameterHistory) docs.

## Usage
### Help
Expand Down Expand Up @@ -279,18 +279,21 @@ $ ssmsh put name=/dev/app/domain value="www.example.com" type=String description
MIT

## Contributing/compiling
1. Ensure you have at least go v1.17
1. Ensure you have at least go v1.21
```
$ go version
go version go1.17.6 darwin/arm64
go version go1.21.0 darwin/arm64
```
2. Ensure your `$GOPATH` exists and is in your `$PATH`
2. Ensure `$GOPATH/bin` is in your `$PATH`
```
export GOPATH=$HOME/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
export PATH=$PATH:$(go env GOPATH)/bin
```
3. Clone the repo and build:
```
git clone https://github.com/bwhaley/ssmsh.git
cd ssmsh
make
```
3. Run `go get github.com/bwhaley/ssmsh`
4. Run `cd $GOPATH/src/github.com/bwhaley/ssmsh && make` to build and install the binary to `$GOPATH/bin/ssmsh`


## Related tools
Expand All @@ -304,5 +307,5 @@ Tool | Description
Library | Use
------- | -----
[abiosoft/ishell](https://github.com/abiosoft/ishell) | The interactive shell for golang
[aws-sdk-go](https://github.com/aws/aws-sdk-go) | The AWS SDK for Go
[aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | The AWS SDK for Go
[mattn/go-shellwords](github.com/mattn/go-shellwords) | Parsing for the shell made easy
25 changes: 12 additions & 13 deletions aws/aws.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package aws

import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"context"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
)

func NewSession(region, profile string) *session.Session {
return session.Must(
session.NewSessionWithOptions(
session.Options{
SharedConfigState: session.SharedConfigEnable,
Config: aws.Config{
Region: aws.String(region),
},
Profile: profile,
},
),
func LoadConfig(region, profile string) aws.Config {
cfg, err := config.LoadDefaultConfig(context.TODO(),
config.WithRegion(region),
config.WithSharedConfigProfile(profile),
)
if err != nil {
panic("unable to load AWS config: " + err.Error())
}
return cfg
}
54 changes: 38 additions & 16 deletions commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"strings"

"github.com/abiosoft/ishell"
"github.com/bwhaley/ssmsh/config"
"github.com/bwhaley/ssmsh/parameterstore"
)

Expand All @@ -14,14 +13,12 @@ type fn func(*ishell.Context)
var (
shell *ishell.Shell
ps *parameterstore.ParameterStore
cfg *config.Config
)

// Init initializes the ssmsh subcommands
func Init(iShell *ishell.Shell, iPs *parameterstore.ParameterStore, iCfg *config.Config) {
func Init(iShell *ishell.Shell, iPs *parameterstore.ParameterStore) {
shell = iShell
ps = iPs
cfg = iCfg
registerCommand("cd", "change your relative location within the parameter store", cd, cdUsage)
registerCommand("cp", "copy source to dest", cp, cpUsage)
registerCommand("decrypt", "toggle parameter decryption", decrypt, decryptUsage)
Expand Down Expand Up @@ -99,20 +96,45 @@ func trim(with []string) (without []string) {
return without
}

func printResult(result interface{}) {
switch cfg.Default.Output {
case "json":
printJSON(result)
default:
shell.Printf("%+v\n", result)
func printResult(result any) {
raw, err := json.Marshal(result)
if err != nil {
shell.Println("Error with result: ", err)
return
}
}

func printJSON(result interface{}) {
resultJSON, err := json.MarshalIndent(result, "", " ")
cleaned := stripNulls(raw)
indented, err := json.MarshalIndent(cleaned, "", " ")
if err != nil {
shell.Println("Error with result: ", err)
} else {
shell.Println(string(resultJSON))
return
}
shell.Println(string(indented))
}

func stripNulls(data []byte) any {
var raw any
if err := json.Unmarshal(data, &raw); err != nil {
return raw
}
return cleanValue(raw)
}

func cleanValue(v any) any {
switch val := v.(type) {
case map[string]any:
cleaned := make(map[string]any)
for k, v := range val {
if v != nil {
cleaned[k] = cleanValue(v)
}
}
return cleaned
case []any:
for i, item := range val {
val[i] = cleanValue(item)
}
return val
default:
return v
}
}
11 changes: 6 additions & 5 deletions commands/key.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package commands

import (
"context"
"fmt"

"github.com/abiosoft/ishell"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/kms"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/kms"
saws "github.com/bwhaley/ssmsh/aws"
)

Expand All @@ -26,15 +27,15 @@ func key(c *ishell.Context) {
}

func checkKey(key string) (err error) {
client := kms.New(saws.NewSession(ps.Region, ps.Profile))
client := kms.NewFromConfig(saws.LoadConfig(ps.Region, ps.Profile))
input := kms.ListKeysInput{}
for {
resp, err := client.ListKeys(&input)
resp, err := client.ListKeys(context.TODO(), &input)
if err != nil {
return err
}
for _, keyEntry := range resp.Keys {
if aws.StringValue(keyEntry.KeyId) == key || aws.StringValue(keyEntry.KeyArn) == key {
if aws.ToString(keyEntry.KeyId) == key || aws.ToString(keyEntry.KeyArn) == key {
return nil
}
}
Expand Down
2 changes: 1 addition & 1 deletion commands/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func createPolicy(policyName string, policyArgs []string) (err error) {
}
policy.noChangeNotification = append(policy.noChangeNotification, *p)
default:
return fmt.Errorf("Unable to parse policy type %s with attributes %s", policyType, policyAttributes)
return fmt.Errorf("unable to parse policy type %s with attributes %s", policyType, policyAttributes)
}
}
policies[policyName] = policy
Expand Down
Loading