diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 5456b143f..dbd885350 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout source code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0 - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9a6aeb582..c1a2bff20 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -43,7 +43,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 3059b05a2..0d5b4e969 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0 - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 67cfa4c36..84d260a8f 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0 - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 96138caf1..21c527442 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest-16-cores steps: - name: Checkout source code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0 with: fetch-depth: 0 @@ -79,7 +79,7 @@ jobs: if: github.ref == 'refs/heads/main' steps: - name: Checkout source code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0 - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 4b135bb2a..6a44c8afb 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -28,7 +28,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/go.mod b/go.mod index b0fef95bc..688094670 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/cyphar/filepath-securejoin v0.4.1 github.com/distribution/distribution/v3 v3.0.0 github.com/evanphx/json-patch/v5 v5.9.11 - github.com/fatih/color v1.13.0 + github.com/fatih/color v1.18.0 github.com/fluxcd/cli-utils v0.36.0-flux.14 github.com/foxcpp/go-mockdns v1.1.0 github.com/gobwas/glob v0.2.3 @@ -32,9 +32,9 @@ require ( github.com/spf13/pflag v1.0.7 github.com/stretchr/testify v1.10.0 go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/crypto v0.40.0 - golang.org/x/term v0.33.0 - golang.org/x/text v0.27.0 + golang.org/x/crypto v0.41.0 + golang.org/x/term v0.34.0 + golang.org/x/text v0.28.0 k8s.io/api v0.33.3 k8s.io/apiextensions-apiserver v0.33.3 k8s.io/apimachinery v0.33.3 @@ -102,7 +102,7 @@ require ( github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/miekg/dns v1.1.57 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect @@ -155,13 +155,13 @@ require ( go.opentelemetry.io/otel/trace v1.37.0 // indirect go.opentelemetry.io/proto/otlp v1.4.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/mod v0.25.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.34.0 // indirect + golang.org/x/sys v0.35.0 // indirect golang.org/x/time v0.12.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/tools v0.35.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect google.golang.org/grpc v1.68.1 // indirect diff --git a/go.sum b/go.sum index f7789cbbb..5ac66f328 100644 --- a/go.sum +++ b/go.sum @@ -83,8 +83,8 @@ github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjT github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fluxcd/cli-utils v0.36.0-flux.14 h1:I//AMVUXTc+M04UtIXArMXQZCazGMwfemodV1j/yG8c= @@ -198,14 +198,11 @@ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhn github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -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/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= @@ -387,16 +384,16 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -410,8 +407,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -431,24 +428,22 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/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-20220520151302-bc2c85ada10a/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -456,8 +451,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -465,8 +460,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -477,8 +472,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/action/get_metadata_test.go b/pkg/action/get_metadata_test.go index 08e99d8d6..6ceb34951 100644 --- a/pkg/action/get_metadata_test.go +++ b/pkg/action/get_metadata_test.go @@ -17,13 +17,606 @@ limitations under the License. package action import ( + "errors" + "io" "testing" + "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" + kubefake "helm.sh/helm/v4/pkg/kube/fake" release "helm.sh/helm/v4/pkg/release/v1" + helmtime "helm.sh/helm/v4/pkg/time" ) +// unreachableKubeClient is a test client that always returns an error for IsReachable +type unreachableKubeClient struct { + kubefake.PrintingKubeClient +} + +func (u *unreachableKubeClient) IsReachable() error { + return errors.New("connection refused") +} + +func TestNewGetMetadata(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetMetadata(cfg) + + assert.NotNil(t, client) + assert.Equal(t, cfg, client.cfg) + assert.Equal(t, 0, client.Version) +} + +func TestGetMetadata_Run_BasicMetadata(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetMetadata(cfg) + + releaseName := "test-release" + deployedTime := helmtime.Now() + + rel := &release.Release{ + Name: releaseName, + Info: &release.Info{ + Status: release.StatusDeployed, + LastDeployed: deployedTime, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "test-chart", + Version: "1.0.0", + AppVersion: "v1.2.3", + }, + }, + Version: 1, + Namespace: "default", + } + + cfg.Releases.Create(rel) + + result, err := client.Run(releaseName) + require.NoError(t, err) + + assert.Equal(t, releaseName, result.Name) + assert.Equal(t, "test-chart", result.Chart) + assert.Equal(t, "1.0.0", result.Version) + assert.Equal(t, "v1.2.3", result.AppVersion) + assert.Equal(t, "default", result.Namespace) + assert.Equal(t, 1, result.Revision) + assert.Equal(t, "deployed", result.Status) + assert.Equal(t, deployedTime.Format(time.RFC3339), result.DeployedAt) + assert.Empty(t, result.Dependencies) + assert.Empty(t, result.Annotations) +} + +func TestGetMetadata_Run_WithDependencies(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetMetadata(cfg) + + releaseName := "test-release" + deployedTime := helmtime.Now() + + dependencies := []*chart.Dependency{ + { + Name: "mysql", + Version: "8.0.25", + Repository: "https://charts.bitnami.com/bitnami", + }, + { + Name: "redis", + Version: "6.2.4", + Repository: "https://charts.bitnami.com/bitnami", + }, + } + + rel := &release.Release{ + Name: releaseName, + Info: &release.Info{ + Status: release.StatusDeployed, + LastDeployed: deployedTime, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "test-chart", + Version: "1.0.0", + AppVersion: "v1.2.3", + Dependencies: dependencies, + }, + }, + Version: 1, + Namespace: "default", + } + + cfg.Releases.Create(rel) + + result, err := client.Run(releaseName) + require.NoError(t, err) + + assert.Equal(t, releaseName, result.Name) + assert.Equal(t, "test-chart", result.Chart) + assert.Equal(t, "1.0.0", result.Version) + assert.Equal(t, dependencies, result.Dependencies) + assert.Len(t, result.Dependencies, 2) + assert.Equal(t, "mysql", result.Dependencies[0].Name) + assert.Equal(t, "redis", result.Dependencies[1].Name) +} + +func TestGetMetadata_Run_WithDependenciesAliases(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetMetadata(cfg) + + releaseName := "test-release" + deployedTime := helmtime.Now() + + dependencies := []*chart.Dependency{ + { + Name: "mysql", + Version: "8.0.25", + Repository: "https://charts.bitnami.com/bitnami", + Alias: "database", + }, + { + Name: "redis", + Version: "6.2.4", + Repository: "https://charts.bitnami.com/bitnami", + Alias: "cache", + }, + } + + rel := &release.Release{ + Name: releaseName, + Info: &release.Info{ + Status: release.StatusDeployed, + LastDeployed: deployedTime, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "test-chart", + Version: "1.0.0", + AppVersion: "v1.2.3", + Dependencies: dependencies, + }, + }, + Version: 1, + Namespace: "default", + } + + cfg.Releases.Create(rel) + + result, err := client.Run(releaseName) + require.NoError(t, err) + + assert.Equal(t, releaseName, result.Name) + assert.Equal(t, "test-chart", result.Chart) + assert.Equal(t, "1.0.0", result.Version) + assert.Equal(t, dependencies, result.Dependencies) + assert.Len(t, result.Dependencies, 2) + assert.Equal(t, "mysql", result.Dependencies[0].Name) + assert.Equal(t, "database", result.Dependencies[0].Alias) + assert.Equal(t, "redis", result.Dependencies[1].Name) + assert.Equal(t, "cache", result.Dependencies[1].Alias) +} + +func TestGetMetadata_Run_WithMixedDependencies(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetMetadata(cfg) + + releaseName := "test-release" + deployedTime := helmtime.Now() + + dependencies := []*chart.Dependency{ + { + Name: "mysql", + Version: "8.0.25", + Repository: "https://charts.bitnami.com/bitnami", + Alias: "database", + }, + { + Name: "nginx", + Version: "1.20.0", + Repository: "https://charts.bitnami.com/bitnami", + }, + { + Name: "redis", + Version: "6.2.4", + Repository: "https://charts.bitnami.com/bitnami", + Alias: "cache", + }, + { + Name: "postgresql", + Version: "11.0.0", + Repository: "https://charts.bitnami.com/bitnami", + }, + } + + rel := &release.Release{ + Name: releaseName, + Info: &release.Info{ + Status: release.StatusDeployed, + LastDeployed: deployedTime, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "test-chart", + Version: "1.0.0", + AppVersion: "v1.2.3", + Dependencies: dependencies, + }, + }, + Version: 1, + Namespace: "default", + } + + cfg.Releases.Create(rel) + + result, err := client.Run(releaseName) + require.NoError(t, err) + + assert.Equal(t, releaseName, result.Name) + assert.Equal(t, "test-chart", result.Chart) + assert.Equal(t, "1.0.0", result.Version) + assert.Equal(t, dependencies, result.Dependencies) + assert.Len(t, result.Dependencies, 4) + + // Verify dependencies with aliases + assert.Equal(t, "mysql", result.Dependencies[0].Name) + assert.Equal(t, "database", result.Dependencies[0].Alias) + assert.Equal(t, "redis", result.Dependencies[2].Name) + assert.Equal(t, "cache", result.Dependencies[2].Alias) + + // Verify dependencies without aliases + assert.Equal(t, "nginx", result.Dependencies[1].Name) + assert.Equal(t, "", result.Dependencies[1].Alias) + assert.Equal(t, "postgresql", result.Dependencies[3].Name) + assert.Equal(t, "", result.Dependencies[3].Alias) +} + +func TestGetMetadata_Run_WithAnnotations(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetMetadata(cfg) + + releaseName := "test-release" + deployedTime := helmtime.Now() + + annotations := map[string]string{ + "helm.sh/hook": "pre-install", + "helm.sh/hook-weight": "5", + "custom.annotation": "test-value", + } + + rel := &release.Release{ + Name: releaseName, + Info: &release.Info{ + Status: release.StatusDeployed, + LastDeployed: deployedTime, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "test-chart", + Version: "1.0.0", + AppVersion: "v1.2.3", + Annotations: annotations, + }, + }, + Version: 1, + Namespace: "default", + } + + cfg.Releases.Create(rel) + + result, err := client.Run(releaseName) + require.NoError(t, err) + + assert.Equal(t, releaseName, result.Name) + assert.Equal(t, "test-chart", result.Chart) + assert.Equal(t, annotations, result.Annotations) + assert.Equal(t, "pre-install", result.Annotations["helm.sh/hook"]) + assert.Equal(t, "5", result.Annotations["helm.sh/hook-weight"]) + assert.Equal(t, "test-value", result.Annotations["custom.annotation"]) +} + +func TestGetMetadata_Run_SpecificVersion(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetMetadata(cfg) + client.Version = 2 + + releaseName := "test-release" + deployedTime := helmtime.Now() + + rel1 := &release.Release{ + Name: releaseName, + Info: &release.Info{ + Status: release.StatusSuperseded, + LastDeployed: helmtime.Time{Time: deployedTime.Time.Add(-time.Hour)}, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "test-chart", + Version: "1.0.0", + AppVersion: "v1.0.0", + }, + }, + Version: 1, + Namespace: "default", + } + + rel2 := &release.Release{ + Name: releaseName, + Info: &release.Info{ + Status: release.StatusDeployed, + LastDeployed: deployedTime, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "test-chart", + Version: "1.1.0", + AppVersion: "v1.1.0", + }, + }, + Version: 2, + Namespace: "default", + } + + cfg.Releases.Create(rel1) + cfg.Releases.Create(rel2) + + result, err := client.Run(releaseName) + require.NoError(t, err) + + assert.Equal(t, releaseName, result.Name) + assert.Equal(t, "test-chart", result.Chart) + assert.Equal(t, "1.1.0", result.Version) + assert.Equal(t, "v1.1.0", result.AppVersion) + assert.Equal(t, 2, result.Revision) + assert.Equal(t, "deployed", result.Status) +} + +func TestGetMetadata_Run_DifferentStatuses(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetMetadata(cfg) + + testCases := []struct { + name string + status release.Status + expected string + }{ + {"deployed", release.StatusDeployed, "deployed"}, + {"failed", release.StatusFailed, "failed"}, + {"uninstalled", release.StatusUninstalled, "uninstalled"}, + {"pending-install", release.StatusPendingInstall, "pending-install"}, + {"pending-upgrade", release.StatusPendingUpgrade, "pending-upgrade"}, + {"pending-rollback", release.StatusPendingRollback, "pending-rollback"}, + {"superseded", release.StatusSuperseded, "superseded"}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + releaseName := "test-release-" + tc.name + deployedTime := helmtime.Now() + + rel := &release.Release{ + Name: releaseName, + Info: &release.Info{ + Status: tc.status, + LastDeployed: deployedTime, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "test-chart", + Version: "1.0.0", + AppVersion: "v1.0.0", + }, + }, + Version: 1, + Namespace: "default", + } + + cfg.Releases.Create(rel) + + result, err := client.Run(releaseName) + require.NoError(t, err) + + assert.Equal(t, tc.expected, result.Status) + }) + } +} + +func TestGetMetadata_Run_UnreachableKubeClient(t *testing.T) { + cfg := actionConfigFixture(t) + cfg.KubeClient = &unreachableKubeClient{ + PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, + } + + client := NewGetMetadata(cfg) + + _, err := client.Run("test-release") + assert.Error(t, err) + assert.Contains(t, err.Error(), "connection refused") +} + +func TestGetMetadata_Run_ReleaseNotFound(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetMetadata(cfg) + + _, err := client.Run("non-existent-release") + assert.Error(t, err) + assert.Contains(t, err.Error(), "not found") +} + +func TestGetMetadata_Run_EmptyAppVersion(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetMetadata(cfg) + + releaseName := "test-release" + deployedTime := helmtime.Now() + + rel := &release.Release{ + Name: releaseName, + Info: &release.Info{ + Status: release.StatusDeployed, + LastDeployed: deployedTime, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "test-chart", + Version: "1.0.0", + AppVersion: "", // Empty app version + }, + }, + Version: 1, + Namespace: "default", + } + + cfg.Releases.Create(rel) + + result, err := client.Run(releaseName) + require.NoError(t, err) + + assert.Equal(t, "", result.AppVersion) +} + +func TestMetadata_FormattedDepNames(t *testing.T) { + testCases := []struct { + name string + dependencies []*chart.Dependency + expected string + }{ + { + name: "no dependencies", + dependencies: []*chart.Dependency{}, + expected: "", + }, + { + name: "single dependency", + dependencies: []*chart.Dependency{ + {Name: "mysql"}, + }, + expected: "mysql", + }, + { + name: "multiple dependencies sorted", + dependencies: []*chart.Dependency{ + {Name: "redis"}, + {Name: "mysql"}, + {Name: "nginx"}, + }, + expected: "mysql,nginx,redis", + }, + { + name: "already sorted dependencies", + dependencies: []*chart.Dependency{ + {Name: "apache"}, + {Name: "mysql"}, + {Name: "zookeeper"}, + }, + expected: "apache,mysql,zookeeper", + }, + { + name: "duplicate names", + dependencies: []*chart.Dependency{ + {Name: "mysql"}, + {Name: "redis"}, + {Name: "mysql"}, + }, + expected: "mysql,mysql,redis", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + metadata := &Metadata{ + Dependencies: tc.dependencies, + } + + result := metadata.FormattedDepNames() + assert.Equal(t, tc.expected, result) + }) + } +} + +func TestMetadata_FormattedDepNames_WithComplexDependencies(t *testing.T) { + dependencies := []*chart.Dependency{ + { + Name: "zookeeper", + Version: "10.0.0", + Repository: "https://charts.bitnami.com/bitnami", + Condition: "zookeeper.enabled", + }, + { + Name: "apache", + Version: "9.0.0", + Repository: "https://charts.bitnami.com/bitnami", + }, + { + Name: "mysql", + Version: "8.0.25", + Repository: "https://charts.bitnami.com/bitnami", + Condition: "mysql.enabled", + }, + } + + metadata := &Metadata{ + Dependencies: dependencies, + } + + result := metadata.FormattedDepNames() + assert.Equal(t, "apache,mysql,zookeeper", result) +} + +func TestMetadata_FormattedDepNames_WithAliases(t *testing.T) { + testCases := []struct { + name string + dependencies []*chart.Dependency + expected string + }{ + { + name: "dependencies with aliases", + dependencies: []*chart.Dependency{ + {Name: "mysql", Alias: "database"}, + {Name: "redis", Alias: "cache"}, + }, + expected: "mysql,redis", + }, + { + name: "mixed dependencies with and without aliases", + dependencies: []*chart.Dependency{ + {Name: "mysql", Alias: "database"}, + {Name: "nginx"}, + {Name: "redis", Alias: "cache"}, + }, + expected: "mysql,nginx,redis", + }, + { + name: "empty alias should use name", + dependencies: []*chart.Dependency{ + {Name: "mysql", Alias: ""}, + {Name: "redis", Alias: "cache"}, + }, + expected: "mysql,redis", + }, + { + name: "sorted by name not alias", + dependencies: []*chart.Dependency{ + {Name: "zookeeper", Alias: "a-service"}, + {Name: "apache", Alias: "z-service"}, + }, + expected: "apache,zookeeper", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + metadata := &Metadata{ + Dependencies: tc.dependencies, + } + + result := metadata.FormattedDepNames() + assert.Equal(t, tc.expected, result) + }) + } +} + func TestGetMetadata_Labels(t *testing.T) { rel := releaseStub() rel.Info.Status = release.StatusDeployed diff --git a/pkg/action/get_values_test.go b/pkg/action/get_values_test.go new file mode 100644 index 000000000..ec785b5c7 --- /dev/null +++ b/pkg/action/get_values_test.go @@ -0,0 +1,218 @@ +/* +Copyright The Helm Authors. + +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 action + +import ( + "io" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + chart "helm.sh/helm/v4/pkg/chart/v2" + kubefake "helm.sh/helm/v4/pkg/kube/fake" + release "helm.sh/helm/v4/pkg/release/v1" +) + +func TestNewGetValues(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetValues(cfg) + + assert.NotNil(t, client) + assert.Equal(t, cfg, client.cfg) + assert.Equal(t, 0, client.Version) + assert.Equal(t, false, client.AllValues) +} + +func TestGetValues_Run_UserConfigOnly(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetValues(cfg) + + releaseName := "test-release" + userConfig := map[string]interface{}{ + "database": map[string]interface{}{ + "host": "localhost", + "port": 5432, + }, + "app": map[string]interface{}{ + "name": "my-app", + "replicas": 3, + }, + } + + rel := &release.Release{ + Name: releaseName, + Info: &release.Info{ + Status: release.StatusDeployed, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "test-chart", + Version: "1.0.0", + }, + Values: map[string]interface{}{ + "defaultKey": "defaultValue", + "app": map[string]interface{}{ + "name": "default-app", + "timeout": 30, + }, + }, + }, + Config: userConfig, + Version: 1, + Namespace: "default", + } + + cfg.Releases.Create(rel) + + result, err := client.Run(releaseName) + require.NoError(t, err) + assert.Equal(t, userConfig, result) +} + +func TestGetValues_Run_AllValues(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetValues(cfg) + client.AllValues = true + + releaseName := "test-release" + userConfig := map[string]interface{}{ + "database": map[string]interface{}{ + "host": "localhost", + "port": 5432, + }, + "app": map[string]interface{}{ + "name": "my-app", + }, + } + + chartDefaultValues := map[string]interface{}{ + "defaultKey": "defaultValue", + "app": map[string]interface{}{ + "name": "default-app", + "timeout": 30, + }, + } + + rel := &release.Release{ + Name: releaseName, + Info: &release.Info{ + Status: release.StatusDeployed, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "test-chart", + Version: "1.0.0", + }, + Values: chartDefaultValues, + }, + Config: userConfig, + Version: 1, + Namespace: "default", + } + + cfg.Releases.Create(rel) + + result, err := client.Run(releaseName) + require.NoError(t, err) + + assert.Equal(t, "my-app", result["app"].(map[string]interface{})["name"]) + assert.Equal(t, 30, result["app"].(map[string]interface{})["timeout"]) + assert.Equal(t, "defaultValue", result["defaultKey"]) + assert.Equal(t, "localhost", result["database"].(map[string]interface{})["host"]) + assert.Equal(t, 5432, result["database"].(map[string]interface{})["port"]) +} + +func TestGetValues_Run_EmptyValues(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetValues(cfg) + + releaseName := "test-release" + + rel := &release.Release{ + Name: releaseName, + Info: &release.Info{ + Status: release.StatusDeployed, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "test-chart", + Version: "1.0.0", + }, + }, + Config: map[string]interface{}{}, + Version: 1, + Namespace: "default", + } + + cfg.Releases.Create(rel) + + result, err := client.Run(releaseName) + require.NoError(t, err) + assert.Equal(t, map[string]interface{}{}, result) +} + +func TestGetValues_Run_UnreachableKubeClient(t *testing.T) { + cfg := actionConfigFixture(t) + cfg.KubeClient = &unreachableKubeClient{ + PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, + } + + client := NewGetValues(cfg) + + _, err := client.Run("test-release") + assert.Error(t, err) + assert.Contains(t, err.Error(), "connection refused") +} + +func TestGetValues_Run_ReleaseNotFound(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetValues(cfg) + + _, err := client.Run("non-existent-release") + assert.Error(t, err) + assert.Contains(t, err.Error(), "not found") +} + +func TestGetValues_Run_NilConfig(t *testing.T) { + cfg := actionConfigFixture(t) + client := NewGetValues(cfg) + + releaseName := "test-release" + + rel := &release.Release{ + Name: releaseName, + Info: &release.Info{ + Status: release.StatusDeployed, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "test-chart", + Version: "1.0.0", + }, + }, + Config: nil, + Version: 1, + Namespace: "default", + } + + cfg.Releases.Create(rel) + + result, err := client.Run(releaseName) + require.NoError(t, err) + assert.Nil(t, result) +} diff --git a/pkg/action/pull.go b/pkg/action/pull.go index a2f53af0d..b4779f8d2 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -114,6 +114,7 @@ func (p *Pull) Run(chartRef string) (string, error) { defer os.RemoveAll(dest) } + downloadSourceRef := chartRef if p.RepoURL != "" { chartURL, err := repo.FindChartInRepoURL( p.RepoURL, @@ -128,10 +129,10 @@ func (p *Pull) Run(chartRef string) (string, error) { if err != nil { return out.String(), err } - chartRef = chartURL + downloadSourceRef = chartURL } - saved, v, err := c.DownloadTo(chartRef, p.Version, dest) + saved, v, err := c.DownloadTo(downloadSourceRef, p.Version, dest) if err != nil { return out.String(), err } diff --git a/pkg/cmd/pull_test.go b/pkg/cmd/pull_test.go index c30c94b49..58e1862ae 100644 --- a/pkg/cmd/pull_test.go +++ b/pkg/cmd/pull_test.go @@ -147,6 +147,18 @@ func TestPullCmd(t *testing.T) { failExpect: "Failed to fetch chart version", wantError: true, }, + { + name: "Chart fetch using repo URL with untardir", + args: "signtest --version=0.1.0 --untar --untardir repo-url-test --repo " + srv.URL(), + expectFile: "./signtest", + expectDir: true, + }, + { + name: "Chart fetch using repo URL with untardir and previous pull", + args: "signtest --version=0.1.0 --untar --untardir repo-url-test --repo " + srv.URL(), + failExpect: "failed to untar", + wantError: true, + }, { name: "Fetch OCI Chart", args: fmt.Sprintf("oci://%s/u/ocitestuser/oci-dependent-chart --version 0.1.0", ociSrv.RegistryURL), diff --git a/pkg/getter/httpgetter.go b/pkg/getter/httpgetter.go index 925df201e..4cf528797 100644 --- a/pkg/getter/httpgetter.go +++ b/pkg/getter/httpgetter.go @@ -122,6 +122,9 @@ func (g *HTTPGetter) httpClient() (*http.Client, error) { g.transport = &http.Transport{ DisableCompression: true, Proxy: http.ProxyFromEnvironment, + // Being nil would cause the tls.Config default to be used + // "NewTLSConfig" modifies an empty TLS config, not the default one + TLSClientConfig: &tls.Config{}, } }) diff --git a/pkg/getter/ocigetter.go b/pkg/getter/ocigetter.go index 2a611e13a..7e8bcfcfb 100644 --- a/pkg/getter/ocigetter.go +++ b/pkg/getter/ocigetter.go @@ -17,6 +17,7 @@ package getter import ( "bytes" + "crypto/tls" "fmt" "net" "net/http" @@ -124,6 +125,9 @@ func (g *OCIGetter) newRegistryClient() (*registry.Client, error) { TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, Proxy: http.ProxyFromEnvironment, + // Being nil would cause the tls.Config default to be used + // "NewTLSConfig" modifies an empty TLS config, not the default one + TLSClientConfig: &tls.Config{}, } }) diff --git a/pkg/registry/client.go b/pkg/registry/client.go index 3ea68f181..0c9f256d3 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -268,7 +268,7 @@ func LoginOptPlainText(isPlainText bool) LoginOption { } } -func ensureTLSConfig(client *auth.Client) (*tls.Config, error) { +func ensureTLSConfig(client *auth.Client, setConfig *tls.Config) (*tls.Config, error) { var transport *http.Transport switch t := client.Client.Transport.(type) { @@ -292,7 +292,10 @@ func ensureTLSConfig(client *auth.Client) (*tls.Config, error) { return nil, fmt.Errorf("unable to access TLS client configuration, the provided HTTP Transport is not supported, given: %T", client.Client.Transport) } - if transport.TLSClientConfig == nil { + switch { + case setConfig != nil: + transport.TLSClientConfig = setConfig + case transport.TLSClientConfig == nil: transport.TLSClientConfig = &tls.Config{} } @@ -302,7 +305,7 @@ func ensureTLSConfig(client *auth.Client) (*tls.Config, error) { // LoginOptInsecure returns a function that sets the insecure setting on login func LoginOptInsecure(insecure bool) LoginOption { return func(o *loginOperation) { - tlsConfig, err := ensureTLSConfig(o.client.authorizer) + tlsConfig, err := ensureTLSConfig(o.client.authorizer, nil) if err != nil { panic(err) @@ -318,7 +321,7 @@ func LoginOptTLSClientConfig(certFile, keyFile, caFile string) LoginOption { if (certFile == "" || keyFile == "") && caFile == "" { return } - tlsConfig, err := ensureTLSConfig(o.client.authorizer) + tlsConfig, err := ensureTLSConfig(o.client.authorizer, nil) if err != nil { panic(err) } @@ -345,6 +348,17 @@ func LoginOptTLSClientConfig(certFile, keyFile, caFile string) LoginOption { } } +// LoginOptTLSClientConfigFromConfig returns a function that sets the TLS settings on login +// receiving the configuration in memory rather than from files. +func LoginOptTLSClientConfigFromConfig(conf *tls.Config) LoginOption { + return func(o *loginOperation) { + _, err := ensureTLSConfig(o.client.authorizer, conf) + if err != nil { + panic(err) + } + } +} + type ( // LogoutOption allows specifying various settings on logout LogoutOption func(*logoutOperation) diff --git a/pkg/registry/client_tls_test.go b/pkg/registry/client_tls_test.go index 156ae4816..0897858b5 100644 --- a/pkg/registry/client_tls_test.go +++ b/pkg/registry/client_tls_test.go @@ -17,6 +17,8 @@ limitations under the License. package registry import ( + "crypto/tls" + "crypto/x509" "os" "testing" @@ -52,6 +54,30 @@ func (suite *TLSRegistryClientTestSuite) Test_0_Login() { suite.Nil(err, "no error logging into registry with good credentials") } +func (suite *TLSRegistryClientTestSuite) Test_1_Login() { + err := suite.RegistryClient.Login(suite.DockerRegistryHost, + LoginOptBasicAuth("badverybad", "ohsobad"), + LoginOptTLSClientConfigFromConfig(&tls.Config{})) + suite.NotNil(err, "error logging into registry with bad credentials") + + // Create a *tls.Config from tlsCert, tlsKey, and tlsCA. + cert, err := tls.LoadX509KeyPair(tlsCert, tlsKey) + suite.Nil(err, "error loading x509 key pair") + rootCAs := x509.NewCertPool() + caCert, err := os.ReadFile(tlsCA) + suite.Nil(err, "error reading CA certificate") + rootCAs.AppendCertsFromPEM(caCert) + conf := &tls.Config{ + Certificates: []tls.Certificate{cert}, + RootCAs: rootCAs, + } + + err = suite.RegistryClient.Login(suite.DockerRegistryHost, + LoginOptBasicAuth(testUsername, testPassword), + LoginOptTLSClientConfigFromConfig(conf)) + suite.Nil(err, "no error logging into registry with good credentials") +} + func (suite *TLSRegistryClientTestSuite) Test_1_Push() { testPush(&suite.TestSuite) }