opsscript-gate 0.9.4__tar.gz → 0.9.5__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.4 → opsscript_gate-0.9.5}/.github/workflow-templates/opsscript-gate.yml +1 -1
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/.github/workflows/deploy-pages.yml +2 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/CHANGELOG.md +9 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/PKG-INFO +12 -7
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/README.md +10 -6
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/README.zh-CN.md +4 -4
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/action.yml +17 -1
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/docs/command-not-found.html +2 -1
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5/docs}/index.html +49 -164
- opsscript_gate-0.9.5/docs/installer-smoke-test.html +73 -0
- opsscript_gate-0.9.5/docs/installer-smoke-test.md +55 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5/docs}/llms.txt +1 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/docs/sitemap.xml +1 -0
- opsscript_gate-0.9.5/examples/github-actions/README.md +11 -0
- opsscript_gate-0.9.5/examples/github-actions/installer-smoke.yml +54 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/examples/github-actions/workflow.yml +1 -1
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/pyproject.toml +2 -1
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/src/opsscript_gate/__init__.py +1 -1
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/src/opsscript_gate/config.py +1 -1
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/src/opsscript_gate/models.py +24 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/src/opsscript_gate/remediation.py +45 -24
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/src/opsscript_gate/reporter.py +20 -4
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/src/opsscript_gate/runner.py +180 -58
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/tests/test_action_contract.py +3 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/tests/test_audit_coverage.py +146 -0
- opsscript_gate-0.9.5/tests/test_installer_example.py +76 -0
- opsscript_gate-0.9.4/examples/github-actions/README.md +0 -5
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/.gitattributes +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/.github/ISSUE_TEMPLATE/distro_request.yml +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/.github/assets/social-preview.png +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/.github/pull_request_template.md +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/.github/workflow-templates/opsscript-gate.properties.json +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/.github/workflows/demo.yml +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/.github/workflows/release.yml +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/.github/workflows/test.yml +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/.gitignore +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/CITATION.cff +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/CONTRIBUTING.md +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/LICENSE +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/ROADMAP.md +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/SECURITY.md +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/demo.html +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/docs/command-not-found.md +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/docs/configuration.md +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/docs/gpt-oss.md +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/docs/robots.txt +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/docs/troubleshooting.md +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/examples/alpine-incompatibility/README.md +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/examples/alpine-incompatibility/apt_dependency.sh +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/examples/basic/README.md +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/examples/basic/clean_setup.sh +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/examples/interactive-hang/README.md +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/examples/interactive-hang/prompt_confirm.sh +0 -0
- {opsscript_gate-0.9.4/docs → opsscript_gate-0.9.5}/index.html +0 -0
- {opsscript_gate-0.9.4/docs → opsscript_gate-0.9.5}/llms.txt +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/src/opsscript_gate/cli.py +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/src/opsscript_gate/discovery.py +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/tests/conftest.py +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/tests/fixtures/fail_deps.sh +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/tests/fixtures/fail_hang.sh +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/tests/fixtures/pass_basic.sh +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/tests/test_onboarding.py +0 -0
- {opsscript_gate-0.9.4 → opsscript_gate-0.9.5}/tests/test_runner.py +0 -0
|
@@ -25,6 +25,8 @@ jobs:
|
|
|
25
25
|
uses: actions/checkout@v4
|
|
26
26
|
- name: Setup Pages
|
|
27
27
|
uses: actions/configure-pages@v5
|
|
28
|
+
- name: Stage downloadable installer workflow
|
|
29
|
+
run: cp examples/github-actions/installer-smoke.yml docs/installer-smoke.yml
|
|
28
30
|
- name: Upload artifact
|
|
29
31
|
uses: actions/upload-pages-artifact@v3
|
|
30
32
|
with:
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.9.5] - 2026-11-08
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Extended structured failure diagnostics to handle exit code 126 (`permission_denied` and `exec_format_error`) and exit code 137 (`oom_killed`) with targeted remediation suggestions.
|
|
7
|
+
- Added native distribution family detection for Amazon Linux (`amazonlinux`, `amzn`) and Oracle Linux (`oracle`, `ol:`) to support RHEL-family package recommendations.
|
|
8
|
+
- Added GitHub Composite Action `outputs` for `all-passed` and `report-file`, exporting execution status via `$GITHUB_OUTPUT`.
|
|
9
|
+
- Surfaced package installation recommendations and package names directly in Markdown compatibility tables, failure diagnostic log drawers, and terminal detail outputs.
|
|
10
|
+
- Added convenient counting properties (`passed_count`, `failed_count`, `total_count`) on `RunReport` and `MultiScriptReport`.
|
|
11
|
+
|
|
3
12
|
## [0.9.4] - 2026-10-11
|
|
4
13
|
|
|
5
14
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: opsscript-gate
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.5
|
|
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/
|
|
@@ -28,6 +28,7 @@ Requires-Dist: docker>=7.0.0
|
|
|
28
28
|
Provides-Extra: test
|
|
29
29
|
Requires-Dist: markdown-it-py>=3.0.0; extra == 'test'
|
|
30
30
|
Requires-Dist: pytest>=8.0.0; extra == 'test'
|
|
31
|
+
Requires-Dist: pyyaml>=6.0.0; extra == 'test'
|
|
31
32
|
Description-Content-Type: text/markdown
|
|
32
33
|
|
|
33
34
|
# OpsScript Gate — cross-distro shell script runtime compatibility checker
|
|
@@ -80,7 +81,7 @@ apt-get --version
|
|
|
80
81
|
Run it locally with `opsscript-gate run ./install.sh`, or add the following step to CI:
|
|
81
82
|
|
|
82
83
|
```yaml
|
|
83
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
84
|
+
- uses: Mresyzz/opsscript-gate@v0.9.4
|
|
84
85
|
with:
|
|
85
86
|
script-path: install.sh
|
|
86
87
|
```
|
|
@@ -89,7 +90,7 @@ The result identifies the failing distribution, exit code, line, missing command
|
|
|
89
90
|
|
|
90
91
|
---
|
|
91
92
|
|
|
92
|
-
## Current
|
|
93
|
+
## Current release: v0.9.4
|
|
93
94
|
|
|
94
95
|
The current release includes a project config file, a dry-run plan, presets, exclusions,
|
|
95
96
|
saved reports, changed-script selection for pull requests, and repeat runs for detecting
|
|
@@ -119,6 +120,10 @@ image's native package manager before testing. Package setup is opt-in and
|
|
|
119
120
|
requires bridge networking. See [configuration and migration](docs/configuration.md) and
|
|
120
121
|
[why a shell script works on Ubuntu but fails on Alpine](docs/troubleshooting.md).
|
|
121
122
|
|
|
123
|
+
Testing an installer? Use the [installation smoke test workflow](docs/installer-smoke-test.md)
|
|
124
|
+
to check the installed binary inside each container. A script's zero exit status
|
|
125
|
+
alone does not prove it installed successfully.
|
|
126
|
+
|
|
122
127
|
## Quickstart
|
|
123
128
|
|
|
124
129
|
### In GitHub Actions
|
|
@@ -143,7 +148,7 @@ jobs:
|
|
|
143
148
|
- uses: actions/checkout@v7
|
|
144
149
|
with:
|
|
145
150
|
persist-credentials: false
|
|
146
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
151
|
+
- uses: Mresyzz/opsscript-gate@v0.9.4
|
|
147
152
|
```
|
|
148
153
|
|
|
149
154
|
This zero-configuration form discovers shell scripts in the repository. Use
|
|
@@ -154,7 +159,7 @@ repository has a single installer. For self-hosted model installers, see the
|
|
|
154
159
|
Or test a specific script with custom execution modes:
|
|
155
160
|
|
|
156
161
|
```yaml
|
|
157
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
162
|
+
- uses: Mresyzz/opsscript-gate@v0.9.4
|
|
158
163
|
with:
|
|
159
164
|
script-path: scripts/install.sh
|
|
160
165
|
shell: auto
|
|
@@ -188,7 +193,7 @@ unrelated scripts:
|
|
|
188
193
|
with:
|
|
189
194
|
persist-credentials: false
|
|
190
195
|
fetch-depth: 0
|
|
191
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
196
|
+
- uses: Mresyzz/opsscript-gate@v0.9.4
|
|
192
197
|
with:
|
|
193
198
|
changed-since: ${{ github.event.pull_request.base.sha }}
|
|
194
199
|
preset: minimal
|
|
@@ -279,7 +284,7 @@ Use `sarif` when the result should appear in GitHub Code Scanning or another
|
|
|
279
284
|
SARIF-compatible viewer. Upload it explicitly with the official upload action:
|
|
280
285
|
|
|
281
286
|
```yaml
|
|
282
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
287
|
+
- uses: Mresyzz/opsscript-gate@v0.9.4
|
|
283
288
|
with:
|
|
284
289
|
script-path: scripts/install.sh
|
|
285
290
|
format: sarif
|
|
@@ -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.4
|
|
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 release: v0.9.4
|
|
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
|
|
@@ -87,6 +87,10 @@ image's native package manager before testing. Package setup is opt-in and
|
|
|
87
87
|
requires bridge networking. See [configuration and migration](docs/configuration.md) and
|
|
88
88
|
[why a shell script works on Ubuntu but fails on Alpine](docs/troubleshooting.md).
|
|
89
89
|
|
|
90
|
+
Testing an installer? Use the [installation smoke test workflow](docs/installer-smoke-test.md)
|
|
91
|
+
to check the installed binary inside each container. A script's zero exit status
|
|
92
|
+
alone does not prove it installed successfully.
|
|
93
|
+
|
|
90
94
|
## Quickstart
|
|
91
95
|
|
|
92
96
|
### In GitHub Actions
|
|
@@ -111,7 +115,7 @@ jobs:
|
|
|
111
115
|
- uses: actions/checkout@v7
|
|
112
116
|
with:
|
|
113
117
|
persist-credentials: false
|
|
114
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
118
|
+
- uses: Mresyzz/opsscript-gate@v0.9.4
|
|
115
119
|
```
|
|
116
120
|
|
|
117
121
|
This zero-configuration form discovers shell scripts in the repository. Use
|
|
@@ -122,7 +126,7 @@ repository has a single installer. For self-hosted model installers, see the
|
|
|
122
126
|
Or test a specific script with custom execution modes:
|
|
123
127
|
|
|
124
128
|
```yaml
|
|
125
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
129
|
+
- uses: Mresyzz/opsscript-gate@v0.9.4
|
|
126
130
|
with:
|
|
127
131
|
script-path: scripts/install.sh
|
|
128
132
|
shell: auto
|
|
@@ -156,7 +160,7 @@ unrelated scripts:
|
|
|
156
160
|
with:
|
|
157
161
|
persist-credentials: false
|
|
158
162
|
fetch-depth: 0
|
|
159
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
163
|
+
- uses: Mresyzz/opsscript-gate@v0.9.4
|
|
160
164
|
with:
|
|
161
165
|
changed-since: ${{ github.event.pull_request.base.sha }}
|
|
162
166
|
preset: minimal
|
|
@@ -247,7 +251,7 @@ Use `sarif` when the result should appear in GitHub Code Scanning or another
|
|
|
247
251
|
SARIF-compatible viewer. Upload it explicitly with the official upload action:
|
|
248
252
|
|
|
249
253
|
```yaml
|
|
250
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
254
|
+
- uses: Mresyzz/opsscript-gate@v0.9.4
|
|
251
255
|
with:
|
|
252
256
|
script-path: scripts/install.sh
|
|
253
257
|
format: sarif
|
|
@@ -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.4
|
|
21
21
|
|
|
22
|
-
v0.9.
|
|
22
|
+
v0.9.4 是当前已发布版本;如果你要从源码验证当前分支,也可以执行:
|
|
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.4`。
|
|
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.4
|
|
78
78
|
with:
|
|
79
79
|
changed-since: ${{ github.event.pull_request.base.sha }}
|
|
80
80
|
preset: minimal
|
|
@@ -80,6 +80,14 @@ inputs:
|
|
|
80
80
|
required: false
|
|
81
81
|
default: ''
|
|
82
82
|
|
|
83
|
+
outputs:
|
|
84
|
+
all-passed:
|
|
85
|
+
description: 'Whether all script compatibility checks passed (true or false)'
|
|
86
|
+
value: ${{ steps.gate.outputs.all-passed }}
|
|
87
|
+
report-file:
|
|
88
|
+
description: 'Path to saved report file if output input was set'
|
|
89
|
+
value: ${{ inputs.output }}
|
|
90
|
+
|
|
83
91
|
runs:
|
|
84
92
|
using: 'composite'
|
|
85
93
|
steps:
|
|
@@ -94,6 +102,7 @@ runs:
|
|
|
94
102
|
pip install "${{ github.action_path }}"
|
|
95
103
|
|
|
96
104
|
- name: Run compatibility gate
|
|
105
|
+
id: gate
|
|
97
106
|
shell: bash
|
|
98
107
|
env:
|
|
99
108
|
INPUT_SCRIPT_PATH: ${{ inputs.script-path }}
|
|
@@ -146,4 +155,11 @@ runs:
|
|
|
146
155
|
echo "dry-run must be true or false" >&2
|
|
147
156
|
exit 1
|
|
148
157
|
fi
|
|
149
|
-
|
|
158
|
+
GATE_STATUS=0
|
|
159
|
+
python -m opsscript_gate.cli "${ARGS[@]}" || GATE_STATUS=$?
|
|
160
|
+
if [ "$GATE_STATUS" -eq 0 ]; then
|
|
161
|
+
echo "all-passed=true" >> "$GITHUB_OUTPUT"
|
|
162
|
+
else
|
|
163
|
+
echo "all-passed=false" >> "$GITHUB_OUTPUT"
|
|
164
|
+
fi
|
|
165
|
+
exit "$GATE_STATUS"
|
|
@@ -134,7 +134,7 @@ jobs:
|
|
|
134
134
|
- uses: actions/checkout@v7
|
|
135
135
|
with:
|
|
136
136
|
persist-credentials: false
|
|
137
|
-
- uses: Mresyzz/opsscript-gate@v0.9.
|
|
137
|
+
- uses: Mresyzz/opsscript-gate@v0.9.4
|
|
138
138
|
with:
|
|
139
139
|
script-path: install.sh
|
|
140
140
|
shell: auto
|
|
@@ -186,6 +186,7 @@ opsscript-gate run ./install.sh</code></pre>
|
|
|
186
186
|
<a href="https://github.com/Mresyzz/opsscript-gate/blob/main/docs/troubleshooting.md">troubleshooting</a>,
|
|
187
187
|
or <a href="https://github.com/Mresyzz/opsscript-gate/blob/main/SECURITY.md">security boundaries</a>.
|
|
188
188
|
<a href="./">Open the interactive demo</a>.</footer>
|
|
189
|
+
<p>Installer returns zero but the program is missing? <a href="installer-smoke-test.html">Verify the installed binary in the same container.</a></p>
|
|
189
190
|
</main>
|
|
190
191
|
</body>
|
|
191
192
|
</html>
|
|
@@ -253,7 +253,7 @@
|
|
|
253
253
|
OpsScript Gate
|
|
254
254
|
</span>
|
|
255
255
|
<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)]">
|
|
256
|
-
v0.9.
|
|
256
|
+
v0.9.4
|
|
257
257
|
</span>
|
|
258
258
|
</div>
|
|
259
259
|
</div>
|
|
@@ -296,7 +296,7 @@
|
|
|
296
296
|
|
|
297
297
|
<div class="pt-2 flex flex-wrap items-center gap-3 text-xs font-mono">
|
|
298
298
|
<button onclick="copyCanonicalWorkflow(this)" class="px-4 py-2 rounded font-medium bg-[var(--brand)] text-white hover:bg-[var(--brand-hover)] shadow-sm transition-all">
|
|
299
|
-
Copy
|
|
299
|
+
Copy Workflow
|
|
300
300
|
</button>
|
|
301
301
|
<a href="./command-not-found.html" class="px-4 py-2 rounded font-medium bg-[var(--surface-elevated)] text-[var(--text-body)] border border-[var(--border-medium)] hover:border-[var(--brand)] hover:text-[var(--brand)] shadow-sm transition-all inline-flex items-center gap-1.5">
|
|
302
302
|
Debug command not found
|
|
@@ -316,13 +316,13 @@
|
|
|
316
316
|
<div class="flex flex-col sm:flex-row sm:items-baseline justify-between gap-1 border-b border-[var(--border-light)] pb-3">
|
|
317
317
|
<div class="space-y-1">
|
|
318
318
|
<div class="inline-flex items-center gap-1.5 px-2 py-0.5 rounded text-[10px] font-mono uppercase tracking-wider bg-[var(--surface-muted)] text-[var(--text-muted)] border border-[var(--border-light)]">
|
|
319
|
-
Section 01 •
|
|
319
|
+
Section 01 • Example walkthrough
|
|
320
320
|
</div>
|
|
321
321
|
<h2 class="font-serif text-xl text-[var(--text-hero)] font-medium">
|
|
322
|
-
|
|
322
|
+
Explore compatibility examples
|
|
323
323
|
</h2>
|
|
324
324
|
<p class="text-xs text-[var(--text-muted)]">
|
|
325
|
-
|
|
325
|
+
Illustrative results only. This page does not run ShellCheck or execute scripts. Use the Action to verify your script in real containers.
|
|
326
326
|
</p>
|
|
327
327
|
</div>
|
|
328
328
|
</div>
|
|
@@ -359,7 +359,7 @@
|
|
|
359
359
|
<!-- whitespace-pre prevents ugly breaking of code indentation -->
|
|
360
360
|
<textarea id="script-input" oninput="evaluateInput()" class="w-full bg-[var(--code-bg)] text-[var(--code-text)] font-mono text-xs p-4 border-0 leading-[1.7] resize-y min-h-[200px] h-[200px] block focus:ring-0 whitespace-pre overflow-x-auto"></textarea>
|
|
361
361
|
<div class="bg-[var(--surface-muted)] px-4 py-1.5 border-t border-[var(--border-light)] flex items-center justify-between text-[11px] font-mono text-[var(--text-subtle)]">
|
|
362
|
-
<span>
|
|
362
|
+
<span>Local editor • edited scripts remain unverified</span>
|
|
363
363
|
<span id="script-line-count">8 lines</span>
|
|
364
364
|
</div>
|
|
365
365
|
</div>
|
|
@@ -371,7 +371,7 @@
|
|
|
371
371
|
<div class="panel-card p-4 flex flex-col justify-between space-y-3">
|
|
372
372
|
<div class="space-y-2.5">
|
|
373
373
|
<div class="flex items-center justify-between border-b border-[var(--border-light)] pb-2">
|
|
374
|
-
<span class="font-mono text-xs font-medium text-[var(--text-muted)]">
|
|
374
|
+
<span class="font-mono text-xs font-medium text-[var(--text-muted)]">ShellCheck example output</span>
|
|
375
375
|
<span id="sc-status" class="font-mono text-xs font-semibold px-2 py-0.5 rounded border">
|
|
376
376
|
0 WARNINGS
|
|
377
377
|
</span>
|
|
@@ -391,7 +391,7 @@
|
|
|
391
391
|
<div class="panel-card p-4 flex flex-col justify-between space-y-3">
|
|
392
392
|
<div class="space-y-2.5">
|
|
393
393
|
<div class="flex items-center justify-between border-b border-[var(--border-light)] pb-2">
|
|
394
|
-
<span class="font-mono text-xs font-medium text-[var(--text-muted)]">OpsScript Gate
|
|
394
|
+
<span class="font-mono text-xs font-medium text-[var(--text-muted)]">OpsScript Gate example output</span>
|
|
395
395
|
<span id="ops-status" class="font-mono text-xs font-semibold px-2 py-0.5 rounded border">
|
|
396
396
|
1 DISTRO FAILED
|
|
397
397
|
</span>
|
|
@@ -532,11 +532,17 @@
|
|
|
532
532
|
</p>
|
|
533
533
|
</div>
|
|
534
534
|
|
|
535
|
+
<p class="text-xs text-[var(--text-muted)]">
|
|
536
|
+
Testing a downloading installer? A zero exit code alone does not prove installation succeeded.
|
|
537
|
+
<a href="./installer-smoke-test.html" class="text-[var(--brand)] underline">Use the installation smoke test guide</a>
|
|
538
|
+
to check the installed binary inside each container.
|
|
539
|
+
</p>
|
|
540
|
+
|
|
535
541
|
<div class="panel-card overflow-hidden">
|
|
536
542
|
<div class="bg-[var(--surface-muted)] px-4 py-2.5 border-b border-[var(--border-light)] flex items-center justify-between text-xs font-mono">
|
|
537
543
|
<div class="flex items-center gap-2 text-[var(--text-muted)]">
|
|
538
544
|
<span class="font-medium text-[var(--text-hero)]">.github/workflows/gate.yml</span>
|
|
539
|
-
<span class="text-[var(--text-subtle)] text-[11px] hidden sm:inline">•
|
|
545
|
+
<span class="text-[var(--text-subtle)] text-[11px] hidden sm:inline">• GitHub Actions</span>
|
|
540
546
|
</div>
|
|
541
547
|
<div class="flex items-center gap-2">
|
|
542
548
|
<button onclick="toggleWorkflowExpansion()" id="expand-btn" class="text-xs text-[var(--text-muted)] hover:text-[var(--text-hero)] px-2 py-0.5 rounded hover:bg-[var(--surface-subtle)] transition-colors">
|
|
@@ -558,16 +564,18 @@
|
|
|
558
564
|
<span class="font-semibold text-[var(--text-hero)]">compatibility:</span>
|
|
559
565
|
<span class="font-semibold text-[var(--text-hero)]">runs-on:</span> ubuntu-latest
|
|
560
566
|
<span class="font-semibold text-[var(--text-hero)]">steps:</span>
|
|
561
|
-
- <span class="font-semibold text-[var(--text-hero)]">uses:</span> actions/checkout@
|
|
567
|
+
- <span class="font-semibold text-[var(--text-hero)]">uses:</span> actions/checkout@v7
|
|
568
|
+
<span class="font-semibold text-[var(--text-hero)]">with:</span>
|
|
569
|
+
<span class="text-[var(--text-body)]">persist-credentials:</span> false
|
|
562
570
|
- <span class="font-semibold text-[var(--text-hero)]">name:</span> Validate scripts across distributions
|
|
563
|
-
<span class="font-semibold text-[var(--brand)]">uses:</span> Mresyzz/opsscript-gate@v0.9.
|
|
571
|
+
<span class="font-semibold text-[var(--brand)]">uses:</span> Mresyzz/opsscript-gate@v0.9.4
|
|
564
572
|
<span class="font-semibold text-[var(--text-hero)]">with:</span>
|
|
565
573
|
<span class="text-[var(--text-body)]">script-path:</span> ./install.sh
|
|
566
574
|
<span class="text-[var(--text-body)]">shell:</span> auto
|
|
567
|
-
<span class="text-[var(--text-body)]">timeout
|
|
575
|
+
<span class="text-[var(--text-body)]">timeout:</span> 120</code></pre>
|
|
568
576
|
<div class="code-gradient-mask" id="workflow-mask" onclick="toggleWorkflowExpansion()">
|
|
569
577
|
<button type="button" class="px-3.5 py-1.5 rounded-full bg-[var(--surface-elevated)] border border-[var(--border-medium)] text-[11px] font-mono text-[var(--text-body)] hover:text-[var(--brand)] hover:border-[var(--brand)] shadow-sm flex items-center gap-1.5 cursor-pointer transition-all">
|
|
570
|
-
<span>Show full configuration
|
|
578
|
+
<span>Show full configuration</span>
|
|
571
579
|
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="6 9 12 15 18 9"></polyline></svg>
|
|
572
580
|
</button>
|
|
573
581
|
</div>
|
|
@@ -579,7 +587,7 @@
|
|
|
579
587
|
<section class="mt-16 sm:mt-20 pt-4">
|
|
580
588
|
<div class="cta-invitation-card p-8 sm:p-11 text-center space-y-4">
|
|
581
589
|
<div class="inline-flex items-center gap-2 px-2.5 py-0.5 rounded text-[11px] font-mono font-medium bg-[var(--brand-surface)] text-[var(--brand)] border border-[var(--brand-border)] mx-auto">
|
|
582
|
-
|
|
590
|
+
Runs in your GitHub Actions runner
|
|
583
591
|
</div>
|
|
584
592
|
<h3 class="font-serif text-2xl sm:text-3xl text-[var(--text-hero)] font-normal tracking-tight">
|
|
585
593
|
Ready to secure your scripts across Linux distributions?
|
|
@@ -593,7 +601,7 @@
|
|
|
593
601
|
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
|
594
602
|
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
|
595
603
|
</svg>
|
|
596
|
-
<span>Copy
|
|
604
|
+
<span>Copy Workflow</span>
|
|
597
605
|
</button>
|
|
598
606
|
<a href="https://github.com/Mresyzz/opsscript-gate" target="_blank" class="px-4 py-2.5 rounded font-medium bg-[var(--surface-elevated)] text-[var(--text-body)] border border-[var(--border-medium)] hover:border-[var(--brand)] hover:text-[var(--brand)] shadow-sm transition-all inline-flex items-center gap-1.5">
|
|
599
607
|
<span>View on GitHub</span>
|
|
@@ -626,13 +634,15 @@ jobs:
|
|
|
626
634
|
compatibility:
|
|
627
635
|
runs-on: ubuntu-latest
|
|
628
636
|
steps:
|
|
629
|
-
- uses: actions/checkout@
|
|
637
|
+
- uses: actions/checkout@v7
|
|
638
|
+
with:
|
|
639
|
+
persist-credentials: false
|
|
630
640
|
- name: Validate scripts across distributions
|
|
631
|
-
uses: Mresyzz/opsscript-gate@v0.9.
|
|
641
|
+
uses: Mresyzz/opsscript-gate@v0.9.4
|
|
632
642
|
with:
|
|
633
643
|
script-path: ./install.sh
|
|
634
644
|
shell: auto
|
|
635
|
-
timeout
|
|
645
|
+
timeout: 120`;
|
|
636
646
|
|
|
637
647
|
function updateThemeButtonText() {
|
|
638
648
|
const isDark = document.documentElement.classList.contains("dark");
|
|
@@ -646,7 +656,7 @@ jobs:
|
|
|
646
656
|
const isDark = document.documentElement.classList.toggle("dark");
|
|
647
657
|
localStorage.setItem("theme", isDark ? "dark" : "light");
|
|
648
658
|
updateThemeButtonText();
|
|
649
|
-
|
|
659
|
+
// Theme changes must preserve the edited script and its unverified state.
|
|
650
660
|
}
|
|
651
661
|
|
|
652
662
|
function toggleWorkflowExpansion() {
|
|
@@ -723,6 +733,7 @@ jobs:
|
|
|
723
733
|
}
|
|
724
734
|
|
|
725
735
|
function selectCase(key) {
|
|
736
|
+
clearTimeout(debounceTimer);
|
|
726
737
|
activeKey = key;
|
|
727
738
|
const c = CASES[key];
|
|
728
739
|
const scriptInput = document.getElementById('script-input');
|
|
@@ -760,7 +771,7 @@ jobs:
|
|
|
760
771
|
|
|
761
772
|
function renderCase(c) {
|
|
762
773
|
const scStatus = document.getElementById('sc-status');
|
|
763
|
-
scStatus.innerText = c.scStatus;
|
|
774
|
+
scStatus.innerText = "EXAMPLE: " + c.scStatus;
|
|
764
775
|
scStatus.className = "font-mono text-xs font-semibold px-2 py-0.5 rounded border " + c.scClass;
|
|
765
776
|
|
|
766
777
|
const scOutput = document.getElementById('sc-output');
|
|
@@ -768,7 +779,7 @@ jobs:
|
|
|
768
779
|
scOutput.className = "bg-[var(--code-bg)] border border-[var(--border-light)] rounded p-3 text-xs font-mono h-[160px] overflow-y-auto whitespace-pre-wrap leading-[1.65] text-[var(--code-text)] break-words fade-switch";
|
|
769
780
|
|
|
770
781
|
const opsStatus = document.getElementById('ops-status');
|
|
771
|
-
opsStatus.innerText = c.opsStatus;
|
|
782
|
+
opsStatus.innerText = "EXAMPLE: " + c.opsStatus;
|
|
772
783
|
opsStatus.className = "font-mono text-xs font-semibold px-2 py-0.5 rounded border " + c.opsClass;
|
|
773
784
|
|
|
774
785
|
const opsOutput = document.getElementById('ops-output');
|
|
@@ -799,150 +810,22 @@ jobs:
|
|
|
799
810
|
}, 160);
|
|
800
811
|
}
|
|
801
812
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
headers: { 'Content-Type': 'application/json' },
|
|
807
|
-
body: JSON.stringify({ script: val })
|
|
808
|
-
});
|
|
809
|
-
if (resp.ok) {
|
|
810
|
-
const data = await resp.json();
|
|
811
|
-
renderRealApiResponse(data);
|
|
812
|
-
return;
|
|
813
|
-
}
|
|
814
|
-
} catch (err) {
|
|
815
|
-
// Fallback for static hosting on GitHub Pages
|
|
816
|
-
}
|
|
817
|
-
clientSideAnalyzeFallback(val);
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
function clientSideAnalyzeFallback(val) {
|
|
821
|
-
let isAlpineFail = false;
|
|
822
|
-
let alpineReason = "";
|
|
823
|
-
const hasBashism = val.includes('[[') || (val.includes('${') && val.includes(':'));
|
|
824
|
-
const hasRead = val.includes('read');
|
|
825
|
-
const hasSetE = val.includes('set -e') || val.includes('set -o errexit');
|
|
826
|
-
const isBashShebang = val.startsWith('#!/bin/bash') || val.startsWith('#!/usr/bin/env bash');
|
|
827
|
-
const isPosixShebang = val.startsWith('#!/bin/sh');
|
|
828
|
-
|
|
829
|
-
// 1. Critical Deadlock & Abort Check: read under set -e
|
|
830
|
-
const isSetEReadAbort = hasRead && hasSetE;
|
|
831
|
-
|
|
832
|
-
// 2. Critical Dependency Check: Missing binaries in minimal containers
|
|
833
|
-
// Minimal base images (debian-slim, ubuntu, alpine) strictly omit curl, jq, git, sudo, python, etc.
|
|
834
|
-
const uninstalledBins = ["curl", "jq", "git", "sudo", "python", "python3", "docker"];
|
|
835
|
-
let missingBin = null;
|
|
836
|
-
let missingBinLine = 1;
|
|
837
|
-
|
|
838
|
-
const lines = val.split('\n');
|
|
839
|
-
for (let i = 0; i < lines.length; i++) {
|
|
840
|
-
const line = lines[i].trim();
|
|
841
|
-
if (line.startsWith('#') || !line) continue;
|
|
842
|
-
for (const bin of uninstalledBins) {
|
|
843
|
-
// Check if command is called directly or in a pipe
|
|
844
|
-
const regex = new RegExp('(?:^|[|;&]\\s*)' + bin + '(?:\\s+|$)', 'i');
|
|
845
|
-
if (regex.test(line)) {
|
|
846
|
-
// Check if installed beforehand in script
|
|
847
|
-
const hasInstall = val.includes('apt-get install') && val.includes(bin) || val.includes('apk add') && val.includes(bin);
|
|
848
|
-
if (!hasInstall) {
|
|
849
|
-
missingBin = bin;
|
|
850
|
-
missingBinLine = i + 1;
|
|
851
|
-
break;
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
if (missingBin) break;
|
|
813
|
+
function runRealEngineAnalysis(val) {
|
|
814
|
+
if (val === CASES[activeKey].code) {
|
|
815
|
+
renderCase(CASES[activeKey]);
|
|
816
|
+
return;
|
|
856
817
|
}
|
|
857
|
-
|
|
858
|
-
if (val.includes('apt-get') && !val.includes('apk')) {
|
|
859
|
-
isAlpineFail = true;
|
|
860
|
-
alpineReason = "apt-get: not found (line 4)";
|
|
861
|
-
} else if (isBashShebang) {
|
|
862
|
-
isAlpineFail = true;
|
|
863
|
-
alpineReason = "/bin/bash: not found (line 1)";
|
|
864
|
-
} else if (isPosixShebang && hasBashism) {
|
|
865
|
-
isAlpineFail = true;
|
|
866
|
-
alpineReason = "syntax error: unexpected [[ or expansion";
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
const scWarnings = [];
|
|
870
|
-
if (hasRead && !val.includes('-r')) scWarnings.push("SC2162 (info): read without -r will mangle backslashes.");
|
|
871
|
-
if (isPosixShebang && hasBashism) scWarnings.push("SC3010 (warning): In POSIX sh, [[ ]] is undefined.");
|
|
872
|
-
if (val.includes('api_key') && !val.includes('$api_key')) scWarnings.push("SC2034 (warning): api_key appears unused. Verify use (or export if used externally).");
|
|
873
|
-
|
|
874
|
-
const scText = scWarnings.length > 0
|
|
875
|
-
? "$ shellcheck script.sh\n" + scWarnings.join('\n')
|
|
876
|
-
: "$ shellcheck script.sh\nNo issues detected. Syntax conforms to grammar.\n(Blind spot: linters verify syntax tokens, cannot check if binaries exist)";
|
|
877
|
-
|
|
878
|
-
let logs = [];
|
|
879
|
-
let overallStatus = "ALL DISTROS PASSED";
|
|
880
|
-
let statusClass = "bg-[var(--status-pass-bg)] text-[var(--status-pass-text)] border-[var(--status-pass-border)]";
|
|
881
|
-
let showDiag = false;
|
|
882
|
-
let diagCode = "Exit Code 0";
|
|
883
|
-
let diagMsg = "";
|
|
884
|
-
|
|
885
|
-
if (missingBin) {
|
|
886
|
-
// Missing command caught by container execution!
|
|
887
|
-
overallStatus = `MISSING BINARY: ${missingBin} (ALL FAILED)`;
|
|
888
|
-
statusClass = "bg-[var(--status-fail-bg)] text-[var(--status-fail-text)] border-[var(--status-fail-border)]";
|
|
889
|
-
showDiag = true;
|
|
890
|
-
diagCode = "Exit Code 127";
|
|
891
|
-
diagMsg = `Standard minimal container images (debian-slim, ubuntu, alpine) do not include '${missingBin}' by default. ShellCheck verified the syntax AST, but OpsScript Gate detected that '${missingBin}' is missing at line ${missingBinLine}.`;
|
|
892
|
-
|
|
893
|
-
const distros = [
|
|
894
|
-
{ d: "debian:12-slim", t: "0.15s" },
|
|
895
|
-
{ d: "ubuntu:22.04", t: "0.16s" },
|
|
896
|
-
{ d: "ubuntu:24.04", t: "0.16s" },
|
|
897
|
-
{ d: "alpine:3.20", t: "0.11s" }
|
|
898
|
-
];
|
|
899
|
-
distros.forEach(item => {
|
|
900
|
-
logs.push('<div class="my-1.5 px-2.5 py-1.5 rounded bg-[var(--status-fail-bg)] border-l-2 border-[var(--status-fail-text)] text-[var(--status-fail-text)]"><span class="font-semibold">[' + item.d + '] FAIL (' + item.t + ') - Exit 127</span><br><span class="opacity-95 font-mono text-[11px]"> /tmp/target_script.sh: line ' + missingBinLine + ': ' + missingBin + ': not found</span></div>');
|
|
901
|
-
});
|
|
902
|
-
} else if (isSetEReadAbort) {
|
|
903
|
-
// True Unix behavior: read returns 1 on EOF (from </dev/null), set -e aborts script instantly!
|
|
904
|
-
overallStatus = "STDIN DEADLOCK INTERCEPTED (ALL FAILED)";
|
|
905
|
-
statusClass = "bg-[var(--status-fail-bg)] text-[var(--status-fail-text)] border-[var(--status-fail-border)]";
|
|
906
|
-
showDiag = true;
|
|
907
|
-
diagCode = "Exit Code 1 (set -e)";
|
|
908
|
-
diagMsg = "Script called 'read' under unattended runner. OpsScript Gate bound stdin to </dev/null; read returned EOF (exit 1), causing 'set -e' to terminate execution immediately before reaching subsequent steps.";
|
|
909
|
-
|
|
910
|
-
const distros = ["debian:12-slim", "ubuntu:22.04", "ubuntu:24.04", "alpine:3.20"];
|
|
911
|
-
distros.forEach(d => {
|
|
912
|
-
logs.push('<div class="my-1.5 px-2.5 py-1.5 rounded bg-[var(--status-fail-bg)] border-l-2 border-[var(--status-fail-text)] text-[var(--status-fail-text)]"><span class="font-semibold">[' + d + '] FAIL (0.12s) - Exit 1</span><br><span class="opacity-95 font-mono text-[11px]"> read: end of file reached via </dev/null (aborted by set -e)</span></div>');
|
|
913
|
-
});
|
|
914
|
-
} else {
|
|
915
|
-
logs = [
|
|
916
|
-
'<div class="text-[var(--status-pass-text)] font-mono text-xs">[debian:12-slim] PASS (0.22s)' + (hasRead ? ' - stdin bound to </dev/null' : '') + '</div>',
|
|
917
|
-
'<div class="text-[var(--status-pass-text)] font-mono text-xs">[ubuntu:22.04] PASS (0.24s)' + (hasRead ? ' - stdin bound to </dev/null' : '') + '</div>',
|
|
918
|
-
'<div class="text-[var(--status-pass-text)] font-mono text-xs">[ubuntu:24.04] PASS (0.26s)' + (hasRead ? ' - stdin bound to </dev/null' : '') + '</div>'
|
|
919
|
-
];
|
|
920
|
-
|
|
921
|
-
if (isAlpineFail) {
|
|
922
|
-
overallStatus = "MATRIX DISCREPANCY DETECTED";
|
|
923
|
-
statusClass = "bg-[var(--status-fail-bg)] text-[var(--status-fail-text)] border-[var(--status-fail-border)]";
|
|
924
|
-
showDiag = true;
|
|
925
|
-
diagCode = "Exit Code 127";
|
|
926
|
-
diagMsg = "Discrepancy detected on Alpine minimal container: " + alpineReason;
|
|
927
|
-
logs.push('<div class="my-1.5 px-2.5 py-1.5 rounded bg-[var(--status-fail-bg)] border-l-2 border-[var(--status-fail-text)] text-[var(--status-fail-text)]"><span class="font-semibold">[alpine:3.20] FAIL (0.11s) - Exit 127</span><br><span class="opacity-95 font-mono text-[11px]"> /tmp/target_script.sh: ' + alpineReason + '</span></div>');
|
|
928
|
-
} else {
|
|
929
|
-
logs.push('<div class="text-[var(--status-pass-text)] font-mono text-xs">[alpine:3.20] PASS (0.18s)</div>');
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
|
|
933
818
|
renderRealApiResponse({
|
|
934
819
|
shellcheck: {
|
|
935
|
-
status_text:
|
|
936
|
-
warning_count:
|
|
937
|
-
output:
|
|
820
|
+
status_text: "NOT RUN",
|
|
821
|
+
warning_count: 0,
|
|
822
|
+
output: "This page does not run ShellCheck. Run shellcheck on your script locally or in CI."
|
|
938
823
|
},
|
|
939
824
|
opsscript: {
|
|
940
|
-
overall_status:
|
|
941
|
-
status_class:
|
|
942
|
-
terminal_html:
|
|
943
|
-
show_diagnostic:
|
|
944
|
-
diagnostic_code: diagCode,
|
|
945
|
-
diagnostic_msg: diagMsg
|
|
825
|
+
overall_status: "UNKNOWN — NOT EXECUTED",
|
|
826
|
+
status_class: "bg-[var(--surface-muted)] text-[var(--text-muted)] border-[var(--border-medium)]",
|
|
827
|
+
terminal_html: "No container execution has taken place. Copy the workflow below to test your script across distributions.",
|
|
828
|
+
show_diagnostic: false
|
|
946
829
|
}
|
|
947
830
|
});
|
|
948
831
|
}
|
|
@@ -951,10 +834,12 @@ jobs:
|
|
|
951
834
|
const sc = data.shellcheck;
|
|
952
835
|
const ops = data.opsscript;
|
|
953
836
|
|
|
954
|
-
//
|
|
837
|
+
// Render the analysis state
|
|
955
838
|
const scStatus = document.getElementById('sc-status');
|
|
956
839
|
scStatus.innerText = sc.status_text;
|
|
957
|
-
scStatus.className = sc.
|
|
840
|
+
scStatus.className = sc.status_text === "NOT RUN"
|
|
841
|
+
? "font-mono text-xs font-semibold px-2 py-0.5 rounded border bg-[var(--surface-muted)] text-[var(--text-muted)] border-[var(--border-medium)]"
|
|
842
|
+
: sc.warning_count > 0
|
|
958
843
|
? "font-mono text-xs font-semibold px-2 py-0.5 rounded border bg-[var(--status-warn-bg)] text-[var(--status-warn-text)] border-[var(--status-warn-border)]"
|
|
959
844
|
: "font-mono text-xs font-semibold px-2 py-0.5 rounded border bg-[var(--status-pass-bg)] text-[var(--status-pass-text)] border-[var(--status-pass-border)]";
|
|
960
845
|
|
|
@@ -962,7 +847,7 @@ jobs:
|
|
|
962
847
|
scOutput.innerText = sc.output;
|
|
963
848
|
scOutput.className = "bg-[var(--code-bg)] border border-[var(--border-light)] rounded p-3 text-xs font-mono h-[160px] overflow-y-auto whitespace-pre-wrap leading-[1.65] text-[var(--code-text)] break-words fade-switch";
|
|
964
849
|
|
|
965
|
-
//
|
|
850
|
+
// Render the runtime state
|
|
966
851
|
const opsStatus = document.getElementById('ops-status');
|
|
967
852
|
opsStatus.innerText = ops.overall_status;
|
|
968
853
|
opsStatus.className = "font-mono text-xs font-semibold px-2 py-0.5 rounded border " + ops.status_class;
|
|
@@ -971,7 +856,7 @@ jobs:
|
|
|
971
856
|
opsOutput.innerHTML = ops.terminal_html;
|
|
972
857
|
opsOutput.className = "bg-[var(--code-bg)] border border-[var(--border-light)] rounded p-3 text-xs font-mono h-[160px] overflow-y-auto whitespace-pre-wrap leading-[1.65] text-[var(--code-text)] break-words fade-switch";
|
|
973
858
|
|
|
974
|
-
//
|
|
859
|
+
// Render diagnostic details
|
|
975
860
|
const panel = document.getElementById('diagnostic-panel');
|
|
976
861
|
if (ops.show_diagnostic) {
|
|
977
862
|
panel.style.display = 'block';
|