From 142442edaad3ba4c76645f3806519039cb6b7007 Mon Sep 17 00:00:00 2001
From: Chris Evich <cevich@redhat.com>
Date: Mon, 4 Mar 2019 16:57:20 -0500
Subject: Cirrus: Add dedicated rootless mode testing

Certain integration tests require execution as a regular user.
This is acomplished by `PodmanTest.PodmanAsUserBase()` wrapping a
specialized execution environment, in `test/utils/utils.go`.  However,
doing this requires passing through python, which vastly increases the
complexity of debugging low-level problems.

This commit introduces a new parallel task, run as a regular user on the
VM as set by three environment variables.  All commands executed in the
``rootless_test.sh`` script, will occur as a real user with a name and
home directory, just as `$DIETY` intended.  All env. vars established
during `environment_setup.sh` (for root) are available.  The PR source
in `$GOSRC` and `$GOPATH` are owned by this user, and ready for use.

Signed-off-by: Chris Evich <cevich@redhat.com>
---
 .cirrus.yml                         | 39 ++++++++++++++++++++++++++-
 contrib/cirrus/README.md            | 20 ++++++++++++++
 contrib/cirrus/lib.sh               | 53 ++++++++++++++++++++++++++++++++-----
 contrib/cirrus/rootless_test.sh     | 36 +++++++++++++++++++++++++
 contrib/cirrus/setup_environment.sh | 20 +++++++++-----
 5 files changed, 155 insertions(+), 13 deletions(-)
 create mode 100755 contrib/cirrus/rootless_test.sh

diff --git a/.cirrus.yml b/.cirrus.yml
index b473980ea..80486395f 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -60,6 +60,13 @@ env:
     # RHEL image must be imported, google bills extra for their native image.
     RHEL_BASE_IMAGE: "rhel-guest-image-7-6-210-x86-64-qcow2-1548099756"
 
+    ####
+    #### Default to NOT running in rootless-testing mode
+    ####
+    ROOTLESS_USER:
+    ROOTLESS_UID:
+    ROOTLESS_GID:
+
     ####
     #### Credentials and other secret-sauces, decrypted at runtime when authorized.
     ####
@@ -88,7 +95,7 @@ env:
         CIRRUS_TASK_ID CIRRUS_REPO_NAME CIRRUS_REPO_OWNER CIRRUS_REPO_FULL_NAME
         CIRRUS_REPO_CLONE_URL CIRRUS_SHELL CIRRUS_USER_COLLABORATOR CIRRUS_USER_PERMISSION
         CIRRUS_WORKING_DIR CIRRUS_HTTP_CACHE_HOST PACKER_BUILDS BUILT_IMAGE_SUFFIX
-        XDG_DATA_DIRS XDG_RUNTIME_DIR XDG_SESSION_ID
+        XDG_DATA_DIRS XDG_RUNTIME_DIR XDG_SESSION_ID ROOTLESS_USER ROOTLESS_UID ROOTLESS_GID
 
 
 # Every *_task runs in parallel in separate VMsd. The name prefix only for reference
@@ -189,6 +196,36 @@ testing_task:
     integration_test_script: $SCRIPT_BASE/integration_test.sh
 
 
+# This task executes tests as a regular user on a system
+rootless_testing_task:
+
+    depends_on:
+        - "gating"
+        - "build_each_commit"
+
+    gce_instance:
+        image_project: "libpod-218412"
+        zone: "us-central1-a"  # Required by Cirrus for the time being
+        cpu: 2
+        memory: "4Gb"
+        disk: 200
+        # A matrix could be used here, for now just one VM
+        image_name: "${FEDORA_CACHE_IMAGE_NAME}"
+
+    env:
+        ROOTLESS_USER: "olympiclongjumpingwithjesus"
+        ROOTLESS_UID: 123456
+        ROOTLESS_GID: 123456
+
+    timeout_in: 120m
+
+    setup_environment_script: $SCRIPT_BASE/setup_environment.sh
+    rootless_test_script: >-
+        ssh $ROOTLESS_USER@localhost
+        -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o CheckHostIP=no
+        $CIRRUS_WORKING_DIR/$SCRIPT_BASE/rootless_test.sh
+
+
 # Because system tests are stored within the repository, it is sometimes
 # necessary to execute them within a PR to validate changes.
 optional_testing_task:
diff --git a/contrib/cirrus/README.md b/contrib/cirrus/README.md
index 0d91301c6..da87fd2e4 100644
--- a/contrib/cirrus/README.md
+++ b/contrib/cirrus/README.md
@@ -52,6 +52,26 @@ task (pass or fail) is set based on the exit status of the last script to execut
    Total execution time is capped at 2-hours (includes all the above)
    but this script normally completes in less than an hour.
 
+### ``rootless_testing`` Task
+
+***N/B: Steps below are performed by automation***
+
+1. After `gating` passes, spin up one VM per
+   `matrix: image_name` item. Once accessible, ``ssh``
+   into each VM as the `root` user.
+
+2. ``setup_environment.sh``: Configure root's `.bash_profile`
+   the same as for other tasks.  However, also add a regular
+   user account, chown all the source code to them.  Set up
+   fresh ssh pub/priv. keys for the root user, adding the
+   public part to the user's `authorized_keys` file.
+
+3. As root, call ssh to connect to localhost as the user,
+   and run the ``rootless_test.sh`` script from the source
+   tree.  This is needed so the user has a clean process tree
+   and environment - i.e. without `sudo`, `su`, `runuser`,
+   etc. in the mix.  From here, all testing as the user may
+   be performed.
 
 ### ``optional_testing`` Task
 
diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh
index acd2447c0..9419dad05 100644
--- a/contrib/cirrus/lib.sh
+++ b/contrib/cirrus/lib.sh
@@ -53,6 +53,9 @@ show_env_vars() {
     echo "
 BUILDTAGS $BUILDTAGS
 BUILT_IMAGE_SUFFIX $BUILT_IMAGE_SUFFIX
+ROOTLESS_USER $ROOTLESS_USER
+ROOTLESS_UID $ROOTLESS_UID
+ROOTLESS_GID $ROOTLESS_GID
 CI $CI
 CIRRUS_CI $CIRRUS_CI
 CI_NODE_INDEX $CI_NODE_INDEX
@@ -117,6 +120,15 @@ bad_os_id_ver() {
     exit 42
 }
 
+run_rootless() {
+    if [[ -z "$ROOTLESS_USER" ]] && [[ -z "$ROOTLESS_UID" ]] && [[ -z "$ROOTLESS_GID" ]]
+    then
+        return 1
+    else
+        return 0
+    fi
+}
+
 stub() {
     echo "STUB: Pretending to do $1"
 }
@@ -146,12 +158,41 @@ record_timestamp() {
     echo -e "BLEEEEEEEEEEP!\n."
 }
 
-# Run sudo in directory with GOPATH set
-cdsudo() {
-    DIR="$1"
-    shift
-    CMD="cd $DIR && $@"
-    sudo --preserve-env=GOPATH --non-interactive bash -c "$CMD"
+setup_rootless() {
+    req_env_var "
+        ROOTLESS_USER $ROOTLESS_USER
+        ROOTLESS_UID $ROOTLESS_UID
+        ROOTLESS_GID $ROOTLESS_GID
+        GOSRC $GOSRC
+        ENVLIB $ENVLIB
+    "
+    echo "creating $ROOTLESS_UID:$ROOTLESS_GID $ROOTLESS_USER user"
+    groupadd -g $ROOTLESS_GID $ROOTLESS_USER
+    useradd -g $ROOTLESS_GID -u $ROOTLESS_UID --no-user-group --create-home $ROOTLESS_USER
+    chown -R $ROOTLESS_UID:$ROOTLESS_GID "$GOSRC"
+
+    echo "creating ssh keypair for $USER"
+    ssh-keygen -P "" -f $HOME/.ssh/id_rsa
+
+    echo "Allowing ssh key for $ROOTLESS_USER"
+    (umask 077 && mkdir "/home/$ROOTLESS_USER/.ssh")
+    chown -R $ROOTLESS_UID:$ROOTLESS_GID "/home/$ROOTLESS_USER/.ssh"
+    install -o $ROOTLESS_UID -g $ROOTLESS_GID -m 0600 \
+        "$HOME/.ssh/id_rsa.pub" "/home/$ROOTLESS_USER/.ssh/authorized_keys"
+
+    echo "Setting permissions on automation files"
+    chmod 666 "$TIMESTAMPS_FILEPATH"
+
+    echo "Copying $HOME/$ENVLIB"
+    install -o $ROOTLESS_UID -g $ROOTLESS_GID -m 0700 \
+        "$HOME/$ENVLIB" "/home/$ROOTLESS_USER/$ENVLIB"
+
+    echo "Configuring user's go environment variables"
+    su --login --command 'go env' $ROOTLESS_USER | \
+        while read envline
+        do
+            X=$(echo "export $envline" | tee -a "/home/$ROOTLESS_USER/$ENVLIB") && echo "$X"
+        done
 }
 
 # Helper/wrapper script to only show stderr/stdout on non-zero exit
diff --git a/contrib/cirrus/rootless_test.sh b/contrib/cirrus/rootless_test.sh
new file mode 100755
index 000000000..811b7cf2e
--- /dev/null
+++ b/contrib/cirrus/rootless_test.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+set -e
+source $HOME/.bash_profile
+
+cd $GOSRC
+source $(dirname $0)/lib.sh
+
+req_env_var "
+GOSRC $GOSRC
+OS_RELEASE_ID $OS_RELEASE_ID
+OS_RELEASE_VER $OS_RELEASE_VER
+"
+
+if ! run_rootless
+then
+    echo "Error: Expected rootless env. vars not set or empty"
+    exit 1
+fi
+
+echo "."
+echo "Hello, my name is $USER and I live in $PWD can I be your friend?"
+
+record_timestamp "rootless test start"
+
+cd "$GOSRC"
+case "${OS_RELEASE_ID}-${OS_RELEASE_VER}" in
+    ubuntu-18) ;&  # Continue to the next item
+    fedora-29) ;&
+    fedora-28)
+        make
+        ;;
+    *) bad_os_id_ver ;;
+esac
+
+record_timestamp "rootless test end"
diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh
index c3276bb6f..d8d97904b 100755
--- a/contrib/cirrus/setup_environment.sh
+++ b/contrib/cirrus/setup_environment.sh
@@ -43,6 +43,9 @@ then
         "export OS_RELEASE_ID=\"$(os_release_id)\"" \
         "export OS_RELEASE_VER=\"$(os_release_ver)\"" \
         "export OS_REL_VER=\"$(os_release_id)-$(os_release_ver)\"" \
+        "export ROOTLESS_USER=$ROOTLESS_USER" \
+        "export ROOTLESS_UID=$ROOTLESS_UID" \
+        "export ROOTLESS_GID=$ROOTLESS_GID" \
         "export BUILT_IMAGE_SUFFIX=\"-$CIRRUS_REPO_NAME-${CIRRUS_CHANGE_IN_REPO:0:8}\"" \
         "export GOPATH=\"/var/tmp/go\"" \
         'export PATH="$HOME/bin:$GOPATH/bin:/usr/local/bin:$PATH"' \
@@ -70,14 +73,19 @@ then
         *) bad_os_id_ver ;;
     esac
 
-    # Do the same for golang env. vars
-    go env | while read envline
-    do
-        X=$(echo "export $envline" | tee -a "$HOME/$ENVLIB") && eval "$X" && echo "$X"
-    done
-
     cd "${GOSRC}/"
     source "$SCRIPT_BASE/lib.sh"
+
+    if run_rootless
+    then
+        setup_rootless
+    else
+        # Includes some $HOME relative details
+        go env | while read envline
+        do
+            X=$(echo "export $envline" | tee -a "$HOME/$ENVLIB") && eval "$X" && echo "$X"
+        done
+    fi
 fi
 
 record_timestamp "env. setup end"
-- 
cgit v1.2.3-54-g00ecf