opsscript-gate 0.5.0__tar.gz → 0.6.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 (50) hide show
  1. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/CHANGELOG.md +27 -18
  2. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/PKG-INFO +67 -42
  3. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/README.md +65 -40
  4. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/README.zh-CN.md +23 -4
  5. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/action.yml +7 -1
  6. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/docs/configuration.md +17 -2
  7. opsscript_gate-0.6.0/docs/gpt-oss.md +80 -0
  8. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/examples/alpine-incompatibility/README.md +2 -1
  9. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/examples/github-actions/README.md +2 -2
  10. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/examples/github-actions/workflow.yml +3 -1
  11. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/pyproject.toml +2 -2
  12. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/src/opsscript_gate/__init__.py +1 -1
  13. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/src/opsscript_gate/cli.py +26 -2
  14. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/src/opsscript_gate/config.py +1 -1
  15. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/src/opsscript_gate/discovery.py +64 -0
  16. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/tests/test_action_contract.py +2 -1
  17. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/tests/test_onboarding.py +35 -1
  18. opsscript_gate-0.5.0/docs/promotion/awesome-lists-pr.md +0 -59
  19. opsscript_gate-0.5.0/docs/promotion/juejin-zhihu-article.md +0 -144
  20. opsscript_gate-0.5.0/docs/promotion/reddit-devops.md +0 -56
  21. opsscript_gate-0.5.0/docs/promotion/show-hn.md +0 -67
  22. opsscript_gate-0.5.0/docs/promotion/v2ex-post.md +0 -68
  23. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/.gitattributes +0 -0
  24. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  25. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/.github/ISSUE_TEMPLATE/distro_request.yml +0 -0
  26. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  27. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/.github/assets/social-preview.png +0 -0
  28. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/.github/pull_request_template.md +0 -0
  29. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/.github/workflows/demo.yml +0 -0
  30. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/.github/workflows/release.yml +0 -0
  31. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/.github/workflows/test.yml +0 -0
  32. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/.gitignore +0 -0
  33. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/CONTRIBUTING.md +0 -0
  34. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/LICENSE +0 -0
  35. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/ROADMAP.md +0 -0
  36. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/SECURITY.md +0 -0
  37. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/docs/troubleshooting.md +0 -0
  38. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/examples/alpine-incompatibility/apt_dependency.sh +0 -0
  39. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/examples/basic/README.md +0 -0
  40. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/examples/basic/clean_setup.sh +0 -0
  41. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/examples/interactive-hang/README.md +0 -0
  42. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/examples/interactive-hang/prompt_confirm.sh +0 -0
  43. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/src/opsscript_gate/models.py +0 -0
  44. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/src/opsscript_gate/remediation.py +0 -0
  45. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/src/opsscript_gate/reporter.py +0 -0
  46. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/src/opsscript_gate/runner.py +0 -0
  47. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/tests/fixtures/fail_deps.sh +0 -0
  48. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/tests/fixtures/fail_hang.sh +0 -0
  49. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/tests/fixtures/pass_basic.sh +0 -0
  50. {opsscript_gate-0.5.0 → opsscript_gate-0.6.0}/tests/test_runner.py +0 -0
@@ -1,21 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.6.0] - 2026-09-30
4
+
5
+ ### Added
6
+ - Added `--changed-since` and the matching Action input to test only shell scripts changed since a Git revision.
7
+ - Changed-script selection uses the existing discovery safety checks and passes when a change contains no shell scripts.
8
+
9
+ ## [0.5.1] - 2026-09-30
10
+
11
+ ### Changed
12
+ - Published the current README and examples with the v0.5.1 Action tag.
13
+ - Updated package and Action metadata to describe the supported container matrix and runtime compatibility check.
14
+
3
15
  ## [0.5.0] - 2026-09-24
4
16
 
5
17
  ### Added
6
- - `init`: non-overwriting project configuration and GitHub workflow generation.
7
- - Shared, strictly validated `.opsscript-gate.json` settings; explicit CLI/Action inputs win.
8
- - Docker-free `--dry-run` plans in text or JSON, including execution counts.
9
- - `minimal` and `ubuntu` distribution presets, repeatable exclusion globs and configurable discovery limit.
10
- - `--output` report artifacts, including failure reports; source/config overwrite protection.
11
- - Action inputs for configuration, presets, exclusions, preview and saved reports.
12
- - Chinese quickstart, configuration guide and Ubuntu/Alpine troubleshooting guide.
18
+ - Added `opsscript-gate init` to create a config file and GitHub workflow without replacing existing files.
19
+ - Added `.opsscript-gate.json` with CLI and Action overrides.
20
+ - Added `--dry-run`, `minimal` and `ubuntu` presets, exclusion globs, and `--output` reports.
21
+ - Added configuration, Chinese quickstart, and Ubuntu/Alpine troubleshooting documentation.
13
22
 
14
23
  ### Fixed
15
- - Discovery now fails on overflow instead of silently testing only the first 20 scripts.
16
- - Discovery skips symlinks and non-files and rejects shebang prefix collisions.
17
- - CLI rejects non-positive limits and unsupported network modes before execution.
18
- - Default Action inputs no longer override a user's project configuration.
24
+ - Discovery stops at the first candidate beyond the configured limit instead of silently ignoring files.
25
+ - Discovery skips symlinks and non-files and checks shebangs without prefix matches.
26
+ - CLI validates limits and network modes before execution.
27
+ - Empty Action inputs no longer override project configuration.
19
28
 
