Skip to content

Dockerize #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 49 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,54 @@
FROM tiangolo/uwsgi-nginx-flask:flask

COPY * /app
RUN apt-get update && apt-get upgrade --fix-missing -y
RUN apt-get update && apt-get install -y curl git bzr mercurial build-essential
RUN apt-get install -y zip ruby-full haskell-platform shellcheck ssh
RUN apt-get install -y python-pip python-dev
RUN apt-get install -y nodejs build-essential golang

RUN curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
RUN apt-get update && apt-get install -y ruby-full haskell-platform shellcheck nodejs build-essential nodejs-legacy
ENV NVM_DIR /usr/local/nvm
ENV NODE_VERSION node

# Install nvm with node and npm
RUN curl https://raw.githubusercontent.com/creationix/nvm/v0.33.0/install.sh | bash \
&& . $NVM_DIR/nvm.sh \
&& nvm install $NODE_VERSION \
&& nvm alias default $NODE_VERSION \
&& nvm use default \
&& npm install -g jsonlint jscs eslint jshint

ENV NODE_PATH $NVM_DIR/versions/node/v$NODE_VERSION/lib/node_modules
ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH

RUN echo '. "$NVM_DIR/nvm.sh"' >> /etc/profile
RUN echo NODE_VERSION=$NODE_VERSION >> /etc/environment
RUN echo NVM_DIR=$NVM_DIR >> /etc/environment
RUN echo NODE_PATH=$NVM_DIR/versions/node/v$NODE_VERSION/lib/node_modules >> /etc/environment
RUN echo PATH=$NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH >> /etc/environment

RUN pip install -U pip
RUN curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash
RUN export PATH="/root/.pyenv/bin:$PATH"
ENV PATH /root/.pyenv/bin:$PATH
RUN eval "$(pyenv init -)"
RUN eval "$(pyenv virtualenv-init -)"
RUN pyenv update
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably want the pyenv steps lower down in the dockerfile than the known hosts steps, since they're more likely to change. E.g. when you want to switch to a new python version.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably. the pyenv stuff isn't even working yet anyway, it still seems to be using the system python.

RUN pyenv install 2.7.13
RUN pyenv install 3.6.0
RUN pyenv global 2.7.13 3.6.0
COPY ./app /app
COPY requirements.txt /app
RUN pip install -r /app/requirements.txt

# Install rvm (https://github.com/vallard/docker/blob/master/rails/Dockerfile)
RUN apt-get install -y curl patch gawk g++ gcc make libc6-dev patch libreadline6-dev zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev sqlite3 autoconf libgdbm-dev libncurses5-dev automake libtool bison pkg-config libffi-dev
RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
RUN curl -L https://get.rvm.io | bash -s stable
RUN bash -l -c "rvm requirements"
RUN bash -l -c "rvm install 2.0"
RUN bash -l -c "gem install bundler --no-ri --no-rdoc"

RUN mkdir -p /root/.ssh
RUN touch /root/.ssh/known_hosts
RUN chmod 0700 /root/.ssh
RUN chmod 0600 /root/.ssh/known_hosts
2 changes: 1 addition & 1 deletion Procfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
web: python main.py
web: python app/main.py
81 changes: 78 additions & 3 deletions main.py → app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
from __future__ import print_function
from __future__ import unicode_literals

import hashlib
import os
import random
import re
import shutil
import subprocess
import tempfile
import threading
import time
import traceback
from flask import Flask, request, redirect
import github3

app = Flask(__name__)

Expand All @@ -20,7 +24,37 @@
SAFE_ENV['TOKEN'] = ''
DOTFILES = 'dotfiles'
STOP_FILE_NAME = '.inlineplzstop'
SSH_FILE_NAME = 'inline_plz_rsa'
SSH_FILE_PATH = os.path.join(os.path.expanduser('~'), '.ssh', SSH_FILE_NAME)
REVIEWS_IN_PROGRESS = dict()
SSH_LOCK = threading.Lock()


def ssh_keygen():
time.sleep(random.randint(1, 10))
while not os.path.exists(SSH_FILE_PATH):
try:
subprocess.check_call(['ssh-keygen', '-t', 'rsa', '-b', '2048', '-f', SSH_FILE_PATH, '-q', '-N', ''])
ssh_output = subprocess.check_output('ssh-agent -s', shell=True, stderr=subprocess.STDOUT)
# http://code.activestate.com/recipes/533143-set-environment-variables-for-using-ssh-in-python-/
for sh_line in ssh_output.splitlines():
matches=re.search("(\S+)\=(\S+)\;", sh_line)
if matches:
os.environ[matches.group(1)]=matches.group(2)
SAFE_ENV[matches.group(1)]=matches.group(2)
subprocess.check_call('ssh-add {}'.format(SSH_FILE_PATH), shell=True)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bandit: subprocess call with shell=True identified, security issue.

except Exception:
traceback.print_exc()
time.sleep(random.randint(1, 10))


TRUSTED = os.environ.get('TRUSTED', '').lower().strip() in ['true', 'yes', '1']
if TRUSTED:
ssh_keygen()

SSH_KEY_HASH = hashlib.md5()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bandit: Use of insecure MD2, MD4, or MD5 hash function.

SSH_KEY_HASH.update(open(SSH_FILE_PATH).read())
SSH_KEY_HASH = SSH_KEY_HASH.hexdigest()[-6:]


@app.errorhandler(Exception)
Expand Down Expand Up @@ -63,14 +97,52 @@ def clone_dotfiles(url, org, tempdir, token):
return clone(clone_url, dotfile_path, token)


def ssh_setup(url, token):
with SSH_LOCK:
try:
with open(os.path.join(os.path.expanduser('~'), '.ssh', 'config'), 'ar+') as sshconfig:
contents = sshconfig.read()
if not 'HostName {}'.format(url) in contents:
sshconfig.write('\nHost {0}\n\tHostName {0}\n\tIdentityFile {1}'.format(url, SSH_FILE_PATH))
except Exception:
traceback.print_exc()
if not url or url in ['http://github.com', 'https://github.com']:
github = github3.GitHub(token=token)
else:
github = github3.GitHubEnterprise(url, token=token)

key_found = False
for key in github.iter_keys():
if SSH_FILE_NAME in key.title and not SSH_KEY_HASH in key.title:
github.delete_key(key.id)
elif key.title == '{}_{}'.format(SSH_FILE_NAME, SSH_KEY_HASH):
key_found = True
if not key_found:
github.create_key('{}_{}'.format(SSH_FILE_NAME, SSH_KEY_HASH), open(SSH_FILE_PATH + '.pub').read())

keygen_url = url.split('//')[-1]
try:
output = subprocess.check_output(['ssh-keygen', '-F', keygen_url], stderr=subprocess.STDOUT)
if output.strip():
return
except subprocess.CalledProcessError:
traceback.print_exc()
try:
output = subprocess.check_output(['ssh-keyscan', '-t', 'rsa', keygen_url], stderr=subprocess.STDOUT)
with open(os.path.join(os.path.expanduser('~'), '.ssh', 'known_hosts'), 'a') as known_hosts:
known_hosts.write(output)
except Exception:
traceback.print_exc()


def lint(data):
try:
pull_request = data['pull_request']['number']
repo_slug = data['repository']['full_name']
name = data['repository']['name']
token = os.environ.get('TOKEN')
interface = 'github'
url = os.environ.get('URL', 'https://github.com')
url = 'https://' + data['repository']['ssh_url'].split('@')[1].split(':')[0]
event_type = data['action']
sha = data['pull_request']['head']['sha']
ref = data['pull_request']['head']['ref']
Expand All @@ -79,7 +151,7 @@ def lint(data):
except KeyError:
traceback.print_exc()
return 'Invalid pull request data.'
trusted = os.environ.get('TRUSTED', '').lower().strip() in ['true', 'yes', '1']


print('Starting inline-plz:')
print('Event: {}'.format(event_type))
Expand All @@ -92,6 +164,9 @@ def lint(data):
if event_type not in ['opened', 'synchronize']:
return

if TRUSTED:
ssh_setup(url, token)

# make temp dirs
tempdir = tempfile.mkdtemp()
dotfile_dir = tempfile.mkdtemp()
Expand Down Expand Up @@ -130,7 +205,7 @@ def lint(data):
'--interface={}'.format(interface),
'--zero-exit'
]
if trusted:
if TRUSTED:
args.append('--trusted')
if clone_dotfiles(url, org, dotfile_dir, token):
args.append('--config-dir={}'.format(
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ configparser==3.5.0
docutils==0.12
dodgy==0.1.9
Flask==0.11.1
github3.py==0.9.5
github3.py==0.9.6
inlineplz==0.23.1
isort==4.2.5
itsdangerous==0.24
Expand Down