-
Notifications
You must be signed in to change notification settings - Fork 0
first #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
first #2
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
a9ab59d
first
reynoldsnlp 25b2e4b
pre-commit
reynoldsnlp 5972972
action versions
reynoldsnlp df2702f
isort
reynoldsnlp 03000f9
Adding commentary on unit file settings
benrencher fcfc0b9
make names less ambiguous
reynoldsnlp f13d866
fixes suggested by Ben
reynoldsnlp 99caf67
example explicit
reynoldsnlp File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| name: Tests | ||
|
|
||
| on: | ||
| pull_request: | ||
| push: | ||
| branches: [main] | ||
|
|
||
| jobs: | ||
| test: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 | ||
| with: | ||
| enable-cache: true | ||
|
|
||
| - name: Set up Python | ||
| run: uv python install 3.14 | ||
|
|
||
| - name: Install dependencies | ||
| run: uv sync --all-extras --dev | ||
|
|
||
| - name: Run ruff | ||
| run: uv run ruff check . | ||
|
|
||
| - name: Run ruff format check | ||
| run: uv run ruff format --check . | ||
|
|
||
| - name: Run tests | ||
| run: uv run pytest |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| repos: | ||
| - repo: https://github.com/pre-commit/pre-commit-hooks | ||
| rev: v5.0.0 | ||
| hooks: | ||
| - id: trailing-whitespace | ||
| - id: end-of-file-fixer | ||
| - id: check-yaml | ||
| - id: check-toml | ||
| - id: check-added-large-files | ||
| - id: check-merge-conflict | ||
| - id: check-case-conflict | ||
| - id: debug-statements | ||
| - id: mixed-line-ending | ||
|
|
||
| - repo: https://github.com/astral-sh/ruff-pre-commit | ||
| rev: v0.8.6 | ||
| hooks: | ||
| - id: ruff | ||
| args: [--fix] | ||
| - id: ruff-format | ||
|
|
||
| - repo: local | ||
| hooks: | ||
| - id: pytest | ||
| name: pytest | ||
| entry: uv run pytest | ||
| language: system | ||
| types: [python] | ||
| pass_filenames: false | ||
| always_run: true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| #!/bin/bash | ||
| # >>> fetch-runner-guard:BEGIN user=deploy | ||
| if [ "$(whoami)" != "deploy" ] || [ "$(id -u)" -eq 0 ]; then | ||
| printf 'fetch-runner-guard: refusing to run as %s (uid %s); required: deploy, non-root\n' "$(whoami)" "$(id -u)" >&2 | ||
| exit 1 | ||
| fi | ||
| # <<< fetch-runner-guard:END | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| # This script is designed to run identically whether fetch-runner invoked it | ||
| # on a new commit or a human invoked it from a terminal. The guard above is | ||
| # the only invariant: the caller must be user=deploy and not root. | ||
|
|
||
| cd "$(dirname -- "$0")" | ||
|
|
||
| echo "deploying $(basename -- "$PWD")" | ||
|
|
||
| # Your deploy steps here, e.g. a docker compose rollout: | ||
| # docker compose pull | ||
| # docker compose up --detach --remove-orphans | ||
| # docker image prune --force |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| [Unit] | ||
| Description=fetch-runner: poll git branches and run scripts on new commits | ||
| Documentation=https://github.com/BYU-ODH/fetch-runner | ||
| After=network-online.target | ||
| Wants=network-online.target | ||
|
|
||
| [Service] | ||
| Type=simple | ||
|
|
||
| # =========================================================================== | ||
| # CUSTOMIZE: edit the lines in this block for each deployment. | ||
| # =========================================================================== | ||
|
|
||
| # MUST match the `user` field in the jobs.toml this unit starts. | ||
| # fetch-runner exits at startup if they do not match. | ||
| User=deploy | ||
| Group=deploy | ||
|
|
||
| # Path to the fetch-runner binary and to the config file it should load. | ||
| # If you installed fetch-runner from a venv, point ExecStart at that venv's | ||
| # bin/fetch-runner. The config path is positional. | ||
| ExecStart=/usr/local/bin/fetch-runner /etc/fetch-runner/jobs.toml | ||
|
|
||
| # Every directory your deploy scripts need to write to must appear here | ||
| # (the git repos you poll, plus any app state they touch). Separate with | ||
| # spaces. The rest of the filesystem is read-only thanks to ProtectSystem. | ||
| ReadWritePaths=/srv | ||
|
|
||
| # =========================================================================== | ||
| # DO NOT MODIFY below this line casually. | ||
| # These settings are the sandbox that keeps a long-running deploy service from | ||
| # having broad access to the host. If you must relax one, document why. | ||
| # =========================================================================== | ||
|
|
||
| Restart=on-failure | ||
| RestartSec=10s | ||
| TimeoutStopSec=30s | ||
|
|
||
| # Send both fetch-runner logs and deploy-script output to journald so there is | ||
| # one place to inspect failures. | ||
| StandardOutput=journal | ||
| StandardError=journal | ||
|
|
||
| # Block privilege escalation; the deploy user never needs more than it has. | ||
| NoNewPrivileges=true | ||
| RestrictSUIDSGID=true | ||
| CapabilityBoundingSet= | ||
| AmbientCapabilities= | ||
|
|
||
| # Keep the filesystem read-only by default, then punch narrow write holes back | ||
| # in with `ReadWritePaths=` above for the repos and app state that deployments | ||
| # genuinely need to modify. | ||
| ProtectSystem=strict | ||
|
|
||
| # Deploy scripts should not need the service user's home directory. | ||
| ProtectHome=read-only | ||
|
|
||
| PrivateTmp=true | ||
| PrivateDevices=true | ||
| ProtectKernelTunables=true | ||
| ProtectKernelModules=true | ||
| ProtectKernelLogs=true | ||
|
|
||
| # Prevent deploy code from reconfiguring host control groups. If your rollout | ||
| # tool genuinely needs cgroup access, revisit this deliberately. | ||
| ProtectControlGroups=true | ||
|
|
||
| ProtectClock=true | ||
| ProtectHostname=true | ||
|
|
||
| # Hide unrelated processes from the service; deploy hooks should not be | ||
| # inspecting the rest of the machine. | ||
| ProtectProc=invisible | ||
|
|
||
| # Kernel / namespace hardening. | ||
| LockPersonality=true | ||
| RestrictRealtime=true | ||
|
|
||
| # Prevent deploy code from creating new namespaces inside the sandbox. | ||
| RestrictNamespaces=true | ||
|
|
||
| RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 | ||
|
|
||
| # Syscall filter. | ||
| SystemCallArchitectures=native | ||
| SystemCallFilter=@system-service | ||
| SystemCallErrorNumber=EPERM | ||
|
|
||
| [Install] | ||
| WantedBy=multi-user.target | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # Sample fetch-runner config. | ||
| # fetch-runner will refuse to load this unless the process is running as the | ||
| # user named below (and not as root). | ||
|
|
||
| [general] | ||
| user = "deploy" | ||
| poll_interval_seconds = 60 | ||
|
|
||
| [[jobs]] | ||
| name = "my example api" | ||
| path = "/srv/api" | ||
| branch = "main" | ||
| script = "/srv/api/deploy.sh" | ||
| timeout_seconds = 600 | ||
|
benrencher marked this conversation as resolved.
|
||
|
|
||
| [[jobs]] | ||
| name = "my example web" | ||
| path = "/srv/web" | ||
| branch = "production" | ||
| script = "/srv/web/deploy.sh" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| [build-system] | ||
| requires = ["uv_build>=0.4.8,<100"] | ||
| build-backend = "uv_build" | ||
|
|
||
| [project] | ||
| name = "fetch-runner" | ||
| version = "0.1.0" | ||
| description = "Poll git branches and run scripts when new commits arrive" | ||
| readme = "README.md" | ||
| requires-python = ">=3.11" | ||
| license = { file = "LICENSE" } | ||
| authors = [{ name = "BYU ODH" }] | ||
| dependencies = [] | ||
|
|
||
| [project.scripts] | ||
| fetch-runner = "fetch_runner.cli:main" | ||
|
|
||
| [tool.uv.build-backend] | ||
| module-name = "fetch_runner" | ||
| module-root = "src" | ||
|
|
||
| [dependency-groups] | ||
| dev = [ | ||
| "pytest>=8", | ||
| "pre-commit>=3", | ||
| "ruff>=0.8", | ||
| ] | ||
|
|
||
| [tool.pytest.ini_options] | ||
| testpaths = ["tests"] | ||
| addopts = "-ra" | ||
|
|
||
| [tool.ruff] | ||
| line-length = 100 | ||
| target-version = "py311" | ||
| src = ["src", "tests"] | ||
|
|
||
| [tool.ruff.lint] | ||
| select = ["E", "F", "I", "W", "UP", "B"] | ||
|
|
||
| [tool.ruff.lint.isort] | ||
| known-first-party = ["fetch_runner"] | ||
| section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"] | ||
| force-single-line = true | ||
| force-sort-within-sections = false |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| from importlib.metadata import PackageNotFoundError | ||
| from importlib.metadata import version as _version | ||
|
|
||
| try: | ||
| __version__ = _version("fetch-runner") | ||
| except PackageNotFoundError: | ||
| __version__ = "0.0.0+unknown" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| from fetch_runner.cli import main | ||
|
|
||
| if __name__ == "__main__": | ||
| raise SystemExit(main()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import argparse | ||
| import logging | ||
| import signal | ||
| import sys | ||
| from pathlib import Path | ||
|
|
||
| from fetch_runner import __version__ | ||
| from fetch_runner.config import ConfigError | ||
| from fetch_runner.config import load_config | ||
| from fetch_runner.guard import GuardError | ||
| from fetch_runner.guard import render_canonical_script_guard | ||
| from fetch_runner.runner import GitPollingRunner | ||
|
|
||
| log = logging.getLogger("fetch_runner") | ||
|
|
||
|
|
||
| def main(argv: list[str] | None = None) -> int: | ||
| argument_parser = argparse.ArgumentParser( | ||
| prog="fetch-runner", | ||
| description="Poll git branches and run scripts when new commits arrive.", | ||
| ) | ||
| argument_parser.add_argument("config", type=Path, nargs="?", help="path to jobs.toml") | ||
| argument_parser.add_argument( | ||
| "--check", | ||
| action="store_true", | ||
| help="validate the config (including every script's guard) and exit", | ||
| ) | ||
|
benrencher marked this conversation as resolved.
|
||
| argument_parser.add_argument( | ||
| "--print-guard", | ||
| metavar="USER", | ||
| help="print the canonical guard block for USER and exit (for pasting into a new script)", | ||
| ) | ||
|
benrencher marked this conversation as resolved.
|
||
| argument_parser.add_argument( | ||
| "-v", | ||
| "--verbose", | ||
| action="store_true", | ||
| help="enable debug logging", | ||
| ) | ||
| argument_parser.add_argument( | ||
| "--version", | ||
| action="version", | ||
| version=f"fetch-runner {__version__}", | ||
| ) | ||
| cli_args = argument_parser.parse_args(argv) | ||
|
|
||
| _configure_logging(cli_args.verbose) | ||
|
|
||
| if cli_args.print_guard: | ||
| try: | ||
| sys.stdout.write(render_canonical_script_guard(cli_args.print_guard)) | ||
| except GuardError as e: | ||
| print(f"error: {e}", file=sys.stderr) | ||
| return 2 | ||
| return 0 | ||
|
|
||
| if cli_args.config is None: | ||
| argument_parser.error("config path is required (or use --print-guard)") | ||
|
|
||
| try: | ||
| runner_config = load_config(cli_args.config) | ||
| except ConfigError as e: | ||
| print(f"config error: {e}", file=sys.stderr) | ||
| return 2 | ||
|
|
||
| if cli_args.check: | ||
| print( | ||
| f"ok: user={runner_config.runtime_user} " | ||
| f"jobs={len(runner_config.jobs)} " | ||
| f"poll={runner_config.poll_interval_seconds}s" | ||
| ) | ||
| return 0 | ||
|
|
||
| runner = GitPollingRunner(runner_config) | ||
|
|
||
| def _handle_stop_signal(signum, _frame): | ||
| log.info("received signal %s; shutting down", signum) | ||
| runner.request_stop() | ||
|
|
||
| signal.signal(signal.SIGTERM, _handle_stop_signal) | ||
| signal.signal(signal.SIGINT, _handle_stop_signal) | ||
| return runner.run_forever() | ||
|
|
||
|
|
||
| def _configure_logging(verbose: bool) -> None: | ||
| logging.basicConfig( | ||
| level=logging.DEBUG if verbose else logging.INFO, | ||
| format="%(asctime)s %(levelname)s %(name)s: %(message)s", | ||
| datefmt="%Y-%m-%dT%H:%M:%S%z", | ||
| stream=sys.stderr, | ||
| ) | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.