20
29
  ### Migration
21
30
  - Repositories with more than 20 discovered scripts must exclude unwanted scripts or raise `max_scripts`.
@@ -31,8 +40,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
31
40
  ## [0.4.1] - 2026-09-19
32
41
 
33
42
  ### Fixed & Hardened
34
- - **Bounded container log capture**: Stream-captures container logs using an immediate rolling byte buffer capped at 256 KiB (`MAX_CAPTURED_LOG_BYTES`) and tail limited to 500 lines (`MAX_LOG_TAIL_LINES`), bounding retained container log data to reduce memory-exhaustion risk from runaway output.
35
- - **Workflow command neutralization**: Neutralizes untrusted container logs starting with `::` into `[container] ::` to prevent malicious scripts from forging GitHub Actions workflow commands in Runner consoles, while keeping OpsScript Gate's own annotations intact.
43
+ - Bounded container log capture with a 256 KiB rolling buffer and 500-line tail.
44
+ - Neutralized untrusted container logs beginning with `::` before they reach GitHub Actions.
36
45
  - **Terminal ANSI and control character sanitization**: Strips ANSI escape sequences (CSI, OSC, 2-byte escapes), removes dangerous C0 control characters and DEL, and normalizes CRLF and standalone carriage returns (`\r`) to defeat terminal line overwrite and status spoofing, while preserving printable Unicode.
37
46
  - **Context-sensitive Markdown and HTML injection defense**: Implemented dedicated escaping (`escape_inline_code`, `escape_markdown_text`, `escape_markdown_table_cell`, `escape_html_text`, `format_safe_code_fence`) to prevent table cell tearing, HTML container breakout (`</details>`), premature code fence closure, and structural Markdown injection from runtime-derived values.
38
47
  - **Bounded streaming script preparation**: Stream-normalizes CRLF in bounded 64 KiB chunks (`SCRIPT_READ_CHUNK_SIZE`), properly handling boundary-split CRLF while preserving lone CR bytes without whole-file memory allocation. Bounded shebang parsing to 4096 bytes (`MAX_SHEBANG_BYTES`).
@@ -45,15 +54,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
45
54
  ## [0.4.0] - 2026-09-19
46
55
 
47
56
  ### Added
48
- - **High-confidence line-level GitHub Actions annotations**: Emits inline `::error` annotations with exact script line numbers directly on pull request file diffs.
57
+ - Line-level GitHub Actions annotations with script paths and line numbers.
49
58
  - **Workflow command injection defense**: Strictly escapes parameters (`%`, `\r`, `\n`, `:`, `,`) and message bodies (`%`, `\r`, `\n`) to eliminate command injection from unclassified container logs.
50
- - **Conservative distro-aware remediation hints**: Suggests testable, high-confidence remediation recommendations (`RemediationRule`) with conservative phrasing (`normally`, `may`, `consider`), covering:
59
+ - Distro-aware remediation hints for common mismatches, including:
51
60
  - Alpine package manager mismatches (`apt`/`apt-get` -> `apk`)
52
61
  - Debian/Ubuntu package manager mismatches (`apk` -> `apt-get`)
53
62
  - Alpine minimal missing Bash (`bash` -> consider POSIX sh or installing bash)
54
63
  - Missing network prerequisites (`curl`, `wget`)
55
64
  - Missing shebang interpreter paths.
56
- - **Re-engineered Compatibility Card**: Overhauled GitHub Actions Step Summary with an instant 5-second triage table and an expandable copy-pasteable Markdown snippet ready for PR descriptions and Issue comments.
65
+ - Updated the GitHub Actions Step Summary with a compatibility table and a Markdown result block.
57
66
  - **Parallel matrix execution (`--jobs` / `jobs`)**: Concurrently runs container checks using `ThreadPoolExecutor` (defaults to `min(2, matrix_size)`), strictly preserving matrix output order and ensuring reliable container cleanup.
58
67
  - **Hardened container resource limits**: Added `--mem-limit` (default: 256m) and `--pids-limit` (default: 128) flags and Action inputs to prevent runaway resource exhaustion.
59
68
  - **Configurable network isolation (`--network`)**: Supports `--network bridge` (default) and `--network none` for offline script execution.
@@ -70,7 +79,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
70
79
 
71
80
  ### Added
72
81
  - Structured runtime failure diagnostics: detect common "command not found" failures across Linux distributions (Alpine/BusyBox ash, Debian/Ubuntu dash, Bash, and missing interpreter paths).
73
- - High-confidence dual-signal classification: requires exit code 127 and matching shell output to produce a `missing_command` diagnostic.
82
+ - Missing-command classification requires exit code 127 and matching shell output.
74
83
  - Additive `diagnostic` field in JSON report format (`SingleResult.to_dict()`) providing structured diagnostic information (backward-compatible for consumers tolerating additional fields).
75
84
  - Enhanced terminal table formatting and GitHub Actions Step Summary showing clear failure causes in the summary overview.
