Use dedicated pseudoterminal

This commit is contained in:
Patrick Lühne 2020-05-27 01:51:41 +02:00
parent 0eb9f4929d
commit 8a886882b7
Signed by: patrick
GPG Key ID: 05F3611E97A70ABF
4 changed files with 53 additions and 14 deletions

View File

@ -1,2 +1,6 @@
#/usr/bin/env bash #/usr/bin/env bash
sudo /usr/lib/github-fast-env/github-fast-env.rb "$@" if [[ "$USER" == "git" ]] ; then
/usr/lib/github-fast-env/github-fast-env.rb "$@"
else
sudo -u git /usr/lib/github-fast-env/github-fast-env.rb "$@"
fi

View File

@ -133,13 +133,13 @@ def clean_up_named_pipes(control_socket, connection_id)
end end
def set_up_pseudoterminal(control_socket, pseudoterminal_path) def set_up_pseudoterminal(control_socket, pseudoterminal_path)
pseudoterminal_io = File.open(pseudoterminal_path, File::RDWR | File::NOCTTY) $pseudoterminal_io = File.open(pseudoterminal_path, File::RDWR | File::NOCTTY)
$original_stderr.puts " connecting to pseudoterminal #{pseudoterminal_path}" $original_stderr.puts " connecting to pseudoterminal #{pseudoterminal_path}"
$stdin.reopen(pseudoterminal_io) $stdin.reopen($pseudoterminal_io)
$stdout.reopen(pseudoterminal_io) $stdout.reopen($pseudoterminal_io)
$stderr.reopen(pseudoterminal_io) $stderr.reopen($pseudoterminal_io)
$original_stderr.puts " connected to pseudoterminal #{pseudoterminal_path}" $original_stderr.puts " connected to pseudoterminal #{pseudoterminal_path}"
@ -148,7 +148,7 @@ end
$original_stderr.puts "preloading common modules" $original_stderr.puts "preloading common modules"
load "/usr/lib/github-fast-env/preload.rb" #load "/usr/lib/github-fast-env/preload.rb"
$original_stderr.puts "ready to serve requests" $original_stderr.puts "ready to serve requests"
@ -207,18 +207,18 @@ while true
set_up_pseudoterminal(control_socket, pseudoterminal_path) set_up_pseudoterminal(control_socket, pseudoterminal_path)
end end
Process.gid = Process.egid = "git"
Process.uid = Process.euid = "git"
$original_stderr.puts " executing script #{script_path} (#{process_id})" $original_stderr.puts " executing script #{script_path} (#{process_id})"
begin begin
begin begin
load script_path, true load script_path, true
$original_stderr.puts " finished executing script"
rescue SystemExit => error rescue SystemExit => error
$original_stderr.puts " exit code: #{error.status}" $original_stderr.puts " exit code: #{error.status}"
exit_code = error.status exit_code = error.status
rescue StandardError => error rescue StandardError => error
$original_stderr.puts " error executing script"
$stdin = $original_stdin $stdin = $original_stdin
$stdout = $original_stdout $stdout = $original_stdout
$stderr = $original_stderr $stderr = $original_stderr
@ -247,9 +247,11 @@ while true
end end
begin begin
# TODO: submit correct exit code upon Ctrl + C
control_socket.puts "done #{exit_code}" control_socket.puts "done #{exit_code}"
rescue rescue
end end
control_socket.close control_socket.close
if mode == "named-pipes" if mode == "named-pipes"
@ -257,6 +259,8 @@ while true
end end
$original_stderr.puts " finished handling request (#{process_id})" $original_stderr.puts " finished handling request (#{process_id})"
$pseudoterminal_io.close
end end
} }

View File

