Files
ss-tools/scripts/dr_recovery_git_command.py

75 lines
2.5 KiB
Python

# #region Tooling.DrRecovery.Git.Runner [C:3] [TYPE Module] [SEMANTICS dr,recovery]
# @BRIEF Run bounded local Git subprocesses with closed configuration and owned process-group cleanup.
import os
import resource
import signal
import subprocess
import tempfile
from dr_recovery_io import Refused, require
# #region Tooling.DrRecovery.Git.Runner.Limits [C:3] [TYPE Function] [SEMANTICS dr,recovery]
def _limits():
resource.setrlimit(resource.RLIMIT_CPU, (30, 30))
resource.setrlimit(resource.RLIMIT_FSIZE, (128 * 1024 * 1024, 128 * 1024 * 1024))
resource.setrlimit(resource.RLIMIT_AS, (1024 * 1024 * 1024, 1024 * 1024 * 1024))
# #endregion Tooling.DrRecovery.Git.Runner.Limits
# #region Tooling.DrRecovery.Git.Command [C:3] [TYPE Function]
def git(root, args, code, output_limit=128 * 1024):
env = dict(
PATH="/usr/bin:/bin",
HOME="/nonexistent",
GIT_CONFIG_NOSYSTEM="1",
GIT_CONFIG_GLOBAL="/dev/null",
GIT_CONFIG_SYSTEM="/dev/null",
GIT_TERMINAL_PROMPT="0",
GIT_CONFIG_COUNT="0",
GIT_NO_REPLACE_OBJECTS="1",
GIT_OPTIONAL_LOCKS="0",
GIT_NO_LAZY_FETCH="1",
)
command = [
"/usr/bin/git",
"--git-dir=" + str(root),
"-c",
"protocol.allow=never",
"-c",
"core.hooksPath=/dev/null",
*args,
]
with tempfile.TemporaryFile() as stdout, tempfile.TemporaryFile() as stderr:
try:
process = subprocess.Popen(
command,
env=env,
stdin=subprocess.DEVNULL,
stdout=stdout,
stderr=stderr,
start_new_session=True,
preexec_fn=_limits,
)
except (OSError, subprocess.SubprocessError):
raise Refused("DR_RECOVERY_GIT_UNAVAILABLE") from None
try:
result = process.wait(timeout=30)
except subprocess.TimeoutExpired:
try:
os.killpg(process.pid, signal.SIGKILL)
except ProcessLookupError:
pass # The owned child/group can exit between the timeout and kill.
process.wait()
raise Refused("DR_RECOVERY_LIMIT") from None
require(result >= 0, "DR_RECOVERY_LIMIT")
require(result == 0, code)
require(
stdout.tell() <= output_limit and stderr.tell() <= 128 * 1024,
"DR_RECOVERY_LIMIT",
)
stdout.seek(0)
return stdout.read(output_limit + 1)
# #endregion Tooling.DrRecovery.Git.Command
# #endregion Tooling.DrRecovery.Git.Runner