implement parsing and conversion, get command
This commit is contained in:
parent
20ba4ba898
commit
2619181be4
|
@ -0,0 +1,13 @@
|
|||
// Copyright © 2022 Roberto Hidalgo <joao@un.rob.mx>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package cmd
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright © 2022 Roberto Hidalgo <joao@un.rob.mx>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package cmd
|
|
@ -0,0 +1,122 @@
|
|||
// Copyright © 2022 Roberto Hidalgo <joao@un.rob.mx>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"git.rob.mx/nidito/joao/pkg/config"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
getCommand.Flags().StringP("output", "o", "raw", "the format to output in")
|
||||
getCommand.Flags().Bool("remote", false, "query 1password instead of the filesystem")
|
||||
getCommand.Flags().Bool("redacted", false, "do not print secrets")
|
||||
}
|
||||
|
||||
var getCommand = &cobra.Command{
|
||||
Use: "get CONFIG [--output|-o=(raw|json|yaml)] [--remote] [--redacted] [jq expr]",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
path := args[0]
|
||||
query := ""
|
||||
if len(args) > 1 {
|
||||
query = args[1]
|
||||
}
|
||||
var cfg *config.Config
|
||||
if strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml") {
|
||||
buf, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read file %s", path)
|
||||
}
|
||||
|
||||
if len(buf) == 0 {
|
||||
buf = []byte("{}")
|
||||
}
|
||||
|
||||
cfg, err = config.ConfigFromYAML(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
format, _ := cmd.Flags().GetString("output")
|
||||
redacted, _ := cmd.Flags().GetBool("redacted")
|
||||
|
||||
if query == "" {
|
||||
switch format {
|
||||
case "yaml", "raw":
|
||||
bytes, err := cfg.AsYAML(redacted)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = cmd.OutOrStdout().Write(bytes)
|
||||
return err
|
||||
case "json", "json-op":
|
||||
bytes, err := cfg.AsJSON(redacted, format == "json-op")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = cmd.OutOrStdout().Write(bytes)
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("unknown format %s", format)
|
||||
}
|
||||
|
||||
parts := strings.Split(query, ".")
|
||||
|
||||
entry := cfg.Tree
|
||||
for _, part := range parts {
|
||||
entry = entry.Children[part]
|
||||
if entry == nil {
|
||||
return fmt.Errorf("value not found at %s of %s", part, query)
|
||||
}
|
||||
}
|
||||
|
||||
var bytes []byte
|
||||
var err error
|
||||
if len(entry.Children) > 0 {
|
||||
val := entry.AsMap()
|
||||
if format == "yaml" {
|
||||
bytes, err = yaml.Marshal(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = cmd.OutOrStdout().Write(bytes)
|
||||
return err
|
||||
}
|
||||
|
||||
bytes, err = json.Marshal(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if valString, ok := entry.Value.(string); ok {
|
||||
bytes = []byte(valString)
|
||||
} else {
|
||||
bytes, err = json.Marshal(entry.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = cmd.OutOrStdout().Write(bytes)
|
||||
return err
|
||||
},
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright © 2022 Roberto Hidalgo <joao@un.rob.mx>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package cmd
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright © 2022 Roberto Hidalgo <joao@un.rob.mx>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var Root = &cobra.Command{
|
||||
Use: "joao [--silent|-v|--verbose] [--[no-]color] [-h|--help] [--version]",
|
||||
Short: "does config",
|
||||
Long: `does config with 1password and stuff`,
|
||||
// DisableAutoGenTag: true,
|
||||
// SilenceUsage: true,
|
||||
// SilenceErrors: true,
|
||||
ValidArgs: []string{""},
|
||||
Annotations: map[string]string{},
|
||||
Args: func(cmd *cobra.Command, args []string) error {
|
||||
err := cobra.OnlyValidArgs(cmd, args)
|
||||
if err != nil {
|
||||
|
||||
suggestions := []string{}
|
||||
bold := color.New(color.Bold)
|
||||
for _, l := range cmd.SuggestionsFor(args[len(args)-1]) {
|
||||
suggestions = append(suggestions, bold.Sprint(l))
|
||||
}
|
||||
errMessage := fmt.Sprintf("Unknown subcommand %s", bold.Sprint(strings.Join(args, " ")))
|
||||
if len(suggestions) > 0 {
|
||||
errMessage += ". Perhaps you meant " + strings.Join(suggestions, ", ") + "?"
|
||||
}
|
||||
return fmt.Errorf("command not found")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
if ok, err := cmd.Flags().GetBool("version"); err == nil && ok {
|
||||
vc, _, err := cmd.Root().Find([]string{"__version"})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return vc.RunE(vc, []string{})
|
||||
}
|
||||
return fmt.Errorf("no command provided")
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func RootCommand(version string) *cobra.Command {
|
||||
Root.Annotations["version"] = version
|
||||
rootFlagset := pflag.NewFlagSet("joao", pflag.ContinueOnError)
|
||||
// for name, opt := range Root.Options {
|
||||
// def, ok := opt.Default.(bool)
|
||||
// if !ok {
|
||||
// def = false
|
||||
// }
|
||||
|
||||
// if opt.ShortName != "" {
|
||||
// rootFlagset.BoolP(name, opt.ShortName, def, opt.Description)
|
||||
// } else {
|
||||
// rootFlagset.Bool(name, def, opt.Description)
|
||||
// }
|
||||
// }
|
||||
|
||||
rootFlagset.Usage = func() {}
|
||||
rootFlagset.SortFlags = false
|
||||
Root.PersistentFlags().AddFlagSet(rootFlagset)
|
||||
|
||||
Root.Flags().Bool("version", false, "Display the version")
|
||||
|
||||
// Root.CompletionOptions.DisableDefaultCmd = true
|
||||
|
||||
Root.AddCommand(getCommand)
|
||||
// Root.AddCommand(completionCommand)
|
||||
// Root.AddCommand(generateDocumentationCommand)
|
||||
// Root.AddCommand(doctorCommand)
|
||||
|
||||
// Root.SetHelpCommand(helpCommand)
|
||||
// helpCommand.AddCommand(docsCommand)
|
||||
// docsCommand.SetHelpFunc(docs.HelpRenderer(Root.Options))
|
||||
// Root.SetHelpFunc(Root.HelpRenderer(Root.Options))
|
||||
|
||||
return Root
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright © 2022 Roberto Hidalgo <joao@un.rob.mx>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package cmd
|
|
@ -0,0 +1,19 @@
|
|||
module git.rob.mx/nidito/joao
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/1Password/connect-sdk-go v1.5.0
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect
|
||||
)
|
|
@ -0,0 +1,96 @@
|
|||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/1Password/connect-sdk-go v1.5.0 h1:F0WJcLSzGg3iXEDY49/ULdszYKsQLGTzn+2cyYXqiyk=
|
||||
github.com/1Password/connect-sdk-go v1.5.0/go.mod h1:TdynFeyvaRoackENbJ8RfJokH+WAowAu1MLmUbdMq6s=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
||||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
|
||||
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
|
||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright © 2022 Roberto Hidalgo <joao@un.rob.mx>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.rob.mx/nidito/joao/cmd"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var version = "dev"
|
||||
|
||||
func main() {
|
||||
logrus.SetFormatter(&logrus.TextFormatter{
|
||||
DisableLevelTruncation: true,
|
||||
DisableTimestamp: true,
|
||||
// ForceColors: runtime.ColorEnabled(),
|
||||
})
|
||||
|
||||
err := cmd.RootCommand(version).Execute()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
// Copyright © 2022 Roberto Hidalgo <joao@un.rob.mx>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
op "github.com/1Password/connect-sdk-go/onepassword"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Path string
|
||||
Vault string
|
||||
Name string
|
||||
Tree *Entry
|
||||
}
|
||||
|
||||
var redactOutput = false
|
||||
|
||||
func (cfg *Config) ToMap() map[string]interface{} {
|
||||
ret := map[string]interface{}{}
|
||||
for _, child := range cfg.Tree.Children {
|
||||
ret[child.Key] = child.AsMap()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (cfg *Config) ToOP() *op.Item {
|
||||
annotationsSection := &op.ItemSection{
|
||||
ID: "~annotations",
|
||||
Label: "~annotations",
|
||||
}
|
||||
sections := []*op.ItemSection{annotationsSection}
|
||||
fields := []*op.ItemField{
|
||||
{
|
||||
ID: "password",
|
||||
Type: "CONCEALED",
|
||||
Purpose: "PASSWORD",
|
||||
Label: "password",
|
||||
Value: "hash",
|
||||
}, {
|
||||
ID: "notesPlain",
|
||||
Type: "STRING",
|
||||
Purpose: "NOTES",
|
||||
Label: "notesPlain",
|
||||
Value: "flushed by joao",
|
||||
},
|
||||
}
|
||||
|
||||
for key, leaf := range cfg.Tree.Children {
|
||||
if len(leaf.Children) == 0 {
|
||||
fields = append(fields, leaf.ToOP(annotationsSection)...)
|
||||
continue
|
||||
}
|
||||
|
||||
if !leaf.isSequence {
|
||||
sections = append(sections, &op.ItemSection{
|
||||
ID: key,
|
||||
Label: key,
|
||||
})
|
||||
} else {
|
||||
fmt.Printf("Found sequence for %s", leaf.Key)
|
||||
}
|
||||
|
||||
for _, child := range leaf.Children {
|
||||
fields = append(fields, child.ToOP(annotationsSection)...)
|
||||
}
|
||||
}
|
||||
|
||||
return &op.Item{
|
||||
Title: cfg.Name,
|
||||
Sections: sections,
|
||||
Vault: op.ItemVault{ID: "nidito-admin"},
|
||||
Category: op.Password,
|
||||
Fields: fields,
|
||||
}
|
||||
}
|
||||
|
||||
func ConfigFromYAML(data []byte) (*Config, error) {
|
||||
cfg := &Config{
|
||||
Vault: "vault",
|
||||
Name: "title",
|
||||
Tree: NewEntry("root"),
|
||||
}
|
||||
|
||||
yaml.Unmarshal(data, cfg.Tree.Children)
|
||||
|
||||
for k, leaf := range cfg.Tree.Children {
|
||||
leaf.SetKey(k, []string{})
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func ConfigFromOP(item *op.Item) (*Config, error) {
|
||||
cfg := &Config{
|
||||
Vault: item.Vault.ID,
|
||||
Name: item.Title,
|
||||
Tree: NewEntry("root"),
|
||||
}
|
||||
|
||||
err := cfg.Tree.FromOP(item.Fields)
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
func (cfg *Config) MarshalYAML() (interface{}, error) {
|
||||
return cfg.Tree.MarshalYAML()
|
||||
}
|
||||
|
||||
func (cfg *Config) AsYAML(redacted bool) ([]byte, error) {
|
||||
redactOutput = redacted
|
||||
bytes, err := yaml.Marshal(cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not serialize config as yaml: %w", err)
|
||||
}
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
func (cfg *Config) AsJSON(redacted bool, item bool) ([]byte, error) {
|
||||
var repr interface{}
|
||||
if item {
|
||||
repr = cfg.ToOP()
|
||||
} else {
|
||||
redactOutput = redacted
|
||||
repr = cfg.ToMap()
|
||||
}
|
||||
|
||||
bytes, err := json.Marshal(repr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not serialize config as json: %w", err)
|
||||
}
|
||||
return bytes, nil
|
||||
}
|
|
@ -0,0 +1,287 @@
|
|||
// Copyright © 2022 Roberto Hidalgo <joao@un.rob.mx>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
op "github.com/1Password/connect-sdk-go/onepassword"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func isNumeric(s string) bool {
|
||||
for _, v := range s {
|
||||
if v < '0' || v > '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type Entry struct {
|
||||
Key string
|
||||
Path []string
|
||||
Value interface{}
|
||||
Children map[string]*Entry
|
||||
isSecret bool
|
||||
isSequence bool
|
||||
node *yaml.Node
|
||||
}
|
||||
|
||||
func NewEntry(name string) *Entry {
|
||||
return &Entry{Key: name, Children: map[string]*Entry{}}
|
||||
}
|
||||
|
||||
func (e *Entry) SetKey(key string, parent []string) {
|
||||
e.Path = append(parent, key)
|
||||
e.Key = key
|
||||
for k, child := range e.Children {
|
||||
child.SetKey(k, e.Path)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Entry) UnmarshalYAML(node *yaml.Node) error {
|
||||
e.node = node
|
||||
switch node.Kind {
|
||||
case yaml.DocumentNode, yaml.MappingNode:
|
||||
if e.Children == nil {
|
||||
e.Children = map[string]*Entry{}
|
||||
}
|
||||
err := node.Decode(&e.Children)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case yaml.SequenceNode:
|
||||
list := []*Entry{}
|
||||
err := node.Decode(&list)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if e.Children == nil {
|
||||
e.Children = map[string]*Entry{}
|
||||
}
|
||||
for idx, child := range list {
|
||||
child.Key = fmt.Sprintf("%d", idx)
|
||||
e.Children[child.Key] = child
|
||||
}
|
||||
e.isSequence = true
|
||||
case yaml.ScalarNode:
|
||||
var val interface{}
|
||||
err := node.Decode(&val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.Value = val
|
||||
e.isSecret = node.Tag == "!!secret"
|
||||
default:
|
||||
return fmt.Errorf("unknown yaml type: %v", node.Kind)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Entry) MarshalYAML() (interface{}, error) {
|
||||
if len(e.Children) == 0 {
|
||||
if redactOutput && e.isSecret {
|
||||
n := e.node
|
||||
return &yaml.Node{
|
||||
Kind: n.Kind,
|
||||
Style: yaml.TaggedStyle,
|
||||
Tag: n.Tag,
|
||||
Value: "",
|
||||
HeadComment: n.HeadComment,
|
||||
LineComment: n.LineComment,
|
||||
FootComment: n.FootComment,
|
||||
Line: n.Line,
|
||||
Column: n.Column,
|
||||
}, nil
|
||||
}
|
||||
return e.node, nil
|
||||
}
|
||||
|
||||
if e.isSequence {
|
||||
ret := make([]*Entry, len(e.Children))
|
||||
for k, child := range e.Children {
|
||||
idx, _ := strconv.Atoi(k)
|
||||
ret[idx] = child
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
ret := map[string]*Entry{}
|
||||
for k, child := range e.Children {
|
||||
ret[k] = child
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (e *Entry) FromOP(fields []*op.ItemField) error {
|
||||
annotations := map[string]string{}
|
||||
data := map[string]string{}
|
||||
labels := []string{}
|
||||
|
||||
for i := 0; i < len(fields); i++ {
|
||||
field := fields[i]
|
||||
label := field.Label
|
||||
if field.Section != nil {
|
||||
if field.Section.Label == "~annotations" {
|
||||
annotations[label] = field.Value
|
||||
continue
|
||||
} else {
|
||||
label = field.Section.Label + "." + label
|
||||
}
|
||||
}
|
||||
labels = append(labels, label)
|
||||
data[label] = field.Value
|
||||
}
|
||||
|
||||
for _, label := range labels {
|
||||
var value interface{} = data[label]
|
||||
|
||||
if typeString, ok := annotations[label]; ok {
|
||||
switch typeString {
|
||||
case "bool":
|
||||
value = value == "true"
|
||||
case "int":
|
||||
var err error
|
||||
value, err = strconv.ParseInt(value.(string), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
path := strings.Split(label, ".")
|
||||
container := e
|
||||
|
||||
for idx, key := range path {
|
||||
if idx == len(path)-1 {
|
||||
if !isNumeric(key) {
|
||||
isSecretLabel := annotations[label]
|
||||
container.Children[key] = &Entry{
|
||||
Key: key,
|
||||
Path: path,
|
||||
Value: value,
|
||||
isSecret: isSecretLabel == "!!secret",
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
holderI := container.Value
|
||||
if container.Value == nil {
|
||||
holderI = []interface{}{}
|
||||
}
|
||||
|
||||
holder := holderI.([]interface{})
|
||||
container.Value = append(holder, value)
|
||||
break
|
||||
}
|
||||
|
||||
subContainer, exists := container.Children[key]
|
||||
if exists {
|
||||
container = subContainer
|
||||
} else {
|
||||
container.Children[key] = NewEntry(key)
|
||||
container = container.Children[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Entry) ToOP(annotationsSection *op.ItemSection) []*op.ItemField {
|
||||
ret := []*op.ItemField{}
|
||||
var section *op.ItemSection
|
||||
name := e.Key
|
||||
if len(e.Path) > 1 {
|
||||
section = &op.ItemSection{ID: e.Path[0]}
|
||||
name = strings.Join(e.Path[1:], ".")
|
||||
}
|
||||
|
||||
if e.isSecret {
|
||||
ret = append(ret, &op.ItemField{
|
||||
ID: "~annotations." + strings.Join(e.Path, "."),
|
||||
Section: annotationsSection,
|
||||
Label: name,
|
||||
Type: "STRING",
|
||||
Value: "secret",
|
||||
})
|
||||
} else if _, ok := e.Value.(bool); ok {
|
||||
ret = append(ret, &op.ItemField{
|
||||
ID: "~annotations." + strings.Join(e.Path, "."),
|
||||
Section: annotationsSection,
|
||||
Label: name,
|
||||
Type: "STRING",
|
||||
Value: "bool",
|
||||
})
|
||||
} else if _, ok := e.Value.(int); ok {
|
||||
ret = append(ret, &op.ItemField{
|
||||
ID: "~annotations." + strings.Join(e.Path, "."),
|
||||
Section: annotationsSection,
|
||||
Label: name,
|
||||
Type: "STRING",
|
||||
Value: "int",
|
||||
})
|
||||
} else if _, ok := e.Value.(float64); ok {
|
||||
ret = append(ret, &op.ItemField{
|
||||
ID: "~annotations." + strings.Join(e.Path, "."),
|
||||
Section: annotationsSection,
|
||||
Label: name,
|
||||
Type: "STRING",
|
||||
Value: "float",
|
||||
})
|
||||
}
|
||||
|
||||
if len(e.Children) == 0 {
|
||||
ret = append(ret, &op.ItemField{
|
||||
ID: strings.Join(e.Path, "."),
|
||||
Section: section,
|
||||
Label: name,
|
||||
Type: "STRING",
|
||||
Value: fmt.Sprintf("%s", e.Value),
|
||||
})
|
||||
} else {
|
||||
for _, child := range e.Children {
|
||||
ret = append(ret, child.ToOP(annotationsSection)...)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (e *Entry) AsMap() interface{} {
|
||||
if len(e.Children) == 0 {
|
||||
if redactOutput && e.isSecret {
|
||||
return ""
|
||||
}
|
||||
return e.Value
|
||||
}
|
||||
|
||||
if e.isSequence {
|
||||
ret := make([]interface{}, len(e.Children))
|
||||
for key, child := range e.Children {
|
||||
idx, _ := strconv.Atoi(key)
|
||||
ret[idx] = child.AsMap()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
ret := map[string]interface{}{}
|
||||
for key, child := range e.Children {
|
||||
ret[key] = child.AsMap()
|
||||
}
|
||||
return ret
|
||||
}
|
Loading…
Reference in New Issue