bitwarden_workflow_linter 0.8.1__tar.gz → 0.9.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 (93) hide show
  1. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/workflows/ci.yml +14 -0
  2. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/PKG-INFO +19 -16
  3. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/README.md +18 -15
  4. bitwarden_workflow_linter-0.9.0/settings.yaml +24 -0
  5. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/__about__.py +1 -1
  6. bitwarden_workflow_linter-0.9.0/src/bitwarden_workflow_linter/default_settings.yaml +24 -0
  7. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/lint.py +23 -4
  8. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/models/workflow.py +2 -0
  9. bitwarden_workflow_linter-0.9.0/src/bitwarden_workflow_linter/rules/permissions_exist.py +43 -0
  10. bitwarden_workflow_linter-0.9.0/tests/rules/test_permissions_exist.py +96 -0
  11. bitwarden_workflow_linter-0.8.1/.github/workflows/lint-examples.yml +0 -37
  12. bitwarden_workflow_linter-0.8.1/settings.yaml +0 -21
  13. bitwarden_workflow_linter-0.8.1/src/bitwarden_workflow_linter/default_settings.yaml +0 -21
  14. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.editorconfig +0 -0
  15. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.gitattributes +0 -0
  16. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/CODEOWNERS +0 -0
  17. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  18. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  19. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/renovate.json +0 -0
  20. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/workflows/_version_type.yml +0 -0
  21. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/workflows/bwwl_operations.yml +0 -0
  22. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/workflows/cd.yml +0 -0
  23. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/workflows/enforce-labels.yml +0 -0
  24. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/workflows/examples/ci.yaml +0 -0
  25. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/workflows/examples/example-references/_build.yml +0 -0
  26. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/workflows/examples/example-references/_docker.yml +0 -0
  27. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/workflows/examples/example-references/_test.yml +0 -0
  28. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/workflows/examples/example-references/_version.yml +0 -0
  29. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/workflows/examples/example.yaml +0 -0
  30. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/workflows/examples/scan.yaml +0 -0
  31. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.github/workflows/scan.yml +0 -0
  32. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.gitignore +0 -0
  33. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.husky/pre-commit +0 -0
  34. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/.python-version +0 -0
  35. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/CONTRIBUTING.md +0 -0
  36. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/LICENSE.txt +0 -0
  37. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/Pipfile +0 -0
  38. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/Pipfile.lock +0 -0
  39. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/RULE_ROLLOUT.md +0 -0
  40. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/SECURITY.md +0 -0
  41. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/Taskfile.yml +0 -0
  42. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/package-lock.json +0 -0
  43. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/package.json +0 -0
  44. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/pylintrc +0 -0
  45. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/pyproject.toml +0 -0
  46. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/pyproject.toml.tpl +0 -0
  47. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/__init__.py +0 -0
  48. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/actions.py +0 -0
  49. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/cli.py +0 -0
  50. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/default_actions.json +0 -0
  51. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/load.py +0 -0
  52. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/models/__init__.py +0 -0
  53. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/models/job.py +0 -0
  54. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/models/step.py +0 -0
  55. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/rule.py +0 -0
  56. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/rules/__init__.py +0 -0
  57. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/rules/check_pr_target.py +0 -0
  58. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/rules/job_environment_prefix.py +0 -0
  59. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/rules/name_capitalized.py +0 -0
  60. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/rules/name_exists.py +0 -0
  61. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/rules/pinned_job_runner.py +0 -0
  62. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/rules/run_actionlint.py +0 -0
  63. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/rules/step_approved.py +0 -0
  64. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/rules/step_pinned.py +0 -0
  65. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/rules/underscore_outputs.py +0 -0
  66. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/src/bitwarden_workflow_linter/utils.py +0 -0
  67. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/__init__.py +0 -0
  68. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/conftest.py +0 -0
  69. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/fixtures/test-alt.yml +0 -0
  70. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/fixtures/test-min-incorrect.yaml +0 -0
  71. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/fixtures/test-min.yaml +0 -0
  72. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/fixtures/test-outputs-incorrect.yml +0 -0
  73. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/fixtures/test.yml +0 -0
  74. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/fixtures/test_a.yaml +0 -0
  75. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/fixtures/test_workflow.yaml +0 -0
  76. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/fixtures/test_workflow_incorrect.yaml +0 -0
  77. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/rules/__init__.py +0 -0
  78. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/rules/test_check_pr_target.py +0 -0
  79. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/rules/test_job_environment_prefix.py +0 -0
  80. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/rules/test_name_capitalized.py +0 -0
  81. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/rules/test_name_exists.py +0 -0
  82. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/rules/test_pinned_job_runner.py +0 -0
  83. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/rules/test_run_actionlint.py +0 -0
  84. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/rules/test_step_approved.py +0 -0
  85. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/rules/test_step_pinned.py +0 -0
  86. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/rules/test_underscore_output.py +0 -0
  87. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/test_job.py +0 -0
  88. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/test_lint.py +0 -0
  89. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/test_load.py +0 -0
  90. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/test_rule.py +0 -0
  91. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/test_step.py +0 -0
  92. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/test_utils.py +0 -0
  93. {bitwarden_workflow_linter-0.8.1 → bitwarden_workflow_linter-0.9.0}/tests/test_workflow.py +0 -0
@@ -7,6 +7,8 @@ on:
7
7
  - "tests/**"
8
8
  workflow_dispatch:
9
9
 
10
+ permissions: read-all
11
+
10
12
  jobs:
11
13
  test:
12
14
  name: CI workflow-linter (v2)
@@ -31,3 +33,15 @@ jobs:
31
33
 
32
34
  - name: Check type hinting
33
35
  run: pipenv run pytype src
36
+
37
+ - name: Test against example workflows
38
+ # run notes:
39
+ # - Changing directories will help catch any repo specific paths in the linter
40
+ # that would not work in a different repository
41
+ # - Changing directories utilizes the default_settings.yaml rather than this repos
42
+ # settings.yaml, which better simulates running from another repository
43
+ # - Using strict to ensure that our examples pass all checks including warnings
44
+ run: |
45
+ pipenv run pip install -e .
46
+ cd .github/workflows
47
+ pipenv run bwwl lint --strict -f ./examples
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bitwarden_workflow_linter
3
- Version: 0.8.1
3
+ Version: 0.9.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
@@ -60,20 +60,20 @@ the below and create a `settings.yaml` in the directory that `bwwl` will be runn
60
60
 
61
61
  ```yaml
62
62
  enabled_rules:
63
- - id: bitwarden_workflow_linter.rules.name_exists.RuleNameExists
64
- level: error
65
- - id: bitwarden_workflow_linter.rules.name_capitalized.RuleNameCapitalized
66
- level: error
67
- - id: bitwarden_workflow_linter.rules.pinned_job_runner.RuleJobRunnerVersionPinned
68
- level: error
69
- - id: bitwarden_workflow_linter.rules.job_environment_prefix.RuleJobEnvironmentPrefix
70
- level: error
71
- - id: bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
72
- level: error
73
- - id: bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
74
- level: warning
75
- - id: bitwarden_workflow_linter.rules.run_actionlint.RunActionlint
76
- level: warning
63
+ - id: bitwarden_workflow_linter.rules.name_exists.RuleNameExists
64
+ level: error
65
+ - id: bitwarden_workflow_linter.rules.name_capitalized.RuleNameCapitalized
66
+ level: error
67
+ - id: bitwarden_workflow_linter.rules.pinned_job_runner.RuleJobRunnerVersionPinned
68
+ level: error
69
+ - id: bitwarden_workflow_linter.rules.job_environment_prefix.RuleJobEnvironmentPrefix
70
+ level: error
71
+ - id: bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
72
+ level: error
73
+ - id: bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
74
+ level: warning
75
+ - id: bitwarden_workflow_linter.rules.run_actionlint.RunActionlint
76
+ level: warning
77
77
 
78
78
  approved_actions_path: default_actions.json
79
79
  ```
@@ -187,7 +187,10 @@ By default, a new Rule needs five things:
187
187
  not support Rules that check against multiple objects at a time OR file level formatting (one empty between each step or
188
188
  two empty lines between each job)
