bitwarden_workflow_linter 0.4.6__tar.gz → 0.5.0__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.
Files changed (78) hide show
  1. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.gitignore +4 -1
  2. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/PKG-INFO +5 -4
  3. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/README.md +4 -3
  4. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/settings.yaml +1 -0
  5. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/__about__.py +1 -1
  6. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/default_actions.json +11 -6
  7. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/default_settings.yaml +1 -0
  8. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/load.py +19 -5
  9. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/models/workflow.py +3 -1
  10. bitwarden_workflow_linter-0.5.0/src/bitwarden_workflow_linter/rules/run_actionlint.py +108 -0
  11. bitwarden_workflow_linter-0.5.0/tests/fixtures/test_workflow.yaml +32 -0
  12. bitwarden_workflow_linter-0.5.0/tests/fixtures/test_workflow_incorrect.yaml +36 -0
  13. bitwarden_workflow_linter-0.5.0/tests/rules/test_run_actionlint.py +181 -0
  14. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/test_workflow.py +3 -3
  15. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.editorconfig +0 -0
  16. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.gitattributes +0 -0
  17. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.github/CODEOWNERS +0 -0
  18. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  19. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  20. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.github/renovate.json +0 -0
  21. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.github/workflows/_version_type.yml +0 -0
  22. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.github/workflows/cd.yml +0 -0
  23. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.github/workflows/ci.yml +0 -0
  24. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.github/workflows/enforce-labels.yml +0 -0
  25. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.github/workflows/scan.yml +0 -0
  26. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.github/workflows/update_actions.yml +0 -0
  27. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.husky/pre-commit +0 -0
  28. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/.python-version +0 -0
  29. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/CONTRIBUTING.md +0 -0
  30. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/LICENSE.txt +0 -0
  31. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/Pipfile +0 -0
  32. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/Pipfile.lock +0 -0
  33. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/SECURITY.md +0 -0
  34. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/Taskfile.yml +0 -0
  35. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/package-lock.json +0 -0
  36. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/package.json +0 -0
  37. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/pylintrc +0 -0
  38. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/pyproject.toml +0 -0
  39. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/pyproject.toml.tpl +0 -0
  40. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/__init__.py +0 -0
  41. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/actions.py +0 -0
  42. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/cli.py +0 -0
  43. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/lint.py +0 -0
  44. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/models/__init__.py +0 -0
  45. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/models/job.py +0 -0
  46. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/models/step.py +0 -0
  47. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/rule.py +0 -0
  48. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/rules/__init__.py +0 -0
  49. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/rules/job_environment_prefix.py +0 -0
  50. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/rules/name_capitalized.py +0 -0
  51. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/rules/name_exists.py +0 -0
  52. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/rules/pinned_job_runner.py +0 -0
  53. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/rules/step_approved.py +0 -0
  54. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/rules/step_pinned.py +0 -0
  55. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/rules/underscore_outputs.py +0 -0
  56. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/src/bitwarden_workflow_linter/utils.py +0 -0
  57. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/__init__.py +0 -0
  58. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/conftest.py +0 -0
  59. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/fixtures/test-alt.yml +0 -0
  60. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/fixtures/test-min-incorrect.yaml +0 -0
  61. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/fixtures/test-min.yaml +0 -0
  62. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/fixtures/test-outputs-incorrect.yml +0 -0
  63. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/fixtures/test.yml +0 -0
  64. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/fixtures/test_a.yaml +0 -0
  65. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/rules/__init__.py +0 -0
  66. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/rules/test_job_environment_prefix.py +0 -0
  67. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/rules/test_name_capitalized.py +0 -0
  68. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/rules/test_name_exists.py +0 -0
  69. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/rules/test_pinned_job_runner.py +0 -0
  70. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/rules/test_step_approved.py +0 -0
  71. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/rules/test_step_pinned.py +0 -0
  72. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/rules/test_underscore_output.py +0 -0
  73. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/test_job.py +0 -0
  74. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/test_lint.py +0 -0
  75. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/test_load.py +0 -0
  76. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/test_rule.py +0 -0
  77. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/test_step.py +0 -0
  78. {bitwarden_workflow_linter-0.4.6 → bitwarden_workflow_linter-0.5.0}/tests/test_utils.py +0 -0