@ -162,10 +162,20 @@ encoded_script_path = Base64.encode64(script_path).delete("\n")
read_ios = [$control_socket] read_ios = [$control_socket]
if $options[:interactive] if $options[:interactive]
pseudoterminal_path = File.readlink("/proc/self/fd/0") #pseudoterminal_path = File.readlink("/proc/self/fd/0")
encoded_pseudoterminal_path = Base64.encode64(pseudoterminal_path).delete("\n") #encoded_pseudoterminal_path = Base64.encode64(pseudoterminal_path).delete("\n")
require "pty"
$control_socket.puts "new v1 pseudoterminal #{encoded_pseudoterminal_path} #{working_directory} #{encoded_script_path}" $pseudoterminal_master, pseudoterminal_client = PTY.open
$pseudoterminal_master.raw!
log "info", "opened pseudoterminal at #{pseudoterminal_client.path}"
encoded_pseudoterminal_client_path = Base64.encode64(pseudoterminal_client.path).delete("\n")
read_ios += [$stdin, $pseudoterminal_master]
$control_socket.puts "new v1 pseudoterminal #{encoded_pseudoterminal_client_path} #{working_directory} #{encoded_script_path}"
else else
$control_socket.puts "new v1 named-pipes #{working_directory} #{encoded_script_path}" $control_socket.puts "new v1 named-pipes #{working_directory} #{encoded_script_path}"
end end
@ -216,7 +226,9 @@ end
exit_code = "unknown" exit_code = "unknown"
while read_ios.include?($control_socket) or read_ios.include?(pipes["stdout"]) or read_ios.include?(pipes["stderr"]) pseudoterminal_master_closed = false
while read_ios.include?($control_socket) or read_ios.include?($pseudoterminal_master) or read_ios.include?(pipes["stdout"]) or read_ios.include?(pipes["stderr"])
log "trace", read_ios.inspect log "trace", read_ios.inspect
ready_read_ios, _, _ = IO.select(read_ios, [], []) ready_read_ios, _, _ = IO.select(read_ios, [], [])
@ -227,13 +239,23 @@ while read_ios.include?($control_socket) or read_ios.include?(pipes["stdout"]) o
begin begin
if ready_read_io.equal? $stdin if ready_read_io.equal? $stdin
log "trace", "writing to stdin" log "trace", "writing to stdin"
pipes["stdin"].write ready_read_io.readpartial(4096) chunk = ready_read_io.readpartial(4096)
if $options[:interactive]
if not pseudoterminal_master_closed
$pseudoterminal_master.write chunk
end
else
pipes["stdin"].write chunk
end
elsif ready_read_io.equal? pipes["stdout"] elsif ready_read_io.equal? pipes["stdout"]
log "trace", "reading from stdout" log "trace", "reading from stdout"
$stdout.write ready_read_io.readpartial(4096) $stdout.write ready_read_io.readpartial(4096)
elsif ready_read_io.equal? pipes["stderr"] elsif ready_read_io.equal? pipes["stderr"]
log "trace", "reading from stderr" log "trace", "reading from stderr"
$stderr.write ready_read_io.readpartial(4096) $stderr.write ready_read_io.readpartial(4096)
elsif ready_read_io.equal? $pseudoterminal_master
log "trace", "reading from pseudoterminal client"
$stdout.write ready_read_io.readpartial(4096)
elsif ready_read_io.equal? $control_socket elsif ready_read_io.equal? $control_socket
log "trace", "reading from control socket" log "trace", "reading from control socket"
command, arguments = read_command command, arguments = read_command
@ -249,6 +271,11 @@ while read_ios.include?($control_socket) or read_ios.include?(pipes["stdout"]) o
log "warn", "received input from unknown stream" log "warn", "received input from unknown stream"
end end
rescue EOFError rescue EOFError
if ready_read_io == $control_socket
$pseudoterminal_master.close_write
pseudoterminal_master_closed = true
end
log "trace", "closing stream #{ready_read_io}" log "trace", "closing stream #{ready_read_io}"
ready_read_io.close ready_read_io.close
end end
@ -262,3 +289,5 @@ exit_code_is_numeric = Integer(exit_code) != nil rescue false
if exit_code_is_numeric if exit_code_is_numeric
exit Integer(exit_code) exit Integer(exit_code)
end end
exit 1

View File

@ -4,6 +4,8 @@ After=github-enterprise.target
Wants=github-enterprise.target Wants=github-enterprise.target
[Service] [Service]
User=git
Group=git
RuntimeDirectory=github-fast-env RuntimeDirectory=github-fast-env
RuntimeDirectoryMode=0700 RuntimeDirectoryMode=0700
Type=simple Type=simple