pyossmtool 0.0.1__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.
Files changed (119) hide show
  1. pyossmtool/__init__.py +3 -0
  2. pyossmtool/bundle/catalog/checks/bandit.scan.yaml +13 -0
  3. pyossmtool/bundle/catalog/checks/codespell.spelling.yaml +12 -0
  4. pyossmtool/bundle/catalog/checks/deadcode.scan.yaml +13 -0
  5. pyossmtool/bundle/catalog/checks/gate.acronym-allowlist.yaml +14 -0
  6. pyossmtool/bundle/catalog/checks/gate.folder-breadth.yaml +14 -0
  7. pyossmtool/bundle/catalog/checks/gate.module-private-vars.yaml +14 -0
  8. pyossmtool/bundle/catalog/checks/gate.module-size.yaml +14 -0
  9. pyossmtool/bundle/catalog/checks/gitleaks.secrets.yaml +21 -0
  10. pyossmtool/bundle/catalog/checks/hadolint.dockerfile.yaml +16 -0
  11. pyossmtool/bundle/catalog/checks/jscpd.duplication.yaml +19 -0
  12. pyossmtool/bundle/catalog/checks/markdownlint.check.yaml +17 -0
  13. pyossmtool/bundle/catalog/checks/mdformat.apply.yaml +10 -0
  14. pyossmtool/bundle/catalog/checks/mdformat.format.yaml +14 -0
  15. pyossmtool/bundle/catalog/checks/mutmut.run.yaml +13 -0
  16. pyossmtool/bundle/catalog/checks/pydeps.cycles.yaml +14 -0
  17. pyossmtool/bundle/catalog/checks/pytest.coverage.yaml +19 -0
  18. pyossmtool/bundle/catalog/checks/pytest.test.yaml +14 -0
  19. pyossmtool/bundle/catalog/checks/radon.cc.yaml +13 -0
  20. pyossmtool/bundle/catalog/checks/radon.mi.yaml +13 -0
  21. pyossmtool/bundle/catalog/checks/ruff.format.apply.yaml +11 -0
  22. pyossmtool/bundle/catalog/checks/ruff.format.yaml +14 -0
  23. pyossmtool/bundle/catalog/checks/ruff.lint.yaml +15 -0
  24. pyossmtool/bundle/catalog/checks/ruff.unused.yaml +17 -0
  25. pyossmtool/bundle/catalog/checks/semgrep.scan.yaml +18 -0
  26. pyossmtool/bundle/catalog/checks/shellcheck.yaml +13 -0
  27. pyossmtool/bundle/catalog/checks/shfmt.apply.yaml +11 -0
  28. pyossmtool/bundle/catalog/checks/shfmt.format.yaml +14 -0
  29. pyossmtool/bundle/catalog/checks/sourcery.review.yaml +14 -0
  30. pyossmtool/bundle/catalog/checks/ty.check.yaml +15 -0
  31. pyossmtool/bundle/catalog/checks/vulture.scan.yaml +16 -0
  32. pyossmtool/bundle/catalog/checks/yamlfmt.apply.yaml +10 -0
  33. pyossmtool/bundle/catalog/checks/yamlfmt.format.yaml +14 -0
  34. pyossmtool/bundle/catalog/checks/yamllint.check.yaml +16 -0
  35. pyossmtool/bundle/catalog/tools/bandit.yaml +20 -0
  36. pyossmtool/bundle/catalog/tools/codespell.yaml +17 -0
  37. pyossmtool/bundle/catalog/tools/deadcode.yaml +13 -0
  38. pyossmtool/bundle/catalog/tools/gitleaks.yaml +9 -0
  39. pyossmtool/bundle/catalog/tools/hadolint.yaml +11 -0
  40. pyossmtool/bundle/catalog/tools/jscpd.yaml +15 -0
  41. pyossmtool/bundle/catalog/tools/markdownlint.yaml +18 -0
  42. pyossmtool/bundle/catalog/tools/mdformat.yaml +13 -0
  43. pyossmtool/bundle/catalog/tools/mutmut.yaml +10 -0
  44. pyossmtool/bundle/catalog/tools/pydeps.yaml +10 -0
  45. pyossmtool/bundle/catalog/tools/pytest.yaml +12 -0
  46. pyossmtool/bundle/catalog/tools/radon.yaml +10 -0
  47. pyossmtool/bundle/catalog/tools/ruff.yaml +26 -0
  48. pyossmtool/bundle/catalog/tools/script.yaml +8 -0
  49. pyossmtool/bundle/catalog/tools/semgrep.yaml +21 -0
  50. pyossmtool/bundle/catalog/tools/shellcheck.yaml +10 -0
  51. pyossmtool/bundle/catalog/tools/shfmt.yaml +13 -0
  52. pyossmtool/bundle/catalog/tools/sourcery.yaml +10 -0
  53. pyossmtool/bundle/catalog/tools/ty.yaml +20 -0
  54. pyossmtool/bundle/catalog/tools/vulture.yaml +13 -0
  55. pyossmtool/bundle/catalog/tools/yamlfmt.yaml +24 -0
  56. pyossmtool/bundle/catalog/tools/yamllint.yaml +24 -0
  57. pyossmtool/bundle/defaults/allowlists/acronyms.yaml +10 -0
  58. pyossmtool/bundle/defaults/allowlists/folder-breadth.txt +1 -0
  59. pyossmtool/bundle/defaults/allowlists/module-private-vars.txt +1 -0
  60. pyossmtool/bundle/defaults/allowlists/module-size.txt +1 -0
  61. pyossmtool/bundle/defaults/configs/bandit.yaml +5 -0
  62. pyossmtool/bundle/defaults/configs/gates/acronym-allowlist.yaml +4 -0
  63. pyossmtool/bundle/defaults/configs/gates/folder-breadth.yaml +12 -0
  64. pyossmtool/bundle/defaults/configs/gates/module-private-vars.yaml +4 -0
  65. pyossmtool/bundle/defaults/configs/gates/module-size.yaml +6 -0
  66. pyossmtool/bundle/defaults/configs/markdownlint.json +8 -0
  67. pyossmtool/bundle/defaults/configs/ruff.toml +8 -0
  68. pyossmtool/bundle/defaults/configs/ty.toml +5 -0
  69. pyossmtool/bundle/defaults/configs/yamlfmt.yaml +4 -0
  70. pyossmtool/bundle/defaults/configs/yamllint.yaml +12 -0
  71. pyossmtool/bundle/defaults/gates/README.md +150 -0
  72. pyossmtool/bundle/defaults/gates/acronym-allowlist.sh +15 -0
  73. pyossmtool/bundle/defaults/gates/folder-breadth.sh +22 -0
  74. pyossmtool/bundle/defaults/gates/lib.sh +116 -0
  75. pyossmtool/bundle/defaults/gates/module-private-vars.sh +77 -0
  76. pyossmtool/bundle/defaults/gates/module-size.sh +60 -0
  77. pyossmtool/bundle/defaults/semgrep/python-quality.yml +19 -0
  78. pyossmtool/bundle/suites/demo.yaml +11 -0
  79. pyossmtool/bundle/suites/extended.yaml +34 -0
  80. pyossmtool/bundle/suites/format.yaml +10 -0
  81. pyossmtool/bundle/suites/formatting.yaml +10 -0
  82. pyossmtool/bundle/suites/policy.yaml +11 -0
  83. pyossmtool/bundle/suites/python-quality.yaml +9 -0
  84. pyossmtool/bundle/suites/reslab-parity.yaml +41 -0
  85. pyossmtool/bundle/suites/standard.yaml +45 -0
  86. pyossmtool/cli.py +233 -0
  87. pyossmtool/config_resolver.py +117 -0
  88. pyossmtool/discovery.py +50 -0
  89. pyossmtool/gate_config.py +119 -0
  90. pyossmtool/gates.py +102 -0
  91. pyossmtool/ignore.py +270 -0
  92. pyossmtool/ignore_materialize.py +184 -0
  93. pyossmtool/installer.py +119 -0
  94. pyossmtool/models.py +279 -0
  95. pyossmtool/parsers/__init__.py +76 -0
  96. pyossmtool/parsers/analysis.py +329 -0
  97. pyossmtool/parsers/base.py +29 -0
  98. pyossmtool/parsers/common.py +57 -0
  99. pyossmtool/parsers/format_text.py +67 -0
  100. pyossmtool/parsers/gates.py +92 -0
  101. pyossmtool/parsers/patterns.py +78 -0
  102. pyossmtool/parsers/prose.py +193 -0
  103. pyossmtool/parsers/ruff.py +103 -0
  104. pyossmtool/parsers/shell.py +83 -0
  105. pyossmtool/policy/__init__.py +0 -0
  106. pyossmtool/policy/acronym_allowlist.py +322 -0
  107. pyossmtool/policy/folder_breadth.py +306 -0
  108. pyossmtool/registry.py +72 -0
  109. pyossmtool/reporter.py +87 -0
  110. pyossmtool/resolver.py +146 -0
  111. pyossmtool/runner.py +482 -0
  112. pyossmtool/runner_script.py +131 -0
  113. pyossmtool/target_expand.py +112 -0
  114. pyossmtool-0.0.1.dist-info/METADATA +94 -0
  115. pyossmtool-0.0.1.dist-info/RECORD +119 -0
  116. pyossmtool-0.0.1.dist-info/WHEEL +5 -0
  117. pyossmtool-0.0.1.dist-info/entry_points.txt +2 -0
  118. pyossmtool-0.0.1.dist-info/licenses/LICENSE +21 -0
  119. pyossmtool-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,10 @@