189
189
 
190
- To activate a rule after implementing it, add it to `settings.yaml` in the project's base folder
190
+ _IMPORTANT: A rule must be implemented and tested then merged into `main` before it can be activated.<br>_
191
+ This is because the released version of bwwl will use the current `settings.yaml` file, but it will not have the new rule functionality yet and cause an error in the workflow linting of this repository.
192
+
193
+ To activate a rule after implementing and releasing it, add it to `settings.yaml` in the project's base folder
191
194
  and `src/bitwarden_workflow_linter/default_settings.yaml` to make the rule default
192
195
 
193
196
  Before creating a new rule please read the [Workflow linter rule rollout process](./RULE_ROLLOUT.md) document in which you'll find the process for rolling out new workflow linter rules.
@@ -34,20 +34,20 @@ the below and create a `settings.yaml` in the directory that `bwwl` will be runn
34
34
 
35
35
  ```yaml
36
36
  enabled_rules:
37
- - id: bitwarden_workflow_linter.rules.name_exists.RuleNameExists
38
- level: error
39
- - id: bitwarden_workflow_linter.rules.name_capitalized.RuleNameCapitalized
40
- level: error
41
- - id: bitwarden_workflow_linter.rules.pinned_job_runner.RuleJobRunnerVersionPinned
42
- level: error
43
- - id: bitwarden_workflow_linter.rules.job_environment_prefix.RuleJobEnvironmentPrefix
44
- level: error
45
- - id: bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
46
- level: error
47
- - id: bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
48
- level: warning
49
- - id: bitwarden_workflow_linter.rules.run_actionlint.RunActionlint
50
- level: warning
37
+ - id: bitwarden_workflow_linter.rules.name_exists.RuleNameExists
38
+ level: error
39
+ - id: bitwarden_workflow_linter.rules.name_capitalized.RuleNameCapitalized
40
+ level: error
41
+ - id: bitwarden_workflow_linter.rules.pinned_job_runner.RuleJobRunnerVersionPinned
42
+ level: error
43
+ - id: bitwarden_workflow_linter.rules.job_environment_prefix.RuleJobEnvironmentPrefix
44
+ level: error
45
+ - id: bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
46
+ level: error
47
+ - id: bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
48
+ level: warning
49
+ - id: bitwarden_workflow_linter.rules.run_actionlint.RunActionlint
50
+ level: warning
51
51
 
52
52
  approved_actions_path: default_actions.json
53
53
  ```
@@ -161,7 +161,10 @@ By default, a new Rule needs five things:
161
161
  not support Rules that check against multiple objects at a time OR file level formatting (one empty between each step or
162
162
  two empty lines between each job)
163
163
 
164
- To activate a rule after implementing it, add it to `settings.yaml` in the project's base folder
164
+ _IMPORTANT: A rule must be implemented and tested then merged into `main` before it can be activated.<br>_
165
+ This is because the released version of bwwl will use the current `settings.yaml` file, but it will not have the new rule functionality yet and cause an error in the workflow linting of this repository.
166
+
167
+ To activate a rule after implementing and releasing it, add it to `settings.yaml` in the project's base folder
165
168
  and `src/bitwarden_workflow_linter/default_settings.yaml` to make the rule default
166
169
 
167
170
  Before creating a new rule please read the [Workflow linter rule rollout process](./RULE_ROLLOUT.md) document in which you'll find the process for rolling out new workflow linter rules.