@@ -12,7 +12,7 @@ Thumbs.db
12
12
  *.sublime-workspace
13
13
 
14
14
  # Visual Studio Code
15
- .vscode/*
15
+ .vscode
16
16
  !.vscode/settings.json
17
17
  !.vscode/tasks.json
18
18
  !.vscode/launch.json
@@ -35,3 +35,6 @@ flake.*
35
35
  # Python
36
36
  **/__pycache__/**
37
37
  *.pyc
38
+ .venv/
39
+ .pytest_cache
40
+ .pytype
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bitwarden_workflow_linter
3
- Version: 0.4.6
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 tools like
31
- [action-lint](https://github.com/rhysd/actionlint) and
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
 
@@ -1,9 +1,8 @@
1
1
  # Bitwarden Workflow Linter
2
2
 
3
3
  Bitwarden's Workflow Linter is an extensible linter to apply opinionated organization-specific
4
- GitHub Action standards. It was designed to be used alongside tools like
5
- [action-lint](https://github.com/rhysd/actionlint) and
6
- [yamllint](https://github.com/adrienverge/yamllint) to check for correct Action syntax and enforce
4
+ GitHub Action standards. It was designed to be used alongside
5
+ [yamllint](https://github.com/adrienverge/yamllint) to enforce
7
6
  specific YAML standards.
8
7
 
9
8
  To see an example of Workflow Linter in practice in GitHub Action, see the
@@ -64,6 +63,8 @@ options:
64
63
 
65
64
  - Python 3.11
66
65
  - pipenv
66
+ - Windows systems: Chocolatey package manager
67
+ - Mac OS systems: Homebrew package manager
67
68
 
68
69
  ### Setup
69
70
 
@@ -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
@@ -1,3 +1,3 @@
1
1
  """Metadata for Workflow Linter."""
2
2
 
3
- __version__ = "0.4.6"
3
+ __version__ = "0.5.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
- return yaml.load(file)
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
- return Workflow.init("", loaded_yaml)
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(cls.__load_workflow_from_file(filename))
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
@@ -0,0 +1,32 @@
1
+ name: test
2
+ on:
3
+ workflow_dispatch:
4
+ pull_request:
5
+
6
+ jobs:
7
+ job-key:
8
+ name: Test
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Test
12
+ run: echo test
13
+
14
+ call-workflow:
15
+ uses: bitwarden/server/.github/workflows/workflow-linter.yml@master
16
+
17
+ test-normal-action:
18
+ name: Download Latest
19
+ runs-on: ubuntu-20.04
20
+ steps:
21
+ - name: Checkout
22
+ uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
23
+
24
+ - run: |
25
+ echo test
26
+
27
+ test-local-action:
28
+ name: Testing a local action call
29
+ runs-on: ubuntu-20.04
30
+ steps:
31
+ - name: local-action
32
+ uses: ./version-bump
@@ -0,0 +1,36 @@
1
+ name: test
2
+ on:
3
+ push:
4
+ branches:
5
+ -
6
+ path:
7
+ - "src/**"
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ job-key:
12
+ name: Test
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Test
16
+ run: echo test
17
+
18
+ call-workflow:
19
+ uses: bitwarden/server/.github/workflows/workflow-linter.yml@master
20
+
21
+ test-normal-action:
22
+ name: Download Latest
23
+ runs-on: ubuntu-20.04
24
+ steps:
25
+ - name: Checkout
26
+ uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
27
+
28
+ - run: |
29
+ echo test
30
+
31
+ test-local-action:
32
+ name: Testing a local action call
33
+ runs-on: ubuntu-20.04
34
+ steps:
35
+ - name: local-action
36
+ uses: ./version-bump
@@ -0,0 +1,181 @@
1
+ """Test src/bitwarden_workflow_linter/rules/run_actionlint."""
2
+
3
+ import pytest
4
+ import subprocess
5
+
6
+ from ruamel.yaml import YAML
7
+
8
+ from src.bitwarden_workflow_linter.load import WorkflowBuilder
9
+ from src.bitwarden_workflow_linter.rules.run_actionlint import (
10
+ RunActionlint,
11
+ install_actionlint_source,
12
+ check_actionlint,
13
+ install_actionlint,
14
+ )
15
+
16
+ yaml = YAML()
17
+
18
+
19
+ @pytest.fixture(name="rule")
20
+ def fixture_rule():
21
+ return RunActionlint()
22
+
23
+
24
+ def test_rule_on_correct_workflow(rule):
25
+ correct_workflow = WorkflowBuilder.build("tests/fixtures/test_workflow.yaml")
26
+ result, _ = rule.fn(correct_workflow)
27
+ assert result is True
28
+
29
+
30
+ def test_rule_on_incorrect_workflow(rule):
31
+ incorrect_workflow = WorkflowBuilder.build(
32
+ "tests/fixtures/test_workflow_incorrect.yaml"
33
+ )
34
+ result, _ = rule.fn(incorrect_workflow)
35
+ assert result is False
36
+
37
+
38
+ def test_pass_install_actionlint_linux():
39
+ result, _ = install_actionlint("Linux")
40
+ assert result is True
41
+
42
+
43
+ def test_install_actionlint_darwin(monkeypatch):
44
+ def mock_run(*args, **kwargs):
45
+ return subprocess.CompletedProcess(args, 0)
46
+
47
+ monkeypatch.setattr(subprocess, "run", mock_run)
48
+ result, _ = install_actionlint("Darwin")
49
+ assert result is True
50
+
51
+
52
+ def test_failed_install_actionlint_darwin(monkeypatch):
53
+ def mock_run(*args, **kwargs):
54
+ raise subprocess.CalledProcessError(1, "cmd")
55
+
56
+ monkeypatch.setattr(subprocess, "run", mock_run)
57
+ result, error = install_actionlint("Darwin")
58
+ assert result is False
59
+ assert "An error occurred" in error
60
+
61
+
62
+ def test_install_actionlint_windows(monkeypatch):
63
+ def mock_run(*args, **kwargs):
64
+ return subprocess.CompletedProcess(args, 0)
65
+
66
+ monkeypatch.setattr(subprocess, "run", mock_run)
67
+ result, _ = install_actionlint("Windows")
68
+ assert result is True
69
+
70
+
71
+ def test_failed_install_actionlint_windows(monkeypatch):
72
+ def mock_run(*args, **kwargs):
73
+ raise subprocess.CalledProcessError(1, "cmd")
74
+
75
+ monkeypatch.setattr(subprocess, "run", mock_run)
76
+ result, error = install_actionlint("Windows")
77
+ assert result is False
78
+ assert "An error occurred" in error
79
+
80
+
81
+ def test_install_actionlint_source(monkeypatch):
82
+ def mock_run(*args, **kwargs):
83
+ return subprocess.CompletedProcess(args, 0)
84
+
85
+ monkeypatch.setattr(subprocess, "run", mock_run)
86
+
87
+ result, _ = install_actionlint_source("An error occurred")
88
+ assert result is True
89
+
90
+
91
+ def test_failed_install_actionlint_source(monkeypatch):
92
+ def mock_run(*args, **kwargs):
93
+ raise subprocess.CalledProcessError(1, "cmd")
94
+
95
+ monkeypatch.setattr(subprocess, "run", mock_run)
96
+
97
+ result, error = install_actionlint_source("An error occurred")
98
+ assert result is False
99
+ assert "An error occurred" in error
100
+
101
+
102
+ def test_check_actionlint_installed(monkeypatch):
103
+ def mock_run(*args, **kwargs):
104
+ return subprocess.CompletedProcess(args, 0)
105
+
106
+ monkeypatch.setattr(subprocess, "run", mock_run)
107
+
108
+ result, _ = check_actionlint("Linux")
109
+ assert result is True
110
+
111
+
112
+ def test_failed_check_actionlint_installed(monkeypatch):
113
+ def mock_run(*args, **kwargs):
114
+ raise subprocess.CalledProcessError(1, "cmd")
115
+
116
+ monkeypatch.setattr(subprocess, "run", mock_run)
117
+
118
+ result, _ = check_actionlint("Linux")
119
+ assert result is False
120
+
121
+
122
+ def test_check_actionlint_not_installed(monkeypatch):
123
+ def mock_run(*args, **kwargs):
124
+ raise FileNotFoundError
125
+
126
+ monkeypatch.setattr(subprocess, "run", mock_run)
127
+
128
+ result, _ = check_actionlint("Linux")
129
+ assert result is False
130
+
131
+
132
+ def test_run_actionlint_installed(monkeypatch, rule):
133
+ def mock_check_actionlint(*args, **kwargs):
134
+ return True, "/mock/location"
135
+
136
+ def mock_run(*args, **kwargs):
137
+ return subprocess.CompletedProcess(args, 0, stdout="")
138
+
139
+ monkeypatch.setattr(subprocess, "run", mock_run)
140
+ monkeypatch.setattr(
141
+ "src.bitwarden_workflow_linter.rules.run_actionlint.check_actionlint",
142
+ mock_check_actionlint,
143
+ )
144
+
145
+ workflow = WorkflowBuilder.build("tests/fixtures/test_workflow.yaml")
146
+ result, _ = rule.fn(workflow)
147
+ assert result is True
148
+
149
+
150
+ def test_run_actionlint_not_installed(monkeypatch, rule):
151
+ def mock_check_actionlint(*args, **kwargs):
152
+ return False, ""
153
+
154
+ monkeypatch.setattr(
155
+ "src.bitwarden_workflow_linter.rules.run_actionlint.check_actionlint",
156
+ mock_check_actionlint,
157
+ )
158
+
159
+ workflow = WorkflowBuilder.build("tests/fixtures/test_workflow.yaml")
160
+ result, error = rule.fn(workflow)
161
+ assert result is False
162
+ assert "Actionlint must pass" in error
163
+
164
+
165
+ def test_run_actionlint_installed_error(monkeypatch, rule):
166
+ def mock_check_actionlint(*args, **kwargs):
167
+ return True, "/mock/location"
168
+
169
+ def mock_run(*args, **kwargs):
170
+ return subprocess.CompletedProcess(args, 110, stdout="An error occurred")
171
+
172
+ monkeypatch.setattr(subprocess, "run", mock_run)
173
+ monkeypatch.setattr(
174
+ "src.bitwarden_workflow_linter.rules.run_actionlint.check_actionlint",
175
+ mock_check_actionlint,
176
+ )
177
+
178
+ workflow = WorkflowBuilder.build("tests/fixtures/test_workflow.yaml")
179
+ result, error = rule.fn(workflow)
180
+ assert result is False
181
+ assert "An error occurred" in error
@@ -72,7 +72,7 @@ jobs:
72
72
 
73
73
 
74
74
  def test_simple_workflow(simple_workflow_yaml):
75
- workflow = Workflow.init("", simple_workflow_yaml)
75
+ workflow = Workflow.init("", None, simple_workflow_yaml)
76
76
 
77
77
  assert workflow.name == "test"
78
78
  assert len(workflow.on.keys()) == 1
@@ -80,7 +80,7 @@ def test_simple_workflow(simple_workflow_yaml):
80
80
 
81
81
 
82
82
  def test_complex_workflow(complex_workflow_yaml):
83
- workflow = Workflow.init("", complex_workflow_yaml)
83
+ workflow = Workflow.init("", None, complex_workflow_yaml)
84
84
 
85
85
  assert workflow.name == "test"
86
86
  assert len(workflow.on.keys()) == 2
@@ -91,7 +91,7 @@ def test_workflow_extra_kwargs(simple_workflow_yaml):
91
91
  extra_data_workflow = simple_workflow_yaml
92
92
  extra_data_workflow["extra"] = "This should not exist"
93
93
 
94
- workflow = Workflow.init("", extra_data_workflow)
94
+ workflow = Workflow.init("", None, extra_data_workflow)
95
95
 
96
96
  with pytest.raises(Exception):
97
97
  assert workflow.extra == "test"