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
Add README and documentation #5
Changes from 15 commits
415c989
cf25700
6671609
8e0343d
4471ade
4da4489
12b1935
9a2b1cc
e29a268
34135fd
b069f0b
4dbaf53
869c277
0cc252b
5e71a2d
622e55e
bccc555
2928cfe
80ef6cb
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 |
---|---|---|
@@ -1 +1,34 @@ | ||
# kube-linter | ||
|
||
kube-linter is a static analysis tool that checks Kubernetes YAML files to ensure the applications represented in them | ||
adhere to best practices. | ||
|
||
In detail, `kube-linter` is a binary that takes in paths to YAML files, and runs a list of checks | ||
against them. If any lint errors are found, they are printed to standard error, and `kube-linter` returns a non-zero | ||
exit code. | ||
|
||
The list of checks that is run is configurable. `kube-linter` comes with several built-in checks, only some of which | ||
are enabled by default. Users can also create custom checks. | ||
|
||
## Install | ||
|
||
If you have `go` installed, you can run `go get golang.stackrox.io/kube-linter/cmd/kube-linter`. | ||
|
||
`kube-linter` binaries can be downloaded from [the Releases page](https://github.com/stackrox/kube-linter/releases). | ||
Download the `kube-linter` binary, and add it to your PATH. | ||
|
||
## Usage | ||
|
||
To lint directories or files, simply run `./kube-linter lint files_or_dirs ...`. If a directory is passed, all files | ||
with `.yaml` or `.yml` extensions are parsed, and Kubernetes objects are loaded from them. If a file is passed, | ||
it is parsed irrespective of extension. | ||
|
||
Users can pass a config file using the `--config` file to control which checks are executed, and to configure custom checks. | ||
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.
|
||
An example config file is provided in `config.yaml.example`. | ||
|
||
See the [documentation](./docs) for more details. | ||
|
||
# WARNING: Breaking changes possible | ||
|
||
kube-linter is currently in a very early stage of development. There may be breaking changes to the command usage, flags | ||
and config file formats. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
* | ||
!.gitignore |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# customChecks defines custom checks. | ||
customChecks: | ||
- name: "required-label-app" | ||
template: "required-label" | ||
params: | ||
key: "app" | ||
checks: | ||
# if doNotAutoAddDefaults is true, default checks are not automatically added. | ||
# Otherwise, they are. | ||
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. Remove, this is pretty obvious based on the previous line 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. Also, I think doNotAutoAddDefaults is backwards, should be autoAddDefaults that defaults to true 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. it's also just a bit too verbose |
||
doNotAutoAddDefaults: false | ||
|
||
# include explicitly adds checks, by name. You can reference any of the built-in checks. | ||
# Note that customChecks defined above are included automatically. | ||
include: | ||
- "required-label-owner" | ||
# exclude explicitly excludes checks, by name. exclude has the highest priority: if a check is | ||
# in exclude, then it is not considered, even if it is in include as well. | ||
exclude: | ||
- "privileged" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
|
||
# Documentation | ||
|
||
Welcome to the `kube-linter` documentation. Read on for more detailed information about using and configuring the tool. | ||
|
||
## Exporing the CLI | ||
|
||
You can run `kube-linter --help` to see a list of supported commands and flags. For each subcommand, you can | ||
run `kube-linter <subcommand> --help` to see detailed help text and flags for it. | ||
|
||
## Running the linter | ||
|
||
To lint directories or files, simply run `./kube-linter lint files_or_dirs ...`. If a directory is passed, all files | ||
with `.yaml` or `.yml` extensions are parsed, and Kubernetes objects are loaded from them. If a file is passed, | ||
it is parsed irrespective of extension. | ||
|
||
Users can pass a config file using the `--config` file to control which checks are executed, and to configure custom checks. | ||
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. flag again (is there some way to not duplicate the contents between this and the top-level readme)? 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. Fixed. And I just removed the duplicate content from the top-level README in favour of just linking. |
||
An example config file is provided [here](../config.yaml.example). | ||
|
||
## Built-in checks | ||
|
||
`kube-linter` comes with a list of built-in checks, which you can find [here](generated/checks.md). Only some | ||
built-in checks are enabled by default -- others must be explicitly enabled in the config. | ||
|
||
## Custom checks | ||
|
||
### Check Templates | ||
|
||
In `kube-linter`, checks are concrete realizations of check templates. A check template describes a class of check -- it | ||
contains logic (written in Go code) that would execute the check, and lays out (zero or more) parameters that it takes. | ||
|
||
The list of supported check templates, along with their metadata, can be found [here](generated/templates.md). | ||
|
||
### Custom checks | ||
|
||
All checks in `kube-linter` are defined by referencing a check template, passing parameters to it, and adding additional | ||
check specific metadata (like check name and description). Users can configure custom checks the same way built-in checks | ||
are configured, and add them to the config file. The built-in checks are specified [here](../internal/builtinchecks). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
The following table enumerates built-in checks: | ||
|
||
|
||
| Name | Enabled by default | Description | Template | Parameters | | ||
--- | --- | --- | --- | --- | | ||
|`env-var-secret`|No|Alert on objects using a secret in an environment variable|env-var|- `name`: `.*secret.*` <br />| | ||
|`privileged-container`|Yes|Alert on deployments with containers running in privileged mode|privileged|none| | ||
|`required-label-owner`|No|Alert on objects without the 'owner' label|required-label|- `key`: `owner` <br />| |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
The following table enumerates supported check templates: | ||
|
||
|
||
| Name | Description | Supported Objects | Parameters | | ||
--- | --- | --- | --- | | ||
|`env-var`|Flag environment variables that match the provided patterns|DeploymentLike|- `name` (required): A regex for the env var name <br />- `value`: A regex for the env var value <br />| | ||
|`privileged`|Flag privileged containers|DeploymentLike|none| | ||
|`required-label`|Flag objects not carrying at least one label matching the provided patterns|Any|- `key` (required): A regex for the key of the required label <br />- `value`: A regex for the value of the required label <br />| |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package checks | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"os" | ||
"strings" | ||
|
||
"github.com/pkg/errors" | ||
"github.com/spf13/cobra" | ||
"golang.stackrox.io/kube-linter/internal/builtinchecks" | ||
"golang.stackrox.io/kube-linter/internal/check" | ||
"golang.stackrox.io/kube-linter/internal/command/common" | ||
"golang.stackrox.io/kube-linter/internal/defaultchecks" | ||
"golang.stackrox.io/kube-linter/internal/ternary" | ||
) | ||
|
||
var ( | ||
dashes = func() string { | ||
var sb strings.Builder | ||
for i := 0; i < 30; i++ { | ||
sb.WriteRune('-') | ||
} | ||
return sb.String() | ||
}() | ||
|
||
formatsToRenderFuncs = map[string]func([]check.Check, io.Writer){ | ||
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. Possibly irrelevant (see below), but the brace following the closing parens without space in between looks weird - doesn't the linter flag this? 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. That brace is actually consistent with |
||
common.PlainFormat: func(checks []check.Check, out io.Writer) { | ||
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. Move these to separate functions instead of inlining them. I would also encourage you to use Go templates for formatting. Especially the markdown formatting (a) looks ugly in code and (b) is extremely limited as you cannot add any custom styling, notes, etc. 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. Done. Also moved to templates. |
||
for i, check := range checks { | ||
fmt.Fprintf(out, "Name: %s\nDescription: %s\nTemplate: %s\nParameters: %v\nEnabled by default: %v\n", | ||
check.Name, check.Description, check.Template, check.Params, defaultchecks.List.Contains(check.Name)) | ||
if i != len(checks)-1 { | ||
fmt.Fprintf(out, "\n%s\n\n", dashes) | ||
} | ||
} | ||
}, | ||
common.MarkdownFormat: func(checks []check.Check, out io.Writer) { | ||
fmt.Fprintf(out, "The following table enumerates built-in checks:\n") | ||
fmt.Fprintf(out, "\n\n| Name | Enabled by default | Description | Template | Parameters |\n --- | --- | --- | --- | --- | \n") | ||
for _, check := range checks { | ||
var params string | ||
if len(check.Params) == 0 { | ||
params = "none" | ||
} else { | ||
var sb strings.Builder | ||
for key, value := range check.Params { | ||
sb.WriteString(fmt.Sprintf("- `%s`: `%s` <br />", key, value)) | ||
} | ||
params = sb.String() | ||
} | ||
fmt.Fprintf(out, "|`%s`|%s|%s|%s|%s|\n", | ||
check.Name, | ||
ternary.String(defaultchecks.List.Contains(check.Name), "Yes", "No"), | ||
check.Description, check.Template, params) | ||
} | ||
}, | ||
} | ||
) | ||
|
||
func listCommand() *cobra.Command { | ||
format := common.FormatWrapper{Format: common.PlainFormat} | ||
c := &cobra.Command{ | ||
Use: "list", | ||
Short: "list built-in checks", | ||
Args: cobra.NoArgs, | ||
RunE: func(cmd *cobra.Command, _ []string) error { | ||
checks, err := builtinchecks.List() | ||
if err != nil { | ||
return err | ||
} | ||
renderFunc := formatsToRenderFuncs[format.Format] | ||
if renderFunc == nil { | ||
return errors.Errorf("unknown format: %q", format.Format) | ||
} | ||
renderFunc(checks, os.Stdout) | ||
return nil | ||
}, | ||
} | ||
c.Flags().Var(&format, "format", "output format") | ||
return c | ||
} | ||
|
||
// Command defines the root of the checks command. | ||
func Command() *cobra.Command { | ||
c := &cobra.Command{ | ||
Use: "checks", | ||
} | ||
c.AddCommand(listCommand()) | ||
return c | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package checks | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"golang.stackrox.io/kube-linter/internal/command/common" | ||
"golang.stackrox.io/kube-linter/internal/set" | ||
) | ||
|
||
func TestAllFormatsSupported(t *testing.T) { | ||
supportedFormats := set.NewStringSet() | ||
for format := range formatsToRenderFuncs { | ||
supportedFormats.Add(format) | ||
} | ||
assert.ElementsMatch(t, supportedFormats.AsSlice(), common.AllSupportedFormats.AsSlice()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO a readme in an open source repository should always include custom build instructions and contributing guidelines (or references to these)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added instructions for building from source. Contributing guidelines, will do in a follow-up -- we still need to iron those out.