opsscript-gate 0.4.1__tar.gz → 0.5.1__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.
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/.github/workflows/test.yml +15 -2
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/CHANGELOG.md +33 -7
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/PKG-INFO +140 -39
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/README.md +138 -37
- opsscript_gate-0.5.1/README.zh-CN.md +67 -0
- opsscript_gate-0.5.1/action.yml +130 -0
- opsscript_gate-0.5.1/docs/configuration.md +115 -0
- opsscript_gate-0.5.1/docs/troubleshooting.md +67 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/examples/alpine-incompatibility/README.md +2 -1
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/examples/github-actions/README.md +2 -2
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/examples/github-actions/workflow.yml +3 -1
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/pyproject.toml +2 -2
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/src/opsscript_gate/__init__.py +1 -1
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/src/opsscript_gate/cli.py +89 -4
- opsscript_gate-0.5.1/src/opsscript_gate/config.py +78 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/src/opsscript_gate/discovery.py +16 -3
- opsscript_gate-0.5.1/tests/test_action_contract.py +22 -0
- opsscript_gate-0.5.1/tests/test_onboarding.py +133 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/tests/test_runner.py +2 -1
- opsscript_gate-0.4.1/action.yml +0 -90
- opsscript_gate-0.4.1/docs/promotion/awesome-lists-pr.md +0 -59
- opsscript_gate-0.4.1/docs/promotion/juejin-zhihu-article.md +0 -144
- opsscript_gate-0.4.1/docs/promotion/reddit-devops.md +0 -56
- opsscript_gate-0.4.1/docs/promotion/show-hn.md +0 -67
- opsscript_gate-0.4.1/docs/promotion/v2ex-post.md +0 -68
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/.gitattributes +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/.github/ISSUE_TEMPLATE/distro_request.yml +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/.github/assets/social-preview.png +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/.github/pull_request_template.md +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/.github/workflows/demo.yml +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/.github/workflows/release.yml +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/.gitignore +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/CONTRIBUTING.md +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/LICENSE +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/ROADMAP.md +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/SECURITY.md +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/examples/alpine-incompatibility/apt_dependency.sh +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/examples/basic/README.md +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/examples/basic/clean_setup.sh +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/examples/interactive-hang/README.md +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/examples/interactive-hang/prompt_confirm.sh +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/src/opsscript_gate/models.py +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/src/opsscript_gate/remediation.py +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/src/opsscript_gate/reporter.py +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/src/opsscript_gate/runner.py +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/tests/fixtures/fail_deps.sh +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/tests/fixtures/fail_hang.sh +0 -0
- {opsscript_gate-0.4.1 → opsscript_gate-0.5.1}/tests/fixtures/pass_basic.sh +0 -0
|
@@ -8,7 +8,11 @@ on:
|
|
|
8
8
|
|
|
9
9
|
jobs:
|
|
10
10
|
test:
|
|
11
|
-
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
os: [ubuntu-latest, windows-latest]
|
|
14
|
+
python: ['3.10', '3.12']
|
|
15
|
+
runs-on: ${{ matrix.os }}
|
|
12
16
|
steps:
|
|
13
17
|
- name: Checkout Code
|
|
14
18
|
uses: actions/checkout@v7
|
|
@@ -16,7 +20,7 @@ jobs:
|
|
|
16
20
|
- name: Set up Python
|
|
17
21
|
uses: actions/setup-python@v7
|
|
18
22
|
with:
|
|
19
|
-
python-version:
|
|
23
|
+
python-version: ${{ matrix.python }}
|
|
20
24
|
|
|
21
25
|
- name: Install Dependencies
|
|
22
26
|
run: |
|
|
@@ -50,3 +54,12 @@ jobs:
|
|
|
50
54
|
- name: Run Docker Integration Tests
|
|
51
55
|
run: |
|
|
52
56
|
pytest -v -m integration
|
|
57
|
+
|
|
58
|
+
- name: Exercise the local composite Action
|
|
59
|
+
uses: ./
|
|
60
|
+
with:
|
|
61
|
+
script-path: tests/fixtures/pass_basic.sh
|
|
62
|
+
preset: minimal
|
|
63
|
+
network: none
|
|
64
|
+
output: action-report.json
|
|
65
|
+
format: json
|
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.1] - 2026-09-30
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- Published the current README and examples with the v0.5.1 Action tag.
|
|
7
|
+
- Updated package and Action metadata to describe the supported container matrix and runtime compatibility check.
|
|
8
|
+
|
|
9
|
+
## [0.5.0] - 2026-09-24
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- Added `opsscript-gate init` to create a config file and GitHub workflow without replacing existing files.
|
|
13
|
+
- Added `.opsscript-gate.json` with CLI and Action overrides.
|
|
14
|
+
- Added `--dry-run`, `minimal` and `ubuntu` presets, exclusion globs, and `--output` reports.
|
|
15
|
+
- Added configuration, Chinese quickstart, and Ubuntu/Alpine troubleshooting documentation.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- Discovery stops at the first candidate beyond the configured limit instead of silently ignoring files.
|
|
19
|
+
- Discovery skips symlinks and non-files and checks shebangs without prefix matches.
|
|
20
|
+
- CLI validates limits and network modes before execution.
|
|
21
|
+
- Empty Action inputs no longer override project configuration.
|
|
22
|
+
|
|
23
|
+
### Migration
|
|
24
|
+
- Repositories with more than 20 discovered scripts must exclude unwanted scripts or raise `max_scripts`.
|
|
25
|
+
- Auto-discovery no longer follows file symlinks; explicit script paths remain supported.
|
|
26
|
+
- Default settings without a configuration file remain compatible with v0.4.1 and earlier.
|
|
27
|
+
- Generated workflows use the v0.5.0 release tag.
|
|
28
|
+
|
|
3
29
|
All notable changes to this project will be documented in this file.
|
|
4
30
|
|
|
5
31
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
@@ -8,8 +34,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
8
34
|
## [0.4.1] - 2026-09-19
|
|
9
35
|
|
|
10
36
|
### Fixed & Hardened
|
|
11
|
-
-
|
|
12
|
-
-
|
|
37
|
+
- Bounded container log capture with a 256 KiB rolling buffer and 500-line tail.
|
|
38
|
+
- Neutralized untrusted container logs beginning with `::` before they reach GitHub Actions.
|
|
13
39
|
- **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.
|
|
14
40
|
- **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.
|
|
15
41
|
- **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`).
|
|
@@ -22,15 +48,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
22
48
|
## [0.4.0] - 2026-09-19
|
|
23
49
|
|
|
24
50
|
### Added
|
|
25
|
-
-
|
|
51
|
+
- Line-level GitHub Actions annotations with script paths and line numbers.
|
|
26
52
|
- **Workflow command injection defense**: Strictly escapes parameters (`%`, `\r`, `\n`, `:`, `,`) and message bodies (`%`, `\r`, `\n`) to eliminate command injection from unclassified container logs.
|
|
27
|
-
-
|
|
53
|
+
- Distro-aware remediation hints for common mismatches, including:
|
|
28
54
|
- Alpine package manager mismatches (`apt`/`apt-get` -> `apk`)
|
|
29
55
|
- Debian/Ubuntu package manager mismatches (`apk` -> `apt-get`)
|
|
30
56
|
- Alpine minimal missing Bash (`bash` -> consider POSIX sh or installing bash)
|
|
31
57
|
- Missing network prerequisites (`curl`, `wget`)
|
|
32
58
|
- Missing shebang interpreter paths.
|
|
33
|
-
-
|
|
59
|
+
- Updated the GitHub Actions Step Summary with a compatibility table and a Markdown result block.
|
|
34
60
|
- **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.
|
|
35
61
|
- **Hardened container resource limits**: Added `--mem-limit` (default: 256m) and `--pids-limit` (default: 128) flags and Action inputs to prevent runaway resource exhaustion.
|
|
36
62
|
- **Configurable network isolation (`--network`)**: Supports `--network bridge` (default) and `--network none` for offline script execution.
|
|
@@ -47,7 +73,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
47
73
|
|
|
48
74
|
### Added
|
|
49
75
|
- Structured runtime failure diagnostics: detect common "command not found" failures across Linux distributions (Alpine/BusyBox ash, Debian/Ubuntu dash, Bash, and missing interpreter paths).
|
|
50
|
-
-
|
|
76
|
+
- Missing-command classification requires exit code 127 and matching shell output.
|
|
51
77
|
- Additive `diagnostic` field in JSON report format (`SingleResult.to_dict()`) providing structured diagnostic information (backward-compatible for consumers tolerating additional fields).
|
|
52
78
|
- Enhanced terminal table formatting and GitHub Actions Step Summary showing clear failure causes in the summary overview.
|
|
53
79
|
|
|
@@ -81,7 +107,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
81
107
|
### Added
|
|
82
108
|
- Configured PyPI Trusted Publishing via GitHub Actions OIDC (`pypa/gh-action-pypi-publish`).
|
|
83
109
|
- Added full PyPI package metadata, classifiers, and project URLs to `pyproject.toml`.
|
|
84
|
-
- Ensured
|
|
110
|
+
- Ensured asset URLs in `README.md` render correctly on PyPI.
|
|
85
111
|
|
|
86
112
|
---
|
|
87
113
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: opsscript-gate
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Run Linux shell scripts
|
|
3
|
+
Version: 0.5.1
|
|
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
|
|
@@ -26,9 +26,11 @@ Provides-Extra: test
|
|
|
26
26
|
Requires-Dist: pytest>=8.0.0; extra == 'test'
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
28
28
|
|
|
29
|
-
# OpsScript Gate
|
|
29
|
+
# OpsScript Gate — shell script compatibility testing
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
[简体中文](README.zh-CN.md) · [Configuration](docs/configuration.md) · [Troubleshooting](docs/troubleshooting.md)
|
|
32
|
+
|
|
33
|
+
> ShellCheck analyzes shell syntax. OpsScript Gate executes scripts in Linux containers.
|
|
32
34
|
|
|
33
35
|
[](https://github.com/Mresyzz/opsscript-gate/actions/workflows/test.yml)
|
|
34
36
|
[](https://github.com/Mresyzz/opsscript-gate/actions/workflows/demo.yml)
|
|
@@ -39,15 +41,42 @@ Description-Content-Type: text/markdown
|
|
|
39
41
|
[](https://opensource.org/licenses/MIT)
|
|
40
42
|
[](#default-test-matrix)
|
|
41
43
|
|
|
42
|
-
**OpsScript Gate** is a
|
|
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
|
+
|
|
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.
|
|
43
47
|
|
|
44
48
|
---
|
|
45
49
|
|
|
46
|
-
##
|
|
50
|
+
## Current release: v0.5.1
|
|
51
|
+
|
|
52
|
+
The current release includes a project config file, a dry-run plan, presets, exclusions,
|
|
53
|
+
and saved reports. These controls were introduced in v0.5.0; projects on v0.4.1 and
|
|
54
|
+
earlier do not include them.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
opsscript-gate init
|
|
58
|
+
opsscript-gate run --dry-run
|
|
59
|
+
opsscript-gate run --format json --output reports/compatibility.json
|
|
60
|
+
```
|
|
47
61
|
|
|
48
|
-
|
|
62
|
+
`init` creates `.opsscript-gate.json` and a GitHub Actions workflow without replacing
|
|
63
|
+
existing files. Review its exclusions (`tests/*`, `examples/*`) and offline network
|
|
64
|
+
default before running. No Docker is required for `init` or `--dry-run`.
|
|
49
65
|
|
|
50
|
-
|
|
66
|
+
Useful for standalone installers, container entrypoints and release scripts that
|
|
67
|
+
must work on both GNU/Linux and Alpine/BusyBox. Each script runs independently;
|
|
68
|
+
repository files, sibling scripts and project dependencies are **not** mounted.
|
|
69
|
+
See [configuration and migration](docs/configuration.md) and
|
|
70
|
+
[why a shell script works on Ubuntu but fails on Alpine](docs/troubleshooting.md).
|
|
71
|
+
|
|
72
|
+
## Quickstart
|
|
73
|
+
|
|
74
|
+
### In GitHub Actions
|
|
75
|
+
|
|
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.
|
|
51
80
|
|
|
52
81
|
```yaml
|
|
53
82
|
name: Shell Compatibility Gate
|
|
@@ -58,15 +87,16 @@ jobs:
|
|
|
58
87
|
runs-on: ubuntu-latest
|
|
59
88
|
steps:
|
|
60
89
|
- uses: actions/checkout@v7
|
|
61
|
-
- uses: Mresyzz/opsscript-gate@v0.
|
|
90
|
+
- uses: Mresyzz/opsscript-gate@v0.5.1
|
|
62
91
|
```
|
|
63
92
|
|
|
64
|
-
|
|
93
|
+
If `script-path` is omitted, the action discovers shell scripts in the repository.
|
|
94
|
+
Use `opsscript-gate run --dry-run` to inspect the selection before running it.
|
|
65
95
|
|
|
66
96
|
Or test a specific script with custom execution modes:
|
|
67
97
|
|
|
68
98
|
```yaml
|
|
69
|
-
- uses: Mresyzz/opsscript-gate@v0.
|
|
99
|
+
- uses: Mresyzz/opsscript-gate@v0.5.1
|
|
70
100
|
with:
|
|
71
101
|
script-path: scripts/install.sh
|
|
72
102
|
shell: auto
|
|
@@ -88,21 +118,50 @@ opsscript-gate run ./scripts/install.sh
|
|
|
88
118
|
opsscript-gate run
|
|
89
119
|
```
|
|
90
120
|
|
|
121
|
+
### Example: package-manager mismatch
|
|
122
|
+
|
|
123
|
+
Create `install.sh`:
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
#!/bin/sh
|
|
127
|
+
set -e
|
|
128
|
+
apt-get --version
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Then run:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
opsscript-gate run ./install.sh
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
A typical result across the default matrix looks like this:
|
|
138
|
+
|
|
139
|
+
```text
|
|
140
|
+
Debian 12 PASS
|
|
141
|
+
Ubuntu 22.04 PASS
|
|
142
|
+
Ubuntu 24.04 PASS
|
|
143
|
+
Alpine 3.20 FAIL
|
|
144
|
+
|
|
145
|
+
apt-get: not found
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
The script is valid shell, but it assumes a command that is not present in Alpine.
|
|
149
|
+
|
|
91
150
|
---
|
|
92
151
|
|
|
93
|
-
##
|
|
152
|
+
## CI output
|
|
94
153
|
|
|
95
|
-
|
|
154
|
+
The action reports failures in two places:
|
|
96
155
|
|
|
97
|
-
###
|
|
98
|
-
|
|
156
|
+
### GitHub annotations
|
|
157
|
+
Failures include the script path, line number, distribution, and a short diagnostic:
|
|
99
158
|
|
|
100
159
|
```text
|
|
101
160
|
::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.
|
|
102
161
|
```
|
|
103
162
|
|
|
104
|
-
###
|
|
105
|
-
|
|
163
|
+
### Step summary
|
|
164
|
+
The action also writes a markdown matrix to `$GITHUB_STEP_SUMMARY`:
|
|
106
165
|
|
|
107
166
|
```markdown
|
|
108
167
|
## 🛡️ OpsScript Gate Compatibility Report
|
|
@@ -121,14 +180,14 @@ A beautifully formatted markdown summary is automatically posted to `$GITHUB_STE
|
|
|
121
180
|
| `alpine:3.20` | ❌ FAIL | `127` | `0.19s` | ⚠️ Missing command: `apt-get` (line 4)<br>💡 *Alpine normally uses apk instead of apt-get.* |
|
|
122
181
|
|
|
123
182
|
<details>
|
|
124
|
-
<summary
|
|
183
|
+
<summary><b>Markdown result</b></summary>
|
|
125
184
|
...
|
|
126
185
|
</details>
|
|
127
186
|
```
|
|
128
187
|
|
|
129
188
|
---
|
|
130
189
|
|
|
131
|
-
##
|
|
190
|
+
## Example: runtime behavior that static analysis misses
|
|
132
191
|
|
|
133
192
|
Consider this clean deployment script:
|
|
134
193
|
|
|
@@ -165,34 +224,38 @@ Failed Distributions - Output Snippets (last 15 lines):
|
|
|
165
224
|
sh: line 4: apt-get: not found
|
|
166
225
|
```
|
|
167
226
|
|
|
168
|
-
**Why it failed:** Alpine
|
|
227
|
+
**Why it failed:** Alpine uses `apk`, not `apt-get`. The report includes the missing command and its line number.
|
|
169
228
|
|
|
170
229
|
---
|
|
171
230
|
|
|
172
|
-
##
|
|
231
|
+
## Scope compared with other checks
|
|
173
232
|
|
|
174
|
-
### OpsScript Gate
|
|
233
|
+
### OpsScript Gate compared with ShellCheck and a custom CI matrix
|
|
175
234
|
|
|
176
235
|
| Capability | OpsScript Gate | ShellCheck | Handwritten CI Matrix |
|
|
177
236
|
| :--- | :---: | :---: | :---: |
|
|
178
237
|
| **Runtime execution** | **Yes** | No (Static AST only) | Yes |
|
|
179
238
|
| **Real distro environments** | **Yes (Debian, Ubuntu, Alpine)** | No | Yes |
|
|
180
239
|
| **Preconfigured defaults** | **Yes** | Yes | Requires custom workflow configuration |
|
|
181
|
-
| **
|
|
240
|
+
| **Restricted container defaults** | **Built-in (`ro`, `cap_drop`, resource limits)** | N/A | User-defined |
|
|
182
241
|
| **Anti-hang stdin protection** | **Built-in (`</dev/null`, noninteractive)** | No | User-defined |
|
|
183
|
-
| **Line-Level Annotations & Hints** | **Built-in
|
|
242
|
+
| **Line-Level Annotations & Hints** | **Built-in** | Static warnings | User-defined |
|
|
184
243
|
| **Parallel Matrix Execution** | **Built-in (`--jobs`)** | N/A | Manual matrix config |
|
|
185
244
|
|
|
186
|
-
|
|
187
|
-
|
|
245
|
+
ShellCheck checks shell syntax and common mistakes. OpsScript Gate runs the script in
|
|
246
|
+
real distributions. A custom CI matrix can do the same job, but each repository must
|
|
247
|
+
maintain its own images, mounts, timeouts, and report handling.
|
|
188
248
|
|
|
189
249
|
---
|
|
190
250
|
|
|
191
|
-
##
|
|
251
|
+
## Security boundaries and container isolation
|
|
192
252
|
|
|
193
|
-
OpsScript Gate is not a security sandbox for untrusted code
|
|
253
|
+
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.
|
|
194
254
|
|
|
195
|
-
|
|
255
|
+
<details>
|
|
256
|
+
<summary><strong>View security boundaries and runtime hardening details</strong></summary>
|
|
257
|
+
|
|
258
|
+
The runner uses restricted container defaults:
|
|
196
259
|
|
|
197
260
|
1. **Restricted Container Defaults**:
|
|
198
261
|
- Containers run with `privileged=False`.
|
|
@@ -208,25 +271,41 @@ OpsScript Gate applies conservative, restricted container defaults when running
|
|
|
208
271
|
4. **Anti-Hang Deadlock Defense**:
|
|
209
272
|
- Disables TTY and stdin (`stdin_open=False`, `tty=False`).
|
|
210
273
|
- Disconnects standard input: `/bin/sh -c "... /tmp/target_script.sh </dev/null"`.
|
|
211
|
-
- Injects `DEBIAN_FRONTEND=noninteractive` and `CI=true`. Interactive prompts (`read -p`) fail
|
|
274
|
+
- Injects `DEBIAN_FRONTEND=noninteractive` and `CI=true`. Interactive prompts (`read -p`) fail instead of hanging CI runners.
|
|
212
275
|
5. **Hard Timeout & Container Cleanup**:
|
|
213
276
|
- Enforces configurable timeout (default: 60s). Timed-out containers are sent `SIGKILL` and marked `TIMED_OUT`.
|
|
214
277
|
- Container removal is attempted from a `finally` block in normal, failure, and timeout execution paths.
|
|
215
278
|
6. **Bounded Output & Memory Protection**:
|
|
216
|
-
- Captures container logs using
|
|
279
|
+
- Captures container logs using a rolling byte buffer capped at 256 KiB (`MAX_CAPTURED_LOG_BYTES`) and a 500-line tail limit (`MAX_LOG_TAIL_LINES`) to reduce memory-exhaustion risk from runaway output.
|
|
217
280
|
7. **Untrusted Log Neutralization & Terminal Defense**:
|
|
218
281
|
- Neutralizes line-leading workflow commands (`[container] ::`) to prevent forged GitHub Actions annotations in CI runners.
|
|
219
|
-
- Strips ANSI escape sequences and dangerous C0 control characters, and normalizes carriage returns (`\r`) to defeat terminal line
|
|
220
|
-
- Employs context-sensitive escaping (`escape_inline_code`, `escape_markdown_text`, `escape_markdown_table_cell`, `escape_html_text`, `format_safe_code_fence`) to
|
|
282
|
+
- Strips ANSI escape sequences and dangerous C0 control characters, and normalizes carriage returns (`\r`) to defeat terminal line-overwrite spoofing.
|
|
283
|
+
- Employs context-sensitive escaping (`escape_inline_code`, `escape_markdown_text`, `escape_markdown_table_cell`, `escape_html_text`, `format_safe_code_fence`) to protect Step Summary output contexts.
|
|
221
284
|
8. **Command Injection Defense**:
|
|
222
|
-
- OpsScript Gate's own annotations (`::error`) apply strict percent-encoding for
|
|
285
|
+
- OpsScript Gate's own annotations (`::error`) apply strict percent-encoding for workflow-command fields and message bodies.
|
|
223
286
|
9. **Bounded Streaming CRLF & Shebang Defense**:
|
|
224
|
-
- Stream-normalizes
|
|
287
|
+
- Stream-normalizes CRLF in 64 KiB chunks and bounds shebang parsing to 4096 bytes without whole-file memory allocation.
|
|
225
288
|
- Pre-normalizes scripts once before parallel matrix runs, sharing a read-only prepared path across worker threads.
|
|
226
289
|
|
|
290
|
+
For the complete supported-version policy and vulnerability reporting guidance, see [SECURITY.md](SECURITY.md).
|
|
291
|
+
|
|
292
|
+
</details>
|
|
293
|
+
|
|
294
|
+
### When NOT to use OpsScript Gate
|
|
295
|
+
|
|
296
|
+
OpsScript Gate is intentionally focused on Linux shell runtime compatibility. It is not designed for:
|
|
297
|
+
|
|
298
|
+
- executing hostile or fully untrusted third-party scripts
|
|
299
|
+
- kernel-level or privileged behavior testing
|
|
300
|
+
- replacing full integration or end-to-end test suites
|
|
301
|
+
- validating macOS or Windows behavior
|
|
302
|
+
- proving that a script is secure
|
|
303
|
+
|
|
304
|
+
Use it when you want to know whether a shell script actually runs across the supported Linux distributions.
|
|
305
|
+
|
|
227
306
|
---
|
|
228
307
|
|
|
229
|
-
##
|
|
308
|
+
## Default test matrix
|
|
230
309
|
|
|
231
310
|
| Image | Distribution | Focus |
|
|
232
311
|
| :--- | :--- | :--- |
|
|
@@ -239,7 +318,7 @@ Customize the matrix at any time via `--matrix` or Action input `matrix`.
|
|
|
239
318
|
|
|
240
319
|
---
|
|
241
320
|
|
|
242
|
-
##
|
|
321
|
+
## CLI reference
|
|
243
322
|
|
|
244
323
|
```text
|
|
245
324
|
usage: opsscript-gate run [-h] [--matrix MATRIX] [-j JOBS] [--timeout TIMEOUT]
|
|
@@ -276,9 +355,25 @@ usage: opsscript-gate run [-h] [--matrix MATRIX] [-j JOBS] [--timeout TIMEOUT]
|
|
|
276
355
|
|
|
277
356
|
---
|
|
278
357
|
|
|
279
|
-
|
|
358
|
+
### v0.5.0 project controls
|
|
359
|
+
|
|
360
|
+
| Option | Purpose |
|
|
361
|
+
| :--- | :--- |
|
|
362
|
+
| `init` | Generate configuration and a GitHub workflow without overwriting files |
|
|
363
|
+
| `--dry-run` | Preview selected scripts, images and total executions without Docker |
|
|
364
|
+
| `--config PATH` | Load a specific JSON configuration file |
|
|
365
|
+
| `--preset minimal` | Debian + Alpine (two container runs per script) |
|
|
366
|
+
| `--preset ubuntu` | Ubuntu 22.04 + 24.04 |
|
|
367
|
+
| `--exclude 'tests/*'` | Exclude a repository-relative glob; repeatable |
|
|
368
|
+
| `--max-scripts 50` | Raise the default discovery limit of 20; overflow is an error |
|
|
369
|
+
| `--output report.json` | Save the selected output format, including failed test reports |
|
|
370
|
+
|
|
371
|
+
Explicit CLI options override project settings. Explicit script paths bypass discovery
|
|
372
|
+
and its exclusions. See [complete configuration semantics](docs/configuration.md).
|
|
280
373
|
|
|
281
|
-
|
|
374
|
+
## Downstream example
|
|
375
|
+
|
|
376
|
+
[`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.
|
|
282
377
|
|
|
283
378
|
See the downstream workflow: [`.github/workflows/test.yml`](https://github.com/Mresyzz/linux-dev-bootstrap/blob/main/.github/workflows/test.yml).
|
|
284
379
|
|
|
@@ -303,6 +398,12 @@ pytest -v
|
|
|
303
398
|
|
|
304
399
|
---
|
|
305
400
|
|
|
401
|
+
## Feedback
|
|
402
|
+
|
|
403
|
+
Please report compatibility cases, bugs, and pull requests in the issue tracker.
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
306
407
|
## 📄 License
|
|
307
408
|
|
|
308
409
|
OpsScript Gate is licensed under the [MIT License](LICENSE).
|