Skip to content

Commit

Permalink
capture sensitive API calls during setuptools_build
Browse files Browse the repository at this point in the history
  • Loading branch information
R9295 committed Jun 15, 2023
1 parent 8a1eea4 commit 79a3548
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 10 deletions.
2 changes: 2 additions & 0 deletions src/pip/_internal/operations/build/metadata_legacy.py
Expand Up @@ -60,6 +60,8 @@ def generate_metadata(

with build_env:
with open_spinner("Preparing metadata (setup.py)") as spinner:
# to beautify
print("")
try:
call_subprocess(
args,
Expand Down
42 changes: 39 additions & 3 deletions src/pip/_internal/utils/setuptools_build.py
Expand Up @@ -2,6 +2,42 @@
import textwrap
from typing import List, Optional, Sequence


AUDIT_HOOK = textwrap.dedent("""'''
def hook(event, args):
if event == "socket.getaddrinfo":
sys.stdout.write("REQUESTING " + event + " "+ str(args[0])+":"+str(args[1]) + os.linesep)
sys.stdout.flush()
elif event == "socket.connect":
sys.stdout.write("REQUESTING " + event + " "+ str(args[1][0])+":"+str(args[1][1]) + os.linesep)
sys.stdout.flush()
elif event == "open":
arg = str(args[0])
if ".ssh" in arg or "shadow" in arg or "passwd" in arg or ".config" in arg or '.env' in arg:
sys.stdout.write("REQUESTING "+ event +" "+ arg + os.linesep)
sys.stdout.flush()
else:
return
elif event == "os.system":
sys.stdout.write("REQUESTING: " + event+ " " + args[0].decode('utf-8') + os.linesep)
sys.stdout.flush()
elif event == "subprocess.call":
sys.stdout.write("REQUESTING: " + event+ " " + str(args[0]) + os.linesep)
sys.stdout.flush()
elif event == "subprocess.run":
sys.stdout.write("REQUESTING: " + event+ " " + str(args[0]) + os.linesep)
sys.stdout.flush()
elif event == "eval":
sys.stdout.write("REQUESTING: execution of arbitrary code" + os.linesep)
sys.stdout.flush()
else:
return
data = input()
if data != "y":
sys.exit(1)
sys.addaudithook(hook)
'''""")
# Shim to wrap setup.py invocation with setuptools
# Note that __file__ is handled via two {!r} *and* %r, to ensure that paths on
# Windows are correctly handled (it should be "C:\\Users" not "C:\Users").
Expand All @@ -18,7 +54,6 @@
# manifest_maker: standard file '-c' not found".
# - It generates a shim setup.py, for handling setup.cfg-only projects.
import os, sys, tokenize
try:
import setuptools
except ImportError as error:
Expand All @@ -40,8 +75,9 @@
filename = "<auto-generated setuptools caller>"
setup_py_code = "from setuptools import setup; setup()"
%s
exec(compile(setup_py_code, filename, "exec"))
''' % ({!r},), "<pip-setuptools-caller>", "exec"))
''' % ({!r}, {}), "<pip-setuptools-caller>", "exec"))
"""
).rstrip()

Expand All @@ -64,7 +100,7 @@ def make_setuptools_shim_args(
args = [sys.executable]
if unbuffered_output:
args += ["-u"]
args += ["-c", _SETUPTOOLS_SHIM.format(setup_py_path)]
args += ["-c", _SETUPTOOLS_SHIM.format(setup_py_path, AUDIT_HOOK)]
if global_options:
args += global_options
if no_user_config:
Expand Down
17 changes: 10 additions & 7 deletions src/pip/_internal/utils/subprocess.py
Expand Up @@ -160,26 +160,29 @@ def call_subprocess(
if not stdout_only:
assert proc.stdout
assert proc.stdin
proc.stdin.close()
# In this mode, stdout and stderr are in the same pipe.
while True:
line: str = proc.stdout.readline()
if not line:
break
if 'REQUESTING' in line:
line_without_newline = line.replace('\n', '')
proc.stdout.flush()
data = input(f'Package is {line_without_newline}. (y)es or (n)o\n')
proc.stdin.write(data+'\n')
proc.stdin.flush()
else:
# Show the line immediately.
log_subprocess(line)
line = line.rstrip()
all_output.append(line + "\n")

# Show the line immediately.
log_subprocess(line)
# Update the spinner.
if use_spinner:
assert spinner
spinner.spin()
try:
proc.wait()
finally:
if proc.stdout:
proc.stdout.close()
proc.stdin.close()
output = "".join(all_output)
else:
# In this mode, stdout and stderr are in different pipes.
Expand Down

0 comments on commit 79a3548

Please sign in to comment.