opsscript-gate 0.1.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.
Files changed (36) hide show
  1. opsscript_gate-0.1.2/.gitattributes +9 -0
  2. opsscript_gate-0.1.2/.github/ISSUE_TEMPLATE/bug_report.yml +41 -0
  3. opsscript_gate-0.1.2/.github/ISSUE_TEMPLATE/distro_request.yml +33 -0
  4. opsscript_gate-0.1.2/.github/ISSUE_TEMPLATE/feature_request.yml +33 -0
  5. opsscript_gate-0.1.2/.github/assets/social-preview.png +0 -0
  6. opsscript_gate-0.1.2/.github/pull_request_template.md +18 -0
  7. opsscript_gate-0.1.2/.github/workflows/demo.yml +55 -0
  8. opsscript_gate-0.1.2/.github/workflows/release.yml +121 -0
  9. opsscript_gate-0.1.2/.github/workflows/test.yml +28 -0
  10. opsscript_gate-0.1.2/.gitignore +52 -0
  11. opsscript_gate-0.1.2/CHANGELOG.md +43 -0
  12. opsscript_gate-0.1.2/CONTRIBUTING.md +82 -0
  13. opsscript_gate-0.1.2/LICENSE +21 -0
  14. opsscript_gate-0.1.2/PKG-INFO +246 -0
  15. opsscript_gate-0.1.2/README.md +218 -0
  16. opsscript_gate-0.1.2/ROADMAP.md +33 -0
  17. opsscript_gate-0.1.2/SECURITY.md +35 -0
  18. opsscript_gate-0.1.2/action.yml +46 -0
  19. opsscript_gate-0.1.2/examples/alpine-incompatibility/README.md +18 -0
  20. opsscript_gate-0.1.2/examples/alpine-incompatibility/apt_dependency.sh +10 -0
  21. opsscript_gate-0.1.2/examples/basic/README.md +13 -0
  22. opsscript_gate-0.1.2/examples/basic/clean_setup.sh +19 -0
  23. opsscript_gate-0.1.2/examples/github-actions/README.md +5 -0
  24. opsscript_gate-0.1.2/examples/github-actions/workflow.yml +25 -0
  25. opsscript_gate-0.1.2/examples/interactive-hang/README.md +15 -0
  26. opsscript_gate-0.1.2/examples/interactive-hang/prompt_confirm.sh +12 -0
  27. opsscript_gate-0.1.2/pyproject.toml +65 -0
  28. opsscript_gate-0.1.2/src/opsscript_gate/__init__.py +4 -0
  29. opsscript_gate-0.1.2/src/opsscript_gate/cli.py +129 -0
  30. opsscript_gate-0.1.2/src/opsscript_gate/models.py +55 -0
  31. opsscript_gate-0.1.2/src/opsscript_gate/reporter.py +158 -0
  32. opsscript_gate-0.1.2/src/opsscript_gate/runner.py +292 -0
  33. opsscript_gate-0.1.2/tests/fixtures/fail_deps.sh +9 -0
  34. opsscript_gate-0.1.2/tests/fixtures/fail_hang.sh +21 -0
  35. opsscript_gate-0.1.2/tests/fixtures/pass_basic.sh +26 -0
  36. opsscript_gate-0.1.2/tests/test_runner.py +456 -0
