Add kube-api-linter plugin to golangci-lint

This commit is contained in:
Joel Speed
2025-04-30 14:59:18 +01:00
parent 1b4c5b3f86
commit 2f50d0a510
9 changed files with 156 additions and 9 deletions

View File

@@ -111,6 +111,13 @@ linters:
linters:
- ineffassign
# Kube-API-Linter should only be run on the API definitions
- linters:
- kubeapilinter
path-except: staging/src/k8s.io/api/.*
# Exceptions for kube-api-linter.
# Exceptions are used for kube-api-linter to ignore existing issues that cannot be fixed without breaking changes.
default: standard
enable: # please keep this alphabetized
@@ -121,6 +128,7 @@ linters:
- govet
- errorlint
- ineffassign
- kubeapilinter
- logcheck
- revive
- staticcheck
@@ -202,6 +210,40 @@ linters:
# this restriction. Whether we then do a global search/replace remains
# to be decided.
with-helpers .*
kubeapilinter:
path: _output/local/bin/kube-api-linter.so
description: kube-api-linter and lints Kube like APIs based on API conventions and best practices.
original-url: sigs.k8s.io/kube-api-linter
settings:
linters:
disable:
- '*'
enable:
# - "commentstart" # Ensure comments start with the serialized version of the field name.
# - "conditions" # Ensure conditions have the correct json tags and markers.
# - "integers" # Ensure only int32 and int64 are used for integers.
# - "jsontags" # Ensure every field has a json tag.
# - "maxlength" # Ensure all strings and arrays have maximum lengths/maximum items. ONLY for CRDs until declarative markers exist in core types.
# - "nobools" # Bools do not evolve over time, should use enums instead.
# - "nofloats" # Ensure floats are not used.
# - "nomaps" # Ensure maps are not used, unless they are `map[string]string` (for labels/annotations/etc).
# - "nophase" # Ensure field names do not have the word "phase" in them.
# - "optionalorrequired" # Every field should be marked as `+optional` xor `+required`.
# - "requiredfields" # Required fields should not be pointers, and should not have `omitempty`.
lintersConfig:
# conditions:
# isFirstField: Warn # Require conditions to be the first field in the status struct.
# usePatchStrategy: SuggestFix # Conditions should not use the patch strategy on CRDs.
# useProtobuf: SuggestFix # We don't use protobuf, so protobuf tags are not required.
# jsonTags:
# jsonTagRegex: "^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$" # The default regex is appropriate for our use case.
# nomaps:
# policy: AllowStringToStringMaps # Determines how the linter should handle maps of basic types. Maps of objects are always disallowed.
# optionalOrRequired:
# preferredOptionalMarker: optional # The preferred optional marker to use, fixes will suggest to use this marker. Defaults to `optional`.
# preferredRequiredMarker: required # The preferred required marker to use, fixes will suggest to use this marker. Defaults to `required`.
# requiredFields:
# pointerPolicy: SuggestFix # Defaults to `SuggestFix`. We want our required fields to not be pointers.
depguard:
rules:
main:

View File

@@ -127,6 +127,13 @@ linters:
- gocritic
text: "assignOp:"
# Kube-API-Linter should only be run on the API definitions
- linters:
- kubeapilinter
path-except: staging/src/k8s.io/api/.*
# Exceptions for kube-api-linter.
# Exceptions are used for kube-api-linter to ignore existing issues that cannot be fixed without breaking changes.
default: none
enable: # please keep this alphabetized
@@ -136,6 +143,7 @@ linters:
- gocritic
- govet
- ineffassign
- kubeapilinter
- logcheck
- revive
- staticcheck
@@ -216,6 +224,40 @@ linters:
# this restriction. Whether we then do a global search/replace remains
# to be decided.
with-helpers .*
kubeapilinter:
path: _output/local/bin/kube-api-linter.so
description: kube-api-linter and lints Kube like APIs based on API conventions and best practices.
original-url: sigs.k8s.io/kube-api-linter
settings:
linters:
disable:
- '*'
enable:
# - "commentstart" # Ensure comments start with the serialized version of the field name.
# - "conditions" # Ensure conditions have the correct json tags and markers.
# - "integers" # Ensure only int32 and int64 are used for integers.
# - "jsontags" # Ensure every field has a json tag.
# - "maxlength" # Ensure all strings and arrays have maximum lengths/maximum items. ONLY for CRDs until declarative markers exist in core types.
# - "nobools" # Bools do not evolve over time, should use enums instead.
# - "nofloats" # Ensure floats are not used.
# - "nomaps" # Ensure maps are not used, unless they are `map[string]string` (for labels/annotations/etc).
# - "nophase" # Ensure field names do not have the word "phase" in them.
# - "optionalorrequired" # Every field should be marked as `+optional` xor `+required`.
# - "requiredfields" # Required fields should not be pointers, and should not have `omitempty`.
lintersConfig:
# conditions:
# isFirstField: Warn # Require conditions to be the first field in the status struct.
# usePatchStrategy: SuggestFix # Conditions should not use the patch strategy on CRDs.
# useProtobuf: SuggestFix # We don't use protobuf, so protobuf tags are not required.
# jsonTags:
# jsonTagRegex: "^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$" # The default regex is appropriate for our use case.
# nomaps:
# policy: AllowStringToStringMaps # Determines how the linter should handle maps of basic types. Maps of objects are always disallowed.
# optionalOrRequired:
# preferredOptionalMarker: optional # The preferred optional marker to use, fixes will suggest to use this marker. Defaults to `optional`.
# preferredRequiredMarker: required # The preferred required marker to use, fixes will suggest to use this marker. Defaults to `required`.
# requiredFields:
# pointerPolicy: SuggestFix # Defaults to `SuggestFix`. We want our required fields to not be pointers.
depguard:
rules:
main:

