From 339820a3a9d928874c9761360f986780d8cfef59 Mon Sep 17 00:00:00 2001 From: Kevin Klopfenstein Date: Tue, 27 Dec 2022 15:04:18 +0100 Subject: [PATCH] init --- draft.sh | 233 +++++++ .dockerignore | 4 + .github/dependabot.yml | 16 + .gitignore | 22 + .golang-ci.yml | 26 + .goreleaser.yml | 130 ++++ .pre-commit-config.yaml | 13 + CODEOWNERS | 1 + Dockerfile | 11 + Makefile | 57 ++ README.md | 132 ++++ cosign.key | 11 + cosign.pub | 4 + example/configuration.yml | 16 + example/my-secrets.ejson | 10 + example/project.json | 7 + examples/basic/blu.ejson | 7 + examples/basic/cluster.vars | 3 + examples/basic/kustomization.yaml | 6 + examples/common/apps/dns-2.yaml | 33 + examples/common/apps/dns.yaml | 35 ++ examples/common/apps/kustomization.yaml | 5 + examples/common/apps/main.vars | 3 + examples/common/env/dev/kustomization.yaml | 5 + examples/common/env/dev/main.vars | 5 + examples/common/env/dev/secret-2.yaml | 6 + examples/common/env/dev/secret.yaml | 7 + examples/common/env/dev/secrets.ejson.old | 10 + examples/common/env/test/kustomization.yaml | 4 + examples/common/env/test/main.vars | 5 + examples/common/env/test/secrets.ejson.old | 10 + examples/kustomization.yaml | 4 + go.mod | 88 +++ go.sum | 654 ++++++++++++++++++++ pkg/config/config.go | 99 +++ pkg/tool/file.go | 75 +++ pkg/tool/merge.go | 74 +++ pkg/tool/render.go | 127 ++++ pkg/tool/types.go | 6 + pkg/utils/kustomize.go | 79 +++ pkg/wrapper/ejson/ejson.go | 130 ++++ subst/cmd/artifact.go | 21 + subst/cmd/artifact_build.go | 21 + subst/cmd/config.go | 34 + subst/cmd/discover.go | 35 ++ subst/cmd/doc.go | 31 + subst/cmd/render.go | 64 ++ subst/cmd/root.go | 60 ++ subst/cmd/version.go | 31 + subst/main.go | 9 + 50 files changed, 2479 insertions(+) create mode 100644 draft.sh create mode 100644 .dockerignore create mode 100644 .github/dependabot.yml create mode 100644 .gitignore create mode 100644 .golang-ci.yml create mode 100644 .goreleaser.yml create mode 100644 .pre-commit-config.yaml create mode 100644 CODEOWNERS create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 README.md create mode 100644 cosign.key create mode 100644 cosign.pub create mode 100644 example/configuration.yml create mode 100644 example/my-secrets.ejson create mode 100644 example/project.json create mode 100644 examples/basic/blu.ejson create mode 100644 examples/basic/cluster.vars create mode 100644 examples/basic/kustomization.yaml create mode 100644 examples/common/apps/dns-2.yaml create mode 100644 examples/common/apps/dns.yaml create mode 100644 examples/common/apps/kustomization.yaml create mode 100644 examples/common/apps/main.vars create mode 100644 examples/common/env/dev/kustomization.yaml create mode 100644 examples/common/env/dev/main.vars create mode 100644 examples/common/env/dev/secret-2.yaml create mode 100644 examples/common/env/dev/secret.yaml create mode 100644 examples/common/env/dev/secrets.ejson.old create mode 100644 examples/common/env/test/kustomization.yaml create mode 100644 examples/common/env/test/main.vars create mode 100644 examples/common/env/test/secrets.ejson.old create mode 100644 examples/kustomization.yaml create mode 100644 go.mod create mode 100644 go.sum create mode 100644 pkg/config/config.go create mode 100644 pkg/tool/file.go create mode 100644 pkg/tool/merge.go create mode 100644 pkg/tool/render.go create mode 100644 pkg/tool/types.go create mode 100644 pkg/utils/kustomize.go create mode 100644 pkg/wrapper/ejson/ejson.go create mode 100644 subst/cmd/artifact.go create mode 100644 subst/cmd/artifact_build.go create mode 100644 subst/cmd/config.go create mode 100644 subst/cmd/discover.go create mode 100644 subst/cmd/doc.go create mode 100644 subst/cmd/render.go create mode 100644 subst/cmd/root.go create mode 100644 subst/cmd/version.go create mode 100644 subst/main.go diff --git a/ draft.sh b/ draft.sh new file mode 100644 index 0000000..5f42f43 --- /dev/null +++ b/ draft.sh @@ -0,0 +1,233 @@ +#!/bin/bash +declare -A ejson_keys + +## -- Default Variables + +# General Plugin Configuration +TMP_DIR=${TMP_DIR:-./tmp} +KUSTOMIZE_BUILD_OPTIONS="" + +# Render Configuration + + + + +ROOT_DIRECTORY=${ARGOCD_ENV_ROOT_DIRECTORY:-.} +EXTRA_DIRECTORIES=${ARGOCD_ENV_EXTRA_DIRECTORIES} +EJSON_FILE_REGEX=${ARGOCD_ENV_EJSON_FILE_REGEX:-"*.ejson"} + +#: ${ARGOCD_APP_NAMESPACE:?"Namespace for ArgoCD Application is required"} +EJSON_SECRET=${ARGOCD_ENV_SECRET} +EJSON_INLINE_KEYS="" + +VAR_FILE_REGEX=${ARGOCD_ENV_VAR_FILE_REGEX:-"*.vars"} + +## -- Help Context +show_help() { +cat << EOF +Usage: ${0##*/} [-h] [-p] "ejson_key" [-s] "directory" [-m] "merge_directory" [-k] "secret_key" [-f] "dir/filename" [-r] + -s secret EJSON Secret name with ejson private keys + -n secret_ns EJSON Secret namespace + -p ejson_keys Add EJSON private key to decrypt ejson files (Comma seperated for multiple keys) + -D directory Root directory to search for files to decrypt [${ROOT_DIRECTORY}] + -m merge_dirs Additional comma seperated directories to merge secrets from + -e file_regex Regex to match files to decrypt [Default: ".*\.ejson$"] + -v vars_regex Regex to match files to merge [Default: ".*\.vars$"] + -d Dry Run Mode (Evaluate Build) + -v Verbose Mode + -h Show this context + +EOF +} + +# -- Script Arguments +OPTIND=1 +while getopts hvdv:e:m:p:n:s: opt; do + case $opt in + h) + show_help + exit 0 + ;; + d) DRY_RUN=true + ;; + v) DEBUG=true + ;; + s) EJSON_SECRET="${OPTARG}" + ;; + p) EJSON_INLINE_KEYS="${OPTARG}" + ;; + D) if [ -d "${OPTARG}" ]; then + ROOT_DIRECTORY=${OPTARG} + else + echo "Root directory '${OPTARG}' does not exist" && exit 1 + fi + ;; + *) + show_help >&2 + exit 1 + ;; + esac +done +shift "$((OPTIND-1))" + +# Constants/States +DEBUG=${ARGOCD_ENV_DEBUG:-false} +DRY_RUN=${ARGOCD_ENV_DRY_RUN:-false} +SUBS_STRUCT="{\"subst\": { \"secrets\": {}, \"vars\": {}, \"env\": {} }}" +DATA_FILE="${TMP_DIR%/}/secrets.tmp.json" + +# -- Validators + +# Namespace +# ARGOCD_APP_NAMESPACE is only set, if destination.namespace is set in the ArgoCD Application + +# -- Functions + +# Initialize +initialize() { + if $DEBUG; then + rm -rf ${TMP_DIR} + fi + + mkdir -p ${TMP_DIR%/}/build + cat > "${DATA_FILE}" << EOF +${SUBS_STRUCT} +EOF + +} + +## -- Debug Logging +debug() { + if $DEBUG; then + echo "$(date) - $1" + fi +} + +cleanup() { + if ! $DEBUG; then + rm -rf ${TMP_DIR} + fi +} +trap cleanup EXIT + +# https://github.com/buttahtoast/ejsonMerger/blob/master/ejson-merger.sh +# Main Function +main() { + + # Evaluate all paths + PATHS=". " + + # Add additional paths to decrypt + if [[ -n "${EXTRA_DIRECTORIES}" ]]; then + IFS=, read -ra DIR <<< "$EXTRA_DIRECTORIES" + for v in "${DIR[@]}"; do + path=$(echo $v | xargs) + if [ -d "$path" ]; then + PATHS="${PATHS} $v" + fi + done + fi + + # Read Kustomization Paths + if [ -f ./kustomization.yaml ]; then + while read -r path; do + if [ -d "$path" ]; then + PATHS="${PATHS} $path" + fi + done <<< "$(spruce json ./kustomization.yaml | jq -r '.resources[]')" + fi + + debug "Lookup Paths: ${PATHS}" + + ## --- Read EJSON Files + if [ -x "$(command -v ejson)" ]; then + + # Key Array + KEYS=() + + if ! [ -z "${EJSON_INLINE_KEYS}" ]; then + IFS=, read -ra INLINE <<< "$EJSON_INLINE_KEYS" + for k in "${INLINE[@]}"; do + KEYS+=($k) + done + else + # Resolve Private Keys from Secret + if ! [ -z "${EJSON_SECRET}" ]; then + while read -r key; do + KEYS+=($(echo "$key" | base64 -d)) + done <<< "$(kubectl get secret test -o go-template='{{range .data}}{{.}}{{"\n"}}{{end}}')" + fi + fi + + SECRET_DATA="{}" + if [ "${#KEYS[@]}" -eq 0 ]; then + debug "No EJSON Keys given" + else + for secret in $(find $PATHS -mindepth 1 -maxdepth 1 -type f -name "${EJSON_FILE_REGEX}"); do + debug "Attempt to decrypt '${secret}'"; + JSON_RESULT=$(cat "${secret}" | jq -r '.data') + if [[ $? -eq 0 ]] && [[ $JSON_RESULT != "null" ]]; then + decrypted=0 + for key in "${KEYS[@]}"; do + if echo "${key}" | ejson decrypt -key-from-stdin "${secret}" &> /dev/null; then + debug "Decrypted '${secret}'"; + data=$(echo "${key}" | ejson decrypt -key-from-stdin "${secret}" | jq -r --argjson struct "$SUBS_STRUCT" '.data as $d | $struct | .subst.secrets = $d' | spruce merge --skip-eval "${DATA_FILE}" - | spruce json) + echo $data > "${DATA_FILE}" + decrypted=1; + break; + fi + done + if [ $decrypted -eq 0 ]; then + debug "Unable to decrypt '${secret}'"; + fi + else + debug "Invalid JSON '${file}'. Does it have '.data' in structure (required)?"; + continue; + fi + done + fi + fi + + + # -- Read Var Files + VAR_FILES=() + readarray -d '' VAR_FILES < <(find $PATHS -mindepth 1 -maxdepth 1 -type f -name "${VARS_FILE_REGEX}") + if ! [ ${#VAR_FILES[@]} -eq 0 ]; then + data=$(spruce merge --skip-eval $(printf '${DATA_FILE} %s ' "${VAR_FILES[@]}") - | spruce json | jq -r --argjson struct "$SUBS_STRUCT" '. as $d | $struct | .subst.vars = $d') + echo $data > "${DATA_FILE}" + + #| jq '. | del(.SECRETS) | del(.VARS)') + + # Redirect Variables to DATA + #DATA=$(echo "$DATA" | jq --argjson vars "$vars" '.VARS = $vars') + fi + + # -- Add Environment Variables + ENV="{}" + while read -r env; do + convert_env=$(echo "$env" | sed "s/ARGOCD_ENV_//") + ENV=$(echo $ENV | jq --arg env "$(echo $convert_env| cut -d "=" -f 1)" --arg value "$(echo $convert_env| cut -d "=" -f 2)" '.[$env] = $value') + done <<< "$(env | grep ARGOCD_ENV_)" + data=$(cat "${DATA_FILE}" | jq -r --argjson ev "$ENV" '.subst.env=$ev') + echo $data > "${DATA_FILE}" + + + # -- Merge Files + debug "Available for subsitution $(cat "${DATA_FILE}")" + + # Envsubstitution allows only + if kustomize build ${ROOT_DIRECTORY} --load-restrictor LoadRestrictionsNone ${KUSTOMIZE_BUILD_OPTIONS} -o ${TMP_DIR%/}/build/; then + debug "Kustomize build succeeded" + for manifest in ${TMP_DIR%/}/build/*.yaml; do + debug "Run Substitution for build ${manifest}" + spruce merge "${DATA_FILE}" $manifest | spruce json | jq 'del(.subst)' + done + else + debug "Kustomize build failed" + exit 1 + fi + +} + +# -- Main +initialize && main \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5f06c7e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.circleci +.history +.idea +.vscode \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..997102f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: +- package-ecosystem: gomod + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 10 +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 10 +- package-ecosystem: "docker" + directory: "/" + schedule: + interval: weekly \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9ba01a --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +vendor/ +dist/ + +# Go workspace file +go.work \ No newline at end of file diff --git a/.golang-ci.yml b/.golang-ci.yml new file mode 100644 index 0000000..76e9a93 --- /dev/null +++ b/.golang-ci.yml @@ -0,0 +1,26 @@ +linters-settings: + lll: + line-length: 130 +linters: + enable-all: true + disable: + - testpackage + - forbidigo + - paralleltest + - exhaustivestruct + - varnamelen + - interfacer + - maligned + - scopelint + - golint + - varcheck + - nosnakecase + - deadcode + - ifshort + - structcheck + - rowserrcheck + - sqlclosecheck + - structcheck + - wastedassign + - exhaustruct + - nolintlint \ No newline at end of file diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..fd478bf --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,130 @@ +project_name: subst + +env: + - COSIGN_EXPERIMENTAL=true + +before: + hooks: + - go mod download + +sboms: +- artifacts: archive + +builds: + - main: subst/main.go + binary: subst + env: + - CGO_ENABLED=0 + goarch: + - amd64 + - arm64 + - arm + goos: + - linux + - darwin + - windows + flags: + - -trimpath + mod_timestamp: '{{ .CommitTimestamp }}' + ldflags: + - >- + -X github.com/buttahtoast/subst/subst/cmd.Version={{ .Tag }} + -X github.com/buttahtoast/subst/subst/cmd.GitCommit={{ .Commit }} + -X github.com/buttahtoast/subst/subst/cmd.BuildDate={{ .Date }} +archives: + - format_overrides: + - goos: windows + format: zip + files: + - LICENSE + - README.md + - etc/chart_schema.yaml + - etc/lintconf.yaml + +checksum: + name_template: 'checksums.txt' + +snapshot: + name_template: "{{ .Tag }}-next" + +dockers: + - image_templates: [ "ghcr.io/buttahtoast/{{ .ProjectName }}:{{ .Tag }}-amd64" ] + dockerfile: Dockerfile + goos: linux + goarch: amd64 + use: buildx + build_flag_templates: + - --platform=linux/arm64 + - --label=org.opencontainers.image.version={{ .Version }} + - --label=org.opencontainers.image.revision={{ .Commit }} + - --label=org.opencontainers.image.title={{ .ProjectName }} + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description=subst - Substitution based on Kustomize + - --label=org.opencontainers.image.vendor=Buttahtoast + - --label=org.opencontainers.image.licenses=Apache-2.0 + - --label=org.opencontainers.image.source=https://github.com/helm/chart-testing + - --label=org.opencontainers.image.authors=Buttahtoast + # - skip_push: false + # use: buildx + # dockerfile: Dockerfile + # image_templates: + # - quay.io/helmpack/chart-testing:{{ .Tag }}-amd64 + # - quay.io/helmpack/chart-testing:latest-amd64 + # build_flag_templates: + # - --platform=linux/amd64 + # - --label=org.opencontainers.image.version={{ .Version }} + # - --label=org.opencontainers.image.revision={{ .Commit }} + # - --label=org.opencontainers.image.title={{ .ProjectName }} + # - --label=org.opencontainers.image.created={{ .Date }} + # - --label=org.opencontainers.image.description=ct - The chart testing tool + # - --label=org.opencontainers.image.vendor=Helm + # - --label=org.opencontainers.image.licenses=Apache-2.0 + # - --label=org.opencontainers.image.source=https://github.com/helm/chart-testing + # - --label=org.opencontainers.image.authors=The Helm Authors + # extra_files: + # - etc/chart_schema.yaml + # - etc/lintconf.yaml + # - skip_push: false + # goarch: arm64 + # use: buildx + # dockerfile: Dockerfile + # image_templates: + # - quay.io/helmpack/chart-testing:{{ .Tag }}-arm64 + # - quay.io/helmpack/chart-testing:latest-arm64 + # build_flag_templates: + # - --platform=linux/arm64 + # - --label=org.opencontainers.image.version={{ .Version }} + # - --label=org.opencontainers.image.revision={{ .Commit }} + # - --label=org.opencontainers.image.title={{ .ProjectName }} + # - --label=org.opencontainers.image.created={{ .Date }} + # - --label=org.opencontainers.image.description=subst - Substitution based on Kustomize + # - --label=org.opencontainers.image.vendor=Buttahtoast + # - --label=org.opencontainers.image.licenses=Apache-2.0 + # - --label=org.opencontainers.image.source=https://github.com/helm/chart-testing + # - --label=org.opencontainers.image.authors=Buttahtoast + # extra_files: + # - etc/chart_schema.yaml + # - etc/lintconf.yaml + +# docker_manifests: +# - name_template: quay.io/buttahtoast/subst:latest +# image_templates: +# - quay.io/buttahtoast/subst:latest-amd64 +# - quay.io/buttahtoast/subst:latest-arm64 +# - name_template: quay.io/buttahtoast/subst:{{ .Tag }} +# image_templates: +# - docker.io/buttahtoast/subst:{{ .Tag }}-amd64 +# - quay.io/buttahtoast/subst:{{ .Tag }}-arm64 + +signs: + - cmd: cosign + stdin: '{{ .Env.COSIGN_PWD }}' + args: ["sign-blob", "-key=cosign.key", "-output=${signature}", "${artifact}"] + artifacts: checksum + +docker_signs: + - id: images + cmd: cosign + args: ["sign", "${artifact}"] + artifacts: manifests + stdin: '{{ .Env.COSIGN_PWD }}' \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..23bf099 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,13 @@ +repos: + # golang pre commits + - repo: https://github.com/dnephin/pre-commit-golang + rev: v0.5.1 + hooks: + - id: go-fmt + - id: go-imports + - id: no-go-testing + - id: golangci-lint + args: ["--skip-dirs=vendor -c .golang-ci.yml ."] + - id: go-unit-tests + - id: go-build + - id: go-mod-tidy \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..99107db --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1 @@ +* @buttahtoast diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..abe11b5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM golang:1.19-alpine as builder +WORKDIR /build +COPY . . +RUN go mod download +RUN CGO_ENABLED=0 GOOS=linux GO111MODULE=on go build -o bin ./subst/ + +FROM gcr.io/distroless/static:nonroot +WORKDIR / +COPY --from=builder /build/bin /subst +USER nonroot:nonroot +ENTRYPOINT ["/subst"] \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6599a66 --- /dev/null +++ b/Makefile @@ -0,0 +1,57 @@ +projectname?=subst + +default: help + +.PHONY: help +help: ## list makefile targets + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: build +build: ## build golang binary + @go build -ldflags "-X main.version=$(shell git describe --abbrev=0 --tags)" -o $(projectname) + +.PHONY: install +install: ## install golang binary + @go install -ldflags "-X main.version=$(shell git describe --abbrev=0 --tags)" + +.PHONY: run +run: ## run the app + @go run -ldflags "-X main.version=$(shell git describe --abbrev=0 --tags)" main.go + +.PHONY: bootstrap +bootstrap: ## install build deps + go generate -tags tools tools/tools.go + +PHONY: test +test: clean ## display test coverage + go test -json -v ./... | gotestfmt + +PHONY: clean +clean: ## clean up environment + @rm -rf coverage.out dist/ $(projectname) + +PHONY: cover +cover: ## display test coverage + go test -v -race $(shell go list ./... | grep -v /vendor/) -v -coverprofile=coverage.out + go tool cover -func=coverage.out + +PHONY: fmt +fmt: ## format go files + gofumpt -w . + gci write . + +PHONY: lint +lint: ## lint go files + golangci-lint run -c .golang-ci.yml + +.PHONY: docker-build +docker-build: ## dockerize golang application + @docker build --tag $(projectname) . + +.PHONY: docker-run +docker-run: + @docker run $(projectname) + +.PHONY: pre-commit +pre-commit: ## run pre-commit hooks + pre-commit run --all-files diff --git a/README.md b/README.md new file mode 100644 index 0000000..edb52d5 --- /dev/null +++ b/README.md @@ -0,0 +1,132 @@ +# Subst + +EJSON Merger is a simple bash script, which uses the tools [spruce](https://github.com/geofffranks/spruce), [jq](https://stedolan.github.io/jq/) and [ejson](https://github.com/Shopify/ejson). The main purpose of the script is, to merge multiple yaml/yml and json scripts together into one big map, which can be exported to a specific file or stdout. Since the merge process is done via spurce, you are able to use all spruce operators across all your files. See all spruce operators [here](https://github.com/geofffranks/spruce/blob/master/doc/operators.md). This tool gives you great advantages in your CI builds, since you are able to spread information into different files, but can join them with each other. But also, you can safely upload secrets to a repo. + + +## Testing + + +Private Key for testing + +Public Key: +5218ea26fa01414883012c8a1c866c5331ebefba069f86a4183090b3b096a771 +Private Key: +82d4af0a44dcabe9e44375e2bbe52842ae9497f068eede12833995bc6ab87020 + +And + +
Public Key:
+ff4bbf46acd0b467ee48f6e75041bc5b45442bb4b32f4bb0a2bfa928d2c21e44
+Private Key:
+b9f24a02dabd1f05c327c51a88f99390dab0835f0e56d4766885648cda2a51d6
+ + +## Rules + +* Each EJSON file has to contain it's public key. All data is given in the .data field. If this field isn't set, the EJSON file is not considered. +* [JQ](https://stedolan.github.io/jq/) is required +* [Spruce](https://github.com/geofffranks/spruce) is required. +* [EJSON](https://github.com/Shopify/ejson) is optional. +* [Ruby YAML gem](https://ruby-doc.org/stdlib-2.5.1/libdoc/yaml/rdoc/YAML.html) is required for YAML outputs. + +## Example + +Create a new EJSON Key-Pair ([More Information](https://github.com/Shopify/ejson)) + +
ejson keygen
+ +Will give you something like this (Don't use these!!): + +
Public Key:
+ff4bbf46acd0b467ee48f6e75041bc5b45442bb4b32f4bb0a2bfa928d2c21e44
+Private Key:
+b9f24a02dabd1f05c327c51a88f99390dab0835f0e56d4766885648cda2a51d6
+ +First create the EJSON File, should look like: + +
{
+  "_public_key": "ff4bbf46acd0b467ee48f6e75041bc5b45442bb4b32f4bb0a2bfa928d2c21e44",
+  "data": {
+     "some_password": "muchUnsecret",
+     "database": {
+       "user": "postgresql",
+       "password": "postgresql"
+     }
+  }
+}
+ +Next, decrypt the created EJSON file: + +
$ ejson encrypt example/my-secrets.ejson
+Wrote 562 bytes to example/my-secrets.ejson.
+ +The content of example/my-secrets.ejson should look like this now: + +
{
+  "_public_key": "ff4bbf46acd0b467ee48f6e75041bc5b45442bb4b32f4bb0a2bfa928d2c21e44",
+  "data": {
+     "some_password": "EJ[1:cwva0hMYQ0Si3CVnXPvFOehf9i5Le6IYQXkR8NIYlRc=:aMfnwm79BF02LbN/q9rP6JkjfNVb0RmX:E/aFMFo5YpPIitMqgQYl3DT/POUkhEcKqR2KYQ==]",
+     "database": {
+       "user": "EJ[1:cwva0hMYQ0Si3CVnXPvFOehf9i5Le6IYQXkR8NIYlRc=:m+rB13UUhxG6k51HuhrIrQsXLJ4g6zJF:/jyC+uV7210F1KzjGHZ8Ub/Eg/EyoF3facU=]",
+       "password": "EJ[1:cwva0hMYQ0Si3CVnXPvFOehf9i5Le6IYQXkR8NIYlRc=:hYP7OqZlGkRQc2BjD9bXfUr+8F/otS75:00D6UzYcZKGLeyIBZGii/mNrFw3w7AzW6Ks=]"
+     }
+  }
+}
+ +As you can see your secrets are now encrypted and can only be decrypted by the matching private key. This allows you to store secrets in git repositories in a secure way, if that's what you are looking for. Next we want to create a Reference to these secrets. let's create example/configuration.yml: + +
...
+  # Make Usage of Spruce Operators
+  user: (( grab $.SECRETS.database.user ))
+  host: postgres
+  password: (( grab $.SECRETS.database.user ))
+  database: (( concat $.PROJECT.name "-" $.PROJECT.version ))
+ +Now you it's time to implement the decryption and merging part, which means running the script with correct parameters. It's very simple, please consider the Options section for all possibilities. For this example, the script needs the private key and the destination (where ejson and other configs are located [./example]). We want the Output to STDOUT in YAML format. The command would look like this: + +
bash ejson-merger.sh -p "b9f24a02dabd1f05c327c51a88f99390dab0835f0e56d4766885648cda2a51d6" -m ./example -s ./example -y
+ +If we haven't done any Syntax Errors the output will look like this: + +
---
+PROJECT:
+  maintainer: oliverbaehler
+  name: example
+  version: 1.0.0
+database:
+  args:
+    database: example-1.0.0
+    host: postgres
+    password: postgresql
+    user: postgresql
+  name: example
+report_stats: false
+server_name: localhost:8800
+signing_key_path: "/src/.buildkite/test.signing.key"
+suppress_key_server_warning: true
+trusted_key_servers:
+- server_name: matrix.org
+ +As you can see our secrets were merged in clear text and other spruce operations were executed as well. Since giving this information to STDOUT makes the entire encryption part useless, I would suggest you using the -f option. This way the output will be generated into a file which then can be use by other Scripts or whatever. It's time, try it yourself? :) + +You can find these files in the [Example Folder](./example) + +## Options + +To see all options available, call the -h option: + +
ejson-merger.sh -h
+ +The Script currently supports the following options: + +
Usage: ejson-merger.sh [-h] [-p] "ejson_key" [-s] "directory" [-m] "merge_directory" [-k] "secret_key" [-f] "dir/filename" [-r]
+    -p ejson_key       Add EJSON private key to decrypt ejson files
+    -s directory       Source directory for ejson files (will be searched recursive) [Default "."]
+    -m merge_dir       Directory where your json/yml files are located to merge with secrets [Default "."]
+    -k secret_key      Top level key for secrets to be mapped to - (( grab $.secret_key.* )) [Default "SECRETS"]
+    -f dir/filename    Merge all files with Secrets in one json file. Given parameter is the name of the generated JSON/YAML
+    -r                 Remove Secrets from merged files [Default: True]
+    -y                 Output in YAML format [Default: JSON]
+    -h                 Show this context
+
+Script logs events/errors to [./ejson-merger.sh.log]
diff --git a/cosign.key b/cosign.key new file mode 100644 index 0000000..502cc5a --- /dev/null +++ b/cosign.key @@ -0,0 +1,11 @@ +-----BEGIN ENCRYPTED COSIGN PRIVATE KEY----- +eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6 +OCwicCI6MX0sInNhbHQiOiJkYlBGdkhEYXp6V0dENmc3by9zK0ZsZGFmREFKamJ3 +N3BoOUJaL2JUM2d3PSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94 +Iiwibm9uY2UiOiJMM3R5bkhJNUs4RTR6aTh6U1hlZ01mQkN0NjY0MWZxTyJ9LCJj +aXBoZXJ0ZXh0IjoiTml2dXU4VmcwV3BSQUZUMy9QTDN1b0pkT2cxRTFFT3AvU0xS +VmhvL1E1azcydXJuNkl5cE1OSVhKOGFiU3lYNmVkTmhOdmN2N0FraGJTMkh4OTBy +UnFGMndXQjZDYmtpTXVKNElXYnp0RnNDTTZESjltOWttTStlaFZlUzhyYjRIK1c3 +Y0NxZE1wNkU4ZWR4Q0R0WDhsaktlTVJzTEl4UjBkNkRoTTJNZnNLSEtETGx2L2Jr +MzdHM2dwOTU2YTBDVFJCK3cyL0xqUHUzM1E9PSJ9 +-----END ENCRYPTED COSIGN PRIVATE KEY----- diff --git a/cosign.pub b/cosign.pub new file mode 100644 index 0000000..0a11bc1 --- /dev/null +++ b/cosign.pub @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEts6ItOYGJude4Iw4ysh6X2bfGyLS +QZjzTUePbNIvgWqC+se6+3SPIU2l7ZTOJ9lLwNvqi3IVk+axJR6WUtNRhg== +-----END PUBLIC KEY----- diff --git a/example/configuration.yml b/example/configuration.yml new file mode 100644 index 0000000..ac7346c --- /dev/null +++ b/example/configuration.yml @@ -0,0 +1,16 @@ +--- +server_name: "localhost:8800" +signing_key_path: "/src/.buildkite/test.signing.key" +report_stats: false +trusted_key_servers: + - server_name: "matrix.org" +suppress_key_server_warning: true + +database: + name: (( grab $.PROJECT.name )) + args: + # Make Usage of Spruce Operators + user: (( grab $.SECRETS.database.user )) + host: postgres + password: (( grab $.SECRETS.database.user )) + database: (( concat $.PROJECT.name "-" $.PROJECT.version )) diff --git a/example/my-secrets.ejson b/example/my-secrets.ejson new file mode 100644 index 0000000..4654bc2 --- /dev/null +++ b/example/my-secrets.ejson @@ -0,0 +1,10 @@ +{ + "_public_key": "ff4bbf46acd0b467ee48f6e75041bc5b45442bb4b32f4bb0a2bfa928d2c21e44", + "data": { + "some_password": "EJ[1:cwva0hMYQ0Si3CVnXPvFOehf9i5Le6IYQXkR8NIYlRc=:aMfnwm79BF02LbN/q9rP6JkjfNVb0RmX:E/aFMFo5YpPIitMqgQYl3DT/POUkhEcKqR2KYQ==]", + "database": { + "user": "EJ[1:cwva0hMYQ0Si3CVnXPvFOehf9i5Le6IYQXkR8NIYlRc=:m+rB13UUhxG6k51HuhrIrQsXLJ4g6zJF:/jyC+uV7210F1KzjGHZ8Ub/Eg/EyoF3facU=]", + "password": "EJ[1:cwva0hMYQ0Si3CVnXPvFOehf9i5Le6IYQXkR8NIYlRc=:hYP7OqZlGkRQc2BjD9bXfUr+8F/otS75:00D6UzYcZKGLeyIBZGii/mNrFw3w7AzW6Ks=]" + } + } +} diff --git a/example/project.json b/example/project.json new file mode 100644 index 0000000..bbdf6e2 --- /dev/null +++ b/example/project.json @@ -0,0 +1,7 @@ +{ + "PROJECT": { + "name": "example", + "maintainer": "oliverbaehler", + "version": "1.0.0" + } +} diff --git a/examples/basic/blu.ejson b/examples/basic/blu.ejson new file mode 100644 index 0000000..162edec --- /dev/null +++ b/examples/basic/blu.ejson @@ -0,0 +1,7 @@ +{ + "_public_key": "0e0f1bddef22f85f34ba0dbb008a333389b4a4c92b835abcabf5083ac286975b", + "data": { + "_database_username": "1234username", + "database_password": "EJ[1:NV/QlJ75jcfA0BY//WO+oFf+hdD9MPDBS0owQVw31Ds=:MOB7VNYxDO7EyA+2xshJdBgFIyI0Ho6b:fHUPqPXSpRwEvBjCJqSdObJ6g4uwCrJZ3eBryg==]" + } +} diff --git a/examples/basic/cluster.vars b/examples/basic/cluster.vars new file mode 100644 index 0000000..78dec91 --- /dev/null +++ b/examples/basic/cluster.vars @@ -0,0 +1,3 @@ +cluster: + name: "new-cluster" + id: 1 \ No newline at end of file diff --git a/examples/basic/kustomization.yaml b/examples/basic/kustomization.yaml new file mode 100644 index 0000000..4bea077 --- /dev/null +++ b/examples/basic/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ../common/env/dev/ + - ../common/apps/ +# - (( concat "../common/env/" $.Subs.Env "/" )) \ No newline at end of file diff --git a/examples/common/apps/dns-2.yaml b/examples/common/apps/dns-2.yaml new file mode 100644 index 0000000..ec6855e --- /dev/null +++ b/examples/common/apps/dns-2.yaml @@ -0,0 +1,33 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: external-dns-2 + namespace: external-dns-2 +spec: + selector: + matchLabels: + app: external-dns + template: + metadata: + labels: + app: external-dns + spec: + serviceAccountName: external-dns + containers: + - name: external-dns + image: registry.k8s.io/external-dns/external-dns:v0.13.1 + args: + - --registry=txt + - --txt-prefix=external-dns- + - --txt-owner-id=k8s + - --provider=rfc2136 + - --rfc2136-host=192.168.0.1 + - --rfc2136-port=53 + - --rfc2136-zone=(( grab $.subst.vars.dns.domain )) + - --rfc2136-tsig-secret=(( grab $.subst.secrets.tsig )) + - --rfc2136-tsig-secret-alg=hmac-sha256 + - --rfc2136-tsig-keyname=externaldns-key + - --rfc2136-tsig-axfr + - --source=ingress + - --domain-filter=(( grab $.subst.vars.dns.domain )) + - --test=(( grab $.SOMETHING )) \ No newline at end of file diff --git a/examples/common/apps/dns.yaml b/examples/common/apps/dns.yaml new file mode 100644 index 0000000..95b5c1a --- /dev/null +++ b/examples/common/apps/dns.yaml @@ -0,0 +1,35 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: external-dns + namespace: external-dns +first_array: + - (( grab $.subst.vars.cluster.name )) + - (( grab $.subst.vars.cluster.id )) +spec: + selector: + matchLabels: + app: external-dns + template: + metadata: + labels: + app: external-dns + spec: + serviceAccountName: external-dns + containers: + - name: external-dns + image: registry.k8s.io/external-dns/external-dns:v0.13.1 + args: + - --registry=txt + - --txt-prefix=external-dns- + - --txt-owner-id=k8s + - --provider=rfc2136 + - --rfc2136-host=192.168.0.1 + - --rfc2136-port=53 + - (( concat "--rfc2136-zone=" $.subst.vars.dns.domain )) + - (( concat "--rfc2136-tsig-secret=" $.subst.secrets.tsig )) + - --rfc2136-tsig-secret-alg=hmac-sha256 + - --rfc2136-tsig-keyname=externaldns-key + - --rfc2136-tsig-axfr + - --source=ingress + - (( concat "--domain-filter=" $.subst.vars.dns.domain )) \ No newline at end of file diff --git a/examples/common/apps/kustomization.yaml b/examples/common/apps/kustomization.yaml new file mode 100644 index 0000000..65cd49b --- /dev/null +++ b/examples/common/apps/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - dns.yaml + - dns-2.yaml \ No newline at end of file diff --git a/examples/common/apps/main.vars b/examples/common/apps/main.vars new file mode 100644 index 0000000..ef92152 --- /dev/null +++ b/examples/common/apps/main.vars @@ -0,0 +1,3 @@ +{ + "bla2": "huuu" +} \ No newline at end of file diff --git a/examples/common/env/dev/kustomization.yaml b/examples/common/env/dev/kustomization.yaml new file mode 100644 index 0000000..6879cb9 --- /dev/null +++ b/examples/common/env/dev/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - secret.yaml + - secret-2.yaml \ No newline at end of file diff --git a/examples/common/env/dev/main.vars b/examples/common/env/dev/main.vars new file mode 100644 index 0000000..6a612f4 --- /dev/null +++ b/examples/common/env/dev/main.vars @@ -0,0 +1,5 @@ +dns: + domain: "dev.company.com" + nameservers: + - "2.2.2.2" + - "2.2.2.3" diff --git a/examples/common/env/dev/secret-2.yaml b/examples/common/env/dev/secret-2.yaml new file mode 100644 index 0000000..db1f0af --- /dev/null +++ b/examples/common/env/dev/secret-2.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Secret +metadata: + name: second-access +data: + hello: (( grab $.subst.vars.cluster.id )) \ No newline at end of file diff --git a/examples/common/env/dev/secret.yaml b/examples/common/env/dev/secret.yaml new file mode 100644 index 0000000..dc7b411 --- /dev/null +++ b/examples/common/env/dev/secret.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + name: database-access +data: + user: (( grab $.subst.vars.cluster.name )) + password: (( grab $.subst.secrets.data.database_password )) \ No newline at end of file diff --git a/examples/common/env/dev/secrets.ejson.old b/examples/common/env/dev/secrets.ejson.old new file mode 100644 index 0000000..d008cf6 --- /dev/null +++ b/examples/common/env/dev/secrets.ejson.old @@ -0,0 +1,10 @@ +{ + "_public_key": "ff4bbf46acd0b467ee48f6e75041bc5b45442bb4b32f4bb0a2bfa928d2c21e44", + "data": { + "tsig": "EJ[1:cwva0hMYQ0Si3CVnXPvFOehf9i5Le6IYQXkR8NIYlRc=:aMfnwm79BF02LbN/q9rP6JkjfNVb0RmX:E/aFMFo5YpPIitMqgQYl3DT/POUkhEcKqR2KYQ==]", + "database": { + "user": "EJ[1:cwva0hMYQ0Si3CVnXPvFOehf9i5Le6IYQXkR8NIYlRc=:m+rB13UUhxG6k51HuhrIrQsXLJ4g6zJF:/jyC+uV7210F1KzjGHZ8Ub/Eg/EyoF3facU=]", + "password": "EJ[1:cwva0hMYQ0Si3CVnXPvFOehf9i5Le6IYQXkR8NIYlRc=:hYP7OqZlGkRQc2BjD9bXfUr+8F/otS75:00D6UzYcZKGLeyIBZGii/mNrFw3w7AzW6Ks=]" + } + } +} \ No newline at end of file diff --git a/examples/common/env/test/kustomization.yaml b/examples/common/env/test/kustomization.yaml new file mode 100644 index 0000000..13519af --- /dev/null +++ b/examples/common/env/test/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - [] \ No newline at end of file diff --git a/examples/common/env/test/main.vars b/examples/common/env/test/main.vars new file mode 100644 index 0000000..68bad65 --- /dev/null +++ b/examples/common/env/test/main.vars @@ -0,0 +1,5 @@ +dns: + domain: "test.company.com" + nameservers: + - "1.1.1.1" + - "1.1.1.2" \ No newline at end of file diff --git a/examples/common/env/test/secrets.ejson.old b/examples/common/env/test/secrets.ejson.old new file mode 100644 index 0000000..8391255 --- /dev/null +++ b/examples/common/env/test/secrets.ejson.old @@ -0,0 +1,10 @@ +{ + "_public_key": "5218ea26fa01414883012c8a1c866c5331ebefba069f86a4183090b3b096a771", + "data": { + "tsig": "EJ[1:2Lbf7vmUIMxKj003UWaU6XXnACMnIMG+EBRKxDoOXXM=:Gr/fhtjyBpxnyZAiRGWR+hsgoHG9n8Dv:nEY2b9RDL74dRsihShntkqbkntdLCARSvr21XQ==]", + "database": { + "user": "EJ[1:2Lbf7vmUIMxKj003UWaU6XXnACMnIMG+EBRKxDoOXXM=:2xVofqsWRBf4mH3yRCB0l6MTzvD6enyD:vvQcsQUNssuHF2/IvtEPWpIXoe1OfIy0nHQ=]", + "password": "EJ[1:2Lbf7vmUIMxKj003UWaU6XXnACMnIMG+EBRKxDoOXXM=:VKU+ccVvCqE4a/ITLEBfT3j6srDoB5aH:qsSewRT2xfpmWgU23vMNfeGU8+qfhSngG2A=]" + } + } +} \ No newline at end of file diff --git a/examples/kustomization.yaml b/examples/kustomization.yaml new file mode 100644 index 0000000..b1c3f7b --- /dev/null +++ b/examples/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./basic diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..61a7020 --- /dev/null +++ b/go.mod @@ -0,0 +1,88 @@ +module github.com/buttahtoast/subst + +go 1.19 + +require ( + github.com/MakeNowJust/heredoc v1.0.0 + github.com/Shopify/ejson v1.3.3 + github.com/geofffranks/spruce v1.29.0 + github.com/spf13/cobra v1.6.1 + github.com/spf13/pflag v1.0.5 + github.com/spf13/viper v1.14.0 + gopkg.in/yaml.v2 v2.4.0 + k8s.io/apimachinery v0.26.0 + k8s.io/client-go v0.26.0 + sigs.k8s.io/kustomize/api v0.12.1 +) + +require ( + github.com/Knetic/govaluate v3.0.0+incompatible // indirect + github.com/aws/aws-sdk-go v1.40.54 // indirect + github.com/cloudfoundry-community/vaultkv v0.0.0-20200311151509-343c0e6fc506 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/evanphx/json-patch v4.12.0+incompatible // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/geofffranks/simpleyaml v0.0.0-20161109204137-c9320f076de5 // indirect + github.com/geofffranks/yaml v0.0.0-20161117152608-9f2fe4b6f295 // indirect + github.com/go-errors/errors v1.0.1 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/swag v0.19.14 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/imdario/mergo v0.3.6 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mitchellh/mapstructure v1.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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/onsi/ginkgo v1.12.0 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.5 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/spf13/afero v1.9.2 // indirect + github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/starkandwayne/goutils v0.0.0-20190115202530-896b8a6904be // indirect + github.com/subosito/gotenv v1.4.1 // indirect + github.com/xlab/treeprint v1.1.0 // indirect + github.com/ziutek/utils v0.0.0-20190626152656-eb2a3b364d6c // indirect + go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect + golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect + golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 // indirect + golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect + golang.org/x/sys v0.3.0 // indirect + golang.org/x/term v0.3.0 // indirect + golang.org/x/text v0.5.0 // indirect + golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.26.0 // indirect + k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect + k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..5214678 --- /dev/null +++ b/go.sum @@ -0,0 +1,654 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= +github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/Shopify/ejson v1.3.3 h1:dPzgmvFhUPTJIzwdF5DaqbwW1dWaoR8ADKRdSTy6Mss= +github.com/Shopify/ejson v1.3.3/go.mod h1:VZMUtDzvBW/PAXRUF5fzp1ffb1ucT8MztrZXXLYZurw= +github.com/aws/aws-sdk-go v1.40.54 h1:8zYzK8wI06G2+Bg2hwTUwzIYCCo6/Wd7lfS0G+GwqXU= +github.com/aws/aws-sdk-go v1.40.54/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +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/cloudfoundry-community/vaultkv v0.0.0-20200311151509-343c0e6fc506 h1:o5GNr/sb9Wkxif5MctE5cZekAPB7jbCUhuXwH7uDJWM= +github.com/cloudfoundry-community/vaultkv v0.0.0-20200311151509-343c0e6fc506/go.mod h1:pMz8czjvi3S7Lb7hgAK4J8knpIi+4fK3Bbe+LyzsHus= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad h1:Qk76DOWdOp+GlyDKBAG3Klr9cn7N+LcYc82AZ2S7+cA= +github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad/go.mod h1:mPKfmRa823oBIgl2r20LeMSpTAteW5j7FLkc0vjmzyQ= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/geofffranks/simpleyaml v0.0.0-20161109204137-c9320f076de5 h1:5AjbNPs5ax5Rf1/FeG8tLUYOoEbEDvcMvBgBUH4fDRM= +github.com/geofffranks/simpleyaml v0.0.0-20161109204137-c9320f076de5/go.mod h1:EoVmbOOR2VpnWfvsZ1wVdjvUbitLYk1SYxGTssyjW4s= +github.com/geofffranks/spruce v1.29.0 h1:D6THmdYb5zMRT/jW8O42U85BeXkbCts9csyroMqB62A= +github.com/geofffranks/spruce v1.29.0/go.mod h1:LysbPKCU2deahHFst/kYj5WMZO/JLRbwwNMutHX9Ct0= +github.com/geofffranks/yaml v0.0.0-20161117152608-9f2fe4b6f295 h1:CxigGHNaNtLTrnMveo9CjJjgXTuZpbLvuOvY/+c1v8g= +github.com/geofffranks/yaml v0.0.0-20161117152608-9f2fe4b6f295/go.mod h1:+Qu4YOxbpR+Dn8JVzOTjJKWt3EZkEQD918wX+CkNcbE= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +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-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +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.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +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.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +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.4.1/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.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/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 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +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.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20211002144500-51d3295ec039 h1:5lduVZdirtbIjJojKmVI/tR2gYU0nAVcmdNEHOBvIC8= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +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.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +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/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +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/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +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 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/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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +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.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/smartystreets/assertions v1.2.1 h1:bKNHfEv7tSIjZ8JbKaFjzFINljxG4lzZvmHUnElzOIg= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +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.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +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/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= +github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= +github.com/starkandwayne/goutils v0.0.0-20190115202530-896b8a6904be h1:vV6o1C8iPioC0Ahi3e9Bs9vVPW9/YN3uwgA6EFahAws= +github.com/starkandwayne/goutils v0.0.0-20190115202530-896b8a6904be/go.mod h1:Py4V645l0xZXsyvSR6WIcsGhNQEiIFDlmJ4Xwd6UCws= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= +github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/ziutek/utils v0.0.0-20190626152656-eb2a3b364d6c h1:PyI4qg2zvSToKuMdr0WiwbsKkKzyKQBwhELU01zOcfg= +github.com/ziutek/utils v0.0.0-20190626152656-eb2a3b364d6c/go.mod h1:ACOZERHuXvWeAzjD4DvMwvxz/Q8DOF9VP8lcfwV59Oo= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +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-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +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.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 h1:Frnccbp+ok2GkUS2tC84yAq/U9Vg+0sIO7aRL3T4Xnc= +golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +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-20190227155943-e225da77a7e6/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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U= +golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +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= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +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.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +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.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.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +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.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/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.0-20200615113413-eeeca48fe776/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= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.26.0 h1:IpPlZnxBpV1xl7TGk/X6lFtpgjgntCg8PJ+qrPHAC7I= +k8s.io/api v0.26.0/go.mod h1:k6HDTaIFC8yn1i6pSClSqIwLABIcLV9l5Q4EcngKnQg= +k8s.io/apimachinery v0.26.0 h1:1feANjElT7MvPqp0JT6F3Ss6TWDwmcjLypwoPpEf7zg= +k8s.io/apimachinery v0.26.0/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= +k8s.io/client-go v0.26.0 h1:lT1D3OfO+wIi9UFolCrifbjUUgu7CpLca0AD8ghRLI8= +k8s.io/client-go v0.26.0/go.mod h1:I2Sh57A79EQsDmn7F7ASpmru1cceh3ocVT9KlX2jEZg= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM= +sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s= +sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= +sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 0000000..683be3e --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,99 @@ +package config + +import ( + "fmt" + "os" + "path/filepath" + "reflect" + "time" + + flag "github.com/spf13/pflag" + + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +type Configuration struct { + RootDirectory string `mapstructure:"root-dir"` + ExtraDirectories []string `mapstructure:"extra-dirs"` + EjsonFilePattern string `mapstructure:"ejson-pattern"` + EjsonSecret string `mapstructure:"ejson-secret"` + EjsonSecretNamespace string `mapstructure:"ejson-namespace"` + EjsonKey []string `mapstructure:"ejson-key"` + SkipDecryption bool `mapstructure:"skip-decryption"` + VarFilePattern string `mapstructure:"vars-pattern"` + Debug bool `mapstructure:"debug"` + KubectlTimeout time.Duration `mapstructure:"kubectl-timeout"` +} + +var ( + configLocations = []string{ + ".", + } +) + +func LoadConfiguration(cfgFile string, cmd *cobra.Command) (*Configuration, error) { + v := viper.New() + + cmd.Flags().VisitAll(func(flag *flag.Flag) { + flagName := flag.Name + if flagName != "config" && flagName != "help" { + if err := v.BindPFlag(flagName, flag); err != nil { + panic(fmt.Sprintf("failed binding flag %q: %v\n", flagName, err.Error())) + } + } + }) + + if cfgFile != "" { + v.SetConfigFile(cfgFile) + } else { + v.SetConfigName("subst") + if cfgFile, ok := os.LookupEnv("SUBST_CONFIG_DIR"); ok { + v.AddConfigPath(cfgFile) + } else { + for _, searchLocation := range configLocations { + v.AddConfigPath(searchLocation) + } + } + } + + if err := v.ReadInConfig(); err != nil { + if cfgFile != "" { + // Only error out for specified config file. Ignore for default locations. + return nil, fmt.Errorf("failed loading config file: %w", err) + } + } + + cfg := &Configuration{} + if err := v.Unmarshal(cfg); err != nil { + return nil, fmt.Errorf("failed unmarshaling configuration: %w", err) + } + + // Resolve Root Directory + rootAbs, err := filepath.Abs(cfg.RootDirectory) + if err != nil { + return nil, fmt.Errorf("failed resolving root directory: %w", err) + } else { + cfg.RootDirectory = rootAbs + } + + return cfg, nil + +} + +func PrintConfiguration(cfg *Configuration) { + fmt.Fprintln(os.Stderr, " Configuration") + e := reflect.ValueOf(cfg).Elem() + typeOfCfg := e.Type() + + for i := 0; i < e.NumField(); i++ { + var pattern string + switch e.Field(i).Kind() { + case reflect.Bool: + pattern = "%s: %t\n" + default: + pattern = "%s: %s\n" + } + fmt.Fprintf(os.Stderr, pattern, typeOfCfg.Field(i).Name, e.Field(i).Interface()) + } +} diff --git a/pkg/tool/file.go b/pkg/tool/file.go new file mode 100644 index 0000000..f431174 --- /dev/null +++ b/pkg/tool/file.go @@ -0,0 +1,75 @@ +package tool + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + + "gopkg.in/yaml.v2" +) + +func NewFile(path string) (*file, error) { + result := &file{ + path: path, + } + err := result.loadMap() + return result, err +} + +func (f *file) loadMap() error { + data, err := f.load() + if err != nil { + return err + } + + err = yaml.Unmarshal(data, &f.data) + if err != nil { + return err + } + + if f.data == nil { + f.data = make(map[interface{}]interface{}) + } + + return nil +} + +func (f *file) load() ([]byte, error) { + var data []byte + data, err = ioutil.ReadFile(f.path) + if err != nil { + return nil, err + } + return data, nil +} + +func (f *file) Map() map[interface{}]interface{} { + return f.data +} + +func (f *file) YAML() ([]byte, error) { + return yaml.Marshal(f.data) +} + +func (f *file) JSON() ([]byte, error) { + return json.Marshal(f.data) +} + +/* create a golang function which prints map[interface{}]interface{} as yaml */ +func (m *file) PrintYAML() { + y, err := yaml.Marshal(m.data) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("---\n%s\n", string(y)) +} + +/* create a golang function which prints map[interface{}]interface{} as json */ +func (m *file) PrintJSON() { + j, err := json.Marshal(m.data) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("%s\n", string(j)) +} diff --git a/pkg/tool/merge.go b/pkg/tool/merge.go new file mode 100644 index 0000000..21d7af2 --- /dev/null +++ b/pkg/tool/merge.go @@ -0,0 +1,74 @@ +package tool + +import ( + "encoding/json" + "fmt" + "log" + + "github.com/buttahtoast/subst/pkg/config" + "github.com/buttahtoast/subst/pkg/utils" + "github.com/geofffranks/spruce" + "gopkg.in/yaml.v2" +) + +func Merge(config config.Configuration, state Spruce) ([]map[interface{}]interface{}, error) { + manifests := []map[interface{}]interface{}{} + + // Create Kustomize Build + kusto, err := utils.Build(config) + if err != nil { + return nil, err + } + + // Merge Substitutions with each Manifest + for _, manifest := range kusto.Resources() { + log.Printf("\n \n %v", manifest) + m, _ := manifest.AsYAML() + var tmp map[interface{}]interface{} + log.Printf("HERE 1") + err := yaml.Unmarshal(m, &tmp) + if err != nil { + return nil, err + } + log.Printf("HERE 2") + s, err := state.ToInterface() + //fmt.Printf("\n \n %v", s) + if err != nil { + return nil, err + } + merged, err := spruce.Merge(s, tmp) + log.Printf("HERE 3") + if err != nil { + return nil, err + } + log.Printf("HERE 4") + // Evaluate with Spruce + evaluator := &spruce.Evaluator{ + Tree: merged, + SkipEval: false, + } + err = evaluator.Run([]string{}, nil) + fmt.Println(err) + if err != nil { + return nil, err + } + delete(evaluator.Tree, "subst") + fmt.Println(evaluator.Tree) + //fmt.Printf("\n \n\n \n\n \n\n \n%v \n \n", eval) + //return eval.Tree, nil + manifests = append(manifests, evaluator.Tree) + + //fmt.Printf(" herehrere %v, %v", eval.Tree, err) + } + + return manifests, nil + +} + +func PrettyPrint(v interface{}) (err error) { + b, err := json.MarshalIndent(v, "", " ") + if err == nil { + fmt.Println(string(b)) + } + return +} diff --git a/pkg/tool/render.go b/pkg/tool/render.go new file mode 100644 index 0000000..005f660 --- /dev/null +++ b/pkg/tool/render.go @@ -0,0 +1,127 @@ +package tool + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/buttahtoast/subst/pkg/config" + "github.com/buttahtoast/subst/pkg/utils" + "github.com/buttahtoast/subst/pkg/wrapper/ejson" + "github.com/geofffranks/spruce" + "gopkg.in/yaml.v2" +) + +type Spruce struct { + Subst struct { + Env map[string]string `yaml:"env"` + Vars map[interface{}]interface{} `yaml:"vars"` + Secrets map[interface{}]interface{} `yaml:"secrets"` + } `yaml:"subst"` +} + +func (s *Spruce) ToInterface() (map[interface{}]interface{}, error) { + tmp := make(map[interface{}]interface{}) + yml, err := yaml.Marshal(s) + if err != nil { + return nil, err + } + err = yaml.Unmarshal(yml, tmp) + return tmp, err + +} + +var ( + state = Spruce{} + paths []string + err error + cfg config.Configuration +) + +func Gather(config config.Configuration) ([]map[interface{}]interface{}, error) { + cfg = config + + readEnvironmentVariables() + + paths, err = utils.GetKustomizePaths(config.RootDirectory) + if err != nil { + return nil, err + } + + // Append Root Directory to paths + paths = append(paths, config.RootDirectory) + + // decrypt ejson + ejs, err := ejson.New(config) + if err != nil { + return nil, err + } + + err = loopPath(VarFiles) + if err != nil { + return nil, err + } + + fmt.Printf("%v", state.Subst.Vars) + + // Read Var Files + + err = loopPath(ejs.Walk) + if err != nil { + return nil, err + } + state.Subst.Secrets = ejs.GetSecrets() + + manifests, err := Merge(config, state) + if err != nil { + return nil, err + } + //fmt.Printf("%v", manifests) + + return manifests, err + +} + +func VarFiles(path string, info fs.FileInfo, err error) error { + if filepath.Ext(path) == cfg.VarFilePattern { + file, err := NewFile(path) + if err != nil { + return err + } + data := file.Map() + state.Subst.Vars, err = spruce.Merge(state.Subst.Vars, data) + if err != nil { + return err + } + } + return err +} + +func loopPath(fn filepath.WalkFunc) error { + for path := range paths { + err := filepath.Walk(paths[path], fn) + if err != nil { + return err + } + } + return nil +} + +func readEnvironmentVariables() { + state.Subst.Env = make(map[string]string) + r, _ := regexp.Compile("^ARGOCD_ENV_.*$") + for _, e := range os.Environ() { + pair := strings.SplitN(e, "=", 2) + key := pair[0] + value := pair[1] + + // Rewrite ArgoCD Environment Variables + if r.MatchString(key) { + key = strings.ReplaceAll(key, "ARGOCD_ENV_", "") + } + state.Subst.Env[key] = value + } +} diff --git a/pkg/tool/types.go b/pkg/tool/types.go new file mode 100644 index 0000000..e7f1a6a --- /dev/null +++ b/pkg/tool/types.go @@ -0,0 +1,6 @@ +package tool + +type file struct { + data map[interface{}]interface{} + path string +} diff --git a/pkg/utils/kustomize.go b/pkg/utils/kustomize.go new file mode 100644 index 0000000..08889be --- /dev/null +++ b/pkg/utils/kustomize.go @@ -0,0 +1,79 @@ +package utils + +import ( + "fmt" + "os" + + "github.com/buttahtoast/subst/pkg/config" + "sigs.k8s.io/kustomize/api/filesys" + "sigs.k8s.io/kustomize/api/konfig" + "sigs.k8s.io/kustomize/api/krusty" + "sigs.k8s.io/kustomize/api/resmap" + "sigs.k8s.io/kustomize/api/types" + kustypes "sigs.k8s.io/kustomize/api/types" +) + +var ( + paths []string +) + +// ReadKustomize reads a kustomization file from a path +func readKustomize(path string) (types.Kustomization, error) { + kz := types.Kustomization{} + for _, kfilename := range konfig.RecognizedKustomizationFileNames() { + if _, err := os.Stat(path + kfilename); err == nil { + kzBytes, err := os.ReadFile(path + kfilename) + if err != nil { + println(err) + } + err = kz.Unmarshal(kzBytes) + + return kz, err + } + } + return kz, fmt.Errorf("no kustomization file found in %v", path) +} + +func GetKustomizePaths(path string) ([]string, error) { + path = convertPath(path) + kz, err := readKustomize(path) + for _, resource := range kz.Resources { + p := fmt.Sprintf("%v%v", path, resource) + file, err := os.Stat(p) + if os.IsNotExist(err) { + return paths, err + } + if file.IsDir() { + p = convertPath(p) + paths = append(paths, p) + GetKustomizePaths(p) + } + } + return paths, err +} + +func Build(config config.Configuration) (resmap.ResMap, error) { + + fs := filesys.MakeFsOnDisk() + + buildOptions := &krusty.Options{ + DoLegacyResourceSort: true, + LoadRestrictions: kustypes.LoadRestrictionsNone, + AddManagedbyLabel: false, + DoPrune: false, + PluginConfig: kustypes.DisabledPluginConfig(), + } + k := krusty.MakeKustomizer(buildOptions) + m, err := k.Run(fs, config.RootDirectory) + if err != nil { + return nil, err + } + return m, nil +} + +func convertPath(path string) string { + if path[len(path)-1:] != "/" { + path = fmt.Sprintf("%v/", path) + } + return path +} diff --git a/pkg/wrapper/ejson/ejson.go b/pkg/wrapper/ejson/ejson.go new file mode 100644 index 0000000..51c8c34 --- /dev/null +++ b/pkg/wrapper/ejson/ejson.go @@ -0,0 +1,130 @@ +package ejson + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "io/fs" + "path/filepath" + + "github.com/Shopify/ejson" + "github.com/buttahtoast/subst/pkg/config" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" +) + +type Ejson struct { + config config.Configuration `json:"-"` + secrets map[interface{}]interface{} + keys []string +} + +type Form struct { + Data map[interface{}]interface{} `json:"-"` + PublicKey string `json:"_public_key"` +} + +func (e *Ejson) GetSecrets() map[interface{}]interface{} { + return e.secrets +} + +func New(config config.Configuration) (Ejson, error) { + ejs := Ejson{ + config: config, + } + return ejs, ejs.loadKeys() +} +func (e *Ejson) loadKeys() error { + // Read inline keys + e.keys = e.config.EjsonKey + + // try to use k8s secrets + if e.config.EjsonSecret != "" { + // Create a new rest config + cfg, err := rest.InClusterConfig() + if err != nil { + panic(err) + } + + // Create a new clientset + clientset, err := kubernetes.NewForConfig(cfg) + if err != nil { + panic(err) + } + + // Set the namespace and secret name + namespace := e.config.EjsonSecretNamespace + secretName := e.config.EjsonSecret + + // Get the secret + secret, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{}) + if err != nil { + panic(err) + } + + // add all keys to + for s := range secret.Data { + decodedData, err := base64.StdEncoding.DecodeString(string(secret.Data[s])) + if err != nil { + return err + } + e.keys = append(e.keys, string(decodedData)) + } // Read from Kubernetes Secret + + } + return nil + +} +func (e *Ejson) Walk(path string, info fs.FileInfo, err error) error { + if filepath.Ext(path) == ".ejson" { + data, err := e.readFile(path) + if err != nil { + return err + } + tmp, err := ExtractKey(string(data), "data") + if err != nil { + return err + } + e.secrets = tmp + } + return err +} +func (e *Ejson) readFile(path string) ([]byte, error) { + var ( + err error + data []byte + ) + + // Try encrypt with every key + for key := range e.keys { + data, err = ejson.DecryptFile(path, "", e.keys[key]) + if err != nil { + // if decryption fail try other key + // maybe optimize this by analysing priv key + continue + } + // leave loop when decryption retrun zero error + break + } + + return data, err +} + +func ExtractKey(jsonStr string, key string) (map[interface{}]interface{}, error) { + var data map[string]interface{} + err := json.Unmarshal([]byte(jsonStr), &data) + if err != nil { + return nil, err + } + + result := make(map[interface{}]interface{}) + value, ok := data[key] + if !ok { + return nil, fmt.Errorf("key '%s' not found in JSON data", key) + } + + result[key] = value + return result, nil +} diff --git a/subst/cmd/artifact.go b/subst/cmd/artifact.go new file mode 100644 index 0000000..e52e906 --- /dev/null +++ b/subst/cmd/artifact.go @@ -0,0 +1,21 @@ +package cmd + +import ( + "github.com/MakeNowJust/heredoc" + "github.com/spf13/cobra" +) + +func newArtifactCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "artifact", + Short: "Artifact interaction", + Long: heredoc.Doc(` + Run 'subst artifact' prints the given configuration (based on configuration files and env)`), + } + + flags := cmd.Flags() + addCommonFlags(flags) + addRenderFlags(flags) + cmd.AddCommand(newArtifactBuildCmd()) + return cmd +} diff --git a/subst/cmd/artifact_build.go b/subst/cmd/artifact_build.go new file mode 100644 index 0000000..ac01941 --- /dev/null +++ b/subst/cmd/artifact_build.go @@ -0,0 +1,21 @@ +package cmd + +import ( + "github.com/MakeNowJust/heredoc" + "github.com/spf13/cobra" +) + +func newArtifactBuildCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "push", + Short: "Push an artifact to a registry", + Long: heredoc.Doc(` + Run 'subst artifact push' prints the given configuration (based on configuration files and env)`), + RunE: configurationcmd, + } + + flags := cmd.Flags() + addCommonFlags(flags) + addRenderFlags(flags) + return cmd +} diff --git a/subst/cmd/config.go b/subst/cmd/config.go new file mode 100644 index 0000000..420f253 --- /dev/null +++ b/subst/cmd/config.go @@ -0,0 +1,34 @@ +package cmd + +import ( + "fmt" + + "github.com/MakeNowJust/heredoc" + "github.com/buttahtoast/subst/pkg/config" + "github.com/spf13/cobra" +) + +func newConfigCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "config", + Short: "Printf Configuration", + Long: heredoc.Doc(` + Run 'subst config' prints the given configuration (based on configuration files and env)`), + RunE: configurationcmd, + } + + flags := cmd.Flags() + addCommonFlags(flags) + addRenderFlags(flags) + return cmd + +} + +func configurationcmd(cmd *cobra.Command, args []string) error { + configuration, err := config.LoadConfiguration(cfgFile, cmd) + if err != nil { + return fmt.Errorf("failed loading configuration: %w", err) + } + config.PrintConfiguration(configuration) + return nil +} diff --git a/subst/cmd/discover.go b/subst/cmd/discover.go new file mode 100644 index 0000000..dceb5b5 --- /dev/null +++ b/subst/cmd/discover.go @@ -0,0 +1,35 @@ +package cmd + +import ( + "fmt" + + "github.com/MakeNowJust/heredoc" + "github.com/buttahtoast/subst/pkg/config" + "github.com/spf13/cobra" +) + +func newDiscoverCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "discover", + Short: "Discover if plugin is applicable to the given directory", + Long: heredoc.Doc(` + Run 'subst discover' to return directories that contain plugin compatible files. Mainly used for automatic plugin discovery by ArgoCD`), + RunE: discover, + } + + flags := cmd.Flags() + addCommonFlags(flags) + return cmd + +} + +func discover(cmd *cobra.Command, args []string) error { + configuration, err := config.LoadConfiguration(cfgFile, cmd) + if err != nil { + return fmt.Errorf("failed loading configuration: %w", err) + } + + println(configuration) + + return nil +} diff --git a/subst/cmd/doc.go b/subst/cmd/doc.go new file mode 100644 index 0000000..7ee0c07 --- /dev/null +++ b/subst/cmd/doc.go @@ -0,0 +1,31 @@ +package cmd + +import ( + "fmt" + + "github.com/MakeNowJust/heredoc" + "github.com/spf13/cobra" + "github.com/spf13/cobra/doc" +) + +func newGenerateDocsCmd() *cobra.Command { + return &cobra.Command{ + Use: "doc-gen", + Short: "Generate documentation", + Long: heredoc.Doc(` + Generate documentation for all commands + to the 'docs' directory.`), + Hidden: true, + RunE: generateDocs, + } +} + +func generateDocs(cmd *cobra.Command, args []string) error { + fmt.Println("Generating docs...") + + err := doc.GenMarkdownTree(NewRootCmd(), "doc") + if err != nil { + return err + } + return nil +} diff --git a/subst/cmd/render.go b/subst/cmd/render.go new file mode 100644 index 0000000..c4d620b --- /dev/null +++ b/subst/cmd/render.go @@ -0,0 +1,64 @@ +package cmd + +import ( + "fmt" + "log" + + "github.com/MakeNowJust/heredoc" + "github.com/buttahtoast/subst/pkg/config" + "github.com/buttahtoast/subst/pkg/tool" + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + "gopkg.in/yaml.v2" +) + +func newRenderCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "render", + Short: "Render structure with substitutions", + Long: heredoc.Doc(` + Run 'subst discover' to return directories that contain plugin compatible files. Mainly used for automatic plugin discovery by ArgoCD`), + RunE: render, + } + + flags := cmd.Flags() + addCommonFlags(flags) + addRenderFlags(flags) + return cmd + +} + +func addRenderFlags(flags *flag.FlagSet) { + flags.String("ejson-secret", "", heredoc.Doc(` + Specify EJSON Secret name (each key within the secret will be used as a decryption key)`)) + flags.String("ejson-namespace", "", heredoc.Doc(` + Specify EJSON Secret namespace`)) + flags.StringSlice("ejson-key", []string{}, heredoc.Doc(` + Specify EJSON Private key used for decryption. + May be specified multiple times or separate values with commas`)) + flags.Bool("skip-decrypt", false, heredoc.Doc(` + Disable decryption of EJSON files`)) +} + +func render(cmd *cobra.Command, args []string) error { + configuration, err := config.LoadConfiguration(cfgFile, cmd) + if err != nil { + return fmt.Errorf("failed loading configuration: %w", err) + } + m, err := tool.Gather(*configuration) + if err != nil { + fmt.Println(err) + } + + for _, f := range m { + y, err := yaml.Marshal(f) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("---\n%s\n", string(y)) + } + //return yaml.Marshal(f.data) + + return nil + +} diff --git a/subst/cmd/root.go b/subst/cmd/root.go new file mode 100644 index 0000000..d2847f7 --- /dev/null +++ b/subst/cmd/root.go @@ -0,0 +1,60 @@ +package cmd + +import ( + "fmt" + "os" + + flag "github.com/spf13/pflag" + + "github.com/MakeNowJust/heredoc" + "github.com/spf13/cobra" +) + +var ( + cfgFile string +) + +func NewRootCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "subst", + Short: "Kustomize with subsitution", + Long: heredoc.Doc(` + Create Kustomize builds with stronmg substitution capabilities`), + SilenceUsage: true, + } + + cmd.AddCommand(newDiscoverCmd()) + cmd.AddCommand(newVersionCmd()) + cmd.AddCommand(newGenerateDocsCmd()) + cmd.AddCommand(newRenderCmd()) + cmd.AddCommand(newConfigCmd()) + cmd.AddCommand(newArtifactCmd()) + // + + cmd.DisableAutoGenTag = true + + return cmd +} + +// Execute runs the application +func Execute() { + if err := NewRootCmd().Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +func addCommonFlags(flags *flag.FlagSet) { + flags.StringVar(&cfgFile, "config", "", "Config file") + flags.String("root-dir", ".", heredoc.Doc(` + Root directory`)) + flags.String("ejson-pattern", ".ejson", heredoc.Doc(` + Pattern to discover ejson files`)) + flags.String("vars-pattern", ".vars", heredoc.Doc(` + Pattern to discover var files`)) + flags.StringSlice("extra-dirs", []string{}, heredoc.Doc(` + Additional directories to search for substitution files`)) + flags.Bool("debug", false, heredoc.Doc(` + Print CLI calls of external tools to stdout (caution: setting this may + expose sensitive data)`)) +} diff --git a/subst/cmd/version.go b/subst/cmd/version.go new file mode 100644 index 0000000..b3f5584 --- /dev/null +++ b/subst/cmd/version.go @@ -0,0 +1,31 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +var ( + // GitCommit is updated with the Git tag by the Goreleaser build + GitCommit = "unknown" + // BuildDate is updated with the current ISO timestamp by the Goreleaser build + BuildDate = "unknown" + // Version is updated with the latest tag by the Goreleaser build + Version = "unreleased" +) + +func newVersionCmd() *cobra.Command { + return &cobra.Command{ + Use: "version", + Short: "Print version information", + Run: version, + } +} + +func version(cmd *cobra.Command, args []string) { + fmt.Println("Version:\t", Version) + fmt.Println("Git commit:\t", GitCommit) + fmt.Println("Date:\t\t", BuildDate) + fmt.Println("License:\t Apache 2.0") +} diff --git a/subst/main.go b/subst/main.go new file mode 100644 index 0000000..151423c --- /dev/null +++ b/subst/main.go @@ -0,0 +1,9 @@ +package main + +import ( + "github.com/buttahtoast/subst/subst/cmd" +) + +func main() { + cmd.Execute() +}