opsscript-gate 0.9.0__tar.gz → 0.9.2__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.2/.ai/v0.9.2_issues_report.md +90 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/.github/workflow-templates/opsscript-gate.yml +1 -1
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/.github/workflows/release.yml +3 -8
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/CHANGELOG.md +30 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/CITATION.cff +1 -2
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/PKG-INFO +16 -13
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/README.md +12 -10
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/README.zh-CN.md +4 -4
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/action.yml +7 -6
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/demo.html +4 -4
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/docs/command-not-found.html +70 -1
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/docs/command-not-found.md +25 -1
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/docs/configuration.md +7 -4
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/docs/gpt-oss.md +1 -1
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/docs/index.html +20 -4
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/docs/llms.txt +8 -1
- opsscript_gate-0.9.2/docs/robots.txt +3 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/examples/github-actions/README.md +1 -1
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/examples/github-actions/workflow.yml +1 -1
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/index.html +20 -4
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/llms.txt +8 -1
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/pyproject.toml +6 -2
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/src/opsscript_gate/__init__.py +1 -1
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/src/opsscript_gate/cli.py +74 -15
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/src/opsscript_gate/config.py +39 -3
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/src/opsscript_gate/discovery.py +37 -3
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/src/opsscript_gate/models.py +20 -8
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/src/opsscript_gate/remediation.py +59 -2
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/src/opsscript_gate/reporter.py +98 -51
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/src/opsscript_gate/runner.py +270 -55
- opsscript_gate-0.9.2/tests/test_action_contract.py +45 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/tests/test_onboarding.py +91 -1
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/tests/test_runner.py +436 -6
- opsscript_gate-0.9.0/tests/test_action_contract.py +0 -24
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/.gitattributes +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/.github/ISSUE_TEMPLATE/distro_request.yml +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/.github/assets/social-preview.png +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/.github/pull_request_template.md +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/.github/workflow-templates/opsscript-gate.properties.json +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/.github/workflows/demo.yml +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/.github/workflows/deploy-pages.yml +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/.github/workflows/test.yml +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/.gitignore +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/CONTRIBUTING.md +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/LICENSE +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/ROADMAP.md +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/SECURITY.md +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/docs/sitemap.xml +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/docs/troubleshooting.md +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/examples/alpine-incompatibility/README.md +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/examples/alpine-incompatibility/apt_dependency.sh +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/examples/basic/README.md +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/examples/basic/clean_setup.sh +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/examples/interactive-hang/README.md +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/examples/interactive-hang/prompt_confirm.sh +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/tests/fixtures/fail_deps.sh +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/tests/fixtures/fail_hang.sh +0 -0
- {opsscript_gate-0.9.0 → opsscript_gate-0.9.2}/tests/fixtures/pass_basic.sh +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# OpsScript Gate 本地 v0.9.2 代码审查、缺陷排查与修复报告
|
|
2
|
+
|
|
3
|
+
**审查与修复时间**:2026-10-05
|
|
4
|
+
**基准分支**:`codex/v0.9.2-hardening`
|
|
5
|
+
**测试套件状态**:`pytest` 177 项测试全量通过(165 passed, 12 skipped, 0 failures)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
|
|
11
|
+
针对本地 `0.9.2` 版本在近期提交(`6260a74` 到 `cae3fbe`)及后续排查中发现的所有缺陷,进行了地毯式分析与代码修复。所有发现的问题均已完成第一性原理剖析、修复并配齐自动化回归测试。
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 本轮新发现的问题与修复记录
|
|
16
|
+
|
|
17
|
+
### 1. `discovery.py` 中 `_is_ignored_path` 误将前导 `./` 路径判定为忽略项
|
|
18
|
+
* **文件位置**:`src/opsscript_gate/discovery.py`
|
|
19
|
+
* **问题成因**:
|
|
20
|
+
`_is_ignored_path` 将路径按 `/` 切分后遍历每个 `part`,直接使用 `part.startswith(".")`。当路径是以 `./` 开头(例如 `./scripts/install.sh` 或 `./run.sh`)时,首个 `part` 为单个点 `.`,`'.'.startswith(".")` 恒为 `True`,导致合法脚本被错误判定为忽略项。
|
|
21
|
+
* **修复方案**:
|
|
22
|
+
在切分前先剥离前导 `./`,并将 `part in (".", "..")` 显式排除在隐藏目录判断之外。
|
|
23
|
+
* **测试用例**:
|
|
24
|
+
新增 `tests/test_runner.py::test_is_ignored_path_dot_slash_and_hidden`。
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
### 2. `runner.py` 中 `_is_wait_timeout_error` 无法识别嵌套异常原因链
|
|
29
|
+
* **文件位置**:`src/opsscript_gate/runner.py`
|
|
30
|
+
* **问题成因**:
|
|
31
|
+
Docker SDK (urllib3 / requests) 发生超时异常时,常将底层的 `ReadTimeout` 或 `SocketTimeout` 包装在 `requests.exceptions.ConnectionError` 或顶层异常中。原函数只检查了外层异常类名,导致被包装的真实超时被误报为通信崩溃(`DistroStatus.ERROR`),且未能触发超时强杀逻辑。
|
|
32
|
+
* **修复方案**:
|
|
33
|
+
在 `_is_wait_timeout_error` 中遍历 `__cause__` 与 `__context__` 异常链,全面识别深层超时错误。
|
|
34
|
+
* **测试用例**:
|
|
35
|
+
新增 `tests/test_runner.py::test_is_wait_timeout_error_cause_chain`。
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
### 3. `cli.py` 中 `--output` 指定已有目录时缺乏前置拦截
|
|
40
|
+
* **文件位置**:`src/opsscript_gate/cli.py`
|
|
41
|
+
* **问题成因**:
|
|
42
|
+
若用户误将已存在的目录传给 `--output`(例如 `--output reports/` 或 `--output .`),原逻辑在跑完所有耗时的容器矩阵测试后,才在 `publish_output` 中因 `write_text` 抛出 `IsADirectoryError` 或 `PermissionError`,严重浪费时间。
|
|
43
|
+
* **修复方案**:
|
|
44
|
+
在执行矩阵前增加 `if output_path.is_dir(): sys.stderr.write("Error: output must name a file, not an existing directory\n"); return 1` 提前拦截。
|
|
45
|
+
* **测试用例**:
|
|
46
|
+
新增 `tests/test_runner.py::test_cli_output_rejects_existing_directory_early`。
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
### 4. `remediation.py` 扩充跨发行版包管理器互踩诊断规则
|
|
51
|
+
* **文件位置**:`src/opsscript_gate/remediation.py`
|
|
52
|
+
* **问题成因**:
|
|
53
|
+
此前仅包含 Debian/Ubuntu(apt)与 Alpine(apk)的双向匹配。当脚本在 Debian/Ubuntu/Alpine 上尝试调用 `yum` 或 `dnf`,或者在 Fedora/CentOS/RHEL 系列镜像上调用 `apt`/`apk` 时,系统只能报通用缺失错误,缺乏精准指引。
|
|
54
|
+
* **修复方案**:
|
|
55
|
+
新增 `_match_debian_ubuntu_yum`、`_match_alpine_yum`、`_match_rhel_fedora_apt` 匹配器及专属修复建议。
|
|
56
|
+
* **测试用例**:
|
|
57
|
+
新增 `tests/test_runner.py::test_remediation_enterprise_distro_package_rules`。
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
### 5. `runner.py` 中保护 `container.reload()` 避免网络抖动覆盖已取得的状态码
|
|
62
|
+
* **文件位置**:`src/opsscript_gate/runner.py`
|
|
63
|
+
* **问题成因**:
|
|
64
|
+
在容器执行完毕后,`container.wait()` 已返回了包含 `StatusCode` 的字典,但随后的 `container.reload()` 调用缺乏异常防护。一旦容器刚好在退出瞬间发生通信抖动,会导致原本已成功完成的测试异常崩溃。
|
|
65
|
+
* **修复方案**:
|
|
66
|
+
为 `container.reload()` 增加 `try-except` 防护,优先并安全地使用已拿到的有效退出码。
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### 6. `remediation.py` 中 `curl`/`wget` 绝对路径匹配与最小容器缺失 `sudo` 修复规则
|
|
71
|
+
* **文件位置**:`src/opsscript_gate/remediation.py`
|
|
72
|
+
* **问题成因**:
|
|
73
|
+
1. `_match_curl` 与 `_match_wget` 仅检查了命令名完全等于 `curl` / `wget`,当脚本使用 `/usr/bin/curl`、`/bin/curl` 等绝对路径调用时,无法匹配到建议规则。
|
|
74
|
+
2. 最小化 Linux 容器镜像(Debian slim、Ubuntu、Alpine 等)默认不带 `sudo`,且容器通常本身即为 root 权限。当运维脚本带有 `sudo` 时会报 `sudo: not found`,此前缺乏专属修复建议。
|
|
75
|
+
* **修复方案**:
|
|
76
|
+
提取命令路径中的 basename 统一进行匹配,并新增 `_match_sudo` 规则与针对性修复建议。
|
|
77
|
+
* **测试用例**:
|
|
78
|
+
新增 `tests/test_runner.py::test_remediation_curl_wget_path_and_sudo`。
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 历史排查问题的闭环确认(已在近期提交中合入)
|
|
83
|
+
|
|
84
|
+
1. **`reporter.py` 中 `_sarif_path` 绝对路径转换**:已在 Commit `6a830e4` 中引入 `os.path.relpath` 与防止 `../` 逃逸的处理。
|
|
85
|
+
2. **`discovery.py` 中 `discover_scripts` 过滤隐藏文件**:已在 Commit `9618874` 中过滤了 `filename.startswith(".")`。
|
|
86
|
+
3. **`action.yml` 中 `dry-run` 大小写敏感**:已在 Commit `03b30ab` 中使用 `tr '[:upper:]' '[:lower:]'` 规整。
|
|
87
|
+
4. **`cli.py` 中 `publish_output` 写文件失败吞没 stdout**:已在 Commit `03b30ab` 中调整为先打印控制台输出再写文件。
|
|
88
|
+
5. **`runner.py` 中多轮执行代表性结果选择**:已在 Commit `6a830e4` 中优化为优先保留具备 `diagnostic` 的结果。
|
|
89
|
+
6. **Docker 引擎模式检查**:已在 Commit `0b8a202` 中通过 `client.info()` 校验 `OSType == "linux"`。
|
|
90
|
+
7. **资源上限守卫**:已在 Commit `cae3fbe`, `13f0730`, `373d5a0` 中为 `matrix`(最多32个)、`timeout`(最多3600秒)、`repeat`(最多20次)增加上限校验。
|
|
@@ -123,17 +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.
|
|
136
|
-
IS_NEW_RELEASE="true"
|
|
131
|
+
echo "Target tag $TARGET_TAG does not exist. Creating it and handing publication to the tag workflow."
|
|
137
132
|
SHOULD_TAG="true"
|
|
138
133
|
fi
|
|
139
134
|
else
|
|
@@ -171,7 +166,7 @@ jobs:
|
|
|
171
166
|
retention-days: 7
|
|
172
167
|
|
|
173
168
|
- name: Create and push Git tag
|
|
174
|
-
if: steps.release-check.outputs.
|
|
169
|
+
if: steps.release-check.outputs.should_tag == 'true'
|
|
175
170
|
shell: bash
|
|
176
171
|
run: |
|
|
177
172
|
TARGET_TAG="${{ steps.release-check.outputs.release_tag }}"
|
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.9.2] - Unreleased
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Hardened SARIF, Markdown, terminal, and machine-readable output handling.
|
|
7
|
+
- Prevented false package-setup errors, stale Docker wait results, hard-link overwrites, and unbounded log copies.
|
|
8
|
+
- Added BOM-aware discovery, Windows exclusion normalization, bounded concurrency, and runtime option validation.
|
|
9
|
+
- Added a one-CPU container limit and bounded Docker log rotation, while keeping disposable container filesystems writable for installers.
|
|
10
|
+
- Normalized SARIF paths, preserved actionable repeat-run diagnostics, skipped hidden auto-discovered files, and kept terminal reports visible when file output fails.
|
|
11
|
+
- Fixed release workflow tag handoff so a `main` push cannot publish the same version twice.
|
|
12
|
+
- Made `doctor` reject Docker's Windows-container mode before Linux image checks begin.
|
|
13
|
+
- Added problem-first FAQ content, structured data, canonical URLs, and AI-readable answers for runtime compatibility searches.
|
|
14
|
+
- Bounded repeat runs to 20 attempts per distribution to prevent accidental unbounded container work and result retention.
|
|
15
|
+
- Bounded per-container timeouts to one hour so fallback polling cannot wait indefinitely on an extreme configuration.
|
|
16
|
+
- Bounded custom matrices to 32 images so a single configuration cannot create unbounded container work.
|
|
17
|
+
- Fixed `_is_ignored_path` in script discovery to avoid misclassifying paths with leading `./` as ignored.
|
|
18
|
+
- Traversed exception cause chains in `_is_wait_timeout_error` to reliably identify nested Docker wait timeouts.
|
|
19
|
+
- Protected container reload against network jitter to preserve valid exit codes.
|
|
20
|
+
- Added early validation for CLI `--output` to reject existing directories before executing test matrices.
|
|
21
|
+
- Expanded cross-distro package manager diagnostics and added remediation for path-qualified curl/wget and missing sudo.
|
|
22
|
+
- Refreshed active workflow templates, examples, and documentation to `v0.9.2`.
|
|
23
|
+
|
|
24
|
+
## [0.9.1] - 2026-10-03
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
- Normalized discovery exclusions so top-level paths match with or without `./`.
|
|
28
|
+
- Made SARIF output conform to the 2.1.0 result schema.
|
|
29
|
+
- Failed closed when Docker omitted an exit code and separated package setup errors from script failures.
|
|
30
|
+
- Validated project configuration in `doctor` and handled UTF-8 BOM scripts.
|
|
31
|
+
- Distinguished Docker wait API errors from genuine execution timeouts.
|
|
32
|
+
|
|
3
33
|
## [0.9.0] - 2026-10-03
|
|
4
34
|
|
|
5
35
|
### Added
|
|
@@ -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.2
|
|
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`.
|