View File

@@ -144,6 +144,12 @@ linters:
{{- end}}
# Kube-API-Linter should only be run on the API definitions
- linters:
- kubeapilinter
path-except: staging/src/k8s.io/api/.*
{{include "hack/kube-api-linter/exceptions.yaml" | indent 6 | trim}}
default: {{if .Base -}} none {{- else -}} standard {{- end}}
enable: # please keep this alphabetized
@@ -156,6 +162,7 @@ linters:
- errorlint
{{- end}}
- ineffassign
- kubeapilinter
- logcheck
- revive
- staticcheck
@@ -175,6 +182,12 @@ linters:
settings:
config: |
{{include "hack/logcheck.conf" | indent 12 | trim}}
kubeapilinter:
path: _output/local/bin/kube-api-linter.so
description: kube-api-linter and lints Kube like APIs based on API conventions and best practices.
original-url: sigs.k8s.io/kube-api-linter
settings:
{{include "hack/kube-api-linter/kube-api-linter.yaml" | indent 10 | trim}}
depguard:
rules:
main:

View File

@@ -0,0 +1,8 @@
# See the OWNERS docs at https://go.k8s.io/owners
options:
no_parent_owners: true
reviewers:
- api-approvers
- JoelSpeed
approvers:
- api-approvers

View File

@@ -0,0 +1,2 @@
# Exceptions for kube-api-linter.
# Exceptions are used for kube-api-linter to ignore existing issues that cannot be fixed without breaking changes.

View File

@@ -0,0 +1,30 @@
linters:
disable:
- '*'
enable:
# - "commentstart" # Ensure comments start with the serialized version of the field name.
# - "conditions" # Ensure conditions have the correct json tags and markers.
# - "integers" # Ensure only int32 and int64 are used for integers.
# - "jsontags" # Ensure every field has a json tag.
# - "maxlength" # Ensure all strings and arrays have maximum lengths/maximum items. ONLY for CRDs until declarative markers exist in core types.
# - "nobools" # Bools do not evolve over time, should use enums instead.
# - "nofloats" # Ensure floats are not used.
# - "nomaps" # Ensure maps are not used, unless they are `map[string]string` (for labels/annotations/etc).
# - "nophase" # Ensure field names do not have the word "phase" in them.
# - "optionalorrequired" # Every field should be marked as `+optional` xor `+required`.
# - "requiredfields" # Required fields should not be pointers, and should not have `omitempty`.
lintersConfig:
# conditions:
# isFirstField: Warn # Require conditions to be the first field in the status struct.
# usePatchStrategy: SuggestFix # Conditions should not use the patch strategy on CRDs.
# useProtobuf: SuggestFix # We don't use protobuf, so protobuf tags are not required.
# jsonTags:
# jsonTagRegex: "^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$" # The default regex is appropriate for our use case.
# nomaps:
# policy: AllowStringToStringMaps # Determines how the linter should handle maps of basic types. Maps of objects are always disallowed.
# optionalOrRequired:
# preferredOptionalMarker: optional # The preferred optional marker to use, fixes will suggest to use this marker. Defaults to `optional`.
# preferredRequiredMarker: required # The preferred required marker to use, fixes will suggest to use this marker. Defaults to `required`.
# requiredFields:
# pointerPolicy: SuggestFix # Defaults to `SuggestFix`. We want our required fields to not be pointers.

View File

