Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Factory:Rebuild
cmctl
cert-manager-1.14.5.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File cert-manager-1.14.5.obscpio of Package cmctl
07070100000000000081A4000000000000000000000001662A23E400002C5E000000000000000000000000000000000000001C00000000cert-manager-1.14.5/LICENSE Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. 07070100000001000081A4000000000000000000000001662A23E40000410A000000000000000000000000000000000000001D00000000cert-manager-1.14.5/LICENSESgithub.com/Azure/go-ntlmssp,https://github.com/Azure/go-ntlmssp/blob/754e69321358/LICENSE,MIT github.com/BurntSushi/toml,https://github.com/BurntSushi/toml/blob/v1.3.2/COPYING,MIT github.com/MakeNowJust/heredoc,https://github.com/MakeNowJust/heredoc/blob/v1.0.0/LICENSE,MIT github.com/Masterminds/goutils,https://github.com/Masterminds/goutils/blob/v1.1.1/LICENSE.txt,Apache-2.0 github.com/Masterminds/semver/v3,https://github.com/Masterminds/semver/blob/v3.2.1/LICENSE.txt,MIT github.com/Masterminds/sprig/v3,https://github.com/Masterminds/sprig/blob/v3.2.3/LICENSE.txt,MIT github.com/Masterminds/squirrel,https://github.com/Masterminds/squirrel/blob/v1.5.4/LICENSE,MIT github.com/asaskevich/govalidator,https://github.com/asaskevich/govalidator/blob/a9d515a09cc2/LICENSE,MIT github.com/beorn7/perks/quantile,https://github.com/beorn7/perks/blob/v1.0.1/LICENSE,MIT github.com/blang/semver/v4,https://github.com/blang/semver/blob/v4.0.0/v4/LICENSE,MIT github.com/cert-manager/cert-manager,https://github.com/cert-manager/cert-manager/blob/HEAD/LICENSE,Apache-2.0 github.com/cert-manager/cert-manager/cmd/ctl,https://github.com/cert-manager/cert-manager/blob/HEAD/cmd/ctl/LICENSE,Apache-2.0 github.com/cespare/xxhash/v2,https://github.com/cespare/xxhash/blob/v2.2.0/LICENSE.txt,MIT github.com/chai2010/gettext-go,https://github.com/chai2010/gettext-go/blob/v1.0.2/LICENSE,BSD-3-Clause github.com/containerd/containerd,https://github.com/containerd/containerd/blob/v1.7.11/LICENSE,Apache-2.0 github.com/containerd/log,https://github.com/containerd/log/blob/v0.1.0/LICENSE,Apache-2.0 github.com/cyphar/filepath-securejoin,https://github.com/cyphar/filepath-securejoin/blob/v0.2.4/LICENSE,BSD-3-Clause github.com/davecgh/go-spew/spew,https://github.com/davecgh/go-spew/blob/d8f796af33cc/LICENSE,ISC github.com/docker/cli/cli/config,https://github.com/docker/cli/blob/v24.0.6/LICENSE,Apache-2.0 github.com/docker/distribution,https://github.com/docker/distribution/blob/v2.8.2/LICENSE,Apache-2.0 github.com/docker/docker,https://github.com/docker/docker/blob/v24.0.7/LICENSE,Apache-2.0 github.com/docker/docker-credential-helpers,https://github.com/docker/docker-credential-helpers/blob/v0.7.0/LICENSE,MIT github.com/docker/go-connections,https://github.com/docker/go-connections/blob/v0.4.0/LICENSE,Apache-2.0 github.com/docker/go-metrics,https://github.com/docker/go-metrics/blob/v0.0.1/LICENSE,Apache-2.0 github.com/docker/go-units,https://github.com/docker/go-units/blob/v0.5.0/LICENSE,Apache-2.0 github.com/emicklei/go-restful/v3,https://github.com/emicklei/go-restful/blob/v3.11.0/LICENSE,MIT github.com/evanphx/json-patch,https://github.com/evanphx/json-patch/blob/v5.7.0/LICENSE,BSD-3-Clause github.com/evanphx/json-patch/v5,https://github.com/evanphx/json-patch/blob/v5.7.0/v5/LICENSE,BSD-3-Clause github.com/exponent-io/jsonpath,https://github.com/exponent-io/jsonpath/blob/d6023ce2651d/LICENSE,MIT github.com/fatih/camelcase,https://github.com/fatih/camelcase/blob/v1.0.0/LICENSE.md,MIT github.com/fatih/color,https://github.com/fatih/color/blob/v1.15.0/LICENSE.md,MIT github.com/felixge/httpsnoop,https://github.com/felixge/httpsnoop/blob/v1.0.4/LICENSE.txt,MIT github.com/go-asn1-ber/asn1-ber,https://github.com/go-asn1-ber/asn1-ber/blob/v1.5.5/LICENSE,MIT github.com/go-errors/errors,https://github.com/go-errors/errors/blob/v1.4.2/LICENSE.MIT,MIT github.com/go-gorp/gorp/v3,https://github.com/go-gorp/gorp/blob/v3.1.0/LICENSE,MIT github.com/go-ldap/ldap/v3,https://github.com/go-ldap/ldap/blob/v3.4.6/v3/LICENSE,MIT github.com/go-logr/logr,https://github.com/go-logr/logr/blob/v1.4.1/LICENSE,Apache-2.0 github.com/go-logr/stdr,https://github.com/go-logr/stdr/blob/v1.2.2/LICENSE,Apache-2.0 github.com/go-logr/zapr,https://github.com/go-logr/zapr/blob/v1.3.0/LICENSE,Apache-2.0 github.com/go-openapi/jsonpointer,https://github.com/go-openapi/jsonpointer/blob/v0.20.2/LICENSE,Apache-2.0 github.com/go-openapi/jsonreference,https://github.com/go-openapi/jsonreference/blob/v0.20.4/LICENSE,Apache-2.0 github.com/go-openapi/swag,https://github.com/go-openapi/swag/blob/v0.22.7/LICENSE,Apache-2.0 github.com/gobwas/glob,https://github.com/gobwas/glob/blob/v0.2.3/LICENSE,MIT github.com/gogo/protobuf,https://github.com/gogo/protobuf/blob/v1.3.2/LICENSE,BSD-3-Clause github.com/golang/protobuf,https://github.com/golang/protobuf/blob/v1.5.3/LICENSE,BSD-3-Clause github.com/google/btree,https://github.com/google/btree/blob/v1.0.1/LICENSE,Apache-2.0 github.com/google/gnostic-models,https://github.com/google/gnostic-models/blob/v0.6.8/LICENSE,Apache-2.0 github.com/google/go-cmp/cmp,https://github.com/google/go-cmp/blob/v0.6.0/LICENSE,BSD-3-Clause github.com/google/gofuzz,https://github.com/google/gofuzz/blob/v1.2.0/LICENSE,Apache-2.0 github.com/google/shlex,https://github.com/google/shlex/blob/e7afc7fbc510/COPYING,Apache-2.0 github.com/google/uuid,https://github.com/google/uuid/blob/v1.5.0/LICENSE,BSD-3-Clause github.com/gorilla/mux,https://github.com/gorilla/mux/blob/v1.8.0/LICENSE,BSD-3-Clause github.com/gorilla/websocket,https://github.com/gorilla/websocket/blob/v1.5.0/LICENSE,BSD-2-Clause github.com/gosuri/uitable,https://github.com/gosuri/uitable/blob/v0.0.4/LICENSE,MIT github.com/gosuri/uitable/util/wordwrap,https://github.com/gosuri/uitable/blob/v0.0.4/util/wordwrap/LICENSE.md,MIT github.com/gregjones/httpcache,https://github.com/gregjones/httpcache/blob/9cad4c3443a7/LICENSE.txt,MIT github.com/hashicorp/errwrap,https://github.com/hashicorp/errwrap/blob/v1.1.0/LICENSE,MPL-2.0 github.com/hashicorp/go-multierror,https://github.com/hashicorp/go-multierror/blob/v1.1.1/LICENSE,MPL-2.0 github.com/huandu/xstrings,https://github.com/huandu/xstrings/blob/v1.4.0/LICENSE,MIT github.com/imdario/mergo,https://github.com/imdario/mergo/blob/v0.3.16/LICENSE,BSD-3-Clause github.com/jmoiron/sqlx,https://github.com/jmoiron/sqlx/blob/v1.3.5/LICENSE,MIT github.com/josharian/intern,https://github.com/josharian/intern/blob/v1.0.0/license.md,MIT github.com/json-iterator/go,https://github.com/json-iterator/go/blob/v1.1.12/LICENSE,MIT github.com/klauspost/compress,https://github.com/klauspost/compress/blob/v1.16.5/LICENSE,MIT github.com/klauspost/compress,https://github.com/klauspost/compress/blob/v1.16.5/LICENSE,Apache-2.0 github.com/klauspost/compress,https://github.com/klauspost/compress/blob/v1.16.5/LICENSE,BSD-3-Clause github.com/klauspost/compress/internal/snapref,https://github.com/klauspost/compress/blob/v1.16.5/internal/snapref/LICENSE,BSD-3-Clause github.com/klauspost/compress/zstd/internal/xxhash,https://github.com/klauspost/compress/blob/v1.16.5/zstd/internal/xxhash/LICENSE.txt,MIT github.com/lann/builder,https://github.com/lann/builder/blob/47ae307949d0/LICENSE,MIT github.com/lann/ps,https://github.com/lann/ps/blob/62de8c46ede0/LICENSE,MIT github.com/lib/pq,https://github.com/lib/pq/blob/v1.10.9/LICENSE.md,MIT github.com/liggitt/tabwriter,https://github.com/liggitt/tabwriter/blob/89fcab3d43de/LICENSE,BSD-3-Clause github.com/mailru/easyjson,https://github.com/mailru/easyjson/blob/v0.7.7/LICENSE,MIT github.com/mattn/go-colorable,https://github.com/mattn/go-colorable/blob/v0.1.13/LICENSE,MIT github.com/mattn/go-isatty,https://github.com/mattn/go-isatty/blob/v0.0.17/LICENSE,MIT github.com/mattn/go-runewidth,https://github.com/mattn/go-runewidth/blob/v0.0.13/LICENSE,MIT github.com/matttproud/golang_protobuf_extensions/v2/pbutil,https://github.com/matttproud/golang_protobuf_extensions/blob/v2.0.0/LICENSE,Apache-2.0 github.com/mitchellh/copystructure,https://github.com/mitchellh/copystructure/blob/v1.2.0/LICENSE,MIT github.com/mitchellh/go-wordwrap,https://github.com/mitchellh/go-wordwrap/blob/v1.0.1/LICENSE.md,MIT github.com/mitchellh/reflectwalk,https://github.com/mitchellh/reflectwalk/blob/v1.0.2/LICENSE,MIT github.com/moby/locker,https://github.com/moby/locker/blob/v1.0.1/LICENSE,Apache-2.0 github.com/moby/spdystream,https://github.com/moby/spdystream/blob/v0.2.0/LICENSE,Apache-2.0 github.com/moby/term,https://github.com/moby/term/blob/v0.5.0/LICENSE,Apache-2.0 github.com/modern-go/concurrent,https://github.com/modern-go/concurrent/blob/bacd9c7ef1dd/LICENSE,Apache-2.0 github.com/modern-go/reflect2,https://github.com/modern-go/reflect2/blob/v1.0.2/LICENSE,Apache-2.0 github.com/monochromegane/go-gitignore,https://github.com/monochromegane/go-gitignore/blob/205db1a8cc00/LICENSE,MIT github.com/morikuni/aec,https://github.com/morikuni/aec/blob/v1.0.0/LICENSE,MIT github.com/munnerz/goautoneg,https://github.com/munnerz/goautoneg/blob/a7dc8b61c822/LICENSE,BSD-3-Clause github.com/mxk/go-flowrate/flowrate,https://github.com/mxk/go-flowrate/blob/cca7078d478f/LICENSE,BSD-3-Clause github.com/opencontainers/go-digest,https://github.com/opencontainers/go-digest/blob/v1.0.0/LICENSE,Apache-2.0 github.com/opencontainers/image-spec/specs-go,https://github.com/opencontainers/image-spec/blob/v1.1.0-rc5/LICENSE,Apache-2.0 github.com/peterbourgon/diskv,https://github.com/peterbourgon/diskv/blob/v2.0.1/LICENSE,MIT github.com/pkg/errors,https://github.com/pkg/errors/blob/v0.9.1/LICENSE,BSD-2-Clause github.com/prometheus/client_golang/prometheus,https://github.com/prometheus/client_golang/blob/v1.18.0/LICENSE,Apache-2.0 github.com/prometheus/client_model/go,https://github.com/prometheus/client_model/blob/v0.5.0/LICENSE,Apache-2.0 github.com/prometheus/common,https://github.com/prometheus/common/blob/v0.45.0/LICENSE,Apache-2.0 github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg,https://github.com/prometheus/common/blob/v0.45.0/internal/bitbucket.org/ww/goautoneg/README.txt,BSD-3-Clause github.com/prometheus/procfs,https://github.com/prometheus/procfs/blob/v0.12.0/LICENSE,Apache-2.0 github.com/rivo/uniseg,https://github.com/rivo/uniseg/blob/v0.2.0/LICENSE.txt,MIT github.com/rubenv/sql-migrate,https://github.com/rubenv/sql-migrate/blob/v1.5.2/LICENSE,MIT github.com/rubenv/sql-migrate/sqlparse,https://github.com/rubenv/sql-migrate/blob/v1.5.2/sqlparse/LICENSE,MIT github.com/russross/blackfriday/v2,https://github.com/russross/blackfriday/blob/v2.1.0/LICENSE.txt,BSD-2-Clause github.com/shopspring/decimal,https://github.com/shopspring/decimal/blob/v1.3.1/LICENSE,MIT github.com/sirupsen/logrus,https://github.com/sirupsen/logrus/blob/v1.9.3/LICENSE,MIT github.com/spf13/cast,https://github.com/spf13/cast/blob/v1.5.0/LICENSE,MIT github.com/spf13/cobra,https://github.com/spf13/cobra/blob/v1.8.0/LICENSE.txt,Apache-2.0 github.com/spf13/pflag,https://github.com/spf13/pflag/blob/v1.0.5/LICENSE,BSD-3-Clause github.com/xeipuuv/gojsonpointer,https://github.com/xeipuuv/gojsonpointer/blob/02993c407bfb/LICENSE-APACHE-2.0.txt,Apache-2.0 github.com/xeipuuv/gojsonreference,https://github.com/xeipuuv/gojsonreference/blob/bd5ef7bd5415/LICENSE-APACHE-2.0.txt,Apache-2.0 github.com/xeipuuv/gojsonschema,https://github.com/xeipuuv/gojsonschema/blob/v1.2.0/LICENSE-APACHE-2.0.txt,Apache-2.0 github.com/xlab/treeprint,https://github.com/xlab/treeprint/blob/v1.2.0/LICENSE,MIT go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp,https://github.com/open-telemetry/opentelemetry-go-contrib/blob/instrumentation/net/http/otelhttp/v0.46.1/instrumentation/net/http/otelhttp/LICENSE,Apache-2.0 go.opentelemetry.io/otel,https://github.com/open-telemetry/opentelemetry-go/blob/v1.21.0/LICENSE,Apache-2.0 go.opentelemetry.io/otel/metric,https://github.com/open-telemetry/opentelemetry-go/blob/metric/v1.21.0/metric/LICENSE,Apache-2.0 go.opentelemetry.io/otel/trace,https://github.com/open-telemetry/opentelemetry-go/blob/trace/v1.21.0/trace/LICENSE,Apache-2.0 go.starlark.net,https://github.com/google/starlark-go/blob/a134d8f9ddca/LICENSE,BSD-3-Clause go.uber.org/multierr,https://github.com/uber-go/multierr/blob/v1.11.0/LICENSE.txt,MIT go.uber.org/zap,https://github.com/uber-go/zap/blob/v1.26.0/LICENSE.txt,MIT golang.org/x/crypto,https://cs.opensource.google/go/x/crypto/+/v0.22.0:LICENSE,BSD-3-Clause golang.org/x/net,https://cs.opensource.google/go/x/net/+/v0.24.0:LICENSE,BSD-3-Clause golang.org/x/oauth2,https://cs.opensource.google/go/x/oauth2/+/v0.15.0:LICENSE,BSD-3-Clause golang.org/x/sync,https://cs.opensource.google/go/x/sync/+/v0.5.0:LICENSE,BSD-3-Clause golang.org/x/sys,https://cs.opensource.google/go/x/sys/+/v0.19.0:LICENSE,BSD-3-Clause golang.org/x/term,https://cs.opensource.google/go/x/term/+/v0.19.0:LICENSE,BSD-3-Clause golang.org/x/text,https://cs.opensource.google/go/x/text/+/v0.14.0:LICENSE,BSD-3-Clause golang.org/x/time/rate,https://cs.opensource.google/go/x/time/+/v0.5.0:LICENSE,BSD-3-Clause google.golang.org/genproto/googleapis/rpc/status,https://github.com/googleapis/go-genproto/blob/50ed04b92917/googleapis/rpc/LICENSE,Apache-2.0 google.golang.org/grpc,https://github.com/grpc/grpc-go/blob/v1.60.1/LICENSE,Apache-2.0 google.golang.org/protobuf,https://github.com/protocolbuffers/protobuf-go/blob/v1.33.0/LICENSE,BSD-3-Clause gopkg.in/inf.v0,https://github.com/go-inf/inf/blob/v0.9.1/LICENSE,BSD-3-Clause gopkg.in/yaml.v2,https://github.com/go-yaml/yaml/blob/v2.4.0/LICENSE,Apache-2.0 gopkg.in/yaml.v3,https://github.com/go-yaml/yaml/blob/v3.0.1/LICENSE,MIT helm.sh/helm/v3,https://github.com/helm/helm/blob/v3.14.2/LICENSE,Apache-2.0 k8s.io/api,https://github.com/kubernetes/api/blob/v0.29.0/LICENSE,Apache-2.0 k8s.io/apiextensions-apiserver/pkg/apis/apiextensions,https://github.com/kubernetes/apiextensions-apiserver/blob/v0.29.0/LICENSE,Apache-2.0 k8s.io/apimachinery/pkg,https://github.com/kubernetes/apimachinery/blob/v0.29.0/LICENSE,Apache-2.0 k8s.io/apimachinery/third_party/forked/golang,https://github.com/kubernetes/apimachinery/blob/v0.29.0/third_party/forked/golang/LICENSE,BSD-3-Clause k8s.io/apiserver/pkg/endpoints/deprecation,https://github.com/kubernetes/apiserver/blob/v0.29.0/LICENSE,Apache-2.0 k8s.io/cli-runtime/pkg,https://github.com/kubernetes/cli-runtime/blob/v0.29.0/LICENSE,Apache-2.0 k8s.io/client-go,https://github.com/kubernetes/client-go/blob/v0.29.0/LICENSE,Apache-2.0 k8s.io/client-go/third_party/forked/golang/template,https://github.com/kubernetes/client-go/blob/v0.29.0/third_party/forked/golang/LICENSE,BSD-3-Clause k8s.io/component-base,https://github.com/kubernetes/component-base/blob/v0.29.0/LICENSE,Apache-2.0 k8s.io/klog/v2,https://github.com/kubernetes/klog/blob/v2.110.1/LICENSE,Apache-2.0 k8s.io/kube-openapi/pkg,https://github.com/kubernetes/kube-openapi/blob/eec4567ac022/LICENSE,Apache-2.0 k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json,https://github.com/kubernetes/kube-openapi/blob/eec4567ac022/pkg/internal/third_party/go-json-experiment/json/LICENSE,BSD-3-Clause k8s.io/kube-openapi/pkg/validation/spec,https://github.com/kubernetes/kube-openapi/blob/eec4567ac022/pkg/validation/spec/LICENSE,Apache-2.0 k8s.io/kubectl/pkg,https://github.com/kubernetes/kubectl/blob/v0.29.0/LICENSE,Apache-2.0 k8s.io/utils,https://github.com/kubernetes/utils/blob/e7106e64919e/LICENSE,Apache-2.0 k8s.io/utils/internal/third_party/forked/golang/net,https://github.com/kubernetes/utils/blob/e7106e64919e/internal/third_party/forked/golang/LICENSE,BSD-3-Clause oras.land/oras-go/pkg,https://github.com/oras-project/oras-go/blob/v1.2.4/LICENSE,Apache-2.0 sigs.k8s.io/controller-runtime/pkg,https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/LICENSE,Apache-2.0 sigs.k8s.io/gateway-api/apis/v1,https://github.com/kubernetes-sigs/gateway-api/blob/v1.0.0/LICENSE,Apache-2.0 sigs.k8s.io/json,https://github.com/kubernetes-sigs/json/blob/bc3834ca7abd/LICENSE,Apache-2.0 sigs.k8s.io/json,https://github.com/kubernetes-sigs/json/blob/bc3834ca7abd/LICENSE,BSD-3-Clause sigs.k8s.io/kustomize/api,https://github.com/kubernetes-sigs/kustomize/blob/6ce0bf390ce3/api/LICENSE,Apache-2.0 sigs.k8s.io/kustomize/kyaml,https://github.com/kubernetes-sigs/kustomize/blob/6ce0bf390ce3/kyaml/LICENSE,Apache-2.0 sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml,https://github.com/kubernetes-sigs/kustomize/blob/6ce0bf390ce3/kyaml/internal/forked/github.com/go-yaml/yaml/LICENSE,MIT sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util,https://github.com/kubernetes-sigs/kustomize/blob/6ce0bf390ce3/kyaml/internal/forked/github.com/qri-io/starlib/util/LICENSE,MIT sigs.k8s.io/structured-merge-diff/v4,https://github.com/kubernetes-sigs/structured-merge-diff/blob/v4.4.1/LICENSE,Apache-2.0 sigs.k8s.io/yaml,https://github.com/kubernetes-sigs/yaml/blob/v1.4.0/LICENSE,MIT sigs.k8s.io/yaml,https://github.com/kubernetes-sigs/yaml/blob/v1.4.0/LICENSE,Apache-2.0 sigs.k8s.io/yaml,https://github.com/kubernetes-sigs/yaml/blob/v1.4.0/LICENSE,BSD-3-Clause sigs.k8s.io/yaml/goyaml.v2,https://github.com/kubernetes-sigs/yaml/blob/v1.4.0/goyaml.v2/LICENSE,Apache-2.0 07070100000002000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000001800000000cert-manager-1.14.5/cmd07070100000003000081A4000000000000000000000001662A23E400000D2F000000000000000000000000000000000000001F00000000cert-manager-1.14.5/cmd/cmd.go/* Copyright 2020 The cert-manager 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 cmd import ( "context" "fmt" "io" "github.com/spf13/cobra" "github.com/spf13/pflag" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/component-base/logs" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build/commands" logf "github.com/cert-manager/cert-manager/pkg/logs" ) func NewCertManagerCtlCommand(ctx context.Context, in io.Reader, out, err io.Writer) *cobra.Command { ctx = logf.NewContext(ctx, logf.Log) logOptions := logs.NewOptions() cmds := &cobra.Command{ Use: build.Name(), Short: "cert-manager CLI tool to manage and configure cert-manager resources", Long: build.WithTemplate(` {{.BuildName}} is a CLI tool manage and configure cert-manager resources for Kubernetes`), CompletionOptions: cobra.CompletionOptions{ DisableDefaultCmd: true, }, PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return logf.ValidateAndApply(logOptions) }, SilenceErrors: true, // Errors are already logged when calling cmd.Execute() } cmds.SetUsageTemplate(usageTemplate()) { var logFlags pflag.FlagSet logf.AddFlagsNonDeprecated(logOptions, &logFlags) logFlags.VisitAll(func(f *pflag.Flag) { switch f.Name { case "v": // "cmctl check api" already had a "v" flag that did not require any value, for // backwards compatibility we allow the "v" logging flag to be set without a value // and default to "2" (which will result in the same behaviour as before). f.NoOptDefVal = "2" cmds.PersistentFlags().AddFlag(f) default: cmds.PersistentFlags().AddFlag(f) } }) } ioStreams := genericclioptions.IOStreams{In: in, Out: out, ErrOut: err} for _, registerCmd := range commands.Commands() { cmds.AddCommand(registerCmd(ctx, ioStreams)) } return cmds } func usageTemplate() string { return fmt.Sprintf(`Usage:{{if .Runnable}} %s {{end}}{{if .HasAvailableSubCommands}} %s [command]{{end}}{{if gt (len .Aliases) 0}} Aliases: {{.NameAndAliases}}{{end}}{{if .HasExample}} Examples: {{.Example}}{{end}}{{if .HasAvailableSubCommands}} Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} Flags: {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} Global Flags: {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} Use "%s [command] --help" for more information about a command.{{end}} `, build.Name(), build.Name(), build.Name()) } 07070100000004000081A4000000000000000000000001662A23E4000021CD000000000000000000000000000000000000001B00000000cert-manager-1.14.5/go.modmodule github.com/cert-manager/cert-manager/cmd/ctl go 1.21 // Do not remove this comment: // please place any replace statements here at the top for visibility and add a // comment to it as to when it can be removed // Note on cert-manager versioning: // Because cmctl and the core cert-manager module live in the same repository, but cmctl depends on a specific // cert-manager version (rather than using replace statements or a go.work file), there's a need to be able // to update cert-manager, then update cmctl to point to that new version. // This means that it's not always possible to use a "nice" tagged version of cert-manager and the version // might look messy. // To update the cert-manager version, use "go get github.com/cert-manager/cert-manager@X", where X could be a commit SHA // or a branch name (master). require ( github.com/cert-manager/cert-manager v1.14.4 github.com/go-logr/logr v1.4.1 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.4 golang.org/x/crypto v0.22.0 helm.sh/helm/v3 v3.14.2 k8s.io/api v0.29.0 k8s.io/apiextensions-apiserver v0.29.0 k8s.io/apimachinery v0.29.0 k8s.io/cli-runtime v0.29.0 k8s.io/client-go v0.29.0 k8s.io/component-base v0.29.0 k8s.io/kubectl v0.29.0 k8s.io/utils v0.0.0-20240102154912-e7106e64919e sigs.k8s.io/controller-runtime v0.16.3 sigs.k8s.io/yaml v1.4.0 ) require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/BurntSushi/toml v1.3.2 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Masterminds/squirrel v1.5.4 // indirect github.com/Microsoft/hcsshim v0.11.4 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect github.com/containerd/containerd v1.7.11 // indirect github.com/containerd/log v0.1.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/docker/cli v24.0.6+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v24.0.7+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v5.7.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.7.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/fatih/camelcase v1.0.0 // indirect github.com/fatih/color v1.15.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-ldap/ldap/v3 v3.4.6 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.4 // indirect github.com/go-openapi/swag v0.22.7 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.5.0 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmoiron/sqlx v1.3.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.16.5 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/locker v1.0.1 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.18.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rubenv/sql-migrate v1.5.2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sergi/go-diff v1.3.1 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect go.opentelemetry.io/otel v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/otel/trace v1.21.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/net v0.24.0 // indirect golang.org/x/oauth2 v0.15.0 // indirect golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.19.0 // indirect golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect google.golang.org/grpc v1.60.1 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiserver v0.29.0 // indirect k8s.io/klog/v2 v2.110.1 // indirect k8s.io/kube-openapi v0.0.0-20240103051144-eec4567ac022 // indirect oras.land/oras-go v1.2.4 // indirect sigs.k8s.io/gateway-api v1.0.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) 07070100000005000081A4000000000000000000000001662A23E40000E6B1000000000000000000000000000000000000001B00000000cert-manager-1.14.5/go.sumcloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cert-manager/cert-manager v1.14.4 h1:DLXIZHx3jhkViYfobXo+N7/od/oj4YgG6AJw4ORJnYs= github.com/cert-manager/cert-manager v1.14.4/go.mod h1:d+CBeRu5MbpHTfXkkiiamUhnfdvhbThoOPwilU4UM98= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/containerd v1.7.11 h1:lfGKw3eU35sjV0aG2eYZTiwFEY1pCzxdzicHP3SZILw= github.com/containerd/containerd v1.7.11/go.mod h1:5UluHxHTX2rdvYuZ5OJTC5m/KJNs0Zs9wVoJm9zf5ZE= github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI= github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc= github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= github.com/go-openapi/swag v0.22.7 h1:JWrc1uc/P9cSomxfnsFSVWoE1FW6bNbrVPmpQYpCcR8= github.com/go-openapi/swag v0.22.7/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs= github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY= github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY= github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 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-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY= github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= 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.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-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 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/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0= github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= 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= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 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/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4= golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 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.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 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= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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-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-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.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.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.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 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.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= 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= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 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 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 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.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= helm.sh/helm/v3 v3.14.2 h1:V71fv+NGZv0icBlr+in1MJXuUIHCiPG1hW9gEBISTIA= helm.sh/helm/v3 v3.14.2/go.mod h1:2itvvDv2WSZXTllknfQo6j7u3VVgMAvm8POCDgYH424= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0= k8s.io/apiextensions-apiserver v0.29.0/go.mod h1:TKmpy3bTS0mr9pylH0nOt/QzQRrW7/h7yLdRForMZwc= k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= k8s.io/apiserver v0.29.0 h1:Y1xEMjJkP+BIi0GSEv1BBrf1jLU9UPfAnnGGbbDdp7o= k8s.io/apiserver v0.29.0/go.mod h1:31n78PsRKPmfpee7/l9NYEv67u6hOL6AfcE761HapDM= k8s.io/cli-runtime v0.29.0 h1:q2kC3cex4rOBLfPOnMSzV2BIrrQlx97gxHJs21KxKS4= k8s.io/cli-runtime v0.29.0/go.mod h1:VKudXp3X7wR45L+nER85YUzOQIru28HQpXr0mTdeCrk= k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= k8s.io/component-base v0.29.0 h1:T7rjd5wvLnPBV1vC4zWd/iWRbV8Mdxs+nGaoaFzGw3s= k8s.io/component-base v0.29.0/go.mod h1:sADonFTQ9Zc9yFLghpDpmNXEdHyQmFIGbiuZbqAXQ1M= k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= k8s.io/kube-openapi v0.0.0-20240103051144-eec4567ac022 h1:avRdiaB03v88Mfvum2S3BBwkNuTlmuar4LlfO9Hajko= k8s.io/kube-openapi v0.0.0-20240103051144-eec4567ac022/go.mod h1:sIV51WBTkZrlGOJMCDZDA1IaPBUDTulPpD4y7oe038k= k8s.io/kubectl v0.29.0 h1:Oqi48gXjikDhrBF67AYuZRTcJV4lg2l42GmvsP7FmYI= k8s.io/kubectl v0.29.0/go.mod h1:0jMjGWIcMIQzmUaMgAzhSELv5WtHo2a8pq67DtviAJs= k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY= oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324= sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4= sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= sigs.k8s.io/gateway-api v1.0.0 h1:iPTStSv41+d9p0xFydll6d7f7MOBGuqXM6p2/zVYMAs= sigs.k8s.io/gateway-api v1.0.0/go.mod h1:4cUgr0Lnp5FZ0Cdq8FdRwCvpiWws7LVhLHGIudLlf4c= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= 07070100000006000081A4000000000000000000000001662A23E400000830000000000000000000000000000000000000001C00000000cert-manager-1.14.5/main.go/* Copyright 2020 The cert-manager 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 main import ( "context" "fmt" "os" "runtime" "strings" cmdutil "k8s.io/kubectl/pkg/cmd/util" ctlcmd "github.com/cert-manager/cert-manager/cmd/ctl/cmd" "github.com/cert-manager/cert-manager/internal/cmd/util" logf "github.com/cert-manager/cert-manager/pkg/logs" ) func main() { stopCh, exit := util.SetupExitHandler(util.AlwaysErrCode) defer exit() // This function might call os.Exit, so defer last logf.InitLogs() defer logf.FlushLogs() // In cmctl, we are using cmdutil.CheckErr, a kubectl utility function that creates human readable // error messages from errors. By default, this function will call os.Exit(1) if it receives an error. // Instead, we want to do a soft exit, and use SetExitCode to set the correct exit code. // Additionally, we make sure to output the final error message to stdout, as we do not want this // message to be mixed with other log outputs from the execution of the command. // To do this, we need to set a custom error handler. cmdutil.BehaviorOnFatal(func(msg string, code int) { if len(msg) > 0 { // add newline if needed if !strings.HasSuffix(msg, "\n") { msg += "\n" } fmt.Fprint(os.Stdout, msg) } util.SetExitCodeValue(code) runtime.Goexit() // Do soft exit (handle all defers, that should set correct exit code) }) ctx := util.ContextWithStopCh(context.Background(), stopCh) cmd := ctlcmd.NewCertManagerCtlCommand(ctx, os.Stdin, os.Stdout, os.Stderr) if err := cmd.Execute(); err != nil { cmdutil.CheckErr(err) } } 07070100000007000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000001800000000cert-manager-1.14.5/pkg07070100000008000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002000000000cert-manager-1.14.5/pkg/approve07070100000009000081A4000000000000000000000001662A23E400001184000000000000000000000000000000000000002B00000000cert-manager-1.14.5/pkg/approve/approve.go/* Copyright 2021 The cert-manager 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 approve import ( "context" "errors" "fmt" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/cli-runtime/pkg/genericclioptions" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/factory" apiutil "github.com/cert-manager/cert-manager/pkg/api/util" cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" ) var ( example = templates.Examples(i18n.T(build.WithTemplate(` # Approve a CertificateRequest with the name 'my-cr' {{.BuildName}} approve my-cr # Approve a CertificateRequest in namespace default {{.BuildName}} approve my-cr --namespace default # Approve a CertificateRequest giving a custom reason and message {{.BuildName}} approve my-cr --reason "ManualApproval" --reason "Approved by PKI department" `))) ) // Options is a struct to support create certificaterequest command type Options struct { // Reason is the string that will be set on the Reason field of the Approved // condition. Reason string // Message is the string that will be set on the Message field of the // Approved condition. Message string genericclioptions.IOStreams *factory.Factory } // newOptions returns initialized Options func newOptions(ioStreams genericclioptions.IOStreams) *Options { return &Options{ IOStreams: ioStreams, } } func NewCmdApprove(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { o := newOptions(ioStreams) cmd := &cobra.Command{ Use: "approve", Short: "Approve a CertificateRequest", Long: `Mark a CertificateRequest as Approved, so it may be signed by a configured Issuer.`, Example: example, ValidArgsFunction: factory.ValidArgsListCertificateRequests(ctx, &o.Factory), Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Validate(args)) cmdutil.CheckErr(o.Run(ctx, args)) }, } cmd.Flags().StringVar(&o.Reason, "reason", "KubectlCertManager", "The reason to give as to what approved this CertificateRequest.") cmd.Flags().StringVar(&o.Message, "message", fmt.Sprintf("manually approved by %q", build.Name()), "The message to give as to why this CertificateRequest was approved.") o.Factory = factory.New(ctx, cmd) return cmd } // Validate validates the provided options func (o *Options) Validate(args []string) error { if len(args) < 1 { return errors.New("the name of the CertificateRequest to approve has to be provided as an argument") } if len(args) > 1 { return errors.New("only one argument can be passed: the name of the CertificateRequest") } if len(o.Reason) == 0 { return errors.New("a reason must be given as to who approved this CertificateRequest") } if len(o.Message) == 0 { return errors.New("a message must be given as to why this CertificateRequest is approved") } return nil } // Run executes approve command func (o *Options) Run(ctx context.Context, args []string) error { cr, err := o.CMClient.CertmanagerV1().CertificateRequests(o.Namespace).Get(ctx, args[0], metav1.GetOptions{}) if err != nil { return err } if apiutil.CertificateRequestIsApproved(cr) { return errors.New("CertificateRequest is already approved") } if apiutil.CertificateRequestIsDenied(cr) { return errors.New("CertificateRequest is already denied") } apiutil.SetCertificateRequestCondition(cr, cmapi.CertificateRequestConditionApproved, cmmeta.ConditionTrue, o.Reason, o.Message) _, err = o.CMClient.CertmanagerV1().CertificateRequests(o.Namespace).UpdateStatus(ctx, cr, metav1.UpdateOptions{}) if err != nil { return err } fmt.Fprintf(o.Out, "Approved CertificateRequest '%s/%s'\n", cr.Namespace, cr.Name) return nil } 0707010000000A000081A4000000000000000000000001662A23E40000092D000000000000000000000000000000000000003000000000cert-manager-1.14.5/pkg/approve/approve_test.go/* Copyright 2021 The cert-manager 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 approve import ( "testing" ) func TestValidate(t *testing.T) { tests := map[string]struct { args []string reason, message string expErr bool expErrMsg string }{ "CR name not passed as arg throws error": { args: []string{}, reason: "", message: "", expErr: true, expErrMsg: "the name of the CertificateRequest to approve has to be provided as an argument", }, "multiple CR names passed as arg throws error": { args: []string{"cr-1", "cr-1"}, reason: "", message: "", expErr: true, expErrMsg: "only one argument can be passed: the name of the CertificateRequest", }, "empty reason given should throw error": { args: []string{"cr-1"}, reason: "", message: "", expErr: true, expErrMsg: "a reason must be given as to who approved this CertificateRequest", }, "empty message given should throw error": { args: []string{"cr-1"}, reason: "foo", message: "", expErr: true, expErrMsg: "a message must be given as to why this CertificateRequest is approved", }, "all fields populated should not error": { args: []string{"cr-1"}, reason: "foo", message: "bar", expErr: false, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { opts := &Options{ Reason: test.reason, Message: test.message, } // Validating args and flags err := opts.Validate(test.args) if (err != nil) != test.expErr { t.Errorf("unexpected error, exp=%t got=%v", test.expErr, err) } if err != nil && err.Error() != test.expErrMsg { t.Errorf("got unexpected error when validating args and flags, expected: %v; actual: %v", test.expErrMsg, err) } }) } } 0707010000000B000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000001E00000000cert-manager-1.14.5/pkg/build0707010000000C000081A4000000000000000000000001662A23E400000504000000000000000000000000000000000000002700000000cert-manager-1.14.5/pkg/build/build.go/* Copyright 2020 The cert-manager 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 build import ( "bytes" "text/template" ) // name is the build time configurable name of the build (name of the target // binary name). var name = "cmctl" // Name returns the build name. func Name() string { return name } // WithTemplate returns a string that has the build name templated out with the // configured build name. Build name templates on '{{ .BuildName }}' variable. func WithTemplate(str string) string { tmpl := template.Must(template.New("build-name").Parse(str)) var buf bytes.Buffer if err := tmpl.Execute(&buf, struct{ BuildName string }{name}); err != nil { // We panic here as it should never be possible that this template fails. panic(err) } return buf.String() } 0707010000000D000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002700000000cert-manager-1.14.5/pkg/build/commands0707010000000E000081A4000000000000000000000001662A23E4000008FB000000000000000000000000000000000000003300000000cert-manager-1.14.5/pkg/build/commands/commands.go/* Copyright 2020 The cert-manager 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 commands import ( "context" "strings" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/approve" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/check" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/completion" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/convert" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/create" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/deny" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/experimental" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/inspect" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/renew" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/status" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/upgrade" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/version" ) // registerCompletion gates whether the completion command is registered. // Specifically useful when building the CLI as a kubectl plugin which does not // support completion. var registerCompletion = "false" type RegisterCommandFunc func(context.Context, genericclioptions.IOStreams) *cobra.Command // Commands returns the cobra Commands that should be registered for the CLI // build. func Commands() []RegisterCommandFunc { cmds := []RegisterCommandFunc{ version.NewCmdVersion, convert.NewCmdConvert, create.NewCmdCreate, renew.NewCmdRenew, status.NewCmdStatus, inspect.NewCmdInspect, approve.NewCmdApprove, deny.NewCmdDeny, check.NewCmdCheck, upgrade.NewCmdUpgrade, // Experimental features experimental.NewCmdExperimental, } if strings.ToLower(registerCompletion) == "true" { cmds = append(cmds, completion.NewCmdCompletion) } return cmds } 0707010000000F000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000001E00000000cert-manager-1.14.5/pkg/check07070100000010000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002200000000cert-manager-1.14.5/pkg/check/api07070100000011000081A4000000000000000000000001662A23E400001071000000000000000000000000000000000000002900000000cert-manager-1.14.5/pkg/check/api/api.go/* Copyright 2021 The cert-manager 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 api import ( "context" "errors" "fmt" "time" "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/cli-runtime/pkg/genericclioptions" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/factory" cmcmdutil "github.com/cert-manager/cert-manager/internal/cmd/util" logf "github.com/cert-manager/cert-manager/pkg/logs" "github.com/cert-manager/cert-manager/pkg/util/cmapichecker" ) // Options is a struct to support check api command type Options struct { // APIChecker is used to check that the cert-manager CRDs have been installed on the K8S // API server and that the cert-manager webhooks are all working APIChecker cmapichecker.Interface // Time before timeout when waiting Wait time.Duration // Time between checks when waiting Interval time.Duration genericclioptions.IOStreams *factory.Factory } var checkApiDesc = templates.LongDesc(i18n.T(` This check attempts to perform a dry-run create of a cert-manager *v1alpha2* Certificate resource in order to verify that CRDs are installed and all the required webhooks are reachable by the K8S API server. We use v1alpha2 API to ensure that the API server has also connected to the cert-manager conversion webhook.`)) // NewOptions returns initialized Options func NewOptions(ioStreams genericclioptions.IOStreams) *Options { return &Options{ IOStreams: ioStreams, } } // Complete takes the command arguments and factory and infers any remaining options. func (o *Options) Complete() error { var err error o.APIChecker, err = cmapichecker.New( o.RESTConfig, runtime.NewScheme(), o.Namespace, ) if err != nil { return err } return nil } // NewCmdCheckApi returns a cobra command for checking creating cert-manager resources against the K8S API server func NewCmdCheckApi(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { o := NewOptions(ioStreams) cmd := &cobra.Command{ Use: "api", Short: "Check if the cert-manager API is ready", Long: checkApiDesc, Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Complete()) cmdutil.CheckErr(o.Run(ctx)) }, } cmd.Flags().DurationVar(&o.Wait, "wait", 0, "Wait until the cert-manager API is ready (default 0s = poll once)") cmd.Flags().DurationVar(&o.Interval, "interval", 5*time.Second, "Time between checks when waiting, must include unit, e.g. 1m or 10m") o.Factory = factory.New(ctx, cmd) return cmd } // Run executes check api command func (o *Options) Run(ctx context.Context) error { log := logf.FromContext(ctx, "checkAPI") start := time.Now() var lastError error pollErr := wait.PollUntilContextCancel(ctx, o.Interval, true, func(ctx context.Context) (bool, error) { if err := o.APIChecker.Check(ctx); err != nil { simpleError := cmapichecker.TranslateToSimpleError(err) if simpleError != nil { log.V(2).Info("Not ready", "err", simpleError, "underlyingError", err) lastError = simpleError } else { log.V(2).Info("Not ready", "err", err) lastError = err } if time.Since(start) > o.Wait { return false, context.DeadlineExceeded } return false, nil } return true, nil }) if pollErr != nil { if errors.Is(pollErr, context.DeadlineExceeded) && o.Wait > 0 { log.V(2).Info("Timed out", "after", o.Wait, "err", pollErr) cmcmdutil.SetExitCode(pollErr) } else { cmcmdutil.SetExitCode(lastError) } return lastError } fmt.Fprintln(o.Out, "The cert-manager API is ready") return nil } 07070100000012000081A4000000000000000000000001662A23E4000004F7000000000000000000000000000000000000002700000000cert-manager-1.14.5/pkg/check/check.go/* Copyright 2021 The cert-manager 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 check import ( "context" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/check/api" ) // NewCmdCheck returns a cobra command for checking cert-manager components. func NewCmdCheck(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { cmds := NewCmdCreateBare() cmds.AddCommand(api.NewCmdCheckApi(ctx, ioStreams)) return cmds } // NewCmdCreateBare returns bare cobra command for checking cert-manager components. func NewCmdCreateBare() *cobra.Command { return &cobra.Command{ Use: "check", Short: "Check cert-manager components", Long: `Check cert-manager components`, } } 07070100000013000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002300000000cert-manager-1.14.5/pkg/completion07070100000014000081A4000000000000000000000001662A23E4000005A6000000000000000000000000000000000000002B00000000cert-manager-1.14.5/pkg/completion/bash.go/* Copyright 2021 The cert-manager 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 completion import ( "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/kubectl/pkg/cmd/util" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" ) func newCmdCompletionBash(ioStreams genericclioptions.IOStreams) *cobra.Command { return &cobra.Command{ Use: "bash", Short: "Generate cert-manager CLI scripts for a Bash shell", Long: build.WithTemplate(`To load completions: Bash: $ source <({{.BuildName}} completion bash) # To load completions for each session, execute once: # Linux: $ {{.BuildName}} completion bash > /etc/bash_completion.d/{{.BuildName}} # macOS: $ {{.BuildName}} completion bash > /usr/local/etc/bash_completion.d/{{.BuildName}} `), DisableFlagsInUseLine: true, Run: func(cmd *cobra.Command, args []string) { util.CheckErr(cmd.Root().GenBashCompletion(ioStreams.Out)) }, } } 07070100000015000081A4000000000000000000000001662A23E4000004D8000000000000000000000000000000000000003100000000cert-manager-1.14.5/pkg/completion/completion.go/* Copyright 2021 The cert-manager 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 completion import ( "context" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" ) func NewCmdCompletion(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { cmds := &cobra.Command{ Use: "completion", Short: "Generate completion scripts for the cert-manager CLI", Long: "Generate completion for the cert-manager CLI so arguments and flags can be suggested and auto-completed", } cmds.AddCommand(newCmdCompletionBash(ioStreams)) cmds.AddCommand(newCmdCompletionZSH(ioStreams)) cmds.AddCommand(newCmdCompletionFish(ioStreams)) cmds.AddCommand(newCmdCompletionPowerShell(ioStreams)) return cmds } 07070100000016000081A4000000000000000000000001662A23E400000543000000000000000000000000000000000000002B00000000cert-manager-1.14.5/pkg/completion/fish.go/* Copyright 2021 The cert-manager 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 completion import ( "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/kubectl/pkg/cmd/util" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" ) func newCmdCompletionFish(ioStreams genericclioptions.IOStreams) *cobra.Command { return &cobra.Command{ Use: "fish", Short: "Generate cert-manager CLI scripts for a Fish shell", Long: build.WithTemplate(`To load completions: $ {{.BuildName}} completion fish | source # To load completions for each session, execute once: $ {{.BuildName}} completion fish > ~/.config/fish/completions/{{.BuildName}}.fish `), DisableFlagsInUseLine: true, Run: func(cmd *cobra.Command, args []string) { util.CheckErr(cmd.Root().GenFishCompletion(ioStreams.Out, true)) }, } } 07070100000017000081A4000000000000000000000001662A23E400000594000000000000000000000000000000000000003100000000cert-manager-1.14.5/pkg/completion/powershell.go/* Copyright 2021 The cert-manager 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 completion import ( "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/kubectl/pkg/cmd/util" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" ) func newCmdCompletionPowerShell(ioStreams genericclioptions.IOStreams) *cobra.Command { return &cobra.Command{ Use: "powershell", Short: "Generate cert-manager CLI scripts for a PowerShell shell", Long: build.WithTemplate(`To load completions: PS> {{.BuildName}} completion powershell | Out-String | Invoke-Expression # To load completions for every new session, run: PS> {{.BuildName}} completion powershell > {{.BuildName}}.ps1 # and source this file from your PowerShell profile. `), DisableFlagsInUseLine: true, Run: func(cmd *cobra.Command, args []string) { util.CheckErr(cmd.Root().GenPowerShellCompletion(ioStreams.Out)) }, } } 07070100000018000081A4000000000000000000000001662A23E400000602000000000000000000000000000000000000002A00000000cert-manager-1.14.5/pkg/completion/zsh.go/* Copyright 2021 The cert-manager 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 completion import ( "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/kubectl/pkg/cmd/util" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" ) func newCmdCompletionZSH(ioStreams genericclioptions.IOStreams) *cobra.Command { return &cobra.Command{ Use: "zsh", Short: "Generation cert-manager CLI scripts for a ZSH shell", Long: build.WithTemplate(`To load completions: # If shell completion is not already enabled in your environment, # you will need to enable it. You can execute the following once: $ echo "autoload -U compinit; compinit" >> ~/.zshrc # To load completions for each session, execute once: $ {{.BuildName}} completion zsh > "${fpath[1]}/_{{.BuildName}}" # You will need to start a new shell for this setup to take effect. `), DisableFlagsInUseLine: true, Run: func(cmd *cobra.Command, args []string) { util.CheckErr(cmd.Root().GenZshCompletion(ioStreams.Out)) }, } } 07070100000019000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002000000000cert-manager-1.14.5/pkg/convert0707010000001A000081A4000000000000000000000001662A23E40000217C000000000000000000000000000000000000002B00000000cert-manager-1.14.5/pkg/convert/convert.go/* Copyright 2020 The cert-manager 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 convert import ( "context" "fmt" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" logf "github.com/cert-manager/cert-manager/pkg/logs" "github.com/spf13/cobra" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" apijson "k8s.io/apimachinery/pkg/runtime/serializer/json" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/printers" "k8s.io/cli-runtime/pkg/resource" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cert-manager/pkg/ctl" ) var ( example = templates.Examples(i18n.T(build.WithTemplate(` # Convert 'cert.yaml' to latest version and print to stdout. {{.BuildName}} convert -f cert.yaml # Convert kustomize overlay under current directory to 'cert-manager.io/v1alpha3' {{.BuildName}} convert -k . --output-version cert-manager.io/v1alpha3`))) longDesc = templates.LongDesc(i18n.T(` Convert cert-manager config files between different API versions. Both YAML and JSON formats are accepted. The command takes filename, directory, or URL as input, and converts into the format of the version specified by --output-version flag. If target version is not specified or not supported, it will convert to the latest version The default output will be printed to stdout in YAML format. One can use -o option to change to output destination.`)) ) var ( // Use this scheme as it has the internal cert-manager types // and their conversion functions registered. scheme = ctl.Scheme ) // Options is a struct to support convert command type Options struct { PrintFlags *genericclioptions.PrintFlags Printer printers.ResourcePrinter OutputVersion string resource.FilenameOptions genericclioptions.IOStreams } // NewOptions returns initialized Options func NewOptions(ioStreams genericclioptions.IOStreams) *Options { return &Options{ IOStreams: ioStreams, PrintFlags: genericclioptions.NewPrintFlags("converted").WithDefaultOutput("yaml"), } } // NewCmdConvert returns a cobra command for converting cert-manager resources func NewCmdConvert(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { o := NewOptions(ioStreams) cmd := &cobra.Command{ Use: "convert", Short: "Convert cert-manager config files between different API versions", Long: longDesc, Example: example, DisableFlagsInUseLine: true, Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Complete()) cmdutil.CheckErr(o.Run()) }, } cmd.Flags().StringVar(&o.OutputVersion, "output-version", o.OutputVersion, "Output the formatted object with the given group version (for ex: 'cert-manager.io/v1alpha3').") cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "Path to a file containing cert-manager resources to be converted.") o.PrintFlags.AddFlags(cmd) return cmd } // Complete collects information required to run Convert command from command line. func (o *Options) Complete() error { err := o.FilenameOptions.RequireFilenameOrKustomize() if err != nil { return err } // build the printer o.Printer, err = o.PrintFlags.ToPrinter() if err != nil { return err } return nil } // Run executes convert command func (o *Options) Run() error { builder := new(resource.Builder) r := builder. WithScheme(scheme). LocalParam(true).FilenameParam(false, &o.FilenameOptions).Flatten().Do() if err := r.Err(); err != nil { return err } singleItemImplied := false infos, err := r.IntoSingleItemImplied(&singleItemImplied).Infos() if err != nil { return err } if len(infos) == 0 { return fmt.Errorf("no objects passed to convert") } var specifiedOutputVersion schema.GroupVersion if len(o.OutputVersion) > 0 { specifiedOutputVersion, err = schema.ParseGroupVersion(o.OutputVersion) if err != nil { return err } } factory := serializer.NewCodecFactory(scheme) serializer := apijson.NewSerializerWithOptions(apijson.DefaultMetaFactory, scheme, scheme, apijson.SerializerOptions{}) encoder := factory.WithoutConversion().EncoderForVersion(serializer, nil) objects, err := asVersionedObject(infos, !singleItemImplied, specifiedOutputVersion, encoder) if err != nil { return err } return o.Printer.PrintObj(objects, o.Out) } // asVersionedObject converts a list of infos into a single object - either a List containing // the objects as children, or if only a single Object is present, as that object. The provided // version will be preferred as the conversion target, but the Object's mapping version will be // used if that version is not present. func asVersionedObject(infos []*resource.Info, forceList bool, specifiedOutputVersion schema.GroupVersion, encoder runtime.Encoder) (runtime.Object, error) { objects, err := asVersionedObjects(infos, specifiedOutputVersion, encoder) if err != nil { return nil, err } var object runtime.Object if len(objects) == 1 && !forceList { object = objects[0] } else { object = &metainternalversion.List{Items: objects} targetVersions := []schema.GroupVersion{} if !specifiedOutputVersion.Empty() { targetVersions = append(targetVersions, specifiedOutputVersion) } // This is needed so we are able to handle the List object when converting // multiple resources targetVersions = append(targetVersions, schema.GroupVersion{Group: "", Version: "v1"}) converted, err := tryConvert(object, targetVersions...) if err != nil { return nil, err } object = converted } actualVersion := object.GetObjectKind().GroupVersionKind() if actualVersion.Version != specifiedOutputVersion.Version { defaultVersionInfo := "" if len(actualVersion.Version) > 0 { defaultVersionInfo = fmt.Sprintf("Defaulting to %q", actualVersion.Version) } logf.V(logf.WarnLevel).Infof("info: the output version specified is invalid. %s\n", defaultVersionInfo) } return object, nil } // asVersionedObjects converts a list of infos into versioned objects. The provided // version will be preferred as the conversion target, but the Object's mapping version will be // used if that version is not present. func asVersionedObjects(infos []*resource.Info, specifiedOutputVersion schema.GroupVersion, encoder runtime.Encoder) ([]runtime.Object, error) { objects := []runtime.Object{} for _, info := range infos { if info.Object == nil { continue } targetVersions := []schema.GroupVersion{} // objects that are not part of api.Scheme must be converted to JSON if !specifiedOutputVersion.Empty() { _, _, err := scheme.ObjectKinds(info.Object) if err != nil { if runtime.IsNotRegisteredError(err) { data, err := runtime.Encode(encoder, info.Object) if err != nil { return nil, err } objects = append(objects, &runtime.Unknown{Raw: data}) continue } return nil, err } targetVersions = append(targetVersions, specifiedOutputVersion) } else { gvks, _, err := scheme.ObjectKinds(info.Object) if err == nil { for _, gvk := range gvks { targetVersions = append(targetVersions, scheme.PrioritizedVersionsForGroup(gvk.Group)...) } } } converted, err := tryConvert(info.Object, targetVersions...) if err != nil { return nil, err } objects = append(objects, converted) } return objects, nil } // tryConvert attempts to convert the given object to the provided versions in order. This function assumes // the object is in internal version. func tryConvert(object runtime.Object, versions ...schema.GroupVersion) (runtime.Object, error) { var last error for _, version := range versions { if version.Empty() { return object, nil } obj, err := scheme.ConvertToVersion(object, version) if err != nil { last = err continue } return obj, nil } return nil, last } 0707010000001B000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000001F00000000cert-manager-1.14.5/pkg/create0707010000001C000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000003200000000cert-manager-1.14.5/pkg/create/certificaterequest0707010000001D000081A4000000000000000000000001662A23E4000031BE000000000000000000000000000000000000004800000000cert-manager-1.14.5/pkg/create/certificaterequest/certificaterequest.go/* Copyright 2020 The cert-manager 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 certificaterequest import ( "context" "encoding/pem" "errors" "fmt" "os" "time" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/resource" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/factory" apiutil "github.com/cert-manager/cert-manager/pkg/api/util" cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" "github.com/cert-manager/cert-manager/pkg/ctl" "github.com/cert-manager/cert-manager/pkg/util/pki" ) var ( long = templates.LongDesc(i18n.T(` Create a new CertificateRequest resource based on a Certificate resource, by generating a private key locally and create a 'certificate signing request' to be submitted to a cert-manager Issuer.`)) example = templates.Examples(i18n.T(build.WithTemplate(` # Create a CertificateRequest with the name 'my-cr', saving the private key in a file named 'my-cr.key'. {{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml # Create a CertificateRequest in namespace default, provided no conflict with namespace defined in file. {{.BuildName}} create certificaterequest my-cr --namespace default --from-certificate-file my-certificate.yaml # Create a CertificateRequest and store private key in file 'new.key'. {{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --output-key-file new.key # Create a CertificateRequest, wait for it to be signed for up to 5 minutes (default) and store the x509 certificate in file 'new.crt'. {{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --output-cert-file new.crt # Create a CertificateRequest, wait for it to be signed for up to 20 minutes and store the x509 certificate in file 'my-cr.crt'. {{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --timeout 20m `))) ) var ( // Dedicated scheme used by the ctl tool that has the internal cert-manager types, // and their conversion functions registered scheme = ctl.Scheme ) // Options is a struct to support create certificaterequest command type Options struct { // Name of file that the generated private key will be stored in // If not specified, the private key will be written to <NameOfCR>.key KeyFilename string // If true, will wait for CertificateRequest to be ready to store the x509 certificate in a file // Command will block until CertificateRequest is ready or timeout as specified by Timeout happens FetchCert bool // Name of file that the generated x509 certificate will be stored in if --fetch-certificate flag is set // If not specified, the private key will be written to <NameOfCR>.crt CertFileName string // Path to a file containing a Certificate resource used as a template // when generating the CertificateRequest resource // Required InputFilename string // Length of time the command blocks to wait on CertificateRequest to be ready if --fetch-certificate flag is set // If not specified, default value is 5 minutes Timeout time.Duration genericclioptions.IOStreams *factory.Factory } // NewOptions returns initialized Options func NewOptions(ioStreams genericclioptions.IOStreams) *Options { return &Options{ IOStreams: ioStreams, } } // NewCmdCreateCR returns a cobra command for create CertificateRequest func NewCmdCreateCR(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { o := NewOptions(ioStreams) cmd := &cobra.Command{ Use: "certificaterequest", Aliases: []string{"cr"}, Short: "Create a cert-manager CertificateRequest resource, using a Certificate resource as a template", Long: long, Example: example, ValidArgsFunction: factory.ValidArgsListCertificateRequests(ctx, &o.Factory), Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Validate(args)) cmdutil.CheckErr(o.Run(ctx, args)) }, } cmd.Flags().StringVar(&o.InputFilename, "from-certificate-file", o.InputFilename, "Path to a file containing a Certificate resource used as a template when generating the CertificateRequest resource") cmd.Flags().StringVar(&o.KeyFilename, "output-key-file", o.KeyFilename, "Name of file that the generated private key will be written to") cmd.Flags().StringVar(&o.CertFileName, "output-certificate-file", o.CertFileName, "Name of the file the certificate is to be stored in") cmd.Flags().BoolVar(&o.FetchCert, "fetch-certificate", o.FetchCert, "If set to true, command will wait for CertificateRequest to be signed to store x509 certificate in a file") cmd.Flags().DurationVar(&o.Timeout, "timeout", 5*time.Minute, "Time before timeout when waiting for CertificateRequest to be signed, must include unit, e.g. 10m or 1h") o.Factory = factory.New(ctx, cmd) return cmd } // Validate validates the provided options func (o *Options) Validate(args []string) error { if len(args) < 1 { return errors.New("the name of the CertificateRequest to be created has to be provided as argument") } if len(args) > 1 { return errors.New("only one argument can be passed in: the name of the CertificateRequest") } if o.InputFilename == "" { return errors.New("the path to a YAML manifest of a Certificate resource cannot be empty, please specify by using --from-certificate-file flag") } if o.KeyFilename != "" && o.CertFileName != "" && o.KeyFilename == o.CertFileName { return errors.New("the file to store private key cannot be the same as the file to store certificate") } if !o.FetchCert && o.CertFileName != "" { return errors.New("cannot specify file to store certificate if not waiting for and fetching certificate, please set --fetch-certificate flag") } return nil } // Run executes create certificaterequest command func (o *Options) Run(ctx context.Context, args []string) error { builder := new(resource.Builder) // Read file as internal API version r := builder. WithScheme(scheme, schema.GroupVersion{Group: cmapi.SchemeGroupVersion.Group, Version: runtime.APIVersionInternal}). LocalParam(true).ContinueOnError(). NamespaceParam(o.Namespace).DefaultNamespace(). FilenameParam(o.EnforceNamespace, &resource.FilenameOptions{Filenames: []string{o.InputFilename}}).Flatten().Do() if err := r.Err(); err != nil { return err } singleItemImplied := false infos, err := r.IntoSingleItemImplied(&singleItemImplied).Infos() if err != nil { return err } // Ensure only one object per command if len(infos) == 0 { return fmt.Errorf("no objects found in manifest file %q. Expected one Certificate object", o.InputFilename) } if len(infos) > 1 { return fmt.Errorf("multiple objects found in manifest file %q. Expected only one Certificate object", o.InputFilename) } info := infos[0] // Convert to v1 because that version is needed for functions that follow crtObj, err := scheme.ConvertToVersion(info.Object, cmapi.SchemeGroupVersion) if err != nil { return fmt.Errorf("failed to convert object into version v1: %w", err) } // Cast Object into Certificate crt, ok := crtObj.(*cmapi.Certificate) if !ok { return errors.New("decoded object is not a v1 Certificate") } crt = crt.DeepCopy() if crt.Spec.PrivateKey == nil { crt.Spec.PrivateKey = &cmapi.CertificatePrivateKey{} } signer, err := pki.GeneratePrivateKeyForCertificate(crt) if err != nil { return fmt.Errorf("error when generating new private key for CertificateRequest: %w", err) } keyData, err := pki.EncodePrivateKey(signer, crt.Spec.PrivateKey.Encoding) if err != nil { return fmt.Errorf("failed to encode new private key for CertificateRequest: %w", err) } crName := args[0] // Storing private key to file keyFileName := crName + ".key" if o.KeyFilename != "" { keyFileName = o.KeyFilename } if err := os.WriteFile(keyFileName, keyData, 0600); err != nil { return fmt.Errorf("error when writing private key to file: %w", err) } fmt.Fprintf(o.ErrOut, "Private key written to file %s\n", keyFileName) // Build CertificateRequest with name as specified by argument req, err := buildCertificateRequest(crt, keyData, crName) if err != nil { return fmt.Errorf("error when building CertificateRequest: %w", err) } ns := crt.Namespace if ns == "" { ns = o.Namespace } req, err = o.CMClient.CertmanagerV1().CertificateRequests(ns).Create(ctx, req, metav1.CreateOptions{}) if err != nil { return fmt.Errorf("error creating CertificateRequest: %w", err) } fmt.Fprintf(o.ErrOut, "CertificateRequest %s has been created in namespace %s\n", req.Name, req.Namespace) if o.FetchCert { fmt.Fprintf(o.ErrOut, "CertificateRequest %v in namespace %v has not been signed yet. Wait until it is signed...\n", req.Name, req.Namespace) err = wait.PollUntilContextTimeout(ctx, time.Second, o.Timeout, false, func(ctx context.Context) (done bool, err error) { req, err = o.CMClient.CertmanagerV1().CertificateRequests(req.Namespace).Get(ctx, req.Name, metav1.GetOptions{}) if err != nil { return false, nil } return apiutil.CertificateRequestHasCondition(req, cmapi.CertificateRequestCondition{ Type: cmapi.CertificateRequestConditionReady, Status: cmmeta.ConditionTrue, }) && len(req.Status.Certificate) > 0, nil }) if err != nil { return fmt.Errorf("error when waiting for CertificateRequest to be signed: %w", err) } fmt.Fprintf(o.ErrOut, "CertificateRequest %v in namespace %v has been signed\n", req.Name, req.Namespace) // Fetch x509 certificate and store to file actualCertFileName := req.Name + ".crt" if o.CertFileName != "" { actualCertFileName = o.CertFileName } err = fetchCertificateFromCR(req, actualCertFileName) if err != nil { return fmt.Errorf("error when writing certificate to file: %w", err) } fmt.Fprintf(o.ErrOut, "Certificate written to file %s\n", actualCertFileName) } return nil } // Builds a CertificateRequest func buildCertificateRequest(crt *cmapi.Certificate, pk []byte, crName string) (*cmapi.CertificateRequest, error) { csrPEM, err := generateCSR(crt, pk) if err != nil { return nil, err } cr := &cmapi.CertificateRequest{ ObjectMeta: metav1.ObjectMeta{ Name: crName, Annotations: crt.Annotations, Labels: crt.Labels, }, Spec: cmapi.CertificateRequestSpec{ Request: csrPEM, Duration: crt.Spec.Duration, IssuerRef: crt.Spec.IssuerRef, IsCA: crt.Spec.IsCA, Usages: crt.Spec.Usages, }, } return cr, nil } func generateCSR(crt *cmapi.Certificate, pk []byte) ([]byte, error) { csr, err := pki.GenerateCSR(crt) if err != nil { return nil, err } signer, err := pki.DecodePrivateKeyBytes(pk) if err != nil { return nil, err } csrDER, err := pki.EncodeCSR(csr, signer) if err != nil { return nil, err } csrPEM := pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: csrDER, }) return csrPEM, nil } // fetchCertificateFromCR fetches the x509 certificate from a CR and stores the // certificate in file specified by certFilename. Assumes CR is ready, // otherwise returns error. func fetchCertificateFromCR(req *cmapi.CertificateRequest, certFileName string) error { // If CR not ready yet, error if !apiutil.CertificateRequestHasCondition(req, cmapi.CertificateRequestCondition{ Type: cmapi.CertificateRequestConditionReady, Status: cmmeta.ConditionTrue, }) || len(req.Status.Certificate) == 0 { return errors.New("CertificateRequest is not ready yet, unable to fetch certificate") } // Store certificate to file err := os.WriteFile(certFileName, req.Status.Certificate, 0600) if err != nil { return fmt.Errorf("error when writing certificate to file: %w", err) } return nil } 0707010000001E000081A4000000000000000000000001662A23E400001B0A000000000000000000000000000000000000004D00000000cert-manager-1.14.5/pkg/create/certificaterequest/certificaterequest_test.go/* Copyright 2020 The cert-manager 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 certificaterequest import ( "context" "os" "testing" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/factory" ) func TestValidate(t *testing.T) { tests := map[string]struct { inputFile string inputArgs []string keyFilename string certFilename string fetchCert bool expErr bool expErrMsg string }{ "CR name not passed as arg throws error": { inputFile: "example.yaml", inputArgs: []string{}, expErr: true, expErrMsg: "the name of the CertificateRequest to be created has to be provided as argument", }, "More than one arg throws error": { inputFile: "example.yaml", inputArgs: []string{"hello", "World"}, expErr: true, expErrMsg: "only one argument can be passed in: the name of the CertificateRequest", }, "not specifying path to yaml manifest throws error": { inputFile: "", inputArgs: []string{"hello"}, expErr: true, expErrMsg: "the path to a YAML manifest of a Certificate resource cannot be empty, please specify by using --from-certificate-file flag", }, "key filename and cert filename are optional flags": { inputFile: "example.yaml", inputArgs: []string{"hello"}, keyFilename: "", certFilename: "", expErr: false, }, "identical key filename and cert filename throws error": { inputFile: "example.yaml", inputArgs: []string{"hello"}, keyFilename: "same", certFilename: "same", expErr: true, expErrMsg: "the file to store private key cannot be the same as the file to store certificate", }, "cannot specify cert filename without fetch-certificate flag": { inputFile: "example.yaml", inputArgs: []string{"hello"}, certFilename: "cert.crt", fetchCert: false, expErr: true, expErrMsg: "cannot specify file to store certificate if not waiting for and fetching certificate, please set --fetch-certificate flag", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { opts := &Options{ InputFilename: test.inputFile, KeyFilename: test.keyFilename, CertFileName: test.certFilename, FetchCert: test.fetchCert, } // Validating args and flags err := opts.Validate(test.inputArgs) if err != nil { if !test.expErr { t.Fatalf("got unexpected error when validating args and flags: %v", err) } if err.Error() != test.expErrMsg { t.Fatalf("got unexpected error when validating args and flags, expected: %v; actual: %v", test.expErrMsg, err) } } else if test.expErr { // got no error t.Errorf("expected but got no error validating args and flags") } }) } } // Test Run tests the Run function's error behaviour up where it fails before interacting with // other components, e.g. writing private key to file. func TestRun(t *testing.T) { const ( crName = "testcr-3" ns1 = "testns-1" ns2 = "testns-2" ) tests := map[string]struct { inputFileContent string inputArgs []string inputNamespace string keyFilename string certFilename string fetchCert bool expErr bool expErrMsg string }{ // Build clients "conflicting namespaces defined in flag and file": { inputFileContent: `--- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: testcert-1 namespace: testns-1 spec: isCA: true secretName: ca-key-pair commonName: my-csi-app issuerRef: name: selfsigned-issuer kind: Issuer group: cert-manager.io `, inputArgs: []string{crName}, inputNamespace: ns2, keyFilename: "", expErr: true, expErrMsg: "the namespace from the provided object \"testns-1\" does not match the namespace \"testns-2\". You must pass '--namespace=testns-1' to perform this operation.", }, "file passed in defines resource other than certificate": { inputFileContent: `--- apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: ca-issuer namespace: testns-1 spec: ca: secretName: ca-key-pair `, inputArgs: []string{crName}, inputNamespace: ns1, keyFilename: "", expErr: true, expErrMsg: "decoded object is not a v1 Certificate", }, "empty manifest file throws error": { inputFileContent: ``, inputArgs: []string{crName}, inputNamespace: ns1, keyFilename: "", expErr: true, expErrMsg: "no objects found in manifest file \"testfile.yaml\". Expected one Certificate object", }, "manifest file with multiple objects throws error": { inputFileContent: `--- apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: ca-issuer namespace: testns-1 spec: ca: secretName: ca-key-pair --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: testcert-1 namespace: testns-1 spec: isCA: true secretName: ca-key-pair commonName: my-csi-app issuerRef: name: selfsigned-issuer kind: Issuer group: cert-manager.io`, inputArgs: []string{crName}, inputNamespace: ns1, keyFilename: "", expErr: true, expErrMsg: "multiple objects found in manifest file \"testfile.yaml\". Expected only one Certificate object", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { if err := os.WriteFile("testfile.yaml", []byte(test.inputFileContent), 0644); err != nil { t.Fatalf("error creating test file %#v", err) } defer os.Remove("testfile.yaml") // Options to run create CR command opts := &Options{ InputFilename: "testfile.yaml", KeyFilename: test.keyFilename, CertFileName: test.certFilename, Factory: &factory.Factory{ Namespace: test.inputNamespace, EnforceNamespace: test.inputNamespace != "", }, } // Validating args and flags err := opts.Validate(test.inputArgs) if err != nil { t.Fatal(err) } // Create CR err = opts.Run(context.TODO(), test.inputArgs) if err != nil { if !test.expErr { t.Fatalf("got unexpected error when trying to create CR: %v", err) } if err.Error() != test.expErrMsg { t.Fatalf("got unexpected error when trying to create CR, expected: %v; actual: %v", test.expErrMsg, err) } } else if test.expErr { // got no error t.Errorf("expected but got no error when creating CR") } }) } } 0707010000001F000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000003900000000cert-manager-1.14.5/pkg/create/certificatesigningrequest07070100000020000081A4000000000000000000000001662A23E400003AE7000000000000000000000000000000000000005600000000cert-manager-1.14.5/pkg/create/certificatesigningrequest/certificatesigningrequest.go/* Copyright 2021 The cert-manager 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 certificatesigningrequest import ( "context" "encoding/pem" "errors" "fmt" "os" "strconv" "time" experimentalapi "github.com/cert-manager/cert-manager/pkg/apis/experimental/v1alpha1" "github.com/spf13/cobra" certificatesv1 "k8s.io/api/certificates/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/resource" "k8s.io/client-go/discovery" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/factory" apiutil "github.com/cert-manager/cert-manager/pkg/api/util" "github.com/cert-manager/cert-manager/pkg/apis/certmanager" cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" "github.com/cert-manager/cert-manager/pkg/ctl" "github.com/cert-manager/cert-manager/pkg/util/pki" ) var ( long = templates.LongDesc(i18n.T(` Experimental. Only supported for Kubernetes versions 1.19+. Requires cert-manager versions 1.4+ with experimental controllers enabled. Create a new CertificateSigningRequest resource based on a Certificate resource, by generating a private key locally and create a 'certificate signing request' to be submitted to a cert-manager Issuer.`)) example = templates.Examples(i18n.T(build.WithTemplate(` # Create a CertificateSigningRequest with the name 'my-csr', saving the private key in a file named 'my-cr.key'. {{.BuildName}} x create certificatesigningrequest my-csr --from-certificate-file my-certificate.yaml # Create a CertificateSigningRequest and store private key in file 'new.key'. {{.BuildName}} x create certificatesigningrequest my-csr --from-certificate-file my-certificate.yaml --output-key-file new.key # Create a CertificateSigningRequest, wait for it to be signed for up to 5 minutes (default) and store the x509 certificate in file 'new.crt'. {{.BuildName}} x create csr my-cr -f my-certificate.yaml -c new.crt -w # Create a CertificateSigningRequest, wait for it to be signed for up to 20 minutes and store the x509 certificate in file 'my-cr.crt'. {{.BuildName}} x create csr my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --timeout 20m `))) ) var ( // Dedicated scheme used by the ctl tool that has the internal cert-manager types, // and their conversion functions registered scheme = ctl.Scheme ) // Options is a struct to support create certificatesigningrequest command type Options struct { // Name of file that the generated private key will be stored in If not // specified, the private key will be written to '<NameOfCSR>.key'. KeyFilename string // If true, will wait for CertificateSigingRequest to be ready to store the // x509 certificate in a file. // Command will block until CertificateSigningRequest is ready or timeout as // specified by Timeout happens. FetchCert bool // Name of file that the generated x509 certificate will be stored in if // --fetch-certificate flag is set If not specified, the private key will be // written to '<NameOfCSR>.crt'. CertFileName string // Path to a file containing a Certificate resource used as a template when // generating the CertificateSigningRequest resource. // Required. InputFilename string // Length of time the command blocks to wait on CertificateSigningRequest to // be ready if --fetch-certificate flag is set If not specified, default // value is 5 minutes. Timeout time.Duration genericclioptions.IOStreams *factory.Factory } // NewOptions returns initialized Options func NewOptions(ioStreams genericclioptions.IOStreams) *Options { return &Options{ IOStreams: ioStreams, } } // NewCmdCreateCSR returns a cobra command for create CertificateSigningRequest func NewCmdCreateCSR(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { o := NewOptions(ioStreams) cmd := &cobra.Command{ Use: "certificatesigningrequest", Aliases: []string{"csr"}, Short: "Create a Kubernetes CertificateSigningRequest resource, using a Certificate resource as a template", Long: long, Example: example, ValidArgsFunction: factory.ValidArgsListCertificateSigningRequests(ctx, &o.Factory), Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Validate(args)) cmdutil.CheckErr(o.Run(ctx, args)) }, } cmd.Flags().StringVarP(&o.InputFilename, "from-certificate-file", "f", o.InputFilename, "Path to a file containing a Certificate resource used as a template when generating the CertificateSigningRequest resource") cmd.Flags().StringVarP(&o.KeyFilename, "output-key-file", "k", o.KeyFilename, "Name of file that the generated private key will be written to") cmd.Flags().StringVarP(&o.CertFileName, "output-certificate-file", "c", o.CertFileName, "Name of the file the certificate is to be stored in") cmd.Flags().BoolVarP(&o.FetchCert, "fetch-certificate", "w", o.FetchCert, "If set to true, command will wait for CertificateSigningRequest to be signed to store x509 certificate in a file") cmd.Flags().DurationVar(&o.Timeout, "timeout", 5*time.Minute, "Time before timeout when waiting for CertificateSigningRequest to be signed, must include unit, e.g. 10m or 1h") o.Factory = factory.New(ctx, cmd) return cmd } // Validate validates the provided options func (o *Options) Validate(args []string) error { if len(args) < 1 { return errors.New("the name of the CertificateSigningRequest to be created has to be provided as argument") } if len(args) > 1 { return errors.New("only one argument can be passed in: the name of the CertificateSigningRequest") } if o.InputFilename == "" { return errors.New("the path to a YAML manifest of a Certificate resource cannot be empty, please specify by using --from-certificate-file or -f flag") } if o.KeyFilename != "" && o.CertFileName != "" && o.KeyFilename == o.CertFileName { return errors.New("the file to store private key cannot be the same as the file to store certificate") } if !o.FetchCert && o.CertFileName != "" { return errors.New("cannot specify file to store certificate if not waiting for and fetching certificate, please set --fetch-certificate or -w flag") } return nil } // Run executes create certificatesigningrequest command func (o *Options) Run(ctx context.Context, args []string) error { builder := new(resource.Builder) // Read file as internal API version r := builder. WithScheme(scheme, schema.GroupVersion{Group: cmapi.SchemeGroupVersion.Group, Version: runtime.APIVersionInternal}). LocalParam(true).ContinueOnError(). FilenameParam(false, &resource.FilenameOptions{Filenames: []string{o.InputFilename}}).Flatten().Do() if err := r.Err(); err != nil { return err } singleItemImplied := false infos, err := r.IntoSingleItemImplied(&singleItemImplied).Infos() if err != nil { return err } // Ensure only one object per command if len(infos) == 0 { return fmt.Errorf("no objects found in manifest file %q. Expected one Certificate object", o.InputFilename) } if len(infos) > 1 { return fmt.Errorf("multiple objects found in manifest file %q. Expected only one Certificate object", o.InputFilename) } info := infos[0] // Convert to v1 because that version is needed for functions that follow crtObj, err := scheme.ConvertToVersion(info.Object, cmapi.SchemeGroupVersion) if err != nil { return fmt.Errorf("failed to convert object into version v1: %s", err) } // Cast Object into Certificate crt, ok := crtObj.(*cmapi.Certificate) if !ok { return errors.New("decoded object is not a v1 Certificate") } crt = crt.DeepCopy() if crt.Spec.PrivateKey == nil { crt.Spec.PrivateKey = &cmapi.CertificatePrivateKey{} } if len(crt.Namespace) == 0 { // Default to the 'default' Namespace if no Namespaced defined on the // Certificate crt.Namespace = "default" } signer, err := pki.GeneratePrivateKeyForCertificate(crt) if err != nil { return fmt.Errorf("error when generating new private key for CertificateSigningRequest: %s", err) } keyPEM, err := pki.EncodePrivateKey(signer, crt.Spec.PrivateKey.Encoding) if err != nil { return fmt.Errorf("failed to encode new private key for CertificateSigningRequest: %s", err) } csrName := args[0] // Storing private key to file keyFileName := csrName + ".key" if o.KeyFilename != "" { keyFileName = o.KeyFilename } if err := os.WriteFile(keyFileName, keyPEM, 0600); err != nil { return fmt.Errorf("error when writing private key to file: %s", err) } fmt.Fprintf(o.Out, "Private key written to file %s\n", keyFileName) signerName, err := buildSignerName(o.KubeClient.Discovery(), crt) if err != nil { return fmt.Errorf("failed to build signerName from Certificate: %s", err) } // Build CertificateSigningRequest with name as specified by argument req, err := buildCertificateSigningRequest(crt, keyPEM, csrName, signerName) if err != nil { return fmt.Errorf("error when building CertificateSigningRequest: %s", err) } req, err = o.KubeClient.CertificatesV1().CertificateSigningRequests().Create(ctx, req, metav1.CreateOptions{}) if err != nil { return fmt.Errorf("error creating CertificateSigningRequest: %s", err) } fmt.Fprintf(o.Out, "CertificateSigningRequest %s has been created\n", req.Name) if o.FetchCert { fmt.Fprintf(o.Out, "CertificateSigningRequest %s has not been signed yet. Wait until it is signed...\n", req.Name) err = wait.PollUntilContextTimeout(ctx, time.Second, o.Timeout, false, func(ctx context.Context) (done bool, err error) { req, err = o.KubeClient.CertificatesV1().CertificateSigningRequests().Get(ctx, req.Name, metav1.GetOptions{}) if err != nil { return false, err } return len(req.Status.Certificate) > 0, nil }) if err != nil { return fmt.Errorf("error when waiting for CertificateSigningRequest to be signed: %s", err) } fmt.Fprintf(o.Out, "CertificateSigningRequest %s has been signed\n", req.Name) // Fetch x509 certificate and store to file actualCertFileName := req.Name + ".crt" if o.CertFileName != "" { actualCertFileName = o.CertFileName } err = storeCertificate(req, actualCertFileName) if err != nil { return fmt.Errorf("error when writing certificate to file: %s", err) } fmt.Fprintf(o.Out, "Certificate written to file %s\n", actualCertFileName) } return nil } // buildSignerName with generate a Kubernetes CertificateSigningRequest signer // name, based on the input Certificate's IssuerRef. This function will use the // Discovery API to fetch the resource definition of the referenced Issuer // Kind. // The signer name format follows that of cert-manager. func buildSignerName(client discovery.DiscoveryInterface, crt *cmapi.Certificate) (string, error) { targetGroup := crt.Spec.IssuerRef.Group if len(targetGroup) == 0 { targetGroup = certmanager.GroupName } targetKind := crt.Spec.IssuerRef.Kind if len(targetKind) == 0 { targetKind = cmapi.IssuerKind } grouplist, err := client.ServerGroups() if err != nil { return "", err } for _, group := range grouplist.Groups { if group.Name != targetGroup { continue } for _, version := range group.Versions { resources, err := client.ServerResourcesForGroupVersion(version.GroupVersion) if err != nil { return "", err } for _, resource := range resources.APIResources { if resource.Kind != targetKind { continue } if resource.Namespaced { return fmt.Sprintf("%s.%s/%s.%s", resource.Name, targetGroup, crt.Namespace, crt.Spec.IssuerRef.Name), nil } return fmt.Sprintf("%s.%s/%s", resource.Name, targetGroup, crt.Spec.IssuerRef.Name), nil } } } return "", fmt.Errorf("issuer references a resource definition which does not exist group=%s kind=%s", targetGroup, targetKind) } // Builds a CertificateSigningRequest func buildCertificateSigningRequest(crt *cmapi.Certificate, pk []byte, crName, signerName string) (*certificatesv1.CertificateSigningRequest, error) { csrPEM, err := generateCSR(crt, pk) if err != nil { return nil, err } ku, eku, err := pki.KeyUsagesForCertificateOrCertificateRequest(crt.Spec.Usages, crt.Spec.IsCA) if err != nil { return nil, err } csr := &certificatesv1.CertificateSigningRequest{ ObjectMeta: metav1.ObjectMeta{ Name: crName, Annotations: crt.Annotations, Labels: crt.Labels, }, Spec: certificatesv1.CertificateSigningRequestSpec{ Request: csrPEM, SignerName: signerName, Usages: append(apiutil.KubeKeyUsageStrings(ku), apiutil.KubeExtKeyUsageStrings(eku)...), }, } if csr.Annotations == nil { csr.Annotations = make(map[string]string) } csr.Annotations[experimentalapi.CertificateSigningRequestIsCAAnnotationKey] = strconv.FormatBool(crt.Spec.IsCA) if crt.Spec.Duration != nil { duration := crt.Spec.Duration.Duration csr.Annotations[experimentalapi.CertificateSigningRequestDurationAnnotationKey] = duration.String() seconds := int32(duration.Seconds()) // technically this could overflow but I do not think it matters csr.Spec.ExpirationSeconds = &seconds // if this is less than 600, the API server will fail the request } return csr, nil } func generateCSR(crt *cmapi.Certificate, pk []byte) ([]byte, error) { csr, err := pki.GenerateCSR(crt) if err != nil { return nil, err } signer, err := pki.DecodePrivateKeyBytes(pk) if err != nil { return nil, err } csrDER, err := pki.EncodeCSR(csr, signer) if err != nil { return nil, err } csrPEM := pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: csrDER, }) return csrPEM, nil } // storeCertificate fetches the x509 certificate from a // CertificateSigningRequest and stores the certificate in file specified by // certFilename. Assumes request is signed, otherwise returns error. func storeCertificate(req *certificatesv1.CertificateSigningRequest, fileName string) error { // If request not signed yet, error if len(req.Status.Certificate) == 0 { return errors.New("CertificateSigningRequest is not ready yet, unable to fetch certificate") } // Store certificate to file err := os.WriteFile(fileName, req.Status.Certificate, 0600) if err != nil { return fmt.Errorf("error when writing certificate to file: %s", err) } return nil } 07070100000021000081A4000000000000000000000001662A23E400000C79000000000000000000000000000000000000005B00000000cert-manager-1.14.5/pkg/create/certificatesigningrequest/certificatesigningrequest_test.go/* Copyright 2020 The cert-manager 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 certificatesigningrequest import ( "testing" ) func Test_Validate(t *testing.T) { tests := map[string]struct { inputFile string inputArgs []string keyFilename string certFilename string fetchCert bool expErr bool expErrMsg string }{ "CSR name not passed as arg throws error": { inputFile: "example.yaml", inputArgs: []string{}, expErr: true, expErrMsg: "the name of the CertificateSigningRequest to be created has to be provided as argument", }, "More than one arg throws error": { inputFile: "example.yaml", inputArgs: []string{"hello", "World"}, expErr: true, expErrMsg: "only one argument can be passed in: the name of the CertificateSigningRequest", }, "not specifying path to yaml manifest throws error": { inputFile: "", inputArgs: []string{"hello"}, expErr: true, expErrMsg: "the path to a YAML manifest of a Certificate resource cannot be empty, please specify by using --from-certificate-file or -f flag", }, "key filename and cert filename are optional flags": { inputFile: "example.yaml", inputArgs: []string{"hello"}, keyFilename: "", certFilename: "", expErr: false, }, "identical key filename and cert filename throws error": { inputFile: "example.yaml", inputArgs: []string{"hello"}, keyFilename: "same", certFilename: "same", expErr: true, expErrMsg: "the file to store private key cannot be the same as the file to store certificate", }, "cannot specify cert filename without fetch-certificate flag": { inputFile: "example.yaml", inputArgs: []string{"hello"}, certFilename: "cert.crt", fetchCert: false, expErr: true, expErrMsg: "cannot specify file to store certificate if not waiting for and fetching certificate, please set --fetch-certificate or -w flag", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { opts := &Options{ InputFilename: test.inputFile, KeyFilename: test.keyFilename, CertFileName: test.certFilename, FetchCert: test.fetchCert, } // Validating args and flags err := opts.Validate(test.inputArgs) if err != nil { if !test.expErr { t.Fatalf("got unexpected error when validating args and flags: %v", err) } if err.Error() != test.expErrMsg { t.Fatalf("got unexpected error when validating args and flags, expected: %v; actual: %v", test.expErrMsg, err) } } else if test.expErr { // got no error t.Errorf("expected but got no error validating args and flags") } }) } } 07070100000022000081A4000000000000000000000001662A23E4000004DC000000000000000000000000000000000000002900000000cert-manager-1.14.5/pkg/create/create.go/* Copyright 2020 The cert-manager 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 create import ( "context" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/create/certificaterequest" ) func NewCmdCreate(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { cmds := NewCmdCreateBare() cmds.AddCommand(certificaterequest.NewCmdCreateCR(ctx, ioStreams)) return cmds } // NewCmdCreateBare creates a bare Create Command, without any subcommands func NewCmdCreateBare() *cobra.Command { return &cobra.Command{ Use: "create", Short: "Create cert-manager resources", Long: `Create cert-manager resources e.g. a CertificateRequest`, } } 07070100000023000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000001D00000000cert-manager-1.14.5/pkg/deny07070100000024000081A4000000000000000000000001662A23E40000114E000000000000000000000000000000000000002500000000cert-manager-1.14.5/pkg/deny/deny.go/* Copyright 2021 The cert-manager 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 deny import ( "context" "errors" "fmt" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/cli-runtime/pkg/genericclioptions" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/factory" apiutil "github.com/cert-manager/cert-manager/pkg/api/util" cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" ) var ( example = templates.Examples(i18n.T(build.WithTemplate(` # Deny a CertificateRequest with the name 'my-cr' {{.BuildName}} deny my-cr # Deny a CertificateRequest in namespace default {{.BuildName}} deny my-cr --namespace default # Deny a CertificateRequest giving a custom reason and message {{.BuildName}} deny my-cr --reason "ManualDenial" --reason "Denied by PKI department" `))) ) // Options is a struct to support create certificaterequest command type Options struct { // Reason is the string that will be set on the Reason field of the Denied // condition. Reason string // Message is the string that will be set on the Message field of the // Denied condition. Message string genericclioptions.IOStreams *factory.Factory } // NewOptions returns initialized Options func NewOptions(ioStreams genericclioptions.IOStreams) *Options { return &Options{ IOStreams: ioStreams, } } func NewCmdDeny(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { o := NewOptions(ioStreams) cmd := &cobra.Command{ Use: "deny", Short: "Deny a CertificateRequest", Long: `Mark a CertificateRequest as Denied, so it may never be signed by a configured Issuer.`, Example: example, ValidArgsFunction: factory.ValidArgsListCertificateRequests(ctx, &o.Factory), Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Validate(args)) cmdutil.CheckErr(o.Run(ctx, args)) }, } cmd.Flags().StringVar(&o.Reason, "reason", "KubectlCertManager", "The reason to give as to what denied this CertificateRequest.") cmd.Flags().StringVar(&o.Message, "message", fmt.Sprintf("manually denied by %q", build.Name()), "The message to give as to why this CertificateRequest was denied.") o.Factory = factory.New(ctx, cmd) return cmd } // Validate validates the provided options func (o *Options) Validate(args []string) error { if len(args) < 1 { return errors.New("the name of the CertificateRequest to deny has to be provided as an argument") } if len(args) > 1 { return errors.New("only one argument can be passed: the name of the CertificateRequest") } if len(o.Reason) == 0 { return errors.New("a reason must be given as to who denied this CertificateRequest") } if len(o.Message) == 0 { return errors.New("a message must be given as to why this CertificateRequest is denied") } return nil } // Run executes deny command func (o *Options) Run(ctx context.Context, args []string) error { cr, err := o.CMClient.CertmanagerV1().CertificateRequests(o.Namespace).Get(ctx, args[0], metav1.GetOptions{}) if err != nil { return err } if apiutil.CertificateRequestIsApproved(cr) { return errors.New("CertificateRequest is already approved") } if apiutil.CertificateRequestIsDenied(cr) { return errors.New("CertificateRequest is already denied") } apiutil.SetCertificateRequestCondition(cr, cmapi.CertificateRequestConditionDenied, cmmeta.ConditionTrue, o.Reason, o.Message) _, err = o.CMClient.CertmanagerV1().CertificateRequests(o.Namespace).UpdateStatus(ctx, cr, metav1.UpdateOptions{}) if err != nil { return err } fmt.Fprintf(o.Out, "Denied CertificateRequest '%s/%s'\n", cr.Namespace, cr.Name) return nil } 07070100000025000081A4000000000000000000000001662A23E400000923000000000000000000000000000000000000002A00000000cert-manager-1.14.5/pkg/deny/deny_test.go/* Copyright 2021 The cert-manager 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 deny import ( "testing" ) func TestValidate(t *testing.T) { tests := map[string]struct { args []string reason, message string expErr bool expErrMsg string }{ "CR name not passed as arg throws error": { args: []string{}, reason: "", message: "", expErr: true, expErrMsg: "the name of the CertificateRequest to deny has to be provided as an argument", }, "multiple CR names passed as arg throws error": { args: []string{"cr-1", "cr-1"}, reason: "", message: "", expErr: true, expErrMsg: "only one argument can be passed: the name of the CertificateRequest", }, "empty reason given should throw error": { args: []string{"cr-1"}, reason: "", message: "", expErr: true, expErrMsg: "a reason must be given as to who denied this CertificateRequest", }, "empty message given should throw error": { args: []string{"cr-1"}, reason: "foo", message: "", expErr: true, expErrMsg: "a message must be given as to why this CertificateRequest is denied", }, "all fields populated should not error": { args: []string{"cr-1"}, reason: "foo", message: "bar", expErr: false, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { opts := &Options{ Reason: test.reason, Message: test.message, } // Validating args and flags err := opts.Validate(test.args) if (err != nil) != test.expErr { t.Errorf("unexpected error, exp=%t got=%v", test.expErr, err) } if err != nil && err.Error() != test.expErrMsg { t.Errorf("got unexpected error when validating args and flags, expected: %v; actual: %v", test.expErrMsg, err) } }) } } 07070100000026000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002500000000cert-manager-1.14.5/pkg/experimental07070100000027000081A4000000000000000000000001662A23E4000005DE000000000000000000000000000000000000003500000000cert-manager-1.14.5/pkg/experimental/experimental.go/* Copyright 2021 The cert-manager 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 experimental import ( "context" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/create" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/create/certificatesigningrequest" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/install" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/uninstall" ) func NewCmdExperimental(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { cmds := &cobra.Command{ Use: "experimental", Aliases: []string{"x"}, Short: "Interact with experimental features", Long: "Interact with experimental features", } create := create.NewCmdCreateBare() create.AddCommand(certificatesigningrequest.NewCmdCreateCSR(ctx, ioStreams)) cmds.AddCommand(create) cmds.AddCommand(install.NewCmdInstall(ctx, ioStreams)) cmds.AddCommand(uninstall.NewCmd(ctx, ioStreams)) return cmds } 07070100000028000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002000000000cert-manager-1.14.5/pkg/factory07070100000029000081A4000000000000000000000001662A23E400000DF0000000000000000000000000000000000000002B00000000cert-manager-1.14.5/pkg/factory/factory.go/* Copyright 2021 The cert-manager 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 factory import ( "context" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/kubectl/pkg/cmd/util" // Load all auth plugins _ "k8s.io/client-go/plugin/pkg/client/auth" cmclient "github.com/cert-manager/cert-manager/pkg/client/clientset/versioned" ) // Factory provides a set of clients and configurations to authenticate and // access a target Kubernetes cluster. Factory will ensure that its fields are // populated and valid during command execution. type Factory struct { factory util.Factory // Namespace is the namespace that the user has requested with the // "--namespace" / "-n" flag. Defaults to "default" if the flag was not // provided. Namespace string // EnforceNamespace will be true if the user provided the namespace flag. EnforceNamespace bool // RESTConfig is a Kubernetes REST config that contains the user's // authentication and access configuration. RESTConfig *rest.Config // CMClient is a Kubernetes clientset for interacting with cert-manager APIs. CMClient cmclient.Interface // KubeClient is a Kubernetes clientset for interacting with the base // Kubernetes APIs. KubeClient kubernetes.Interface // RESTClientGetter is used to get RESTConfig, DiscoveryClients and // RESTMapper implementations RESTClientGetter genericclioptions.RESTClientGetter } // New returns a new Factory. The supplied command will have flags registered // for interacting with the Kubernetes access options. Factory will be // populated when the command is executed using the cobra PreRun. If a PreRun // is already defined, it will be executed _after_ Factory has been populated, // making it available. func New(ctx context.Context, cmd *cobra.Command) *Factory { f := new(Factory) kubeConfigFlags := genericclioptions.NewConfigFlags(true) f.factory = util.NewFactory(kubeConfigFlags) kubeConfigFlags.AddFlags(cmd.Flags()) cmd.RegisterFlagCompletionFunc("namespace", validArgsListNamespaces(ctx, f)) // Setup a PreRunE to populate the Factory. Catch the existing PreRunE command // if one was defined, and execute it second. existingPreRunE := cmd.PreRunE cmd.PreRunE = func(cmd *cobra.Command, args []string) error { if err := f.complete(); err != nil { return err } if existingPreRunE != nil { return existingPreRunE(cmd, args) } return nil } return f } // complete will populate the Factory with values using the shared Kubernetes // CLI factory. func (f *Factory) complete() error { var err error f.Namespace, f.EnforceNamespace, err = f.factory.ToRawKubeConfigLoader().Namespace() if err != nil { return err } f.RESTConfig, err = f.factory.ToRESTConfig() if err != nil { return err } f.KubeClient, err = kubernetes.NewForConfig(f.RESTConfig) if err != nil { return err } f.CMClient, err = cmclient.NewForConfig(f.RESTConfig) if err != nil { return err } f.RESTClientGetter = f.factory return nil } 0707010000002A000081A4000000000000000000000001662A23E4000013A2000000000000000000000000000000000000002D00000000cert-manager-1.14.5/pkg/factory/validargs.go/* Copyright 2021 The cert-manager 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 factory import ( "context" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // ValidArgsListCertificates returns a cobra ValidArgsFunction for listing Certificates. func ValidArgsListCertificates(ctx context.Context, factory **Factory) func(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) { return func(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) { if len(args) > 0 { return nil, cobra.ShellCompDirectiveNoFileComp } f := *factory if err := f.complete(); err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } certList, err := f.CMClient.CertmanagerV1().Certificates(f.Namespace).List(ctx, metav1.ListOptions{}) if err != nil { return nil, cobra.ShellCompDirectiveError } var names []string for _, cert := range certList.Items { names = append(names, cert.Name) } return names, cobra.ShellCompDirectiveNoFileComp } } // ValidArgsListSecrets returns a cobra ValidArgsFunction for listing Secrets. func ValidArgsListSecrets(ctx context.Context, factory **Factory) func(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) { return func(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) { if len(args) > 0 { return nil, cobra.ShellCompDirectiveNoFileComp } f := *factory if err := f.complete(); err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } secretsList, err := f.KubeClient.CoreV1().Secrets(f.Namespace).List(ctx, metav1.ListOptions{}) if err != nil { return nil, cobra.ShellCompDirectiveError } var names []string for _, secret := range secretsList.Items { names = append(names, secret.Name) } return names, cobra.ShellCompDirectiveNoFileComp } } // ValidArgsListCertificateSigningRequests returns a cobra ValidArgsFunction for // listing CertificateSigningRequests. func ValidArgsListCertificateSigningRequests(ctx context.Context, factory **Factory) func(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) { return func(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) { if len(args) > 0 { return nil, cobra.ShellCompDirectiveNoFileComp } f := *factory if err := f.complete(); err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } csrList, err := f.KubeClient.CertificatesV1().CertificateSigningRequests().List(ctx, metav1.ListOptions{}) if err != nil { return nil, cobra.ShellCompDirectiveError } var names []string for _, csr := range csrList.Items { names = append(names, csr.Name) } return names, cobra.ShellCompDirectiveNoFileComp } } // ValidArgsListCertificateRequests returns a cobra ValidArgsFunction for listing // CertificateRequests. func ValidArgsListCertificateRequests(ctx context.Context, factory **Factory) func(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) { return func(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) { if len(args) > 0 { return nil, cobra.ShellCompDirectiveNoFileComp } f := *factory if err := f.complete(); err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } crList, err := f.CMClient.CertmanagerV1().CertificateRequests(f.Namespace).List(ctx, metav1.ListOptions{}) if err != nil { return nil, cobra.ShellCompDirectiveError } var names []string for _, cr := range crList.Items { names = append(names, cr.Name) } return names, cobra.ShellCompDirectiveNoFileComp } } // validArgsListNamespaces returns a cobra ValidArgsFunction for listing // namespaces. func validArgsListNamespaces(ctx context.Context, factory *Factory) func(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) { return func(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) { if len(args) > 0 { return nil, cobra.ShellCompDirectiveNoFileComp } if err := factory.complete(); err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } namespaceList, err := factory.KubeClient.CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) if err != nil { return nil, cobra.ShellCompDirectiveError } var names []string for _, namespace := range namespaceList.Items { names = append(names, namespace.Name) } return names, cobra.ShellCompDirectiveNoFileComp } } 0707010000002B000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002000000000cert-manager-1.14.5/pkg/inspect0707010000002C000081A4000000000000000000000001662A23E40000044E000000000000000000000000000000000000002B00000000cert-manager-1.14.5/pkg/inspect/inspect.go/* Copyright 2020 The cert-manager 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 inspect import ( "context" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/inspect/secret" ) func NewCmdInspect(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { cmds := &cobra.Command{ Use: "inspect", Short: "Get details on certificate related resources", Long: `Get details on certificate related resources, e.g. secrets`, } cmds.AddCommand(secret.NewCmdInspectSecret(ctx, ioStreams)) return cmds } 0707010000002D000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002700000000cert-manager-1.14.5/pkg/inspect/secret0707010000002E000081A4000000000000000000000001662A23E4000027EC000000000000000000000000000000000000003100000000cert-manager-1.14.5/pkg/inspect/secret/secret.go/* Copyright 2020 The cert-manager 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 secret import ( "bytes" "context" "crypto/x509" "errors" "fmt" "net/url" "strings" "text/template" "time" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/cli-runtime/pkg/genericclioptions" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" k8sclock "k8s.io/utils/clock" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/factory" cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" "github.com/cert-manager/cert-manager/pkg/util/pki" ) var clock k8sclock.Clock = k8sclock.RealClock{} const validForTemplate = `Valid for: DNS Names: {{ .DNSNames }} URIs: {{ .URIs }} IP Addresses: {{ .IPAddresses }} Email Addresses: {{ .EmailAddresses }} Usages: {{ .KeyUsage }}` const validityPeriodTemplate = `Validity period: Not Before: {{ .NotBefore }} Not After: {{ .NotAfter }}` const issuedByTemplate = `Issued By: Common Name: {{ .CommonName }} Organization: {{ .CommonName }} OrganizationalUnit: {{ .OrganizationalUnit }} Country: {{ .Country }}` const issuedForTemplate = `Issued For: Common Name: {{ .CommonName }} Organization: {{ .CommonName }} OrganizationalUnit: {{ .OrganizationalUnit }} Country: {{ .Country }}` const certificateTemplate = `Certificate: Signing Algorithm: {{ .SigningAlgorithm }} Public Key Algorithm: {{ .PublicKeyAlgorithm }} Serial Number: {{ .SerialNumber }} Fingerprints: {{ .Fingerprints }} Is a CA certificate: {{ .IsCACertificate }} CRL: {{ .CRL }} OCSP: {{ .OCSP }}` const debuggingTemplate = `Debugging: Trusted by this computer: {{ .TrustedByThisComputer }} CRL Status: {{ .CRLStatus }} OCSP Status: {{ .OCSPStatus }}` var ( long = templates.LongDesc(i18n.T(` Get details about a kubernetes.io/tls typed secret`)) example = templates.Examples(i18n.T(build.WithTemplate(` # Query information about a secret with name 'my-crt' in namespace 'my-namespace' {{.BuildName}} inspect secret my-crt --namespace my-namespace `))) ) // Options is a struct to support status certificate command type Options struct { genericclioptions.IOStreams *factory.Factory } // NewOptions returns initialized Options func NewOptions(ioStreams genericclioptions.IOStreams) *Options { return &Options{ IOStreams: ioStreams, } } // NewCmdInspectSecret returns a cobra command for status certificate func NewCmdInspectSecret(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { o := NewOptions(ioStreams) cmd := &cobra.Command{ Use: "secret", Short: "Get details about a kubernetes.io/tls typed secret", Long: long, Example: example, ValidArgsFunction: factory.ValidArgsListSecrets(ctx, &o.Factory), Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Validate(args)) cmdutil.CheckErr(o.Run(ctx, args)) }, } o.Factory = factory.New(ctx, cmd) return cmd } // Validate validates the provided options func (o *Options) Validate(args []string) error { if len(args) < 1 { return errors.New("the name of the Secret has to be provided as argument") } if len(args) > 1 { return errors.New("only one argument can be passed in: the name of the Secret") } return nil } // Run executes status certificate command func (o *Options) Run(ctx context.Context, args []string) error { secret, err := o.KubeClient.CoreV1().Secrets(o.Namespace).Get(ctx, args[0], metav1.GetOptions{}) if err != nil { return fmt.Errorf("error when finding Secret %q: %w\n", args[0], err) } certData := secret.Data[corev1.TLSCertKey] certs, err := splitPEMs(certData) if err != nil { return err } if len(certs) < 1 { return errors.New("no PEM data found in secret") } intermediates := [][]byte(nil) if len(certs) > 1 { intermediates = certs[1:] } // we only want to inspect the leaf certificate x509Cert, err := pki.DecodeX509CertificateBytes(certs[0]) if err != nil { return fmt.Errorf("error when parsing 'tls.crt': %w", err) } out := []string{ describeValidFor(x509Cert), describeValidityPeriod(x509Cert), describeIssuedBy(x509Cert), describeIssuedFor(x509Cert), describeCertificate(x509Cert), describeDebugging(x509Cert, intermediates, secret.Data[cmmeta.TLSCAKey]), } fmt.Println(strings.Join(out, "\n\n")) return nil } func describeValidFor(cert *x509.Certificate) string { var b bytes.Buffer template.Must(template.New("validForTemplate").Parse(validForTemplate)).Execute(&b, struct { DNSNames string URIs string IPAddresses string EmailAddresses string KeyUsage string }{ DNSNames: printSlice(cert.DNSNames), URIs: printSlice(pki.URLsToString(cert.URIs)), IPAddresses: printSlice(pki.IPAddressesToString(cert.IPAddresses)), EmailAddresses: printSlice(cert.EmailAddresses), KeyUsage: printKeyUsage(pki.BuildCertManagerKeyUsages(cert.KeyUsage, cert.ExtKeyUsage)), }) return b.String() } func describeValidityPeriod(cert *x509.Certificate) string { var b bytes.Buffer template.Must(template.New("validityPeriodTemplate").Parse(validityPeriodTemplate)).Execute(&b, struct { NotBefore string NotAfter string }{ NotBefore: cert.NotBefore.Format(time.RFC1123), NotAfter: cert.NotAfter.Format(time.RFC1123), }) return b.String() } func describeIssuedBy(cert *x509.Certificate) string { var b bytes.Buffer template.Must(template.New("issuedByTemplate").Parse(issuedByTemplate)).Execute(&b, struct { CommonName string Organization string OrganizationalUnit string Country string }{ CommonName: printOrNone(cert.Issuer.CommonName), Organization: printSliceOrOne(cert.Issuer.Organization), OrganizationalUnit: printSliceOrOne(cert.Issuer.Organization), Country: printSliceOrOne(cert.Issuer.Country), }) return b.String() } func describeIssuedFor(cert *x509.Certificate) string { var b bytes.Buffer template.Must(template.New("issuedForTemplate").Parse(issuedForTemplate)).Execute(&b, struct { CommonName string Organization string OrganizationalUnit string Country string }{ CommonName: printOrNone(cert.Subject.CommonName), Organization: printSliceOrOne(cert.Subject.Organization), OrganizationalUnit: printSliceOrOne(cert.Subject.Organization), Country: printSliceOrOne(cert.Subject.Country), }) return b.String() } func describeCertificate(cert *x509.Certificate) string { var b bytes.Buffer template.Must(template.New("certificateTemplate").Parse(certificateTemplate)).Execute(&b, struct { SigningAlgorithm string PublicKeyAlgorithm string SerialNumber string Fingerprints string IsCACertificate bool CRL string OCSP string }{ SigningAlgorithm: cert.SignatureAlgorithm.String(), PublicKeyAlgorithm: cert.PublicKeyAlgorithm.String(), SerialNumber: cert.SerialNumber.String(), Fingerprints: fingerprintCert(cert), IsCACertificate: cert.IsCA, CRL: printSliceOrOne(cert.CRLDistributionPoints), OCSP: printSliceOrOne(cert.OCSPServer), }) return b.String() } func describeDebugging(cert *x509.Certificate, intermediates [][]byte, ca []byte) string { var b bytes.Buffer template.Must(template.New("debuggingTemplate").Parse(debuggingTemplate)).Execute(&b, struct { TrustedByThisComputer string CRLStatus string OCSPStatus string }{ TrustedByThisComputer: describeTrusted(cert, intermediates), CRLStatus: describeCRL(cert), OCSPStatus: describeOCSP(cert, intermediates, ca), }) return b.String() } func describeCRL(cert *x509.Certificate) string { if len(cert.CRLDistributionPoints) < 1 { return "No CRL endpoints set" } hasChecked := false for _, crlURL := range cert.CRLDistributionPoints { u, err := url.Parse(crlURL) if err != nil { return fmt.Sprintf("Invalid CRL URL: %v", err) } if u.Scheme != "ldap" && u.Scheme != "https" { continue } hasChecked = true valid, err := checkCRLValidCert(cert, crlURL) if err != nil { return fmt.Sprintf("Cannot check CRL: %s", err.Error()) } if !valid { return fmt.Sprintf("Revoked by %s", crlURL) } } if !hasChecked { return "No CRL endpoints we support found" } return "Valid" } func describeOCSP(cert *x509.Certificate, intermediates [][]byte, ca []byte) string { if len(ca) > 1 { intermediates = append([][]byte{ca}, intermediates...) } if len(intermediates) < 1 { return "Cannot check OCSP, does not have a CA or intermediate certificate provided" } issuerCert, err := pki.DecodeX509CertificateBytes(intermediates[len(intermediates)-1]) if err != nil { return fmt.Sprintf("Cannot parse intermediate certificate: %s", err.Error()) } valid, err := checkOCSPValidCert(cert, issuerCert) if err != nil { return fmt.Sprintf("Cannot check OCSP: %s", err.Error()) } if !valid { return "Marked as revoked" } return "valid" } func describeTrusted(cert *x509.Certificate, intermediates [][]byte) string { systemPool, err := x509.SystemCertPool() if err != nil { return fmt.Sprintf("Error getting system CA store: %s", err.Error()) } for _, intermediate := range intermediates { systemPool.AppendCertsFromPEM(intermediate) } _, err = cert.Verify(x509.VerifyOptions{ Roots: systemPool, CurrentTime: clock.Now(), }) if err == nil { return "yes" } return fmt.Sprintf("no: %s", err.Error()) } 0707010000002F000081A4000000000000000000000001662A23E400002842000000000000000000000000000000000000003600000000cert-manager-1.14.5/pkg/inspect/secret/secret_test.go/* Copyright 2020 The cert-manager 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 secret import ( "crypto/x509" "strings" "testing" "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" fakeclock "k8s.io/utils/clock/testing" v1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" "github.com/cert-manager/cert-manager/pkg/util/pki" "github.com/cert-manager/cert-manager/test/unit/gen" ) var ( testCert string testCertSerial string testCertFingerprint string testNotBefore string testNotAfter string ) func init() { caKey, err := pki.GenerateECPrivateKey(256) if err != nil { panic(err) } caCertificateTemplate := gen.Certificate( "ca", gen.SetCertificateCommonName("testing-ca"), gen.SetCertificateIsCA(true), gen.SetCertificateKeyAlgorithm(v1.ECDSAKeyAlgorithm), gen.SetCertificateKeySize(256), gen.SetCertificateKeyUsages( v1.UsageDigitalSignature, v1.UsageKeyEncipherment, v1.UsageCertSign, ), gen.SetCertificateNotBefore(metav1.Time{Time: time.Now().Add(-time.Hour)}), gen.SetCertificateNotAfter(metav1.Time{Time: time.Now().Add(time.Hour)}), ) caCertificateTemplate.Spec.Subject = &v1.X509Subject{ Organizations: []string{"Internet Widgets, Inc."}, Countries: []string{"US"}, OrganizationalUnits: []string{"WWW"}, Localities: []string{"San Francisco"}, Provinces: []string{"California"}, } caX509Cert, err := pki.GenerateTemplate(caCertificateTemplate) if err != nil { panic(err) } _, caCert, err := pki.SignCertificate(caX509Cert, caX509Cert, caKey.Public(), caKey) if err != nil { panic(err) } testCertKey, err := pki.GenerateECPrivateKey(256) if err != nil { panic(err) } testCertTemplate := gen.Certificate( "testing-cert", gen.SetCertificateDNSNames("cert-manager.test"), gen.SetCertificateIPs("10.0.0.1"), gen.SetCertificateURIs("spiffe://cert-manager.test"), gen.SetCertificateEmails("test@cert-manager.io"), gen.SetCertificateIsCA(true), gen.SetCertificateKeyAlgorithm(v1.ECDSAKeyAlgorithm), gen.SetCertificateIsCA(false), gen.SetCertificateKeySize(256), gen.SetCertificateKeyUsages( v1.UsageDigitalSignature, v1.UsageKeyEncipherment, v1.UsageServerAuth, v1.UsageClientAuth, ), gen.SetCertificateNotBefore(metav1.Time{Time: time.Now().Add(-30 * time.Minute)}), gen.SetCertificateNotAfter(metav1.Time{Time: time.Now().Add(30 * time.Minute)}), ) testCertTemplate.Spec.Subject = &v1.X509Subject{ Organizations: []string{"cncf"}, Countries: []string{"GB"}, OrganizationalUnits: []string{"cert-manager"}, } testX509Cert, err := pki.GenerateTemplate(testCertTemplate) if err != nil { panic(err) } testCertPEM, testCertGo, err := pki.SignCertificate(testX509Cert, caCert, testCertKey.Public(), caKey) if err != nil { panic(err) } testCert = string(testCertPEM) testCertSerial = testCertGo.SerialNumber.String() testCertFingerprint = fingerprintCert(testCertGo) testNotBefore = testCertGo.NotBefore.Format(time.RFC1123) testNotAfter = testCertGo.NotAfter.Format(time.RFC1123) } func MustParseCertificate(t *testing.T, certData string) *x509.Certificate { x509Cert, err := pki.DecodeX509CertificateBytes([]byte(certData)) if err != nil { t.Fatalf("error when parsing crt: %v", err) } return x509Cert } func Test_describeCRL(t *testing.T) { tests := []struct { name string cert *x509.Certificate want string }{ { name: "Print cert without CRL", cert: MustParseCertificate(t, testCert), want: "No CRL endpoints set", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := describeCRL(tt.cert); got != tt.want { t.Errorf("describeCRL() = %v, want %v", makeInvisibleVisible(got), makeInvisibleVisible(tt.want)) } }) } } func Test_describeCertificate(t *testing.T) { tests := []struct { name string cert *x509.Certificate want string }{ { name: "Describe test certificate", cert: MustParseCertificate(t, testCert), want: `Certificate: Signing Algorithm: ECDSA-SHA256 Public Key Algorithm: ECDSA Serial Number: ` + testCertSerial + ` Fingerprints: ` + testCertFingerprint + ` Is a CA certificate: false CRL: <none> OCSP: <none>`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := describeCertificate(tt.cert); got != tt.want { t.Errorf("describeCertificate() = %v, want %v", makeInvisibleVisible(got), makeInvisibleVisible(tt.want)) } }) } } func Test_describeDebugging(t *testing.T) { type args struct { cert *x509.Certificate intermediates [][]byte ca []byte } tests := []struct { name string args args want string }{ { name: "Debug test cert without trusting CA", args: args{ cert: MustParseCertificate(t, testCert), intermediates: nil, ca: nil, }, want: `Debugging: Trusted by this computer: no: x509: certificate signed by unknown authority CRL Status: No CRL endpoints set OCSP Status: Cannot check OCSP, does not have a CA or intermediate certificate provided`, }, // TODO: add fake clock and test with trusting CA } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := describeDebugging(tt.args.cert, tt.args.intermediates, tt.args.ca); got != tt.want { t.Errorf("describeDebugging() = %v, want %v", makeInvisibleVisible(got), makeInvisibleVisible(tt.want)) } }) } } func Test_describeIssuedBy(t *testing.T) { tests := []struct { name string cert *x509.Certificate want string }{ { name: "Describe test certificate", cert: MustParseCertificate(t, testCert), want: `Issued By: Common Name: testing-ca Organization: testing-ca OrganizationalUnit: Internet Widgets, Inc. Country: US`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := describeIssuedBy(tt.cert); got != tt.want { t.Errorf("describeIssuedBy() = %v, want %v", makeInvisibleVisible(got), makeInvisibleVisible(tt.want)) } }) } } func Test_describeIssuedFor(t *testing.T) { tests := []struct { name string cert *x509.Certificate want string }{ { name: "Describe test cert", cert: MustParseCertificate(t, testCert), want: `Issued For: Common Name: <none> Organization: <none> OrganizationalUnit: cncf Country: GB`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := describeIssuedFor(tt.cert); got != tt.want { t.Errorf("describeIssuedFor() = %v, want %v", makeInvisibleVisible(got), makeInvisibleVisible(tt.want)) } }) } } func Test_describeOCSP(t *testing.T) { type args struct { cert *x509.Certificate intermediates [][]byte ca []byte } tests := []struct { name string args args want string }{ { name: "Describe cert with no OCSP", args: args{ cert: MustParseCertificate(t, testCert), }, want: "Cannot check OCSP, does not have a CA or intermediate certificate provided", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := describeOCSP(tt.args.cert, tt.args.intermediates, tt.args.ca); got != tt.want { t.Errorf("describeOCSP() = %v, want %v", makeInvisibleVisible(got), makeInvisibleVisible(tt.want)) } }) } } func Test_describeTrusted(t *testing.T) { // set clock to when our test cert was trusted t1, _ := time.Parse("Thu, 27 Nov 2020 10:00:00 UTC", time.RFC1123) clock = fakeclock.NewFakeClock(t1) type args struct { cert *x509.Certificate intermediates [][]byte } tests := []struct { name string args args want string }{ { name: "Describe test certificate", args: args{ cert: MustParseCertificate(t, testCert), intermediates: nil, }, want: "no: x509: certificate signed by unknown authority", }, { name: "Describe test certificate with adding it to the trust store", args: args{ cert: MustParseCertificate(t, testCert), intermediates: [][]byte{[]byte(testCert)}, }, want: "yes", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := describeTrusted(tt.args.cert, tt.args.intermediates); got != tt.want { t.Errorf("describeTrusted() = %v, want %v", makeInvisibleVisible(got), makeInvisibleVisible(tt.want)) } }) } } func Test_describeValidFor(t *testing.T) { tests := []struct { name string cert *x509.Certificate want string }{ { name: "Describe test certificate", cert: MustParseCertificate(t, testCert), want: `Valid for: DNS Names: - cert-manager.test URIs: - spiffe://cert-manager.test IP Addresses: - 10.0.0.1 Email Addresses: - test@cert-manager.io Usages: - digital signature - key encipherment - server auth - client auth`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := describeValidFor(tt.cert); got != tt.want { t.Errorf("describeValidFor() = %v, want %v", makeInvisibleVisible(got), makeInvisibleVisible(tt.want)) } }) } } func Test_describeValidityPeriod(t *testing.T) { tests := []struct { name string cert *x509.Certificate want string }{ { name: "Describe test certificate", cert: MustParseCertificate(t, testCert), want: `Validity period: Not Before: ` + testNotBefore + ` Not After: ` + testNotAfter, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := describeValidityPeriod(tt.cert); got != tt.want { t.Errorf("describeValidityPeriod() = %v, want %v", makeInvisibleVisible(got), makeInvisibleVisible(tt.want)) } }) } } func makeInvisibleVisible(in string) string { in = strings.Replace(in, "\n", "\\n\n", -1) in = strings.Replace(in, "\t", "\\t", -1) return in } 07070100000030000081A4000000000000000000000001662A23E40000114F000000000000000000000000000000000000002F00000000cert-manager-1.14.5/pkg/inspect/secret/util.go/* Copyright 2020 The cert-manager 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 secret import ( "bytes" "crypto" "crypto/sha256" "crypto/x509" "encoding/pem" "errors" "fmt" "io" "net/http" "net/url" "strings" "golang.org/x/crypto/ocsp" cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" ) func fingerprintCert(cert *x509.Certificate) string { if cert == nil { return "" } fingerprint := sha256.Sum256(cert.Raw) var buf bytes.Buffer for i, f := range fingerprint { if i > 0 { fmt.Fprintf(&buf, ":") } fmt.Fprintf(&buf, "%02X", f) } return buf.String() } func checkOCSPValidCert(leafCert, issuerCert *x509.Certificate) (bool, error) { if len(leafCert.OCSPServer) < 1 { return false, errors.New("No OCSP Server set") } buffer, err := ocsp.CreateRequest(leafCert, issuerCert, &ocsp.RequestOptions{Hash: crypto.SHA1}) if err != nil { return false, fmt.Errorf("error creating OCSP request: %w", err) } for _, ocspServer := range leafCert.OCSPServer { httpRequest, err := http.NewRequest(http.MethodPost, ocspServer, bytes.NewBuffer(buffer)) if err != nil { return false, fmt.Errorf("error creating HTTP request: %w", err) } ocspUrl, err := url.Parse(ocspServer) if err != nil { return false, fmt.Errorf("error parsing OCSP URL: %w", err) } httpRequest.Header.Add("Content-Type", "application/ocsp-request") httpRequest.Header.Add("Accept", "application/ocsp-response") httpRequest.Header.Add("Host", ocspUrl.Host) httpClient := &http.Client{} httpResponse, err := httpClient.Do(httpRequest) if err != nil { return false, fmt.Errorf("error making HTTP request: %w", err) } defer httpResponse.Body.Close() output, err := io.ReadAll(httpResponse.Body) if err != nil { return false, fmt.Errorf("error reading HTTP body: %w", err) } ocspResponse, err := ocsp.ParseResponse(output, issuerCert) if err != nil { return false, fmt.Errorf("error reading OCSP response: %w", err) } if ocspResponse.Status == ocsp.Revoked { // one OCSP revoked it do not trust return false, nil } } return true, nil } func checkCRLValidCert(cert *x509.Certificate, url string) (bool, error) { resp, err := http.Get(url) if err != nil { return false, fmt.Errorf("error getting HTTP response: %w", err) } body, err := io.ReadAll(resp.Body) if err != nil { return false, fmt.Errorf("error reading HTTP body: %w", err) } resp.Body.Close() crl, err := x509.ParseRevocationList(body) if err != nil { return false, fmt.Errorf("error parsing HTTP body: %w", err) } // TODO: check CRL signature for _, revoked := range crl.RevokedCertificateEntries { if cert.SerialNumber.Cmp(revoked.SerialNumber) == 0 { return false, nil } } return true, nil } func printSlice(in []string) string { if len(in) < 1 { return "<none>" } return "\n\t\t- " + strings.Trim(strings.Join(in, "\n\t\t- "), " ") } func printSliceOrOne(in []string) string { if len(in) < 1 { return "<none>" } else if len(in) == 1 { return in[0] } return printSlice(in) } func printOrNone(in string) string { if in == "" { return "<none>" } return in } func printKeyUsage(in []cmapi.KeyUsage) string { if len(in) < 1 { return " <none>" } var usageStrings []string for _, usage := range in { usageStrings = append(usageStrings, string(usage)) } return "\n\t\t- " + strings.Trim(strings.Join(usageStrings, "\n\t\t- "), " ") } func splitPEMs(certData []byte) ([][]byte, error) { certs := [][]byte(nil) for { block, rest := pem.Decode(certData) if block == nil { break // got no more certs to decode } // ignore private key data if block.Type == "CERTIFICATE" { buf := bytes.NewBuffer(nil) err := pem.Encode(buf, block) if err != nil { return nil, fmt.Errorf("error when reencoding PEM: %s", err) } certs = append(certs, buf.Bytes()) } certData = rest } return certs, nil } 07070100000031000081A4000000000000000000000001662A23E40000164E000000000000000000000000000000000000003400000000cert-manager-1.14.5/pkg/inspect/secret/util_test.go/* Copyright 2020 The cert-manager 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 secret import ( "crypto/x509" "reflect" "testing" cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" ) const testCertForFingerprinting = `-----BEGIN CERTIFICATE----- MIICljCCAhugAwIBAgIUNAQr779ga/BNXyCpK7ddFbjAK98wCgYIKoZIzj0EAwMw aTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh biBGcmFuY2lzY28xHzAdBgNVBAoTFkludGVybmV0IFdpZGdldHMsIEluYy4xDDAK BgNVBAsTA1dXVzAeFw0yMTAyMjYxMDM1MDBaFw0yMjAyMjYxMDM1MDBaMDMxCzAJ BgNVBAYTAkdCMQ0wCwYDVQQKEwRjbmNmMRUwEwYDVQQLEwxjZXJ0LW1hbmFnZXIw WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATd5gWH2rkzWBGrr1jCR6JDB0dZOizZ jCt2gnzNfzZmEg3rqxPvIakfT1lsjL2HrQyBRMQGGZhj7RkN7/VUM+VUo4HWMIHT MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUCUEeUFyT7U3e6zP4q4VYEr2x0KcwHwYD VR0jBBgwFoAUFkKAaJ18Vg9xFx3K7d5b7HjoSSMwVAYDVR0RBE0wS4IRY2VydC1t YW5hZ2VyLnRlc3SBFHRlc3RAY2VydC1tYW5hZ2VyLmlvhwQKAAABhhpzcGlmZmU6 Ly9jZXJ0LW1hbmFnZXIudGVzdDAKBggqhkjOPQQDAwNpADBmAjEA3Fv1aP+dBtBh +DThW0QQO/Xl0CHQRKnJmJ8JjnleaMYFVdHf7dcf0ZeyOC26aUkdAjEA/fvxvhcz Dtj+gY2rewoeJv5Pslli+SEObUslRaVtUMGxwUbmPU2fKuZHWBfe2FfA -----END CERTIFICATE----- ` func Test_fingerprintCert(t *testing.T) { tests := []struct { name string cert *x509.Certificate want string }{ { name: "Fingerprint a valid cert", cert: MustParseCertificate(t, testCertForFingerprinting), want: "FF:D0:A8:85:0B:A4:5A:E1:FC:55:40:E1:FC:07:09:F1:02:AE:B9:EB:28:C4:01:23:B9:4F:C8:FA:9B:EF:F4:C1", }, { name: "Fingerprint nil", cert: nil, want: "", }, { name: "Fingerprint invalid cert", cert: &x509.Certificate{Raw: []byte("fake")}, want: "B5:D5:4C:39:E6:66:71:C9:73:1B:9F:47:1E:58:5D:82:62:CD:4F:54:96:3F:0C:93:08:2D:8D:CF:33:4D:4C:78", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := fingerprintCert(tt.cert); got != tt.want { t.Errorf("fingerprintCert() = %v, want %v", got, tt.want) } }) } } func Test_printKeyUsage(t *testing.T) { type args struct { in []cmapi.KeyUsage } tests := []struct { name string args args want string }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := printKeyUsage(tt.args.in); got != tt.want { t.Errorf("printKeyUsage() = %v, want %v", got, tt.want) } }) } } func Test_printOrNone(t *testing.T) { tests := []struct { name string in string want string }{ { name: "Print none on empty", in: "", want: "<none>", }, { name: "Print value on not empty", in: "ok", want: "ok", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := printOrNone(tt.in); got != tt.want { t.Errorf("printOrNone() = %v, want %v", got, tt.want) } }) } } func Test_printSlice(t *testing.T) { tests := []struct { name string in []string want string }{ { name: "Print test slice multiple objects", in: []string{"test", "ok"}, want: ` - test - ok`, }, { name: "Print test slice one object", in: []string{"test"}, want: "\n\t\t- test", }, { name: "Print nil slice", in: nil, want: "<none>", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := printSlice(tt.in); got != tt.want { t.Errorf("printSlice() = %v, want %v", got, tt.want) } }) } } func Test_printSliceOrOne(t *testing.T) { tests := []struct { name string in []string want string }{ { name: "Print test slice multiple objects", in: []string{"test", "ok"}, want: ` - test - ok`, }, { name: "Print test slice one object", in: []string{"test"}, want: "test", }, { name: "Print nil slice", in: nil, want: "<none>", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := printSliceOrOne(tt.in); got != tt.want { t.Errorf("printSliceOrOne() = %v, want %v", got, tt.want) } }) } } func Test_splitPEMs(t *testing.T) { type args struct { certData []byte } tests := []struct { name string certData []byte want [][]byte wantErr bool }{ { name: "Single PEM in file", certData: []byte(testCert), want: [][]byte{[]byte(testCert)}, wantErr: false, }, { name: "2 PEMs in file", certData: []byte(testCert + "\n" + testCert), want: [][]byte{[]byte(testCert), []byte(testCert)}, wantErr: false, }, { name: "Invalid input after a valid PEM", certData: []byte(testCert + "\n\ninvalid"), want: [][]byte{[]byte(testCert)}, wantErr: false, }, { name: "Invalid input without PEM block", certData: []byte("invalid"), want: nil, wantErr: false, }, // TODO: somehow find an error case the PEM encoder/decoder is quite error resistant } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := splitPEMs(tt.certData) if (err != nil) != tt.wantErr { t.Errorf("splitPEMs() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { t.Errorf("splitPEMs() got = %v, want %v", got, tt.want) } }) } } 07070100000032000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002000000000cert-manager-1.14.5/pkg/install07070100000033000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002500000000cert-manager-1.14.5/pkg/install/helm07070100000034000081A4000000000000000000000001662A23E40000066D000000000000000000000000000000000000003100000000cert-manager-1.14.5/pkg/install/helm/applycrd.go/* Copyright 2021 The cert-manager 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 helm import ( "time" "helm.sh/helm/v3/pkg/action" "k8s.io/cli-runtime/pkg/resource" logf "github.com/cert-manager/cert-manager/pkg/logs" ) // CreateCRDs creates cert manager CRDs. Before calling this function, we // made sure that the CRDs are not yet installed on the cluster. func CreateCRDs(allCRDs []*resource.Info, cfg *action.Configuration) error { logf.Log.Info("Creating the cert-manager CRDs") // Create all CRDs rr, err := cfg.KubeClient.Create(allCRDs) if err != nil { return err } createdCRDs := rr.Created // Invalidate the local cache, since it will not have the new CRDs // present. discoveryClient, err := cfg.RESTClientGetter.ToDiscoveryClient() if err != nil { return err } logf.Log.Info("Clearing discovery cache") discoveryClient.Invalidate() // Give time for the CRD to be recognized. if err := cfg.KubeClient.Wait(createdCRDs, 60*time.Second); err != nil { return err } // Make sure to force a rebuild of the cache. if _, err := discoveryClient.ServerGroups(); err != nil { return err } return nil } 07070100000035000081A4000000000000000000000001662A23E4000009D3000000000000000000000000000000000000003100000000cert-manager-1.14.5/pkg/install/helm/resource.go/* Copyright 2021 The cert-manager 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 helm import ( "bytes" "fmt" "helm.sh/helm/v3/pkg/kube" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/cli-runtime/pkg/resource" ) const ( customResourceDefinitionGroup = "apiextensions.k8s.io" customResourceDefinitionKind = "CustomResourceDefinition" ) // Build a list of resource.Info objects from a rendered manifest. func ParseMultiDocumentYAML(manifest string, kubeClient kube.Interface) ([]*resource.Info, error) { resources := make([]*resource.Info, 0) res, err := kubeClient.Build(bytes.NewBufferString(manifest), false) if err != nil { return nil, fmt.Errorf("Parsing the CRDs from the rendered manifest was not successful: %w", err) } resources = append(resources, res...) return resources, nil } func filterResources(resources []*resource.Info, filter func(*resource.Info) bool) []*resource.Info { filtered := make([]*resource.Info, 0) for _, res := range resources { if filter(res) { filtered = append(filtered, res) } } return filtered } // Retrieve the latest version of the resources from the kubernetes cluster. func FetchResources(resources []*resource.Info, kubeClient kube.Interface) ([]*resource.Info, error) { detected := make([]*resource.Info, 0) for _, info := range resources { helper := resource.NewHelper(info.Client, info.Mapping) obj, err := helper.Get(info.Namespace, info.Name) if err != nil { if apierrors.IsNotFound(err) { continue } return nil, err } info.Object = obj detected = append(detected, info) } return detected, nil } // Filter resources that are Custom Resource Definitions. func FilterCrdResources(resources []*resource.Info) []*resource.Info { return filterResources(resources, func(res *resource.Info) bool { groupVersionKind := res.Object.GetObjectKind().GroupVersionKind() return (groupVersionKind.Group == customResourceDefinitionGroup) && (groupVersionKind.Kind == customResourceDefinitionKind) }) } 07070100000036000081A4000000000000000000000001662A23E400000C93000000000000000000000000000000000000003100000000cert-manager-1.14.5/pkg/install/helm/settings.go/* Copyright 2021 The cert-manager 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 helm import ( "context" "fmt" "os" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/factory" logf "github.com/cert-manager/cert-manager/pkg/logs" "github.com/go-logr/logr" "github.com/spf13/cobra" "github.com/spf13/pflag" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/cli" ) const defaultCertManagerNamespace = "cert-manager" const debugLogLevel = 3 type NormalisedEnvSettings struct { logger logr.Logger EnvSettings *cli.EnvSettings ActionConfiguration *action.Configuration Factory *factory.Factory } func NewNormalisedEnvSettings() *NormalisedEnvSettings { return &NormalisedEnvSettings{ EnvSettings: cli.New(), ActionConfiguration: &action.Configuration{}, } } func (n *NormalisedEnvSettings) Namespace() string { return n.Factory.Namespace } func (n *NormalisedEnvSettings) Setup(ctx context.Context, cmd *cobra.Command) { log := logf.FromContext(ctx) n.logger = log n.Factory = factory.New(ctx, cmd) n.setupEnvSettings(ctx, cmd) { // Add a PreRunE hook to initialise the action configuration. existingPreRunE := cmd.PreRunE cmd.PreRunE = func(cmd *cobra.Command, args []string) error { if existingPreRunE != nil { if err := existingPreRunE(cmd, args); err != nil { return err } } return n.InitActionConfiguration() } } // Fix the default namespace to be cert-manager cmd.Flag("namespace").DefValue = defaultCertManagerNamespace cmd.Flag("namespace").Value.Set(defaultCertManagerNamespace) } func (n *NormalisedEnvSettings) setupEnvSettings(ctx context.Context, cmd *cobra.Command) { { // Create a tempoary flag set to add the EnvSettings flags to, this // can then be iterated over to copy the flags we want to the command var tmpFlagSet pflag.FlagSet n.EnvSettings.AddFlags(&tmpFlagSet) tmpFlagSet.VisitAll(func(f *pflag.Flag) { switch f.Name { case "registry-config", "repository-config", "repository-cache": cmd.Flags().AddFlag(f) } }) } { // Add a PreRunE hook to set the debug value to true if the log level is // >= 3. existingPreRunE := cmd.PreRunE cmd.PreRunE = func(cmd *cobra.Command, args []string) error { if n.logger.V(debugLogLevel).Enabled() { n.EnvSettings.Debug = true } if existingPreRunE != nil { return existingPreRunE(cmd, args) } return nil } } } func (n *NormalisedEnvSettings) InitActionConfiguration() error { return n.ActionConfiguration.Init( n.Factory.RESTClientGetter, n.Factory.Namespace, os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) { n.logger.Info(fmt.Sprintf(format, v...)) }, ) } 07070100000037000081A4000000000000000000000001662A23E4000023FD000000000000000000000000000000000000002B00000000cert-manager-1.14.5/pkg/install/install.go/* Copyright 2021 The cert-manager 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 install import ( "context" "fmt" "io" "strings" "time" "github.com/spf13/cobra" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/cli/values" "helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v3/pkg/release" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/install/helm" logf "github.com/cert-manager/cert-manager/pkg/logs" ) type InstallOptions struct { settings *helm.NormalisedEnvSettings client *action.Install valueOpts *values.Options ChartName string DryRun bool Wait bool genericclioptions.IOStreams } const ( installCRDsFlagName = "installCRDs" ) func installDesc() string { return build.WithTemplate(`This command installs cert-manager. It uses the Helm libraries to do so. The latest published cert-manager chart in the "https://charts.jetstack.io" repo is used. Most of the features supported by 'helm install' are also supported by this command. In addition, this command will always correctly install the required CRD resources. Some example uses: $ {{.BuildName}} x install or $ {{.BuildName}} x install -n new-cert-manager or $ {{.BuildName}} x install --version v1.4.0 or $ {{.BuildName}} x install --set prometheus.enabled=false To override values in the cert-manager chart, use either the '--values' flag and pass in a file or use the '--set' flag and pass configuration from the command line. `) } func NewCmdInstall(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { settings := helm.NewNormalisedEnvSettings() options := &InstallOptions{ settings: settings, client: action.NewInstall(settings.ActionConfiguration), valueOpts: &values.Options{}, IOStreams: ioStreams, } cmd := &cobra.Command{ Use: "install", Short: "Install cert-manager", Long: installDesc(), RunE: func(cmd *cobra.Command, args []string) error { options.client.Namespace = settings.Namespace() rel, err := options.runInstall(ctx) if err != nil { return err } if options.DryRun { fmt.Fprintf(ioStreams.Out, "%s", rel.Manifest) return nil } printReleaseSummary(ioStreams.Out, rel) return nil }, SilenceUsage: true, SilenceErrors: true, } settings.Setup(ctx, cmd) addInstallUninstallFlags(cmd.Flags(), &options.client.Timeout, &options.Wait) addInstallFlags(cmd.Flags(), options.client) addValueOptionsFlags(cmd.Flags(), options.valueOpts) addChartPathOptionsFlags(cmd.Flags(), &options.client.ChartPathOptions) cmd.Flags().BoolVar(&options.client.CreateNamespace, "create-namespace", true, "Create the release namespace if not present") cmd.Flags().MarkHidden("create-namespace") cmd.Flags().StringVar(&options.ChartName, "chart-name", "cert-manager", "Name of the chart to install") cmd.Flags().MarkHidden("chart-name") cmd.Flags().BoolVar(&options.DryRun, "dry-run", false, "Simulate install and output manifest") return cmd } // The overall strategy is to install the CRDs first, and not as part of a Helm // release, and then to install a Helm release without the CRDs. This is to // ensure that CRDs are not removed by a subsequent helm uninstall or by a // future cmctl uninstall. We want the removal of CRDs to only be performed by // an administrator who understands that the consequences of removing CRDs will // be the garbage collection of all the related CRs in the cluster. We first // do a dry-run install of the chart (effectively helm template // --validate=false) to render the CRDs from the CRD templates in the Chart. // The ClientOnly option is required, otherwise Helm will return an error in // case the CRDs are already installed in the cluster. We then extract the // CRDs from the resulting dry-run manifests and install those first. Finally, // we perform a helm install to install the remaining non-CRD resources and // wait for those to be "Ready". // This creates a Helm "release" artifact in a Secret in the target namespace, which contains // a record of all the resources installed by Helm (except the CRDs). func (o *InstallOptions) runInstall(ctx context.Context) (*release.Release, error) { log := logf.FromContext(ctx, "install") // Find chart cp, err := o.client.ChartPathOptions.LocateChart(o.ChartName, o.settings.EnvSettings) if err != nil { return nil, err } chart, err := loader.Load(cp) if err != nil { return nil, err } // Check if chart is installable if err := checkIfInstallable(chart); err != nil { return nil, err } // Console print if chart is deprecated if chart.Metadata.Deprecated { log.Error(fmt.Errorf("chart.Metadata.Deprecated is true"), "This chart is deprecated") } // Merge all values flags p := getter.All(o.settings.EnvSettings) chartValues, err := o.valueOpts.MergeValues(p) if err != nil { return nil, err } // Dryrun template generation (used for rendering the CRDs in /templates) o.client.DryRun = true // Do not apply install o.client.ClientOnly = true // Do not validate against cluster (otherwise double CRDs can cause error) // Kube version to be used in dry run template generation which does not // talk to kube apiserver. This is to ensure that template generation // does not fail because our Kubernetes minimum version requirement is // higher than that hardcoded in Helm codebase for client-only runs o.client.KubeVersion = &chartutil.KubeVersion{ Version: "v999.999.999", Major: "999", Minor: "999", } chartValues[installCRDsFlagName] = true // Make sure to render CRDs dryRunResult, err := o.client.Run(chart, chartValues) if err != nil { return nil, err } if o.DryRun { return dryRunResult, nil } // The o.client.Run() call above will have altered the settings.ActionConfiguration // object, so we need to re-initialise it. if err := o.settings.InitActionConfiguration(); err != nil { return nil, err } // Extract the resource.Info objects from the manifest resources, err := helm.ParseMultiDocumentYAML(dryRunResult.Manifest, o.settings.ActionConfiguration.KubeClient) if err != nil { return nil, err } // Filter resource.Info objects and only keep the CRDs crds := helm.FilterCrdResources(resources) // Abort in case CRDs were not found in chart if len(crds) == 0 { return nil, fmt.Errorf("Found no CRDs in provided cert-manager chart.") } // Make sure that no CRDs are currently installed originalCRDs, err := helm.FetchResources(crds, o.settings.ActionConfiguration.KubeClient) if err != nil { return nil, err } if len(originalCRDs) > 0 { return nil, fmt.Errorf("Found existing installed cert-manager CRDs! Cannot continue with installation.") } // Install CRDs if err := helm.CreateCRDs(crds, o.settings.ActionConfiguration); err != nil { return nil, err } // Install chart o.client.DryRun = false // Apply DryRun cli flags o.client.ClientOnly = false // Perform install against cluster o.client.KubeVersion = nil o.client.Wait = o.Wait // Wait for resources to be ready // If part of the install fails and the Atomic option is set to True, // all resource installs are reverted. Atomic cannot be enabled without // waiting (if Atomic=True is set, the value for Wait is overwritten with True), // so only enable Atomic if we are waiting. o.client.Atomic = o.Wait // The cert-manager chart currently has only a startupapicheck hook, // if waiting is disabled, this hook should be disabled too; otherwise // the hook will still wait for the installation to succeed. o.client.DisableHooks = !o.Wait chartValues[installCRDsFlagName] = false // Do not render CRDs, as this might cause problems when uninstalling using helm return o.client.Run(chart, chartValues) } func printReleaseSummary(out io.Writer, rel *release.Release) { fmt.Fprintf(out, "NAME: %s\n", rel.Name) if !rel.Info.LastDeployed.IsZero() { fmt.Fprintf(out, "LAST DEPLOYED: %s\n", rel.Info.LastDeployed.Format(time.ANSIC)) } fmt.Fprintf(out, "NAMESPACE: %s\n", rel.Namespace) fmt.Fprintf(out, "STATUS: %s\n", rel.Info.Status.String()) fmt.Fprintf(out, "REVISION: %d\n", rel.Version) fmt.Fprintf(out, "DESCRIPTION: %s\n", rel.Info.Description) if len(rel.Info.Notes) > 0 { fmt.Fprintf(out, "NOTES:\n%s\n", strings.TrimSpace(rel.Info.Notes)) } } // Only Application chart type are installable. func checkIfInstallable(ch *chart.Chart) error { switch ch.Metadata.Type { case "", "application": return nil } return fmt.Errorf("%s charts are not installable", ch.Metadata.Type) } 07070100000038000081A4000000000000000000000001662A23E400000D7B000000000000000000000000000000000000002800000000cert-manager-1.14.5/pkg/install/util.go/* Copyright 2021 The cert-manager 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 install import ( "os" "path/filepath" "time" "github.com/spf13/pflag" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/cli/values" "k8s.io/client-go/util/homedir" ) // Flags that are shared between the Install and the Uninstall command func addInstallUninstallFlags(f *pflag.FlagSet, timeout *time.Duration, wait *bool) { f.DurationVar(timeout, "timeout", 300*time.Second, "Time to wait for any individual Kubernetes operation (like Jobs for hooks)") f.MarkHidden("timeout") f.BoolVar(wait, "wait", true, "If set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout") f.MarkHidden("wait") } func addInstallFlags(f *pflag.FlagSet, client *action.Install) { f.StringVar(&client.ReleaseName, "release-name", "cert-manager", "Name of the helm release") f.MarkHidden("release-name") f.BoolVarP(&client.GenerateName, "generate-name", "g", false, "Generate the name (instead of using the default 'cert-manager' value)") f.MarkHidden("generate-name") f.StringVar(&client.NameTemplate, "name-template", "", "Specify template used to name the release") f.MarkHidden("name-template") f.StringVar(&client.Description, "description", "Cert-manager was installed using the cert-manager CLI", "Add a custom description") f.MarkHidden("description") } func addValueOptionsFlags(f *pflag.FlagSet, v *values.Options) { f.StringSliceVarP(&v.ValueFiles, "values", "f", []string{}, "Specify values in a YAML file or a URL (can specify multiple)") f.StringArrayVar(&v.Values, "set", []string{}, "Set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.StringArrayVar(&v.StringValues, "set-string", []string{}, "Set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.MarkHidden("set-string") f.StringArrayVar(&v.FileValues, "set-file", []string{}, "Set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)") f.MarkHidden("set-file") } // defaultKeyring returns the expanded path to the default keyring. func defaultKeyring() string { if v, ok := os.LookupEnv("GNUPGHOME"); ok { return filepath.Join(v, "pubring.gpg") } return filepath.Join(homedir.HomeDir(), ".gnupg", "pubring.gpg") } func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) { c.Keyring = defaultKeyring() c.RepoURL = "https://charts.jetstack.io" f.StringVar(&c.Version, "version", "", "specify a version constraint for the chart version to use. This constraint can be a specific tag (e.g. 1.1.1) or it may reference a valid range (e.g. ^2.0.0). If this is not specified, the latest version is used") } 07070100000039000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000001E00000000cert-manager-1.14.5/pkg/renew0707010000003A000081A4000000000000000000000001662A23E400001A1B000000000000000000000000000000000000002700000000cert-manager-1.14.5/pkg/renew/renew.go/* Copyright 2020 The cert-manager 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 renew import ( "context" "errors" "fmt" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/kubernetes" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/factory" apiutil "github.com/cert-manager/cert-manager/pkg/api/util" cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" cmclient "github.com/cert-manager/cert-manager/pkg/client/clientset/versioned" ) var ( long = templates.LongDesc(i18n.T(` Mark cert-manager Certificate resources for manual renewal.`)) example = templates.Examples(i18n.T(build.WithTemplate(` # Renew the Certificates named 'my-app' and 'vault' in the current context namespace. {{.BuildName}} renew my-app vault # Renew all Certificates in the 'kube-system' namespace. {{.BuildName}} renew --namespace kube-system --all # Renew all Certificates in all namespaces, provided those Certificates have the label 'app=my-service' {{.BuildName}} renew --all-namespaces -l app=my-service`))) ) // Options is a struct to support renew command type Options struct { LabelSelector string All bool AllNamespaces bool genericclioptions.IOStreams *factory.Factory } // NewOptions returns initialized Options func NewOptions(ioStreams genericclioptions.IOStreams) *Options { return &Options{ IOStreams: ioStreams, } } // NewCmdRenew returns a cobra command for renewing Certificates func NewCmdRenew(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { o := NewOptions(ioStreams) cmd := &cobra.Command{ Use: "renew", Short: "Mark a Certificate for manual renewal", Long: long, Example: example, ValidArgsFunction: factory.ValidArgsListCertificates(ctx, &o.Factory), Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Validate(cmd, args)) cmdutil.CheckErr(o.Run(ctx, args)) }, } cmd.Flags().StringVarP(&o.LabelSelector, "selector", "l", o.LabelSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)") cmd.Flags().BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If present, mark Certificates across namespaces for manual renewal. Namespace in current context is ignored even if specified with --namespace.") cmd.Flags().BoolVar(&o.All, "all", o.All, "Renew all Certificates in the given Namespace, or all namespaces with --all-namespaces enabled.") o.Factory = factory.New(ctx, cmd) return cmd } // Validate validates the provided options func (o *Options) Validate(cmd *cobra.Command, args []string) error { if len(o.LabelSelector) > 0 && len(args) > 0 { return errors.New("cannot specify Certificate names in conjunction with label selectors") } if len(o.LabelSelector) > 0 && o.All { return errors.New("cannot specify label selectors in conjunction with --all flag") } if o.All && len(args) > 0 { return errors.New("cannot specify Certificate names in conjunction with --all flag") } if o.All && cmd.PersistentFlags().Changed("namespace") { return errors.New("cannot specify --namespace flag in conjunction with --all flag") } if !o.All && len(args) == 0 { return errors.New("please supply one or more Certificate resource names or use the --all flag to renew all Certificate resources") } return nil } // Complete takes the command arguments and factory and infers any remaining options. func (o *Options) Complete(f cmdutil.Factory) error { var err error o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace() if err != nil { return err } o.RESTConfig, err = f.ToRESTConfig() if err != nil { return err } o.CMClient, err = cmclient.NewForConfig(o.RESTConfig) if err != nil { return err } return nil } // Run executes renew command func (o *Options) Run(ctx context.Context, args []string) error { nss := []corev1.Namespace{{ObjectMeta: metav1.ObjectMeta{Name: o.Namespace}}} if o.AllNamespaces { kubeClient, err := kubernetes.NewForConfig(o.RESTConfig) if err != nil { return err } nsList, err := kubeClient.CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) if err != nil { return err } nss = nsList.Items } var crts []cmapi.Certificate for _, ns := range nss { switch { case o.All, len(o.LabelSelector) > 0: crtsList, err := o.CMClient.CertmanagerV1().Certificates(ns.Name).List(ctx, metav1.ListOptions{ LabelSelector: o.LabelSelector, }) if err != nil { return err } crts = append(crts, crtsList.Items...) default: for _, crtName := range args { crt, err := o.CMClient.CertmanagerV1().Certificates(ns.Name).Get(ctx, crtName, metav1.GetOptions{}) if err != nil { return err } crts = append(crts, *crt) } } } if len(crts) == 0 { if o.AllNamespaces { fmt.Fprintln(o.ErrOut, "No Certificates found") } else { fmt.Fprintf(o.ErrOut, "No Certificates found in %s namespace.\n", o.Namespace) } return nil } for _, crt := range crts { // #nosec G601 -- False positive. See https://github.com/golang/go/discussions/56010 if err := o.renewCertificate(ctx, &crt); err != nil { return err } } return nil } func (o *Options) renewCertificate(ctx context.Context, crt *cmapi.Certificate) error { apiutil.SetCertificateCondition(crt, crt.Generation, cmapi.CertificateConditionIssuing, cmmeta.ConditionTrue, "ManuallyTriggered", "Certificate re-issuance manually triggered") _, err := o.CMClient.CertmanagerV1().Certificates(crt.Namespace).UpdateStatus(ctx, crt, metav1.UpdateOptions{}) if err != nil { return fmt.Errorf("failed to trigger issuance of Certificate %s/%s: %v", crt.Namespace, crt.Name, err) } fmt.Fprintf(o.Out, "Manually triggered issuance of Certificate %s/%s\n", crt.Namespace, crt.Name) return nil } 0707010000003B000081A4000000000000000000000001662A23E400000C5A000000000000000000000000000000000000002C00000000cert-manager-1.14.5/pkg/renew/renew_test.go/* Copyright 2020 The cert-manager 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 renew import ( "context" "testing" "k8s.io/cli-runtime/pkg/genericclioptions" ) type stringFlag struct { name, value string } func TestValidate(t *testing.T) { tests := map[string]struct { options *Options args []string setStringFlags []stringFlag expErr bool }{ "If there are arguments, as well as label selector, error": { options: &Options{ LabelSelector: "foo=bar", }, args: []string{"abc"}, expErr: true, }, "If there are all certificates selected, as well as label selector, error": { options: &Options{ LabelSelector: "foo=bar", All: true, }, args: []string{""}, expErr: true, }, "If there are all certificates selected, as well as arguments, error": { options: &Options{ All: true, }, args: []string{"abc"}, expErr: true, }, "If all certificates in all namespaces selected, don't error": { options: &Options{ All: true, AllNamespaces: true, }, expErr: false, }, "If --namespace and --all namespace specified, error": { options: &Options{ All: true, }, setStringFlags: []stringFlag{ {name: "namespace", value: "foo"}, }, expErr: true, }, "If --namespace specified without arguments, error": { options: &Options{}, setStringFlags: []stringFlag{ {name: "namespace", value: "foo"}, }, expErr: true, }, "If --namespace specified and at least one argument, don't error": { options: &Options{}, args: []string{"bar"}, setStringFlags: []stringFlag{ {name: "namespace", value: "foo"}, }, expErr: false, }, "If --namespace specified with multiple arguments, don't error": { options: &Options{}, args: []string{"bar", "abc"}, setStringFlags: []stringFlag{ {name: "namespace", value: "foo"}, }, expErr: false, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { cmd := NewCmdRenew(context.TODO(), genericclioptions.IOStreams{}) // This is normally registered in the main func. We add here to test // against flags normally inherited. kubeConfigFlags := genericclioptions.NewConfigFlags(true) kubeConfigFlags.AddFlags(cmd.PersistentFlags()) if test.setStringFlags != nil { for _, s := range test.setStringFlags { if err := cmd.PersistentFlags().Set(s.name, s.value); err != nil { t.Fatal(err) } } } err := test.options.Validate(cmd, test.args) if test.expErr != (err != nil) { t.Errorf("expected error=%t got=%v", test.expErr, err) } }) } } 0707010000003C000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000001F00000000cert-manager-1.14.5/pkg/status0707010000003D000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002B00000000cert-manager-1.14.5/pkg/status/certificate0707010000003E000081A4000000000000000000000001662A23E4000035C3000000000000000000000000000000000000003A00000000cert-manager-1.14.5/pkg/status/certificate/certificate.go/* Copyright 2020 The cert-manager 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 certificate import ( "context" "errors" "fmt" "time" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/reference" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/factory" cmacme "github.com/cert-manager/cert-manager/pkg/apis/acme/v1" cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" cmclient "github.com/cert-manager/cert-manager/pkg/client/clientset/versioned" "github.com/cert-manager/cert-manager/pkg/ctl" "github.com/cert-manager/cert-manager/pkg/util/predicate" ) var ( long = templates.LongDesc(i18n.T(` Get details about the current status of a cert-manager Certificate resource, including information on related resources like CertificateRequest or Order.`)) example = templates.Examples(i18n.T(build.WithTemplate(` # Query status of Certificate with name 'my-crt' in namespace 'my-namespace' {{.BuildName}} status certificate my-crt --namespace my-namespace `))) ) // Options is a struct to support status certificate command type Options struct { genericclioptions.IOStreams *factory.Factory } // Data is a struct containing the information to build a CertificateStatus type Data struct { Certificate *cmapi.Certificate CrtEvents *corev1.EventList Issuer cmapi.GenericIssuer IssuerKind string IssuerError error IssuerEvents *corev1.EventList Secret *corev1.Secret SecretError error SecretEvents *corev1.EventList Req *cmapi.CertificateRequest ReqError error ReqEvents *corev1.EventList Order *cmacme.Order OrderError error Challenges []*cmacme.Challenge ChallengeErr error } // NewOptions returns initialized Options func NewOptions(ioStreams genericclioptions.IOStreams) *Options { return &Options{ IOStreams: ioStreams, } } // NewCmdStatusCert returns a cobra command for status certificate func NewCmdStatusCert(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { o := NewOptions(ioStreams) cmd := &cobra.Command{ Use: "certificate", Short: "Get details about the current status of a cert-manager Certificate resource", Long: long, Example: example, ValidArgsFunction: factory.ValidArgsListCertificates(ctx, &o.Factory), Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Validate(args)) cmdutil.CheckErr(o.Run(ctx, args)) }, } o.Factory = factory.New(ctx, cmd) return cmd } // Validate validates the provided options func (o *Options) Validate(args []string) error { if len(args) < 1 { return errors.New("the name of the Certificate has to be provided as argument") } if len(args) > 1 { return errors.New("only one argument can be passed in: the name of the Certificate") } return nil } // Run executes status certificate command func (o *Options) Run(ctx context.Context, args []string) error { data, err := o.GetResources(ctx, args[0]) if err != nil { return err } // Build status of Certificate with data gathered status := StatusFromResources(data) fmt.Fprintf(o.Out, status.String()) return nil } // GetResources collects all related resources of the Certificate and any errors while doing so // in a Data struct and returns it. // Returns error if error occurs when finding Certificate resource or while preparing to find other resources, // e.g. when creating clientSet func (o *Options) GetResources(ctx context.Context, crtName string) (*Data, error) { clientSet, err := kubernetes.NewForConfig(o.RESTConfig) if err != nil { return nil, err } crt, err := o.CMClient.CertmanagerV1().Certificates(o.Namespace).Get(ctx, crtName, metav1.GetOptions{}) if err != nil { return nil, fmt.Errorf("error when getting Certificate resource: %v", err) } crtRef, err := reference.GetReference(ctl.Scheme, crt) if err != nil { return nil, err } // If no events found, crtEvents would be nil and handled down the line in DescribeEvents crtEvents, err := clientSet.CoreV1().Events(crt.Namespace).Search(ctl.Scheme, crtRef) if err != nil { return nil, err } issuer, issuerKind, issuerError := getGenericIssuer(o.CMClient, ctx, crt) var issuerEvents *corev1.EventList if issuer != nil { issuerRef, err := reference.GetReference(ctl.Scheme, issuer) if err != nil { return nil, err } // If no events found, issuerEvents would be nil and handled down the line in DescribeEvents issuerEvents, err = clientSet.CoreV1().Events(issuer.GetNamespace()).Search(ctl.Scheme, issuerRef) if err != nil { return nil, err } } secret, secretErr := clientSet.CoreV1().Secrets(crt.Namespace).Get(ctx, crt.Spec.SecretName, metav1.GetOptions{}) if secretErr != nil { secretErr = fmt.Errorf("error when finding Secret %q: %w\n", crt.Spec.SecretName, secretErr) } var secretEvents *corev1.EventList if secret != nil { secretRef, err := reference.GetReference(ctl.Scheme, secret) if err != nil { return nil, err } // If no events found, secretEvents would be nil and handled down the line in DescribeEvents secretEvents, err = clientSet.CoreV1().Events(secret.Namespace).Search(ctl.Scheme, secretRef) if err != nil { return nil, err } } // TODO: What about timing issues? When I query condition it's not ready yet, but then looking for cr it's finished and deleted // Try find the CertificateRequest that is owned by crt and has the correct revision req, reqErr := findMatchingCR(o.CMClient, ctx, crt) if reqErr != nil { reqErr = fmt.Errorf("error when finding CertificateRequest: %w\n", reqErr) } else if req == nil { reqErr = errors.New("No CertificateRequest found for this Certificate\n") } var reqEvents *corev1.EventList if req != nil { reqRef, err := reference.GetReference(ctl.Scheme, req) if err != nil { return nil, err } // If no events found, reqEvents would be nil and handled down the line in DescribeEvents reqEvents, err = clientSet.CoreV1().Events(req.Namespace).Search(ctl.Scheme, reqRef) if err != nil { return nil, err } } var ( order *cmacme.Order orderErr error challenges []*cmacme.Challenge challengeErr error ) // Nothing to output about Order and Challenge if no CR or not ACME Issuer if req != nil && issuer != nil && issuer.GetSpec().ACME != nil { // Get Order order, orderErr = findMatchingOrder(o.CMClient, ctx, req) if orderErr != nil { orderErr = fmt.Errorf("error when finding Order: %w\n", orderErr) } else if order == nil { orderErr = errors.New("No Order found for this Certificate\n") } if order != nil { challenges, challengeErr = findMatchingChallenges(o.CMClient, ctx, order) if challengeErr != nil { challengeErr = fmt.Errorf("error when finding Challenges: %w\n", challengeErr) } else if len(challenges) == 0 { challengeErr = errors.New("No Challenges found for this Certificate\n") } } } return &Data{ Certificate: crt, CrtEvents: crtEvents, Issuer: issuer, IssuerKind: issuerKind, IssuerError: issuerError, IssuerEvents: issuerEvents, Secret: secret, SecretError: secretErr, SecretEvents: secretEvents, Req: req, ReqError: reqErr, ReqEvents: reqEvents, Order: order, OrderError: orderErr, Challenges: challenges, ChallengeErr: challengeErr, }, nil } // StatusFromResources takes in a Data struct and returns a CertificateStatus built using // the information in data. func StatusFromResources(data *Data) *CertificateStatus { return newCertificateStatusFromCert(data.Certificate). withEvents(data.CrtEvents). withGenericIssuer(data.Issuer, data.IssuerKind, data.IssuerEvents, data.IssuerError). withSecret(data.Secret, data.SecretEvents, data.SecretError). withCR(data.Req, data.ReqEvents, data.ReqError). withOrder(data.Order, data.OrderError). withChallenges(data.Challenges, data.ChallengeErr) } // formatStringSlice takes in a string slice and formats the contents of the slice // into a single string where each element of the slice is prefixed with "- " and on a new line func formatStringSlice(strings []string) string { result := "" for _, str := range strings { result += "- " + str + "\n" } return result } // formatTimeString returns the time as a string // If nil, return "<none>" func formatTimeString(t *metav1.Time) string { if t == nil { return "<none>" } return t.Time.Format(time.RFC3339) } // findMatchingCR tries to find a CertificateRequest that is owned by crt and has the correct revision annotated from reqs. // If none found returns nil // If one found returns the CR // If multiple found or error occurs when listing CRs, returns error func findMatchingCR(cmClient cmclient.Interface, ctx context.Context, crt *cmapi.Certificate) (*cmapi.CertificateRequest, error) { reqs, err := cmClient.CertmanagerV1().CertificateRequests(crt.Namespace).List(ctx, metav1.ListOptions{}) if err != nil { return nil, fmt.Errorf("error when listing CertificateRequest resources: %w", err) } possibleMatches := []*cmapi.CertificateRequest{} // CertificateRequest revisions begin from 1. // If no revision is set on the Certificate then assume the revision on the CertificateRequest should be 1. // If revision is set on the Certificate then revision on the CertificateRequest should be crt.Status.Revision + 1. nextRevision := 1 if crt.Status.Revision != nil { nextRevision = *crt.Status.Revision + 1 } for _, req := range reqs.Items { // #nosec G601 -- False positive. See https://github.com/golang/go/discussions/56010 if predicate.CertificateRequestRevision(nextRevision)(&req) && predicate.ResourceOwnedBy(crt)(&req) { possibleMatches = append(possibleMatches, req.DeepCopy()) } } if len(possibleMatches) < 1 { return nil, nil } else if len(possibleMatches) == 1 { return possibleMatches[0], nil } else { return nil, errors.New("found multiple certificate requests with expected revision and owner") } } // findMatchingOrder tries to find an Order that is owned by req. // If none found returns nil // If one found returns the Order // If multiple found or error occurs when listing Orders, returns error func findMatchingOrder(cmClient cmclient.Interface, ctx context.Context, req *cmapi.CertificateRequest) (*cmacme.Order, error) { orders, err := cmClient.AcmeV1().Orders(req.Namespace).List(ctx, metav1.ListOptions{}) if err != nil { return nil, err } possibleMatches := []*cmacme.Order{} for _, order := range orders.Items { // #nosec G601 -- False positive. See https://github.com/golang/go/discussions/56010 if predicate.ResourceOwnedBy(req)(&order) { possibleMatches = append(possibleMatches, order.DeepCopy()) } } if len(possibleMatches) < 1 { return nil, nil } else if len(possibleMatches) == 1 { return possibleMatches[0], nil } else { return nil, fmt.Errorf("found multiple orders owned by CertificateRequest %s", req.Name) } } func getGenericIssuer(cmClient cmclient.Interface, ctx context.Context, crt *cmapi.Certificate) (cmapi.GenericIssuer, string, error) { issuerKind := crt.Spec.IssuerRef.Kind if issuerKind == "" { issuerKind = "Issuer" } if crt.Spec.IssuerRef.Group != "cert-manager.io" && crt.Spec.IssuerRef.Group != "" { // TODO: Support Issuers/ClusterIssuers from other groups as well return nil, "", fmt.Errorf("The %s %q is not of the group cert-manager.io, this command currently does not support third party issuers.\nTo get more information about %q, try 'kubectl describe'\n", issuerKind, crt.Spec.IssuerRef.Name, crt.Spec.IssuerRef.Name) } else if issuerKind == "Issuer" { issuer, issuerErr := cmClient.CertmanagerV1().Issuers(crt.Namespace).Get(ctx, crt.Spec.IssuerRef.Name, metav1.GetOptions{}) if issuerErr != nil { issuerErr = fmt.Errorf("error when getting Issuer: %v\n", issuerErr) } return issuer, issuerKind, issuerErr } else { // ClusterIssuer clusterIssuer, issuerErr := cmClient.CertmanagerV1().ClusterIssuers().Get(ctx, crt.Spec.IssuerRef.Name, metav1.GetOptions{}) if issuerErr != nil { issuerErr = fmt.Errorf("error when getting ClusterIssuer: %v\n", issuerErr) } return clusterIssuer, issuerKind, issuerErr } } // findMatchingChallenges tries to find Challenges that are owned by order. // If none found returns empty slice. func findMatchingChallenges(cmClient cmclient.Interface, ctx context.Context, order *cmacme.Order) ([]*cmacme.Challenge, error) { challenges, err := cmClient.AcmeV1().Challenges(order.Namespace).List(ctx, metav1.ListOptions{}) if err != nil { return nil, err } possibleMatches := []*cmacme.Challenge{} for _, challenge := range challenges.Items { // #nosec G601 -- False positive. See https://github.com/golang/go/discussions/56010 if predicate.ResourceOwnedBy(order)(&challenge) { possibleMatches = append(possibleMatches, challenge.DeepCopy()) } } return possibleMatches, nil } 0707010000003F000081A4000000000000000000000001662A23E400003E1A000000000000000000000000000000000000003F00000000cert-manager-1.14.5/pkg/status/certificate/certificate_test.go/* Copyright 2020 The cert-manager 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 certificate import ( "crypto/x509" "errors" "math/big" "strings" "testing" "time" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cmacme "github.com/cert-manager/cert-manager/pkg/apis/acme/v1" cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" "github.com/cert-manager/cert-manager/test/unit/gen" ) func TestFormatStringSlice(t *testing.T) { tests := map[string]struct { slice []string expOutput string }{ // Newlines are part of the expected output "Empty slice returns empty string": { slice: []string{}, expOutput: ``, }, "Slice with one element returns string with one line": { slice: []string{"hello"}, expOutput: `- hello `, }, "Slice with multiple elements returns string with multiple lines": { slice: []string{"hello", "World", "another line"}, expOutput: `- hello - World - another line `, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { if actualOutput := formatStringSlice(test.slice); actualOutput != test.expOutput { t.Errorf("Unexpected output; expected: \n%s\nactual: \n%s", test.expOutput, actualOutput) } }) } } func TestCRInfoString(t *testing.T) { tests := map[string]struct { cr *cmapi.CertificateRequest err error expOutput string }{ // Newlines are part of the expected output "Nil pointer output correct": { cr: nil, err: errors.New("No CertificateRequest found for this Certificate\n"), expOutput: `No CertificateRequest found for this Certificate `, }, "CR with no condition output correct": { cr: &cmapi.CertificateRequest{Status: cmapi.CertificateRequestStatus{Conditions: []cmapi.CertificateRequestCondition{}}}, expOutput: `CertificateRequest: Name: Namespace: Conditions: No Conditions set Events: <none> `, }, "CR with conditions output correct": { cr: &cmapi.CertificateRequest{ Status: cmapi.CertificateRequestStatus{ Conditions: []cmapi.CertificateRequestCondition{ {Type: cmapi.CertificateRequestConditionReady, Status: cmmeta.ConditionTrue, Message: "example"}, }}}, expOutput: `CertificateRequest: Name: Namespace: Conditions: Ready: True, Reason: , Message: example Events: <none> `, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { actualOutput := (&CertificateStatus{}).withCR(test.cr, nil, test.err).CRStatus.String() if strings.ReplaceAll(actualOutput, " \n", "\n") != strings.ReplaceAll(test.expOutput, " \n", "\n") { t.Errorf("Unexpected output; expected: \n%s\nactual: \n%s", test.expOutput, actualOutput) } }) } } func TestKeyUsageToString(t *testing.T) { tests := map[string]struct { usage x509.KeyUsage expOutput string }{ "no key usage set": { usage: x509.KeyUsage(0), expOutput: "", }, "key usage Digital Signature": { usage: x509.KeyUsageDigitalSignature, expOutput: "Digital Signature", }, "key usage Digital Signature and Data Encipherment": { usage: x509.KeyUsageDigitalSignature | x509.KeyUsageDataEncipherment, expOutput: "Digital Signature, Data Encipherment", }, "key usage with three usages is ordered": { usage: x509.KeyUsageDigitalSignature | x509.KeyUsageDataEncipherment | x509.KeyUsageContentCommitment, expOutput: "Digital Signature, Content Commitment, Data Encipherment", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { if actualOutput := keyUsageToString(test.usage); actualOutput != test.expOutput { t.Errorf("Unexpected output; expected: \n%s\nactual: \n%s", test.expOutput, actualOutput) } }) } } func TestExtKeyUsageToString(t *testing.T) { tests := map[string]struct { extUsage []x509.ExtKeyUsage expOutput string expError bool expErrorOutput string }{ "no extended key usage": { extUsage: []x509.ExtKeyUsage{}, expOutput: "", }, "extended key usage Any": { extUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, expOutput: "Any", }, "multiple extended key usages": { extUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageEmailProtection}, expOutput: "Client Authentication, Email Protection", }, "undefined extended key usage": { extUsage: []x509.ExtKeyUsage{x509.ExtKeyUsage(42)}, expOutput: "", expError: true, expErrorOutput: "error when converting Extended Usages to string: encountered unknown Extended Usage with code 42", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { actualOutput, err := extKeyUsageToString(test.extUsage) if err != nil { if !test.expError || test.expErrorOutput != err.Error() { t.Errorf("got unexpected error. This test expects an error: %t. expected error: %q, actual error: %q", test.expError, test.expErrorOutput, err.Error()) } } else if test.expError { t.Errorf("expects error: %q, but did not get any", test.expErrorOutput) } if actualOutput != test.expOutput { t.Errorf("Unexpected output; expected: \n%s\nactual: \n%s", test.expOutput, actualOutput) } }) } } func TestStatusFromResources(t *testing.T) { timestamp, err := time.Parse(time.RFC3339, "2020-09-16T09:26:18Z") if err != nil { t.Fatal(err) } tlsCrt := []byte(`-----BEGIN CERTIFICATE----- MIICyTCCAbGgAwIBAgIRAOL4jtyULBSEYyGdqQn9YzowDQYJKoZIhvcNAQELBQAw DzENMAsGA1UEAxMEdGVzdDAeFw0yMDA3MzAxNjExNDNaFw0yMDEwMjgxNjExNDNa MA8xDTALBgNVBAMTBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDdfNmjh5ag7f6U1hj1OAx/dEN9kQzPsSlBMXGb/Ho4k5iegrFd6w8JkYdCthFv lfg3bIhw5tCKaw1o57HnWKBKKGt7XpeIu1mEcv8pveMIPO7TZ4+oElgX880NfJmL DkjEcctEo/+FurudO1aEbNfbNWpzudYKj7gGtYshBytqaYt4/APqWARJBFCYVVys wexZ0fLi5cBD8H1bQ1Ec3OCr5Mrq9thAGkj+rVlgYR0AZVGa9+SCOj27t6YCmyzR AJSEQ35v58Zfxp5tNyYd6wcAswJ9YipnUXvwahF95PNlRmMhp3Eo15m9FxehcVXU BOfxykMwZN7onMhuHiiwiB+NAgMBAAGjIDAeMA4GA1UdDwEB/wQEAwIFoDAMBgNV HRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQALrnldWjTBTvV5WKapUHUG0rhA vp2Cf+5FsPw8vKScXp4L+wKGdPOjhHz6NOiw5wu8A0HxlVUFawRpagkjFkeTL78O 9ghBHLiqn9xNPIKC6ID3WpnN5terwQxQeO/M54sVMslUWCcZm9Pu4Eb//2e6wEdu eMmpfeISQmCsBC1CTmpxUjeUg5DEQ0X1TQykXq+bG2iso6RYPxZTFTHJFzXiDYEc /X7H+bOmpo/dMrXapwfvp2gD+BEq96iVpf/DBzGYNs/657LAHJ4YtxtAZCa1CK9G MA6koCR/K23HZfML8vT6lcHvQJp9XXaHRIe9NX/M/2f6VpfO7JjKWLou5k5a -----END CERTIFICATE-----`) serialNum, _ := new(big.Int).SetString("301696114246524167282555582613204853562", 10) ns := "ns1" dummyEventList := &corev1.EventList{ Items: []corev1.Event{{ Type: "type", Reason: "reason", Message: "message", }}, } tests := map[string]struct { inputData *Data expOutput *CertificateStatus }{ "Correct information extracted from Certificate resource": { inputData: &Data{ Certificate: gen.Certificate("test-crt", gen.SetCertificateNamespace(ns), gen.SetCertificateNotAfter(metav1.Time{Time: timestamp}), gen.SetCertificateNotBefore(metav1.Time{Time: timestamp}), gen.SetCertificateRenewalTime(metav1.Time{Time: timestamp}), gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue, Message: "Certificate is up to date and has not expired"}), gen.SetCertificateDNSNames("example.com"), ), CrtEvents: dummyEventList, }, expOutput: &CertificateStatus{ Name: "test-crt", Namespace: ns, CreationTime: metav1.Time{}, Conditions: []cmapi.CertificateCondition{{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue, Message: "Certificate is up to date and has not expired"}}, DNSNames: []string{"example.com"}, Events: dummyEventList, NotBefore: &metav1.Time{Time: timestamp}, NotAfter: &metav1.Time{Time: timestamp}, RenewalTime: &metav1.Time{Time: timestamp}, }, }, "Issuer correctly with Kind Issuer": { inputData: &Data{ Certificate: gen.Certificate("test-crt", gen.SetCertificateNamespace(ns)), Issuer: gen.Issuer("test-issuer"), IssuerKind: "Issuer", IssuerError: nil, IssuerEvents: dummyEventList, }, expOutput: &CertificateStatus{ Name: "test-crt", Namespace: ns, CreationTime: metav1.Time{}, IssuerStatus: &IssuerStatus{ Name: "test-issuer", Kind: "Issuer", Events: dummyEventList, }, }, }, "Issuer correctly with Kind ClusterIssuer": { inputData: &Data{ Certificate: gen.Certificate("test-crt", gen.SetCertificateNamespace(ns)), Issuer: gen.Issuer("test-clusterissuer"), IssuerKind: "ClusterIssuer", IssuerError: nil, IssuerEvents: dummyEventList, }, expOutput: &CertificateStatus{ Name: "test-crt", Namespace: ns, CreationTime: metav1.Time{}, IssuerStatus: &IssuerStatus{ Name: "test-clusterissuer", Kind: "ClusterIssuer", Events: dummyEventList, }, }, }, "Correct information extracted from Secret resource": { inputData: &Data{ Certificate: gen.Certificate("test-crt", gen.SetCertificateNamespace(ns)), Secret: gen.Secret("existing-tls-secret", gen.SetSecretNamespace(ns), gen.SetSecretData(map[string][]byte{"tls.crt": tlsCrt})), SecretError: nil, SecretEvents: dummyEventList, }, expOutput: &CertificateStatus{ Name: "test-crt", Namespace: ns, CreationTime: metav1.Time{}, SecretStatus: &SecretStatus{ Error: nil, Name: "existing-tls-secret", IssuerCountry: nil, IssuerOrganisation: nil, IssuerCommonName: "test", KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, ExtKeyUsage: nil, PublicKeyAlgorithm: x509.RSA, SignatureAlgorithm: x509.SHA256WithRSA, SubjectKeyId: nil, AuthorityKeyId: nil, SerialNumber: serialNum, Events: dummyEventList, }, }, }, "Correct information extracted from CR resource": { inputData: &Data{ Certificate: gen.Certificate("test-crt", gen.SetCertificateNamespace(ns)), Req: gen.CertificateRequest("test-req", gen.SetCertificateRequestNamespace(ns), gen.SetCertificateRequestStatusCondition(cmapi.CertificateRequestCondition{Type: cmapi.CertificateRequestConditionReady, Status: cmmeta.ConditionFalse, Reason: "Pending", Message: "Waiting on certificate issuance from order default/example-order: \"pending\""})), ReqError: nil, ReqEvents: dummyEventList, }, expOutput: &CertificateStatus{ Name: "test-crt", Namespace: ns, CreationTime: metav1.Time{}, CRStatus: &CRStatus{ Error: nil, Name: "test-req", Namespace: ns, Conditions: []cmapi.CertificateRequestCondition{{Type: cmapi.CertificateRequestConditionReady, Status: cmmeta.ConditionFalse, Reason: "Pending", Message: "Waiting on certificate issuance from order default/example-order: \"pending\""}}, Events: dummyEventList, }, }, }, "Correct information extracted from Order resource": { inputData: &Data{ Certificate: gen.Certificate("test-crt", gen.SetCertificateNamespace(ns)), Order: &cmacme.Order{ TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{Name: "example-order", Namespace: ns}, Spec: cmacme.OrderSpec{Request: []byte("dummyCSR"), DNSNames: []string{"www.example.com"}}, Status: cmacme.OrderStatus{}, }, OrderError: nil, }, expOutput: &CertificateStatus{ Name: "test-crt", Namespace: ns, CreationTime: metav1.Time{}, OrderStatus: &OrderStatus{ Error: nil, Name: "example-order", State: "", Reason: "", Authorizations: nil, FailureTime: nil, }, }, }, "Correct information extracted from Challenge resources": { inputData: &Data{ Certificate: gen.Certificate("test-crt", gen.SetCertificateNamespace(ns)), Challenges: []*cmacme.Challenge{ { TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{Name: "test-challenge1", Namespace: ns}, Spec: cmacme.ChallengeSpec{ Type: "HTTP-01", Token: "token", Key: "key", }, Status: cmacme.ChallengeStatus{ Processing: false, Presented: false, Reason: "reason", State: "state", }, }, { TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{Name: "test-challenge2", Namespace: ns}, Spec: cmacme.ChallengeSpec{ Type: "HTTP-01", Token: "token", Key: "key", }, Status: cmacme.ChallengeStatus{ Processing: false, Presented: false, Reason: "reason", State: "state", }, }, }, ChallengeErr: nil, }, expOutput: &CertificateStatus{ Name: "test-crt", Namespace: ns, CreationTime: metav1.Time{}, ChallengeStatusList: &ChallengeStatusList{ ChallengeStatuses: []*ChallengeStatus{ { Name: "test-challenge1", Type: "HTTP-01", Token: "token", Key: "key", State: "state", Reason: "reason", Processing: false, Presented: false, }, { Name: "test-challenge2", Type: "HTTP-01", Token: "token", Key: "key", State: "state", Reason: "reason", Processing: false, Presented: false, }, }, }, }, }, "When error, ignore rest of the info about the resource": { inputData: &Data{ Certificate: gen.Certificate("test-crt", gen.SetCertificateNamespace(ns)), CrtEvents: nil, Issuer: gen.Issuer("test-issuer"), IssuerKind: "", IssuerError: errors.New("dummy error"), IssuerEvents: dummyEventList, Secret: gen.Secret("test-secret"), SecretError: errors.New("dummy error"), SecretEvents: dummyEventList, Req: gen.CertificateRequest("test-req"), ReqError: errors.New("dummy error"), ReqEvents: dummyEventList, Order: &cmacme.Order{ ObjectMeta: metav1.ObjectMeta{Name: "test-order"}, }, OrderError: errors.New("dummy error"), Challenges: []*cmacme.Challenge{{ObjectMeta: metav1.ObjectMeta{Name: "test-challenge"}}}, ChallengeErr: errors.New("dummy error"), }, expOutput: &CertificateStatus{ Name: "test-crt", Namespace: ns, CreationTime: metav1.Time{}, IssuerStatus: &IssuerStatus{Error: errors.New("dummy error")}, SecretStatus: &SecretStatus{Error: errors.New("dummy error")}, CRStatus: &CRStatus{Error: errors.New("dummy error")}, OrderStatus: &OrderStatus{Error: errors.New("dummy error")}, ChallengeStatusList: &ChallengeStatusList{Error: errors.New("dummy error")}, }, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { got := StatusFromResources(test.inputData) assert.Equal(t, test.expOutput, got) }) } } 07070100000040000081A4000000000000000000000001662A23E40000412F000000000000000000000000000000000000003400000000cert-manager-1.14.5/pkg/status/certificate/types.go/* Copyright 2020 The cert-manager 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 certificate import ( "bytes" "crypto/x509" "encoding/hex" "fmt" "math/big" "strings" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/kubectl/pkg/describe" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/status/util" cmacme "github.com/cert-manager/cert-manager/pkg/apis/acme/v1" cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" "github.com/cert-manager/cert-manager/pkg/util/pki" ) type CertificateStatus struct { // Name of the Certificate resource Name string // Namespace of the Certificate resource Namespace string // Creation Time of Certificate resource CreationTime metav1.Time // Conditions of Certificate resource Conditions []cmapi.CertificateCondition // DNS Names of Certificate resource DNSNames []string // Events of Certificate resource Events *v1.EventList // Not Before of Certificate resource NotBefore *metav1.Time // Not After of Certificate resource NotAfter *metav1.Time // Renewal Time of Certificate resource RenewalTime *metav1.Time IssuerStatus *IssuerStatus SecretStatus *SecretStatus CRStatus *CRStatus OrderStatus *OrderStatus ChallengeStatusList *ChallengeStatusList } type IssuerStatus struct { // If Error is not nil, there was a problem getting the status of the Issuer/ClusterIssuer resource, // so the rest of the fields is unusable Error error // Name of the Issuer/ClusterIssuer resource Name string // Kind of the resource, can be Issuer or ClusterIssuer Kind string // Conditions of Issuer/ClusterIssuer resource Conditions []cmapi.IssuerCondition // Events of Issuer/ClusterIssuer resource Events *v1.EventList } type SecretStatus struct { // If Error is not nil, there was a problem getting the status of the Secret resource, // so the rest of the fields is unusable Error error // Name of the Secret resource Name string // Issuer Countries of the x509 certificate in the Secret IssuerCountry []string // Issuer Organisations of the x509 certificate in the Secret IssuerOrganisation []string // Issuer Common Name of the x509 certificate in the Secret IssuerCommonName string // Key Usage of the x509 certificate in the Secret KeyUsage x509.KeyUsage // Extended Key Usage of the x509 certificate in the Secret ExtKeyUsage []x509.ExtKeyUsage // Public Key Algorithm of the x509 certificate in the Secret PublicKeyAlgorithm x509.PublicKeyAlgorithm // Signature Algorithm of the x509 certificate in the Secret SignatureAlgorithm x509.SignatureAlgorithm // Subject Key Id of the x509 certificate in the Secret SubjectKeyId []byte // Authority Key Id of the x509 certificate in the Secret AuthorityKeyId []byte // Serial Number of the x509 certificate in the Secret SerialNumber *big.Int // Events of Secret resource Events *v1.EventList } type CRStatus struct { // If Error is not nil, there was a problem getting the status of the CertificateRequest resource, // so the rest of the fields is unusable Error error // Name of the CertificateRequest resource Name string // Namespace of the CertificateRequest resource Namespace string // Conditions of CertificateRequest resource Conditions []cmapi.CertificateRequestCondition // Events of CertificateRequest resource Events *v1.EventList } type OrderStatus struct { // If Error is not nil, there was a problem getting the status of the Order resource, // so the rest of the fields is unusable Error error // Name of the Order resource Name string // State of Order resource State cmacme.State // Reason why the Order resource is in its State Reason string // What authorizations must be completed to validate the DNS names specified on the Order Authorizations []cmacme.ACMEAuthorization // Time the Order failed FailureTime *metav1.Time } type ChallengeStatusList struct { // If Error is not nil, there was a problem getting the status of the Order resource, // so the rest of the fields is unusable Error error ChallengeStatuses []*ChallengeStatus } type ChallengeStatus struct { Name string Type cmacme.ACMEChallengeType Token string Key string State cmacme.State Reason string Processing bool Presented bool } func newCertificateStatusFromCert(crt *cmapi.Certificate) *CertificateStatus { if crt == nil { return nil } return &CertificateStatus{ Name: crt.Name, Namespace: crt.Namespace, CreationTime: crt.CreationTimestamp, Conditions: crt.Status.Conditions, DNSNames: crt.Spec.DNSNames, NotBefore: crt.Status.NotBefore, NotAfter: crt.Status.NotAfter, RenewalTime: crt.Status.RenewalTime} } func (status *CertificateStatus) withEvents(events *v1.EventList) *CertificateStatus { status.Events = events return status } func (status *CertificateStatus) withGenericIssuer(genericIssuer cmapi.GenericIssuer, issuerKind string, issuerEvents *v1.EventList, err error) *CertificateStatus { if err != nil { status.IssuerStatus = &IssuerStatus{Error: err} return status } if genericIssuer == nil { return status } if issuerKind == "ClusterIssuer" { status.IssuerStatus = &IssuerStatus{Name: genericIssuer.GetName(), Kind: "ClusterIssuer", Conditions: genericIssuer.GetStatus().Conditions, Events: issuerEvents} return status } status.IssuerStatus = &IssuerStatus{Name: genericIssuer.GetName(), Kind: "Issuer", Conditions: genericIssuer.GetStatus().Conditions, Events: issuerEvents} return status } func (status *CertificateStatus) withSecret(secret *v1.Secret, secretEvents *v1.EventList, err error) *CertificateStatus { if err != nil { status.SecretStatus = &SecretStatus{Error: err} return status } if secret == nil { return status } certData := secret.Data["tls.crt"] if len(certData) == 0 { status.SecretStatus = &SecretStatus{Error: fmt.Errorf("error: 'tls.crt' of Secret %q is not set\n", secret.Name)} return status } x509Cert, err := pki.DecodeX509CertificateBytes(certData) if err != nil { status.SecretStatus = &SecretStatus{Error: fmt.Errorf("error when parsing 'tls.crt' of Secret %q: %s\n", secret.Name, err)} return status } status.SecretStatus = &SecretStatus{Error: nil, Name: secret.Name, IssuerCountry: x509Cert.Issuer.Country, IssuerOrganisation: x509Cert.Issuer.Organization, IssuerCommonName: x509Cert.Issuer.CommonName, KeyUsage: x509Cert.KeyUsage, ExtKeyUsage: x509Cert.ExtKeyUsage, PublicKeyAlgorithm: x509Cert.PublicKeyAlgorithm, SignatureAlgorithm: x509Cert.SignatureAlgorithm, SubjectKeyId: x509Cert.SubjectKeyId, AuthorityKeyId: x509Cert.AuthorityKeyId, SerialNumber: x509Cert.SerialNumber, Events: secretEvents} return status } func (status *CertificateStatus) withCR(req *cmapi.CertificateRequest, events *v1.EventList, err error) *CertificateStatus { if err != nil { status.CRStatus = &CRStatus{Error: err} return status } if req == nil { return status } status.CRStatus = &CRStatus{Name: req.Name, Namespace: req.Namespace, Conditions: req.Status.Conditions, Events: events} return status } func (status *CertificateStatus) withOrder(order *cmacme.Order, err error) *CertificateStatus { if err != nil { status.OrderStatus = &OrderStatus{Error: err} return status } if order == nil { return status } status.OrderStatus = &OrderStatus{Name: order.Name, State: order.Status.State, Reason: order.Status.Reason, Authorizations: order.Status.Authorizations, FailureTime: order.Status.FailureTime} return status } func (status *CertificateStatus) withChallenges(challenges []*cmacme.Challenge, err error) *CertificateStatus { if err != nil { status.ChallengeStatusList = &ChallengeStatusList{Error: err} return status } if len(challenges) == 0 { return status } var list []*ChallengeStatus for _, challenge := range challenges { list = append(list, &ChallengeStatus{ Name: challenge.Name, Type: challenge.Spec.Type, Token: challenge.Spec.Token, Key: challenge.Spec.Key, State: challenge.Status.State, Reason: challenge.Status.Reason, Processing: challenge.Status.Processing, Presented: challenge.Status.Presented, }) } status.ChallengeStatusList = &ChallengeStatusList{ChallengeStatuses: list} return status } func (status *CertificateStatus) String() string { output := "" output += fmt.Sprintf("Name: %s\n", status.Name) output += fmt.Sprintf("Namespace: %s\n", status.Namespace) output += fmt.Sprintf("Created at: %s\n", formatTimeString(&status.CreationTime)) // Output one line about each type of Condition that is set. // Certificate can have multiple Conditions of different types set, e.g. "Ready" or "Issuing" conditionMsg := "" for _, con := range status.Conditions { conditionMsg += fmt.Sprintf(" %s: %s, Reason: %s, Message: %s\n", con.Type, con.Status, con.Reason, con.Message) } if conditionMsg == "" { conditionMsg = " No Conditions set\n" } output += fmt.Sprintf("Conditions:\n%s", conditionMsg) output += fmt.Sprintf("DNS Names:\n%s", formatStringSlice(status.DNSNames)) output += eventsToString(status.Events, 0) output += status.IssuerStatus.String() output += status.SecretStatus.String() output += fmt.Sprintf("Not Before: %s\n", formatTimeString(status.NotBefore)) output += fmt.Sprintf("Not After: %s\n", formatTimeString(status.NotAfter)) output += fmt.Sprintf("Renewal Time: %s\n", formatTimeString(status.RenewalTime)) output += status.CRStatus.String() // OrderStatus is nil is not found or Issuer/ClusterIssuer is not ACME Issuer if status.OrderStatus != nil { output += status.OrderStatus.String() } if status.ChallengeStatusList != nil { output += status.ChallengeStatusList.String() } return output } // String returns the information about the status of a Issuer/ClusterIssuer as a string to be printed as output func (issuerStatus *IssuerStatus) String() string { if issuerStatus.Error != nil { return issuerStatus.Error.Error() } issuerFormat := `Issuer: Name: %s Kind: %s Conditions: %s` conditionMsg := "" for _, con := range issuerStatus.Conditions { conditionMsg += fmt.Sprintf(" %s: %s, Reason: %s, Message: %s\n", con.Type, con.Status, con.Reason, con.Message) } if conditionMsg == "" { conditionMsg = " No Conditions set\n" } output := fmt.Sprintf(issuerFormat, issuerStatus.Name, issuerStatus.Kind, conditionMsg) output += eventsToString(issuerStatus.Events, 1) return output } // String returns the information about the status of a Secret as a string to be printed as output func (secretStatus *SecretStatus) String() string { if secretStatus.Error != nil { return secretStatus.Error.Error() } secretFormat := `Secret: Name: %s Issuer Country: %s Issuer Organisation: %s Issuer Common Name: %s Key Usage: %s Extended Key Usages: %s Public Key Algorithm: %s Signature Algorithm: %s Subject Key ID: %s Authority Key ID: %s Serial Number: %s ` extKeyUsageString, err := extKeyUsageToString(secretStatus.ExtKeyUsage) if err != nil { extKeyUsageString = err.Error() } output := fmt.Sprintf(secretFormat, secretStatus.Name, strings.Join(secretStatus.IssuerCountry, ", "), strings.Join(secretStatus.IssuerOrganisation, ", "), secretStatus.IssuerCommonName, keyUsageToString(secretStatus.KeyUsage), extKeyUsageString, secretStatus.PublicKeyAlgorithm, secretStatus.SignatureAlgorithm, hex.EncodeToString(secretStatus.SubjectKeyId), hex.EncodeToString(secretStatus.AuthorityKeyId), hex.EncodeToString(secretStatus.SerialNumber.Bytes())) output += eventsToString(secretStatus.Events, 1) return output } var ( keyUsageToStringMap = map[int]string{ 1: "Digital Signature", 2: "Content Commitment", 4: "Key Encipherment", 8: "Data Encipherment", 16: "Key Agreement", 32: "Cert Sign", 64: "CRL Sign", 128: "Encipher Only", 256: "Decipher Only", } keyUsagePossibleValues = []int{256, 128, 64, 32, 16, 8, 4, 2, 1} extKeyUsageStringValues = []string{"Any", "Server Authentication", "Client Authentication", "Code Signing", "Email Protection", "IPSEC End System", "IPSEC Tunnel", "IPSEC User", "Time Stamping", "OCSP Signing", "Microsoft Server Gated Crypto", "Netscape Server Gated Crypto", "Microsoft Commercial Code Signing", "Microsoft Kernel Code Signing", } ) func keyUsageToString(usage x509.KeyUsage) string { usageInt := int(usage) var usageStrings []string for _, val := range keyUsagePossibleValues { if usageInt >= val { usageInt -= val usageStrings = append(usageStrings, keyUsageToStringMap[val]) } if usageInt == 0 { break } } // Reversing because that's usually the order the usages are printed for i := 0; i < len(usageStrings)/2; i++ { opp := len(usageStrings) - 1 - i usageStrings[i], usageStrings[opp] = usageStrings[opp], usageStrings[i] } return strings.Join(usageStrings, ", ") } func extKeyUsageToString(extUsages []x509.ExtKeyUsage) (string, error) { var extUsageStrings []string for _, extUsage := range extUsages { if extUsage < 0 || int(extUsage) >= len(extKeyUsageStringValues) { return "", fmt.Errorf("error when converting Extended Usages to string: encountered unknown Extended Usage with code %d", extUsage) } extUsageStrings = append(extUsageStrings, extKeyUsageStringValues[extUsage]) } return strings.Join(extUsageStrings, ", "), nil } // String returns the information about the status of a CR as a string to be printed as output func (crStatus *CRStatus) String() string { if crStatus.Error != nil { return crStatus.Error.Error() } crFormat := ` Name: %s Namespace: %s Conditions: %s` conditionMsg := "" for _, con := range crStatus.Conditions { conditionMsg += fmt.Sprintf(" %s: %s, Reason: %s, Message: %s\n", con.Type, con.Status, con.Reason, con.Message) } if conditionMsg == "" { conditionMsg = " No Conditions set\n" } infos := fmt.Sprintf(crFormat, crStatus.Name, crStatus.Namespace, conditionMsg) infos = fmt.Sprintf("CertificateRequest:%s", infos) infos += eventsToString(crStatus.Events, 1) return infos } // String returns the information about the status of a CR as a string to be printed as output func (orderStatus *OrderStatus) String() string { if orderStatus.Error != nil { return orderStatus.Error.Error() } output := "Order:\n" output += fmt.Sprintf(" Name: %s\n", orderStatus.Name) output += fmt.Sprintf(" State: %s, Reason: %s\n", orderStatus.State, orderStatus.Reason) authString := "" for _, auth := range orderStatus.Authorizations { wildcardString := "nil (bool pointer not set)" if auth.Wildcard != nil { wildcardString = fmt.Sprintf("%t", *auth.Wildcard) } authString += fmt.Sprintf(" URL: %s, Identifier: %s, Initial State: %s, Wildcard: %s\n", auth.URL, auth.Identifier, auth.InitialState, wildcardString) } if authString == "" { output += " No Authorizations for this Order\n" } else { output += " Authorizations:\n" output += authString } if orderStatus.FailureTime != nil { output += fmt.Sprintf(" FailureTime: %s\n", formatTimeString(orderStatus.FailureTime)) } return output } func (c *ChallengeStatusList) String() string { if c.Error != nil { return c.Error.Error() } challengeStrings := []string{} for _, challengeStatus := range c.ChallengeStatuses { challengeStrings = append(challengeStrings, challengeStatus.String()) } output := "Challenges:\n" output += formatStringSlice(challengeStrings) return output } func (challengeStatus *ChallengeStatus) String() string { return fmt.Sprintf("Name: %s, Type: %s, Token: %s, Key: %s, State: %s, Reason: %s, Processing: %t, Presented: %t", challengeStatus.Name, challengeStatus.Type, challengeStatus.Token, challengeStatus.Key, challengeStatus.State, challengeStatus.Reason, challengeStatus.Processing, challengeStatus.Presented) } func eventsToString(events *v1.EventList, baseLevel int) string { var buf bytes.Buffer defer buf.Reset() tabWriter := util.NewTabWriter(&buf) prefixWriter := describe.NewPrefixWriter(tabWriter) util.DescribeEvents(events, prefixWriter, baseLevel) tabWriter.Flush() return buf.String() } 07070100000041000081A4000000000000000000000001662A23E40000046B000000000000000000000000000000000000002900000000cert-manager-1.14.5/pkg/status/status.go/* Copyright 2020 The cert-manager 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 status import ( "context" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/status/certificate" ) func NewCmdStatus(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { cmds := &cobra.Command{ Use: "status", Short: "Get details on current status of cert-manager resources", Long: `Get details on current status of cert-manager resources, e.g. Certificate`, } cmds.AddCommand(certificate.NewCmdStatusCert(ctx, ioStreams)) return cmds } 07070100000042000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002400000000cert-manager-1.14.5/pkg/status/util07070100000043000081A4000000000000000000000001662A23E400000C43000000000000000000000000000000000000002C00000000cert-manager-1.14.5/pkg/status/util/util.go/* Copyright 2020 The cert-manager 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 util import ( "fmt" "io" "sort" "strings" "text/tabwriter" "time" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/duration" "k8s.io/kubectl/pkg/describe" "k8s.io/kubectl/pkg/util/event" ) // This file contains functions that are copied from "k8s.io/kubectl/pkg/describe". // DescribeEvents was slightly modified. The other functions are copied over. // The purpose of this is to be able to reuse the PrefixWriter interface defined in the describe package, // and because we need to indent certain lines differently than the original function. // DescribeEvents writes a formatted string of the Events in el with PrefixWriter. // The intended use is for w to be created with a *tabWriter.Writer underneath, and the caller // of DescribeEvents would need to call Flush() on that *tabWriter.Writer to actually print the output. func DescribeEvents(el *corev1.EventList, w describe.PrefixWriter, baseLevel int) { if el == nil || len(el.Items) == 0 { w.Write(baseLevel, "Events:\t<none>\n") w.Flush() return } w.Flush() sort.Sort(event.SortableEvents(el.Items)) w.Write(baseLevel, "Events:\n") w.Write(baseLevel+1, "Type\tReason\tAge\tFrom\tMessage\n") w.Write(baseLevel+1, "----\t------\t----\t----\t-------\n") for _, e := range el.Items { var interval string if e.Count > 1 { interval = fmt.Sprintf("%s (x%d over %s)", translateTimestampSince(e.LastTimestamp), e.Count, translateTimestampSince(e.FirstTimestamp)) } else { interval = translateTimestampSince(e.FirstTimestamp) } w.Write(baseLevel+1, "%v\t%v\t%s\t%v\t%v\n", e.Type, e.Reason, interval, formatEventSource(e.Source), strings.TrimSpace(e.Message), ) } w.Flush() } // NewTabWriter returns a *tabwriter.Writer with fixed parameters to be used in the status command func NewTabWriter(writer io.Writer) *tabwriter.Writer { return tabwriter.NewWriter(writer, 0, 8, 2, ' ', 0) } // formatEventSource formats EventSource as a comma separated string excluding Host when empty func formatEventSource(es corev1.EventSource) string { EventSourceString := []string{es.Component} if len(es.Host) > 0 { EventSourceString = append(EventSourceString, es.Host) } return strings.Join(EventSourceString, ", ") } // translateTimestampSince returns the elapsed time since timestamp in // human-readable approximation. func translateTimestampSince(timestamp metav1.Time) string { if timestamp.IsZero() { return "<unknown>" } return duration.HumanDuration(time.Since(timestamp.Time)) } 07070100000044000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002200000000cert-manager-1.14.5/pkg/uninstall07070100000045000081A4000000000000000000000001662A23E400000E5C000000000000000000000000000000000000002F00000000cert-manager-1.14.5/pkg/uninstall/uninstall.go/* Copyright 2022 The cert-manager 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 uninstall import ( "context" "errors" "fmt" "time" "github.com/spf13/cobra" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/storage/driver" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/install/helm" ) type options struct { settings *helm.NormalisedEnvSettings client *action.Uninstall releaseName string disableHooks bool dryRun bool wait bool genericclioptions.IOStreams } const ( releaseName = "cert-manager" ) func description() string { return build.WithTemplate(`This command uninstalls any Helm-managed release of cert-manager. The CRDs will be deleted if you installed cert-manager with the option --set CRDs=true. Most of the features supported by 'helm uninstall' are also supported by this command. Some example uses: $ {{.BuildName}} x uninstall or $ {{.BuildName}} x uninstall --namespace my-cert-manager or $ {{.BuildName}} x uninstall --dry-run or $ {{.BuildName}} x uninstall --no-hooks `) } func NewCmd(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { settings := helm.NewNormalisedEnvSettings() options := options{ settings: settings, client: action.NewUninstall(settings.ActionConfiguration), IOStreams: ioStreams, } cmd := &cobra.Command{ Use: "uninstall", Short: "Uninstall cert-manager", Long: description(), RunE: func(cmd *cobra.Command, args []string) error { res, err := run(ctx, options) if err != nil { return err } if options.dryRun { fmt.Fprintf(ioStreams.Out, "%s", res.Release.Manifest) return nil } return nil }, SilenceUsage: true, SilenceErrors: true, } settings.Setup(ctx, cmd) cmd.Flags().DurationVar(&options.client.Timeout, "timeout", 5*time.Minute, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") cmd.Flags().StringVar(&options.releaseName, "release-name", releaseName, "name of the helm release to uninstall") cmd.Flags().BoolVar(&options.wait, "wait", true, "if set, will wait until all the resources are deleted before returning. It will wait for as long as --timeout") cmd.Flags().BoolVar(&options.dryRun, "dry-run", false, "simulate uninstall and output manifests to be deleted") cmd.Flags().BoolVar(&options.disableHooks, "no-hooks", false, "prevent hooks from running during uninstallation (pre- and post-uninstall hooks)") return cmd } // run assumes cert-manager was installed as a Helm release named cert-manager. // this is not configurable to avoid uninstalling non-cert-manager releases. func run(ctx context.Context, o options) (*release.UninstallReleaseResponse, error) { o.client.DisableHooks = o.disableHooks o.client.DryRun = o.dryRun o.client.Wait = o.wait res, err := o.client.Run(o.releaseName) if errors.Is(err, driver.ErrReleaseNotFound) { return nil, fmt.Errorf("release %v not found in namespace %v, did you use the correct namespace?", releaseName, o.settings.Namespace()) } return res, nil } 07070100000046000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002000000000cert-manager-1.14.5/pkg/upgrade07070100000047000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000003200000000cert-manager-1.14.5/pkg/upgrade/migrateapiversion07070100000048000081A4000000000000000000000001662A23E4000012E4000000000000000000000000000000000000003D00000000cert-manager-1.14.5/pkg/upgrade/migrateapiversion/command.go/* Copyright 2022 The cert-manager 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 migrateapiversion import ( "context" "github.com/spf13/cobra" apiextinstall "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install" "k8s.io/apimachinery/pkg/runtime" "k8s.io/cli-runtime/pkg/genericclioptions" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/factory" acmeinstall "github.com/cert-manager/cert-manager/internal/apis/acme/install" cminstall "github.com/cert-manager/cert-manager/internal/apis/certmanager/install" ) var ( long = templates.LongDesc(i18n.T(` Ensures resources in your Kubernetes cluster are persisted in the v1 API version. This must be run prior to upgrading to ensure your cluster is ready to upgrade to cert-manager v1.7 and beyond. This command must be run with a cluster running cert-manager v1.0 or greater.`)) example = templates.Examples(i18n.T(build.WithTemplate(` # Check the cert-manager installation is ready to be upgraded to v1.7 and perform necessary migrations # to ensure that the kube-apiserver has stored only v1 API versions. {{.BuildName}} upgrade migrate-api-version # Force migrations to be run, even if the 'status.storedVersion' field on the CRDs does not contain # old, deprecated API versions. # This should only be used if you have manually edited/patched the CRDs already. # It will force a read and a write of ALL cert-manager resources unconditionally. {{.BuildName}} upgrade migrate-api-version --skip-stored-version-check `))) ) // Options is a struct to support renew command type Options struct { genericclioptions.IOStreams *factory.Factory client client.Client skipStoredVersionCheck bool qps float32 burst int } // NewOptions returns initialized Options func NewOptions(ioStreams genericclioptions.IOStreams) *Options { return &Options{ IOStreams: ioStreams, } } // NewCmdMigrate returns a cobra command for updating resources in an apiserver // to force a new storage version to be used. func NewCmdMigrate(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { o := NewOptions(ioStreams) cmd := &cobra.Command{ Use: "migrate-api-version", Short: "Migrate all existing persisted cert-manager resources to the v1 API version", Long: long, Example: example, Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Validate(args)) cmdutil.CheckErr(o.Complete()) cmdutil.CheckErr(o.Run(ctx, args)) }, } cmd.Flags().BoolVar(&o.skipStoredVersionCheck, "skip-stored-version-check", o.skipStoredVersionCheck, ""+ "If true, all resources will be read and written regardless of the 'status.storedVersions' on the CRD resource. "+ "Use this mode if you have previously manually modified the 'status.storedVersions' field on CRD resources.") cmd.Flags().Float32Var(&o.qps, "qps", 5, "Indicates the maximum QPS to the apiserver from the client.") cmd.Flags().IntVar(&o.burst, "burst", 10, "Maximum burst value for queries set to the apiserver from the client.") o.Factory = factory.New(ctx, cmd) return cmd } // Validate validates the provided options func (o *Options) Validate(_ []string) error { return nil } // Complete takes the command arguments and factory and infers any remaining options. func (o *Options) Complete() error { var err error scheme := runtime.NewScheme() apiextinstall.Install(scheme) cminstall.Install(scheme) acmeinstall.Install(scheme) if o.qps != 0 { o.RESTConfig.QPS = o.qps } if o.burst != 0 { o.RESTConfig.Burst = o.burst } o.client, err = client.New(o.RESTConfig, client.Options{Scheme: scheme}) if err != nil { return err } return nil } // Run executes renew command func (o *Options) Run(ctx context.Context, args []string) error { _, err := NewMigrator(o.client, o.skipStoredVersionCheck, o.Out, o.ErrOut).Run(ctx, "v1", []string{ "certificates.cert-manager.io", "certificaterequests.cert-manager.io", "issuers.cert-manager.io", "clusterissuers.cert-manager.io", "orders.acme.cert-manager.io", "challenges.acme.cert-manager.io", }) return err } 07070100000049000081A4000000000000000000000001662A23E400002DFC000000000000000000000000000000000000003E00000000cert-manager-1.14.5/pkg/upgrade/migrateapiversion/migrator.go/* Copyright 2022 The cert-manager 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 migrateapiversion import ( "context" "fmt" "io" "time" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/util/retry" apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) type Migrator struct { // Client used for API interactions Client client.Client // If true, skip checking the 'status.storedVersion' before running the migration. // By default, migration will only be run if the CRD contains storedVersions other // than the desired target version. SkipStoredVersionCheck bool // Writers to write informational & error messages to Out, ErrOut io.Writer } // NewMigrator creates a new migrator with the given API client. // If either of out or errOut are nil, log messages will be discarded. func NewMigrator(client client.Client, skipStoredVersionCheck bool, out, errOut io.Writer) *Migrator { if out == nil { out = io.Discard } if errOut == nil { errOut = io.Discard } return &Migrator{ Client: client, SkipStoredVersionCheck: skipStoredVersionCheck, Out: out, ErrOut: errOut, } } // Run begins the migration of all the named CRDs. // It will attempt to migrate all resources defined as part of these CRDs to the // given 'targetVersion', and after completion will update the `status.storedVersions` // field on the corresponding CRD version to only contain the given targetVersion. // Returns 'true' if a migration was actually performed, and false if migration was not required. func (m *Migrator) Run(ctx context.Context, targetVersion string, names []string) (bool, error) { fmt.Fprintf(m.Out, "Checking all CustomResourceDefinitions have storage version set to \"%s\"\n", targetVersion) allTargetVersion, allCRDs, err := m.ensureCRDStorageVersionEquals(ctx, targetVersion, names) if err != nil { return false, err } if !allTargetVersion { fmt.Fprintf(m.ErrOut, "It looks like you are running a version of cert-manager that does not set the storage version of CRDs to %q. You MUST upgrade to cert-manager v1.0-v1.6 before migrating resources for v1.7.\n", targetVersion) return false, fmt.Errorf("preflight checks failed") } fmt.Fprintf(m.Out, "All CustomResourceDefinitions have %q configured as the storage version.\n", targetVersion) crdsRequiringMigration := allCRDs if !m.SkipStoredVersionCheck { fmt.Fprintf(m.Out, "Looking for CRDs that contain resources that require migrating to %q...\n", targetVersion) crdsRequiringMigration, err = m.discoverCRDsRequiringMigration(ctx, targetVersion, names) if err != nil { fmt.Fprintf(m.ErrOut, "Failed to determine resource types that require migration: %v\n", err) return false, err } if len(crdsRequiringMigration) == 0 { fmt.Fprintln(m.Out, "Nothing to do. cert-manager CRDs do not have \"status.storedVersions\" containing old API versions. You may proceed to upgrade to cert-manager v1.7.") return false, nil } } else { fmt.Fprintln(m.Out, "Forcing migration of all CRD resources as --skip-stored-version-check=true") } fmt.Fprintf(m.Out, "Found %d resource types that require migration:\n", len(crdsRequiringMigration)) for _, crd := range crdsRequiringMigration { fmt.Fprintf(m.Out, " - %s (%s)\n", crd.Name, crd.Spec.Names.Kind) } for _, crd := range crdsRequiringMigration { if err := m.migrateResourcesForCRD(ctx, crd); err != nil { fmt.Fprintf(m.ErrOut, "Failed to migrate resource: %v\n", err) return false, err } } fmt.Fprintf(m.Out, "Patching CRD resources to set \"status.storedVersions\" to %q...\n", targetVersion) if err := m.patchCRDStoredVersions(ctx, crdsRequiringMigration); err != nil { fmt.Fprintf(m.ErrOut, "Failed to patch \"status.storedVersions\" field: %v\n", err) return false, err } fmt.Fprintln(m.Out, "Successfully migrated all cert-manager resource types. It is now safe to upgrade to cert-manager v1.7.") return true, nil } func (m *Migrator) ensureCRDStorageVersionEquals(ctx context.Context, vers string, names []string) (bool, []*apiext.CustomResourceDefinition, error) { var crds []*apiext.CustomResourceDefinition for _, crdName := range names { crd := &apiext.CustomResourceDefinition{} if err := m.Client.Get(ctx, client.ObjectKey{Name: crdName}, crd); err != nil { return false, nil, err } // Discover the storage version storageVersion := storageVersionForCRD(crd) if storageVersion != vers { fmt.Fprintf(m.Out, "CustomResourceDefinition object %q has storage version set to %q.\n", crdName, storageVersion) return false, nil, nil } crds = append(crds, crd) } return true, crds, nil } func (m *Migrator) discoverCRDsRequiringMigration(ctx context.Context, desiredStorageVersion string, names []string) ([]*apiext.CustomResourceDefinition, error) { var requireMigration []*apiext.CustomResourceDefinition for _, name := range names { crd := &apiext.CustomResourceDefinition{} if err := m.Client.Get(ctx, client.ObjectKey{Name: name}, crd); err != nil { return nil, err } // If no versions are stored, there's nothing to migrate. if len(crd.Status.StoredVersions) == 0 { continue } // If more than one entry exists in `storedVersions` OR if the only element in there is not // the desired version, perform a migration. if len(crd.Status.StoredVersions) > 1 || crd.Status.StoredVersions[0] != desiredStorageVersion { requireMigration = append(requireMigration, crd) } } return requireMigration, nil } func (m *Migrator) migrateResourcesForCRD(ctx context.Context, crd *apiext.CustomResourceDefinition) error { startTime := time.Now() timeFormat := "15:04:05" fmt.Fprintf(m.Out, "Migrating %q objects in group %q - this may take a while (started at %s)...\n", crd.Spec.Names.Kind, crd.Spec.Group, startTime.Format(timeFormat)) list := &unstructured.UnstructuredList{} list.SetGroupVersionKind(schema.GroupVersionKind{ Group: crd.Spec.Group, Version: storageVersionForCRD(crd), Kind: crd.Spec.Names.ListKind, }) if err := m.Client.List(ctx, list); err != nil { return err } fmt.Fprintf(m.Out, " %d resources to migrate...\n", len(list.Items)) for _, obj := range list.Items { // retry on any kind of error to handle cases where e.g. the network connection to the apiserver fails if err := retry.OnError(wait.Backoff{ Duration: time.Second, // wait 1s between attempts Steps: 3, // allow up to 3 attempts per object }, func(err error) bool { // Retry on any errors that are not otherwise skipped/ignored return handleUpdateErr(err) != nil }, func() error { return m.Client.Update(ctx, &obj) // #nosec G601 -- False positive. See https://github.com/golang/go/discussions/56010 }); handleUpdateErr(err) != nil { return err } } // add 500ms to the duration to ensure we always round up duration := time.Now().Sub(startTime) + (time.Millisecond * 500) fmt.Fprintf(m.Out, " Successfully migrated %d %s objects in %s\n", len(list.Items), crd.Spec.Names.Kind, duration.Round(time.Second)) return nil } // patchCRDStoredVersions will patch the `status.storedVersions` field of all passed in CRDs to be // set to an array containing JUST the current storage version. // This is only safe to run after a successful migration (i.e. a read/write of all resources of the given CRD type). func (m *Migrator) patchCRDStoredVersions(ctx context.Context, crds []*apiext.CustomResourceDefinition) error { for _, crd := range crds { // fetch a fresh copy of the CRD to avoid any conflict errors freshCRD := &apiext.CustomResourceDefinition{} if err := m.Client.Get(ctx, client.ObjectKey{Name: crd.Name}, freshCRD); err != nil { return err } // Check the latest copy of the CRD to ensure that: // 1) the storage version is the same as it was at the start of the migration // 2) the status.storedVersion field has not changed, and if it has, it has only added the new/desired storage version // This helps to avoid cases where the storage version was changed by a third-party midway through the migration, // which could lead to corrupted apiservers when we patch the status.storedVersions field below. expectedStorageVersion := storageVersionForCRD(crd) if storageVersionForCRD(freshCRD) != expectedStorageVersion { return newUnexpectedChangeError(crd) } newlyAddedVersions := storedVersionsAdded(crd, freshCRD) if newlyAddedVersions.Len() != 0 && !newlyAddedVersions.Equal(sets.New[string](expectedStorageVersion)) { return newUnexpectedChangeError(crd) } // Set the `status.storedVersions` field to the target storage version freshCRD.Status.StoredVersions = []string{storageVersionForCRD(crd)} if err := m.Client.Status().Update(ctx, freshCRD); err != nil { return err } } return nil } // storageVersionForCRD discovers the storage version for a given CRD. func storageVersionForCRD(crd *apiext.CustomResourceDefinition) string { storageVersion := "" for _, v := range crd.Spec.Versions { if v.Storage { storageVersion = v.Name break } } return storageVersion } // storedVersionsAdded returns a list of any versions added to the `status.storedVersions` field on // a CRD resource. func storedVersionsAdded(old, new *apiext.CustomResourceDefinition) sets.Set[string] { oldStoredVersions := sets.New[string](old.Status.StoredVersions...) newStoredVersions := sets.New[string](new.Status.StoredVersions...) return newStoredVersions.Difference(oldStoredVersions) } // newUnexpectedChangeError creates a new 'error' that informs users that a change to the CRDs // was detected during the migration process and so the migration must be re-run. func newUnexpectedChangeError(crd *apiext.CustomResourceDefinition) error { errorFmt := "" + "The CRD %q unexpectedly changed during the migration. " + "This means that either an object was persisted in a non-storage version during the migration, " + "or the storage version was changed by someone else (or some automated deployment tooling) whilst the migration " + "was in progress.\n\n" + "All automated deployment tooling should be in a stable state (i.e. no upgrades to cert-manager CRDs should be" + "in progress whilst the migration is running).\n\n" + "Please ensure no changes to the CRDs are made during the migration process and re-run the migration until you" + "no longer see this message." return fmt.Errorf(errorFmt, crd.Name) } // handleUpdateErr will absorb certain types of errors that we know can be skipped/passed on // during a migration of a particular object. func handleUpdateErr(err error) error { if err == nil { return nil } // If the resource no longer exists, don't return the error as the object no longer // needs updating to the new API version. if apierrors.IsNotFound(err) { return nil } // If there was a conflict, another client must have written the object already which // means we don't need to force an update. if apierrors.IsConflict(err) { return nil } return err } 0707010000004A000081A4000000000000000000000001662A23E40000046A000000000000000000000000000000000000002B00000000cert-manager-1.14.5/pkg/upgrade/upgrade.go/* Copyright 2022 The cert-manager 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 upgrade import ( "context" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/upgrade/migrateapiversion" ) func NewCmdUpgrade(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { cmds := &cobra.Command{ Use: "upgrade", Short: "Tools that assist in upgrading cert-manager", Long: `Note: this command does NOT actually upgrade cert-manager installations`, } cmds.AddCommand(migrateapiversion.NewCmdMigrate(ctx, ioStreams)) return cmds } 0707010000004B000041ED000000000000000000000002662A23E400000000000000000000000000000000000000000000002000000000cert-manager-1.14.5/pkg/version0707010000004C000081A4000000000000000000000001662A23E40000160B000000000000000000000000000000000000002B00000000cert-manager-1.14.5/pkg/version/version.go/* Copyright 2020 The cert-manager 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 version import ( "context" "encoding/json" "errors" "fmt" "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/runtime" "k8s.io/cli-runtime/pkg/genericclioptions" cmdutil "k8s.io/kubectl/pkg/cmd/util" "sigs.k8s.io/yaml" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/build" "github.com/cert-manager/cert-manager/cmd/ctl/pkg/factory" "github.com/cert-manager/cert-manager/pkg/util" "github.com/cert-manager/cert-manager/pkg/util/versionchecker" ) // Version is a struct for version information type Version struct { ClientVersion *util.Version `json:"clientVersion,omitempty"` ServerVersion *versionchecker.Version `json:"serverVersion,omitempty"` } // Options is a struct to support version command type Options struct { // If true, don't try to retrieve the installed version ClientOnly bool // If true, only prints the version number. Short bool // Output is the target output format for the version string. This may be of // value "", "json" or "yaml". Output string VersionChecker versionchecker.Interface genericclioptions.IOStreams *factory.Factory } // NewOptions returns initialized Options func NewOptions(ioStreams genericclioptions.IOStreams) *Options { return &Options{ IOStreams: ioStreams, } } func versionLong() string { return build.WithTemplate(`Print the cert-manager CLI version and the deployed cert-manager version. The CLI version is embedded in the binary and directly displayed. Determining the deployed cert-manager version is done by querying the cert-manger resources. First, the tool looks at the labels of the cert-manager CRD resources. Then, it searches for the labels of the resources related the the cert-manager webhook linked in the CRDs. It also tries to derive the version from the docker image tag of that webhook service. After gathering all this version information, the tool checks if all versions are the same and returns that version. If no version information is found or the found versions differ, an error will be displayed. The '--client' flag can be used to disable the logic that tries to determine the installed cert-manager version. Some example uses: $ {{.BuildName}} version or $ {{.BuildName}} version --client or $ {{.BuildName}} version --short or $ {{.BuildName}} version -o yaml `) } // NewCmdVersion returns a cobra command for fetching versions func NewCmdVersion(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { o := NewOptions(ioStreams) cmd := &cobra.Command{ Use: "version", Short: "Print the cert-manager CLI version and the deployed cert-manager version", Long: versionLong(), Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Validate()) cmdutil.CheckErr(o.Complete()) cmdutil.CheckErr(o.Run(ctx)) }, } cmd.Flags().BoolVar(&o.ClientOnly, "client", o.ClientOnly, "If true, shows client version only (no server required).") cmd.Flags().BoolVar(&o.Short, "short", o.Short, "If true, print just the version number.") cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "One of 'yaml' or 'json'.") o.Factory = factory.New(ctx, cmd) return cmd } // Validate validates the provided options func (o *Options) Validate() error { switch o.Output { case "", "yaml", "json": return nil default: return errors.New(`--output must be '', 'yaml' or 'json'`) } } // Complete takes the command arguments and factory and infers any remaining options. func (o *Options) Complete() error { if o.ClientOnly { return nil } versionChecker, err := versionchecker.New( o.RESTConfig, runtime.NewScheme(), ) if err != nil { return err } o.VersionChecker = versionChecker return nil } // Run executes version command func (o *Options) Run(ctx context.Context) error { var ( serverVersion *versionchecker.Version serverErr error versionInfo Version ) clientVersion := util.VersionInfo() versionInfo.ClientVersion = &clientVersion if !o.ClientOnly { serverVersion, serverErr = o.VersionChecker.Version(ctx) versionInfo.ServerVersion = serverVersion } switch o.Output { case "": if o.Short { fmt.Fprintf(o.Out, "Client Version: %s\n", clientVersion.GitVersion) if serverVersion != nil { fmt.Fprintf(o.Out, "Server Version: %s\n", serverVersion.Detected) } } else { fmt.Fprintf(o.Out, "Client Version: %s\n", fmt.Sprintf("%#v", clientVersion)) if serverVersion != nil { fmt.Fprintf(o.Out, "Server Version: %s\n", fmt.Sprintf("%#v", serverVersion)) } } case "yaml": marshalled, err := yaml.Marshal(&versionInfo) if err != nil { return err } fmt.Fprint(o.Out, string(marshalled)) case "json": marshalled, err := json.MarshalIndent(&versionInfo, "", " ") if err != nil { return err } fmt.Fprintln(o.Out, string(marshalled)) default: // There is a bug in the program if we hit this case. // However, we follow a policy of never panicking. return fmt.Errorf("VersionOptions were not validated: --output=%q should have been rejected", o.Output) } return serverErr } 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!665 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor