test about half of what matters
This commit is contained in:
parent
6f163b5e22
commit
632af1a2be
19
.milpa/commands/joao/test/unit.sh
Normal file
19
.milpa/commands/joao/test/unit.sh
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
# Copyright © 2021 Roberto Hidalgo <joao@un.rob.mx>
|
||||||
|
|
||||||
|
cd "$MILPA_REPO_ROOT" || @milpa.fail "could not cd into $MILPA_REPO_ROOT"
|
||||||
|
@milpa.log info "Running unit tests"
|
||||||
|
args=()
|
||||||
|
after_run=complete
|
||||||
|
if [[ "${MILPA_OPT_COVERAGE}" ]]; then
|
||||||
|
after_run=success
|
||||||
|
args=( -coverprofile=coverage.out --coverpkg=./...)
|
||||||
|
fi
|
||||||
|
gotestsum --format testname -- "$MILPA_ARG_SPEC" "${args[@]}" || exit 2
|
||||||
|
@milpa.log "$after_run" "Unit tests passed"
|
||||||
|
|
||||||
|
[[ ! "${MILPA_OPT_COVERAGE}" ]] && exit
|
||||||
|
@milpa.log info "Building coverage report"
|
||||||
|
go tool cover -html=coverage.out -o coverage.html || @milpa.fail "could not build reports"
|
||||||
|
@milpa.log complete "Coverage report ready at coverage.html"
|
13
.milpa/commands/joao/test/unit.yaml
Normal file
13
.milpa/commands/joao/test/unit.yaml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
summary: Runs unit tests
|
||||||
|
description: |
|
||||||
|
Runs unit tests using gotestsum
|
||||||
|
arguments:
|
||||||
|
- name: spec
|
||||||
|
default: ./...
|
||||||
|
description: the package to test
|
||||||
|
values:
|
||||||
|
dirs: "*"
|
||||||
|
options:
|
||||||
|
coverage:
|
||||||
|
type: bool
|
||||||
|
description: if provided, will output coverage reports
|
5
bad-test.yaml
Normal file
5
bad-test.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
_config: !!joao
|
||||||
|
name: some:test
|
||||||
|
vault: bad-example
|
||||||
|
int: -:a\
|
||||||
|
|
105
cmd/fetch_test.go
Normal file
105
cmd/fetch_test.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// Copyright © 2022 Roberto Hidalgo <joao@un.rob.mx>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
package cmd_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "git.rob.mx/nidito/joao/cmd"
|
||||||
|
"git.rob.mx/nidito/joao/internal/op-client/mock"
|
||||||
|
"github.com/1Password/connect-sdk-go/onepassword"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFetch(t *testing.T) {
|
||||||
|
mockOPConnect(t)
|
||||||
|
f := testConfig.Fields
|
||||||
|
s := testConfig.Sections
|
||||||
|
defer func() { testConfig.Fields = f; testConfig.Sections = s }()
|
||||||
|
|
||||||
|
testConfig.Sections = append(testConfig.Sections,
|
||||||
|
&onepassword.ItemSection{ID: "o", Label: "o"},
|
||||||
|
&onepassword.ItemSection{ID: "e-fez-tambem", Label: "e-fez-tambem"},
|
||||||
|
)
|
||||||
|
testConfig.Fields = append(testConfig.Fields,
|
||||||
|
&onepassword.ItemField{
|
||||||
|
ID: "o.ganso.gosto",
|
||||||
|
Section: &onepassword.ItemSection{ID: "o", Label: "o"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "ganso.gosto",
|
||||||
|
Value: "da dupla",
|
||||||
|
},
|
||||||
|
&onepassword.ItemField{
|
||||||
|
ID: "e-fez-tambem.0",
|
||||||
|
Section: &onepassword.ItemSection{ID: "e-fez-tambem", Label: "e-fez-tambem"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "0",
|
||||||
|
Value: "quém!",
|
||||||
|
},
|
||||||
|
&onepassword.ItemField{
|
||||||
|
ID: "e-fez-tambem.1",
|
||||||
|
Section: &onepassword.ItemSection{ID: "e-fez-tambem", Label: "e-fez-tambem"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "1",
|
||||||
|
Value: "quém!",
|
||||||
|
},
|
||||||
|
&onepassword.ItemField{
|
||||||
|
ID: "e-fez-tambem.2",
|
||||||
|
Section: &onepassword.ItemSection{ID: "e-fez-tambem", Label: "e-fez-tambem"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "2",
|
||||||
|
Value: "quém!",
|
||||||
|
})
|
||||||
|
mock.Update(testConfig)
|
||||||
|
root := fromProjectRoot()
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
Fetch.SetBindings()
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.Flags().Bool("dry-run", true, "")
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
Fetch.Cobra = cmd
|
||||||
|
logrus.SetLevel(logrus.DebugLevel)
|
||||||
|
err := Fetch.Run(cmd, []string{root + "/test.yaml"})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not get: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := `_config: !!joao
|
||||||
|
name: some:test
|
||||||
|
vault: example
|
||||||
|
# not sorted on purpose
|
||||||
|
int: 1 # line
|
||||||
|
# foot
|
||||||
|
string: pato
|
||||||
|
bool: false
|
||||||
|
secret: !!secret very secret
|
||||||
|
nested:
|
||||||
|
string: quem
|
||||||
|
int: 1
|
||||||
|
secret: !!secret very secret
|
||||||
|
bool: true
|
||||||
|
list:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
list:
|
||||||
|
- one
|
||||||
|
- two
|
||||||
|
- three
|
||||||
|
o:
|
||||||
|
ganso:
|
||||||
|
gosto: da dupla
|
||||||
|
e-fez-tambem:
|
||||||
|
- quém!
|
||||||
|
- quém!
|
||||||
|
- quém!`
|
||||||
|
|
||||||
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
||||||
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
||||||
|
}
|
||||||
|
}
|
21
cmd/get.go
21
cmd/get.go
@ -77,6 +77,7 @@ looks at the filesystem or remotely, using 1password (over the CLI if available,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if query == "" || query == "." {
|
if query == "" || query == "." {
|
||||||
|
var bytes []byte
|
||||||
switch format {
|
switch format {
|
||||||
case "yaml", "raw", "diff-yaml":
|
case "yaml", "raw", "diff-yaml":
|
||||||
modes := []config.OutputMode{}
|
modes := []config.OutputMode{}
|
||||||
@ -86,21 +87,17 @@ looks at the filesystem or remotely, using 1password (over the CLI if available,
|
|||||||
if format == "diff-yaml" {
|
if format == "diff-yaml" {
|
||||||
modes = append(modes, config.OutputModeNoComments, config.OutputModeSorted)
|
modes = append(modes, config.OutputModeNoComments, config.OutputModeSorted)
|
||||||
}
|
}
|
||||||
bytes, err := cfg.AsYAML(modes...)
|
bytes, err = cfg.AsYAML(modes...)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = cmd.Cobra.OutOrStdout().Write(bytes)
|
|
||||||
return err
|
|
||||||
case "json", "op":
|
case "json", "op":
|
||||||
bytes, err := cfg.AsJSON(redacted, format == "op")
|
bytes, err = cfg.AsJSON(redacted, format == "op")
|
||||||
if err != nil {
|
default:
|
||||||
return err
|
return fmt.Errorf("unknown format %s", format)
|
||||||
}
|
}
|
||||||
_, err = cmd.Cobra.OutOrStdout().Write(bytes)
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return fmt.Errorf("unknown format %s", format)
|
_, err = cmd.Cobra.OutOrStdout().Write(bytes)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
parts := strings.Split(query, ".")
|
parts := strings.Split(query, ".")
|
||||||
|
331
cmd/get_test.go
331
cmd/get_test.go
@ -11,9 +11,166 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "git.rob.mx/nidito/joao/cmd"
|
. "git.rob.mx/nidito/joao/cmd"
|
||||||
|
opclient "git.rob.mx/nidito/joao/internal/op-client"
|
||||||
|
"git.rob.mx/nidito/joao/internal/op-client/mock"
|
||||||
|
"github.com/1Password/connect-sdk-go/connect"
|
||||||
|
"github.com/1Password/connect-sdk-go/onepassword"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var testConfig = &onepassword.Item{
|
||||||
|
Title: "some:test",
|
||||||
|
Vault: onepassword.ItemVault{ID: "example"},
|
||||||
|
Category: "PASSWORD",
|
||||||
|
Sections: []*onepassword.ItemSection{
|
||||||
|
{ID: "~annotations", Label: "~annotations"},
|
||||||
|
// {ID: "nested", Label: "nested"},
|
||||||
|
{ID: "list", Label: "list"},
|
||||||
|
},
|
||||||
|
Fields: []*onepassword.ItemField{
|
||||||
|
{
|
||||||
|
ID: "password",
|
||||||
|
Type: "CONCEALED",
|
||||||
|
Purpose: "PASSWORD",
|
||||||
|
Label: "password",
|
||||||
|
Value: "56615e9be5f0ce5f97d5b446faaa1d39f95a13a1ea8326ae933c3d29eb29735c",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "notesPlain",
|
||||||
|
Type: "STRING",
|
||||||
|
Purpose: "NOTES",
|
||||||
|
Label: "notesPlain",
|
||||||
|
Value: "flushed by joao",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "~annotations.int",
|
||||||
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "int",
|
||||||
|
Value: "int",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "int",
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "int",
|
||||||
|
Value: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "string",
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "string",
|
||||||
|
Value: "pato",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "~annotations.bool",
|
||||||
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "bool",
|
||||||
|
Value: "bool",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "bool",
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "bool",
|
||||||
|
Value: "false",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "~annotations.secret",
|
||||||
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "secret",
|
||||||
|
Value: "secret",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "secret",
|
||||||
|
Type: "CONCEALED",
|
||||||
|
Label: "secret",
|
||||||
|
Value: "very secret",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "nested.string",
|
||||||
|
Section: &onepassword.ItemSection{ID: "nested", Label: "nested"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "string",
|
||||||
|
Value: "quem",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "~annotations.nested.int",
|
||||||
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "nested.int",
|
||||||
|
Value: "int",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "nested.int",
|
||||||
|
Section: &onepassword.ItemSection{ID: "nested", Label: "nested"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "int",
|
||||||
|
Value: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "~annotations.nested.secret",
|
||||||
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "nested.secret",
|
||||||
|
Value: "secret",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "nested.secret",
|
||||||
|
Section: &onepassword.ItemSection{ID: "nested", Label: "nested"},
|
||||||
|
Type: "CONCEALED",
|
||||||
|
Label: "secret",
|
||||||
|
Value: "very secret",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "~annotations.nested.bool",
|
||||||
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "nested.bool",
|
||||||
|
Value: "bool",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "nested.bool",
|
||||||
|
Section: &onepassword.ItemSection{ID: "nested", Label: "nested"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "bool",
|
||||||
|
Value: "true",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "list.0",
|
||||||
|
Section: &onepassword.ItemSection{ID: "list", Label: "list"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "0",
|
||||||
|
Value: "one",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "list.1",
|
||||||
|
Section: &onepassword.ItemSection{ID: "list", Label: "list"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "1",
|
||||||
|
Value: "two",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "list.2",
|
||||||
|
Section: &onepassword.ItemSection{ID: "list", Label: "list"},
|
||||||
|
Type: "STRING",
|
||||||
|
Label: "2",
|
||||||
|
Value: "three",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockOPConnect(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
opclient.ConnectClientFactory = func(host, token, userAgent string) connect.Client {
|
||||||
|
return &mock.Client{}
|
||||||
|
}
|
||||||
|
client := opclient.NewConnect("", "")
|
||||||
|
opclient.Use(client)
|
||||||
|
mock.Add(testConfig)
|
||||||
|
}
|
||||||
|
|
||||||
func fromProjectRoot() string {
|
func fromProjectRoot() string {
|
||||||
_, filename, _, _ := runtime.Caller(0)
|
_, filename, _, _ := runtime.Caller(0)
|
||||||
dir := path.Join(path.Dir(filename), "../")
|
dir := path.Join(path.Dir(filename), "../")
|
||||||
@ -24,29 +181,42 @@ func fromProjectRoot() string {
|
|||||||
return wd
|
return wd
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetRedacted(t *testing.T) {
|
func TestGetBadYAML(t *testing.T) {
|
||||||
root := fromProjectRoot()
|
root := fromProjectRoot()
|
||||||
out := bytes.Buffer{}
|
|
||||||
Get.SetBindings()
|
Get.SetBindings()
|
||||||
|
out := bytes.Buffer{}
|
||||||
cmd := &cobra.Command{}
|
cmd := &cobra.Command{}
|
||||||
cmd.Flags().Bool("redacted", true, "")
|
|
||||||
cmd.SetOut(&out)
|
cmd.SetOut(&out)
|
||||||
cmd.SetErr(&out)
|
cmd.SetErr(&out)
|
||||||
Get.Cobra = cmd
|
Get.Cobra = cmd
|
||||||
err := Get.Run(cmd, []string{root + "/test.yaml", ".", "--redacted"})
|
err := Get.Run(cmd, []string{root + "/bad-test.yaml", "."})
|
||||||
|
if err == nil {
|
||||||
if err != nil {
|
t.Fatalf("Did not throw on bad path: %s", out.String())
|
||||||
t.Fatalf("could not get: %s", err)
|
|
||||||
}
|
}
|
||||||
|
wantedPrefix := "could not parse file"
|
||||||
expected, err := os.ReadFile(root + "/test.yaml")
|
wantedSuffix := "/bad-test.yaml as yaml: line 4: mapping values are not allowed in this context"
|
||||||
if err != nil {
|
if got := err.Error(); !(strings.HasPrefix(got, wantedPrefix) && strings.HasSuffix(got, wantedSuffix)) {
|
||||||
t.Fatalf("could not read file: %s", err)
|
t.Fatalf("Failed with bad error, wanted %s /some-path%s, got %s", wantedPrefix, wantedSuffix, got)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
got := out.String()
|
func TestGetBadPath(t *testing.T) {
|
||||||
if strings.TrimSpace(got) != strings.ReplaceAll(strings.TrimSpace(string(expected)), " very secret", "") {
|
root := fromProjectRoot()
|
||||||
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
Get.SetBindings()
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
Get.Cobra = cmd
|
||||||
|
err := Get.Run(cmd, []string{root + "/does-not-exist.yaml", "."})
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Did not throw on bad path: %s", out.String())
|
||||||
|
}
|
||||||
|
wantedPrefix := "could not read file"
|
||||||
|
wantedSuffix := "/does-not-exist.yaml"
|
||||||
|
|
||||||
|
if got := err.Error(); !(strings.HasPrefix(got, wantedPrefix) && strings.HasSuffix(got, wantedSuffix)) {
|
||||||
|
t.Fatalf("Failed with bad error, wanted %s /some-path%s, got %s", wantedPrefix, wantedSuffix, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,8 +240,32 @@ func TestGetNormal(t *testing.T) {
|
|||||||
t.Fatalf("could not read file: %s", err)
|
t.Fatalf("could not read file: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
got := out.String()
|
if got := out.String(); strings.TrimSpace(got) != strings.TrimSpace(string(expected)) {
|
||||||
if strings.TrimSpace(got) != strings.TrimSpace(string(expected)) {
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRedacted(t *testing.T) {
|
||||||
|
root := fromProjectRoot()
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
Get.SetBindings()
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.Flags().Bool("redacted", true, "")
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
Get.Cobra = cmd
|
||||||
|
err := Get.Run(cmd, []string{root + "/test.yaml", ".", "--redacted"})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not get: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected, err := os.ReadFile(root + "/test.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := out.String(); strings.TrimSpace(got) != strings.ReplaceAll(strings.TrimSpace(string(expected)), " very secret", "") {
|
||||||
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,6 +276,7 @@ func TestGetPath(t *testing.T) {
|
|||||||
Get.SetBindings()
|
Get.SetBindings()
|
||||||
cmd := &cobra.Command{}
|
cmd := &cobra.Command{}
|
||||||
cmd.Flags().Bool("redacted", false, "")
|
cmd.Flags().Bool("redacted", false, "")
|
||||||
|
cmd.Flags().StringP("output", "o", "yaml", "")
|
||||||
cmd.SetOut(&out)
|
cmd.SetOut(&out)
|
||||||
cmd.SetErr(&out)
|
cmd.SetErr(&out)
|
||||||
Get.Cobra = cmd
|
Get.Cobra = cmd
|
||||||
@ -92,8 +287,29 @@ func TestGetPath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expected := "very secret"
|
expected := "very secret"
|
||||||
got := out.String()
|
if got := out.String(); strings.TrimSpace(got) != strings.TrimSpace(expected) {
|
||||||
if strings.TrimSpace(got) != strings.TrimSpace(expected) {
|
t.Fatalf("did not get expected scalar output:\nwanted: %s\ngot: %s", expected, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
out = bytes.Buffer{}
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
err = Get.Run(cmd, []string{root + "/test.yaml", "nested", "--output", "diff-yaml"})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not get: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = `bool: true
|
||||||
|
int: 1
|
||||||
|
list:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
secret: very secret
|
||||||
|
string: quem`
|
||||||
|
|
||||||
|
if got := out.String(); strings.TrimSpace(got) != strings.TrimSpace(expected) {
|
||||||
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,11 +332,14 @@ func TestGetPathCollection(t *testing.T) {
|
|||||||
|
|
||||||
expected := `bool: true
|
expected := `bool: true
|
||||||
int: 1
|
int: 1
|
||||||
|
list:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
secret: very secret
|
secret: very secret
|
||||||
string: quem`
|
string: quem`
|
||||||
|
|
||||||
got := out.String()
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
||||||
if strings.TrimSpace(got) != expected {
|
|
||||||
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,13 +372,16 @@ list:
|
|||||||
nested:
|
nested:
|
||||||
bool: true
|
bool: true
|
||||||
int: 1
|
int: 1
|
||||||
|
list:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
secret: !!secret very secret
|
secret: !!secret very secret
|
||||||
string: quem
|
string: quem
|
||||||
secret: !!secret very secret
|
secret: !!secret very secret
|
||||||
string: "pato"`
|
string: pato`
|
||||||
|
|
||||||
got := out.String()
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
||||||
if strings.TrimSpace(got) != expected {
|
|
||||||
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,10 +402,9 @@ func TestGetJSON(t *testing.T) {
|
|||||||
t.Fatalf("could not get: %s", err)
|
t.Fatalf("could not get: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := `{"bool":false,"int":1,"list":["one","two","three"],"nested":{"bool":true,"int":1,"secret":"very secret","string":"quem"},"secret":"very secret","string":"pato"}`
|
expected := `{"bool":false,"int":1,"list":["one","two","three"],"nested":{"bool":true,"int":1,"list":[1,2,3],"secret":"very secret","string":"quem"},"secret":"very secret","string":"pato"}`
|
||||||
|
|
||||||
got := out.String()
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
||||||
if strings.TrimSpace(got) != expected {
|
|
||||||
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,10 +425,9 @@ func TestGetJSONPathScalar(t *testing.T) {
|
|||||||
t.Fatalf("could not get: %s", err)
|
t.Fatalf("could not get: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := `very secret`
|
expected := `very secret` // nolint: ifshort
|
||||||
|
|
||||||
got := out.String()
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
||||||
if strings.TrimSpace(got) != expected {
|
|
||||||
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,10 +448,9 @@ func TestGetJSONPathCollection(t *testing.T) {
|
|||||||
t.Fatalf("could not get: %s", err)
|
t.Fatalf("could not get: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := `{"bool":true,"int":1,"secret":"very secret","string":"quem"}`
|
expected := `{"bool":true,"int":1,"list":[1,2,3],"secret":"very secret","string":"quem"}`
|
||||||
|
|
||||||
got := out.String()
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
||||||
if strings.TrimSpace(got) != expected {
|
|
||||||
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,10 +471,9 @@ func TestGetJSONRedacted(t *testing.T) {
|
|||||||
t.Fatalf("could not get: %s", err)
|
t.Fatalf("could not get: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := `{"bool":false,"int":1,"list":["one","two","three"],"nested":{"bool":true,"int":1,"secret":"","string":"quem"},"secret":"","string":"pato"}`
|
expected := `{"bool":false,"int":1,"list":["one","two","three"],"nested":{"bool":true,"int":1,"list":[1,2,3],"secret":"","string":"quem"},"secret":"","string":"pato"}`
|
||||||
|
|
||||||
got := out.String()
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
||||||
if strings.TrimSpace(got) != expected {
|
|
||||||
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,10 +493,47 @@ func TestGetJSONOP(t *testing.T) {
|
|||||||
t.Fatalf("could not get: %s", err)
|
t.Fatalf("could not get: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := `{"id":"","title":"some:test","vault":{"id":"example"},"category":"PASSWORD","sections":[{"id":"~annotations","label":"~annotations"},{"id":"nested","label":"nested"}],"fields":[{"id":"password","type":"CONCEALED","purpose":"PASSWORD","label":"password","value":"56615e9be5f0ce5f97d5b446faaa1d39f95a13a1ea8326ae933c3d29eb29735c"},{"id":"notesPlain","type":"STRING","purpose":"NOTES","label":"notesPlain","value":"flushed by joao"},{"id":"~annotations.int","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"int","value":"int"},{"id":"int","type":"STRING","label":"int","value":"1"},{"id":"string","type":"STRING","label":"string","value":"pato"},{"id":"~annotations.bool","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"bool","value":"bool"},{"id":"bool","type":"STRING","label":"bool","value":"false"},{"id":"~annotations.secret","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"secret","value":"secret"},{"id":"secret","type":"CONCEALED","label":"secret","value":"very secret"},{"id":"nested.string","section":{"id":"nested"},"type":"STRING","label":"string","value":"quem"},{"id":"~annotations.nested.int","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"nested.int","value":"int"},{"id":"nested.int","section":{"id":"nested"},"type":"STRING","label":"int","value":"1"},{"id":"~annotations.nested.secret","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"nested.secret","value":"secret"},{"id":"nested.secret","section":{"id":"nested"},"type":"CONCEALED","label":"secret","value":"very secret"},{"id":"~annotations.nested.bool","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"nested.bool","value":"bool"},{"id":"nested.bool","section":{"id":"nested"},"type":"STRING","label":"bool","value":"true"},{"id":"list.0","section":{"id":"list"},"type":"STRING","label":"0","value":"one"},{"id":"list.1","section":{"id":"list"},"type":"STRING","label":"1","value":"two"},{"id":"list.2","section":{"id":"list"},"type":"STRING","label":"2","value":"three"}],"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"}`
|
expected := `{"id":"","title":"some:test","vault":{"id":"example"},"category":"PASSWORD","sections":[{"id":"~annotations","label":"~annotations"},{"id":"nested","label":"nested"},{"id":"list","label":"list"}],"fields":[{"id":"password","type":"CONCEALED","purpose":"PASSWORD","label":"password","value":"cedbdf86fb15cf1237569e9b3188372d623aea9d6a707401aca656645590227c"},{"id":"notesPlain","type":"STRING","purpose":"NOTES","label":"notesPlain","value":"flushed by joao"},{"id":"~annotations.int","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"int","value":"int"},{"id":"int","type":"STRING","label":"int","value":"1"},{"id":"string","type":"STRING","label":"string","value":"pato"},{"id":"~annotations.bool","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"bool","value":"bool"},{"id":"bool","type":"STRING","label":"bool","value":"false"},{"id":"~annotations.secret","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"secret","value":"secret"},{"id":"secret","type":"CONCEALED","label":"secret","value":"very secret"},{"id":"nested.string","section":{"id":"nested"},"type":"STRING","label":"string","value":"quem"},{"id":"~annotations.nested.int","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"nested.int","value":"int"},{"id":"nested.int","section":{"id":"nested"},"type":"STRING","label":"int","value":"1"},{"id":"~annotations.nested.secret","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"nested.secret","value":"secret"},{"id":"nested.secret","section":{"id":"nested"},"type":"CONCEALED","label":"secret","value":"very secret"},{"id":"~annotations.nested.bool","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"nested.bool","value":"bool"},{"id":"nested.bool","section":{"id":"nested"},"type":"STRING","label":"bool","value":"true"},{"id":"~annotations.nested.list.0","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"nested.list.0","value":"int"},{"id":"nested.list.0","section":{"id":"nested"},"type":"STRING","label":"list.0","value":"1"},{"id":"~annotations.nested.list.1","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"nested.list.1","value":"int"},{"id":"nested.list.1","section":{"id":"nested"},"type":"STRING","label":"list.1","value":"2"},{"id":"~annotations.nested.list.2","section":{"id":"~annotations","label":"~annotations"},"type":"STRING","label":"nested.list.2","value":"int"},{"id":"nested.list.2","section":{"id":"nested"},"type":"STRING","label":"list.2","value":"3"},{"id":"list.0","section":{"id":"list"},"type":"STRING","label":"0","value":"one"},{"id":"list.1","section":{"id":"list"},"type":"STRING","label":"1","value":"two"},{"id":"list.2","section":{"id":"list"},"type":"STRING","label":"2","value":"three"}],"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"}`
|
||||||
|
|
||||||
got := out.String()
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
||||||
if strings.TrimSpace(got) != expected {
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRemote(t *testing.T) {
|
||||||
|
mockOPConnect(t)
|
||||||
|
root := fromProjectRoot()
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
Get.SetBindings()
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.Flags().Bool("redacted", false, "")
|
||||||
|
cmd.Flags().Bool("remote", true, "")
|
||||||
|
cmd.Flags().StringP("output", "o", "diff-yaml", "")
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
Get.Cobra = cmd
|
||||||
|
logrus.SetLevel(logrus.DebugLevel)
|
||||||
|
err := Get.Run(cmd, []string{root + "/test.yaml", ".", "--output", "diff-yaml", "--remote"})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not get: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := `bool: false
|
||||||
|
int: 1
|
||||||
|
list:
|
||||||
|
- one
|
||||||
|
- two
|
||||||
|
- three
|
||||||
|
nested:
|
||||||
|
bool: true
|
||||||
|
int: 1
|
||||||
|
secret: !!secret very secret
|
||||||
|
string: quem
|
||||||
|
secret: !!secret very secret
|
||||||
|
string: pato`
|
||||||
|
|
||||||
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
||||||
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
cmd/set.go
10
cmd/set.go
@ -5,6 +5,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -89,7 +90,7 @@ Will read values from stdin (or ﹅--from﹅ a file) and store it at the ﹅PATH
|
|||||||
}
|
}
|
||||||
|
|
||||||
if delete && input != "/dev/stdin" {
|
if delete && input != "/dev/stdin" {
|
||||||
logrus.Warn("Ignoring --file while deleting")
|
logrus.Warn("Ignoring --input while deleting")
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err = config.Load(path, false)
|
cfg, err = config.Load(path, false)
|
||||||
@ -104,7 +105,12 @@ Will read values from stdin (or ﹅--from﹅ a file) and store it at the ﹅PATH
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
valueBytes, err := os.ReadFile(input)
|
var valueBytes []byte
|
||||||
|
if input == "/dev/stdin" {
|
||||||
|
valueBytes, err = ioutil.ReadAll(cmd.Cobra.InOrStdin())
|
||||||
|
} else {
|
||||||
|
valueBytes, err = os.ReadFile(input)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
457
cmd/set_test.go
Normal file
457
cmd/set_test.go
Normal file
@ -0,0 +1,457 @@
|
|||||||
|
// Copyright © 2022 Roberto Hidalgo <joao@un.rob.mx>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
package cmd_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "git.rob.mx/nidito/joao/cmd"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func tempTestYaml(root, name string, data []byte) (string, func(), error) {
|
||||||
|
path := fmt.Sprintf("%s/test-%s.yaml", root, name)
|
||||||
|
if err := ioutil.WriteFile(path, data, fs.FileMode(0644)); err != nil {
|
||||||
|
return path, nil, fmt.Errorf("could not create test file")
|
||||||
|
}
|
||||||
|
return path, func() { os.Remove(path) }, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSet(t *testing.T) {
|
||||||
|
root := fromProjectRoot()
|
||||||
|
Set.SetBindings()
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
stdin := bytes.Buffer{}
|
||||||
|
stdin.Write([]byte("pato\nganso\nmarreco\n"))
|
||||||
|
cmd.SetIn(&stdin)
|
||||||
|
Set.Cobra = cmd
|
||||||
|
cmd.Flags().Bool("secret", false, "")
|
||||||
|
cmd.Flags().Bool("delete", false, "")
|
||||||
|
cmd.Flags().Bool("json", false, "")
|
||||||
|
cmd.Flags().Bool("flush", false, "")
|
||||||
|
original, err := ioutil.ReadFile(root + "/test.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
path, cleanup, err := tempTestYaml(root, "set-plain", original)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
err = Set.Run(cmd, []string{path, "string"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Threw on good set: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
changed, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(changed) == string(original) {
|
||||||
|
t.Fatal("Did not change file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(changed), `
|
||||||
|
string: |-
|
||||||
|
pato
|
||||||
|
ganso
|
||||||
|
marreco`) {
|
||||||
|
t.Fatalf("Did not contain expected new string, got:\n%s", changed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetSecret(t *testing.T) {
|
||||||
|
root := fromProjectRoot()
|
||||||
|
Set.SetBindings()
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
stdin := bytes.Buffer{}
|
||||||
|
stdin.Write([]byte("new secret\n"))
|
||||||
|
cmd.SetIn(&stdin)
|
||||||
|
Set.Cobra = cmd
|
||||||
|
cmd.Flags().Bool("secret", true, "")
|
||||||
|
cmd.Flags().Bool("delete", false, "")
|
||||||
|
cmd.Flags().Bool("json", false, "")
|
||||||
|
cmd.Flags().Bool("flush", false, "")
|
||||||
|
original, err := ioutil.ReadFile(root + "/test.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
path, cleanup, err := tempTestYaml(root, "set-plain", original)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
err = Set.Run(cmd, []string{path, "secret", "--secret"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Threw on good set: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
changed, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(changed) == string(original) {
|
||||||
|
t.Fatal("Did not change file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(changed), "\nsecret: !!secret new secret\n") {
|
||||||
|
t.Fatalf("Did not contain expected new string, got:\n%s", changed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetFromFile(t *testing.T) {
|
||||||
|
root := fromProjectRoot()
|
||||||
|
Set.SetBindings()
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
Set.Cobra = cmd
|
||||||
|
cmd.Flags().Bool("secret", false, "")
|
||||||
|
cmd.Flags().Bool("delete", false, "")
|
||||||
|
cmd.Flags().Bool("json", false, "")
|
||||||
|
cmd.Flags().Bool("flush", false, "")
|
||||||
|
original, err := ioutil.ReadFile(root + "/test.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
dataPath, dataCleanup, err := tempTestYaml(root, "set-from-file-data", []byte("ganso"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer dataCleanup()
|
||||||
|
cmd.Flags().StringP("input", "i", dataPath, "")
|
||||||
|
|
||||||
|
path, cleanup, err := tempTestYaml(root, "set-from-file", original)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
err = Set.Run(cmd, []string{path, "string", "--input", dataPath})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Threw on good set: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
changed, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(changed) == string(original) {
|
||||||
|
t.Fatal("Did not change file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(changed), "\nstring: ganso\n") {
|
||||||
|
t.Fatalf("Did not contain expected new string, got:\n%s", changed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetNew(t *testing.T) {
|
||||||
|
root := fromProjectRoot()
|
||||||
|
Set.SetBindings()
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
stdin := bytes.Buffer{}
|
||||||
|
stdin.Write([]byte("pato\nganso\nmarreco\ncisne\n"))
|
||||||
|
cmd.SetIn(&stdin)
|
||||||
|
Set.Cobra = cmd
|
||||||
|
cmd.Flags().Bool("secret", false, "")
|
||||||
|
cmd.Flags().Bool("delete", false, "")
|
||||||
|
cmd.Flags().Bool("json", false, "")
|
||||||
|
cmd.Flags().Bool("flush", false, "")
|
||||||
|
cmd.Flags().StringP("input", "i", "/dev/stdin", "")
|
||||||
|
original, err := ioutil.ReadFile(root + "/test.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
path, cleanup, err := tempTestYaml(root, "set-new-key", original)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
err = Set.Run(cmd, []string{path, "quarteto"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Threw on good new set: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
changed, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(changed) == string(original) {
|
||||||
|
t.Fatal("Did not change file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(changed), `
|
||||||
|
quarteto: |-
|
||||||
|
pato
|
||||||
|
ganso
|
||||||
|
marreco
|
||||||
|
cisne`) {
|
||||||
|
t.Fatalf("Did not contain expected new string, got:\n%s", changed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetNested(t *testing.T) {
|
||||||
|
root := fromProjectRoot()
|
||||||
|
Set.SetBindings()
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
stdin := bytes.Buffer{}
|
||||||
|
stdin.Write([]byte("tico"))
|
||||||
|
cmd.SetIn(&stdin)
|
||||||
|
Set.Cobra = cmd
|
||||||
|
cmd.Flags().Bool("secret", false, "")
|
||||||
|
cmd.Flags().Bool("delete", false, "")
|
||||||
|
cmd.Flags().Bool("json", false, "")
|
||||||
|
cmd.Flags().Bool("flush", false, "")
|
||||||
|
cmd.Flags().StringP("input", "i", "/dev/stdin", "")
|
||||||
|
original, err := ioutil.ReadFile(root + "/test.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
path, cleanup, err := tempTestYaml(root, "set-nested-key", original)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
err = Set.Run(cmd, []string{path, "nested.tico"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Threw on good nested set: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
changed, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(changed) == string(original) {
|
||||||
|
t.Fatal("Did not change file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(changed), `
|
||||||
|
tico: tico
|
||||||
|
`) {
|
||||||
|
t.Fatalf("Did not contain expected new string, got:\n%s", changed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetJSON(t *testing.T) {
|
||||||
|
root := fromProjectRoot()
|
||||||
|
Set.SetBindings()
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
stdin := bytes.Buffer{}
|
||||||
|
stdin.Write([]byte(`{"foram": "ensaiar", "para": "começar"}`))
|
||||||
|
cmd.SetIn(&stdin)
|
||||||
|
Set.Cobra = cmd
|
||||||
|
cmd.Flags().Bool("secret", false, "")
|
||||||
|
cmd.Flags().Bool("delete", false, "")
|
||||||
|
cmd.Flags().Bool("json", true, "")
|
||||||
|
cmd.Flags().Bool("flush", false, "")
|
||||||
|
cmd.Flags().StringP("input", "i", "/dev/stdin", "")
|
||||||
|
original, err := ioutil.ReadFile(root + "/test.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
path, cleanup, err := tempTestYaml(root, "set-json", original)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
err = Set.Run(cmd, []string{path, "na-beira-da-lagoa"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Threw on good nested set: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
changed, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(changed) == string(original) {
|
||||||
|
t.Fatal("Did not change file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(changed), `
|
||||||
|
na-beira-da-lagoa:
|
||||||
|
foram: ensaiar
|
||||||
|
para: começar
|
||||||
|
`) {
|
||||||
|
t.Fatalf("Did not contain expected new entry tree, got:\n%s", changed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetList(t *testing.T) {
|
||||||
|
logrus.SetLevel(logrus.DebugLevel)
|
||||||
|
|
||||||
|
root := fromProjectRoot()
|
||||||
|
Set.SetBindings()
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
stdin := bytes.Buffer{}
|
||||||
|
stdin.Write([]byte("um"))
|
||||||
|
cmd.SetIn(&stdin)
|
||||||
|
Set.Cobra = cmd
|
||||||
|
cmd.Flags().Bool("secret", false, "")
|
||||||
|
cmd.Flags().Bool("delete", false, "")
|
||||||
|
cmd.Flags().Bool("json", false, "")
|
||||||
|
cmd.Flags().Bool("flush", false, "")
|
||||||
|
cmd.Flags().StringP("input", "i", "/dev/stdin", "")
|
||||||
|
original, err := ioutil.ReadFile(root + "/test.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
path, cleanup, err := tempTestYaml(root, "set-list-key", original)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
err = Set.Run(cmd, []string{path, "asdf.0"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Threw on good nested set: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
changed, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(changed) == string(original) {
|
||||||
|
t.Fatal("Did not change file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(changed), `
|
||||||
|
asdf:
|
||||||
|
- um
|
||||||
|
`) {
|
||||||
|
t.Fatalf("Did not contain expected new string, got:\n%s", changed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
root := fromProjectRoot()
|
||||||
|
Set.SetBindings()
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
Set.Cobra = cmd
|
||||||
|
cmd.Flags().Bool("secret", false, "")
|
||||||
|
cmd.Flags().Bool("delete", true, "")
|
||||||
|
cmd.Flags().Bool("json", false, "")
|
||||||
|
cmd.Flags().Bool("flush", false, "")
|
||||||
|
cmd.Flags().StringP("input", "i", "/dev/stdin", "")
|
||||||
|
original, err := ioutil.ReadFile(root + "/test.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
path, cleanup, err := tempTestYaml(root, "set-delete-key", original)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
err = Set.Run(cmd, []string{path, "string", "--delete"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Threw on good set delete: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
changed, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(changed) == string(original) {
|
||||||
|
t.Fatal("Did not change file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(string(changed), `
|
||||||
|
string: pato
|
||||||
|
`) {
|
||||||
|
t.Fatalf("Still contains deleted key, got:\n%s", changed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteNested(t *testing.T) {
|
||||||
|
root := fromProjectRoot()
|
||||||
|
Set.SetBindings()
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
cmd.SetOut(&out)
|
||||||
|
cmd.SetErr(&out)
|
||||||
|
Set.Cobra = cmd
|
||||||
|
cmd.Flags().Bool("secret", false, "")
|
||||||
|
cmd.Flags().Bool("delete", true, "")
|
||||||
|
cmd.Flags().Bool("json", false, "")
|
||||||
|
cmd.Flags().Bool("flush", false, "")
|
||||||
|
cmd.Flags().StringP("input", "i", "/dev/stdin", "")
|
||||||
|
original, err := ioutil.ReadFile(root + "/test.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
path, cleanup, err := tempTestYaml(root, "set-delete-nested-key", original)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
err = Set.Run(cmd, []string{path, "nested.string", "--delete"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Threw on good set delete nested: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
changed, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(changed) == string(original) {
|
||||||
|
t.Fatal("Did not change file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(string(changed), `
|
||||||
|
string: quem
|
||||||
|
`) {
|
||||||
|
t.Fatalf("Still contains deleted nested key, got:\n%s", changed)
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@ import (
|
|||||||
var Plugin = &command.Command{
|
var Plugin = &command.Command{
|
||||||
Path: []string{"vault", "server"},
|
Path: []string{"vault", "server"},
|
||||||
Summary: "Starts a vault-joao-plugin server",
|
Summary: "Starts a vault-joao-plugin server",
|
||||||
Description: `Runs ﹅joao﹅ as a vault plugin.
|
Description: `Runs ﹅joao﹅ as a vault plugin. See https://developer.hashicorp.com/vault/docs/plugins
|
||||||
|
|
||||||
You'll need to install ﹅joao﹅ in the machine running ﹅vault﹅ to ﹅plugin_directory﹅ as specified by vault's config. The installed ﹅joao﹅ executable needs to be executable for the user running vault only.
|
You'll need to install ﹅joao﹅ in the machine running ﹅vault﹅ to ﹅plugin_directory﹅ as specified by vault's config. The installed ﹅joao﹅ executable needs to be executable for the user running vault only.
|
||||||
|
|
||||||
|
@ -3,10 +3,14 @@
|
|||||||
package opclient
|
package opclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/1Password/connect-sdk-go/connect"
|
"github.com/1Password/connect-sdk-go/connect"
|
||||||
op "github.com/1Password/connect-sdk-go/onepassword"
|
op "github.com/1Password/connect-sdk-go/onepassword"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ConnectClientFactory func(host, token, userAgent string) connect.Client = connect.NewClientWithUserAgent
|
||||||
|
|
||||||
// UUIDLength defines the required length of UUIDs.
|
// UUIDLength defines the required length of UUIDs.
|
||||||
const UUIDLength = 26
|
const UUIDLength = 26
|
||||||
|
|
||||||
@ -33,7 +37,7 @@ type Connect struct {
|
|||||||
const userAgent = "nidito-joao"
|
const userAgent = "nidito-joao"
|
||||||
|
|
||||||
func NewConnect(host, token string) *Connect {
|
func NewConnect(host, token string) *Connect {
|
||||||
client := connect.NewClientWithUserAgent(host, token, userAgent)
|
client := ConnectClientFactory(host, token, userAgent)
|
||||||
return &Connect{client: client}
|
return &Connect{client: client}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,12 +45,27 @@ func (b *Connect) Get(vault, name string) (*op.Item, error) {
|
|||||||
return b.client.GetItem(name, vault)
|
return b.client.GetItem(name, vault)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Connect) Update(item *op.Item) error {
|
func (b *Connect) Update(item *op.Item, remote *op.Item) error {
|
||||||
_, err := b.client.UpdateItem(item, item.Vault.ID)
|
_, err := b.client.UpdateItem(item, item.Vault.ID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Connect) List(vault, prefix string) ([]string, error) {
|
func (b *Connect) List(vault, prefix string) ([]string, error) {
|
||||||
// TODO: get this done
|
items, err := b.client.GetItems(vault)
|
||||||
return nil, nil
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res := []string{}
|
||||||
|
for _, item := range items {
|
||||||
|
if prefix != "" && !strings.HasPrefix(item.Title, prefix) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
res = append(res, item.Title)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Connect) Create(item *op.Item) error {
|
||||||
|
_, err := b.client.CreateItem(item, item.Vault.ID)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,12 @@ func (cfg *Config) Set(path []string, data []byte, isSecret, parseEntry bool) er
|
|||||||
if err := yaml.Unmarshal(data, newEntry); err != nil {
|
if err := yaml.Unmarshal(data, newEntry); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if newEntry.Kind == yaml.MappingNode || newEntry.Kind == yaml.SequenceNode {
|
||||||
|
newEntry.Style = yaml.FoldedStyle | yaml.LiteralStyle
|
||||||
|
for _, v := range newEntry.Content {
|
||||||
|
v.Style = yaml.FlowStyle
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
valueStr = strings.Trim(valueStr, "\n")
|
valueStr = strings.Trim(valueStr, "\n")
|
||||||
if isSecret {
|
if isSecret {
|
||||||
@ -108,12 +114,14 @@ func (cfg *Config) Set(path []string, data []byte, isSecret, parseEntry bool) er
|
|||||||
entry := cfg.Tree
|
entry := cfg.Tree
|
||||||
for idx, key := range path {
|
for idx, key := range path {
|
||||||
if len(path)-1 == idx {
|
if len(path)-1 == idx {
|
||||||
dst := entry.ChildNamed(key)
|
if dst := entry.ChildNamed(key); dst == nil {
|
||||||
if dst == nil {
|
key := NewEntry(key, yaml.ScalarNode)
|
||||||
if entry.Kind == yaml.MappingNode {
|
if entry.Kind == yaml.MappingNode {
|
||||||
key := NewEntry(key, yaml.ScalarNode)
|
logrus.Infof("setting new map key %v", newEntry.Path)
|
||||||
entry.Content = append(entry.Content, key, newEntry)
|
entry.Content = append(entry.Content, key, newEntry)
|
||||||
} else {
|
} else {
|
||||||
|
logrus.Infof("setting new list key %v", newEntry.Path)
|
||||||
|
entry.Kind = yaml.SequenceNode
|
||||||
entry.Content = append(entry.Content, newEntry)
|
entry.Content = append(entry.Content, newEntry)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -131,12 +139,15 @@ func (cfg *Config) Set(path []string, data []byte, isSecret, parseEntry bool) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
kind := yaml.MappingNode
|
kind := yaml.MappingNode
|
||||||
if isNumeric(key) {
|
if idx+1 == len(path)-1 && isNumeric(path[idx+1]) {
|
||||||
kind = yaml.SequenceNode
|
kind = yaml.SequenceNode
|
||||||
}
|
}
|
||||||
sub := NewEntry(key, kind)
|
sub := NewEntry(key, kind)
|
||||||
sub.Path = append(entry.Path, key) // nolint: gocritic
|
sub.Path = append(entry.Path, key) // nolint: gocritic
|
||||||
entry.Content = append(entry.Content, sub)
|
|
||||||
|
keyEntry := NewEntry(sub.Name(), yaml.ScalarNode)
|
||||||
|
keyEntry.Value = key
|
||||||
|
entry.Content = append(entry.Content, keyEntry, sub)
|
||||||
entry = sub
|
entry = sub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,6 +206,10 @@ func (e *Entry) MarshalYAML() (*yaml.Node, error) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
entries := e.Contents()
|
entries := e.Contents()
|
||||||
|
if len(entries)%2 != 0 {
|
||||||
|
return nil, fmt.Errorf("cannot decode odd numbered contents list: %s", e.Path)
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < len(entries); i += 2 {
|
for i := 0; i < len(entries); i += 2 {
|
||||||
key := entries[i]
|
key := entries[i]
|
||||||
value := entries[i+1]
|
value := entries[i+1]
|
||||||
@ -213,6 +217,11 @@ func (e *Entry) MarshalYAML() (*yaml.Node, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if key.Type == "" {
|
||||||
|
key.Kind = yaml.ScalarNode
|
||||||
|
key.Type = "!!map"
|
||||||
|
}
|
||||||
|
|
||||||
keyNode, err := key.MarshalYAML()
|
keyNode, err := key.MarshalYAML()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -288,11 +297,11 @@ func (e *Entry) FromOP(fields []*op.ItemField) error {
|
|||||||
Type: kind,
|
Type: kind,
|
||||||
}
|
}
|
||||||
if isNumeric(key) {
|
if isNumeric(key) {
|
||||||
// logrus.Debugf("hydrating sequence value at %s", path)
|
logrus.Debugf("hydrating sequence value at %s", path)
|
||||||
container.Kind = yaml.SequenceNode
|
container.Kind = yaml.SequenceNode
|
||||||
container.Content = append(container.Content, newEntry)
|
container.Content = append(container.Content, newEntry)
|
||||||
} else {
|
} else {
|
||||||
// logrus.Debugf("hydrating map value at %s", path)
|
logrus.Debugf("hydrating map value at %s", path)
|
||||||
keyEntry := NewEntry(key, yaml.ScalarNode)
|
keyEntry := NewEntry(key, yaml.ScalarNode)
|
||||||
keyEntry.Value = key
|
keyEntry.Value = key
|
||||||
container.Content = append(container.Content, keyEntry, newEntry)
|
container.Content = append(container.Content, keyEntry, newEntry)
|
||||||
@ -303,25 +312,21 @@ func (e *Entry) FromOP(fields []*op.ItemField) error {
|
|||||||
subContainer := container.ChildNamed(key)
|
subContainer := container.ChildNamed(key)
|
||||||
if subContainer != nil {
|
if subContainer != nil {
|
||||||
container = subContainer
|
container = subContainer
|
||||||
} else {
|
continue
|
||||||
kind := yaml.MappingNode
|
|
||||||
if idx+1 < len(path)-1 && isNumeric(path[idx+1]) {
|
|
||||||
// logrus.Debugf("creating sequence container for key %s at %s", key, path)
|
|
||||||
kind = yaml.SequenceNode
|
|
||||||
}
|
|
||||||
child := NewEntry(key, kind)
|
|
||||||
child.Path = append(container.Path, key) // nolint: gocritic
|
|
||||||
|
|
||||||
if kind == yaml.SequenceNode {
|
|
||||||
container.Content = append(container.Content, child)
|
|
||||||
} else {
|
|
||||||
// logrus.Debugf("creating mapping container for %s at %s", key, container.Path)
|
|
||||||
keyEntry := NewEntry(child.Name(), yaml.ScalarNode)
|
|
||||||
keyEntry.Value = key
|
|
||||||
container.Content = append(container.Content, keyEntry, child)
|
|
||||||
}
|
|
||||||
container = child
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kind := yaml.MappingNode
|
||||||
|
if idx+1 == len(path)-1 && isNumeric(path[idx+1]) {
|
||||||
|
logrus.Debugf("creating sequence container for key %s at %s", key, path)
|
||||||
|
kind = yaml.SequenceNode
|
||||||
|
}
|
||||||
|
child := NewEntry(key, kind)
|
||||||
|
child.Path = append(container.Path, key) // nolint: gocritic
|
||||||
|
|
||||||
|
keyEntry := NewEntry(child.Name(), yaml.ScalarNode)
|
||||||
|
keyEntry.Value = key
|
||||||
|
container.Content = append(container.Content, keyEntry, child)
|
||||||
|
container = child
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +337,7 @@ func (e *Entry) ToOP() []*op.ItemField {
|
|||||||
ret := []*op.ItemField{}
|
ret := []*op.ItemField{}
|
||||||
var section *op.ItemSection
|
var section *op.ItemSection
|
||||||
|
|
||||||
if e.Kind == yaml.ScalarNode {
|
if e.IsScalar() {
|
||||||
name := e.Path[len(e.Path)-1]
|
name := e.Path[len(e.Path)-1]
|
||||||
fullPath := strings.Join(e.Path, ".")
|
fullPath := strings.Join(e.Path, ".")
|
||||||
if len(e.Path) > 1 {
|
if len(e.Path) > 1 {
|
||||||
@ -466,10 +471,8 @@ func (e *Entry) Merge(other *Entry) error {
|
|||||||
if err := local.Merge(remote); err != nil {
|
if err := local.Merge(remote); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
logrus.Debugf("adding new collection value at %s", remote.Path)
|
|
||||||
local.Content = append(local.Content, remote)
|
|
||||||
}
|
}
|
||||||
|
local.Content = append(local.Content, remote)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -48,7 +48,11 @@ func Load(ref string, preferRemote bool) (*Config, error) {
|
|||||||
return nil, fmt.Errorf("could not load %s from local as it's not a path", ref)
|
return nil, fmt.Errorf("could not load %s from local as it's not a path", ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
return FromFile(ref)
|
cfg, err := FromFile(ref)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not load file %s: %w", ref, err)
|
||||||
|
}
|
||||||
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromFile reads a path and returns a config.
|
// FromFile reads a path and returns a config.
|
||||||
@ -86,7 +90,7 @@ func FromYAML(data []byte) (*Config, error) {
|
|||||||
|
|
||||||
err := yaml.Unmarshal(data, &cfg.Tree)
|
err := yaml.Unmarshal(data, &cfg.Tree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("could not parse %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
|
@ -15,22 +15,6 @@ import (
|
|||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (cfg *Config) Lookup(query []string) (*Entry, error) {
|
|
||||||
if len(query) == 0 || len(query) == 1 && query[0] == "." {
|
|
||||||
return cfg.Tree, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
entry := cfg.Tree
|
|
||||||
for _, part := range query {
|
|
||||||
entry = entry.ChildNamed(part)
|
|
||||||
if entry == nil {
|
|
||||||
return nil, fmt.Errorf("value not found at %s of %s", part, query)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func findRepoConfig(from string) (*opDetails, error) {
|
func findRepoConfig(from string) (*opDetails, error) {
|
||||||
parts := strings.Split(from, "/")
|
parts := strings.Split(from, "/")
|
||||||
for i := len(parts); i > 0; i-- {
|
for i := len(parts); i > 0; i-- {
|
||||||
@ -107,7 +91,7 @@ func AutocompleteKeys(cmd *command.Command, currentValue, config string) ([]stri
|
|||||||
|
|
||||||
keys, err := KeysFromYAML(buf)
|
keys, err := KeysFromYAML(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, flag, err
|
return nil, flag, fmt.Errorf("could not parse file %s as %w", file, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
|
@ -84,7 +84,7 @@ func (cfg *Config) ToOP() *op.Item {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if value.Kind == yaml.MappingNode {
|
if value.Kind == yaml.MappingNode || value.Kind == yaml.SequenceNode {
|
||||||
sections = append(sections, &op.ItemSection{
|
sections = append(sections, &op.ItemSection{
|
||||||
ID: value.Name(),
|
ID: value.Name(),
|
||||||
Label: value.Name(),
|
Label: value.Name(),
|
||||||
|
@ -4,7 +4,7 @@ _config: !!joao
|
|||||||
# not sorted on purpose
|
# not sorted on purpose
|
||||||
int: 1 # line
|
int: 1 # line
|
||||||
# foot
|
# foot
|
||||||
string: "pato"
|
string: pato
|
||||||
bool: false
|
bool: false
|
||||||
secret: !!secret very secret
|
secret: !!secret very secret
|
||||||
nested:
|
nested:
|
||||||
@ -12,6 +12,10 @@ nested:
|
|||||||
int: 1
|
int: 1
|
||||||
secret: !!secret very secret
|
secret: !!secret very secret
|
||||||
bool: true
|
bool: true
|
||||||
|
list:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
list:
|
list:
|
||||||
- one
|
- one
|
||||||
- two
|
- two
|
||||||
|
Loading…
Reference in New Issue
Block a user