Google SRE Python code review: How would you safely run kubectl and cloud CLI commands from a Python automation script without creating shell injection, hung-process, or unreadable-error risks?
Quick Answer
Use subprocess with an argument list, shell=False, explicit timeouts, captured output, check=True, and structured error handling. Avoid string-concatenated shell commands, validate user-controlled arguments, and return a typed result that preserves stdout, stderr, exit code, and duration.
Detailed Answer
Think of an automation script like a dispatcher sending technicians to data centers. If the dispatcher writes a vague instruction on a sticky note, the technician may interpret it differently, take too long, or do something dangerous. A production Python script calling kubectl, aws, helm, or terraform needs precise instructions, a deadline, and a clean incident report when something fails.
In Python, the safe default is subprocess.run with a list of arguments and shell=False. The Python documentation recommends passing arguments as a sequence because Python can handle escaping and quoting without involving a shell. That matters because shell=True turns one string into shell syntax, so characters such as semicolons, pipes, dollar expansion, and backticks become meaningful. In interview terms, this is not just style; it is a security boundary.
A strong implementation wraps subprocess calls in one function. The wrapper sets timeout, text=True, capture_output=True, check=True, cwd only when needed, and a minimal env when credentials or PATH should be controlled. It catches subprocess.TimeoutExpired and subprocess.CalledProcessError separately because a timeout is an operational failure while a non-zero exit is a command-level failure. The wrapper should log the command safely, redacting tokens and kubeconfigs, and it should never dump secrets from stderr into chat tools or tickets.
At scale, the tricky behavior is that automation failures are often partial. A kubectl apply may fail on one manifest after mutating another. An aws command may succeed but return paginated or eventually consistent data. A hung process can hold a deployment lock and block the next run. That is why serious automation includes idempotency, dry-run mode, bounded retries around known transient errors, and audit output that lets an on-call engineer prove exactly what was attempted.
The non-obvious gotcha is that avoiding shell=True does not automatically make input safe. If a user can pass --kubeconfig, --context, --namespace, or a file path, they can still redirect the automation into the wrong cluster or sensitive files. Senior candidates explain both layers: command invocation safety and business-rule validation of the arguments being passed.