-
Notifications
You must be signed in to change notification settings - Fork 25
Add markerscope linter #161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
4057248
9e2a498
1ed3baf
ae5012e
853918d
b65c448
330da8d
222cd0d
f400cf4
09b2fb5
7945f60
963973e
75e9afb
2c2f8cb
1d2abb9
c4f233b
ada18fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ | |
| - [ForbiddenMarkers](#forbiddenmarkers) - Checks that no forbidden markers are present on types/fields. | ||
| - [Integers](#integers) - Validates usage of supported integer types | ||
| - [JSONTags](#jsontags) - Ensures proper JSON tag formatting | ||
| - [MarkerScope](#markerscope) - Validates that markers are applied in the correct scope | ||
| - [MaxLength](#maxlength) - Checks for maximum length constraints on strings and arrays | ||
| - [NamingConventions](#namingconventions) - Ensures field names adhere to user-defined naming conventions | ||
| - [NoBools](#nobools) - Prevents usage of boolean types | ||
|
|
@@ -383,6 +384,169 @@ lintersConfig: | |
| jsonTagRegex: "^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$" # Provide a custom regex, which the json tag must match. | ||
| ``` | ||
|
|
||
| ## MarkerScope | ||
|
|
||
| The `markerscope` linter validates that markers are applied in the correct scope and to the correct types. It ensures that markers are placed on appropriate Go language constructs (types, fields) and applied to compatible data types according to their intended usage. | ||
|
|
||
| The linter performs two levels of validation: | ||
|
|
||
| 1. **Scope validation**: Ensures markers are placed on the correct location (field vs type) | ||
| 2. **Type constraint validation**: Ensures markers are applied to compatible data types (e.g., numeric markers on numeric types only) | ||
|
|
||
| ### Scope Types | ||
|
|
||
| The linter defines different scope types for markers: | ||
|
|
||
| - **FieldScope**: Can only be applied to struct fields (e.g., `optional`, `required`, `nullable`) | ||
| - **TypeScope**: Can only be applied to type definitions (e.g., `kubebuilder:validation:items:ExactlyOneOf`) | ||
| - **AnyScope**: Can be applied to either fields or type definitions (e.g., `kubebuilder:validation:Minimum`, `kubebuilder:validation:Pattern`) | ||
|
|
||
| ### Type Constraints | ||
|
|
||
| The linter validates that markers are applied to compatible OpenAPI schema types: | ||
|
|
||
| - **Numeric markers** (`Minimum`, `Maximum`, `MultipleOf`): Only for `integer` or `number` types | ||
| - **String markers** (`Pattern`, `MinLength`, `MaxLength`): Only for `string` types | ||
| - **Array markers** (`MinItems`, `MaxItems`, `UniqueItems`): Only for `array` types | ||
| - **Object markers** (`MinProperties`, `MaxProperties`): Only for `object` types (struct/map) | ||
| - **Array items markers** (`items:Minimum`, `items:Pattern`, etc.): Apply constraints to array element types | ||
|
|
||
| OpenAPI schema types map to Go types as follows: | ||
| - `integer`: int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64 | ||
| - `number`: float32, float64 | ||
| - `string`: string | ||
| - `boolean`: bool | ||
| - `array`: []T, [N]T (slices and arrays) | ||
| - `object`: struct, map[K]V | ||
|
|
||
| #### Strict Type Constraints | ||
|
|
||
| For markers with `AnyScope` and type constraints, the `strictTypeConstraint` flag controls where the marker should be declared when used with named types: | ||
|
|
||
| - When `strictTypeConstraint` is `false` (default): The marker can be declared on either the field or the type definition. | ||
| - When `strictTypeConstraint` is `true`: The marker must be declared on the type definition, not on fields using that type. | ||
|
|
||
| Example with `strictTypeConstraint: true`: | ||
|
|
||
| ```go | ||
| // ✅ Valid: marker on type definition | ||
| // +kubebuilder:validation:Minimum=0 | ||
| type Port int32 | ||
|
|
||
| type Service struct { | ||
| Port Port `json:"port"` | ||
| } | ||
|
|
||
| // ❌ Invalid: marker on field using named type | ||
| type Port int32 | ||
|
|
||
| type Service struct { | ||
| // +kubebuilder:validation:Minimum=0 // Error: should be on Port type definition | ||
| Port Port `json:"port"` | ||
| } | ||
| ``` | ||
|
|
||
| Most built-in kubebuilder validation markers use `strictTypeConstraint: true` to encourage consistent marker placement on type definitions. | ||
|
|
||
| ### Default Marker Rules | ||
|
|
||
| The linter includes built-in rules for all standard kubebuilder markers and k8s declarative validation markers. Examples: | ||
|
|
||
| **Field-only markers:** | ||
| - `optional`, `required`, `nullable` | ||
| - `kubebuilder:default`, `kubebuilder:validation:Example` | ||
|
|
||
| **Type-only markers:** | ||
| - `kubebuilder:validation:items:ExactlyOneOf` | ||
| - `kubebuilder:validation:items:AtMostOneOf` | ||
| - `kubebuilder:validation:items:AtLeastOneOf` | ||
|
|
||
| **AnyScope markers with type constraints:** | ||
| - `kubebuilder:validation:Minimum` (integer/number types only) | ||
| - `kubebuilder:validation:Pattern` (string types only) | ||
| - `kubebuilder:validation:MinItems` (array types only) | ||
| - `kubebuilder:validation:MinProperties` (object types only) | ||
|
|
||
| **AnyScope markers without type constraints:** | ||
| - `kubebuilder:validation:Enum`, `kubebuilder:validation:Format` | ||
| - `kubebuilder:pruning:PreserveUnknownFields`, `kubebuilder:title` | ||
|
|
||
| ### Configuration | ||
|
|
||
| You can customize marker rules or add support for custom markers. | ||
|
|
||
| **Scope values:** | ||
| - `Field`: Marker can only be applied to struct fields | ||
| - `Type`: Marker can only be applied to type definitions | ||
| - `Any`: Marker can be applied to either fields or type definitions | ||
|
|
||
| **Type constraints:** | ||
|
|
||
| The `typeConstraint` field allows you to restrict which Go types a marker can be applied to. This ensures that markers are only used with compatible data types (e.g., numeric markers like `Minimum` are only applied to integer/number types). | ||
|
|
||
| **Type constraint fields:** | ||
| - `allowedSchemaTypes`: List of allowed OpenAPI schema types (`integer`, `number`, `string`, `boolean`, `array`, `object`) | ||
| - `elementConstraint`: Nested constraint for array element types (only valid when `allowedSchemaTypes` includes `array`) | ||
| - `strictTypeConstraint`: When `true`, markers with `AnyScope` and type constraints applied to fields using named types must be declared on the type definition instead of the field. Defaults to `false`. | ||
|
|
||
| **Configuration example:** | ||
|
|
||
| ```yaml | ||
| lintersConfig: | ||
| markerscope: | ||
| policy: Warn | SuggestFix # The policy for marker scope violations. Defaults to `Warn`. | ||
| allowDangerousTypes: false # Allow dangerous number types (float32, float64). Defaults to `false`. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this linter should care about that, we have a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Understood. I'm going to turn this setting off.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We handled it here. |
||
|
|
||
| # Override default rules for built-in markers | ||
| overrideMarkers: | ||
| - identifier: "optional" | ||
| scope: Field # or: Type, Any | ||
|
|
||
| # Add rules for custom markers | ||
| customMarkers: | ||
| # Custom marker with scope constraint only | ||
| - identifier: "mycompany:validation:CustomMarker" | ||
| scope: Any | ||
|
|
||
| # Custom marker with scope and type constraints | ||
| - identifier: "mycompany:validation:NumericLimit" | ||
| scope: Any | ||
| strictTypeConstraint: true # Require declaration on type definition for named types | ||
| typeConstraint: | ||
nayuta723 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| allowedSchemaTypes: | ||
| - integer | ||
| - number | ||
|
|
||
| # Custom array items marker with element type constraint | ||
| - identifier: "mycompany:validation:items:StringFormat" | ||
| scope: Any | ||
| typeConstraint: | ||
| allowedSchemaTypes: | ||
| - array | ||
| elementConstraint: | ||
| allowedSchemaTypes: | ||
| - string | ||
| ``` | ||
|
|
||
| **Configuration notes:** | ||
| - Use `overrideMarkers` to customize the behavior of built-in kubebuilder/controller-runtime markers | ||
| - Use `customMarkers` to add validation for your own custom markers | ||
| - If a marker is not in either list and not in the default rules, no validation is performed for that marker | ||
|
|
||
| ### Fixes | ||
|
|
||
| When the `policy` is set to `SuggestFix`, the `markerscope` linter provides automatic fix suggestions for marker violations: | ||
|
|
||
| 1. **Scope violations**: For markers applied to the wrong scope (field vs type), the linter suggests moving the marker to the correct location. | ||
|
|
||
| 2. **Type constraint violations**: For markers applied to incompatible types, the linter suggests removing the invalid marker. | ||
|
|
||
| 3. **Named type violations**: For AnyScope markers with type constraints applied to fields using named types, the linter suggests moving the marker to the type definition if the underlying type is compatible with the marker's type constraints. | ||
|
|
||
| When the `policy` is set to `Warn`, violations are reported as warnings without suggesting fixes. | ||
|
|
||
| **Note**: This linter is not enabled by default and must be explicitly enabled in the configuration. | ||
|
|
||
| ## MaxLength | ||
|
|
||
| The `maxlength` linter checks that string and array fields in the API are bounded by a maximum length. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.