76
85
 
@@ -104,7 +113,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
104
113
  ### Added
105
114
  - Configured PyPI Trusted Publishing via GitHub Actions OIDC (`pypa/gh-action-pypi-publish`).
106
115
  - Added full PyPI package metadata, classifiers, and project URLs to `pyproject.toml`.
107
- - Ensured absolute asset URLs in `README.md` for seamless PyPI rendering.
116
+ - Ensured asset URLs in `README.md` render correctly on PyPI.
108
117
 
109
118
  ---
110
119
 
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: opsscript-gate
3
- Version: 0.5.0
4
- Summary: Run Linux shell scripts across Debian, Ubuntu and Alpine before release to catch runtime compatibility failures
3
+ Version: 0.6.0
4
+ Summary: Run Linux shell scripts in Debian, Ubuntu and Alpine containers to catch runtime compatibility failures before merge
5
5
  Project-URL: Homepage, https://github.com/Mresyzz/opsscript-gate
6
6
  Project-URL: Repository, https://github.com/Mresyzz/opsscript-gate
7
7
  Project-URL: Issues, https://github.com/Mresyzz/opsscript-gate/issues
@@ -28,9 +28,9 @@ Description-Content-Type: text/markdown
28
28
 
29
29
  # OpsScript Gate — shell script compatibility testing
30
30
 
31
- [简体中文](README.zh-CN.md) · [Configuration](docs/configuration.md) · [Troubleshooting](docs/troubleshooting.md)
31
+ [简体中文](README.zh-CN.md) · [Configuration](docs/configuration.md) · [Troubleshooting](docs/troubleshooting.md) · [Self-hosted model installer guide](docs/gpt-oss.md)
32
32
 
33
- > **ShellCheck tells you if your script looks portable. OpsScript Gate checks if it actually runs there.**
33
+ > ShellCheck analyzes shell syntax. OpsScript Gate executes scripts in Linux containers.
34
34
 