1
+ id: pydeps
2
+ name: pydeps
3
+ description: Python module dependency analysis and cycle detection.
4
+ install:
5
+ method: pip
6
+ package: pydeps>=3.0
7
+ binary: pydeps
8
+ documentation_url: https://github.com/thebjorn/pydeps
9
+ files:
10
+ - '**/*.py'
@@ -0,0 +1,12 @@
1
+ id: pytest
2
+ name: pytest
3
+ description: Python test runner with optional coverage via pytest-cov plugin.
4
+ install:
5
+ method: pip
6
+ package: pytest>=8.0 pytest-cov>=6.0
7
+ binary: pytest
8
+ documentation_url: https://docs.pytest.org/
9
+ ignore:
10
+ kind: flag_pairs
11
+ flag: --ignore
12
+ files: []
@@ -0,0 +1,10 @@
1
+ id: radon
2
+ name: Radon
3
+ description: Code metrics for cyclomatic complexity and maintainability index.
4
+ install:
5
+ method: pip
6
+ package: radon>=6.0.0
7
+ binary: radon
8
+ documentation_url: https://radon.readthedocs.io/
9
+ files:
10
+ - '**/*.py'
@@ -0,0 +1,26 @@
1
+ id: ruff
2
+ name: Ruff
3
+ description: Fast Python linter and formatter.
4
+ install:
5
+ method: pip
6
+ package: ruff>=0.15.0
7
+ binary: ruff
8
+ documentation_url: https://docs.astral.sh/ruff/
9
+ config:
10
+ flag: --config
11
+ bundled: ruff.toml
12
+ repo_files:
13
+ - ruff.toml
14
+ pyproject:
15
+ - tool
16
+ - ruff
17
+ ignore:
18
+ kind: config_overlay
19
+ format: toml
20
+ file: ruff.toml
21
+ flag: --config
22
+ key: extend-exclude
23
+ extend_from: base_or_pyproject
24
+ extend_key: extend
25
+ files:
26
+ - '**/*.py'
@@ -0,0 +1,8 @@
1
+ id: script
2
+ name: Shell Script Gate
3
+ description: Project-local bash gate script (install skipped; uses system bash).
4
+ install:
5
+ method: skip
6
+ binary: bash
7
+ documentation_url: https://github.com/dayhatt/pyossmtool#script-gates
8
+ files: []
@@ -0,0 +1,21 @@
1
+ id: semgrep
2
+ name: Semgrep
3
+ description: Static analysis for security and code quality patterns.
4
+ install:
5
+ method: pip
6
+ package: semgrep>=1.79.0
7
+ binary: semgrep
8
+ documentation_url: https://semgrep.dev/
9
+ config:
10
+ flag: --config
11
+ bundled_path: defaults/semgrep/python-quality.yml
12
+ pass_flag: false
13
+ repo_dirs:
14
+ - .semgrep
15
+ - .tools/semgrep
16
+ ignore:
17
+ kind: flag_pairs
18
+ flag: --exclude
19
+ post_subcommand: true
20
+ files:
21
+ - '**/*.py'
@@ -0,0 +1,10 @@
1
+ id: shellcheck
2
+ name: ShellCheck
3
+ description: Static analysis for shell scripts.
4
+ install:
5
+ method: system
6
+ package: shellcheck
7
+ binary: shellcheck
8
+ documentation_url: https://www.shellcheck.net/
9
+ files:
10
+ - '**/*.{sh,bash,ksh,zsh}'
@@ -0,0 +1,13 @@
1
+ id: shfmt
2
+ name: shfmt
3
+ description: Shell script formatter (via shfmt-py).
4
+ install:
5
+ method: pip
6
+ package: shfmt-py>=4.0.0
7
+ binary: shfmt
8
+ documentation_url: https://github.com/mvdan/sh
9
+ config:
10
+ repo_files:
11
+ - .editorconfig
12
+ files:
13
+ - '**/*.{sh,bash,ksh,zsh}'
@@ -0,0 +1,10 @@
1
+ id: sourcery
2
+ name: Sourcery
3
+ description: Automated Python code review and refactoring suggestions.
4
+ install:
5
+ method: pip
6
+ package: sourcery>=1.0.0
7
+ binary: sourcery
8
+ documentation_url: https://sourcery.ai/
9
+ files:
10
+ - '**/*.py'
@@ -0,0 +1,20 @@
1
+ id: ty
2
+ name: ty
3
+ description: Astral static type checker for Python.
4
+ install:
5
+ method: pip
6
+ package: ty>=0.0.50
7
+ binary: ty
8
+ documentation_url: https://docs.astral.sh/ty/
9
+ config:
10
+ flag: --config-file
11
+ bundled: ty.toml
12
+ pyproject:
13
+ - tool
14
+ - ty
15
+ ignore:
16
+ kind: flag_pairs
17
+ flag: --exclude
18
+ post_subcommand: true
19
+ files:
20
+ - "**/*.py"
@@ -0,0 +1,13 @@
1
+ id: vulture
2
+ name: Vulture
3
+ description: Find dead Python code with high confidence.
4
+ install:
5
+ method: pip
6
+ package: vulture>=2.14
7
+ binary: vulture
8
+ documentation_url: https://github.com/jendrikseipp/vulture
9
+ ignore:
10
+ kind: prefix
11
+ prefix: --exclude=
12
+ files:
13
+ - '**/*.py'
@@ -0,0 +1,24 @@
1
+ id: yamlfmt
2
+ name: yamlfmt
3
+ description: YAML formatter and linter from Google.
4
+ install:
5
+ method: system
6
+ package: yamlfmt
7
+ binary: yamlfmt
8
+ documentation_url: https://github.com/google/yamlfmt
9
+ config:
10
+ flag: -conf
11
+ bundled: yamlfmt.yaml
12
+ repo_files:
13
+ - .yamlfmt.yaml
14
+ - .yamlfmt.yml
15
+ - yamlfmt.yaml
16
+ ignore:
17
+ kind: config_overlay
18
+ format: yaml
19
+ file: yamlfmt.yaml
20
+ flag: -conf
21
+ key: exclude
22
+ key_style: list
23
+ files:
24
+ - '**/*.{yml,yaml}'
@@ -0,0 +1,24 @@
1
+ id: yamllint
2
+ name: yamllint
3
+ description: YAML syntax and style linter.
4
+ install:
5
+ method: pip
6
+ package: yamllint>=1.38.0
7
+ binary: yamllint
8
+ documentation_url: https://yamllint.readthedocs.io/
9
+ config:
10
+ flag: -c
11
+ bundled: yamllint.yaml
12
+ repo_files:
13
+ - .yamllint
14
+ - .yamllint.yaml
15
+ - .yamllint.yml
16
+ ignore:
17
+ kind: config_overlay
18
+ format: yaml
19
+ file: yamllint.yaml
20
+ flag: -c
21
+ key: ignore
22
+ key_style: block
23
+ files:
24
+ - '**/*.{yml,yaml}'
@@ -0,0 +1,10 @@
1
+ AI:
2
+ expansion: Artificial intelligence
3
+ API:
4
+ expansion: Application programming interface
5
+ CI:
6
+ expansion: Continuous integration
7
+ CLI:
8
+ expansion: Command-line interface
9
+ README:
10
+ expansion: Read me (project overview document)
@@ -0,0 +1 @@
1
+ # Directory paths exempt from folder breadth limits (repo-relative).
@@ -0,0 +1 @@
1
+ # One repo-relative file path per line (whole-file exemption).
@@ -0,0 +1 @@
1
+ # One repo-relative path per line (optional). Lines starting with # are ignored.
@@ -0,0 +1,5 @@
1
+ # Bandit defaults for quality-tool orchestrators (subprocess is expected).
2
+ skips:
3
+ - B404
4
+ - B603
5
+ - B607
@@ -0,0 +1,4 @@
1
+ scan_roots:
2
+ - docs/
3
+ - AGENTS.md
4
+ allowlist_file: .pyossmtool/allowlists/acronyms.yaml
@@ -0,0 +1,12 @@
1
+ max_allowed: 12
2
+ scan_roots:
3
+ - src/
4
+ - docs/
5
+ - tests/
6
+ extensions:
7
+ - .py
8
+ - .md
9
+ - .yaml
10
+ - .sh
11
+ strict: true
12
+ allowlist_file: .pyossmtool/allowlists/folder-breadth.txt
@@ -0,0 +1,4 @@
1
+ scan_roots:
2
+ - src/
3
+ base_branch: main
4
+ allowlist_file: .pyossmtool/allowlists/module-private-vars.txt
@@ -0,0 +1,6 @@
1
+ scan_roots:
2
+ - src/
3
+ portfolio_max_lines: 1000
4
+ new_file_max_lines: 500
5
+ base_branch: main
6
+ allowlist_file: .pyossmtool/allowlists/module-size.txt
@@ -0,0 +1,8 @@
1
+ {
2
+ "default": true,
3
+ "MD013": false,
4
+ "MD033": false,
5
+ "MD041": false,
6
+ "MD040": false,
7
+ "MD060": false
8
+ }
@@ -0,0 +1,8 @@
1
+ line-length = 100
2
+ target-version = "py311"
3
+
4
+ [lint]
5
+ select = ["E", "F", "I", "UP", "B"]
6
+
7
+ [format]
8
+ quote-style = "double"
@@ -0,0 +1,5 @@
1
+ [environment]
2
+ python-version = "3.11"
3
+
4
+ [rules]
5
+ all = "error"
@@ -0,0 +1,4 @@
1
+ formatter:
2
+ type: basic
3
+ indent: 2
4
+ include_document_start: false
@@ -0,0 +1,12 @@
1
+ extends: default
2
+
3
+ rules:
4
+ line-length:
5
+ max: 120
6
+ level: warning
7
+ document-start: disable
8
+ truthy:
9
+ allowed-values: ["true", "false", "on", "off"]
10
+ check-keys: false
11
+ brackets:
12
+ forbid: false
@@ -0,0 +1,150 @@
1
+ # Script gates
2
+
3
+ Shell-based policy checks integrated with pyossmtool failure reports.
4
+
5
+ ## Bundled policy gates
6
+
7
+ | Check | Script | Config |
8
+ | -------------------------- | --------------------------------------- | ------------------------------------------------- |
9
+ | `gate.module-size` | `defaults/gates/module-size.sh` | `defaults/configs/gates/module-size.yaml` |
10
+ | `gate.module-private-vars` | `defaults/gates/module-private-vars.sh` | `defaults/configs/gates/module-private-vars.yaml` |
11
+ | `gate.folder-breadth` | `defaults/gates/folder-breadth.sh` | `defaults/configs/gates/folder-breadth.yaml` |
12
+ | `gate.acronym-allowlist` | `defaults/gates/acronym-allowlist.sh` | `defaults/configs/gates/acronym-allowlist.yaml` |
13
+
14
+ Run via suite `policy` or as part of `standard`.
15
+
16
+ ### Configure per repo
17
+
18
+ Each gate check declares where config lives (see `config:` on `catalog/checks/gate.*.yaml`):
19
+
20
+ ```yaml
21
+ config:
22
+ bundled: gates/module-size.yaml
23
+ project_file: .pyossmtool/configs/gates/gate.module-size.yaml
24
+ allowlist_bundled: module-size.txt
25
+ ```
26
+
27
+ Resolution order: `configs.mode: paths` override → `project_file` if present → `bundled` under `defaults/configs/`.
28
+
29
+ Override bundled defaults by adding the project file:
30
+
31
+ ```yaml
32
+ # .pyossmtool/configs/gates/gate.module-size.yaml
33
+ scan_roots:
34
+ - src/myapp
35
+ - scripts
36
+ portfolio_max_lines: 800
37
+ new_file_max_lines: 400
38
+ base_branch: main
39
+ allowlist_file: .pyossmtool/allowlists/module-size.txt
40
+ ```
41
+
42
+ Or set explicit paths in `pyossmtool.yaml`:
43
+
44
+ ```yaml
45
+ configs:
46
+ mode: paths
47
+ paths:
48
+ gate.module-size: .pyossmtool/configs/gates/gate.module-size.yaml
49
+ ```
50
+
51
+ Config keys are exported to gate scripts as `GATE_<KEY>` environment variables (lists become space-separated).
52
+
53
+ ## Quick start (custom gate)
54
+
55
+ ```bash
56
+ pyossmtool gate init module-size --description "Cap Python module line counts"
57
+ # edit .pyossmtool/gates/module-size.sh
58
+ # add to pyossmtool.yaml checks: - id: gate.module-size
59
+ pyossmtool run --check gate.module-size --target src/
60
+ ```
61
+
62
+ ## Layout
63
+
64
+ ```text
65
+ .pyossmtool/
66
+ gates/ # your bash scripts
67
+ module-size.sh
68
+ catalog/
69
+ checks/ # gate.<name>.yaml registrations
70
+ gate.module-size.yaml
71
+ reports/ # structured JSON written by lib.sh (gitignore this)
72
+ gate.module-size.json
73
+ ```
74
+
75
+ Project catalog entries **override** bundled checks with the same id.
76
+
77
+ ## Gate script contract
78
+
79
+ 1. Source `defaults/gates/lib.sh` via `pyossmtool gates lib-path`
80
+ 1. Call `gate_init "<name>"`
81
+ 1. Use `gate_fail` / `gate_warn` for findings
82
+ 1. Call `gate_finish` (exits 0 on pass, 1 on fail)
83
+
84
+ ### Environment (set by runner)
85
+
86
+ | Variable | Meaning |
87
+ | --------------------------- | ------------------------------------------------------------ |
88
+ | `PYOSSMTOOL_ROOT` | Repository root |
89
+ | `PYOSSMTOOL_TARGET` | Resolved scan target for this check |
90
+ | `PYOSSMTOOL_CHECK_ID` | Catalog check id |
91
+ | `PYOSSMTOOL_REPORT` | Path to write structured JSON findings |
92
+ | `PYOSSMTOOL_IGNORE_PROFILES` | Newline-separated ignore profile files (`.gitignore` syntax) |
93
+ | `PYOSSMTOOL_IGNORE_PATHS` | Newline-separated repo-relative paths/globs to skip |
94
+
95
+ Use `gate_path_ignored "<repo-relative-path>"` in bash gates to skip ignored files.
96
+
97
+ ### Structured output
98
+
99
+ `gate_fail` / `gate_warn` append to `PYOSSMTOOL_REPORT`:
100
+
101
+ ```json
102
+ {
103
+ "findings": [
104
+ {
105
+ "rule_id": "module-size",
106
+ "severity": "error",
107
+ "message": "src/foo.py has 1200 lines (cap 1000)",
108
+ "location": { "file": "src/foo.py", "line": 1 }
109
+ }
110
+ ]
111
+ }
112
+ ```
113
+
114
+ On failure, pyossmtool normalizes this into `FailureReport` v1 under `reports/failures/`.
115
+
116
+ ### Legacy scripts (no lib)
117
+
118
+ Existing bash gates that print `FAIL ...` lines still work when registered with `parser: script_text`.
119
+
120
+ ## Catalog entry
121
+
122
+ ```yaml
123
+ id: gate.module-size
124
+ tool: script
125
+ name: Module Size Gate
126
+ description: Enforce per-file line limits.
127
+ script: .pyossmtool/gates/module-size.sh
128
+ parser: gate_json
129
+ output_file: .pyossmtool/reports/gate.module-size.json
130
+ argv: []
131
+ success:
132
+ exit_codes: [0]
133
+ ```
134
+
135
+ Optional `argv` entries are passed after the script path; use `{target}` and `{cov}` placeholders.
136
+
137
+ ## Wrapping existing reslab gates
138
+
139
+ Keep `bin/gates/module-size-check.sh` as-is and register it:
140
+
141
+ ```yaml
142
+ id: gate.module-size
143
+ tool: script
144
+ name: Module Size Gate
145
+ script: bin/gates/module-size-check.sh
146
+ parser: script_text
147
+ argv: []
148
+ ```
149
+
150
+ Use `parser: gate_json` after migrating the script to call `gate_fail` / `gate_finish`.
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env bash
2
+ # Documented-acronym gate for contributor-facing prose.
3
+ set -euo pipefail
4
+
5
+ # shellcheck source=/dev/null
6
+ source "$(pyossmtool gates lib-path)"
7
+
8
+ gate_init "acronym-allowlist"
9
+
10
+ CONFIG="${PYOSSMTOOL_GATE_CONFIG:?PYOSSMTOOL_GATE_CONFIG is required}"
11
+ ROOT="${PYOSSMTOOL_ROOT:?PYOSSMTOOL_ROOT is required}"
12
+ REPORT="${PYOSSMTOOL_REPORT:?PYOSSMTOOL_REPORT is required}"
13
+
14
+ "${PYOSSMTOOL_PYTHON:?PYOSSMTOOL_PYTHON is required}" -m pyossmtool.policy.acronym_allowlist --root "${ROOT}" --config "${CONFIG}" --report "${REPORT}"
15
+ exit $?
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env bash
2
+ # Folder breadth gate — caps direct sibling file counts per directory.
3
+ set -euo pipefail
4
+
5
+ # shellcheck source=/dev/null
6
+ source "$(pyossmtool gates lib-path)"
7
+
8
+ gate_init "folder-breadth"
9
+
10
+ CONFIG="${PYOSSMTOOL_GATE_CONFIG:?PYOSSMTOOL_GATE_CONFIG is required}"
11
+ ROOT="${PYOSSMTOOL_ROOT:?PYOSSMTOOL_ROOT is required}"
12
+ REPORT="${PYOSSMTOOL_REPORT:?PYOSSMTOOL_REPORT is required}"
13
+
14
+ ARGS=(--root "${ROOT}" --config "${CONFIG}" --report "${REPORT}")
15
+ if [[ ${GATE_STRICT:-1} == "1" ]]; then
16
+ ARGS+=(--strict)
17
+ else
18
+ ARGS+=(--advisory)
19
+ fi
20
+
21
+ "${PYOSSMTOOL_PYTHON:?PYOSSMTOOL_PYTHON is required}" -m pyossmtool.policy.folder_breadth "${ARGS[@]}"
22
+ exit $?
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env bash
2
+ # pyossmtool script-gate helper library.
3
+ # Source from project gates: source "$(pyossmtool gates lib-path)"
4
+ set -euo pipefail
5
+
6
+ gate_init() {
7
+ GATE_NAME="${1:-script-gate}"
8
+ GATE_FINDING_COUNT=0
9
+ if [[ -z "${PYOSSMTOOL_REPORT:-}" ]]; then
10
+ echo "gate_init: PYOSSMTOOL_REPORT is not set (pyossmtool runner should set this)" >&2
11
+ exit 2
12
+ fi
13
+ mkdir -p "$(dirname "${PYOSSMTOOL_REPORT}")"
14
+ printf '%s\n' '{"findings":[]}' >"${PYOSSMTOOL_REPORT}"
15
+ }
16
+
17
+ _gate_append_finding() {
18
+ local rule_id="$1"
19
+ local severity="$2"
20
+ local message="$3"
21
+ local file="${4:-}"
22
+ local line="${5:-}"
23
+ python3 - "${PYOSSMTOOL_REPORT}" "${rule_id}" "${severity}" "${message}" "${file}" "${line}" <<'PY'
24
+ import json
25
+ import sys
26
+ from pathlib import Path
27
+
28
+ report_path, rule_id, severity, message, file, line = sys.argv[1:7]
29
+ payload = json.loads(Path(report_path).read_text(encoding="utf-8"))
30
+ finding = {
31
+ "rule_id": rule_id,
32
+ "severity": severity,
33
+ "message": message,
34
+ }
35
+ if file:
36
+ location = {"file": file}
37
+ if line:
38
+ try:
39
+ location["line"] = int(line)
40
+ except ValueError:
41
+ pass
42
+ finding["location"] = location
43
+ payload.setdefault("findings", []).append(finding)
44
+ Path(report_path).write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
45
+ PY
46
+ GATE_FINDING_COUNT=$((GATE_FINDING_COUNT + 1))
47
+ }
48
+
49
+ gate_fail() {
50
+ local rule_id="${1:-gate}"
51
+ local message="${2:-gate failed}"
52
+ local file="${3:-}"
53
+ local line="${4:-}"
54
+ _gate_append_finding "${rule_id}" "error" "${message}" "${file}" "${line}"
55
+ echo "FAIL ${rule_id}: ${message}" >&2
56
+ }
57
+
58
+ gate_warn() {
59
+ local rule_id="${1:-gate}"
60
+ local message="${2:-gate warning}"
61
+ local file="${3:-}"
62
+ local line="${4:-}"
63
+ _gate_append_finding "${rule_id}" "warning" "${message}" "${file}" "${line}"
64
+ echo "WARN ${rule_id}: ${message}" >&2
65
+ }
66
+
67
+ gate_path_ignored() {
68
+ local rel_path="${1#./}"
69
+ "${PYOSSMTOOL_PYTHON:-python3}" - "${rel_path}" <<'PY'
70
+ import fnmatch
71
+ import os
72
+ import sys
73
+ from pathlib import Path
74
+
75
+ try:
76
+ import pathspec
77
+ except ImportError:
78
+ pathspec = None
79
+
80
+ rel = sys.argv[1].replace("\\", "/").lstrip("./")
81
+ patterns: list[str] = [
82
+ p.strip() for p in os.environ.get("PYOSSMTOOL_IGNORE_PATHS", "").splitlines() if p.strip()
83
+ ]
84
+ for profile in os.environ.get("PYOSSMTOOL_IGNORE_PROFILES", "").splitlines():
85
+ path = Path(profile.strip())
86
+ if not path.is_file():
87
+ continue
88
+ for line in path.read_text(encoding="utf-8").splitlines():
89
+ stripped = line.strip()
90
+ if stripped and not stripped.startswith("#") and not stripped.startswith("!"):
91
+ patterns.append(stripped)
92
+
93
+ if not patterns:
94
+ raise SystemExit(1)
95
+
96
+ if pathspec is not None:
97
+ matcher = pathspec.PathSpec.from_lines("gitignore", patterns)
98
+ raise SystemExit(0 if matcher.match_file(rel) else 1)
99
+
100
+ for pattern in patterns:
101
+ normalized = pattern.rstrip("/")
102
+ if rel == normalized or rel.startswith(f"{normalized}/"):
103
+ raise SystemExit(0)
104
+ if "*" in pattern and fnmatch.fnmatch(rel, pattern):
105
+ raise SystemExit(0)
106
+ raise SystemExit(1)
107
+ PY
108
+ }
109
+
110
+ gate_finish() {
111
+ if ((GATE_FINDING_COUNT > 0)); then
112
+ echo "gate '${GATE_NAME}' failed with ${GATE_FINDING_COUNT} finding(s)" >&2
113
+ exit 1
114
+ fi
115
+ exit 0
116
+ }