diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 71f1279..c379e06 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -16,3 +16,9 @@ updates: k8s.io: patterns: - "k8s.io/*" + - package-ecosystem: 'gomod' + directory: '/deploy/tools' + schedule: + interval: 'weekly' + day: 'tuesday' + open-pull-requests-limit: 3 diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 082f1a3..6d0b73d 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -54,6 +54,10 @@ jobs: ./deploy/deploy --k8s-flavor vanilla --secret my-secret my-images > manifests/vanilla-with-secret.yaml ./deploy/deploy --k8s-flavor ocp --secret my-secret my-images > manifests/ocp-with-secret.yaml + - name: kubeconform + run: | + make -C deploy kubeconform MANIFESTS=`pwd`/manifests + - name: kube-linter uses: stackrox/kube-linter-action@v1.0.5 with: diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2ab9c64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.gotools/ diff --git a/deploy/Makefile b/deploy/Makefile new file mode 100644 index 0000000..efae404 --- /dev/null +++ b/deploy/Makefile @@ -0,0 +1,9 @@ +BASE_PATH ?= $(CURDIR) + +include $(BASE_PATH)/../make/gotools.mk + +$(call go-tool, KUBECONFORM, github.com/yannh/kubeconform/cmd/kubeconform, tools) + +.PHONY: kubeconform +kubeconform: $(KUBECONFORM) + $(KUBECONFORM) --verbose $(MANIFESTS) diff --git a/deploy/tools/go.mod b/deploy/tools/go.mod new file mode 100644 index 0000000..ed71727 --- /dev/null +++ b/deploy/tools/go.mod @@ -0,0 +1,10 @@ +module github.com/stackrox/image-prefetcher/deploy/tools + +go 1.22.1 + +require github.com/yannh/kubeconform v0.6.6 + +require ( + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect +) diff --git a/deploy/tools/go.sum b/deploy/tools/go.sum new file mode 100644 index 0000000..2e5c910 --- /dev/null +++ b/deploy/tools/go.sum @@ -0,0 +1,10 @@ +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/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/yannh/kubeconform v0.6.6 h1:2v0IKk4YCos7SMHZRkEC0D+wfcpW4aEEKy9BWJEkyV0= +github.com/yannh/kubeconform v0.6.6/go.mod h1:cxRqUWj9Rd7rkPgaAoB0jHY6TjkI7c1GLyhul2Dwz3U= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/deploy/tools/tools-import.go b/deploy/tools/tools-import.go new file mode 100644 index 0000000..62d3881 --- /dev/null +++ b/deploy/tools/tools-import.go @@ -0,0 +1,12 @@ +//go:build tools + +package tools + +// This file declares dependencies on tool for `go mod` purposes. +// See https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module +// for an explanation of the approach. + +import ( + // Tool dependencies, not used anywhere in the code. + _ "github.com/yannh/kubeconform/cmd/kubeconform" +) diff --git a/deploy/tools/tools.go b/deploy/tools/tools.go new file mode 100644 index 0000000..b2918ed --- /dev/null +++ b/deploy/tools/tools.go @@ -0,0 +1,3 @@ +package tools + +// This file only exists to prevent package loading errors for this directory. diff --git a/make/gotools.mk b/make/gotools.mk new file mode 100644 index 0000000..cbf2291 --- /dev/null +++ b/make/gotools.mk @@ -0,0 +1,130 @@ +# gotools.mk +# Simplified installation & usage of Go-based tools +# Copied from https://github.com/stackrox/stackrox/blob/master/make/gotools.mk +# DO NOT EDIT. Instead modify the upstream file and copy. +# +# Input variables: +# GOTOOLS_PROJECT_ROOT: the project root directory; defaults to $(CURDIR) +# GOTOOLS_ROOT: the directory in which this file stores auxiliary data (should be .gitignore'd); defaults to +# $(GOTOOLS_PROJECT_ROOT)/.gotools +# GOTOOLS_BIN: the directory in which binaries are stored; defaults to $(GOTOOLS_ROOT)/bin. +# +# This file defines a single (user-facing) macro, `go-tool`, which can be invoked via +# $(call go-tool VARNAME, go-pkg [, module-root]) +# where go-pkg can be: +# - an absolute Go import path with an explicit version, e.g., +# github.com/golangci/golangci-lint/cmd/golangci-lint@v1.49.0. In this case, the tool is installed via `go install`, +# and module information from the local workspace is ignored, in accordance with the normal behavior of go install +# with an explicit version given. +# - an absolute Go import path WITHOUT a version, e.g., github.com/golangci/golangci-lint/cmd/golangci-lint. In this +# case, the tool is installed via `go install` from the module rooted at $(GOTOOLS_PROJECT_ROOT), or, if +# module-root is given, from the module rooted at that (relative) path. I.e., go-pkg must be provided by a module +# listed as a requirement in /go.mod. +# - a relative Go import path (WITHOUT a version), e.g., ./tools/roxvet. In this case, the tool is installed via +# `go install` from the module rooted at $(GOTOOLS_PROJECT_ROOT). +# +# Invoking go-tool will set up Makefile rules to build the tools, using reasonable strategies for caching to avoid +# building a tool multiple times. In particular: +# - when using an absolute Go import path with a version, the rule is set up such that the `go install` command is only +# run once. +# - when using an absolute Go import path without a version, the rule is set up such that the `go install` command is +# re-run only when the respective go.mod file changes. +# - when using a relative Go import path, the rule is set up such that the `go install` command is re-run on every +# `make` invocation. +# Note that `go install` uses a pretty effective caching strategy under the hood, so even with relative import path, +# you should not expect noticeable latency. +# +# In addition to setting up the rules for building, invoking go-tool will also set the value of the variable `VARNAME` +# to the (canonical) location of the respective tool's binary, which is $(GOTOOLS_BIN)/. `$(VARNAME)` +# should be used as the only way of both invoking the tool in the Makefile as well as expressing a dependency on the +# installation of the tool. +# For use in non-Makefile scripts, a target `which-` is added, whhere is the basename of the tool binary. +# This target prints the canonical location of the binary and, if necessary, builds it. Note that invocations of +# `make which-tool` should be made with the flags `--quiet --no-print-directory` set, as otherwise the output gets +# clobbered. +# +# This file also defines two static, global targets: +# gotools-clean: this removes all gotools-related data +# gotools-all: this builds all gotools. + +GOTOOLS_PROJECT_ROOT ?= $(CURDIR) +GOTOOLS_ROOT ?= $(GOTOOLS_PROJECT_ROOT)/.gotools +GOTOOLS_BIN ?= $(GOTOOLS_ROOT)/bin + +_GOTOOLS_ALL_GOTOOLS := + +define go-tool-impl +# The variable via which the executable can be referenced +_gotools_var_name := $(strip $(1)) +# The importable Go package path that contains the "main" package for the tool +_gotools_pkg := $(firstword $(subst @, ,$(strip $(2)))) +# The version of the tool (if a version was explicitly specified) +_gotools_version := $(word 2,$(subst @, ,$(strip $(2)))) +# The folder containing the go.mod file, if not the root folder +ifeq ($(strip $(3)),) +_gotools_mod_root := $(GOTOOLS_PROJECT_ROOT) +else +_gotools_mod_root := $(strip $(3)) +endif + +# We need to strip a `/v2` (etc.) suffix to derive the tool binary's basename. +_gotools_bin_name := $$(notdir $$(shell echo "$$(_gotools_pkg)" | sed -E 's@/v[[:digit:]]+$$$$@@g')) +_gotools_canonical_bin_path := $(GOTOOLS_BIN)/$$(_gotools_bin_name) +$$(_gotools_var_name) := $$(_gotools_canonical_bin_path) + +.PHONY: which-$$(_gotools_bin_name) +which-$$(_gotools_bin_name): + @$(MAKE) $$($(strip $(1))) >&2 + @echo $$($(strip $(1))) + +ifneq ($(filter ./%,$(2)),) +# Tool is built from local files. We have to introduce a phony target and let the Go compiler +# do all the caching. +.PHONY: $$(_gotools_canonical_bin_path) +$$(_gotools_canonical_bin_path): + @echo "+ $$(notdir $$@)" + $$(SILENT)GOBIN="$$(dir $$@)" go install "$(strip $(2))" +else +# Tool is specified with version, so we don't take any info from the go.mod file. +# We install the tool into a location that is version-dependent, and build it via this target. Since the name of +# the tool under that path is version-dependent, we never have to rebuild it, as it's either the correct version, or +# does not exist. +ifneq ($$(_gotools_version),) +_gotools_versioned_bin_path := $(GOTOOLS_ROOT)/versioned/$$(_gotools_pkg)/$$(_gotools_version)/$$(_gotools_bin_name) +$$(_gotools_versioned_bin_path): + @echo "+ $$(notdir $$@)" + $$(SILENT)GOBIN="$$(dir $$@)" go install "$(strip $(2))" + +# To make the tool accessible in the canonical location, we create a symlink. This only depends on the versioned path, +# i.e., only needs to be recreated when the version is bumped. +$$(_gotools_canonical_bin_path): $$(_gotools_versioned_bin_path) + @mkdir -p "$(GOTOOLS_BIN)" + $$(SILENT)ln -sf "$$<" "$$@" + +else + +# Tool is specified with an absolute path without a version. Take info from go.mod file in the respective directory. +$$(_gotools_canonical_bin_path): $$(_gotools_mod_root)/go.mod $$(_gotools_mod_root)/go.sum + @echo "+ $$(notdir $$@)" + $$(SILENT)cd "$$(dir $$<)" && GOBIN="$$(dir $$@)" go install "$(strip $(2))" + +endif +endif + +_GOTOOLS_ALL_GOTOOLS += $$(_gotools_canonical_bin_path) + +endef + +go-tool = $(eval $(call go-tool-impl,$(1),$(2),$(3))) + + +.PHONY: gotools-clean +gotools-clean: + @echo "+ $@" + @git clean -dfX "$(GOTOOLS_ROOT)" # don't use rm -rf to avoid catastrophes + +.PHONY: gotools-all +gotools-all: + @# these cannot be dependencies, as we need `$(_GOTOOLS_ALL_GOTOOLS)` to be + @# evaluated when the target is actually run. + $(MAKE) $(_GOTOOLS_ALL_GOTOOLS)