bitwarden_workflow_linter 0.14.4__tar.gz → 0.15.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 (94) hide show
  1. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/bwwl_operations.yml +1 -1
  2. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/PKG-INFO +1 -1
  3. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/__about__.py +1 -1
  4. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/default_actions.json +5 -0
  5. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/models/job.py +2 -0
  6. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/rules/permissions_exist.py +11 -4
  7. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/rules/test_permissions_exist.py +54 -0
  8. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.editorconfig +0 -0
  9. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.gitattributes +0 -0
  10. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/CODEOWNERS +0 -0
  11. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  12. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  13. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/renovate.json +0 -0
  14. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/_version_type.yml +0 -0
  15. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/actionlint_windows.yml +0 -0
  16. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/cd.yml +0 -0
  17. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/ci.yml +0 -0
  18. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/enforce-labels.yml +0 -0
  19. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/examples/ci.yaml +0 -0
  20. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/examples/example-references/_build.yml +0 -0
  21. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/examples/example-references/_docker.yml +0 -0
  22. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/examples/example-references/_test.yml +0 -0
  23. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/examples/example-references/_version.yml +0 -0
  24. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/examples/example.yaml +0 -0
  25. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/examples/pull_request_target.yml +0 -0
  26. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/examples/scan.yaml +0 -0
  27. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.github/workflows/scan.yml +0 -0
  28. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.gitignore +0 -0
  29. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.husky/pre-commit +0 -0
  30. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/.python-version +0 -0
  31. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/CONTRIBUTING.md +0 -0
  32. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/LICENSE.txt +0 -0
  33. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/Pipfile +0 -0
  34. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/Pipfile.lock +0 -0
  35. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/README.md +0 -0
  36. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/RULE_ROLLOUT.md +0 -0
  37. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/SECURITY.md +0 -0
  38. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/Taskfile.yml +0 -0
  39. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/actionlint_version.json +0 -0
  40. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/package-lock.json +0 -0
  41. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/package.json +0 -0
  42. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/pylintrc +0 -0
  43. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/pyproject.toml +0 -0
  44. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/pyproject.toml.tpl +0 -0
  45. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/settings.yaml +0 -0
  46. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/__init__.py +0 -0
  47. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/actionlint_version.yaml +0 -0
  48. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/actions.py +0 -0
  49. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/cli.py +0 -0
  50. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/default_settings.yaml +0 -0
  51. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/lint.py +0 -0
  52. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/load.py +0 -0
  53. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/models/__init__.py +0 -0
  54. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/models/step.py +0 -0
  55. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/models/workflow.py +0 -0
  56. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/rule.py +0 -0
  57. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/rules/__init__.py +0 -0
  58. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/rules/check_pr_target.py +0 -0
  59. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/rules/job_environment_prefix.py +0 -0
  60. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/rules/name_capitalized.py +0 -0
  61. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/rules/name_exists.py +0 -0
  62. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/rules/pinned_job_runner.py +0 -0
  63. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/rules/run_actionlint.py +0 -0
  64. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/rules/step_approved.py +0 -0
  65. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/rules/step_pinned.py +0 -0
  66. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/rules/underscore_outputs.py +0 -0
  67. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/src/bitwarden_workflow_linter/utils.py +0 -0
  68. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/__init__.py +0 -0
  69. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/conftest.py +0 -0
  70. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/fixtures/test-alt.yml +0 -0
  71. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/fixtures/test-min-incorrect.yaml +0 -0
  72. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/fixtures/test-min.yaml +0 -0
  73. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/fixtures/test-outputs-incorrect.yml +0 -0
  74. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/fixtures/test.yml +0 -0
  75. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/fixtures/test_a.yaml +0 -0
  76. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/fixtures/test_workflow.yaml +0 -0
  77. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/fixtures/test_workflow_incorrect.yaml +0 -0
  78. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/rules/__init__.py +0 -0
  79. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/rules/test_check_pr_target.py +0 -0
  80. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/rules/test_job_environment_prefix.py +0 -0
  81. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/rules/test_name_capitalized.py +0 -0
  82. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/rules/test_name_exists.py +0 -0
  83. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/rules/test_pinned_job_runner.py +0 -0
  84. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/rules/test_run_actionlint.py +0 -0
  85. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/rules/test_step_approved.py +0 -0
  86. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/rules/test_step_pinned.py +0 -0
  87. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/rules/test_underscore_output.py +0 -0
  88. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/test_job.py +0 -0
  89. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/test_lint.py +0 -0
  90. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/test_load.py +0 -0
  91. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/test_rule.py +0 -0
  92. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/test_step.py +0 -0
  93. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/test_utils.py +0 -0
  94. {bitwarden_workflow_linter-0.14.4 → bitwarden_workflow_linter-0.15.0}/tests/test_workflow.py +0 -0
@@ -57,7 +57,7 @@ jobs:
57
57
  - name: Set up Python 3.12
58
58
  uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
59
59
  with:
60
- python-version: "3.13"
60
+ python-version: "3.12"
61
61
 
62
62
  - name: Install bwwl binary
63
63
  run: python -m pip install --upgrade bitwarden_workflow_linter
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bitwarden_workflow_linter
3
- Version: 0.14.4
3
+ Version: 0.15.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
@@ -1,3 +1,3 @@
1
1
  """Metadata for Workflow Linter."""
2
2
 
3
- __version__ = "0.14.4"
3
+ __version__ = "0.15.0"
@@ -209,6 +209,11 @@
209
209
  "sha": "a9ffb7d5ac46eca1bb1f06656bf888b39462f161",
