diff --git a/.custom-gcl.yml b/.custom-gcl.yml new file mode 100644 index 0000000000..84754359fa --- /dev/null +++ b/.custom-gcl.yml @@ -0,0 +1,6 @@ +version: v2.2.1 +name: golangci-kube-api-linter +destination: ./bin +plugins: +- module: 'sigs.k8s.io/kube-api-linter' + version: 'v0.0.0-20250715075424-4fab82d26a8e' # Pin to a commit while there's no tag diff --git a/.github/workflows/kal.yml b/.github/workflows/kal.yml new file mode 100644 index 0000000000..d657969f5d --- /dev/null +++ b/.github/workflows/kal.yml @@ -0,0 +1,25 @@ +name: PR golangci-lint + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +# Remove all permissions from GITHUB_TOKEN except metadata. +permissions: {} + +jobs: + golangci: + name: kube-api-lint + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - name: Set up Go + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # tag=v5.5.0 + - name: Install Golang CI Lint + run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.2.1 + - name: Build KAL + run: golangci-lint custom + - name: run api linter + run: ./bin/golangci-kube-api-linter run -c ./.golangci-kal.yml ./... diff --git a/.golangci-kal.yml b/.golangci-kal.yml new file mode 100644 index 0000000000..aad23ab40d --- /dev/null +++ b/.golangci-kal.yml @@ -0,0 +1,36 @@ +version: "2" +linters: + default: none + enable: + - kubeapilinter + settings: + custom: + kubeapilinter: + type: module + description: Kube API LInter lints Kube like APIs based on API conventions and best practices. + settings: + linters: + enable: + - "duplicatemarkers" # Ensure there are no exact duplicate markers. for types and fields. + - "jsontags" # Ensure every field has a json tag. + - "nofloats" # Ensure floats are not used. + - "nomaps" # Ensure maps are not used. + - "nophase" # Phase fields are discouraged by the Kube API conventions, use conditions instead. + - "statussubresource" # All root objects that have a `status` field should have a status subresource. + - "uniquemarkers" # Ensure that types and fields do not contain more than a single definition of a marker that should only be present once. + disable: + - "*" + lintersConfig: {} + exclusions: + generated: strict + paths: + - conformance/ + paths-except: + - apis/ + - apisx/ +issues: + max-issues-per-linter: 0 + max-same-issues: 0 +run: + timeout: 5m + tests: false diff --git a/apis/v1/httproute_types.go b/apis/v1/httproute_types.go index e59ebf7bcc..157932e971 100644 --- a/apis/v1/httproute_types.go +++ b/apis/v1/httproute_types.go @@ -1590,7 +1590,6 @@ type HTTPBackendRef struct { // +optional // +kubebuilder:validation:MaxItems=16 // +kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))" - // +kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))" // +kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1" // +kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1" // +kubebuilder:validation:XValidation:message="RequestRedirect filter cannot be repeated",rule="self.filter(f, f.type == 'RequestRedirect').size() <= 1" diff --git a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml index cf2b274655..fe5b7f0330 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml @@ -1524,10 +1524,6 @@ spec: maxItems: 16 type: array x-kubernetes-validations: - - message: May specify either httpRouteFilterRequestRedirect - or httpRouteFilterRequestRewrite, but not both - rule: '!(self.exists(f, f.type == ''RequestRedirect'') - && self.exists(f, f.type == ''URLRewrite''))' - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both rule: '!(self.exists(f, f.type == ''RequestRedirect'') @@ -5144,10 +5140,6 @@ spec: maxItems: 16 type: array x-kubernetes-validations: - - message: May specify either httpRouteFilterRequestRedirect - or httpRouteFilterRequestRewrite, but not both - rule: '!(self.exists(f, f.type == ''RequestRedirect'') - && self.exists(f, f.type == ''URLRewrite''))' - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both rule: '!(self.exists(f, f.type == ''RequestRedirect'') diff --git a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml index 8533381fc2..1824bd5e19 100644 --- a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml @@ -1191,10 +1191,6 @@ spec: maxItems: 16 type: array x-kubernetes-validations: - - message: May specify either httpRouteFilterRequestRedirect - or httpRouteFilterRequestRewrite, but not both - rule: '!(self.exists(f, f.type == ''RequestRedirect'') - && self.exists(f, f.type == ''URLRewrite''))' - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both rule: '!(self.exists(f, f.type == ''RequestRedirect'') @@ -3995,10 +3991,6 @@ spec: maxItems: 16 type: array x-kubernetes-validations: - - message: May specify either httpRouteFilterRequestRedirect - or httpRouteFilterRequestRewrite, but not both - rule: '!(self.exists(f, f.type == ''RequestRedirect'') - && self.exists(f, f.type == ''URLRewrite''))' - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both rule: '!(self.exists(f, f.type == ''RequestRedirect'')