@@ -0,0 +1,24 @@
1
+ enabled_rules:
2
+ - id: bitwarden_workflow_linter.rules.name_exists.RuleNameExists
3
+ level: error
4
+ - id: bitwarden_workflow_linter.rules.name_capitalized.RuleNameCapitalized
5
+ level: error
6
+ - id: bitwarden_workflow_linter.rules.pinned_job_runner.RuleJobRunnerVersionPinned
7
+ level: error
8
+ - id: bitwarden_workflow_linter.rules.job_environment_prefix.RuleJobEnvironmentPrefix
9
+ level: error
10
+ # - id: bitwarden_workflow_linter.rules.step_approved.RuleStepUsesApproved
11
+ # level: error
12
+ - id: bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
13
+ level: error
14
+ - id: bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
15
+ level: warning
16
+ - id: bitwarden_workflow_linter.rules.run_actionlint.RunActionlint
17
+ level: warning
18
+ - id: bitwarden_workflow_linter.rules.check_pr_target.RuleCheckPrTarget
19
+ level: warning
20
+ # Cannot add this in until the rule functionality is merged through to main
21
+ # - id: bitwarden_workflow_linter.rules.permissions_exist.RulePermissionsExist
22
+ # level: warning
23
+
24
+ approved_actions_path: default_actions.json
@@ -1,3 +1,3 @@
1
1
  """Metadata for Workflow Linter."""
2
2
 
3
- __version__ = "0.8.1"
3
+ __version__ = "0.9.0"
@@ -0,0 +1,24 @@
1
+ enabled_rules:
2
+ - id: bitwarden_workflow_linter.rules.name_exists.RuleNameExists
3
+ level: error
4
+ - id: bitwarden_workflow_linter.rules.name_capitalized.RuleNameCapitalized
5
+ level: error
6
+ - id: bitwarden_workflow_linter.rules.pinned_job_runner.RuleJobRunnerVersionPinned
7
+ level: error
8
+ - id: bitwarden_workflow_linter.rules.job_environment_prefix.RuleJobEnvironmentPrefix
9
+ level: error
10
+ # - id: bitwarden_workflow_linter.rules.step_approved.RuleStepUsesApproved
11
+ # level: error
12
+ - id: bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
13
+ level: error
14
+ - id: bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
15
+ level: warning
16
+ - id: bitwarden_workflow_linter.rules.run_actionlint.RunActionlint
17
+ level: warning
18
+ - id: bitwarden_workflow_linter.rules.check_pr_target.RuleCheckPrTarget
19
+ level: warning
20
+ # Cannot add this in until the rule functionality is merged through to main
21
+ # - id: bitwarden_workflow_linter.rules.permissions_exist.RulePermissionsExist
22
+ # level: warning
23
+
24
+ approved_actions_path: default_actions.json
@@ -4,7 +4,6 @@ Workflows."""
4
4
  import argparse
5
5
  import os
6
6
 
7
- from functools import reduce
8
7
  from typing import Optional
9
8
 
10
9
  from .load import WorkflowBuilder, Rules
@@ -115,6 +114,7 @@ class LinterCmd:
115
114
  if len(findings) > 0:
116
115
  for finding in findings:
117
116
  print(f" - {finding}")
117
+ print(f"Issues found by {len(findings)} rules in {filename}")
118
118
  print()
119
119
 
120
120
  max_error_level = self.get_max_error_level(findings)
@@ -162,9 +162,28 @@ class LinterCmd:
162
162
  files = self.generate_files(input_files)
163
163
 
164
164
  if len(input_files) > 0:
165
- return_code = reduce(
166
- lambda a, b: a if a > b else b, map(self.lint_file, files)
167
- )
165
+ files_with_issues = []
166
+ return_code = 0
167
+ for file in files:
168
+ return_value = self.lint_file(file)
169
+ if return_value > 0:
170
+ files_with_issues.append(file)
171
+ return_code = max(return_code, return_value)
172
+
173
+ if len(files_with_issues) > 0:
174
+ newline = "\n" # For compatibility with Python 3.11
175
+ print(
176
+ f"""Found {len(files_with_issues)} file(s) with issues:
177
+ {f"{newline} ".join(files_with_issues)}
178
+
179
+ For help, refer to
180
+ - Workflow Syntax: \
181
+ https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions
182
+ - Bitwarden Examples: \
183
+ https://github.com/bitwarden/workflow-linter/tree/main/.github/workflows/examples")"""
184
+ )
185
+ else:
186
+ print("No issues found")
168
187
 
169
188
  if return_code == 1 and not strict:
170
189
  return_code = 0
@@ -27,6 +27,7 @@ class Workflow:
27
27
  name: Optional[str] = None
