Skip to content

Conversation

@munnerz
Copy link
Member

@munnerz munnerz commented Sep 30, 2021

This PR adds a new CLI tool named crd-linter which will lint/run checks against CRD resources and their corresponding schema.

Initially this includes just 4 linters to check for:

  • SchemaProvided: ensures a schema is provided for all API versions
  • PreserveUnknownFields: ensures that provideUnknownFields and x-kubernetes-preserve-unknown-fields is not used
  • MaxLengthStrings: ensures string typed fields have a maxLength specified
  • MaxItemsArrays: ensures array typed fields have a maxItems specified

This is all in the effort to ensure a higher quality of CRDs, which helps protect apiservers against e.g. too much data being stored in a CRD, or ever-growing number of items in arrays that can cause scalability issues.

These linters aren't aimed at all being "best practice", but providing this tool allows teams to check for potential issues/better understand APIs they are installing and where issues may be found.

I'm not sure where this is best to live, nor am I wedded to any parts of the design of it, so welcome any and all feedback 😄

ref https://kubernetes.slack.com/archives/C0EG7JC6T/p1628592082067800

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Sep 30, 2021
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: munnerz
To complete the pull request process, please assign vincepri after the PR has been reviewed.
You can assign the PR to them by writing /assign @vincepri in a comment when ready.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Sep 30, 2021
@munnerz
Copy link
Member Author

munnerz commented Oct 1, 2021

Just one failure left, and I'm not sure if it makes sense to change the code here:

cmd/crd-linter/exceptions/exceptions.go:77:9: G306: Expect WriteFile permissions to be 0600 or less (gosec)
	return ioutil.WriteFile(path, []byte(l.String()), 0644)

@erikgb
Copy link
Member

erikgb commented Oct 2, 2021

Just one failure left, and I'm not sure if it makes sense to change the code here:


cmd/crd-linter/exceptions/exceptions.go:77:9: G306: Expect WriteFile permissions to be 0600 or less (gosec)

	return ioutil.WriteFile(path, []byte(l.String()), 0644)

IMO this should be considered a false positive and suppressed with an annotation.

return &ExceptionList{Exceptions: make([]Exception, 0)}
}

// LoadFromFile will load a pipe (|) separated list of Exceptions from the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doc appears a bit confusing to me. The exception list seems to be separated by newline; one exception per line. But one exception seems to be serialized in a pipe-separated format.

Have you considered other file formats? The suggested format is very compact, but the semantics are not apparent when looking at a file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 the format here wasn't so much chosen to be compact, but rather just to have each entry on a single line to make it clear to see how many violations there are. An example line:

path/to/the/file/jaegertracing.io_jaegers_crd.yaml|jaegers.jaegertracing.io|MaxLengthStrings|spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.collector.properties.volumes.items.properties.flexVolume.properties.fsType.maxLength is not specified on a field of type 'string'

Happy to adjust this format however you feel makes it clearer - what sort of format do you think would be better/what do you have in mind?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@munnerz Sorry for the delay. You have reasonable arguments for selecting the chosen file format, and I think it should be ok. Only downside I see, is that it is not very human readable. The format must remain stable over time, so we should decide if human readability is important now. I'll guess an IDE could be a consumer of these files. Do we have any reference or common practice to refer to?

@munnerz
Copy link
Member Author

munnerz commented Oct 25, 2021

Thanks for the review comments, I'll be updating the PR this week 😄

@munnerz
Copy link
Member Author

munnerz commented Nov 2, 2021

I've addressed all the feedback - there's just the one open question on the serialisation format for the exceptions file left :)

@k8s-ci-robot
Copy link
Contributor

@munnerz: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
pull-controller-tools-test-master 2f473e2 link true /test pull-controller-tools-test-master

Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

@k8s-ci-robot
Copy link
Contributor

@munnerz: PR needs rebase.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Nov 11, 2021
Copy link
Member

@camilamacedo86 camilamacedo86 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have we an enhancement proposal for this one?

| MaxLengthStrings | Ensures that all 'string' type fields have a `maxLength` option set |
| MaxItemsArrays | Ensures that all 'array' type fields have a `maxItems` option set |
| SchemaProvided | Ensures that all versions of all CRDs provide an OpenAPI schema |
| PreserveUnknownFields | Ensures that no fields within a CRD schema permit unknown fields |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is not this attr only valid for v1beta1 CRDs? This project no longer supports or work with v1beta1

For example:

```
crd-linter --path ./path/to/crds/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This project is responsible for gen resources?
could you add in the first comment why do you think that this project ought to also linter the resources? I think we need here to know when and why it would be required and used?

Also, would that be a new bin or it would also be hipped with controller-gen? Have we an enhancement proposal for it? and then, why add support to lint only the CRD and not all manifests generated by the project?

Comment on lines +35 to +52
func (p NoPreserveUnknownFields) Description() string {
return "Fields should avoid using 'preserveUnknownFields' as it means any data can be persisted into the Kubernetes apiserver " +
"without any guards on the size and type of data. Setting this to true is no longer permitted in the 'v1' API version of " +
"CustomResourceDefinitions, and as such, it should not be used: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#field-pruning"
}

func (p NoPreserveUnknownFields) Execute(crd *v1.CustomResourceDefinition) WarningList {
var errs []Warning
if crd.Spec.PreserveUnknownFields {
errs = append(errs, Warning{Message: "spec.preserveUnknownFields is set to 'true'"})
}
return append(errs, recurseAllSchemas(crd.Spec.Versions, func(props v1.JSONSchemaProps, path string) []Warning {
if props.XPreserveUnknownFields != nil && *props.XPreserveUnknownFields == true {
return newWarningList(fmt.Sprintf("%s.x-kubernetes-preserve-unknown-fields is set to 'true'", path))
}
return nil
})...)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description mentions that v1 forbids it, but that seems to be true only to spec.preserveUnknownFields and not to x-kubernetes-preserve-unknown-fields on specific properties. Am I missing something?

@k8s-triage-robot
Copy link

The Kubernetes project currently lacks enough contributors to adequately respond to all issues and PRs.

This bot triages issues and PRs according to the following rules:

  • After 90d of inactivity, lifecycle/stale is applied
  • After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied
  • After 30d of inactivity since lifecycle/rotten was applied, the issue is closed

You can:

  • Mark this issue or PR as fresh with /remove-lifecycle stale
  • Mark this issue or PR as rotten with /lifecycle rotten
  • Close this issue or PR with /close
  • Offer to help out with Issue Triage

Please send feedback to sig-contributor-experience at kubernetes/community.

/lifecycle stale

@k8s-ci-robot k8s-ci-robot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Apr 6, 2022
@erikgb
Copy link
Member

erikgb commented Apr 6, 2022

/remove-lifecycle stale

I would like to use this tool! 😊

@k8s-ci-robot k8s-ci-robot removed the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Apr 6, 2022
@k8s-triage-robot
Copy link

The Kubernetes project currently lacks enough contributors to adequately respond to all issues and PRs.

This bot triages issues and PRs according to the following rules:

  • After 90d of inactivity, lifecycle/stale is applied
  • After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied
  • After 30d of inactivity since lifecycle/rotten was applied, the issue is closed

You can:

  • Mark this issue or PR as fresh with /remove-lifecycle stale
  • Mark this issue or PR as rotten with /lifecycle rotten
  • Close this issue or PR with /close
  • Offer to help out with Issue Triage

Please send feedback to sig-contributor-experience at kubernetes/community.

/lifecycle stale

@k8s-ci-robot k8s-ci-robot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Jul 5, 2022
@k8s-triage-robot
Copy link

The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs.

This bot triages issues and PRs according to the following rules:

  • After 90d of inactivity, lifecycle/stale is applied
  • After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied
  • After 30d of inactivity since lifecycle/rotten was applied, the issue is closed

You can:

  • Mark this issue or PR as fresh with /remove-lifecycle rotten
  • Close this issue or PR with /close
  • Offer to help out with Issue Triage

Please send feedback to sig-contributor-experience at kubernetes/community.

/lifecycle rotten

@k8s-ci-robot k8s-ci-robot added lifecycle/rotten Denotes an issue or PR that has aged beyond stale and will be auto-closed. and removed lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. labels Aug 4, 2022
@k8s-triage-robot
Copy link

The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs.

This bot triages issues and PRs according to the following rules:

  • After 90d of inactivity, lifecycle/stale is applied
  • After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied
  • After 30d of inactivity since lifecycle/rotten was applied, the issue is closed

You can:

  • Reopen this issue or PR with /reopen
  • Mark this issue or PR as fresh with /remove-lifecycle rotten
  • Offer to help out with Issue Triage

Please send feedback to sig-contributor-experience at kubernetes/community.

/close

@k8s-ci-robot
Copy link
Contributor

@k8s-triage-robot: Closed this PR.

In response to this:

The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs.

This bot triages issues and PRs according to the following rules:

  • After 90d of inactivity, lifecycle/stale is applied
  • After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied
  • After 30d of inactivity since lifecycle/rotten was applied, the issue is closed

You can:

  • Reopen this issue or PR with /reopen
  • Mark this issue or PR as fresh with /remove-lifecycle rotten
  • Offer to help out with Issue Triage

Please send feedback to sig-contributor-experience at kubernetes/community.

/close

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lifecycle/rotten Denotes an issue or PR that has aged beyond stale and will be auto-closed. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants