Revert "keyring swap, better error messages/warnings, delay upgrade notif"

This reverts commit 7f69a3b23f.
pull/819/head
Maidul Islam 10 months ago
parent 7f69a3b23f
commit 7accaeffcf

@ -3,6 +3,7 @@ module github.com/Infisical/infisical-merge
go 1.19
require (
github.com/99designs/keyring v1.2.2
github.com/charmbracelet/lipgloss v0.5.0
github.com/denisbrodbeck/machineid v1.0.1
github.com/fatih/semgroup v1.2.0
@ -14,40 +15,43 @@ require (
github.com/muesli/reflow v0.3.0
github.com/muesli/roff v0.1.0
github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
github.com/posthog/posthog-go v0.0.0-20221221115252-24dfed35d71a
github.com/rs/cors v1.9.0
github.com/rs/zerolog v1.26.1
github.com/spf13/cobra v1.6.1
github.com/spf13/viper v1.8.1
github.com/stretchr/testify v1.8.1
github.com/stretchr/testify v1.8.0
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
golang.org/x/term v0.9.0
)
require (
github.com/alessio/shellescape v1.4.1 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/danieljoos/wincred v1.2.0 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-openapi/errors v0.20.2 // indirect
github.com/go-openapi/strfmt v0.21.3 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/muesli/mango v0.1.0 // indirect
github.com/muesli/mango-pflag v0.1.0 // indirect
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/pelletier/go-toml v1.9.3 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rs/cors v1.9.0 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
@ -58,7 +62,6 @@ require (
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/text v0.7.0 // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
@ -71,5 +74,4 @@ require (
github.com/jedib0t/go-pretty v4.3.0+incompatible
github.com/manifoldco/promptui v0.9.0
github.com/spf13/pflag v1.0.5 // indirect
github.com/zalando/go-keyring v0.2.3
)

@ -37,10 +37,12 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0=
github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0=
github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@ -70,13 +72,15 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
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/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE=
github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec=
github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0=
github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0=
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/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM=
github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@ -103,9 +107,9 @@ github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtK
github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg=
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -175,6 +179,8 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
@ -251,6 +257,8 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=
github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a h1:jlDOeO5TU0pYlbc/y6PFguab5IjANI0Knrpg3u/ton4=
github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/mango v0.1.0 h1:DZQK45d2gGbql1arsYA4vfg4d7I9Hfx5rX/GCmzsAvI=
@ -318,9 +326,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -328,9 +335,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
@ -348,8 +354,6 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zalando/go-keyring v0.2.3 h1:v9CUu9phlABObO4LPWycf+zwMG7nlbb3t/B5wa97yms=
github.com/zalando/go-keyring v0.2.3/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
@ -523,10 +527,15 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

@ -1,68 +0,0 @@
package book
import (
"time"
"github.com/zalando/go-keyring"
)
// Inspired by Github CLI
const MAIN_KEYRING_SERVICE = "infisical-cli"
type TimeoutError struct {
message string
}
func (e *TimeoutError) Error() string {
return e.message
}
func Set(key, value string) error {
ch := make(chan error, 1)
go func() {
defer close(ch)
ch <- keyring.Set(MAIN_KEYRING_SERVICE, key, value)
}()
select {
case err := <-ch:
return err
case <-time.After(3 * time.Second):
return &TimeoutError{"timeout while trying to set secret in keyring"}
}
}
func Get(key string) (string, error) {
ch := make(chan struct {
val string
err error
}, 1)
go func() {
defer close(ch)
val, err := keyring.Get(MAIN_KEYRING_SERVICE, key)
ch <- struct {
val string
err error
}{val, err}
}()
select {
case res := <-ch:
return res.val, res.err
case <-time.After(3 * time.Second):
return "", &TimeoutError{"timeout while trying to get secret from keyring"}
}
}
func Delete(key string) error {
ch := make(chan error, 1)
go func() {
defer close(ch)
ch <- keyring.Delete(MAIN_KEYRING_SERVICE, key)
}()
select {
case err := <-ch:
return err
case <-time.After(3 * time.Second):
return &TimeoutError{"timeout while trying to delete secret from keyring"}
}
}

@ -4,9 +4,7 @@ Copyright (c) 2023 Infisical Inc.
package main
import (
"fmt"
"os"
"strings"
"github.com/Infisical/infisical-merge/packages/cmd"
"github.com/rs/zerolog"
@ -14,33 +12,6 @@ import (
)
func main() {
log.Logger = log.Output(zerolog.ConsoleWriter{
Out: os.Stderr,
FormatTimestamp: func(i interface{}) string { return "" },
FormatLevel: func(i interface{}) string {
levelStr, ok := i.(string)
if !ok {
return ""
}
levelStr = strings.ToUpper(levelStr)
switch levelStr {
case "TRACE":
return fmt.Sprintf("\x1b[36m%s\x1b[0m", "trace:")
case "DEBUG":
return fmt.Sprintf("\x1b[34m%s\x1b[0m", "debug:")
case "INFO":
return ""
case "WARN":
return fmt.Sprintf("\x1b[33m%s\x1b[0m", "warning:")
case "ERROR":
return fmt.Sprintf("\x1b[31m%s\x1b[0m", "error:")
case "FATAL":
return fmt.Sprintf("\x1b[31;1m%s\x1b[0m", "fatal:")
default:
return levelStr
}
}})
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
cmd.Execute()
}

@ -3,7 +3,6 @@ package api
import (
"fmt"
"net/http"
"strings"
"github.com/Infisical/infisical-merge/packages/config"
"github.com/go-resty/resty/v2"
@ -25,10 +24,8 @@ func CallGetEncryptedWorkspaceKey(httpClient *resty.Client, request GetEncrypted
return GetEncryptedWorkspaceKeyResponse{}, fmt.Errorf("CallGetEncryptedWorkspaceKey: Unable to complete api request [err=%s]", err)
}
PrintApiRequestDebugLog(response)
if response.IsError() {
return GetEncryptedWorkspaceKeyResponse{}, PrintApiRequestError(response)
return GetEncryptedWorkspaceKeyResponse{}, fmt.Errorf("CallGetEncryptedWorkspaceKey: Unsuccessful response: [response=%s]", response)
}
return result, nil
@ -42,14 +39,12 @@ func CallGetServiceTokenDetailsV2(httpClient *resty.Client) (GetServiceTokenDeta
SetHeader("User-Agent", USER_AGENT).
Get(fmt.Sprintf("%v/v2/service-token", config.INFISICAL_URL))
PrintApiRequestDebugLog(response)
if err != nil {
return GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unable to complete api request [err=%s]", err)
}
if response.IsError() {
return GetServiceTokenDetailsResponse{}, PrintApiRequestError(response)
return GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unsuccessful response: [response=%s]", response)
}
return tokenDetailsResponse, nil
@ -64,14 +59,12 @@ func CallLogin1V2(httpClient *resty.Client, request GetLoginOneV2Request) (GetLo
SetBody(request).
Post(fmt.Sprintf("%v/v2/auth/login1", config.INFISICAL_URL))
PrintApiRequestDebugLog(response)
if err != nil {
return GetLoginOneV2Response{}, fmt.Errorf("CallLogin1V2: Unable to complete api request [err=%s]", err)
}
if response.IsError() {
return GetLoginOneV2Response{}, PrintApiRequestError(response)
return GetLoginOneV2Response{}, fmt.Errorf("CallLogin1V2: Unsuccessful response: [response=%s]", response)
}
return loginOneV2Response, nil
@ -104,8 +97,6 @@ func CallVerifyMfaToken(httpClient *resty.Client, request VerifyMfaTokenRequest)
verifyMfaTokenResponse.RefreshToken = refreshToken.Value
}
PrintApiRequestDebugLog(response)
if err != nil {
return nil, nil, fmt.Errorf("CallVerifyMfaToken: Unable to complete api request [err=%s]", err)
}
@ -142,14 +133,12 @@ func CallLogin2V2(httpClient *resty.Client, request GetLoginTwoV2Request) (GetLo
loginTwoV2Response.RefreshToken = refreshToken.Value
}
PrintApiRequestDebugLog(response)
if err != nil {
return GetLoginTwoV2Response{}, fmt.Errorf("CallLogin2V2: Unable to complete api request [err=%s]", err)
}
if response.IsError() {
return GetLoginTwoV2Response{}, PrintApiRequestError(response)
return GetLoginTwoV2Response{}, fmt.Errorf("CallLogin2V2: Unsuccessful response: [response=%s]", response)
}
return loginTwoV2Response, nil
@ -163,14 +152,12 @@ func CallGetAllWorkSpacesUserBelongsTo(httpClient *resty.Client) (GetWorkSpacesR
SetHeader("User-Agent", USER_AGENT).
Get(fmt.Sprintf("%v/v1/workspace", config.INFISICAL_URL))
PrintApiRequestDebugLog(response)
if err != nil {
return GetWorkSpacesResponse{}, err
}
if response.IsError() {
return GetWorkSpacesResponse{}, PrintApiRequestError(response)
return GetWorkSpacesResponse{}, fmt.Errorf("CallGetAllWorkSpacesUserBelongsTo: Unsuccessful response: [response=%v]", response)
}
return workSpacesResponse, nil
@ -184,8 +171,6 @@ func CallIsAuthenticated(httpClient *resty.Client) bool {
SetHeader("User-Agent", USER_AGENT).
Post(fmt.Sprintf("%v/v1/auth/checkAuth", config.INFISICAL_URL))
PrintApiRequestDebugLog(response)
if err != nil {
return false
}
@ -206,14 +191,12 @@ func CallGetAccessibleEnvironments(httpClient *resty.Client, request GetAccessib
SetHeader("User-Agent", USER_AGENT).
Get(fmt.Sprintf("%v/v2/workspace/%s/environments", config.INFISICAL_URL, request.WorkspaceId))
PrintApiRequestDebugLog(response)
if err != nil {
return GetAccessibleEnvironmentsResponse{}, err
}
if response.IsError() {
return GetAccessibleEnvironmentsResponse{}, PrintApiRequestError(response)
return GetAccessibleEnvironmentsResponse{}, fmt.Errorf("CallGetAccessibleEnvironments: Unsuccessful response: [response=%v]", response)
}
return accessibleEnvironmentsResponse, nil
@ -231,14 +214,12 @@ func CallGetNewAccessTokenWithRefreshToken(httpClient *resty.Client, refreshToke
}).
Post(fmt.Sprintf("%v/v1/auth/token", config.INFISICAL_URL))
PrintApiRequestDebugLog(response)
if err != nil {
return GetNewAccessTokenWithRefreshTokenResponse{}, err
}
if response.IsError() {
return GetNewAccessTokenWithRefreshTokenResponse{}, PrintApiRequestError(response)
return GetNewAccessTokenWithRefreshTokenResponse{}, fmt.Errorf("CallGetNewAccessTokenWithRefreshToken: Unsuccessful response: [response=%v]", response)
}
return newAccessToken, nil
@ -264,8 +245,6 @@ func CallGetSecretsV3(httpClient *resty.Client, request GetEncryptedSecretsV3Req
response, err := httpRequest.Get(fmt.Sprintf("%v/v3/secrets", config.INFISICAL_URL))
PrintApiRequestDebugLog(response)
if err != nil {
return GetEncryptedSecretsV3Response{}, fmt.Errorf("CallGetSecretsV3: Unable to complete api request [err=%s]", err)
}
@ -274,7 +253,7 @@ func CallGetSecretsV3(httpClient *resty.Client, request GetEncryptedSecretsV3Req
if response.StatusCode() == 401 {
return GetEncryptedSecretsV3Response{}, fmt.Errorf("CallGetSecretsV3: Request to access secrets with [environment=%v] [path=%v] [workspaceId=%v] is denied. Please check if your authentication method has access to requested scope", request.Environment, request.SecretPath, request.WorkspaceId)
} else {
return GetEncryptedSecretsV3Response{}, fmt.Errorf("CallGetSecretsV3: Unsuccessful response with http [status=%v]. Please make sure your secret path, workspace and environment name are all correct", response.StatusCode())
return GetEncryptedSecretsV3Response{}, fmt.Errorf("CallGetSecretsV3: Unsuccessful response. Please make sure your secret path, workspace and environment name are all correct [response=%v]", response.RawResponse)
}
}
@ -290,14 +269,12 @@ func CallCreateSecretsV3(httpClient *resty.Client, request CreateSecretV3Request
SetBody(request).
Post(fmt.Sprintf("%v/v3/secrets/%s", config.INFISICAL_URL, request.SecretName))
PrintApiRequestDebugLog(response)
if err != nil {
return fmt.Errorf("CallCreateSecretsV3: Unable to complete api request [err=%s]", err)
}
if response.IsError() {
return fmt.Errorf("CallCreateSecretsV3: Unsuccessful response with http [status=%v]. Please make sure your secret path, workspace and environment name are all correct", response.StatusCode())
return fmt.Errorf("CallCreateSecretsV3: Unsuccessful response. Please make sure your secret path, workspace and environment name are all correct [response=%s]", response)
}
return nil
@ -312,14 +289,12 @@ func CallDeleteSecretsV3(httpClient *resty.Client, request DeleteSecretV3Request
SetBody(request).
Delete(fmt.Sprintf("%v/v3/secrets/%s", config.INFISICAL_URL, request.SecretName))
PrintApiRequestDebugLog(response)
if err != nil {
return fmt.Errorf("CallDeleteSecretsV3: Unable to complete api request [err=%s]", err)
}
if response.IsError() {
return fmt.Errorf("CallDeleteSecretsV3: Unsuccessful response with http [status=%v]. Please make sure your secret path, workspace and environment name are all correct", response.StatusCode())
return fmt.Errorf("CallDeleteSecretsV3: Unsuccessful response. Please make sure your secret path, workspace and environment name are all correct [response=%s]", response)
}
return nil
@ -334,8 +309,6 @@ func CallUpdateSecretsV3(httpClient *resty.Client, request UpdateSecretByNameV3R
SetBody(request).
Patch(fmt.Sprintf("%v/v3/secrets/%s", config.INFISICAL_URL, request.SecretName))
PrintApiRequestDebugLog(response)
if err != nil {
return fmt.Errorf("CallUpdateSecretsV3: Unable to complete api request [err=%s]", err)
}
@ -356,8 +329,6 @@ func CallGetSingleSecretByNameV3(httpClient *resty.Client, request CreateSecretV
SetBody(request).
Post(fmt.Sprintf("%v/v3/secrets/%s", config.INFISICAL_URL, request.SecretName))
PrintApiRequestDebugLog(response)
if err != nil {
return fmt.Errorf("CallGetSingleSecretByNameV3: Unable to complete api request [err=%s]", err)
}
@ -368,17 +339,3 @@ func CallGetSingleSecretByNameV3(httpClient *resty.Client, request CreateSecretV
return nil
}
// API helper
func PrintApiRequestError(response *resty.Response) error {
method := strings.ToUpper(response.Request.Method)
url := response.Request.URL
responseStatus := response.StatusCode()
return fmt.Errorf("request to call %v %v resulted in response status %v", method, url, responseStatus)
}
func PrintApiRequestDebugLog(response *resty.Response) {
method := strings.ToUpper(response.Request.Method)
url := response.Request.URL
log.Debug().Msgf("requesting to call %v %v with [request=%v] returned [response=%v]", method, url, response.Request, response.RawResponse)
}

@ -77,7 +77,7 @@ var exportCmd = &cobra.Command{
secrets, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, InfisicalToken: infisicalToken, TagSlugs: tagSlugs, WorkspaceId: projectId, SecretsPath: secretsPath})
if err != nil {
util.HandleError(err, "Something went wrong when fetching secrets for export")
util.HandleError(err, "Unable to fetch secrets")
}
if secretOverriding {
@ -112,7 +112,7 @@ func init() {
exportCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
exportCmd.Flags().StringP("format", "f", "dotenv", "Set the format of the output file (dotenv, json, csv)")
exportCmd.Flags().Bool("secret-overriding", true, "Prioritizes personal secrets, if any, with the same name over shared secrets")
exportCmd.Flags().String("token", "", "Fetch secrets using the service token [can also set via environment variable name: INFISICAL_TOKEN")
exportCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")
exportCmd.Flags().StringP("tags", "t", "", "filter secrets by tag slugs")
exportCmd.Flags().String("projectId", "", "manually set the projectId to fetch secrets from")
exportCmd.Flags().String("path", "/", "get secrets within a folder path")

@ -46,10 +46,6 @@ var initCmd = &cobra.Command{
util.HandleError(err, "Unable to get your login details")
}
if userCreds.LoginExpired {
util.PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
httpClient := resty.New()
httpClient.SetAuthToken(userCreds.UserCredentials.JTWToken)
workspaceResponse, err := api.CallGetAllWorkSpacesUserBelongsTo(httpClient)

@ -117,7 +117,8 @@ var loginCmd = &cobra.Command{
err = util.StoreUserCredsInKeyRing(&userCredentialsToBeStored)
if err != nil {
log.Error().Msg("Unable to store your credentials in keyring")
currentVault, _ := util.GetCurrentVaultBackend()
log.Error().Msgf("Unable to store your credentials in system vault [%s]. Rerun with flag -d to see full logs", currentVault)
log.Error().Msgf("\nTo trouble shoot further, read https://infisical.com/docs/cli/faq")
log.Debug().Err(err)
//return here

@ -26,8 +26,13 @@ var resetCmd = &cobra.Command{
os.RemoveAll(pathToDir)
// TODO
// keyring.Delete()
// delete keyring
keyringInstance, err := util.GetKeyRing()
if err != nil {
util.HandleError(err)
}
keyringInstance.Remove(util.KEYRING_SERVICE_NAME)
// delete secrets backup
util.DeleteBackupSecrets()

@ -188,7 +188,7 @@ func filterReservedEnvVars(env map[string]models.SingleEnvironmentVariable) {
func init() {
rootCmd.AddCommand(runCmd)
runCmd.Flags().String("token", "", "Fetch secrets using the service token [can also set via environment variable name: INFISICAL_TOKEN")
runCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")
runCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from")
runCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
runCmd.Flags().Bool("include-imports", true, "Import linked secrets ")

@ -11,6 +11,8 @@ import (
"strings"
"unicode"
"crypto/sha256"
"github.com/Infisical/infisical-merge/packages/api"
"github.com/Infisical/infisical-merge/packages/crypto"
"github.com/Infisical/infisical-merge/packages/models"
@ -126,10 +128,6 @@ var secretsSetCmd = &cobra.Command{
util.HandleError(err, "Unable to authenticate")
}
if loggedInUserDetails.LoginExpired {
util.PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
httpClient := resty.New().
SetAuthToken(loggedInUserDetails.UserCredentials.JTWToken).
SetHeader("Accept", "application/json")
@ -188,11 +186,13 @@ var secretsSetCmd = &cobra.Command{
key := strings.ToUpper(splitKeyValueFromArg[0])
value := splitKeyValueFromArg[1]
hashedKey := fmt.Sprintf("%x", sha256.Sum256([]byte(key)))
encryptedKey, err := crypto.EncryptSymmetric([]byte(key), []byte(plainTextEncryptionKey))
if err != nil {
util.HandleError(err, "unable to encrypt your secrets")
}
hashedValue := fmt.Sprintf("%x", sha256.Sum256([]byte(value)))
encryptedValue, err := crypto.EncryptSymmetric([]byte(value), []byte(plainTextEncryptionKey))
if err != nil {
util.HandleError(err, "unable to encrypt your secrets")
@ -205,6 +205,7 @@ var secretsSetCmd = &cobra.Command{
SecretValueCiphertext: base64.StdEncoding.EncodeToString(encryptedValue.CipherText),
SecretValueIV: base64.StdEncoding.EncodeToString(encryptedValue.Nonce),
SecretValueTag: base64.StdEncoding.EncodeToString(encryptedValue.AuthTag),
SecretValueHash: hashedValue,
PlainTextKey: key,
Type: existingSecret.Type,
}
@ -232,9 +233,11 @@ var secretsSetCmd = &cobra.Command{
SecretKeyCiphertext: base64.StdEncoding.EncodeToString(encryptedKey.CipherText),
SecretKeyIV: base64.StdEncoding.EncodeToString(encryptedKey.Nonce),
SecretKeyTag: base64.StdEncoding.EncodeToString(encryptedKey.AuthTag),
SecretKeyHash: hashedKey,
SecretValueCiphertext: base64.StdEncoding.EncodeToString(encryptedValue.CipherText),
SecretValueIV: base64.StdEncoding.EncodeToString(encryptedValue.Nonce),
SecretValueTag: base64.StdEncoding.EncodeToString(encryptedValue.AuthTag),
SecretValueHash: hashedValue,
Type: util.SECRET_TYPE_SHARED,
PlainTextKey: key,
}
@ -331,10 +334,6 @@ var secretsDeleteCmd = &cobra.Command{
util.HandleError(err, "Unable to authenticate")
}
if loggedInUserDetails.LoginExpired {
util.PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil {
util.HandleError(err, "Unable to get local project details")
@ -628,10 +627,10 @@ func getSecretsByKeys(secrets []models.SingleEnvironmentVariable) map[string]mod
func init() {
secretsGenerateExampleEnvCmd.Flags().String("token", "", "Fetch secrets using the service token [can also set via environment variable name: INFISICAL_TOKEN")
secretsGenerateExampleEnvCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")
secretsCmd.AddCommand(secretsGenerateExampleEnvCmd)
secretsGetCmd.Flags().String("token", "", "Fetch secrets using the service token [can also set via environment variable name: INFISICAL_TOKEN")
secretsGetCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")
secretsCmd.AddCommand(secretsGetCmd)
secretsCmd.AddCommand(secretsSetCmd)
@ -650,7 +649,7 @@ func init() {
util.RequireLocalWorkspaceFile()
}
secretsCmd.Flags().String("token", "", "Fetch secrets using the service token [can also set via environment variable name: INFISICAL_TOKEN")
secretsCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")
secretsCmd.PersistentFlags().String("env", "dev", "Used to select the environment name on which actions should be taken on")
secretsCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
secretsCmd.Flags().Bool("include-imports", true, "Imported linked secrets ")

@ -0,0 +1,103 @@
/*
Copyright (c) 2023 Infisical Inc.
*/
package cmd
import (
"fmt"
"github.com/99designs/keyring"
"github.com/Infisical/infisical-merge/packages/util"
"github.com/posthog/posthog-go"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)
var vaultSetCmd = &cobra.Command{
Example: `infisical vault set pass`,
Use: "set [vault-name]",
Short: "Used to set the vault backend to store your login details securely at rest",
DisableFlagsInUseLine: true,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
wantedVaultTypeName := args[0]
currentVaultBackend, err := util.GetCurrentVaultBackend()
if err != nil {
log.Error().Msgf("Unable to set vault to [%s] because of [err=%s]", wantedVaultTypeName, err)
return
}
if wantedVaultTypeName == string(currentVaultBackend) {
log.Error().Msgf("You are already on vault backend [%s]", currentVaultBackend)
return
}
if isVaultToSwitchToValid(wantedVaultTypeName) {
configFile, err := util.GetConfigFile()
if err != nil {
log.Error().Msgf("Unable to set vault to [%s] because of [err=%s]", wantedVaultTypeName, err)
return
}
configFile.VaultBackendType = keyring.BackendType(wantedVaultTypeName) // save selected vault
configFile.LoggedInUserEmail = "" // reset the logged in user to prompt them to re login
err = util.WriteConfigFile(&configFile)
if err != nil {
log.Error().Msgf("Unable to set vault to [%s] because an error occurred when saving the config file [err=%s]", wantedVaultTypeName, err)
return
}
fmt.Printf("\nSuccessfully, switched vault backend from [%s] to [%s]. Please login in again to store your login details in the new vault with [infisical login]\n", currentVaultBackend, wantedVaultTypeName)
Telemetry.CaptureEvent("cli-command:vault set", posthog.NewProperties().Set("currentVault", currentVaultBackend).Set("wantedVault", wantedVaultTypeName).Set("version", util.CLI_VERSION))
} else {
log.Error().Msgf("The requested vault type [%s] is not available on this system. Only the following vault backends are available for you system: %s", wantedVaultTypeName, keyring.AvailableBackends())
}
},
}
// runCmd represents the run command
var vaultCmd = &cobra.Command{
Use: "vault",
Short: "Used to manage where your Infisical login token is saved on your machine",
DisableFlagsInUseLine: true,
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
printAvailableVaultBackends()
},
}
func printAvailableVaultBackends() {
fmt.Printf("The following vaults are available on your system:")
for _, backend := range keyring.AvailableBackends() {
fmt.Printf("\n- %s", backend)
}
currentVaultBackend, err := util.GetCurrentVaultBackend()
if err != nil {
log.Error().Msgf("printAvailableVaultBackends: unable to print the available vault backend because of error [err=%s]", err)
}
Telemetry.CaptureEvent("cli-command:vault", posthog.NewProperties().Set("currentVault", currentVaultBackend).Set("version", util.CLI_VERSION))
fmt.Printf("\n\nYou are currently using [%s] vault to store your login credentials\n", string(currentVaultBackend))
}
// Checks if the vault that the user wants to switch to is a valid available vault
func isVaultToSwitchToValid(vaultNameToSwitchTo string) bool {
isFound := false
for _, backend := range keyring.AvailableBackends() {
if vaultNameToSwitchTo == string(backend) {
isFound = true
break
}
}
return isFound
}
func init() {
vaultCmd.AddCommand(vaultSetCmd)
rootCmd.AddCommand(vaultCmd)
}

@ -1,5 +1,9 @@
package models
import (
"github.com/99designs/keyring"
)
type UserCredentials struct {
Email string `json:"email"`
PrivateKey string `json:"privateKey"`
@ -9,9 +13,10 @@ type UserCredentials struct {
// The file struct for Infisical config file
type ConfigFile struct {
LoggedInUserEmail string `json:"loggedInUserEmail"`
LoggedInUserDomain string `json:"LoggedInUserDomain,omitempty"`
LoggedInUsers []LoggedInUser `json:"loggedInUsers,omitempty"`
LoggedInUserEmail string `json:"loggedInUserEmail"`
LoggedInUserDomain string `json:"LoggedInUserDomain,omitempty"`
VaultBackendType keyring.BackendType `json:"vaultBackendType"`
LoggedInUsers []LoggedInUser `json:"loggedInUsers,omitempty"`
}
type LoggedInUser struct {

@ -11,7 +11,6 @@ import (
"os/exec"
"runtime"
"strings"
"time"
"github.com/fatih/color"
"github.com/rs/zerolog/log"
@ -21,16 +20,13 @@ func CheckForUpdate() {
if checkEnv := os.Getenv("INFISICAL_DISABLE_UPDATE_CHECK"); checkEnv != "" {
return
}
latestVersion, publishedDate, err := getLatestTag("Infisical", "infisical")
latestVersion, err := getLatestTag("Infisical", "infisical")
if err != nil {
log.Debug().Err(err)
// do nothing and continue
return
}
daysSinceRelease, _ := daysSinceDate(publishedDate)
if latestVersion != CLI_VERSION && daysSinceRelease > 5 {
if latestVersion != CLI_VERSION {
yellow := color.New(color.FgYellow).SprintFunc()
blue := color.New(color.FgCyan).SprintFunc()
black := color.New(color.FgBlack).SprintFunc()
@ -47,45 +43,44 @@ func CheckForUpdate() {
updateInstructions := GetUpdateInstructions()
if updateInstructions != "" {
msg = fmt.Sprintf("%s\n", GetUpdateInstructions())
msg = fmt.Sprintf("\n%s\n", GetUpdateInstructions())
fmt.Fprintln(os.Stderr, msg)
}
}
}
func getLatestTag(repoOwner string, repoName string) (string, string, error) {
func getLatestTag(repoOwner string, repoName string) (string, error) {
url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", repoOwner, repoName)
resp, err := http.Get(url)
if err != nil {
return "", "", err
return "", err
}
if resp.StatusCode != 200 {
return "", "", errors.New(fmt.Sprintf("gitHub API returned status code %d", resp.StatusCode))
return "", errors.New(fmt.Sprintf("gitHub API returned status code %d", resp.StatusCode))
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", "", err
return "", err
}
var releaseDetails struct {
TagName string `json:"tag_name"`
PublishedAt string `json:"published_at"`
var releaseTag struct {
TagName string `json:"tag_name"`
}
if err := json.Unmarshal(body, &releaseDetails); err != nil {
return "", "", fmt.Errorf("failed to unmarshal github response: %w", err)
if err := json.Unmarshal(body, &releaseTag); err != nil {
return "", fmt.Errorf("failed to unmarshal github response: %w", err)
}
tag_prefix := "infisical-cli/v"
// Extract the version from the first valid tag
version := strings.TrimPrefix(releaseDetails.TagName, tag_prefix)
version := strings.TrimPrefix(releaseTag.TagName, tag_prefix)
return version, releaseDetails.PublishedAt, nil
return version, nil
}
func GetUpdateInstructions() string {
@ -150,16 +145,3 @@ func IsRunningInDocker() bool {
return strings.Contains(string(cgroup), "docker")
}
func daysSinceDate(dateString string) (int, error) {
layout := "2006-01-02T15:04:05Z"
parsedDate, err := time.Parse(layout, dateString)
if err != nil {
return 0, err
}
currentTime := time.Now()
difference := currentTime.Sub(parsedDate)
days := int(difference.Hours() / 24)
return days, nil
}

@ -52,6 +52,7 @@ func WriteInitalConfig(userCredentials *models.UserCredentials) error {
configFile := models.ConfigFile{
LoggedInUserEmail: userCredentials.Email,
LoggedInUserDomain: config.INFISICAL_URL,
VaultBackendType: existingConfigFile.VaultBackendType,
LoggedInUsers: existingConfigFile.LoggedInUsers,
}

@ -4,8 +4,7 @@ import (
"encoding/json"
"fmt"
keyring "github.com/Infisical/infisical-merge/internal"
"github.com/99designs/keyring"
"github.com/Infisical/infisical-merge/packages/api"
"github.com/Infisical/infisical-merge/packages/config"
"github.com/Infisical/infisical-merge/packages/models"
@ -25,7 +24,17 @@ func StoreUserCredsInKeyRing(userCred *models.UserCredentials) error {
return fmt.Errorf("StoreUserCredsInKeyRing: something went wrong when marshalling user creds [err=%s]", err)
}
err = keyring.Set(userCred.Email, string(userCredMarshalled))
// Get keyring
configuredKeyring, err := GetKeyRing()
if err != nil {
return fmt.Errorf("StoreUserCredsInKeyRing: unable to get keyring instance with [err=%s]", err)
}
err = configuredKeyring.Set(keyring.Item{
Key: userCred.Email,
Data: []byte(string(userCredMarshalled)),
})
if err != nil {
return fmt.Errorf("StoreUserCredsInKeyRing: unable to store user credentials because [err=%s]", err)
}
@ -34,14 +43,20 @@ func StoreUserCredsInKeyRing(userCred *models.UserCredentials) error {
}
func GetUserCredsFromKeyRing(userEmail string) (credentials models.UserCredentials, err error) {
credentialsValue, err := keyring.Get(userEmail)
// Get keyring
configuredKeyring, err := GetKeyRing()
if err != nil {
return models.UserCredentials{}, fmt.Errorf("GetUserCredsFromKeyRing: unable to get keyring instance with [err=%s]", err)
}
credentialsValue, err := configuredKeyring.Get(userEmail)
if err != nil {
return models.UserCredentials{}, fmt.Errorf("GetUserCredsFromKeyRing: Unable to get key from Keyring. Could not find login credentials in your Keyring [err=%v]", err)
return models.UserCredentials{}, fmt.Errorf("GetUserCredsFromKeyRing: unable to get key from Keyring. could not find login credentials in your Keyring. This is common if you have switched vault backend recently. If so, please login in again and retry [err=%s]", err)
}
var userCredentials models.UserCredentials
err = json.Unmarshal([]byte(credentialsValue), &userCredentials)
err = json.Unmarshal([]byte(credentialsValue.Data), &userCredentials)
if err != nil {
return models.UserCredentials{}, fmt.Errorf("getUserCredsFromKeyRing: Something went wrong when unmarshalling user creds [err=%s]", err)
}
@ -83,11 +98,9 @@ func GetCurrentLoggedInUserDetails() (LoggedInUserDetails, error) {
isAuthenticated := api.CallIsAuthenticated(httpClient)
// TODO
// No cookie is set when user logins via browser
if !isAuthenticated {
accessTokenResponse, err := api.CallGetNewAccessTokenWithRefreshToken(httpClient, userCreds.RefreshToken)
if err == nil && accessTokenResponse.Token != "" {
accessTokenResponse, _ := api.CallGetNewAccessTokenWithRefreshToken(httpClient, userCreds.RefreshToken)
if accessTokenResponse.Token != "" {
isAuthenticated = true
userCreds.JTWToken = accessTokenResponse.Token
}

@ -5,7 +5,6 @@ import (
"os"
"github.com/fatih/color"
"github.com/rs/zerolog/log"
)
func HandleError(err error, messages ...string) {
@ -17,11 +16,12 @@ func PrintErrorAndExit(exitCode int, err error, messages ...string) {
if len(messages) > 0 {
for _, message := range messages {
log.Info().Msg(message)
fmt.Println(message)
}
}
log.Info().Msg("If this issue continues, get support at https://infisical.com/slack")
supportMsg := fmt.Sprintf("\n\nIf this issue continues, get support at https://infisical.com/slack")
fmt.Fprintln(os.Stderr, supportMsg)
os.Exit(exitCode)
}
@ -45,5 +45,5 @@ func PrintErrorMessageAndExit(messages ...string) {
}
func printError(e error) {
log.Error().Msg(e.Error())
color.New(color.FgRed).Fprintf(os.Stderr, "Hmm, we ran into an error: %v\n", e)
}

@ -17,18 +17,6 @@ import (
"github.com/rs/zerolog/log"
)
func containsGlobPatterns(secretPath string) bool {
globChars := []string{"*", "?", "[", "]", "{", "}", "**"}
normalizedPath := path.Clean(secretPath)
for _, char := range globChars {
if strings.Contains(normalizedPath, char) {
return true
}
}
return false
}
func GetPlainTextSecretsViaServiceToken(fullServiceToken string, environment string, secretPath string, includeImports bool) ([]models.SingleEnvironmentVariable, api.GetServiceTokenDetailsResponse, error) {
serviceTokenParts := strings.SplitN(fullServiceToken, ".", 4)
if len(serviceTokenParts) < 4 {
@ -38,6 +26,7 @@ func GetPlainTextSecretsViaServiceToken(fullServiceToken string, environment str
serviceToken := fmt.Sprintf("%v.%v.%v", serviceTokenParts[0], serviceTokenParts[1], serviceTokenParts[2])
httpClient := resty.New()
httpClient.SetAuthToken(serviceToken).
SetHeader("Accept", "application/json")
@ -209,21 +198,15 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models
log.Debug().Msg("GetAllEnvironmentVariables: Connected to internet, checking logged in creds")
RequireLocalWorkspaceFile()
RequireLogin()
} else {
PrintErrorMessageAndExit("It looks like you are not connected to the internet, please reconnect and try again")
}
log.Trace().Msg("GetAllEnvironmentVariables: Trying to fetch secrets using logged in details")
log.Debug().Msg("GetAllEnvironmentVariables: Trying to fetch secrets using logged in details")
loggedInUserDetails, err := GetCurrentLoggedInUserDetails()
if err != nil {
return nil, err
}
if loggedInUserDetails.LoginExpired {
PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
workspaceFile, err := GetWorkSpaceFromFile()
if err != nil {
return nil, err
@ -259,7 +242,7 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models
}
} else {
log.Trace().Msg("Trying to fetch secrets using service token")
log.Debug().Msg("Trying to fetch secrets using service token")
secretsToReturn, _, errorToReturn = GetPlainTextSecretsViaServiceToken(infisicalToken, params.Environment, params.SecretsPath, params.IncludeImport)
}
@ -429,11 +412,7 @@ func ExpandSecrets(secrets []models.SingleEnvironmentVariable, infisicalToken st
// if not in cross reference cache, fetch it from server
refSecs, err := GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: env, InfisicalToken: infisicalToken, SecretsPath: secPath})
if err != nil {
if infisicalToken != "" {
HandleError(err, fmt.Sprintf("Could not fetch secrets in environment: %s secret-path: %s", env, secPath), "Please ensure your service token has access to the required environments and paths to fetch the requested secrets")
} else {
HandleError(err, fmt.Sprintf("Could not fetch secrets in environment: %s secret-path: %s", env, secPath))
}
HandleError(err, fmt.Sprintf("Could not fetch secrets in environment: %s secret-path: %s", env, secPath), "If you are using a service token to fetch secrets, please ensure it is valid")
}
refSecsByKey := getSecretsByKeys(refSecs)
// save it to avoid calling api again for same environment and folder path
@ -697,6 +676,7 @@ func GetEnvelopmentBasedOnGitBranch(workspaceFile models.WorkspaceConfigFile) st
if err == nil && ok {
return envBasedOnGitBranch
} else {
log.Debug().Msgf("getEnvelopmentBasedOnGitBranch: [err=%s]", err)
return ""
}
}

@ -0,0 +1,258 @@
package util
import (
"io"
"os"
"path"
"testing"
"github.com/Infisical/infisical-merge/packages/models"
)
// References to self should return the value unaltered
func Test_SubstituteSecrets_When_ReferenceToSelf(t *testing.T) {
var tests = []struct {
Key string
Value string
ExpectedValue string
}{
{Key: "A", Value: "${A}", ExpectedValue: "${A}"},
{Key: "A", Value: "${A} ${A}", ExpectedValue: "${A} ${A}"},
{Key: "A", Value: "${A}${A}", ExpectedValue: "${A}${A}"},
}
for _, test := range tests {
secret := models.SingleEnvironmentVariable{
Key: test.Key,
Value: test.Value,
}
secrets := []models.SingleEnvironmentVariable{secret}
result := SubstituteSecrets(secrets)
if result[0].Value != test.ExpectedValue {
t.Errorf("Test_SubstituteSecrets_When_ReferenceToSelf: expected %s but got %s for input %s", test.ExpectedValue, result[0].Value, test.Value)
}
}
}
func Test_SubstituteSecrets_When_ReferenceDoesNotExist(t *testing.T) {
var tests = []struct {
Key string
Value string
ExpectedValue string
}{
{Key: "A", Value: "${X}", ExpectedValue: "${X}"},
{Key: "A", Value: "${H}HELLO", ExpectedValue: "${H}HELLO"},
{Key: "A", Value: "${L}${S}", ExpectedValue: "${L}${S}"},
}
for _, test := range tests {
secret := models.SingleEnvironmentVariable{
Key: test.Key,
Value: test.Value,
}
secrets := []models.SingleEnvironmentVariable{secret}
result := SubstituteSecrets(secrets)
if result[0].Value != test.ExpectedValue {
t.Errorf("Test_SubstituteSecrets_When_ReferenceToSelf: expected %s but got %s for input %s", test.ExpectedValue, result[0].Value, test.Value)
}
}
}
func Test_SubstituteSecrets_When_ReferenceDoesNotExist_And_Self_Referencing(t *testing.T) {
tests := []struct {
Key string
Value string
ExpectedValue string
}{
{
Key: "O",
Value: "${P} ==$$ ${X} ${UNKNOWN} ${A}",
ExpectedValue: "DOMAIN === ${A} DOMAIN >>> ==$$ DOMAIN ${UNKNOWN} ${A}",
},
{
Key: "X",
Value: "DOMAIN",
ExpectedValue: "DOMAIN",
},
{
Key: "A",
Value: "*${A}* ${X}",
ExpectedValue: "*${A}* DOMAIN",
},
{
Key: "H",
Value: "${X} >>>",
ExpectedValue: "DOMAIN >>>",
},
{
Key: "P",
Value: "DOMAIN === ${A} ${H}",
ExpectedValue: "DOMAIN === ${A} DOMAIN >>>",
},
{
Key: "T",
Value: "${P} ==$$ ${X} ${UNKNOWN} ${A} ${P} ==$$ ${X} ${UNKNOWN} ${A}",
ExpectedValue: "DOMAIN === ${A} DOMAIN >>> ==$$ DOMAIN ${UNKNOWN} ${A} DOMAIN === ${A} DOMAIN >>> ==$$ DOMAIN ${UNKNOWN} ${A}",
},
{
Key: "S",
Value: "${ SSS$$ ${HEY}",
ExpectedValue: "${ SSS$$ ${HEY}",
},
}
secrets := []models.SingleEnvironmentVariable{}
for _, test := range tests {
secrets = append(secrets, models.SingleEnvironmentVariable{Key: test.Key, Value: test.Value})
}
results := SubstituteSecrets(secrets)
for index, expanded := range results {
if expanded.Value != tests[index].ExpectedValue {
t.Errorf("Test_SubstituteSecrets_When_ReferenceToSelf: expected [%s] but got [%s] for input [%s]", tests[index].ExpectedValue, expanded.Value, tests[index].Value)
}
}
}
func Test_SubstituteSecrets_When_No_SubstituteNeeded(t *testing.T) {
tests := []struct {
Key string
Value string
ExpectedValue string
}{
{
Key: "DOMAIN",
Value: "infisical.com",
ExpectedValue: "infisical.com",
},
{
Key: "API_KEY",
Value: "hdgsvjshcgkdckhevdkd",
ExpectedValue: "hdgsvjshcgkdckhevdkd",
},
{
Key: "ENV",
Value: "PROD",
ExpectedValue: "PROD",
},
}
secrets := []models.SingleEnvironmentVariable{}
for _, test := range tests {
secrets = append(secrets, models.SingleEnvironmentVariable{Key: test.Key, Value: test.Value})
}
results := SubstituteSecrets(secrets)
for index, expanded := range results {
if expanded.Value != tests[index].ExpectedValue {
t.Errorf("Test_SubstituteSecrets_When_ReferenceToSelf: expected [%s] but got [%s] for input [%s]", tests[index].ExpectedValue, expanded.Value, tests[index].Value)
}
}
}
func Test_Read_Env_From_File(t *testing.T) {
type testCase struct {
TestFile string
ExpectedEnv string
}
var cases = []testCase{
{
TestFile: "testdata/infisical-default-env.json",
ExpectedEnv: "myDefaultEnv",
},
{
TestFile: "testdata/infisical-branch-env.json",
ExpectedEnv: "myMainEnv",
},
{
TestFile: "testdata/infisical-no-matching-branch-env.json",
ExpectedEnv: "myDefaultEnv",
},
}
// create a tmp directory for testing
testDir, err := os.MkdirTemp(os.TempDir(), "infisical-test")
if err != nil {
t.Errorf("Test_Read_DefaultEnv_From_File: Failed to create temp directory: %s", err)
}
// safe the current working directory
originalDir, err := os.Getwd()
if err != nil {
t.Errorf("Test_Read_DefaultEnv_From_File: Failed to get current working directory: %s", err)
}
// backup the original git command
originalGitCmd := getCurrentBranchCmd
// make sure to clean up after the test
t.Cleanup(func() {
os.Chdir(originalDir)
os.RemoveAll(testDir)
getCurrentBranchCmd = originalGitCmd
})
// mock the git command to return "main" as the current branch
getCurrentBranchCmd = execCmd{cmd: "echo", args: []string{"main"}}
for _, c := range cases {
// make sure we start in the original directory
err = os.Chdir(originalDir)
if err != nil {
t.Errorf("Test_Read_DefaultEnv_From_File: Failed to change working directory: %s", err)
}
// remove old test file if it exists
err = os.Remove(path.Join(testDir, INFISICAL_WORKSPACE_CONFIG_FILE_NAME))
if err != nil && !os.IsNotExist(err) {
t.Errorf("Test_Read_DefaultEnv_From_File: Failed to remove old test file: %s", err)
}
// deploy the test file
copyTestFile(t, c.TestFile, path.Join(testDir, INFISICAL_WORKSPACE_CONFIG_FILE_NAME))
// change the working directory to the tmp directory
err = os.Chdir(testDir)
if err != nil {
t.Errorf("Test_Read_DefaultEnv_From_File: Failed to change working directory: %s", err)
}
// get env from file
env := GetEnvFromWorkspaceFile()
if env != c.ExpectedEnv {
t.Errorf("Test_Read_DefaultEnv_From_File: Expected env to be %s but got %s", c.ExpectedEnv, env)
}
}
}
func copyTestFile(t *testing.T, src, dst string) {
srcFile, err := os.Open(src)
if err != nil {
t.Errorf("Test_Read_Env_From_File_By_Branch: Failed to open source file: %s", err)
}
defer srcFile.Close()
dstFile, err := os.Create(dst)
if err != nil {
t.Errorf("Test_Read_Env_From_File_By_Branch: Failed to create destination file: %s", err)
}
defer dstFile.Close()
_, err = io.Copy(dstFile, srcFile)
if err != nil {
t.Errorf("Test_Read_Env_From_File_By_Branch: Failed to copy file: %s", err)
}
}

@ -0,0 +1,73 @@
package util
import (
"fmt"
"os"
"github.com/99designs/keyring"
"golang.org/x/term"
)
func GetCurrentVaultBackend() (keyring.BackendType, error) {
configFile, err := GetConfigFile()
if err != nil {
return "", fmt.Errorf("getCurrentVaultBackend: unable to get config file [err=%s]", err)
}
if configFile.VaultBackendType == "" {
return keyring.AvailableBackends()[0], nil
}
return configFile.VaultBackendType, nil
}
func GetKeyRing() (keyring.Keyring, error) {
currentVaultBackend, err := GetCurrentVaultBackend()
if err != nil {
return nil, fmt.Errorf("GetKeyRing: unable to get the current vault backend, [err=%s]", err)
}
keyringInstanceConfig := keyring.Config{
FilePasswordFunc: fileKeyringPassphrasePrompt,
ServiceName: KEYRING_SERVICE_NAME,
LibSecretCollectionName: KEYRING_SERVICE_NAME,
KWalletAppID: KEYRING_SERVICE_NAME,
KWalletFolder: KEYRING_SERVICE_NAME,
KeychainName: "login", // default so user will not be prompted
KeychainTrustApplication: true,
WinCredPrefix: KEYRING_SERVICE_NAME,
FileDir: fmt.Sprintf("~/%s-file-vault", KEYRING_SERVICE_NAME),
KeychainAccessibleWhenUnlocked: true,
}
// if the user explicitly sets a vault backend, then only use that
if currentVaultBackend != "" {
keyringInstanceConfig.AllowedBackends = []keyring.BackendType{keyring.BackendType(currentVaultBackend)}
}
keyringInstance, err := keyring.Open(keyringInstanceConfig)
if err != nil {
return nil, fmt.Errorf("GetKeyRing: Unable to create instance of Keyring because of [err=%s]", err)
}
return keyringInstance, nil
}
func fileKeyringPassphrasePrompt(prompt string) (string, error) {
if password, ok := os.LookupEnv("VAULT_PASS"); ok {
return password, nil
} else if password, ok := os.LookupEnv("INFISICAL_VAULT_FILE_PASSPHRASE"); ok {
return password, nil
} else {
fmt.Println("To avoid repeatedly typing your password, set the environment variable `VAULT_PASS` to your password")
}
fmt.Fprintf(os.Stderr, "%s:", prompt)
b, err := term.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
return "", err
}
fmt.Println("")
return string(b), nil
}

@ -0,0 +1,51 @@
---
title: "infisical vault"
description: "Change the vault type in Infisical"
---
<Tabs>
<Tab title="View current Vault">
```bash
infisical vault
# Example output
The following vaults are available on your system:
- keychain
- pass
- file
You are currently using [keychain] vault to store your login credentials
```
</Tab>
<Tab title="Switch vault">
```bash
infisical vault set <name-of-vault>
# Example
infisical vault set keychain
```
</Tab>
</Tabs>
## Description
To ensure secure storage of your login credentials when using the CLI, Infisical stores login credentials securely in a system vault or encrypted text file with a passphrase known only by the user.
<Accordion title="Supported vaults">
By default, the most appropriate vault is chosen to store your login credentials.
For example, if you are on macOS, KeyChain will be automatically selected.
- [macOS Keychain](https://support.apple.com/en-au/guide/keychain-access/welcome/mac)
- [Windows Credential Manager](https://support.microsoft.com/en-au/help/4026814/windows-accessing-credential-manager)
- Secret Service ([Gnome Keyring](https://wiki.gnome.org/Projects/GnomeKeyring), [KWallet](https://kde.org/applications/system/org.kde.kwalletmanager5))
- [KWallet](https://kde.org/applications/system/org.kde.kwalletmanager5)
- [Pass](https://www.passwordstore.org/)
- [KeyCtl]()
- Encrypted file (JWT)
</Accordion>
<Tip>To avoid constantly entering your passphrase when using the `file` vault type, set the `INFISICAL_VAULT_FILE_PASSPHRASE` environment variable with your password in your shell</Tip>

@ -166,6 +166,7 @@
"cli/commands/run",
"cli/commands/secrets",
"cli/commands/export",
"cli/commands/vault",
"cli/commands/user",
"cli/commands/reset",
{

Loading…
Cancel
Save