MCPcopy Create free account
hub / github.com/Dispatcharr/Dispatcharr / execute

Method execute

apps/connect/handlers/script.py:97–150  ·  view source on GitHub ↗
(self)

Source from the content-addressed store, hash-verified

95
96class ScriptHandler(IntegrationHandler):
97 def execute(self):
98 raw_path = self.integration.config.get("path")
99 if not raw_path:
100 raise ValueError("Missing 'path' in integration config")
101
102 # Resolve and validate path
103 real_path = os.path.abspath(os.path.realpath(raw_path))
104
105 if not os.path.exists(real_path):
106 raise FileNotFoundError(f"Script not found: {real_path}")
107
108 if not _is_path_allowed(real_path):
109 raise PermissionError(
110 f"Script path '{real_path}' not within allowed directories: "
111 f"{getattr(settings, 'CONNECT_ALLOWED_SCRIPT_DIRS', [])}"
112 )
113
114 if getattr(settings, "CONNECT_SCRIPT_REQUIRE_EXECUTABLE", True):
115 if not os.access(real_path, os.X_OK):
116 raise PermissionError(f"Script is not executable: {real_path}")
117
118 if getattr(settings, "CONNECT_SCRIPT_DISALLOW_WORLD_WRITABLE", True):
119 st = os.stat(real_path)
120 if st.st_mode & stat.S_IWOTH:
121 raise PermissionError(
122 f"Refusing to execute world-writable script: {real_path}"
123 )
124
125 # Build a sanitized minimal environment; avoid inheriting secrets
126 env = {
127 "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
128 }
129 for key, value in (self.payload or {}).items():
130 env_key = f"DISPATCHARR_{str(key).upper()}"
131 env[env_key] = "" if value is None else str(value)
132
133 # Run with a timeout to prevent hanging scripts
134 timeout = getattr(settings, "CONNECT_SCRIPT_TIMEOUT", 10)
135 max_out = getattr(settings, "CONNECT_SCRIPT_MAX_OUTPUT", 65536)
136
137 rc, stdout, stderr = _posix_run(real_path, env, timeout)
138
139 # Truncate outputs to avoid excessive memory/logging
140 if len(stdout) > max_out:
141 stdout = stdout[:max_out] + "... [truncated]"
142 if len(stderr) > max_out:
143 stderr = stderr[:max_out] + "... [truncated]"
144
145 return {
146 "exit_code": rc,
147 "stdout": stdout,
148 "stderr": stderr,
149 "success": rc == 0,
150 }

Callers 15

testMethod · 0.95
_gevent_ws_sendFunction · 0.45
_force_utc0Method · 0.45
handleMethod · 0.45
update_stream_profileMethod · 0.45

Calls 4

_is_path_allowedFunction · 0.85
_posix_runFunction · 0.85
getMethod · 0.45
existsMethod · 0.45

Tested by

no test coverage detected