bitwarden_workflow_linter 0.4.6__py3-none-any.whl → 0.5.0__py3-none-any.whl
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/__about__.py +1 -1
- bitwarden_workflow_linter/default_actions.json +11 -6
- bitwarden_workflow_linter/default_settings.yaml +1 -0
- bitwarden_workflow_linter/load.py +19 -5
- bitwarden_workflow_linter/models/workflow.py +3 -1
- bitwarden_workflow_linter/rules/run_actionlint.py +108 -0
- {bitwarden_workflow_linter-0.4.6.dist-info → bitwarden_workflow_linter-0.5.0.dist-info}/METADATA +5 -4
- {bitwarden_workflow_linter-0.4.6.dist-info → bitwarden_workflow_linter-0.5.0.dist-info}/RECORD +11 -10
- {bitwarden_workflow_linter-0.4.6.dist-info → bitwarden_workflow_linter-0.5.0.dist-info}/WHEEL +0 -0
- {bitwarden_workflow_linter-0.4.6.dist-info → bitwarden_workflow_linter-0.5.0.dist-info}/entry_points.txt +0 -0
- {bitwarden_workflow_linter-0.4.6.dist-info → bitwarden_workflow_linter-0.5.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -244,6 +244,11 @@
|
|
244
244
|
"sha": "1482605bfc5719782e1267fd0c0cc350fe7646b8",
|
245
245
|
"version": "v1"
|
246
246
|
},
|
247
|
+
"fastly/compute-actions": {
|
248
|
+
"name": "fastly/compute-actions",
|
249
|
+
"sha": "ca26cccf1fa541576c6fbdf50d62feb6db6ba181",
|
250
|
+
"version": "v10"
|
251
|
+
},
|
247
252
|
"futureware-tech/simulator-action": {
|
248
253
|
"name": "futureware-tech/simulator-action",
|
249
254
|
"sha": "dab10d813144ef59b48d401cd95da151222ef8cd",
|
@@ -329,16 +334,16 @@
|
|
329
334
|
"sha": "d33c176a9b784876d966f80fb1b461808edc0641",
|
330
335
|
"version": "v2.1.1"
|
331
336
|
},
|
332
|
-
"slackapi/slack-github-action": {
|
333
|
-
"name": "slackapi/slack-github-action",
|
334
|
-
"sha": "485a9d42d3a73031f12ec201c457e2162c45d02d",
|
335
|
-
"version": "v2.0.0"
|
336
|
-
},
|
337
337
|
"sigstore/cosign-installer": {
|
338
338
|
"name": "sigstore/cosign-installer",
|
339
339
|
"sha": "dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da",
|
340
340
|
"version": "v3.7.0"
|
341
341
|
},
|
342
|
+
"slackapi/slack-github-action": {
|
343
|
+
"name": "slackapi/slack-github-action",
|
344
|
+
"sha": "485a9d42d3a73031f12ec201c457e2162c45d02d",
|
345
|
+
"version": "v2.0.0"
|
346
|
+
},
|
342
347
|
"snapcore/action-build": {
|
343
348
|
"name": "snapcore/action-build",
|
344
349
|
"sha": "3bdaa03e1ba6bf59a65f84a751d943d549a54e79",
|
@@ -384,4 +389,4 @@
|
|
384
389
|
"sha": "a3c219da6b8fa73f6ba62b68ff09c469b3a1c024",
|
385
390
|
"version": "2.2.2"
|
386
391
|
}
|
387
|
-
}
|
392
|
+
}
|
@@ -6,5 +6,6 @@ enabled_rules:
|
|
6
6
|
- bitwarden_workflow_linter.rules.step_approved.RuleStepUsesApproved
|
7
7
|
- bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
|
8
8
|
- bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
|
9
|
+
- bitwarden_workflow_linter.rules.run_actionlint.RunActionlint
|
9
10
|
|
10
11
|
approved_actions_path: default_actions.json
|
@@ -39,20 +39,32 @@ class WorkflowBuilder:
|
|
39
39
|
objects (depending on their location in the file).
|
40
40
|
"""
|
41
41
|
with open(filename, encoding="utf8") as file:
|
42
|
-
|
42
|
+
if not file:
|
43
|
+
raise WorkflowBuilderError(f"Could not load {filename}")
|
44
|
+
try:
|
45
|
+
return yaml.load(file)
|
46
|
+
except Exception as e:
|
47
|
+
raise WorkflowBuilderError(f"Error loading YAML file {filename}: {e}")
|
43
48
|
|
44
49
|
@classmethod
|
45
|
-
def __build_workflow(cls, loaded_yaml: CommentedMap) -> Workflow:
|
50
|
+
def __build_workflow(cls, filename: str, loaded_yaml: CommentedMap) -> Workflow:
|
46
51
|
"""Parse the YAML and build out the workflow to run Rules against.
|
47
52
|
|
48
53
|
Args:
|
54
|
+
filename:
|
55
|
+
The name of the file that the YAML was loaded from
|
49
56
|
loaded_yaml:
|
50
57
|
YAML that was loaded from either code or a file
|
51
58
|
|
52
59
|
Returns
|
53
60
|
A Workflow to run linting Rules against
|
54
61
|
"""
|
55
|
-
|
62
|
+
try:
|
63
|
+
if not loaded_yaml:
|
64
|
+
raise WorkflowBuilderError("No YAML loaded")
|
65
|
+
return Workflow.init("", filename, loaded_yaml)
|
66
|
+
except Exception as e:
|
67
|
+
raise WorkflowBuilderError(f"Error building workflow: {e}")
|
56
68
|
|
57
69
|
@classmethod
|
58
70
|
def build(
|
@@ -76,9 +88,11 @@ class WorkflowBuilder:
|
|
76
88
|
be loaded from disk
|
77
89
|
"""
|
78
90
|
if from_file and filename is not None:
|
79
|
-
return cls.__build_workflow(
|
91
|
+
return cls.__build_workflow(
|
92
|
+
filename, cls.__load_workflow_from_file(filename)
|
93
|
+
)
|
80
94
|
elif not from_file and workflow is not None:
|
81
|
-
return cls.__build_workflow(workflow)
|
95
|
+
return cls.__build_workflow("", workflow)
|
82
96
|
|
83
97
|
raise WorkflowBuilderError(
|
84
98
|
"The workflow must either be built from a file or from a CommentedMap"
|
@@ -23,14 +23,16 @@ class Workflow:
|
|
23
23
|
"""
|
24
24
|
|
25
25
|
key: str = ""
|
26
|
+
filename: Optional[str] = None
|
26
27
|
name: Optional[str] = None
|
27
28
|
on: Optional[CommentedMap] = None
|
28
29
|
jobs: Optional[Dict[str, Job]] = None
|
29
30
|
|
30
31
|
@classmethod
|
31
|
-
def init(cls: Self, key: str, data: CommentedMap) -> Self:
|
32
|
+
def init(cls: Self, key: str, filename: str, data: CommentedMap) -> Self:
|
32
33
|
init_data = {
|
33
34
|
"key": key,
|
35
|
+
"filename": filename,
|
34
36
|
"name": data["name"] if "name" in data else None,
|
35
37
|
"on": data["on"] if "on" in data else None,
|
36
38
|
}
|
@@ -0,0 +1,108 @@
|
|
1
|
+
"""A Rule to run actionlint on workflows."""
|
2
|
+
|
3
|
+
from typing import Optional, Tuple
|
4
|
+
import subprocess
|
5
|
+
import platform
|
6
|
+
import urllib.request
|
7
|
+
import os
|
8
|
+
|
9
|
+
from ..rule import Rule
|
10
|
+
from ..models.workflow import Workflow
|
11
|
+
from ..utils import LintLevels, Settings
|
12
|
+
|
13
|
+
|
14
|
+
def install_actionlint(platform_system: str) -> Tuple[bool, str]:
|
15
|
+
"""If actionlint is not installed, detects OS platform
|
16
|
+
and installs actionlint"""
|
17
|
+
|
18
|
+
error = f"An error occurred when installing Actionlint on {platform_system}"
|
19
|
+
|
20
|
+
if platform_system.startswith("Linux"):
|
21
|
+
return install_actionlint_source(error)
|
22
|
+
elif platform_system == "Darwin":
|
23
|
+
try:
|
24
|
+
subprocess.run(["brew", "install", "actionlint"], check=True)
|
25
|
+
return True, ""
|
26
|
+
except (FileNotFoundError, subprocess.CalledProcessError):
|
27
|
+
return False, f"{error} : check Brew installation"
|
28
|
+
elif platform_system.startswith("Win"):
|
29
|
+
try:
|
30
|
+
subprocess.run(["choco", "install", "actionlint", "-y"], check=True)
|
31
|
+
return True, ""
|
32
|
+
except (FileNotFoundError, subprocess.CalledProcessError):
|
33
|
+
return False, f"{error} : check Choco installation"
|
34
|
+
return False, error
|
35
|
+
|
36
|
+
|
37
|
+
def install_actionlint_source(error) -> Tuple[bool, str]:
|
38
|
+
"""Install Actionlint Binary from provided script"""
|
39
|
+
url = "https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash"
|
40
|
+
version = "1.6.17"
|
41
|
+
request = urllib.request.urlopen(url)
|
42
|
+
with open("download-actionlint.bash", "wb+") as fp:
|
43
|
+
fp.write(request.read())
|
44
|
+
try:
|
45
|
+
subprocess.run(["bash", "download-actionlint.bash", version], check=True)
|
46
|
+
return True, os.getcwd()
|
47
|
+
except (FileNotFoundError, subprocess.CalledProcessError):
|
48
|
+
return False, error
|
49
|
+
|
50
|
+
|
51
|
+
def check_actionlint(platform_system: str) -> Tuple[bool, str]:
|
52
|
+
"""Check if the actionlint is in the system's PATH."""
|
53
|
+
try:
|
54
|
+
subprocess.run(
|
55
|
+
["actionlint", "--version"],
|
56
|
+
stdout=subprocess.PIPE,
|
57
|
+
stderr=subprocess.PIPE,
|
58
|
+
check=True,
|
59
|
+
)
|
60
|
+
return True, ""
|
61
|
+
except subprocess.CalledProcessError:
|
62
|
+
return (
|
63
|
+
False,
|
64
|
+
"Failed to install Actionlint, \
|
65
|
+
please check your package installer or manually install it",
|
66
|
+
)
|
67
|
+
except FileNotFoundError:
|
68
|
+
return install_actionlint(platform_system)
|
69
|
+
|
70
|
+
|
71
|
+
class RunActionlint(Rule):
|
72
|
+
"""Rule to run actionlint as part of workflow linter V2."""
|
73
|
+
|
74
|
+
def __init__(self, settings: Optional[Settings] = None) -> None:
|
75
|
+
self.message = "Actionlint must pass without errors"
|
76
|
+
self.on_fail = LintLevels.WARNING
|
77
|
+
self.compatibility = [Workflow]
|
78
|
+
self.settings = settings
|
79
|
+
|
80
|
+
def fn(self, obj: Workflow) -> Tuple[bool, str]:
|
81
|
+
if not obj or not obj.filename:
|
82
|
+
raise AttributeError(
|
83
|
+
"Running actionlint without a filename is not currently supported"
|
84
|
+
)
|
85
|
+
|
86
|
+
installed, location = check_actionlint(platform.system())
|
87
|
+
if installed:
|
88
|
+
if location:
|
89
|
+
result = subprocess.run(
|
90
|
+
[location + "/actionlint", obj.filename],
|
91
|
+
capture_output=True,
|
92
|
+
text=True,
|
93
|
+
check=False,
|
94
|
+
)
|
95
|
+
else:
|
96
|
+
result = subprocess.run(
|
97
|
+
["actionlint", obj.filename],
|
98
|
+
capture_output=True,
|
99
|
+
text=True,
|
100
|
+
check=False,
|
101
|
+
)
|
102
|
+
if result.returncode == 1:
|
103
|
+
return False, result.stdout
|
104
|
+
if result.returncode > 1:
|
105
|
+
return False, result.stdout
|
106
|
+
return True, ""
|
107
|
+
else:
|
108
|
+
return False, self.message
|
{bitwarden_workflow_linter-0.4.6.dist-info → bitwarden_workflow_linter-0.5.0.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: bitwarden_workflow_linter
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.5.0
|
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
|
@@ -27,9 +27,8 @@ Description-Content-Type: text/markdown
|
|
27
27
|
# Bitwarden Workflow Linter
|
28
28
|
|
29
29
|
Bitwarden's Workflow Linter is an extensible linter to apply opinionated organization-specific
|
30
|
-
GitHub Action standards. It was designed to be used alongside
|
31
|
-
[
|
32
|
-
[yamllint](https://github.com/adrienverge/yamllint) to check for correct Action syntax and enforce
|
30
|
+
GitHub Action standards. It was designed to be used alongside
|
31
|
+
[yamllint](https://github.com/adrienverge/yamllint) to enforce
|
33
32
|
specific YAML standards.
|
34
33
|
|
35
34
|
To see an example of Workflow Linter in practice in GitHub Action, see the
|
@@ -90,6 +89,8 @@ options:
|
|
90
89
|
|
91
90
|
- Python 3.11
|
92
91
|
- pipenv
|
92
|
+
- Windows systems: Chocolatey package manager
|
93
|
+
- Mac OS systems: Homebrew package manager
|
93
94
|
|
94
95
|
### Setup
|
95
96
|
|
{bitwarden_workflow_linter-0.4.6.dist-info → bitwarden_workflow_linter-0.5.0.dist-info}/RECORD
RENAMED
@@ -1,27 +1,28 @@
|
|
1
|
-
bitwarden_workflow_linter/__about__.py,sha256=
|
1
|
+
bitwarden_workflow_linter/__about__.py,sha256=J8OcMo9sMh_CmVCcZ_CEwP4v_C878iSmJ7XnhYlovUo,59
|
2
2
|
bitwarden_workflow_linter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
bitwarden_workflow_linter/actions.py,sha256=LAn3yQeMMmCOvJWeTn3dE1U2nyEJqIBMwESq3TtY9hE,9069
|
4
4
|
bitwarden_workflow_linter/cli.py,sha256=wgkK1MlVbo6Zx3f2CZZ_tkSWq_hdsGciHJA1knX6Yuw,1699
|
5
|
-
bitwarden_workflow_linter/default_actions.json,sha256=
|
6
|
-
bitwarden_workflow_linter/default_settings.yaml,sha256=
|
5
|
+
bitwarden_workflow_linter/default_actions.json,sha256=LPJIB9rCnQksBz_2Y3bOagTrbPbqficG5Y0u0yhGhSk,12170
|
6
|
+
bitwarden_workflow_linter/default_settings.yaml,sha256=3GgDYOgqZ13wMnEtDZUjgibQkf5xYzbcSfvOG7Yim1s,641
|
7
7
|
bitwarden_workflow_linter/lint.py,sha256=RDHv5jGeGCf5XIHE8jyqQET3-cFykl7223SQVS4Q3pg,5525
|
8
|
-
bitwarden_workflow_linter/load.py,sha256=
|
8
|
+
bitwarden_workflow_linter/load.py,sha256=XXbja-sVUtXaJjqF9sTP2xzFto3CXcCuEBNFp3Yo4VM,5078
|
9
9
|
bitwarden_workflow_linter/rule.py,sha256=Qb60JiUDAWN3ayrMGoSbbDCSFmw-ql8djzAkxISaob4,3250
|
10
10
|
bitwarden_workflow_linter/utils.py,sha256=9WO3T9w9vKAow_xR6JDz2MvdMXKExV18AzucF0vh67s,4695
|
11
11
|
bitwarden_workflow_linter/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
12
|
bitwarden_workflow_linter/models/job.py,sha256=nBK7_VYu6RRST7WLtdLsoRErl5j4Er8W9hCw9XlSECk,2043
|
13
13
|
bitwarden_workflow_linter/models/step.py,sha256=j81iWYWcNI9x55n1MOR0N6ogKaQ_4-CKu9LnI_fwEOE,1814
|
14
|
-
bitwarden_workflow_linter/models/workflow.py,sha256=
|
14
|
+
bitwarden_workflow_linter/models/workflow.py,sha256=Jr1CJSCpII9Z4RT6Sh1wjzZU6ov3fZt45BmTrfLNLLE,1479
|
15
15
|
bitwarden_workflow_linter/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
16
|
bitwarden_workflow_linter/rules/job_environment_prefix.py,sha256=sY1cBU5AeBHWSyun7gwnoS0ycRyBMjjVo_2lvanBj7U,2612
|
17
17
|
bitwarden_workflow_linter/rules/name_capitalized.py,sha256=quuqXM_qg93UE8mQo1YQp8cQ_Fx6c2u03_19s_c0ntw,1981
|
18
18
|
bitwarden_workflow_linter/rules/name_exists.py,sha256=MxcaNQz64JXeHRPiOip9BxJNgPdpKQa7Z51mDoNw2hU,1681
|
19
19
|
bitwarden_workflow_linter/rules/pinned_job_runner.py,sha256=Dm6_sdPX0yFMji_y2LMFj4gWFaToEgauyBVpNRP2qiI,1606
|
20
|
+
bitwarden_workflow_linter/rules/run_actionlint.py,sha256=qzfrBUcvNMkeBKGMKkIyqRaRV18dUREcuhZlZHxjgkk,3762
|
20
21
|
bitwarden_workflow_linter/rules/step_approved.py,sha256=6XuYoasw2ME8vQu5G0ZygUSi7X5amLLWeXH81cqvKv8,3159
|
21
22
|
bitwarden_workflow_linter/rules/step_pinned.py,sha256=fyqBjarR0UNQ6tU_ja0ZOi2afP942BMqOz5nU_yKzmw,3413
|
22
23
|
bitwarden_workflow_linter/rules/underscore_outputs.py,sha256=w8pP1dTJEC9I2X5fQIAHDAEiaNP1xMhb4kPiF-dn8U0,4131
|
23
|
-
bitwarden_workflow_linter-0.
|
24
|
-
bitwarden_workflow_linter-0.
|
25
|
-
bitwarden_workflow_linter-0.
|
26
|
-
bitwarden_workflow_linter-0.
|
27
|
-
bitwarden_workflow_linter-0.
|
24
|
+
bitwarden_workflow_linter-0.5.0.dist-info/METADATA,sha256=YKg1LLvX2wEIvrC5Aacy6zFOxHrxdKKZQfcZ8AgHVQs,6164
|
25
|
+
bitwarden_workflow_linter-0.5.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
26
|
+
bitwarden_workflow_linter-0.5.0.dist-info/entry_points.txt,sha256=SA_yF9CwL4VMUvdcmCd7k9rjsQNzfeOUBuDnMnaO8QQ,60
|
27
|
+
bitwarden_workflow_linter-0.5.0.dist-info/licenses/LICENSE.txt,sha256=uY-7N9tbI7xc_c0WeTIGpacSCnsB91N05eCIg3bkaRw,35140
|
28
|
+
bitwarden_workflow_linter-0.5.0.dist-info/RECORD,,
|
{bitwarden_workflow_linter-0.4.6.dist-info → bitwarden_workflow_linter-0.5.0.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|
File without changes
|