diff --git a/sample/.github/workflows/kube-linter.yml b/.github/workflows/kube-linter-sample.yml similarity index 52% rename from sample/.github/workflows/kube-linter.yml rename to .github/workflows/kube-linter-sample.yml index 6418478..78451dc 100755 --- a/sample/.github/workflows/kube-linter.yml +++ b/.github/workflows/kube-linter-sample.yml @@ -11,9 +11,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Scan repo - id: kube-lint-repo - uses: stackrox/kube-linter-action@v1.0.0 + + - name: Scan valid yaml with kube-linter + uses: stackrox/kube-linter-action@v1.0.2 with: - directory: yaml - #config: .kube-linter/config.yaml + directory: sample/valid-yaml + config: sample/.kube-linter-config.yaml diff --git a/.github/workflows/self-test.yml b/.github/workflows/self-test.yml new file mode 100755 index 0000000..59d1d7b --- /dev/null +++ b/.github/workflows/self-test.yml @@ -0,0 +1,65 @@ +# This workflow is provided for testing changes to the action. +# When developing make sure that "Scan 2 - failing" produces expected kube-linter validation logs. + +name: kube-linter-action development self-test + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + test-scan-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Scan 1 - succeeding + uses: ./ + with: + directory: sample/valid-yaml + config: sample/.kube-linter-config.yaml + + - name: Scan 2 - failing + uses: ./ + with: + directory: sample/invalid-yaml + config: sample/.kube-linter-config.yaml + continue-on-error: true + + test-scan-windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + + - name: Scan 1 - succeeding + uses: ./ + with: + directory: sample/valid-yaml + config: sample/.kube-linter-config.yaml + + - name: Scan 2 - failing + uses: ./ + with: + directory: sample/invalid-yaml + config: sample/.kube-linter-config.yaml + continue-on-error: true + + test-scan-macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + + - name: Scan 1 - succeeding + uses: ./ + with: + directory: sample/valid-yaml + config: sample/.kube-linter-config.yaml + + - name: Scan 2 - failing + uses: ./ + with: + directory: sample/invalid-yaml + config: sample/.kube-linter-config.yaml + continue-on-error: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f11b75 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ diff --git a/README.md b/README.md index 2427abf..858b70a 100755 --- a/README.md +++ b/README.md @@ -1,23 +1,28 @@ -# kube-linter-action +