28
28
  on: Optional[CommentedMap] = None
29
29
  jobs: Optional[Dict[str, Job]] = None
30
+ permissions: Optional[object] = None # This can be a CommentedMap or a string
30
31
 
31
32
  @classmethod
32
33
  def init(cls: Self, key: str, filename: str, data: CommentedMap) -> Self:
@@ -35,6 +36,7 @@ class Workflow:
35
36
  "filename": filename,
36
37
  "name": data["name"] if "name" in data else None,
37
38
  "on": data["on"] if "on" in data else None,
39
+ "permissions": data["permissions"] if "permissions" in data else None,
38
40
  }
39
41
 
40
42
  new_workflow = cls.from_dict(init_data)
@@ -0,0 +1,43 @@
1
+ """A Rule to enforce that the required permissions are specified on every workflow"""
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 RulePermissionsExist(Rule):
11
+ """
12
+ Rule to enforce that the required permissions are specified on every workflow.
13
+
14
+ To allow for keeping repository default GITHUB_TOKEN permissions to a minimum,
15
+ each workflow must specify the permissions block (including read).
16
+
17
+ This has 2 benefits:
18
+ 1) When changing the default repository setting to a more restrictive one,
19
+ the workflows will not be affected.
20
+ 2) It is clear to the user what permissions are required for the workflow to run.
21
+ """
22
+
23
+ def __init__(
24
+ self,
25
+ settings: Optional[Settings] = None,
26
+ lint_level: Optional[LintLevels] = LintLevels.NONE,
27
+ ) -> None:
28
+ self.message = (
29
+ "A top-level permissions section must be configured in the workflow."
30
+ )
31
+ self.on_fail = lint_level
32
+ self.compatibility = [Workflow]
33
+ self.settings = settings
34
+
35
+ def permissions_exist(self, obj: Workflow) -> bool:
36
+ if obj.permissions is None:
37
+ return False
38
+ return True
39
+
40
+ def fn(self, obj: Workflow) -> Tuple[bool, str]:
41
+ if not self.permissions_exist(obj):
42
+ return False, f"{self.message}"
43
+ return True, ""
@@ -0,0 +1,96 @@
1
+ """Test src/bitwarden_workflow_linter/rules/permissions_exist.py."""
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.permissions_exist import RulePermissionsExist
9
+
10
+
11
+ yaml = YAML()
12
+
13
+
14
+ @pytest.fixture(name="correct_workflow_read_all")
15
+ def fixture_correct_workflow_read_all():
16
+ workflow = """\
17
+ ---
18
+ name: Test Workflow
19
+
20
+ on:
21
+ workflow_dispatch:
22
+
23
+ permissions: read-all
24
+
25
+ jobs:
26
+ job-key:
27
+ name: Test
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - name: Test
31
+ run: echo test
32
+ """
33
+ return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
34
+
35
+
36
+ @pytest.fixture(name="correct_workflow_scoped_permissions")
37
+ def fixture_correct_workflow_scoped_permissions():
38
+ workflow = """\
39
+ ---
40
+ on:
41
+ workflow_dispatch:
42
+
43
+ permissions:
44
+ checks: write
45
+ contents: read
46
+ id-token: write
47
+ pull-requests: write
48
+
49
+
50
+ jobs:
51
+ job-key:
52
+ runs-on: ubuntu-latest
53
+ steps:
54
+ - run: echo test
55
+ """
56
+ return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
57
+
58
+
59
+ @pytest.fixture(name="incorrect_workflow_missing_permissions")
60
+ def fixture_incorrect_workflow_missing_permissions():
61
+ workflow = """\
62
+ ---
63
+ on:
64
+ workflow_dispatch:
65
+
66
+ jobs:
67
+ job-key:
68
+ runs-on: ubuntu-latest
69
+ steps:
70
+ - run: echo test
71
+ """
72
+ return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
73
+
74
+
75
+ @pytest.fixture(name="rule")
76
+ def fixture_rule():
77
+ return RulePermissionsExist()
78
+
79
+
80
+ def test_rule_on_correct_workflow_read_all(rule, correct_workflow_read_all):
81
+ result, _ = rule.fn(correct_workflow_read_all)
82
+ assert result is True
83
+
84
+
85
+ def test_rule_on_correct_workflow_scoped_permissions(
86
+ rule, correct_workflow_scoped_permissions
87
+ ):
88
+ result, _ = rule.fn(correct_workflow_scoped_permissions)
89
+ assert result is True
90
+
91
+
92
+ def test_rule_on_incorrect_workflow_missing_permissions(
93
+ rule, incorrect_workflow_missing_permissions
94
+ ):
95
+ result, _ = rule.fn(incorrect_workflow_missing_permissions)
96
+ assert result is False
@@ -1,37 +0,0 @@
1
- name: Lint Example Workflows
2
-
3
- on:
4
- pull_request:
5
- branches:
6
- - "main"
7
- merge_group:
8
- types: [checks_requested]
9
- workflow_call:
10
- workflow_dispatch:
11
-
12
- jobs:
13
- test-lint-workflow:
14
- name: Test Lint Workflow
15
- runs-on: ubuntu-24.04
16
- steps:
17
- - name: Checkout Branch
18
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
19
-
20
- - name: Get workflow list
21
- id: workflow-list
22
- run: |
23
- WORKFLOW_LIST=$(find .github/workflows/examples -maxdepth 1 -type f | xargs -I {} echo -n "{} ")
24
- echo "workflow-list=$WORKFLOW_LIST" >> $GITHUB_OUTPUT
25
-
26
- - name: Lint examples
27
- id: lint-examples
28
- uses: bitwarden/gh-actions/lint-workflow@main
29
- with:
30
- workflows: ${{ steps.workflow-list.outputs.workflow-list }}
31
-
32
- - name: Failure message
33
- if: ${{ failure() && steps.lint-examples.conclusion == 'failure' }}
34
- run: |
35
- echo "Changes to the workflow linter should include updating workflow \
36
- examples in .github/workflows/examples directory"
37
- exit 1
@@ -1,21 +0,0 @@
1
- enabled_rules:
2
- - id: bitwarden_workflow_linter.rules.name_exists.RuleNameExists
3
- level: error
4
- - id: bitwarden_workflow_linter.rules.name_capitalized.RuleNameCapitalized
5
- level: error
6
- - id: bitwarden_workflow_linter.rules.pinned_job_runner.RuleJobRunnerVersionPinned
7
- level: error
8
- - id: bitwarden_workflow_linter.rules.job_environment_prefix.RuleJobEnvironmentPrefix
9
- level: error
10
- # - id: bitwarden_workflow_linter.rules.step_approved.RuleStepUsesApproved
11
- # level: error
12
- - id: bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
13
- level: error
14
- - id: bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
15
- level: warning
16
- - id: bitwarden_workflow_linter.rules.run_actionlint.RunActionlint
17
- level: warning
18
- - id: bitwarden_workflow_linter.rules.check_pr_target.RuleCheckPrTarget
19
- level: warning
20
-
21
- approved_actions_path: default_actions.json
@@ -1,21 +0,0 @@
1
- enabled_rules:
2
- - id: bitwarden_workflow_linter.rules.name_exists.RuleNameExists
3
- level: error
4
- - id: bitwarden_workflow_linter.rules.name_capitalized.RuleNameCapitalized
5
- level: error
6
- - id: bitwarden_workflow_linter.rules.pinned_job_runner.RuleJobRunnerVersionPinned
7
- level: error
8
- - id: bitwarden_workflow_linter.rules.job_environment_prefix.RuleJobEnvironmentPrefix
9
- level: error
10
- # - id: bitwarden_workflow_linter.rules.step_approved.RuleStepUsesApproved
11
- # level: error
12
- - id: bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
13
- level: error
14
- - id: bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
15
- level: warning
16
- - id: bitwarden_workflow_linter.rules.run_actionlint.RunActionlint
17
- level: warning
18
- - id: bitwarden_workflow_linter.rules.check_pr_target.RuleCheckPrTarget
19
- level: warning
20
-
21
- approved_actions_path: default_actions.json