opsscript-gate 0.9.1__tar.gz → 0.9.4__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.9.1 → opsscript_gate-0.9.4}/.github/workflow-templates/opsscript-gate.yml +1 -1
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/.github/workflows/release.yml +3 -7
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/.gitignore +1 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/CHANGELOG.md +43 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/CITATION.cff +1 -2
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/PKG-INFO +16 -13
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/README.md +12 -10
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/README.zh-CN.md +4 -4
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/action.yml +7 -6
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/demo.html +4 -4
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/docs/command-not-found.html +70 -1
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/docs/command-not-found.md +25 -1
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/docs/configuration.md +7 -4
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/docs/gpt-oss.md +1 -1
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/docs/index.html +20 -4
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/docs/llms.txt +8 -1
- opsscript_gate-0.9.4/docs/robots.txt +3 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/examples/github-actions/README.md +1 -1
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/examples/github-actions/workflow.yml +1 -1
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/index.html +20 -4
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/llms.txt +8 -1
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/pyproject.toml +6 -2
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/src/opsscript_gate/__init__.py +1 -1
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/src/opsscript_gate/cli.py +79 -11
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/src/opsscript_gate/config.py +39 -3
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/src/opsscript_gate/discovery.py +40 -8
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/src/opsscript_gate/models.py +23 -12
- opsscript_gate-0.9.4/src/opsscript_gate/remediation.py +239 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/src/opsscript_gate/reporter.py +116 -56
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/src/opsscript_gate/runner.py +286 -96
- opsscript_gate-0.9.4/tests/conftest.py +17 -0
- opsscript_gate-0.9.4/tests/test_action_contract.py +45 -0
- opsscript_gate-0.9.4/tests/test_audit_coverage.py +577 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/tests/test_onboarding.py +73 -1
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/tests/test_runner.py +459 -7
- opsscript_gate-0.9.1/src/opsscript_gate/remediation.py +0 -104
- opsscript_gate-0.9.1/tests/test_action_contract.py +0 -24
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/.gitattributes +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/.github/ISSUE_TEMPLATE/distro_request.yml +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/.github/assets/social-preview.png +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/.github/pull_request_template.md +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/.github/workflow-templates/opsscript-gate.properties.json +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/.github/workflows/demo.yml +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/.github/workflows/deploy-pages.yml +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/.github/workflows/test.yml +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/CONTRIBUTING.md +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/LICENSE +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/ROADMAP.md +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/SECURITY.md +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/docs/sitemap.xml +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/docs/troubleshooting.md +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/examples/alpine-incompatibility/README.md +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/examples/alpine-incompatibility/apt_dependency.sh +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/examples/basic/README.md +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/examples/basic/clean_setup.sh +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/examples/interactive-hang/README.md +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/examples/interactive-hang/prompt_confirm.sh +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/tests/fixtures/fail_deps.sh +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/tests/fixtures/fail_hang.sh +0 -0
- {opsscript_gate-0.9.1 → opsscript_gate-0.9.4}/tests/fixtures/pass_basic.sh +0 -0
|
@@ -123,16 +123,12 @@ jobs:
|
|
|
123
123
|
TAG_SHA=$(git rev-list -n 1 "$TARGET_TAG")
|
|
124
124
|
echo "Tag $TARGET_TAG already exists, pointing to commit: $TAG_SHA"
|
|
125
125
|
if [ "$TAG_SHA" = "${{ github.sha }}" ]; then
|
|
126
|
-
echo "Tag $TARGET_TAG points to current commit
|
|
127
|
-
IS_NEW_RELEASE="true"
|
|
128
|
-
SHOULD_TAG="false"
|
|
126
|
+
echo "Tag $TARGET_TAG already points to the current commit. The tag workflow owns release publication."
|
|
129
127
|
else
|
|
130
128
|
echo "Tag $TARGET_TAG was released from earlier commit ($TAG_SHA != ${{ github.sha }}). Skipping release."
|
|
131
|
-
IS_NEW_RELEASE="false"
|
|
132
|
-
SHOULD_TAG="false"
|
|
133
129
|
fi
|
|
134
130
|
else
|
|
135
|
-
echo "Target tag $TARGET_TAG does not exist.
|
|
131
|
+
echo "Target tag $TARGET_TAG does not exist. Creating tag and publishing release."
|
|
136
132
|
IS_NEW_RELEASE="true"
|
|
137
133
|
SHOULD_TAG="true"
|
|
138
134
|
fi
|
|
@@ -171,7 +167,7 @@ jobs:
|
|
|
171
167
|
retention-days: 7
|
|
172
168
|
|
|
173
169
|
- name: Create and push Git tag
|
|
174
|
-
if: steps.release-check.outputs.
|
|
170
|
+
if: steps.release-check.outputs.should_tag == 'true'
|
|
175
171
|
shell: bash
|
|
176
172
|
run: |
|
|
177
173
|
TARGET_TAG="${{ steps.release-check.outputs.release_tag }}"
|
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.9.4] - 2026-10-11
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Fixed release workflow publishing deadlock where `main` pushes skipped distribution package builds and release creation due to GITHUB_TOKEN tag events not triggering new workflows.
|
|
7
|
+
- Unified command path extraction in remediation rules to ensure full-path commands (e.g. `/usr/bin/apt-get`, `/sbin/apk`, `/bin/yum`, `/usr/local/bin/bash`) accurately match package manager and shell hints.
|
|
8
|
+
- Added native RHEL/Fedora/CentOS package mappings in `COMMON_COMMAND_PACKAGES` to prevent fallback to invalid Debian package names.
|
|
9
|
+
- Added native container package pre-installation support for `dnf`, `microdnf`, and `yum` in `runner._wrap_with_package_setup`.
|
|
10
|
+
- Fixed `RunReport` and `MultiScriptReport` `__post_init__` to preserve explicitly passed `all_passed=False` when result collections are empty.
|
|
11
|
+
- Supported bare directory exclusions (e.g. `tests` or `tests/`) in `_matches_exclude` to match both directories and all contained files.
|
|
12
|
+
|
|
13
|
+
## [0.9.3] - 2026-10-11
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- Added cross-distribution package name mapping and actionable remediation suggestions (`apt-get`, `apk`, `dnf`) for common missing operations commands (`curl`, `wget`, `jq`, `git`, `tar`, `python3`, `pip`, `sudo`, `make`, `gcc`, etc.).
|
|
17
|
+
- Extended `FailureDiagnostic` and SARIF output with structured `suggested_package` property.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- Fixed unreadable shell script candidate misclassification during discovery.
|
|
21
|
+
- Ensured temporary script files are safely cleaned up during distribution preparation errors.
|
|
22
|
+
- Added preflight validation to reject directory and missing script paths before creating worker threads.
|
|
23
|
+
- Enforced consistent POSIX LF line endings in report output files across platforms.
|
|
24
|
+
|
|
25
|
+
## [0.9.2] - 2026-10-05
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- Hardened SARIF, Markdown, terminal, and machine-readable output handling.
|
|
29
|
+
- Prevented false package-setup errors, stale Docker wait results, hard-link overwrites, and unbounded log copies.
|
|
30
|
+
- Added BOM-aware discovery, Windows exclusion normalization, bounded concurrency, and runtime option validation.
|
|
31
|
+
- Added a one-CPU container limit and bounded Docker log rotation, while keeping disposable container filesystems writable for installers.
|
|
32
|
+
- Normalized SARIF paths, preserved actionable repeat-run diagnostics, skipped hidden auto-discovered files, and kept terminal reports visible when file output fails.
|
|
33
|
+
- Fixed release workflow tag handoff so a `main` push cannot publish the same version twice.
|
|
34
|
+
- Made `doctor` reject Docker's Windows-container mode before Linux image checks begin.
|
|
35
|
+
- Added problem-first FAQ content, structured data, canonical URLs, and AI-readable answers for runtime compatibility searches.
|
|
36
|
+
- Bounded repeat runs to 20 attempts per distribution to prevent accidental unbounded container work and result retention.
|
|
37
|
+
- Bounded per-container timeouts to one hour so fallback polling cannot wait indefinitely on an extreme configuration.
|
|
38
|
+
- Bounded custom matrices to 32 images so a single configuration cannot create unbounded container work.
|
|
39
|
+
- Fixed `_is_ignored_path` in script discovery to avoid misclassifying paths with leading `./` as ignored.
|
|
40
|
+
- Traversed exception cause chains in `_is_wait_timeout_error` to reliably identify nested Docker wait timeouts.
|
|
41
|
+
- Protected container reload against network jitter to preserve valid exit codes.
|
|
42
|
+
- Added early validation for CLI `--output` to reject existing directories before executing test matrices.
|
|
43
|
+
- Expanded cross-distro package manager diagnostics and added remediation for path-qualified curl/wget and missing sudo.
|
|
44
|
+
- Refreshed active workflow templates, examples, and documentation to `v0.9.2`.
|
|
45
|
+
|
|
3
46
|
## [0.9.1] - 2026-10-03
|
|
4
47
|
|
|
5
48
|
### Fixed
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: opsscript-gate
|
|
3
|
-
Version: 0.9.
|
|
4
|
-
Summary: Cross-distro shell script compatibility checker for
|
|
3
|
+
Version: 0.9.4
|
|
4
|
+
Summary: Cross-distro shell script compatibility and portability checker for Debian, Ubuntu, and Alpine. Runs real containers to diagnose command not found.
|
|
5
5
|
Project-URL: Homepage, https://mresyzz.github.io/opsscript-gate/
|
|
6
6
|
Project-URL: Demo, https://mresyzz.github.io/opsscript-gate/
|
|
7
7
|
Project-URL: Repository, https://github.com/Mresyzz/opsscript-gate
|
|
@@ -12,7 +12,7 @@ Project-URL: Troubleshooting, https://github.com/Mresyzz/opsscript-gate/blob/mai
|
|
|
12
12
|
Author: Mresyzz
|
|
13
13
|
License: MIT
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Keywords: alpine,apk,apt-get,bashisms,bootstrap,busybox,ci,command-not-found,compatibility,cross-distro,debian,devops,docker,github-actions,installer,installer-testing,linux,portable-shell,posix,runtime-compatibility,shell,shell-portability,shell-script-testing,shellcheck,shellcheck-alternative,testing,ubuntu
|
|
15
|
+
Keywords: alpine,apk,apt-get,bashisms,bootstrap,busybox,ci,command-not-found,compatibility,cross-distro,debian,devops,distribution-compatibility,docker,github-actions,installer,installer-testing,linux,portable-shell,posix,real-container-testing,runtime-compatibility,shell,shell-portability,shell-runtime,shell-script-testing,shellcheck,shellcheck-alternative,testing,ubuntu
|
|
16
16
|
Classifier: Development Status :: 4 - Beta
|
|
17
17
|
Classifier: Intended Audience :: Developers
|
|
18
18
|
Classifier: Intended Audience :: System Administrators
|
|
@@ -26,6 +26,7 @@ Classifier: Topic :: System :: Systems Administration
|
|
|
26
26
|
Requires-Python: >=3.10
|
|
27
27
|
Requires-Dist: docker>=7.0.0
|
|
28
28
|
Provides-Extra: test
|
|
29
|
+
Requires-Dist: markdown-it-py>=3.0.0; extra == 'test'
|
|
29
30
|
Requires-Dist: pytest>=8.0.0; extra == 'test'
|
|
30
31
|
Description-Content-Type: text/markdown
|
|
31
32
|
|
|
@@ -79,7 +80,7 @@ apt-get --version
|
|
|
79
80
|
Run it locally with `opsscript-gate run ./install.sh`, or add the following step to CI:
|
|
80
81
|
|
|
81
82
|
```yaml
|
|
82
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
83
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
83
84
|
with:
|
|
84
85
|
script-path: install.sh
|
|
85
86
|
```
|
|
@@ -88,7 +89,7 @@ The result identifies the failing distribution, exit code, line, missing command
|
|
|
88
89
|
|
|
89
90
|
---
|
|
90
91
|
|
|
91
|
-
## Current
|
|
92
|
+
## Current version: v0.9.2 (local candidate)
|
|
92
93
|
|
|
93
94
|
The current release includes a project config file, a dry-run plan, presets, exclusions,
|
|
94
95
|
saved reports, changed-script selection for pull requests, and repeat runs for detecting
|
|
@@ -142,7 +143,7 @@ jobs:
|
|
|
142
143
|
- uses: actions/checkout@v7
|
|
143
144
|
with:
|
|
144
145
|
persist-credentials: false
|
|
145
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
146
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
146
147
|
```
|
|
147
148
|
|
|
148
149
|
This zero-configuration form discovers shell scripts in the repository. Use
|
|
@@ -153,7 +154,7 @@ repository has a single installer. For self-hosted model installers, see the
|
|
|
153
154
|
Or test a specific script with custom execution modes:
|
|
154
155
|
|
|
155
156
|
```yaml
|
|
156
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
157
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
157
158
|
with:
|
|
158
159
|
script-path: scripts/install.sh
|
|
159
160
|
shell: auto
|
|
@@ -187,7 +188,7 @@ unrelated scripts:
|
|
|
187
188
|
with:
|
|
188
189
|
persist-credentials: false
|
|
189
190
|
fetch-depth: 0
|
|
190
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
191
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
191
192
|
with:
|
|
192
193
|
changed-since: ${{ github.event.pull_request.base.sha }}
|
|
193
194
|
preset: minimal
|
|
@@ -199,8 +200,8 @@ container. The same selection can be previewed locally with
|
|
|
199
200
|
|
|
200
201
|
### Detect intermittent runtime failures
|
|
201
202
|
|
|
202
|
-
Use `--repeat N` when a script sometimes passes and sometimes fails in CI.
|
|
203
|
-
Gate runs each distribution N times and reports `FLAKY` when the same distribution has
|
|
203
|
+
Use `--repeat N` when a script sometimes passes and sometimes fails in CI. Values from
|
|
204
|
+
1 through 20 are accepted. OpsScript Gate runs each distribution N times and reports `FLAKY` when the same distribution has
|
|
204
205
|
both passing and failing attempts. The JSON, Markdown, SARIF, annotations, and step
|
|
205
206
|
summary include the attempt counts so a retry cannot silently turn an unstable script
|
|
206
207
|
green.
|
|
@@ -278,7 +279,7 @@ Use `sarif` when the result should appear in GitHub Code Scanning or another
|
|
|
278
279
|
SARIF-compatible viewer. Upload it explicitly with the official upload action:
|
|
279
280
|
|
|
280
281
|
```yaml
|
|
281
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
282
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
282
283
|
with:
|
|
283
284
|
script-path: scripts/install.sh
|
|
284
285
|
format: sarif
|
|
@@ -373,9 +374,11 @@ The runner uses restricted container defaults:
|
|
|
373
374
|
2. **Resource Constraints**:
|
|
374
375
|
- Memory limits enforced per container (`--mem-limit`, default: `256m`).
|
|
375
376
|
- Process caps enforced to prevent fork bombs (`--pids-limit`, default: `128`).
|
|
377
|
+
- CPU is capped at one host CPU per container and Docker's JSON log driver rotates logs.
|
|
376
378
|
- Network isolation configurable (`--network bridge` or `--network none`).
|
|
377
379
|
3. **Read-Only Target Mount**:
|
|
378
380
|
- The tested script is mounted read-only (`:ro`) at `/tmp/target_script.sh`.
|
|
381
|
+
- The disposable container root remains writable so installers can create files during a real run.
|
|
379
382
|
- No host directories or sensitive sockets are mounted into test containers.
|
|
380
383
|
4. **Anti-Hang Deadlock Defense**:
|
|
381
384
|
- Disables TTY and stdin (`stdin_open=False`, `tty=False`).
|
|
@@ -448,8 +451,8 @@ usage: opsscript-gate run [-h] [--matrix MATRIX] [-j JOBS] [--timeout TIMEOUT]
|
|
|
448
451
|
| :--- | :--- | :--- | :--- |
|
|
449
452
|
| `script_path` | Positional | *Optional* | Path to target shell script (auto-discovers if omitted) |
|
|
450
453
|
| `-j, --jobs` | Integer | `min(2, size)` | Number of concurrent container jobs |
|
|
451
|
-
| `--matrix` | String | `debian:12-slim,ubuntu:22.04,ubuntu:24.04,alpine:3.20` | Comma-separated list of Docker images |
|
|
452
|
-
| `--timeout` | Integer | `60` | Hard timeout per container in seconds |
|
|
454
|
+
| `--matrix` | String | `debian:12-slim,ubuntu:22.04,ubuntu:24.04,alpine:3.20` | Comma-separated list of Docker images (maximum `32`) |
|
|
455
|
+
| `--timeout` | Integer | `60` | Hard timeout per container in seconds (maximum `3600`) |
|
|
453
456
|
| `--format` | Choice | `table` | Output format: `table`, `markdown`, `json`, or `sarif` |
|
|
454
457
|
| `--shell` | Choice | `posix` | Execution mode: `posix` (default), `shebang`, or `auto` |
|
|
455
458
|
| `--mem-limit` | String | `256m` | Memory limit per container (e.g. `256m`, `512m`) |
|
|
@@ -48,7 +48,7 @@ apt-get --version
|
|
|
48
48
|
Run it locally with `opsscript-gate run ./install.sh`, or add the following step to CI:
|
|
49
49
|
|
|
50
50
|
```yaml
|
|
51
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
51
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
52
52
|
with:
|
|
53
53
|
script-path: install.sh
|
|
54
54
|
```
|
|
@@ -57,7 +57,7 @@ The result identifies the failing distribution, exit code, line, missing command
|
|
|
57
57
|
|
|
58
58
|
---
|
|
59
59
|
|
|
60
|
-
## Current
|
|
60
|
+
## Current version: v0.9.2 (local candidate)
|
|
61
61
|
|
|
62
62
|
The current release includes a project config file, a dry-run plan, presets, exclusions,
|
|
63
63
|
saved reports, changed-script selection for pull requests, and repeat runs for detecting
|
|
@@ -111,7 +111,7 @@ jobs:
|
|
|
111
111
|
- uses: actions/checkout@v7
|
|
112
112
|
with:
|
|
113
113
|
persist-credentials: false
|
|
114
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
114
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
This zero-configuration form discovers shell scripts in the repository. Use
|
|
@@ -122,7 +122,7 @@ repository has a single installer. For self-hosted model installers, see the
|
|
|
122
122
|
Or test a specific script with custom execution modes:
|
|
123
123
|
|
|
124
124
|
```yaml
|
|
125
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
125
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
126
126
|
with:
|
|
127
127
|
script-path: scripts/install.sh
|
|
128
128
|
shell: auto
|
|
@@ -156,7 +156,7 @@ unrelated scripts:
|
|
|
156
156
|
with:
|
|
157
157
|
persist-credentials: false
|
|
158
158
|
fetch-depth: 0
|
|
159
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
159
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
160
160
|
with:
|
|
161
161
|
changed-since: ${{ github.event.pull_request.base.sha }}
|
|
162
162
|
preset: minimal
|
|
@@ -168,8 +168,8 @@ container. The same selection can be previewed locally with
|
|
|
168
168
|
|
|
169
169
|
### Detect intermittent runtime failures
|
|
170
170
|
|
|
171
|
-
Use `--repeat N` when a script sometimes passes and sometimes fails in CI.
|
|
172
|
-
Gate runs each distribution N times and reports `FLAKY` when the same distribution has
|
|
171
|
+
Use `--repeat N` when a script sometimes passes and sometimes fails in CI. Values from
|
|
172
|
+
1 through 20 are accepted. OpsScript Gate runs each distribution N times and reports `FLAKY` when the same distribution has
|
|
173
173
|
both passing and failing attempts. The JSON, Markdown, SARIF, annotations, and step
|
|
174
174
|
summary include the attempt counts so a retry cannot silently turn an unstable script
|
|
175
175
|
green.
|
|
@@ -247,7 +247,7 @@ Use `sarif` when the result should appear in GitHub Code Scanning or another
|
|
|
247
247
|
SARIF-compatible viewer. Upload it explicitly with the official upload action:
|
|
248
248
|
|
|
249
249
|
```yaml
|
|
250
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
250
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
251
251
|
with:
|
|
252
252
|
script-path: scripts/install.sh
|
|
253
253
|
format: sarif
|
|
@@ -342,9 +342,11 @@ The runner uses restricted container defaults:
|
|
|
342
342
|
2. **Resource Constraints**:
|
|
343
343
|
- Memory limits enforced per container (`--mem-limit`, default: `256m`).
|
|
344
344
|
- Process caps enforced to prevent fork bombs (`--pids-limit`, default: `128`).
|
|
345
|
+
- CPU is capped at one host CPU per container and Docker's JSON log driver rotates logs.
|
|
345
346
|
- Network isolation configurable (`--network bridge` or `--network none`).
|
|
346
347
|
3. **Read-Only Target Mount**:
|
|
347
348
|
- The tested script is mounted read-only (`:ro`) at `/tmp/target_script.sh`.
|
|
349
|
+
- The disposable container root remains writable so installers can create files during a real run.
|
|
348
350
|
- No host directories or sensitive sockets are mounted into test containers.
|
|
349
351
|
4. **Anti-Hang Deadlock Defense**:
|
|
350
352
|
- Disables TTY and stdin (`stdin_open=False`, `tty=False`).
|
|
@@ -417,8 +419,8 @@ usage: opsscript-gate run [-h] [--matrix MATRIX] [-j JOBS] [--timeout TIMEOUT]
|
|
|
417
419
|
| :--- | :--- | :--- | :--- |
|
|
418
420
|
| `script_path` | Positional | *Optional* | Path to target shell script (auto-discovers if omitted) |
|
|
419
421
|
| `-j, --jobs` | Integer | `min(2, size)` | Number of concurrent container jobs |
|
|
420
|
-
| `--matrix` | String | `debian:12-slim,ubuntu:22.04,ubuntu:24.04,alpine:3.20` | Comma-separated list of Docker images |
|
|
421
|
-
| `--timeout` | Integer | `60` | Hard timeout per container in seconds |
|
|
422
|
+
| `--matrix` | String | `debian:12-slim,ubuntu:22.04,ubuntu:24.04,alpine:3.20` | Comma-separated list of Docker images (maximum `32`) |
|
|
423
|
+
| `--timeout` | Integer | `60` | Hard timeout per container in seconds (maximum `3600`) |
|
|
422
424
|
| `--format` | Choice | `table` | Output format: `table`, `markdown`, `json`, or `sarif` |
|
|
423
425
|
| `--shell` | Choice | `posix` | Execution mode: `posix` (default), `shebang`, or `auto` |
|
|
424
426
|
| `--mem-limit` | String | `256m` | Memory limit per container (e.g. `256m`, `512m`) |
|
|
@@ -17,9 +17,9 @@ Bash 依赖、包管理器假设和交互式阻塞。它与 ShellCheck 互补。
|
|
|
17
17
|
|
|
18
18
|
也可以直接打开 [OpsScript Gate 在线演示](https://mresyzz.github.io/opsscript-gate/),先查看 ShellCheck 与运行时验证的差异,再复制 workflow 到自己的仓库。
|
|
19
19
|
|
|
20
|
-
## 当前版本 v0.9.
|
|
20
|
+
## 当前版本 v0.9.2
|
|
21
21
|
|
|
22
|
-
v0.9.
|
|
22
|
+
v0.9.2 是当前本地候选版本;如果你要从源码验证当前分支,也可以执行:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
25
|
pip install -e .
|
|
@@ -35,7 +35,7 @@ opsscript-gate run --dry-run
|
|
|
35
35
|
opsscript-gate run --format json --output reports/compatibility.json
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
`init` 生成配置和 GitHub 工作流,不覆盖已有文件。工作流引用 `v0.9.
|
|
38
|
+
`init` 生成配置和 GitHub 工作流,不覆盖已有文件。工作流引用 `v0.9.2`。
|
|
39
39
|
预览不需要 Docker;真实运行需要 Python 3.10+
|
|
40
40
|
和可访问的 Linux Docker 引擎。
|
|
41
41
|
`opsscript-gate doctor` 可以在真实运行前检查 Python 和 Docker。
|
|
@@ -74,7 +74,7 @@ Docker daemon 和可选的项目配置。
|
|
|
74
74
|
- uses: actions/checkout@v7
|
|
75
75
|
with:
|
|
76
76
|
fetch-depth: 0
|
|
77
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
77
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
78
78
|
with:
|
|
79
79
|
changed-since: ${{ github.event.pull_request.base.sha }}
|
|
80
80
|
preset: minimal
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
name: 'OpsScript Gate'
|
|
2
|
-
description: 'Cross-distro shell script compatibility checker for
|
|
2
|
+
description: 'Cross-distro shell script compatibility and portability checker for Debian, Ubuntu, and Alpine. Runs real containers to diagnose command not found.'
|
|
3
3
|
author: 'Mresyzz'
|
|
4
4
|
branding:
|
|
5
5
|
icon: 'shield'
|
|
@@ -11,7 +11,7 @@ inputs:
|
|
|
11
11
|
required: false
|
|
12
12
|
default: ''
|
|
13
13
|
matrix:
|
|
14
|
-
description: 'Comma-separated container images to test (e.g. debian:12-slim,ubuntu:22.04,ubuntu:24.04,alpine:3.20)'
|
|
14
|
+
description: 'Comma-separated container images to test (maximum: 32; e.g. debian:12-slim,ubuntu:22.04,ubuntu:24.04,alpine:3.20)'
|
|
15
15
|
required: false
|
|
16
16
|
default: ''
|
|
17
17
|
jobs:
|
|
@@ -19,11 +19,11 @@ inputs:
|
|
|
19
19
|
required: false
|
|
20
20
|
default: ''
|
|
21
21
|
timeout:
|
|
22
|
-
description: 'Hard timeout in seconds per container (default: 60)'
|
|
22
|
+
description: 'Hard timeout in seconds per container (default: 60, maximum: 3600)'
|
|
23
23
|
required: false
|
|
24
24
|
default: ''
|
|
25
25
|
repeat:
|
|
26
|
-
description: 'Repeat each distribution run to detect flaky runtime behavior (default: 1)'
|
|
26
|
+
description: 'Repeat each distribution run to detect flaky runtime behavior (default: 1, maximum: 20)'
|
|
27
27
|
required: false
|
|
28
28
|
default: ''
|
|
29
29
|
format:
|
|
@@ -139,9 +139,10 @@ runs:
|
|
|
139
139
|
pattern="${pattern%$'\r'}"
|
|
140
140
|
[ -z "$pattern" ] || ARGS+=("--exclude" "$pattern")
|
|
141
141
|
done <<< "$INPUT_EXCLUDE"
|
|
142
|
-
|
|
142
|
+
DRY_RUN_VALUE="$(printf '%s' "$INPUT_DRY_RUN" | tr '[:upper:]' '[:lower:]')"
|
|
143
|
+
if [ "$DRY_RUN_VALUE" = "true" ]; then
|
|
143
144
|
ARGS+=("--dry-run")
|
|
144
|
-
elif [ "$
|
|
145
|
+
elif [ "$DRY_RUN_VALUE" != "false" ]; then
|
|
145
146
|
echo "dry-run must be true or false" >&2
|
|
146
147
|
exit 1
|
|
147
148
|
fi
|
|
@@ -232,7 +232,7 @@
|
|
|
232
232
|
OpsScript Gate
|
|
233
233
|
</span>
|
|
234
234
|
<span class="font-mono text-[11px] px-1.5 py-0.5 rounded bg-[var(--surface-muted)] text-[var(--text-muted)] border border-[var(--border-light)]">
|
|
235
|
-
v0.9.
|
|
235
|
+
v0.9.2
|
|
236
236
|
</span>
|
|
237
237
|
</div>
|
|
238
238
|
</div>
|
|
@@ -367,7 +367,7 @@
|
|
|
367
367
|
<div class="panel-card p-4 flex flex-col justify-between space-y-3">
|
|
368
368
|
<div class="space-y-2.5">
|
|
369
369
|
<div class="flex items-center justify-between border-b border-[var(--border-light)] pb-2">
|
|
370
|
-
<span class="font-mono text-xs font-medium text-[var(--text-muted)]">OpsScript Gate Runtime (v0.9.
|
|
370
|
+
<span class="font-mono text-xs font-medium text-[var(--text-muted)]">OpsScript Gate Runtime (v0.9.2)</span>
|
|
371
371
|
<span id="ops-status" class="font-mono text-xs font-semibold px-2 py-0.5 rounded border">
|
|
372
372
|
1 DISTRO FAILED
|
|
373
373
|
</span>
|
|
@@ -536,7 +536,7 @@
|
|
|
536
536
|
<span class="font-semibold text-[var(--text-hero)]">steps:</span>
|
|
537
537
|
- <span class="font-semibold text-[var(--text-hero)]">uses:</span> actions/checkout@v4
|
|
538
538
|
- <span class="font-semibold text-[var(--text-hero)]">name:</span> Validate scripts across distributions
|
|
539
|
-
<span class="font-semibold text-[var(--brand)]">uses:</span> Mresyzz/opsscript-gate@v0.9.
|
|
539
|
+
<span class="font-semibold text-[var(--brand)]">uses:</span> Mresyzz/opsscript-gate@v0.9.2
|
|
540
540
|
<span class="font-semibold text-[var(--text-hero)]">with:</span>
|
|
541
541
|
<span class="text-[var(--text-body)]">script-path:</span> ./install.sh
|
|
542
542
|
<span class="text-[var(--text-body)]">shell:</span> auto
|
|
@@ -604,7 +604,7 @@ jobs:
|
|
|
604
604
|
steps:
|
|
605
605
|
- uses: actions/checkout@v4
|
|
606
606
|
- name: Validate scripts across distributions
|
|
607
|
-
uses: Mresyzz/opsscript-gate@v0.9.
|
|
607
|
+
uses: Mresyzz/opsscript-gate@v0.9.2
|
|
608
608
|
with:
|
|
609
609
|
script-path: ./install.sh
|
|
610
610
|
shell: auto
|
|
@@ -5,6 +5,61 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<title>Test shell scripts in Debian, Ubuntu and Alpine: command not found | OpsScript Gate</title>
|
|
7
7
|
<meta name="description" content="Test a shell installer in real Debian, Ubuntu and Alpine containers. Diagnose command not found, exit code 127 and missing Bash with OpsScript Gate, a GitHub Action and CLI.">
|
|
8
|
+
<script type="application/ld+json">
|
|
9
|
+
{
|
|
10
|
+
"@context": "https://schema.org",
|
|
11
|
+
"@type": "SoftwareApplication",
|
|
12
|
+
"name": "OpsScript Gate",
|
|
13
|
+
"applicationCategory": "DeveloperApplication",
|
|
14
|
+
"operatingSystem": "Linux",
|
|
15
|
+
"description": "Run shell scripts in real Debian, Ubuntu, and Alpine containers to diagnose command not found and cross-distro runtime failures.",
|
|
16
|
+
"url": "https://mresyzz.github.io/opsscript-gate/command-not-found.html",
|
|
17
|
+
"codeRepository": "https://github.com/Mresyzz/opsscript-gate",
|
|
18
|
+
"downloadUrl": "https://pypi.org/project/opsscript-gate/",
|
|
19
|
+
"isAccessibleForFree": true,
|
|
20
|
+
"license": "https://opensource.org/licenses/MIT"
|
|
21
|
+
}
|
|
22
|
+
</script>
|
|
23
|
+
<script type="application/ld+json">
|
|
24
|
+
{
|
|
25
|
+
"@context": "https://schema.org",
|
|
26
|
+
"@type": "FAQPage",
|
|
27
|
+
"mainEntity": [
|
|
28
|
+
{
|
|
29
|
+
"@type": "Question",
|
|
30
|
+
"name": "How do I test a shell script on Debian, Ubuntu, and Alpine?",
|
|
31
|
+
"acceptedAnswer": {
|
|
32
|
+
"@type": "Answer",
|
|
33
|
+
"text": "Add the OpsScript Gate GitHub Action or install the Python CLI, then run the script in real Debian, Ubuntu, and Alpine containers. The report shows the failing image, exit code, line, and missing command."
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"@type": "Question",
|
|
38
|
+
"name": "Why can ShellCheck pass while a shell installer still fails with command not found?",
|
|
39
|
+
"acceptedAnswer": {
|
|
40
|
+
"@type": "Answer",
|
|
41
|
+
"text": "ShellCheck analyzes shell source and syntax. It does not know which binaries are installed in the runtime image. OpsScript Gate executes the script so missing commands and package-manager assumptions appear in the target distribution."
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"@type": "Question",
|
|
46
|
+
"name": "How do I diagnose apt-get not found on Alpine?",
|
|
47
|
+
"acceptedAnswer": {
|
|
48
|
+
"@type": "Answer",
|
|
49
|
+
"text": "Alpine normally uses apk rather than apt-get. Run the installer across the matrix and branch on the package manager or document a distribution-specific prerequisite."
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"@type": "Question",
|
|
54
|
+
"name": "Can I run the cross-distro shell check without GitHub Actions?",
|
|
55
|
+
"acceptedAnswer": {
|
|
56
|
+
"@type": "Answer",
|
|
57
|
+
"text": "Yes. Install opsscript-gate from PyPI, ensure a Docker engine running Linux containers is reachable, and run opsscript-gate run ./install.sh."
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
</script>
|
|
8
63
|
<link rel="canonical" href="https://mresyzz.github.io/opsscript-gate/command-not-found.html">
|
|
9
64
|
<meta property="og:title" content="ShellCheck passed. Does your installer run on Alpine?">
|
|
10
65
|
<meta property="og:description" content="A reproducible shell runtime compatibility check for Debian, Ubuntu and Alpine, with a copyable GitHub Actions workflow.">
|
|
@@ -79,7 +134,7 @@ jobs:
|
|
|
79
134
|
- uses: actions/checkout@v7
|
|
80
135
|
with:
|
|
81
136
|
persist-credentials: false
|
|
82
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
137
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
83
138
|
with:
|
|
84
139
|
script-path: install.sh
|
|
85
140
|
shell: auto
|
|
@@ -113,6 +168,20 @@ opsscript-gate run ./install.sh</code></pre>
|
|
|
113
168
|
<p>OpsScript Gate mounts each script independently. Sibling files and repository dependencies are not mounted.
|
|
114
169
|
These are distribution user-space tests in containers, not separate Linux kernels or full-machine tests.
|
|
115
170
|
Passing checks do not prove security or replace project integration tests.</p>
|
|
171
|
+
|
|
172
|
+
<h2 id="faq">Frequently asked questions</h2>
|
|
173
|
+
<h3>How do I test a shell script on Debian, Ubuntu, and Alpine?</h3>
|
|
174
|
+
<p>Add the GitHub Action or install the CLI, then run the script in real containers for each distribution.
|
|
175
|
+
The report identifies the failing image, exit code, line, and missing command.</p>
|
|
176
|
+
<h3>Why can ShellCheck pass while the installer still fails?</h3>
|
|
177
|
+
<p>ShellCheck analyzes source and syntax. It cannot know which binaries are installed in the image that
|
|
178
|
+
executes the script. Runtime execution exposes missing commands and package-manager assumptions.</p>
|
|
179
|
+
<h3>How do I diagnose <code>apt-get: not found</code> on Alpine?</h3>
|
|
180
|
+
<p>Alpine normally uses <code>apk</code>. Detect the available package manager or document a distribution-specific
|
|
181
|
+
prerequisite instead of assuming Debian's APT exists everywhere.</p>
|
|
182
|
+
<h3>Can I run the check without GitHub Actions?</h3>
|
|
183
|
+
<p>Yes. Install <code>opsscript-gate</code> from PyPI, make sure a Docker engine running Linux containers is
|
|
184
|
+
reachable, and run <code>opsscript-gate run ./install.sh</code>.</p>
|
|
116
185
|
<footer>Read the <a href="https://github.com/Mresyzz/opsscript-gate/blob/main/docs/configuration.md">configuration guide</a>,
|
|
117
186
|
<a href="https://github.com/Mresyzz/opsscript-gate/blob/main/docs/troubleshooting.md">troubleshooting</a>,
|
|
118
187
|
or <a href="https://github.com/Mresyzz/opsscript-gate/blob/main/SECURITY.md">security boundaries</a>.
|
|
@@ -25,7 +25,7 @@ jobs:
|
|
|
25
25
|
- uses: actions/checkout@v7
|
|
26
26
|
with:
|
|
27
27
|
persist-credentials: false
|
|
28
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
28
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
29
29
|
with:
|
|
30
30
|
script-path: scripts/install.sh
|
|
31
31
|
shell: auto
|
|
@@ -117,3 +117,27 @@ run in the Linux environments we support?**
|
|
|
117
117
|
|
|
118
118
|
See the [Alpine incompatibility example](../examples/alpine-incompatibility/README.md),
|
|
119
119
|
[troubleshooting guide](troubleshooting.md), or the [interactive demo](https://mresyzz.github.io/opsscript-gate/).
|
|
120
|
+
|
|
121
|
+
## Frequently asked questions
|
|
122
|
+
|
|
123
|
+
### How do I test a shell script on Debian, Ubuntu, and Alpine?
|
|
124
|
+
|
|
125
|
+
Add the OpsScript Gate GitHub Action or install the CLI, then run the script in real
|
|
126
|
+
containers for each distribution. The report identifies the failing image, exit code,
|
|
127
|
+
line, and missing command.
|
|
128
|
+
|
|
129
|
+
### Why can ShellCheck pass while the installer still fails?
|
|
130
|
+
|
|
131
|
+
ShellCheck analyzes source and syntax. It cannot know which binaries are installed in
|
|
132
|
+
the image that executes the script. Runtime execution exposes missing commands and
|
|
133
|
+
package-manager assumptions.
|
|
134
|
+
|
|
135
|
+
### How do I diagnose `apt-get: not found` on Alpine?
|
|
136
|
+
|
|
137
|
+
Alpine normally uses `apk`. Detect the available package manager or document a
|
|
138
|
+
distribution-specific prerequisite instead of assuming Debian's APT exists everywhere.
|
|
139
|
+
|
|
140
|
+
### Can I run the check without GitHub Actions?
|
|
141
|
+
|
|
142
|
+
Yes. Install `opsscript-gate` from PyPI, make sure a Docker engine running Linux
|
|
143
|
+
containers is reachable, and run `opsscript-gate run ./install.sh`.
|
|
@@ -12,7 +12,7 @@ opsscript-gate run --dry-run
|
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
`init` refuses to overwrite either `.opsscript-gate.json` or
|
|
15
|
-
`.github/workflows/opsscript-gate.yml`. The generated workflow uses the v0.9.
|
|
15
|
+
`.github/workflows/opsscript-gate.yml`. The generated workflow uses the v0.9.2 tag.
|
|
16
16
|
|
|
17
17
|
`doctor` checks Python and Docker connectivity without executing repository scripts.
|
|
18
18
|
Use `opsscript-gate doctor --format json` when collecting a support report.
|
|
@@ -53,7 +53,7 @@ names to install inside each test container before the target script runs. The
|
|
|
53
53
|
runner uses `apt-get` for Debian/Ubuntu images and `apk` for Alpine images. It
|
|
54
54
|
accepts package names only, never shell commands, and requires `network: bridge`.
|
|
55
55
|
The default is an empty list, so existing networking settings and execution remain unchanged.
|
|
56
|
-
`repeat` runs each distribution more than once and reports `FLAKY` when at least one
|
|
56
|
+
`repeat` runs each distribution more than once (up to 20 attempts) and reports `FLAKY` when at least one
|
|
57
57
|
attempt passes and another fails. Keep it at `1` for the normal fast gate; use `3` or
|
|
58
58
|
`5` while investigating intermittent CI failures.
|
|
59
59
|
|
|
@@ -109,7 +109,7 @@ For pull requests, set `changed-since` to the base commit and fetch full Git his
|
|
|
109
109
|
- uses: actions/checkout@v7
|
|
110
110
|
with:
|
|
111
111
|
fetch-depth: 0
|
|
112
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
112
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
113
113
|
with:
|
|
114
114
|
changed-since: ${{ github.event.pull_request.base.sha }}
|
|
115
115
|
preset: minimal
|
|
@@ -119,7 +119,7 @@ The Action passes when no changed shell scripts are selected. This keeps unrelat
|
|
|
119
119
|
documentation or application changes from starting container jobs.
|
|
120
120
|
|
|
121
121
|
```yaml
|
|
122
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
122
|
+
- uses: Mresyzz/opsscript-gate@v0.9.2
|
|
123
123
|
with:
|
|
124
124
|
config: .opsscript-gate.json
|
|
125
125
|
format: json
|
|
@@ -146,3 +146,6 @@ offline networking and a smaller matrix. Existing users do not need to run `init
|
|
|
146
146
|
|
|
147
147
|
The intentional breaking corrections are that discovery overflow now fails and
|
|
148
148
|
symlinked files are no longer automatically selected. Preview discovery after upgrading.
|
|
149
|
+
|
|
150
|
+
`timeout` is the hard limit per container in seconds. It must be between 1 and 3600.
|
|
151
|
+
Custom `matrix` values may contain up to 32 container images.
|