210
210
  "version": "v2.4.0"
211
211
  },
212
+ "databricks/setup-cli": {
213
+ "name": "databricks/setup-cli",
214
+ "sha": "e36d8a56a09740e5a9e4ed5aeaf6fc3a2eb2e148",
215
+ "version": "v0.252.0"
216
+ },
212
217
  "dawidd6/action-download-artifact": {
213
218
  "name": "dawidd6/action-download-artifact",
214
219
  "sha": "80620a5d27ce0ae443b965134db88467fc607b43",
@@ -32,6 +32,7 @@ class Job:
32
32
  metadata=config(field_name="with"), default=None
33
33
  )
34
34
  outputs: Optional[CommentedMap] = None
35
+ permissions: Optional[object] = None # This can be a CommentedMap or a string
35
36
 
36
37
  @classmethod
37
38
  def parse_needs(cls: Self, value):
@@ -50,6 +51,7 @@ class Job:
50
51
  "env": data["env"] if "env" in data else None,
51
52
  "needs": Job.parse_needs(data["needs"]) if "needs" in data else None,
52
53
  "outputs": data["outputs"] if "outputs" in data else None,
54
+ "permissions": data["permissions"] if "permissions" in data else None,
53
55
  }
54
56
 
55
57
  new_job = cls.from_dict(init_data)
@@ -3,6 +3,7 @@
3
3
  from typing import Optional, Tuple
4
4
 
5
5
  from ..models.workflow import Workflow
6
+ from ..models.job import Job
6
7
  from ..rule import Rule
7
8
  from ..utils import LintLevels, Settings
8
9
 
@@ -26,18 +27,24 @@ class RulePermissionsExist(Rule):
26
27
  lint_level: Optional[LintLevels] = LintLevels.NONE,
27
28
  ) -> None:
28
29
  self.message = (
29
- "A top-level permissions section must be configured in the workflow."
30
+ "All workflows must specify permissions on either workflow or job level"
30
31
  )
31
32
  self.on_fail = lint_level
32
33
  self.compatibility = [Workflow]
33
34
  self.settings = settings
34
35
 
35
- def permissions_exist(self, obj: Workflow) -> bool:
36
- if obj.permissions is None:
36
+ def permissions_exist_on_workflow(self, workflow: Workflow) -> bool:
37
+ if workflow.permissions is None:
37
38
  return False
38
39
  return True
39
40
 
41
+ def permissions_exist_on_jobs(self, jobs: list[Job]) -> bool:
42
+ for job in jobs:
43
+ if job.permissions is None:
44
+ return False
45
+ return True
46
+
40
47
  def fn(self, obj: Workflow) -> Tuple[bool, str]:
41
- if not self.permissions_exist(obj):
48
+ if not self.permissions_exist_on_workflow(obj) and not self.permissions_exist_on_jobs(obj.jobs.values()):
42
49
  return False, f"{self.message}"
43
50
  return True, ""
@@ -56,6 +56,25 @@ jobs:
56
56
  return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
57
57
 
58
58
 
59
+ @pytest.fixture(name="correct_workflow_scoped_permissions_on_job")
60
+ def fixture_correct_workflow_scoped_permissions_on_job():
61
+ workflow = """\
62
+ ---
63
+ on:
64
+ workflow_dispatch:
65
+
66
+ jobs:
67
+ job-key:
68
+ runs-on: ubuntu-latest
69
+ permissions:
70
+ contents: read
71
+ packages: read
72
+ steps:
73
+ - run: echo test
74
+ """
75
+ return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
76
+
77
+
59
78
  @pytest.fixture(name="incorrect_workflow_missing_permissions")
60
79
  def fixture_incorrect_workflow_missing_permissions():
61
80
  workflow = """\
@@ -72,6 +91,28 @@ jobs:
72
91
  return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
73
92
 
74
93
 
94
+ @pytest.fixture(name="incorrect_workflow_missing_permissions_partial")
95
+ def fixture_incorrect_workflow_missing_permissions_partial():
96
+ workflow = """\
97
+ ---
98
+ on:
99
+ workflow_dispatch:
100
+
101
+ jobs:
102
+ job-key:
103
+ runs-on: ubuntu-latest
104
+ steps:
105
+ - run: echo test
106
+
107
+ job-key2:
108
+ runs-on: ubuntu-latest
109
+ permissions: read-all
110
+ steps:
111
+ - run: echo test2
112
+ """
113
+ return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
114
+
115
+
75
116
  @pytest.fixture(name="rule")
76
117
  def fixture_rule():
77
118
  return RulePermissionsExist()
@@ -89,8 +130,21 @@ def test_rule_on_correct_workflow_scoped_permissions(
89
130
  assert result is True
90
131
 
91
132
 
133
+ def test_rule_on_correct_workflow_scoped_permissions_on_job(
134
+ rule, correct_workflow_scoped_permissions_on_job
135
+ ):
136
+ result, _ = rule.fn(correct_workflow_scoped_permissions_on_job)
137
+ assert result is True
138
+
139
+
92
140
  def test_rule_on_incorrect_workflow_missing_permissions(
93
141
  rule, incorrect_workflow_missing_permissions
94
142
  ):
95
143
  result, _ = rule.fn(incorrect_workflow_missing_permissions)
96
144
  assert result is False
145
+
146
+ def test_rule_on_incorrect_workflow_missing_permissions_partial(
147
+ rule, incorrect_workflow_missing_permissions_partial
148
+ ):
149
+ result, _ = rule.fn(incorrect_workflow_missing_permissions_partial)
150
+ assert result is False