Skip to main content

Custom GitHub Action Workflow Linter

Project description

Bitwarden Workflow Linter

Bitwarden's Workflow Linter is an extensible linter to apply opinionated organization-specific GitHub Action standards. It was designed to be used alongside tools like action-lint and yamllint to check for correct Action syntax and enforce specific YAML standards.

To see an example of Workflow Linter in practice in GitHub Action, see the composite Action.

Installation

From GitHub Release

Not yet implemented

Locally

git clone git@github.com:bitwarden/workflow-linter.git
cd workflow-linter

pip install -e .

Usage

Setup settings.yaml

If a non-default configuration is desired (different than src/bitwarden_workflow_linter/default_settings.yaml), copy the below and create a settings.yaml in the directory that bwwl will be running from.

enabled_rules:
    - bitwarden_workflow_linter.rules.name_exists.RuleNameExists
    - bitwarden_workflow_linter.rules.name_capitalized.RuleNameCapitalized
    - bitwarden_workflow_linter.rules.pinned_job_runner.RuleJobRunnerVersionPinned
    - bitwarden_workflow_linter.rules.job_environment_prefix.RuleJobEnvironmentPrefix
    - bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
    - bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs

approved_actions_path: default_actions.json
usage: bwwl [-h] [-v] {lint,actions} ...

positional arguments:
  {lint,actions}
    lint          Verify that a GitHub Action Workflow follows all of the Rules.
    actions       Add or Update Actions in the pre-approved list.

options:
  -h, --help      show this help message and exit
  -v, --verbose

Development

Requirements

  • Python 3.11
  • pipenv

Setup

pipenv install --dev
pipenv shell

Testing

All built-in src/bitwarden_workflow_linter/rules should have 100% code coverage and we should shoot for an overall coverage of 80%+. We are lax on the imperative shell (code interacting with other systems; ie. disk, network, etc), but we strive to maintain a high coverage over the functional core (objects and models).

pipenv shell
pytest tests --cov=src

Code Reformatting

We adhere to PEP8 and use black to maintain this adherence. black should be run on any change being merged to main.

pipenv shell
black .

Linting

We loosely use Google's Python style guide, but yield to black when there is a conflict

pipenv shell
pylint --rcfile pylintrc src/ tests/

Add a new Rule

A new Rule is created by extending the Rule base class and overriding the fn(obj: Union[Workflow, Job, Step]) method. Available attributes of Workflows, Jobs and Steps can be found in their definitons under src/models.

For a simple example, we'll take a look at enforcing the existence of the name key in a Job. This is already done by default with the src.rules.name_exists.RuleNameExists, but provides a simple enough example to walk through.

from typing import Union, Tuple

from ..rule import Rule
from ..models.job import Job
from ..models.workflow import Workflow
from ..models.step import Step
from ..utils import LintLevels, Settings


class RuleJobNameExists(Rule):
    def __init__(self, settings: Settings = None) -> None:
        self.message = "name must exist"
        self.on_fail: LintLevels = LintLevels.ERROR
        self.compatibility: List[Union[Workflow, Job, Step]] = [Job]
        self.settings: Settings = settings

    def fn(self, obj: Job) -> Tuple[bool, str]:
        """<doc block goes here> """
        if obj.name is not None:
            return True, ""
        return False, self.message

By default, a new Rule needs five things:

  • self.message: The message to return to the user on a lint failure
  • self.on_fail: The level of failure on a lint failure (NONE, WARNING, ERROR). NONE and WARNING will exit with a code of 0 (unless using strict mode for WARNING). ERROR will exit with a non-zero exit code
  • self.compatibility: The list of objects this rule is compatible with. This is used to create separate instances of the Rule for each object in the Rules collection.
  • self.settings: In general, this should default to what is shown here, but allows for overrides
  • self.fn: The function doing the actual work to check the object and enforce the standard.

fn can be as simple or as complex as it needs to be to run a check on a single object. This linter currently does not support Rules that check against multiple objects at a time OR file level formatting (one empty between each step or two empty lines between each job)

To activate a rule after implementing it, add it to settings.yaml in the project's base folder and src/bitwarden_workflow_linter/default_settings.yaml to make the rule default

ToDo

  • Add Rule to assert correct format for single line run

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bitwarden_workflow_linter-0.1.0.tar.gz (79.8 kB view details)

Uploaded Source

Built Distribution

File details

Details for the file bitwarden_workflow_linter-0.1.0.tar.gz.

File metadata

File hashes

Hashes for bitwarden_workflow_linter-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ff09e356a8ab83242e3f33572010596610cd66ea6f870a111c865a061aa913d4
MD5 0ab54c953ad8eef45bcd62765ee64d94
BLAKE2b-256 81d99de0b4396179ef665e9dd077b9187eb429e0225582aaeb8e195d7a2751af

See more details on using hashes here.

File details

Details for the file bitwarden_workflow_linter-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for bitwarden_workflow_linter-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7c294e0350a8f361cee952ac17a400cc3f1384efd42078025981166d8c669896
MD5 19345c21527142483479ce2063223669
BLAKE2b-256 0a7a2fe1894f06d982e6d8293bc03010b543bf0e081b639f926018f56b0c3334

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page