-This is a GitHub action for scanning Kubernetes deployment files with [kube-linter](https://github.com/stackrox/kube-linter). This includes both the action itself (.github/actions) and sample GitHub workflow (.github/workflows) and a test YAML. +# kube-linter-action - KubeLinter GitHub Action -Quick deployment: +This is a GitHub action for scanning Kubernetes YAML files and Helm charts in your GitHub workflow with [kube-linter](https://github.com/stackrox/kube-linter). -1. Create a new GitHub repo. -2. Push all files from the `sample` directory into the repo. -3. The `kube-linter.yml` workflow will run as an action every time there's a new push to this repo. +## Quickstart -The action takes two parameters. +1. Copy [.github/workflows/kube-linter-sample.yml](https://github.com/stackrox/kube-linter-action/tree/main/.github/workflows/kube-linter-sample.yml) file to `.github/workflows` directory in your repo. +2. Adjust scan `directory` to the location where your Kubernetes or Helm files are. See Parameters below. -``` - - name: Scan repo - id: kube-lint-repo - uses: stackrox/kube-linter-action@v1 +The new workflow will run every time there's a new push to the repo. +Workflow will fail if kube-linter detects issues. You'll find issues in the output of `kube-linter-action`. + +### Example + +```yaml + - name: Scan repo with kube-linter + uses: stackrox/kube-linter-action@v1.0.2 with: directory: yamls config: .kube-linter/config.yaml ``` -* `directory` is mandatory -- this is the directory of deployment files to scan. -* `config` is optional -- this is the path to a [configuration file](https://github.com/stackrox/kube-linter/blob/main/config.yaml.example) if you wish to use a non-default configuration. +### Parameters + +* `directory` (required) - path of file or directory to scan, absolute or relative to the root of the repo. +* `config` (optional) - path to a [configuration file](https://docs.kubelinter.io/#/configuring-kubelinter) if you wish to use a non-default configuration. diff --git a/action.yml b/action.yml index 610ef80..abd2981 100755 --- a/action.yml +++ b/action.yml @@ -1,11 +1,11 @@ name: 'kube-linter' -description: 'Scan directory with kube-linter' +description: 'Scan directory or file with kube-linter' branding: icon: 'check-circle' color: 'green' inputs: directory: - description: 'Directory to scan ' + description: 'Directory or file to scan' required: true config: description: 'Path to config file' @@ -17,25 +17,35 @@ inputs: runs: using: "composite" steps: - - name: Download latest kube-linter + - name: Download the latest kube-linter run: | - LOCATION=$(curl -s https://api.github.com/repos/stackrox/kube-linter/releases/latest \ - | grep "tag_name" \ - | awk '{print "https://github.com/stackrox/kube-linter/releases/download/" substr($2, 2, length($2)-3) "/kube-linter-linux.tar.gz"}') - curl -s -L -o kube-linter-linux.tar.gz $LOCATION - tar -xf kube-linter-linux.tar.gz -C "${GITHUB_WORKSPACE}/" + set -euo pipefail + case "${{ runner.os }}" in + macOS) OS=darwin ;; + Windows) OS=windows ;; + *) OS=linux ;; + esac + RELEASE_INFO=$(curl --silent --show-error --fail https://api.github.com/repos/stackrox/kube-linter/releases/latest) + RELEASE_NAME=$(echo "${RELEASE_INFO}" | jq --raw-output ".name") + LOCATION=$(echo "${RELEASE_INFO}" \ + | jq --raw-output ".assets[].browser_download_url" \ + | grep --fixed-strings kube-linter-${OS}.tar.gz) + TARGET=kube-linter-${OS}-${RELEASE_NAME}.tar.gz + # Skip downloading release if downloaded already, e.g. when the action is used multiple times. + if [ ! -e $TARGET ]; then + curl --silent --show-error --fail --location --output $TARGET "$LOCATION" + tar -xf $TARGET + fi shell: bash - name: Lint files - id: lint run: | + set -u set +e - cd "${GITHUB_WORKSPACE}" if [ -z ${{ inputs.config }} ]; then - export CONFIG="" + CONFIG="" else - export CONFIG="--config ${{ inputs.config }}" + CONFIG="--config ${{ inputs.config }}" fi - ./kube-linter $CONFIG lint ${{ inputs.directory }} 2>&1 | tee ${{ inputs.output-file }} - result_code=${PIPESTATUS[0]} - exit $result_code + ./kube-linter $CONFIG lint ${{ inputs.directory }} 2>&1 | tee -a ${{ inputs.output-file }} + exit ${PIPESTATUS[0]} shell: bash diff --git a/sample/.kube-linter-config.yml b/sample/.kube-linter-config.yml new file mode 100644 index 0000000..2ed6041 --- /dev/null +++ b/sample/.kube-linter-config.yml @@ -0,0 +1,17 @@ +# customChecks defines custom checks. +customChecks: + - name: "required-annotation-team" + template: "required-annotation" + params: + key: "team" + remediation: "Add a team annotation to your object" +checks: + # if doNotAutoAddDefaults is true, default checks are not automatically added. + 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: [ ] + # 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: [ ] diff --git a/sample/yaml/deploy.yaml b/sample/invalid-yaml/deploy.yaml similarity index 71% rename from sample/yaml/deploy.yaml rename to sample/invalid-yaml/deploy.yaml index 3649247..007ecd3 100755 --- a/sample/yaml/deploy.yaml +++ b/sample/invalid-yaml/deploy.yaml @@ -15,7 +15,7 @@ spec: app: nginx spec: containers: - - name: nginx - image: nginx:1.14.2 - ports: - - containerPort: 80 \ No newline at end of file + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/sample/valid-yaml/deploy.yaml b/sample/valid-yaml/deploy.yaml new file mode 100755 index 0000000..e45e24e --- /dev/null +++ b/sample/valid-yaml/deploy.yaml @@ -0,0 +1,45 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: compliant + namespace: my-namespace + annotations: + team: database +spec: + replicas: 1 + minReadySeconds: 15 + selector: + matchLabels: + app: compliant + strategy: + type: Recreate + template: + metadata: + namespace: my-namespace + labels: + app: compliant + spec: + serviceAccountName: my-service-account + containers: + - image: nginx:latest + name: nginx + securityContext: + runAsNonRoot: true + readOnlyRootFilesystem: true + resources: + requests: + memory: "1Gi" + cpu: "1" + limits: + memory: "4Gi" + cpu: "2" +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: my-service-account + namespace: my-namespace + labels: + app.kubernetes.io/name: my-app + annotations: + team: database