diff --git a/ci/Dockerfile b/ci/Dockerfile
new file mode 100644
index 0000000..b76e798
--- /dev/null
+++ b/ci/Dockerfile
@@ -0,0 +1,37 @@
+FROM debian:8 AS base
+ENV DEBIAN_FRONTEND=noninteractive
+RUN apt-get update && \
+ apt-get upgrade && \
+ apt-get install --no-install-recommends --no-install-suggests -y \
+ gcc \
+ git \
+ openssh-client \
+ make \
+ python \
+ python-dev \
+ python-virtualenv \
+ virtualenv
+
+
+ENV LC_ALL=C.utf8
+ENV LANG=C.utf8
+ENV LANGUAGE=C.utf8
+# Add user jenkins to the image
+RUN groupadd -g 1001 jenkins && \
+ useradd -m -u 1001 -g 1001 -d /home/jenkins2 -s /bin/bash jenkins && \
+ mkdir /home/jenkins && chown jenkins:jenkins /home/jenkins && \
+ echo "jenkins:jenkins" | chpasswd
+USER jenkins
+RUN virtualenv /home/jenkins/secopvenv
+
+FROM base AS docs
+ENV DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update && \
+ apt-get install -y --no-install-suggests --no-install-recommends \
+ texlive-latex-extra \
+ texlive-latex-base \
+ texlive-latex-recommended \
+ texlive-base \
+ texlive-binaries
+
diff --git a/ci/Jenkinsfile b/ci/Jenkinsfile
new file mode 100644
index 0000000..fe54eaa
--- /dev/null
+++ b/ci/Jenkinsfile
@@ -0,0 +1,112 @@
+properties([
+ buildDiscarder(logRotator(artifactDaysToKeepStr: '',
+ artifactNumToKeepStr: '',
+ daysToKeepStr: '',
+ numToKeepStr: '50')),
+ parameters([
+ string(defaultValue: 'sine2020/secop/playground',
+ description: '', name: 'GERRIT_PROJECT'),
+ string(defaultValue: 'master',
+ description: '', name: 'GERRIT_BRANCH'),
+ string(defaultValue: 'refs/heads/master',
+ description: '', name: 'GERRIT_REFSPEC'),
+ choice(choices: '''\
+patchset-created
+ref-updated
+change-merged''',
+ description: '', name: 'GERRIT_EVENT'),
+ choice(choices: '''\
+patchset-created
+ref-updated
+change-merged''',
+ description: '', name: 'GERRIT_EVENT_TYPE')])
+])
+
+
+
+this.verifyresult = [:]
+
+def run_tests(pyver)
+{
+ writeFile file: 'setup.cfg', text: '''
+[tool:pytest]
+addopts = --junit-xml=pytest.xml --junit-prefix=''' + pyver
+
+ def status = "OK"
+ verifyresult.put(pyver, 0)
+ try {
+ timeout(5) {
+ sh '''\
+#!/bin/bash
+. /home/jenkins/secopvenv/bin/activate
+pip install -r requirements-dev.txt
+pip install -r requirements.txt
+make test
+'''
+ verifyresult.put(pyver, 1)
+ }
+ } catch (all) {
+ currentBuild.result = 'FAILURE'
+ status = 'FAILURE'
+ verifyresult.put(pyver, -1)
+ }
+ gerritverificationpublisher([
+ verifyStatusValue: verifyresult[pyver],
+ verifyStatusCategory: 'test ',
+ verifyStatusName: 'pytest-'+pyver,
+ verifyStatusReporter: 'jenkins',
+ verifyStatusRerun: '!recheck'])
+
+ step([$class: 'JUnitResultArchiver', allowEmptyResults: true,
+ keepLongStdio: true, testResults: 'pytest.xml'])
+ if (status == 'FAILURE') {
+ throw new Exception('Failure in test with ' + pyver)
+ }
+}
+
+
+node("master") {
+ stage('clean workspace')
+ {
+ cleanWs()
+ }
+ stage('checkout') {
+ checkout poll: false,
+ scm: [$class: 'GitSCM',
+ branches: [[name: '${GERRIT_BRANCH}']],
+ doGenerateSubmoduleConfigurations: false,
+ extensions: [
+ [$class: 'CleanCheckout'],
+ [$class: 'hudson.plugins.git.extensions.impl.BuildChooserSetting',
+ buildChooser: [$class: "com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.GerritTriggerBuildChooser"]],
+ ],
+ submoduleCfg: [],
+ userRemoteConfigs:
+ [[
+ refspec: GERRIT_REFSPEC,
+ credentialsId: 'jenkins_ecdsa_x',
+ url: 'ssh://jenkins@forge.frm2.tum.de:29418/${GERRIT_PROJECT}']]]
+ sh 'git show'
+ }
+ stage('(re-)generate image') {
+ try {
+ sh '''#!/bin/bash
+ git worktree add tmpmaster refs/changes/17/18617/8
+ cd tmpmaster
+ docker build --target base --tag jenkinsng.admin.frm2:5000/secop_base:latest \
+ --tag secop_base:latest ci
+ cd ..
+ rm -rf tmpmaster
+ '''
+ } catch (all) {
+ }
+ }
+
+ stage('execute tests') {
+ img = docker.image('jenkinsng.admin.frm2:5000/secop_base:latest')
+ img.pull()
+ img.inside {
+ run_tests('python2')
+ }
+ }
+}
diff --git a/ci/README b/ci/README
new file mode 100644
index 0000000..38a7213
--- /dev/null
+++ b/ci/README
@@ -0,0 +1,23 @@
+This directory contains the necessary files for running tests inside a docker container.
+
+The Dockerfile defines two images:
+- base
+ -> this is the image used for testing
+- docs
+ -> Include a latex install for sphinx pdf builds
+
+(The following assumes you have a docker daemon running on your working computer)
+
+To create the images:
+
+ docker build --target --tag secop_:latest .
+
+To test images interactivly:
+ docker run -u jenkins -i -t secop /bin/bash
+
+The Jenkinsfile uses this Dockerfile (only approved checked-in versions from master)
+to build the images (a rebuild will only happen if the Dockerfile is changed as docker
+ caches the images and build information) and run the test suite inside the container.
+
+(Note: The initial version still has some bootstrapping glue, that will get
+changed in a followup).