bitwarden_workflow_linter 0.5.6__tar.gz → 0.5.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/PKG-INFO +1 -1
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/settings.yaml +1 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/__about__.py +1 -1
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/default_settings.yaml +1 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/models/job.py +9 -0
- bitwarden_workflow_linter-0.5.7/src/bitwarden_workflow_linter/rules/check_pr_target.py +81 -0
- bitwarden_workflow_linter-0.5.7/tests/rules/test_check_pr_target.py +276 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.editorconfig +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.gitattributes +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/CODEOWNERS +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/renovate.json +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/workflows/_version_type.yml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/workflows/cd.yml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/workflows/ci.yml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/workflows/enforce-labels.yml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/workflows/scan.yml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/workflows/update_actions.yml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.gitignore +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.husky/pre-commit +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.python-version +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/CONTRIBUTING.md +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/LICENSE.txt +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/Pipfile +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/Pipfile.lock +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/README.md +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/SECURITY.md +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/Taskfile.yml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/package-lock.json +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/package.json +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/pylintrc +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/pyproject.toml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/pyproject.toml.tpl +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/__init__.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/actions.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/cli.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/default_actions.json +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/lint.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/load.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/models/__init__.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/models/step.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/models/workflow.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/rule.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/rules/__init__.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/rules/job_environment_prefix.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/rules/name_capitalized.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/rules/name_exists.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/rules/pinned_job_runner.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/rules/run_actionlint.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/rules/step_approved.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/rules/step_pinned.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/rules/underscore_outputs.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/src/bitwarden_workflow_linter/utils.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/__init__.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/conftest.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/fixtures/test-alt.yml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/fixtures/test-min-incorrect.yaml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/fixtures/test-min.yaml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/fixtures/test-outputs-incorrect.yml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/fixtures/test.yml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/fixtures/test_a.yaml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/fixtures/test_workflow.yaml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/fixtures/test_workflow_incorrect.yaml +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/rules/__init__.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/rules/test_job_environment_prefix.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/rules/test_name_capitalized.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/rules/test_name_exists.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/rules/test_pinned_job_runner.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/rules/test_run_actionlint.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/rules/test_step_approved.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/rules/test_step_pinned.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/rules/test_underscore_output.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/test_job.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/test_lint.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/test_load.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/test_rule.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/test_step.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/test_utils.py +0 -0
- {bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/test_workflow.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: bitwarden_workflow_linter
|
3
|
-
Version: 0.5.
|
3
|
+
Version: 0.5.7
|
4
4
|
Summary: Custom GitHub Action Workflow Linter
|
5
5
|
Project-URL: Homepage, https://github.com/bitwarden/workflow-linter
|
6
6
|
Project-URL: Issues, https://github.com/bitwarden/workflow-linter/issues
|
@@ -7,5 +7,6 @@ enabled_rules:
|
|
7
7
|
- bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
|
8
8
|
- bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
|
9
9
|
- bitwarden_workflow_linter.rules.run_actionlint.RunActionlint
|
10
|
+
- bitwarden_workflow_linter.rules.check_pr_target.RuleCheckPrTarget
|
10
11
|
|
11
12
|
approved_actions_path: default_actions.json
|
@@ -7,5 +7,6 @@ enabled_rules:
|
|
7
7
|
- bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
|
8
8
|
- bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
|
9
9
|
- bitwarden_workflow_linter.rules.run_actionlint.RunActionlint
|
10
|
+
- bitwarden_workflow_linter.rules.check_pr_target.RuleCheckPrTarget
|
10
11
|
|
11
12
|
approved_actions_path: default_actions.json
|
@@ -23,6 +23,7 @@ class Job:
|
|
23
23
|
key: Optional[str] = None
|
24
24
|
name: Optional[str] = None
|
25
25
|
env: Optional[CommentedMap] = None
|
26
|
+
needs: Optional[List[str]] = None
|
26
27
|
steps: Optional[List[Step]] = None
|
27
28
|
uses: Optional[str] = None
|
28
29
|
uses_path: Optional[str] = None
|
@@ -32,6 +33,13 @@ class Job:
|
|
32
33
|
)
|
33
34
|
outputs: Optional[CommentedMap] = None
|
34
35
|
|
36
|
+
@classmethod
|
37
|
+
def parse_needs(cls: Self, value):
|
38
|
+
"""Parser to make all needs values lists that can be searched by linter."""
|
39
|
+
if isinstance(value, str):
|
40
|
+
return [value]
|
41
|
+
return value
|
42
|
+
|
35
43
|
@classmethod
|
36
44
|
def init(cls: Self, key: str, data: CommentedMap) -> Self:
|
37
45
|
"""Custom dataclass constructor to map job data to a Job."""
|
@@ -40,6 +48,7 @@ class Job:
|
|
40
48
|
"name": data["name"] if "name" in data else None,
|
41
49
|
"runs-on": data["runs-on"] if "runs-on" in data else None,
|
42
50
|
"env": data["env"] if "env" in data else None,
|
51
|
+
"needs": Job.parse_needs(data["needs"]) if "needs" in data else None,
|
43
52
|
"outputs": data["outputs"] if "outputs" in data else None,
|
44
53
|
}
|
45
54
|
|
@@ -0,0 +1,81 @@
|
|
1
|
+
"""A Rule to enforce check-run is run when workflow uses pull_request_target."""
|
2
|
+
|
3
|
+
from typing import Optional, Tuple
|
4
|
+
|
5
|
+
from ..models.workflow import Workflow
|
6
|
+
from ..rule import Rule
|
7
|
+
from ..utils import LintLevels, Settings
|
8
|
+
|
9
|
+
|
10
|
+
class RuleCheckPrTarget(Rule):
|
11
|
+
def __init__(self, settings: Optional[Settings] = None) -> None:
|
12
|
+
"""
|
13
|
+
To ensure pull_request_target is safe to use, the check-run step is added
|
14
|
+
to all jobs as a dependency.
|
15
|
+
|
16
|
+
Once a branch is pushed to Github, it already opens up a vulnerability
|
17
|
+
even if the check-run scan fails to detect this.
|
18
|
+
|
19
|
+
In order to prevent a vulnerable branch from being used for an attack
|
20
|
+
prior to being caught through vetting, all pull_request_target workflows
|
21
|
+
should only be run by users with appropriate permissions.
|
22
|
+
|
23
|
+
This greatly reduces the risk as community contributors can't use a fork to run a compromised workflow that uses pull_request_target.
|
24
|
+
"""
|
25
|
+
self.message = "A check-run job must be included as a direct job dependency when pull_request_target is used and the workflow may only apply to runs on the main branch"
|
26
|
+
self.on_fail = LintLevels.WARNING
|
27
|
+
self.compatibility = [Workflow]
|
28
|
+
self.settings = settings
|
29
|
+
|
30
|
+
def targets_main_branch(self, obj:Workflow) -> bool:
|
31
|
+
if obj.on["pull_request_target"].get("branches"):
|
32
|
+
branches_list = obj.on["pull_request_target"].get("branches")
|
33
|
+
if isinstance(branches_list, str):
|
34
|
+
branches_list = [branches_list]
|
35
|
+
if any(branch != 'main' for branch in branches_list):
|
36
|
+
return False
|
37
|
+
else:
|
38
|
+
return False
|
39
|
+
return True
|
40
|
+
|
41
|
+
def has_check_run(self, obj: Workflow) -> Tuple[bool, str]:
|
42
|
+
for name, job in obj.jobs.items():
|
43
|
+
if job.uses == "bitwarden/gh-actions/.github/workflows/check-run.yml@main":
|
44
|
+
return True, name
|
45
|
+
return False, ""
|
46
|
+
|
47
|
+
def check_run_required(self, obj:Workflow, check_job:str) -> list:
|
48
|
+
missing_jobs = []
|
49
|
+
for job in list(obj.jobs.keys()):
|
50
|
+
if job is not check_job:
|
51
|
+
job_list = obj.jobs[job].needs
|
52
|
+
if job_list:
|
53
|
+
if check_job not in job_list:
|
54
|
+
missing_jobs.append(job)
|
55
|
+
else:
|
56
|
+
missing_jobs.append(job)
|
57
|
+
return missing_jobs
|
58
|
+
|
59
|
+
def fn(self, obj: Workflow) -> Tuple[bool, str]:
|
60
|
+
Errors = []
|
61
|
+
if obj.on.get("pull_request_target"):
|
62
|
+
result, check_job = self.has_check_run(obj)
|
63
|
+
main_branch_only = self.targets_main_branch(obj)
|
64
|
+
if not main_branch_only:
|
65
|
+
Errors.append("Workflows using pull_request_target can only target the main branch")
|
66
|
+
if result:
|
67
|
+
missing_jobs = self.check_run_required(obj, check_job)
|
68
|
+
if missing_jobs:
|
69
|
+
job_list = ', '.join(missing_jobs)
|
70
|
+
message = f"Check-run is missing from the following jobs in the workflow: {job_list}"
|
71
|
+
Errors.append(message)
|
72
|
+
else:
|
73
|
+
message = f"A check-run job must be included as a direct job dependency when pull_request_target is used"
|
74
|
+
Errors.append(message)
|
75
|
+
if Errors:
|
76
|
+
self.message = "\n".join(Errors)
|
77
|
+
return False, f"{self.message}"
|
78
|
+
else:
|
79
|
+
return True, ""
|
80
|
+
else:
|
81
|
+
return True, ""
|
@@ -0,0 +1,276 @@
|
|
1
|
+
"""Test src/bitwarden_workflow_linter/rules/check_pr_target."""
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
from ruamel.yaml import YAML
|
6
|
+
|
7
|
+
from src.bitwarden_workflow_linter.load import WorkflowBuilder
|
8
|
+
from src.bitwarden_workflow_linter.rules.check_pr_target import (
|
9
|
+
RuleCheckPrTarget,
|
10
|
+
)
|
11
|
+
|
12
|
+
yaml = YAML()
|
13
|
+
message = "A check-run job must be included as a direct job dependency when pull_request_target is used and the workflow may only apply to runs on the main branch"
|
14
|
+
|
15
|
+
@pytest.fixture(name="correct_workflow")
|
16
|
+
def fixture_correct_workflow():
|
17
|
+
workflow = """\
|
18
|
+
---
|
19
|
+
on:
|
20
|
+
workflow_dispatch:
|
21
|
+
pull_request_target:
|
22
|
+
types: [opened, synchronize]
|
23
|
+
branches:
|
24
|
+
- 'main'
|
25
|
+
|
26
|
+
jobs:
|
27
|
+
check-run:
|
28
|
+
name: Check PR run
|
29
|
+
uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main
|
30
|
+
|
31
|
+
quality:
|
32
|
+
name: Quality scan
|
33
|
+
needs: check-run
|
34
|
+
steps:
|
35
|
+
- run: echo test
|
36
|
+
|
37
|
+
dependent-job:
|
38
|
+
name: Another Dependent Job
|
39
|
+
needs:
|
40
|
+
- quality
|
41
|
+
- check-run
|
42
|
+
steps:
|
43
|
+
- run: echo another dependent job
|
44
|
+
"""
|
45
|
+
return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
|
46
|
+
|
47
|
+
@pytest.fixture(name="no_check_workflow")
|
48
|
+
def fixture_no_check_workflow():
|
49
|
+
workflow = """\
|
50
|
+
---
|
51
|
+
on:
|
52
|
+
workflow_dispatch:
|
53
|
+
pull_request_target:
|
54
|
+
types: [opened, synchronize]
|
55
|
+
branches:
|
56
|
+
- 'main'
|
57
|
+
|
58
|
+
jobs:
|
59
|
+
job-key:
|
60
|
+
runs-on: ubuntu-22.04
|
61
|
+
steps:
|
62
|
+
- run: echo test
|
63
|
+
"""
|
64
|
+
return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
|
65
|
+
|
66
|
+
@pytest.fixture(name="no_needs_workflow")
|
67
|
+
def fixture_no_needs_workflow():
|
68
|
+
workflow = """\
|
69
|
+
---
|
70
|
+
on:
|
71
|
+
workflow_dispatch:
|
72
|
+
pull_request_target:
|
73
|
+
types: [opened, synchronize]
|
74
|
+
branches: main
|
75
|
+
|
76
|
+
jobs:
|
77
|
+
check-run:
|
78
|
+
name: Check PR run
|
79
|
+
uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main
|
80
|
+
|
81
|
+
job-key:
|
82
|
+
runs-on: ubuntu-22.04
|
83
|
+
steps:
|
84
|
+
- run: echo test
|
85
|
+
|
86
|
+
quality:
|
87
|
+
name: Quality scan
|
88
|
+
steps:
|
89
|
+
- run: echo test
|
90
|
+
|
91
|
+
"""
|
92
|
+
return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
|
93
|
+
|
94
|
+
@pytest.fixture(name="no_target_workflow")
|
95
|
+
def fixture_no_target_workflow():
|
96
|
+
workflow = """\
|
97
|
+
---
|
98
|
+
on:
|
99
|
+
workflow_dispatch:
|
100
|
+
|
101
|
+
jobs:
|
102
|
+
job-key:
|
103
|
+
runs-on: ubuntu-22.04
|
104
|
+
steps:
|
105
|
+
- run: echo test
|
106
|
+
"""
|
107
|
+
return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
|
108
|
+
|
109
|
+
@pytest.fixture(name="dependent_missing_check_workflow")
|
110
|
+
def dependent_missing_check_workflow():
|
111
|
+
workflow = """\
|
112
|
+
---
|
113
|
+
on:
|
114
|
+
workflow_dispatch:
|
115
|
+
pull_request_target:
|
116
|
+
types: [opened, synchronize]
|
117
|
+
branches:
|
118
|
+
- 'main'
|
119
|
+
|
120
|
+
jobs:
|
121
|
+
check-run:
|
122
|
+
name: Check PR run
|
123
|
+
uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main
|
124
|
+
|
125
|
+
quality:
|
126
|
+
name: Quality scan
|
127
|
+
needs: check-run
|
128
|
+
steps:
|
129
|
+
- run: echo test
|
130
|
+
|
131
|
+
dependent-job:
|
132
|
+
name: Another Dependent Job
|
133
|
+
needs:
|
134
|
+
- quality
|
135
|
+
steps:
|
136
|
+
- run: echo another dependent job
|
137
|
+
"""
|
138
|
+
return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
|
139
|
+
|
140
|
+
@pytest.fixture(name="no_branches_workflow")
|
141
|
+
def fixture_no_branches_workflow():
|
142
|
+
workflow = """\
|
143
|
+
---
|
144
|
+
on:
|
145
|
+
workflow_dispatch:
|
146
|
+
pull_request_target:
|
147
|
+
types: [opened, synchronize]
|
148
|
+
|
149
|
+
jobs:
|
150
|
+
check-run:
|
151
|
+
name: Check PR run
|
152
|
+
uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main
|
153
|
+
|
154
|
+
quality:
|
155
|
+
name: Quality scan
|
156
|
+
needs: check-run
|
157
|
+
steps:
|
158
|
+
- run: echo test
|
159
|
+
|
160
|
+
dependent-job:
|
161
|
+
name: Another Dependent Job
|
162
|
+
needs:
|
163
|
+
- quality
|
164
|
+
- check-run
|
165
|
+
steps:
|
166
|
+
- run: echo another dependent job
|
167
|
+
"""
|
168
|
+
return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
|
169
|
+
|
170
|
+
@pytest.fixture(name="bad_branches_workflow")
|
171
|
+
def fixture_bad_branches_workflow():
|
172
|
+
workflow = """\
|
173
|
+
---
|
174
|
+
on:
|
175
|
+
workflow_dispatch:
|
176
|
+
pull_request_target:
|
177
|
+
types: [opened, synchronize]
|
178
|
+
branches:
|
179
|
+
- 'main'
|
180
|
+
- 'not main'
|
181
|
+
|
182
|
+
jobs:
|
183
|
+
check-run:
|
184
|
+
name: Check PR run
|
185
|
+
uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main
|
186
|
+
|
187
|
+
quality:
|
188
|
+
name: Quality scan
|
189
|
+
needs: check-run
|
190
|
+
steps:
|
191
|
+
- run: echo test
|
192
|
+
|
193
|
+
dependent-job:
|
194
|
+
name: Another Dependent Job
|
195
|
+
needs:
|
196
|
+
- quality
|
197
|
+
- check-run
|
198
|
+
steps:
|
199
|
+
- run: echo another dependent job
|
200
|
+
"""
|
201
|
+
return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
|
202
|
+
|
203
|
+
@pytest.fixture(name="two_failures_workflow")
|
204
|
+
def fixture_two_failures_workflow():
|
205
|
+
workflow = """\
|
206
|
+
---
|
207
|
+
on:
|
208
|
+
workflow_dispatch:
|
209
|
+
pull_request_target:
|
210
|
+
types: [opened, synchronize]
|
211
|
+
|
212
|
+
jobs:
|
213
|
+
check-run:
|
214
|
+
name: Check PR run
|
215
|
+
uses: bitwarden/some-other-repo/.github/workflows/check-run.yml@main
|
216
|
+
|
217
|
+
quality:
|
218
|
+
name: Quality scan
|
219
|
+
needs: check-run
|
220
|
+
steps:
|
221
|
+
- run: echo test
|
222
|
+
|
223
|
+
dependent-job:
|
224
|
+
name: Another Dependent Job
|
225
|
+
needs:
|
226
|
+
- quality
|
227
|
+
- check-run
|
228
|
+
steps:
|
229
|
+
- run: echo another dependent job
|
230
|
+
"""
|
231
|
+
return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
|
232
|
+
|
233
|
+
@pytest.fixture(name="rule")
|
234
|
+
def fixture_rule():
|
235
|
+
return RuleCheckPrTarget()
|
236
|
+
|
237
|
+
def test_rule_on_correct_workflow(rule, correct_workflow):
|
238
|
+
result, message = rule.fn(correct_workflow)
|
239
|
+
assert result is True
|
240
|
+
assert message == ""
|
241
|
+
|
242
|
+
|
243
|
+
def test_rule_on_no_checkworkflow(rule, no_check_workflow):
|
244
|
+
result, message = rule.fn(no_check_workflow)
|
245
|
+
assert result is False
|
246
|
+
assert message == message
|
247
|
+
|
248
|
+
def test_rule_on_no_target_workflow(rule, no_target_workflow):
|
249
|
+
result, message = rule.fn(no_target_workflow)
|
250
|
+
assert result is True
|
251
|
+
assert message == ""
|
252
|
+
|
253
|
+
def test_rule_on_jobs_without_needs(rule, no_needs_workflow):
|
254
|
+
result, message = rule.fn(no_needs_workflow)
|
255
|
+
assert result is False
|
256
|
+
assert message == message, "check-run is missing from the following jobs in the workflow: quality"
|
257
|
+
|
258
|
+
def test_rule_on_dependencies_without_check(rule, dependent_missing_check_workflow):
|
259
|
+
result, message = rule.fn(dependent_missing_check_workflow)
|
260
|
+
assert result is False
|
261
|
+
assert message == message, "check-run is missing from the following jobs in the workflow: dependent-job"
|
262
|
+
|
263
|
+
def test_rule_on_no_branches_workflow(rule, no_branches_workflow):
|
264
|
+
result, message = rule.fn(no_branches_workflow)
|
265
|
+
assert result is False
|
266
|
+
assert message == "Workflows using pull_request_target can only target the main branch"
|
267
|
+
|
268
|
+
def test_rule_on_only_target_main(rule, bad_branches_workflow):
|
269
|
+
result, message = rule.fn(bad_branches_workflow)
|
270
|
+
assert result is False
|
271
|
+
assert message == "Workflows using pull_request_target can only target the main branch"
|
272
|
+
|
273
|
+
def test_rule_on_two_failures(rule, two_failures_workflow):
|
274
|
+
result, message = rule.fn(two_failures_workflow)
|
275
|
+
assert result is False
|
276
|
+
assert message == "Workflows using pull_request_target can only target the main branch\nA check-run job must be included as a direct job dependency when pull_request_target is used"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/PULL_REQUEST_TEMPLATE.md
RENAMED
File without changes
|
File without changes
|
File without changes
|
{bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/workflows/cd.yml
RENAMED
File without changes
|
{bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/workflows/ci.yml
RENAMED
File without changes
|
File without changes
|
{bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/.github/workflows/scan.yml
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/fixtures/test-alt.yml
RENAMED
File without changes
|
File without changes
|
{bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/fixtures/test-min.yaml
RENAMED
File without changes
|
File without changes
|
File without changes
|
{bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/fixtures/test_a.yaml
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/rules/test_name_exists.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{bitwarden_workflow_linter-0.5.6 → bitwarden_workflow_linter-0.5.7}/tests/rules/test_step_pinned.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|