diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index 7c6d4cb..a9237a9 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check Latest Commit Message run: make test-commit @@ -27,7 +27,7 @@ jobs: if: github.event_name == 'pull_request' steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Get PR Commits id: get-pr-commits @@ -52,7 +52,7 @@ jobs: if: github.event_name == 'pull_request' steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check Pull Request Title uses: deepakputhraya/action-pr-title@master @@ -80,7 +80,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check License Lines uses: kt3k/license_checker@v1.0.6 @@ -89,15 +89,15 @@ jobs: name: Lint runs-on: ubuntu-latest steps: - - uses: actions/setup-go@v3 + - uses: actions/setup-go@v5 with: - go-version: "1.19" + go-version: "1.22" - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Lint uses: golangci/golangci-lint-action@v3 with: - version: v1.52.2 + version: v1.57.1 args: --timeout 3m diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 9ba8189..6160792 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -10,14 +10,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: - go-version: "1.19" + go-version: "1.21" # NOTE: removing support for snapcraft as their CLI has become increasingly unstable and errors have become # common place. See https://github.com/snapcore/action-publish/issues/28 for an example of some of the issues diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c249e6b..b88238b 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -15,16 +15,16 @@ jobs: fail-fast: false matrix: include: - - go-version: "1.19" - - go-version: "1.20" + - go-version: "1.21" + - go-version: "1.22" steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} @@ -42,16 +42,16 @@ jobs: fail-fast: false matrix: include: - - go-version: "1.19" - - go-version: "1.20" + - go-version: "1.21" + - go-version: "1.22" steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} @@ -59,9 +59,9 @@ jobs: run: make build - name: Store Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: operator-builder + name: operator-builder-${{ matrix.go-version }} path: bin/operator-builder # @@ -78,36 +78,36 @@ jobs: - name: Standalone Operator (Current Go Version) artifact: standalone-codebase test-workload-path: test/cases/standalone - go-version: "1.20" + go-version: "1.22" - name: Standalone Edge Cases Operator (Current Go Version - 1) artifact: standalone-edge-codebase test-workload-path: test/cases/edge-standalone - go-version: "1.19" + go-version: "1.21" - name: Workload Collection Operator (Current Go Version) artifact: collection-codebase test-workload-path: test/cases/collection - go-version: "1.20" + go-version: "1.22" - name: Workload Collection Edge Cases Operator (Current Go Version - 1) artifact: collection-edge-codebase test-workload-path: test/cases/edge-collection - go-version: "1.19" + go-version: "1.21" env: TEST_WORKLOAD_PATH: "${{ matrix.test-workload-path }}" TEST_PATH: "/tmp/operator-builder-func-test" steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Download operator-builder Binary - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: operator-builder + name: operator-builder-${{ matrix.go-version }} path: bin - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} @@ -122,7 +122,7 @@ jobs: - name: Store ${{ matrix.name }} Codebase if: github.event_name == 'pull_request' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.artifact }} path: ${{ env.TEST_PATH }} @@ -145,22 +145,22 @@ jobs: artifact: standalone-codebase test-build: "true" test-deploy: "true" - go-version: "1.20" + go-version: "1.22" - name: Standalone Edge Cases Operator (Current Go Version - 1) artifact: standalone-edge-codebase test-build: "false" test-deploy: "false" - go-version: "1.19" + go-version: "1.21" - name: Workload Collection Operator (Current Go Version) artifact: collection-codebase test-build: "true" test-deploy: "false" - go-version: "1.20" + go-version: "1.22" - name: Workload Collection Edge Cases Operator (Current Go Version - 1) artifact: collection-edge-codebase test-build: "true" test-deploy: "false" - go-version: "1.19" + go-version: "1.21" services: registry: image: registry:2 @@ -171,17 +171,17 @@ jobs: working-directory: /tmp/operator-builder-test steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} - name: Download ${{ matrix.name }} Codebase - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: ${{ matrix.artifact }} path: /tmp/operator-builder-test diff --git a/.golangci.yml b/.golangci.yml index 93fbfde..f45362f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -72,7 +72,7 @@ linters: - asciicheck - bodyclose #- cyclop - - depguard + #- depguard - dogsled - dupl - durationcheck @@ -134,7 +134,7 @@ linters: - wastedassign - whitespace - wrapcheck - - wsl + #- wsl issues: # Excluding configuration per-path, per-linter, per-text and per-source @@ -147,6 +147,12 @@ issues: - path: internal/commands/*\.go linters: - gochecknoglobals + - path: internal/plugins/workload/v1/scaffolds + linters: + - goconst + - path: internal/plugins/config/v1/plugin.go + linters: + - gocritic - path: internal/plugins/workload/v1/scaffolds/templates/readme.go linters: - gomnd diff --git a/Makefile b/Makefile index f5023e1..6a7e6ab 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ install: build # # traditional testing # -GOLANGCI_LINT_VERSION ?= v1.52.2 +GOLANGCI_LINT_VERSION ?= v1.57.1 install-linter: go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) diff --git a/go.sum b/go.sum index fc54c6c..68cf3df 100644 --- a/go.sum +++ b/go.sum @@ -312,6 +312,7 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= diff --git a/internal/markers/marker/argument.go b/internal/markers/marker/argument.go index b54614d..868427a 100644 --- a/internal/markers/marker/argument.go +++ b/internal/markers/marker/argument.go @@ -35,7 +35,6 @@ type Argument struct { isSet bool } -//nolint:gocritic //needed to implement string interface func (a Argument) String() string { if a.Optional { return fmt.Sprintf("", a.Type) diff --git a/internal/plugins/workload/v1/scaffolds/init.go b/internal/plugins/workload/v1/scaffolds/init.go index 13d6bb3..8c8f39c 100644 --- a/internal/plugins/workload/v1/scaffolds/init.go +++ b/internal/plugins/workload/v1/scaffolds/init.go @@ -13,7 +13,6 @@ import ( "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "sigs.k8s.io/kubebuilder/v3/pkg/plugins" kustomizecommonv1 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/common/kustomize/v1" - scaffoldsv4 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v4/scaffolds" "github.com/nukleros/operator-builder/internal/plugins/workload/v1/scaffolds/templates" "github.com/nukleros/operator-builder/internal/plugins/workload/v1/scaffolds/templates/cli" @@ -24,7 +23,8 @@ import ( ) const ( - operatorSDKVersion = "v1.28.0" + operatorSDKVersion = "v1.28.0" + controllerToolsVersion = "v0.14.0" ) var _ plugins.Scaffolder = &initScaffolder{} @@ -100,13 +100,12 @@ func (s *initScaffolder) Scaffold() error { ControllerImg: s.controllerImg, }, &templates.Makefile{ - RootCmdName: s.cliRootCommandName, - ControllerImg: s.controllerImg, - EnableOLM: s.enableOlm, - KustomizeVersion: kustomizecommonv1.KustomizeVersion, - ControllerToolsVersion: scaffoldsv4.ControllerToolsVersion, - ControllerRuntimeVersion: scaffoldsv4.ControllerRuntimeVersion, - OperatorSDKVersion: operatorSDKVersion, + RootCmdName: s.cliRootCommandName, + ControllerImg: s.controllerImg, + EnableOLM: s.enableOlm, + KustomizeVersion: kustomizecommonv1.KustomizeVersion, + ControllerToolsVersion: controllerToolsVersion, + OperatorSDKVersion: operatorSDKVersion, }, &e2e.Test{}, ); err != nil { diff --git a/internal/plugins/workload/v1/scaffolds/templates/controller/controller.go b/internal/plugins/workload/v1/scaffolds/templates/controller/controller.go index 98cf663..cbac80b 100644 --- a/internal/plugins/workload/v1/scaffolds/templates/controller/controller.go +++ b/internal/plugins/workload/v1/scaffolds/templates/controller/controller.go @@ -65,6 +65,7 @@ func (f *Controller) setOtherImports() { `ctrl "sigs.k8s.io/controller-runtime"`, `"sigs.k8s.io/controller-runtime/pkg/client"`, `"sigs.k8s.io/controller-runtime/pkg/controller"`, + `"sigs.k8s.io/controller-runtime/pkg/manager"`, `"github.com/nukleros/operator-builder-tools/pkg/controller/phases"`, `"github.com/nukleros/operator-builder-tools/pkg/controller/predicates"`, `"github.com/nukleros/operator-builder-tools/pkg/controller/workload"`, @@ -143,6 +144,7 @@ type {{ .Resource.Kind }}Reconciler struct { FieldManager string Watches []client.Object Phases *phases.Registry + Manager manager.Manager } func New{{ .Resource.Kind }}Reconciler(mgr ctrl.Manager) *{{ .Resource.Kind }}Reconciler { @@ -154,6 +156,7 @@ func New{{ .Resource.Kind }}Reconciler(mgr ctrl.Manager) *{{ .Resource.Kind }}Re Log: ctrl.Log.WithName("controllers").WithName("{{ .Resource.Group }}").WithName("{{ .Resource.Kind }}"), Watches: []client.Object{}, Phases: &phases.Registry{}, + Manager: mgr, } } @@ -291,7 +294,7 @@ func (r *{{ .Resource.Kind }}Reconciler) EnqueueRequestOnCollectionChange(req *w } // create a function which maps this specific reconcile request - mapFn := func(collection client.Object) []reconcile.Request { + mapFn := func(_ context.Context, collection client.Object) []reconcile.Request { return []reconcile.Request{ { NamespacedName: types.NamespacedName{ @@ -304,7 +307,7 @@ func (r *{{ .Resource.Kind }}Reconciler) EnqueueRequestOnCollectionChange(req *w // watch the collection and use our map function to enqueue the request if err := r.Controller.Watch( - &source.Kind{Type: req.Collection}, + source.Kind(r.Manager.GetCache(), req.Collection), handler.EnqueueRequestsFromMapFunc(mapFn), predicate.Funcs{ UpdateFunc: func(e event.UpdateEvent) bool { @@ -373,6 +376,11 @@ func (r *{{ .Resource.Kind }}Reconciler) GetController() controller.Controller { return r.Controller } +// GetManager returns the manager object assocated with the reconciler. +func (r *{{ .Resource.Kind }}Reconciler) GetManager() manager.Manager { + return r.Manager +} + // GetWatches returns the objects which are current being watched by the reconciler. func (r *{{ .Resource.Kind }}Reconciler) GetWatches() []client.Object { return r.Watches diff --git a/internal/plugins/workload/v1/scaffolds/templates/gomod.go b/internal/plugins/workload/v1/scaffolds/templates/gomod.go index 5f34d81..3f0c678 100644 --- a/internal/plugins/workload/v1/scaffolds/templates/gomod.go +++ b/internal/plugins/workload/v1/scaffolds/templates/gomod.go @@ -28,28 +28,26 @@ type GoMod struct { // See https://github.com/vmware-tanzu-labs/operator-builder/issues/250 func goModDependencyMap() map[string]string { return map[string]string{ - "github.com/go-logr/logr": "v1.2.3", - "github.com/nukleros/operator-builder-tools": "v0.3.0", - "github.com/onsi/ginkgo": "v1.16.5", - "github.com/onsi/gomega": "v1.24.0", - "github.com/spf13/cobra": "v1.6.1", - "github.com/stretchr/testify": "v1.8.1", - "google.golang.org/api": "v0.102.0", + "github.com/go-logr/logr": "v1.4.1", + "github.com/nukleros/operator-builder-tools": "v0.4.0", + "github.com/onsi/ginkgo/v2": "v2.17.1", + "github.com/onsi/gomega": "v1.32.0", + "github.com/spf13/cobra": "v1.8.0", + "github.com/stretchr/testify": "v1.9.0", "gopkg.in/yaml.v2": "v2.4.0", - "k8s.io/api": "v0.25.3", - "k8s.io/apimachinery": "v0.25.3", - "k8s.io/client-go": "v0.25.3", - "sigs.k8s.io/controller-runtime": "v0.13.1", + "k8s.io/api": "v0.29.4", + "k8s.io/apimachinery": "v0.29.4", + "k8s.io/client-go": "v0.29.4", + "sigs.k8s.io/controller-runtime": "v0.17.3", "sigs.k8s.io/kubebuilder/v3": "v3.7.0", - "sigs.k8s.io/yaml": "v1.3.0", + "sigs.k8s.io/yaml": "v1.4.0", } } +// NOTE: there are no indirect dependencies to manage at this time, but we will leave +// it in place when the time comes to use it. func goModIndirectDependencyMap() map[string]string { - return map[string]string{ - "gopkg.in/check.v1": "v1.0.0-20201130134442-10cb98267c6c", - "cloud.google.com/go/compute/metadata": "v0.2.1", - } + return map[string]string{} } func (f *GoMod) SetTemplateDefaults() error { @@ -77,9 +75,11 @@ require ( {{- end }} ) +{{ if gt (len $.IndirectDependencies) 0 }} require ( {{ range $package, $version := $.IndirectDependencies }} "{{ $package }}" {{ $version }} {{- end }} ) +{{- end }} ` diff --git a/internal/plugins/workload/v1/scaffolds/templates/main.go b/internal/plugins/workload/v1/scaffolds/templates/main.go index 17e874f..c5c8692 100644 --- a/internal/plugins/workload/v1/scaffolds/templates/main.go +++ b/internal/plugins/workload/v1/scaffolds/templates/main.go @@ -179,6 +179,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/healthz" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" %s ) @@ -201,16 +202,20 @@ func init() { func main() { {{- if not .ComponentConfig }} var metricsAddr string - var enableLeaderElection bool - var probeAddr string + var secureMetrics bool + var enableHTTP2 bool flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") flag.BoolVar(&enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. " + "Enabling this will ensure there is only one active controller manager.") + flag.BoolVar(&secureMetrics, "metrics-secure", false, + "If set the metrics endpoint is served securely") + flag.BoolVar(&enableHTTP2, "enable-http2", false, + "If set, HTTP/2 will be enabled for the metrics and webhook servers") {{- else }} var configFile string flag.StringVar(&configFile, "config", "", @@ -235,13 +240,32 @@ func main() { ) {{ if not .ComponentConfig }} + // if the enable-http2 flag is false (the default), http/2 should be disabled + // due to its vulnerabilities. More specifically, disabling http/2 will + // prevent from being vulnerable to the HTTP/2 Stream Cancellation and + // Rapid Reset CVEs. For more information see: + // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 + // - https://github.com/advisories/GHSA-4374-p667-p6c8 + disableHTTP2 := func(c *tls.Config) { + setupLog.Info("disabling http/2") + c.NextProtos = []string{"http/1.1"} + } + + tlsOpts := []func(*tls.Config){} + if !enableHTTP2 { + tlsOpts = append(tlsOpts, disableHTTP2) + } + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ Scheme: scheme, - MetricsBindAddress: metricsAddr, - Port: 9443, HealthProbeBindAddress: probeAddr, LeaderElection: enableLeaderElection, LeaderElectionID: "{{ hashFNV .Repo }}.{{ .Domain }}", + Metrics: metricsserver.Options{ + BindAddress: metricsAddr, + SecureServing: secureMetrics, + TLSOpts: tlsOpts, + }, }) {{- else }} var err error diff --git a/internal/plugins/workload/v1/scaffolds/templates/makefile.go b/internal/plugins/workload/v1/scaffolds/templates/makefile.go index 1301a2d..716ca44 100644 --- a/internal/plugins/workload/v1/scaffolds/templates/makefile.go +++ b/internal/plugins/workload/v1/scaffolds/templates/makefile.go @@ -26,10 +26,9 @@ type Makefile struct { ControllerImg string EnableOLM bool - ControllerToolsVersion string - KustomizeVersion string - ControllerRuntimeVersion string - OperatorSDKVersion string + ControllerToolsVersion string + KustomizeVersion string + OperatorSDKVersion string } func (f *Makefile) SetTemplateDefaults() error { diff --git a/internal/utils/version.go b/internal/utils/version.go index 661260b..6dc6cc9 100644 --- a/internal/utils/version.go +++ b/internal/utils/version.go @@ -6,8 +6,8 @@ package utils const ( // specifies the minimum version required to build the generated project. - GeneratedGoVersionMinimum = "1.18" + GeneratedGoVersionMinimum = "1.21" // specifies the preferred version. - GeneratedGoVersionPreferred = "1.19" + GeneratedGoVersionPreferred = "1.22" ) diff --git a/internal/workload/v1/manifests/child_resource.go b/internal/workload/v1/manifests/child_resource.go index ddfe72c..77fdee1 100644 --- a/internal/workload/v1/manifests/child_resource.go +++ b/internal/workload/v1/manifests/child_resource.go @@ -62,7 +62,6 @@ func NewChildResource(object unstructured.Unstructured) (*ChildResource, error) }, nil } -//nolint:gocritic // needed to satisfy the stringer interface func (resource ChildResource) String() string { return fmt.Sprintf( "{Group: %s, Version: %s, Kind: %s, Name: %s}", diff --git a/internal/workload/v1/manifests/manifest.go b/internal/workload/v1/manifests/manifest.go index a7099b7..d0ff197 100644 --- a/internal/workload/v1/manifests/manifest.go +++ b/internal/workload/v1/manifests/manifest.go @@ -65,7 +65,7 @@ func (manifest *Manifest) ExtractManifests() []string { for _, line := range lines { if strings.TrimRight(line, " ") == "---" { - if len(content) > 0 { + if content != "" { manifests = append(manifests, content) content = "" } @@ -74,7 +74,7 @@ func (manifest *Manifest) ExtractManifests() []string { } } - if len(content) > 0 { + if content != "" { manifests = append(manifests, content) } diff --git a/internal/workload/v1/markers/collection_field_marker.go b/internal/workload/v1/markers/collection_field_marker.go index 0e3442d..2fb639f 100644 --- a/internal/workload/v1/markers/collection_field_marker.go +++ b/internal/workload/v1/markers/collection_field_marker.go @@ -23,7 +23,6 @@ const ( // is discovered different via a different prefix. type CollectionFieldMarker FieldMarker -//nolint:gocritic //needed to implement string interface func (cfm CollectionFieldMarker) String() string { return fmt.Sprintf("CollectionFieldMarker{Name: %s Type: %v Description: %q Default: %v}", cfm.GetName(), diff --git a/internal/workload/v1/markers/field_marker.go b/internal/workload/v1/markers/field_marker.go index 89a16a5..e38fa25 100644 --- a/internal/workload/v1/markers/field_marker.go +++ b/internal/workload/v1/markers/field_marker.go @@ -41,7 +41,6 @@ type FieldMarker struct { originalValue interface{} } -//nolint:gocritic //needed to implement string interface func (fm FieldMarker) String() string { var arbitraryBool bool