@@ -4,6 +4,7 @@ go 1.24.0
tool (
github.com/golangci/golangci-lint/v2/cmd/golangci-lint
sigs.k8s.io/kube-api-linter/pkg/plugin
sigs.k8s.io/logtools/logcheck
)
@@ -51,7 +52,7 @@ require (
github.com/curioswitch/go-reassign v0.3.0 // indirect
github.com/daixiang0/gci v0.13.6 // indirect
github.com/dave/dst v0.27.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/denis-tingaikin/go-header v0.5.0 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/ettle/strcase v0.2.0 // indirect
@@ -73,7 +74,7 @@ require (
github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect
github.com/golangci/go-printf-func-name v0.1.0 // indirect
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect
@@ -134,7 +135,7 @@ require (
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/polyfloyd/go-errorlint v1.8.0 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
@@ -205,7 +206,9 @@ require (
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
honnef.co/go/tools v0.6.1 // indirect
k8s.io/apimachinery v0.32.3 // indirect
mvdan.cc/gofumpt v0.8.0 // indirect
mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 // indirect
sigs.k8s.io/kube-api-linter v0.0.0-20250516124914-6df69a12c92c // indirect
sigs.k8s.io/logtools v0.9.0 // indirect
)

View File

@@ -144,8 +144,9 @@ github.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEy
github.com/dave/jennifer v1.7.1 h1:B4jJJDHelWcDhlRQxWeo0Npa/pYKBLrirAQoTN45txo=
github.com/dave/jennifer v1.7.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc=
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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8=
github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
@@ -243,8 +244,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
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/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 h1:WUvBfQL6EW/40l6OmeSBYQJNSif4O11+bmWEz+C7FYw=
github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E=
github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUPPyAKJuzv8pEJU=
@@ -450,8 +451,9 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/polyfloyd/go-errorlint v1.8.0 h1:DL4RestQqRLr8U4LygLw8g2DX6RN1eBJOpa2mzsrl1Q=
github.com/polyfloyd/go-errorlint v1.8.0/go.mod h1:G2W0Q5roxbLCt0ZQbdoxQxXktTjwNyDbEaj3n7jvl4s=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
@@ -994,6 +996,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI=
honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4=
k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U=
k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
mvdan.cc/gofumpt v0.8.0 h1:nZUCeC2ViFaerTcYKstMmfysj6uhQrA2vJe+2vwGU6k=
mvdan.cc/gofumpt v0.8.0/go.mod h1:vEYnSzyGPmjvFkqJWtXkh79UwPWP9/HMxQdGEXZHjpg=
mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 h1:WjUu4yQoT5BHT1w8Zu56SP8367OuBV5jvo+4Ulppyf8=
@@ -1001,5 +1005,7 @@ mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4/go.mod h1:rthT7OuvRbaGcd5gin
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/kube-api-linter v0.0.0-20250516124914-6df69a12c92c h1:sybeA6NAACfxBiZLdY9iRNAT9jVs25TwBnLnqG+TyTs=
sigs.k8s.io/kube-api-linter v0.0.0-20250516124914-6df69a12c92c/go.mod h1:tnzp9Oj2Qi0qPg5t5tbDrUixTlZLjPpEjzk1kxO/2EE=
sigs.k8s.io/logtools v0.9.0 h1:IMP/HTDkfM6rg6os/tcEjmQeIHyOyu/enduM/cOPGNQ=
sigs.k8s.io/logtools v0.9.0/go.mod h1:74Z5BP7ehrMHi/Q31W1gSf8YgwT/4GPjVH5xPSPeZA0=

View File

@@ -129,13 +129,14 @@ kube::util::ensure-temp-dir
# Installing from source (https://golangci-lint.run/welcome/install/#install-from-sources)
# is not recommended, but for Kubernetes we prefer it because it avoids the need for
# pre-built binaries for different platforms and gives more insights on dependencies.
echo "installing golangci-lint and logcheck plugin from hack/tools into ${GOBIN}"
echo "installing golangci-lint, logcheck and kube-api-linter plugins from hack/tools/golangci-lint into ${GOBIN}"
GOTOOLCHAIN="$(kube::golang::hack_tools_gotoolchain)" go -C "${KUBE_ROOT}/hack/tools/golangci-lint" install github.com/golangci/golangci-lint/v2/cmd/golangci-lint
if [ "${golangci_config}" ]; then
# This cannot be used without a config.
# Plugins cannot be used without a config.
# This uses `go build` because `go install -buildmode=plugin` doesn't work
# (on purpose: https://github.com/golang/go/issues/64964).
GOTOOLCHAIN="$(kube::golang::hack_tools_gotoolchain)" go -C "${KUBE_ROOT}/hack/tools/golangci-lint" build -o "${GOBIN}/logcheck.so" -buildmode=plugin sigs.k8s.io/logtools/logcheck/plugin
GOTOOLCHAIN="$(kube::golang::hack_tools_gotoolchain)" go -C "${KUBE_ROOT}/hack/tools/golangci-lint" build -o "${GOBIN}/kube-api-linter.so" -buildmode=plugin sigs.k8s.io/kube-api-linter/pkg/plugin
fi
# Verify that the given config is valid. "golangci-lint run" does not