@@ -0,0 +1,9 @@
1
+ # Auto-detect text files and perform LF normalization
2
+ * text=auto eol=lf
3
+
4
+ # Force shell scripts to strictly retain LF line endings
5
+ *.sh text eol=lf
6
+ *.yml text eol=lf
7
+ *.yaml text eol=lf
8
+ *.toml text eol=lf
9
+ *.py text eol=lf
@@ -0,0 +1,41 @@
1
+ name: Bug Report
2
+ description: File an issue about an unexpected failure or compatibility bug in opsscript-gate
3
+ title: "[BUG] "
4
+ labels: ["bug"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for taking the time to report an issue! Please provide as much detail as possible.
10
+ - type: textarea
11
+ id: description
12
+ attributes:
13
+ label: Bug Description
14
+ description: A clear and concise description of what happened.
15
+ placeholder: What went wrong?
16
+ validations:
17
+ required: true
18
+ - type: textarea
19
+ id: script
20
+ attributes:
21
+ label: Reproducible Shell Script
22
+ description: Provide a minimal shell script snippet reproducing the issue.
23
+ render: bash
24
+ validations:
25
+ required: true
26
+ - type: textarea
27
+ id: logs
28
+ attributes:
29
+ label: Output / Failure Diagnostics
30
+ description: Terminal output or GitHub Actions step summary.
31
+ render: text
32
+ validations:
33
+ required: true
34
+ - type: input
35
+ id: environment
36
+ attributes:
37
+ label: Environment Info
38
+ description: Operating system, Docker version, Python version, opsscript-gate version.
39
+ placeholder: Ubuntu 24.04, Docker 27.2, Python 3.12, opsscript-gate 0.1.1
40
+ validations:
41
+ required: false
@@ -0,0 +1,33 @@
1
+ name: Distribution Support Request
2
+ description: Request adding a new Linux distribution or version to the default matrix
3
+ title: "[DISTRO] Support "
4
+ labels: ["distro-matrix"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Suggesting a new Linux distribution? Please ensure an official public image exists and boots without interactive init.
10
+ - type: input
11
+ id: distro_image
12
+ attributes:
13
+ label: Proposed Docker Image
14
+ description: The official public container image tag.
15
+ placeholder: e.g. fedora:40, rockylinux:9
16
+ validations:
17
+ required: true
18
+ - type: textarea
19
+ id: use_case
20
+ attributes:
21
+ label: Rationale & Use Case
22
+ description: Why is testing this distribution valuable for production ops scripts?
23
+ validations:
24
+ required: true
25
+ - type: checkboxes
26
+ id: checks
27
+ attributes:
28
+ label: Distribution Compatibility Checklist
29
+ options:
30
+ - label: Image provides a standard POSIX /bin/sh.
31
+ required: true
32
+ - label: Container starts without systemd or interactive configuration.
33
+ required: true
@@ -0,0 +1,33 @@
1
+ name: Feature Request
2
+ description: Suggest an idea or architectural improvement for opsscript-gate
3
+ title: "[FEATURE] "
4
+ labels: ["enhancement"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ We appreciate feature suggestions! Please note our security boundaries: no privileged containers, read-only script mounts, and timeouts.
10
+ - type: textarea
11
+ id: problem
12
+ attributes:
13
+ label: Problem Statement
14
+ description: What problem are you trying to solve?
15
+ validations:
16
+ required: true
17
+ - type: textarea
18
+ id: solution
19
+ attributes:
20
+ label: Proposed Solution
21
+ description: Describe your proposed change or command option.
22
+ validations:
23
+ required: true
24
+ - type: checkboxes
25
+ id: security_check
26
+ attributes:
27
+ label: Security Assessment
28
+ description: Please verify that this proposal adheres to unprivileged runtime boundaries.
29
+ options:
30
+ - label: Does NOT require container privilege or root access on the host.
31
+ required: true
32
+ - label: Respects timeouts and non-interactive execution.
33
+ required: true
@@ -0,0 +1,18 @@
1
+ ## Description
2
+
3
+ Briefly describe the change and the motivation behind it.
4
+
5
+ ## Changes Made
6
+ -
7
+
8
+ ## Runner Safety Verification
9
+ Please check all that apply:
10
+ - [ ] Unprivileged mode maintained (`privileged=False`)
11
+ - [ ] Capabilities drop maintained (`cap_drop=["ALL"]`)
12
+ - [ ] `no-new-privileges:true` maintained
13
+ - [ ] Target scripts remain mounted read-only (`:ro`)
14
+ - [ ] Timeout and container cleanup logic preserved
15
+
16
+ ## Testing
17
+ - [ ] Unit tests added/updated (`pytest -v -m "not integration"`)
18
+ - [ ] All tests passing locally
@@ -0,0 +1,55 @@
1
+ name: Demo Shell Script Compatibility Gate
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ compatibility-demo:
10
+ name: Cross-Distro Compatibility Demos
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - name: Checkout repository
14
+ uses: actions/checkout@v7
15
+
16
+ # Scenario 1: Fully compatible POSIX script passes on all 4 distributions
17
+ - name: "Scenario 1: POSIX script verification (Expect: ALL PASS)"
18
+ uses: ./
19
+ with:
20
+ script-path: 'tests/fixtures/pass_basic.sh'
21
+ matrix: 'debian:12-slim,ubuntu:22.04,ubuntu:24.04,alpine:3.20'
22
+ timeout: '30'
23
+ format: 'table'
24
+
25
+ # Scenario 2: Alpine catches missing apt-get dependency (exit 127 intercepted)
26
+ - name: "Scenario 2: Missing dependency interception (Expect: Alpine FAIL 127)"
27
+ id: demo_fail_deps
28
+ continue-on-error: true
29
+ uses: ./
30
+ with:
31
+ script-path: 'tests/fixtures/fail_deps.sh'
32
+ matrix: 'debian:12-slim,ubuntu:22.04,ubuntu:24.04,alpine:3.20'
33
+ timeout: '30'
34
+ format: 'table'
35
+
36
+ - name: Verify Scenario 2 Interception
37
+ if: steps.demo_fail_deps.outcome == 'failure'
38
+ run: |
39
+ echo "::notice title=Interception Verified::Successfully caught missing apt-get on Alpine (Exit code 127 intercepted)!"
40
+
41
+ # Scenario 3: Script waiting for interactive input terminated immediately by /dev/null
42
+ - name: "Scenario 3: Interactive hang defense (Expect: /dev/null EOF failure intercepted)"
43
+ id: demo_fail_hang
44
+ continue-on-error: true
45
+ uses: ./
46
+ with:
47
+ script-path: 'tests/fixtures/fail_hang.sh'
48
+ matrix: 'alpine:3.20'
49
+ timeout: '15'
50
+ format: 'table'
51
+
52
+ - name: Verify Scenario 3 Interception
53
+ if: steps.demo_fail_hang.outcome == 'failure'
54
+ run: |
55
+ echo "::notice title=Anti-Hang Verified::Interactive prompt prevented from hanging CI by automatic /dev/null redirection!"
@@ -0,0 +1,121 @@
1
+ name: Build and Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ name: Run Test Suite
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - name: Checkout Code
18
+ uses: actions/checkout@v7
19
+
20
+ - name: Set up Python
21
+ uses: actions/setup-python@v7
22
+ with:
23
+ python-version: '3.12'
24
+
25
+ - name: Install Dependencies
26
+ run: |
27
+ python -m pip install --upgrade pip
28
+ pip install -e .[test]
29
+
30
+ - name: Run Tests
31
+ run: |
32
+ pytest -v -m "not integration"
33
+
34
+ build:
35
+ name: Build Distribution Packages
36
+ needs: test
37
+ runs-on: ubuntu-latest
38
+ permissions:
39
+ contents: write
40
+ steps:
41
+ - name: Checkout Code
42
+ uses: actions/checkout@v7
43
+
44
+ - name: Set up Python
45
+ uses: actions/setup-python@v7
46
+ with:
47
+ python-version: '3.12'
48
+
49
+ - name: Verify Version Consistency
50
+ shell: bash
51
+ run: |
52
+ TOML_VERSION=$(python -c "import tomllib; f=open('pyproject.toml', 'rb'); print(tomllib.load(f)['project']['version'])")
53
+ INIT_VERSION=$(python -c "import sys; sys.path.insert(0, 'src'); import opsscript_gate; print(opsscript_gate.__version__)")
54
+
55
+ echo "pyproject.toml version: $TOML_VERSION"
56
+ echo "opsscript_gate version: $INIT_VERSION"
57
+
58
+ if [ "$TOML_VERSION" != "$INIT_VERSION" ]; then
59
+ echo "::error::Version mismatch: pyproject.toml ($TOML_VERSION) != __init__.py ($INIT_VERSION)"
60
+ exit 1
61
+ fi
62
+
63
+ if [[ "${{ github.ref }}" =~ ^refs/tags/v ]]; then
64
+ TAG_VERSION="${GITHUB_REF_NAME#v}"
65
+ echo "Git tag version: $TAG_VERSION"
66
+ if [ "$TAG_VERSION" != "$TOML_VERSION" ]; then
67
+ echo "::error::Tag mismatch: Git tag v$TAG_VERSION does not match project version $TOML_VERSION"
68
+ exit 1
69
+ fi
70
+ fi
71
+
72
+ echo "Version consistency verified: $TOML_VERSION"
73
+
74
+ - name: Install build tools
75
+ run: |
76
+ python -m pip install --upgrade pip
77
+ pip install build twine
78
+
79
+ - name: Build sdist and wheel
80
+ run: |
81
+ python -m build
82
+
83
+ - name: Verify Package Metadata
84
+ run: |
85
+ python -m twine check dist/*
86
+
87
+ - name: Upload dist artifacts
88
+ uses: actions/upload-artifact@v4
89
+ with:
90
+ name: dist
91
+ path: dist/
92
+ retention-days: 7
93
+
94
+ - name: Create GitHub Release and Upload Assets
95
+ uses: softprops/action-gh-release@v2
96
+ if: startsWith(github.ref, 'refs/tags/v')
97
+ with:
98
+ files: dist/*
99
+ generate_release_notes: true
100
+
101
+ publish-pypi:
102
+ name: Publish to PyPI via OIDC
103
+ needs: [test, build]
104
+ if: startsWith(github.ref, 'refs/tags/v')
105
+ runs-on: ubuntu-latest
106
+ environment:
107
+ name: pypi
108
+ url: https://pypi.org/p/opsscript-gate
109
+ permissions:
110
+ id-token: write
111
+ steps:
112
+ - name: Download dist artifacts
113
+ uses: actions/download-artifact@v4
114
+ with:
115
+ name: dist
116
+ path: dist
117
+
118
+ - name: Publish package distributions to PyPI
119
+ uses: pypa/gh-action-pypi-publish@release/v1
120
+ with:
121
+ packages-dir: dist/
@@ -0,0 +1,28 @@
1
+ name: Test opsscript-gate
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, test ]
6
+ pull_request:
7
+ branches: [ main, test ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - name: Checkout Code
14
+ uses: actions/checkout@v7
15
+
16
+ - name: Set up Python
17
+ uses: actions/setup-python@v7
18
+ with:
19
+ python-version: '3.12'
20
+
21
+ - name: Install Dependencies
22
+ run: |
23
+ python -m pip install --upgrade pip
24
+ pip install -e .[test]
25
+
26
+ - name: Run Pytest
27
+ run: |
28
+ pytest -v -m "not integration"
@@ -0,0 +1,52 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ .Python
8
+ build/
9
+ develop-eggs/
10
+ dist/
11
+ downloads/
12
+ eggs/
13
+ .eggs/
14
+ lib/
15
+ lib64/
16
+ parts/
17
+ sdist/
18
+ var/
19
+ wheels/
20
+ share/python-wheels/
21
+ *.egg-info/
22
+ .installed.cfg
23
+ *.egg
24
+ MANIFEST
25
+
26
+ # Pytest / Test / Coverage
27
+ .pytest_cache/
28
+ .coverage
29
+ .coverage.*
30
+ .cache
31
+ nosetests.xml
32
+ coverage.xml
33
+ *.cover
34
+ *.log
35
+
36
+ # Environments
37
+ .env
38
+ .venv
39
+ env/
40
+ venv/
41
+ ENV/
42
+ env.bak/
43
+ venv.bak/
44
+
45
+ # IDE & OS files
46
+ .vscode/
47
+ .idea/
48
+ *.swp
49
+ *.swo
50
+ *~
51
+ .DS_Store
52
+ Thumbs.db
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.2] - 2026-09-18
9
+
10
+ ### Added
11
+ - Configured PyPI Trusted Publishing via GitHub Actions OIDC (`pypa/gh-action-pypi-publish`).
12
+ - Added full PyPI package metadata, classifiers, and project URLs to `pyproject.toml`.
13
+ - Ensured absolute asset URLs in `README.md` for seamless PyPI rendering.
14
+
15
+ ---
16
+
17
+ ## [0.1.1] - 2026-09-18
18
+
19
+ ### Added
20
+ - Created `examples/` directory showcasing basic setup, Alpine package manager incompatibility, and interactive hang prevention.
21
+ - Added GitHub Issue templates for bug reports, feature requests, and distribution support requests.
22
+ - Added `CONTRIBUTING.md`, `SECURITY.md`, and `ROADMAP.md`.
23
+ - Enforced `security_opt=["no-new-privileges:true"]` on all container executions.
24
+
25
+ ### Fixed
26
+ - Upgraded GitHub Actions dependencies to `actions/checkout@v7` and `actions/setup-python@v7` (Node 24 runtime).
27
+ - Fixed secret referencing syntax in release workflow to ensure reliable binary asset uploads.
28
+
29
+ ---
30
+
31
+ ## [0.1.0] - 2026-09-18
32
+
33
+ ### Added
34
+ - Initial MVP release of `opsscript-gate`.
35
+ - CLI entrypoint (`opsscript-gate run <script_path>`).
36
+ - Unprivileged container isolation engine supporting `debian:12-slim`, `ubuntu:22.04`, `ubuntu:24.04`, and `alpine:3.20`.
37
+ - Safe read-only script mounting (`:ro`).
38
+ - Hard per-container timeout with forced `SIGKILL` and cleanup.
39
+ - Stdin disconnection (`</dev/null`) and non-interactive environment enforcement.
40
+ - Windows CRLF line-ending normalization defense.
41
+ - Unified ASCII table, GitHub Actions Step Summary Markdown, and JSON reporting formats.
42
+ - Composite GitHub Action published to Marketplace.
43
+ - Unit and integration test suite.
@@ -0,0 +1,82 @@
1
+ # Contributing to OpsScript Gate
2
+
3
+ Thank you for your interest in contributing to **OpsScript Gate**! We welcome bug reports, compatibility test fixtures, feature suggestions, and pull requests.
4
+
5
+ ---
6
+
7
+ ## Development Setup
8
+
9
+ OpsScript Gate requires **Python 3.10+** and a standard virtual environment.
10
+
11
+ ```bash
12
+ # Clone the repository
13
+ git clone https://github.com/Mresyzz/opsscript-gate.git
14
+ cd opsscript-gate
15
+
16
+ # Create and activate virtual environment
17
+ python -m venv .venv
18
+ source .venv/bin/activate # On Windows: .venv\Scripts\activate
19
+
20
+ # Install package in editable mode with test dependencies
21
+ pip install -e .[test]
22
+ ```
23
+
24
+ ---
25
+
26
+ ## Running Tests
27
+
28
+ The test suite separates mocked unit tests from Docker integration tests:
29
+ - **Unit tests**: Use mocking and do not require a running Docker daemon.
30
+ - **Integration tests**: Labeled with `@pytest.mark.integration` and run against real Docker containers.
31
+
32
+ ```bash
33
+ # Run unit tests (recommended for daily development)
34
+ pytest -v -m "not integration"
35
+
36
+ # Run full test suite including live Docker integration tests
37
+ pytest -v
38
+ ```
39
+
40
+ Pull requests should pass the unit test suite.
41
+
42
+ ---
43
+
44
+ ## Runner safety constraints
45
+
46
+ Any changes affecting the container runner should preserve these constraints:
47
+
48
+ 1. **Unprivileged execution**:
49
+ - Containers must not run with `privileged=True`.
50
+ - `cap_drop` must remain `["ALL"]`.
51
+ - `security_opt` must include `["no-new-privileges:true"]`.
52
+ 2. **Read-only script mount**:
53
+ - Target scripts must remain read-only (`:ro`).
54
+ - Do not mount additional host filesystem paths into test containers.
55
+ 3. **Timeout & cleanup**:
56
+ - Containers reaching timeout limits should be terminated with `container.kill()`.
57
+ - Container removal in `finally` blocks must be preserved.
58
+ 4. **Non-interactive execution**:
59
+ - Standard input should remain detached (`stdin_open=False`, `tty=False`, `</dev/null`).
60
+ - Keep non-interactive environment variables (`DEBIAN_FRONTEND=noninteractive`, `CI=true`).
61
+ 5. **Scope**:
62
+ - Avoid emulating complex init systems (like systemd) inside containers; the runner focuses on standard script execution, command availability, and exit codes.
63
+
64
+ ---
65
+
66
+ ## Adding a New Linux Distribution
67
+
68
+ To propose or add a new distribution image:
69
+ 1. Ensure the official image is available on Docker Hub and is publicly accessible.
70
+ 2. Confirm the image contains `/bin/sh` for minimal POSIX execution.
71
+ 3. Add a representative compatibility test fixture in `tests/fixtures/` demonstrating standard behavior.
72
+ 4. Ensure the image does not require interactive initialization.
73
+
74
+ ---
75
+
76
+ ## Pull Request Workflow
77
+
78
+ 1. Fork the repository and create a descriptive feature branch from `main`.
79
+ 2. Make your modifications, adhering to standard Python formatting (PEP 8) and type hints.
80
+ 3. Add or update unit tests in `tests/test_runner.py` verifying both success and failure paths.
81
+ 4. Verify tests pass locally: `pytest -v -m "not integration"`.
82
+ 5. Open a Pull Request against the `main` branch with a clear summary of changes.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OpsScript Gate Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.