Cross-distro shell script runtime compatibility checker

ShellCheck passed.
Your installer still failed on Alpine.

OpsScript Gate tests shell scripts in real Debian, Ubuntu, and Alpine containers. It is a GitHub Action and Python CLI that reports each distribution's PASS/FAIL result and diagnoses runtime failures such as command not found.

Use it for standalone installers, bootstrap scripts, and shell entrypoints. You supply the script; the tool runs the distribution matrix and collects the diagnostic report.

Add the runtime check to CI

A valid shell script can assume the wrong command

Save this as install.sh. The syntax is valid POSIX shell, but Alpine uses apk and does not supply apt-get in its standard image.

#!/bin/sh
set -eu
apt-get --version

Expected outcome for this example; this page does not execute containers in your browser.

ImageResultDiagnostic
debian:12-slimPASSExit 0
ubuntu:22.04PASSExit 0
ubuntu:24.04PASSExit 0
alpine:3.20FAILExit 127: apt-get: not found, line 3

A shell linter checks source code. Executing the script tests which commands actually exist in the target image. Run both checks to cover source mistakes and runtime assumptions.

A complete GitHub Actions workflow

Copy this into .github/workflows/shell-runtime.yml and set script-path to your installer. The Ubuntu runner starts the Debian, Ubuntu, and Alpine containers.

name: Shell runtime compatibility
on: [push, pull_request]
permissions:
  contents: read
jobs:
  runtime:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          persist-credentials: false
      - uses: Mresyzz/opsscript-gate@v0.9.2
        with:
          script-path: install.sh
          shell: auto
          format: markdown
          output: reports/compatibility.md

The report includes the image, exit code, script line where available, missing command, and remediation hint. GitHub Actions also receives workflow annotations and a Step Summary. Inspect the project's real CI demo runs.

What the failure tells you

apt-get: not found

Check for APT or apk before calling it. Package names differ by distribution; do not replace them blindly.

/bin/bash: not found

Minimal Alpine omits Bash by default. Use POSIX shell or declare an image or package prerequisite that supplies Bash.

curl or jq missing

Minimal images omit many convenience tools. Declare required tools through packages or explain the prerequisite in your installer.

Run the same check locally

Requires Python 3.10+ and a reachable Docker engine running Linux containers.

pip install opsscript-gate
opsscript-gate doctor
opsscript-gate run ./install.sh

The CLI supports table, Markdown, JSON, and SARIF reports. --dry-run previews the plan without Docker; it does not verify runtime compatibility.

Where this check fits

ShellCheck analyzes shell source; OpsScript Gate executes it across distributions. A handwritten Docker matrix can also run scripts, but you maintain its image list, timeouts, log parsing, and reports.

OpsScript Gate mounts each script independently. Sibling files and repository dependencies are not mounted. These are distribution user-space tests in containers, not separate Linux kernels or full-machine tests. Passing checks do not prove security or replace project integration tests.

Frequently asked questions

How do I test a shell script on Debian, Ubuntu, and Alpine?

Add the GitHub Action or install the CLI, then run the script in real containers for each distribution. The report identifies the failing image, exit code, line, and missing command.

Why can ShellCheck pass while the installer still fails?

ShellCheck analyzes source and syntax. It cannot know which binaries are installed in the image that executes the script. Runtime execution exposes missing commands and package-manager assumptions.

How do I diagnose apt-get: not found on Alpine?

Alpine normally uses apk. Detect the available package manager or document a distribution-specific prerequisite instead of assuming Debian's APT exists everywhere.

Can I run the check without GitHub Actions?

Yes. Install opsscript-gate from PyPI, make sure a Docker engine running Linux containers is reachable, and run opsscript-gate run ./install.sh.