Skip to content

Commit

Permalink
Remove 'message' attribute from Rule base class. Fix linting findings…
Browse files Browse the repository at this point in the history
… for RuleStepPinned
  • Loading branch information
joseph-flinn committed Jan 12, 2024
1 parent b52eaab commit 057c2c5
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 29 deletions.
5 changes: 2 additions & 3 deletions lint-workflow/src/rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ class RuleExecutionException(Exception):
class Rule:
"""Base class of a Rule to extend to create a linting Rule."""

message: str = "error"
on_fail: str = "error"
on_fail: LintLevels = LintLevels.ERROR
compatibility: List[Union[Workflow, Job, Step]] = [Workflow, Job, Step]
settings: Settings = None

Expand All @@ -30,7 +29,7 @@ def fn(self, obj: Union[Workflow, Job, Step]) -> bool:
Returns:
The success/failure of the result of the Rule ran on the input.
"""
return False, f"{obj.name}: {self.message}"
return False, f"{obj.name}: <default fail message>"

def build_lint_message(self, message: str, obj: Union[Workflow, Job, Step]) -> str:
"""Build the lint failure message.
Expand Down
2 changes: 1 addition & 1 deletion lint-workflow/src/rules/job_environment_prefix.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __init__(self, settings: Settings = None) -> None:
A Settings object that contains any default, overriden, or custom settings
required anywhere in the application.
"""
self.message: str = "Job Environment vars should start with and underscore:"
self.message: str = "Job environment vars should start with and underscore:"
self.on_fail: LintLevels = LintLevels.ERROR
self.compatibility: List[Union[Workflow, Job, Step]] = [Job]
self.settings: Settings = settings
Expand Down
8 changes: 7 additions & 1 deletion lint-workflow/src/rules/step_approved.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ class RuleStepUsesApproved(Rule):
check against.
"""
def __init__(self, settings: Settings = None) -> None:
self.message = "error"
"""Constructor for RuleStepUsesApproved to override Rule class.
Args:
settings:
A Settings object that contains any default, overriden, or custom settings
required anywhere in the application.
"""
self.on_fail: LintLevels = LintLevels.WARNING
self.compatibility: List[Union[Workflow, Job, Step]] = [Step]
self.settings: Settings = settings
Expand Down
29 changes: 25 additions & 4 deletions lint-workflow/src/rules/step_pinned.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Union, Tuple
"""A Rule to enforce Actions are pinned correctly."""
from typing import List, Tuple, Union

from ..models.job import Job
from ..models.workflow import Workflow
Expand All @@ -8,8 +9,28 @@


class RuleStepUsesPinned(Rule):
"""Rule to contain the enforcement logic for pinning Actions versions.
Definition of Internal Action:
An Action that exists in the `bitwarden/gh-actions` GitHub Repository.
For any external Action (any Action that does not fit the above definition of
an Internal Action), to mitigate the risks of supply chain attacks in our CI
pipelines, we pin any use of an Action to a specific hash that has been verified
and pre-approved after a security audit of the version of the Action.
All Internl Actions, should be pinned to 'main'. This prevents Renovate from
spamming a bunch of PRs across all of our repos when `bitwarden/gh-actions` is
updated.
"""
def __init__(self, settings: Settings = None) -> None:
self.message = f"error"
"""Constructor for RuleStepUsesPinned to override base Rule.
Args:
settings:
A Settings object that contains any default, overriden, or custom settings
required anywhere in the application.
"""
self.on_fail: LintLevels = LintLevels.ERROR
self.compatibility: List[Union[Workflow, Job, Step]] = [Step]
self.settings: Settings = settings
Expand Down Expand Up @@ -68,10 +89,10 @@ def fn(self, obj: Step) -> Tuple[bool, str]:

try:
int(ref, 16)
except:
except ValueError:
return False, "Please pin the action to a commit sha"

if len(ref) != 40:
return False, f"Please use the full commit sha to pin the action"
return False, "Please use the full commit sha to pin the action"

return True, ""
38 changes: 18 additions & 20 deletions lint-workflow/tests/rules/test_step_pinned.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
"""Test src/rules/step_pinned.py."""
import pytest

from ruamel.yaml import YAML

from ..conftest import FIXTURE_DIR
from ..context import src

from src.load import WorkflowBuilder
from src.rules.step_pinned import RuleStepUsesPinned

yaml = YAML()


@pytest.fixture
def correct_workflow():
@pytest.fixture(name="correct_workflow")
def fixture_correct_workflow():
workflow = """\
---
on:
Expand All @@ -37,8 +35,8 @@ def correct_workflow():
return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)


@pytest.fixture
def incorrect_workflow():
@pytest.fixture(name="incorrect_workflow")
def fixture_incorrect_workflow():
workflow = """\
---
on:
Expand All @@ -60,40 +58,40 @@ def incorrect_workflow():
return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)


@pytest.fixture
def rule():
@pytest.fixture(name="rule")
def fixture_rule():
return RuleStepUsesPinned()


def test_rule_on_correct_workflow(rule, correct_workflow):
result, message = rule.fn(correct_workflow.jobs["job-key"].steps[0])
assert result == True
result, _ = rule.fn(correct_workflow.jobs["job-key"].steps[0])
assert result is True

result, message = rule.fn(correct_workflow.jobs["job-key"].steps[1])
assert result == True
result, _ = rule.fn(correct_workflow.jobs["job-key"].steps[1])
assert result is True

result, message = rule.fn(correct_workflow.jobs["job-key"].steps[2])
assert result == True
result, _ = rule.fn(correct_workflow.jobs["job-key"].steps[2])
assert result is True

result, message = rule.fn(correct_workflow.jobs["job-key"].steps[3])
assert result == True
result, _ = rule.fn(correct_workflow.jobs["job-key"].steps[3])
assert result is True


def test_rule_on_incorrect_workflow_external_branch(rule, incorrect_workflow):
result, message = rule.fn(incorrect_workflow.jobs["job-key"].steps[0])
assert result == False
assert result is False
assert "Please pin the action" in message


def test_rule_on_incorrect_workflow_hex(rule, incorrect_workflow):
result, message = rule.fn(incorrect_workflow.jobs["job-key"].steps[1])
assert result == False
assert result is False
assert "Please use the full commit sha" in message


def test_rule_on_incorrect_workflow_internal_commit(rule, incorrect_workflow):
result, message = rule.fn(incorrect_workflow.jobs["job-key"].steps[2])
assert result == False
assert result is False
assert "Please pin to main" in message


Expand Down

0 comments on commit 057c2c5

Please sign in to comment.