35
35
  [![CI](https://github.com/Mresyzz/opsscript-gate/actions/workflows/test.yml/badge.svg)](https://github.com/Mresyzz/opsscript-gate/actions/workflows/test.yml)
36
36
  [![Demo](https://github.com/Mresyzz/opsscript-gate/actions/workflows/demo.yml/badge.svg)](https://github.com/Mresyzz/opsscript-gate/actions/workflows/demo.yml)
@@ -41,17 +41,17 @@ Description-Content-Type: text/markdown
41
41
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
42
42
  [![Supported Distros](https://img.shields.io/badge/matrix-Debian%20%7C%20Ubuntu%20%7C%20Alpine-orange.svg)](#default-test-matrix)
43
43
 
44
- **OpsScript Gate** is a drop-in runtime compatibility gate for Linux shell scripts. It executes your scripts inside unprivileged Debian, Ubuntu, and Alpine containers before merge, catching environment-specific runtime failures, missing interpreters, and package-manager assumptions that static analysis cannot detect.
44
+ **OpsScript Gate** is a runtime compatibility checker for Linux shell scripts. It executes scripts inside unprivileged Debian, Ubuntu, and Alpine containers, catching environment-specific failures, missing interpreters, and package-manager assumptions that static analysis cannot detect.
45
45
 
46
46
  It is designed for shell testing, portable shell validation, Bash/POSIX compatibility checks, and cross-distro CI where syntax-only tooling is not enough.
47
47
 
48
48
  ---
49
49
 
50
- ## New in v0.5.0
50
+ ## Current release: v0.6.0
51
51
 
52
- Preview exactly what will run, keep local and CI settings together, and exclude test
53
- fixtures before executing scripts. These controls are included in v0.5.0. Projects on
54
- v0.4.1 and earlier do not include them.
52
+ The current release includes a project config file, a dry-run plan, presets, exclusions,
53
+ saved reports, and changed-script selection for pull requests. The project controls
54
+ were introduced in v0.5.0; projects on v0.4.1 and earlier do not include them.
55
55
 
56
56
  ```bash
57
57
  opsscript-gate init
@@ -69,11 +69,14 @@ repository files, sibling scripts and project dependencies are **not** mounted.
69
69
  See [configuration and migration](docs/configuration.md) and
70
70
  [why a shell script works on Ubuntu but fails on Alpine](docs/troubleshooting.md).
71
71
 
72
- ## ⚡ 30-Second Quickstart
72
+ ## Quickstart
73
73
 
74
- ### In GitHub Actions (Zero Config)
74
+ ### In GitHub Actions
75
75
 
76
- Drop this minimal workflow into `.github/workflows/shell-compat.yml`:
76
+ Add this workflow to `.github/workflows/shell-compat.yml`:
77
+
78
+ You can copy the maintained example from [`examples/github-actions/workflow.yml`](examples/github-actions/workflow.yml)
79
+ and change the `script-path`, or use the minimal workflow below.
77
80
 
78
81
  ```yaml
79
82
  name: Shell Compatibility Gate
@@ -84,15 +87,18 @@ jobs:
84
87
  runs-on: ubuntu-latest
85
88
  steps:
86
89
  - uses: actions/checkout@v7
87
- - uses: Mresyzz/opsscript-gate@v0.5.0
90
+ - uses: Mresyzz/opsscript-gate@v0.6.0
88
91
  ```
89
92
 
90
- > **Zero Config**: If `script-path` is omitted, OpsScript Gate automatically discovers shell scripts in your repository. Scripts run sequentially, with concurrent distribution checks for each script. Preview discovery before running unfamiliar repositories.
93
+ This zero-configuration form discovers shell scripts in the repository. Use
94
+ `opsscript-gate run --dry-run` to inspect the selection, or set `script-path` when the
95
+ repository has a single installer. For self-hosted model installers, see the
96
+ [installer guide](docs/gpt-oss.md).
91
97
 
92
98
  Or test a specific script with custom execution modes:
93
99
 
94
100
  ```yaml
95
- - uses: Mresyzz/opsscript-gate@v0.5.0
101
+ - uses: Mresyzz/opsscript-gate@v0.6.0
96
102
  with:
97
103
  script-path: scripts/install.sh
98
104
  shell: auto
@@ -114,7 +120,26 @@ opsscript-gate run ./scripts/install.sh
114
120
  opsscript-gate run
115
121
  ```
116
122
 
117
- ### Try a Real Failure in 30 Seconds
123
+ ### Test only scripts changed in a pull request
124
+
125
+ Fetch the comparison revision and pass the pull request base SHA to avoid running
126
+ unrelated scripts:
127
+
128
+ ```yaml
129
+ - uses: actions/checkout@v7
130
+ with:
131
+ fetch-depth: 0
132
+ - uses: Mresyzz/opsscript-gate@v0.6.0
133
+ with:
134
+ changed-since: ${{ github.event.pull_request.base.sha }}
135
+ preset: minimal
136
+ ```
137
+
138
+ If the change does not include a shell script, the check passes without starting a
139
+ container. The same selection can be previewed locally with
140
+ `opsscript-gate run --changed-since origin/main --dry-run`.
141
+
142
+ ### Example: package-manager mismatch
118
143
 
119
144
  Create `install.sh`:
120
145
 
@@ -141,23 +166,23 @@ Alpine 3.20 FAIL
141
166
  apt-get: not found
142
167
  ```
143
168
 
144
- The script is valid shell, but the runtime environment is incompatible. That is exactly the class of failure OpsScript Gate is designed to catch.
169
+ The script is valid shell, but it assumes a command that is not present in Alpine.
145
170
 
146
171
  ---
147
172
 
148
- ## 🎯 Reviewer-First Experience: What It Produces
173
+ ## CI output
149
174
 
150
- Every run of OpsScript Gate generates clean, actionable feedback right where developers and reviewers need it:
175
+ The action reports failures in two places:
151
176
 
152
- ### 1. Line-Level GitHub Annotations
153
- When a failure occurs, OpsScript Gate flags the exact script line on your Pull Request's **Files Changed** view with high-confidence diagnostics and conservative remediation hints:
177
+ ### GitHub annotations
178
+ Failures include the script path, line number, distribution, and a short diagnostic:
154
179
 
155
180
  ```text
156
181
  ::error file=scripts/setup.sh,line=4,title=OpsScript Gate: [alpine:3.20] command not found: apt-get::command not found: apt-get — Alpine normally uses apk instead of apt-get.
157
182
  ```
158
183
 
159
- ### 2. GitHub Step Summary Compatibility Card
160
- A beautifully formatted markdown summary is automatically posted to `$GITHUB_STEP_SUMMARY`:
184
+ ### Step summary
185
+ The action also writes a markdown matrix to `$GITHUB_STEP_SUMMARY`:
161
186
 
162
187
  ```markdown
163
188
  ## 🛡️ OpsScript Gate Compatibility Report
@@ -176,14 +201,14 @@ A beautifully formatted markdown summary is automatically posted to `$GITHUB_STE
176
201
  | `alpine:3.20` | ❌ FAIL | `127` | `0.19s` | ⚠️ Missing command: `apt-get` (line 4)<br>💡 *Alpine normally uses apk instead of apt-get.* |
177
202
 
178
203
  <details>
179
- <summary>📋 <b>Copyable Markdown (Click to expand & copy to PR / Issue)</b></summary>
204
+ <summary><b>Markdown result</b></summary>
180
205
  ...
181
206
  </details>
182
207
  ```
183
208
 
184
209
  ---
185
210
 
186
- ## 🔍 Example: What Static Analysis Misses
211
+ ## Example: runtime behavior that static analysis misses
187
212
 
188
213
  Consider this clean deployment script:
189
214
 
@@ -220,37 +245,38 @@ Failed Distributions - Output Snippets (last 15 lines):
220
245
  sh: line 4: apt-get: not found
221
246
  ```
222
247
 
223
- **Why it failed:** Alpine Linux is musl/BusyBox-based and uses `apk`, not `apt-get`. OpsScript Gate catches the missing command (`exit code 127`) and gives you the exact line number and conservative remediation hint before deployment.
248
+ **Why it failed:** Alpine uses `apk`, not `apt-get`. The report includes the missing command and its line number.
224
249
 
225
250
  ---
226
251
 
227
- ## 🛡️ Why OpsScript Gate?
252
+ ## Scope compared with other checks
228
253
 
229
- ### OpsScript Gate vs ShellCheck vs Custom CI Matrix
254
+ ### OpsScript Gate compared with ShellCheck and a custom CI matrix
230
255
 
231
256
  | Capability | OpsScript Gate | ShellCheck | Handwritten CI Matrix |
232
257
  | :--- | :---: | :---: | :---: |
233
258
  | **Runtime execution** | **Yes** | No (Static AST only) | Yes |
234
259
  | **Real distro environments** | **Yes (Debian, Ubuntu, Alpine)** | No | Yes |
235
260
  | **Preconfigured defaults** | **Yes** | Yes | Requires custom workflow configuration |
236
- | **Hardened container defaults** | **Built-in (`ro`, `cap_drop`, resource limits)** | N/A | User-defined |
261
+ | **Restricted container defaults** | **Built-in (`ro`, `cap_drop`, resource limits)** | N/A | User-defined |
237
262
  | **Anti-hang stdin protection** | **Built-in (`</dev/null`, noninteractive)** | No | User-defined |
238
- | **Line-Level Annotations & Hints** | **Built-in (Zero config)** | Static warnings | User-defined |
263
+ | **Line-Level Annotations & Hints** | **Built-in** | Static warnings | User-defined |
239
264
  | **Parallel Matrix Execution** | **Built-in (`--jobs`)** | N/A | Manual matrix config |
240
265
 
241
- - **ShellCheck** is indispensable for static analysis (syntax, quoting, SC warnings). OpsScript Gate complements it by testing actual execution behavior in real distributions.
242
- - **Handwritten CI Matrix** requires maintaining complex Docker configurations, volume mounts, timeout guards, and log parsers across every project. OpsScript Gate packages this into a single check.
266
+ ShellCheck checks shell syntax and common mistakes. OpsScript Gate runs the script in
267
+ real distributions. A custom CI matrix can do the same job, but each repository must
268
+ maintain its own images, mounts, timeouts, and report handling.
243
269
 
244
270
  ---
245
271
 
246
- ## 🔒 Security Boundaries & Hardened Isolation
272
+ ## Security boundaries and container isolation
247
273
 
248
274
  OpsScript Gate is a runtime compatibility testing tool, **not a security sandbox for hostile or fully untrusted code**. Containers still share the host kernel, so target scripts should be treated accordingly.
249
275
 
250
276
  <details>
251
277
  <summary><strong>View security boundaries and runtime hardening details</strong></summary>
252
278
 
253
- OpsScript Gate applies conservative, restricted container defaults when running scripts:
279
+ The runner uses restricted container defaults:
254
280
 
255
281
  1. **Restricted Container Defaults**:
256
282
  - Containers run with `privileged=False`.
@@ -300,7 +326,7 @@ Use it when you want to know whether a shell script actually runs across the sup
300
326
 
301
327
  ---
302
328
 
303
- ## 📦 Default Test Matrix
329
+ ## Default test matrix
304
330
 
305
331
  | Image | Distribution | Focus |
306
332
  | :--- | :--- | :--- |
@@ -313,7 +339,7 @@ Customize the matrix at any time via `--matrix` or Action input `matrix`.
313
339
 
314
340
  ---
315
341
 
316
- ## 🛠️ CLI Reference
342
+ ## CLI reference
317
343
 
318
344
  ```text
319
345
  usage: opsscript-gate run [-h] [--matrix MATRIX] [-j JOBS] [--timeout TIMEOUT]
@@ -335,6 +361,7 @@ usage: opsscript-gate run [-h] [--matrix MATRIX] [-j JOBS] [--timeout TIMEOUT]
335
361
  | `--mem-limit` | String | `256m` | Memory limit per container (e.g. `256m`, `512m`) |
336
362
  | `--pids-limit`| Integer | `128` | Maximum number of processes per container |
337
363
  | `--network` | Choice | `bridge` | Container network mode: `bridge` or `none` |
364
+ | `--changed-since` | Git revision | - | Test shell scripts changed between this revision and `HEAD` |
338
365
  | `--version` | Flag | - | Show version number |
339
366
  | `-h, --help` | Flag | - | Show argument help |
340
367
 
@@ -366,9 +393,9 @@ usage: opsscript-gate run [-h] [--matrix MATRIX] [-j JOBS] [--timeout TIMEOUT]
366
393
  Explicit CLI options override project settings. Explicit script paths bypass discovery
367
394
  and its exclusions. See [complete configuration semantics](docs/configuration.md).
368
395
 
369
- ## 🌍 Real-World Usage
396
+ ## Downstream example
370
397
 
371
- OpsScript Gate is actively used in [`Mresyzz/linux-dev-bootstrap`](https://github.com/Mresyzz/linux-dev-bootstrap) to validate `install.sh` across the default Debian, Ubuntu, and Alpine matrix in GitHub Actions.
398
+ [`Mresyzz/linux-dev-bootstrap`](https://github.com/Mresyzz/linux-dev-bootstrap) contains a workflow that validates `install.sh` across the default Debian, Ubuntu, and Alpine matrix.
372
399
 
373
400
  See the downstream workflow: [`.github/workflows/test.yml`](https://github.com/Mresyzz/linux-dev-bootstrap/blob/main/.github/workflows/test.yml).
374
401
 
@@ -393,11 +420,9 @@ pytest -v
393
420
 
394
421
  ---
395
422
 
396
- ## 💛 If OpsScript Gate Helps
397
-
398
- If OpsScript Gate catches a compatibility problem in one of your scripts, consider starring the repository so other shell and DevOps maintainers can find it too.
423
+ ## Feedback
399
424
 
400
- Bug reports, real-world compatibility cases, and pull requests are especially welcome.
425
+ Please report compatibility cases, bugs, and pull requests in the issue tracker.
401
426
 
402
427
  ---
403
428
 
@@ -1,8 +1,8 @@
1
1
  # OpsScript Gate — shell script compatibility testing
2
2
 
3
- [简体中文](README.zh-CN.md) · [Configuration](docs/configuration.md) · [Troubleshooting](docs/troubleshooting.md)
3
+ [简体中文](README.zh-CN.md) · [Configuration](docs/configuration.md) · [Troubleshooting](docs/troubleshooting.md) · [Self-hosted model installer guide](docs/gpt-oss.md)
4
4
 
5
- > **ShellCheck tells you if your script looks portable. OpsScript Gate checks if it actually runs there.**
5
+ > ShellCheck analyzes shell syntax. OpsScript Gate executes scripts in Linux containers.
6
6
 
7
7
  [![CI](https://github.com/Mresyzz/opsscript-gate/actions/workflows/test.yml/badge.svg)](https://github.com/Mresyzz/opsscript-gate/actions/workflows/test.yml)
8
8
  [![Demo](https://github.com/Mresyzz/opsscript-gate/actions/workflows/demo.yml/badge.svg)](https://github.com/Mresyzz/opsscript-gate/actions/workflows/demo.yml)
@@ -13,17 +13,17 @@
13
13
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
14
14
  [![Supported Distros](https://img.shields.io/badge/matrix-Debian%20%7C%20Ubuntu%20%7C%20Alpine-orange.svg)](#default-test-matrix)
15
15
 
16
- **OpsScript Gate** is a drop-in runtime compatibility gate for Linux shell scripts. It executes your scripts inside unprivileged Debian, Ubuntu, and Alpine containers before merge, catching environment-specific runtime failures, missing interpreters, and package-manager assumptions that static analysis cannot detect.
16
+ **OpsScript Gate** is a runtime compatibility checker for Linux shell scripts. It executes scripts inside unprivileged Debian, Ubuntu, and Alpine containers, catching environment-specific failures, missing interpreters, and package-manager assumptions that static analysis cannot detect.
17
17
 
18
18
  It is designed for shell testing, portable shell validation, Bash/POSIX compatibility checks, and cross-distro CI where syntax-only tooling is not enough.
19
19
 
20
20
  ---
21
21
 
22
- ## New in v0.5.0
22
+ ## Current release: v0.6.0
23
23
 
24
- Preview exactly what will run, keep local and CI settings together, and exclude test
25
- fixtures before executing scripts. These controls are included in v0.5.0. Projects on
26
- v0.4.1 and earlier do not include them.
24
+ The current release includes a project config file, a dry-run plan, presets, exclusions,
25
+ saved reports, and changed-script selection for pull requests. The project controls
26
+ were introduced in v0.5.0; projects on v0.4.1 and earlier do not include them.
27
27
 
28
28
  ```bash
29
29
  opsscript-gate init
@@ -41,11 +41,14 @@ repository files, sibling scripts and project dependencies are **not** mounted.
41
41
  See [configuration and migration](docs/configuration.md) and
42
42
  [why a shell script works on Ubuntu but fails on Alpine](docs/troubleshooting.md).
43
43
 
44
- ## ⚡ 30-Second Quickstart
44
+ ## Quickstart
45
45
 
46
- ### In GitHub Actions (Zero Config)
46
+ ### In GitHub Actions
47
47
 
48
- Drop this minimal workflow into `.github/workflows/shell-compat.yml`:
48
+ Add this workflow to `.github/workflows/shell-compat.yml`:
49
+
50
+ You can copy the maintained example from [`examples/github-actions/workflow.yml`](examples/github-actions/workflow.yml)
51
+ and change the `script-path`, or use the minimal workflow below.
49
52
 
50
53
  ```yaml
51
54
  name: Shell Compatibility Gate
@@ -56,15 +59,18 @@ jobs:
56
59
  runs-on: ubuntu-latest
57
60
  steps:
58
61
  - uses: actions/checkout@v7
59
- - uses: Mresyzz/opsscript-gate@v0.5.0
62
+ - uses: Mresyzz/opsscript-gate@v0.6.0
60
63
  ```
61
64
 
62
- > **Zero Config**: If `script-path` is omitted, OpsScript Gate automatically discovers shell scripts in your repository. Scripts run sequentially, with concurrent distribution checks for each script. Preview discovery before running unfamiliar repositories.
65
+ This zero-configuration form discovers shell scripts in the repository. Use
66
+ `opsscript-gate run --dry-run` to inspect the selection, or set `script-path` when the
67
+ repository has a single installer. For self-hosted model installers, see the
68
+ [installer guide](docs/gpt-oss.md).
63
69
 
64
70
  Or test a specific script with custom execution modes:
65
71
 
66
72
  ```yaml
67
- - uses: Mresyzz/opsscript-gate@v0.5.0
73
+ - uses: Mresyzz/opsscript-gate@v0.6.0
68
74
  with:
69
75
  script-path: scripts/install.sh
70
76
  shell: auto
@@ -86,7 +92,26 @@ opsscript-gate run ./scripts/install.sh
86
92
  opsscript-gate run
87
93
  ```
88
94
 
89
- ### Try a Real Failure in 30 Seconds
95
+ ### Test only scripts changed in a pull request
96
+
97
+ Fetch the comparison revision and pass the pull request base SHA to avoid running
98
+ unrelated scripts:
99
+
100
+ ```yaml
101
+ - uses: actions/checkout@v7
102
+ with:
103
+ fetch-depth: 0
104
+ - uses: Mresyzz/opsscript-gate@v0.6.0
105
+ with:
106
+ changed-since: ${{ github.event.pull_request.base.sha }}
107
+ preset: minimal
108
+ ```
109
+
110
+ If the change does not include a shell script, the check passes without starting a
111
+ container. The same selection can be previewed locally with
112
+ `opsscript-gate run --changed-since origin/main --dry-run`.
113
+
114
+ ### Example: package-manager mismatch
90
115
 
91
116
  Create `install.sh`:
92
117
 
@@ -113,23 +138,23 @@ Alpine 3.20 FAIL
113
138
  apt-get: not found
114
139
  ```
115
140
 
116
- The script is valid shell, but the runtime environment is incompatible. That is exactly the class of failure OpsScript Gate is designed to catch.
141
+ The script is valid shell, but it assumes a command that is not present in Alpine.
117
142
 
118
143
  ---
119
144
 
120
- ## 🎯 Reviewer-First Experience: What It Produces
145
+ ## CI output
121
146
 
122
- Every run of OpsScript Gate generates clean, actionable feedback right where developers and reviewers need it:
147
+ The action reports failures in two places:
123
148
 
124
- ### 1. Line-Level GitHub Annotations
125
- When a failure occurs, OpsScript Gate flags the exact script line on your Pull Request's **Files Changed** view with high-confidence diagnostics and conservative remediation hints:
149
+ ### GitHub annotations
150
+ Failures include the script path, line number, distribution, and a short diagnostic:
126
151
 
127
152
  ```text
128
153
  ::error file=scripts/setup.sh,line=4,title=OpsScript Gate: [alpine:3.20] command not found: apt-get::command not found: apt-get — Alpine normally uses apk instead of apt-get.
129
154
  ```
130
155
 
131
- ### 2. GitHub Step Summary Compatibility Card
132
- A beautifully formatted markdown summary is automatically posted to `$GITHUB_STEP_SUMMARY`:
156
+ ### Step summary
157
+ The action also writes a markdown matrix to `$GITHUB_STEP_SUMMARY`:
133
158
 
134
159
  ```markdown
135
160
  ## 🛡️ OpsScript Gate Compatibility Report
@@ -148,14 +173,14 @@ A beautifully formatted markdown summary is automatically posted to `$GITHUB_STE
148
173
  | `alpine:3.20` | ❌ FAIL | `127` | `0.19s` | ⚠️ Missing command: `apt-get` (line 4)<br>💡 *Alpine normally uses apk instead of apt-get.* |
149
174
 
150
175
  <details>
151
- <summary>📋 <b>Copyable Markdown (Click to expand & copy to PR / Issue)</b></summary>
176
+ <summary><b>Markdown result</b></summary>
152
177
  ...
153
178
  </details>
154
179
  ```
155
180
 
156
181
  ---
157
182
 
158
- ## 🔍 Example: What Static Analysis Misses
183
+ ## Example: runtime behavior that static analysis misses
159
184
 
160
185
  Consider this clean deployment script:
161
186
 
@@ -192,37 +217,38 @@ Failed Distributions - Output Snippets (last 15 lines):
192
217
  sh: line 4: apt-get: not found
193
218
  ```
194
219
 
195
- **Why it failed:** Alpine Linux is musl/BusyBox-based and uses `apk`, not `apt-get`. OpsScript Gate catches the missing command (`exit code 127`) and gives you the exact line number and conservative remediation hint before deployment.
220
+ **Why it failed:** Alpine uses `apk`, not `apt-get`. The report includes the missing command and its line number.
196
221
 
197
222
  ---
198
223
 
199
- ## 🛡️ Why OpsScript Gate?
224
+ ## Scope compared with other checks
200
225
 
201
- ### OpsScript Gate vs ShellCheck vs Custom CI Matrix
226
+ ### OpsScript Gate compared with ShellCheck and a custom CI matrix
202
227
 
203
228
  | Capability | OpsScript Gate | ShellCheck | Handwritten CI Matrix |
204
229
  | :--- | :---: | :---: | :---: |
205
230
  | **Runtime execution** | **Yes** | No (Static AST only) | Yes |
206
231
  | **Real distro environments** | **Yes (Debian, Ubuntu, Alpine)** | No | Yes |
207
232
  | **Preconfigured defaults** | **Yes** | Yes | Requires custom workflow configuration |
208
- | **Hardened container defaults** | **Built-in (`ro`, `cap_drop`, resource limits)** | N/A | User-defined |
233
+ | **Restricted container defaults** | **Built-in (`ro`, `cap_drop`, resource limits)** | N/A | User-defined |
209
234
  | **Anti-hang stdin protection** | **Built-in (`</dev/null`, noninteractive)** | No | User-defined |
210
- | **Line-Level Annotations & Hints** | **Built-in (Zero config)** | Static warnings | User-defined |
235
+ | **Line-Level Annotations & Hints** | **Built-in** | Static warnings | User-defined |
211
236
  | **Parallel Matrix Execution** | **Built-in (`--jobs`)** | N/A | Manual matrix config |
212
237
 
213
- - **ShellCheck** is indispensable for static analysis (syntax, quoting, SC warnings). OpsScript Gate complements it by testing actual execution behavior in real distributions.
214
- - **Handwritten CI Matrix** requires maintaining complex Docker configurations, volume mounts, timeout guards, and log parsers across every project. OpsScript Gate packages this into a single check.
238
+ ShellCheck checks shell syntax and common mistakes. OpsScript Gate runs the script in
239
+ real distributions. A custom CI matrix can do the same job, but each repository must
240
+ maintain its own images, mounts, timeouts, and report handling.
215
241
 
216
242
  ---
217
243
 
218
- ## 🔒 Security Boundaries & Hardened Isolation
244
+ ## Security boundaries and container isolation
219
245
 
220
246
  OpsScript Gate is a runtime compatibility testing tool, **not a security sandbox for hostile or fully untrusted code**. Containers still share the host kernel, so target scripts should be treated accordingly.
221
247
 
222
248
  <details>
223
249
  <summary><strong>View security boundaries and runtime hardening details</strong></summary>
224
250
 
225
- OpsScript Gate applies conservative, restricted container defaults when running scripts:
251
+ The runner uses restricted container defaults:
226
252
 
227
253
  1. **Restricted Container Defaults**:
228
254
  - Containers run with `privileged=False`.
@@ -272,7 +298,7 @@ Use it when you want to know whether a shell script actually runs across the sup
272
298
 
273
299
  ---
274
300
 
275
- ## 📦 Default Test Matrix
301
+ ## Default test matrix
276
302
 
277
303
  | Image | Distribution | Focus |
278
304
  | :--- | :--- | :--- |
@@ -285,7 +311,7 @@ Customize the matrix at any time via `--matrix` or Action input `matrix`.
285
311
 
286
312
  ---
287
313
 
288
- ## 🛠️ CLI Reference
314
+ ## CLI reference
289
315
 
290
316
  ```text
291
317
  usage: opsscript-gate run [-h] [--matrix MATRIX] [-j JOBS] [--timeout TIMEOUT]
@@ -307,6 +333,7 @@ usage: opsscript-gate run [-h] [--matrix MATRIX] [-j JOBS] [--timeout TIMEOUT]
307
333
  | `--mem-limit` | String | `256m` | Memory limit per container (e.g. `256m`, `512m`) |
308
334
  | `--pids-limit`| Integer | `128` | Maximum number of processes per container |
309
335
  | `--network` | Choice | `bridge` | Container network mode: `bridge` or `none` |
336
+ | `--changed-since` | Git revision | - | Test shell scripts changed between this revision and `HEAD` |
310
337
  | `--version` | Flag | - | Show version number |
311
338
  | `-h, --help` | Flag | - | Show argument help |
312
339
 
@@ -338,9 +365,9 @@ usage: opsscript-gate run [-h] [--matrix MATRIX] [-j JOBS] [--timeout TIMEOUT]
338
365
  Explicit CLI options override project settings. Explicit script paths bypass discovery
339
366
  and its exclusions. See [complete configuration semantics](docs/configuration.md).
340
367
 
341
- ## 🌍 Real-World Usage
368
+ ## Downstream example
342
369
 
343
- OpsScript Gate is actively used in [`Mresyzz/linux-dev-bootstrap`](https://github.com/Mresyzz/linux-dev-bootstrap) to validate `install.sh` across the default Debian, Ubuntu, and Alpine matrix in GitHub Actions.
370
+ [`Mresyzz/linux-dev-bootstrap`](https://github.com/Mresyzz/linux-dev-bootstrap) contains a workflow that validates `install.sh` across the default Debian, Ubuntu, and Alpine matrix.
344
371
 
345
372
  See the downstream workflow: [`.github/workflows/test.yml`](https://github.com/Mresyzz/linux-dev-bootstrap/blob/main/.github/workflows/test.yml).
346
373
 
@@ -365,11 +392,9 @@ pytest -v
365
392
 
366
393
  ---
367
394
 
368
- ## 💛 If OpsScript Gate Helps
369
-
370
- If OpsScript Gate catches a compatibility problem in one of your scripts, consider starring the repository so other shell and DevOps maintainers can find it too.
395
+ ## Feedback
371
396
 
372
- Bug reports, real-world compatibility cases, and pull requests are especially welcome.
397
+ Please report compatibility cases, bugs, and pull requests in the issue tracker.
373
398
 
374
399
  ---
375
400