From 8f91e4aedc5f693017283f564c5799e1e386bb5e Mon Sep 17 00:00:00 2001 From: Evilham Date: Thu, 18 Jun 2020 00:22:54 +0200 Subject: [PATCH] [__git] Keep repository up to date in subsequent runs. This also ensure that tags and branch changes are supported. Closes #819. --- cdist/conf/type/__git/explorer/branch | 22 +++++++++++++++ cdist/conf/type/__git/explorer/needs-update | 27 ++++++++++++++++++ cdist/conf/type/__git/gencode-remote | 31 +++++++++++++++++++-- 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100755 cdist/conf/type/__git/explorer/branch create mode 100755 cdist/conf/type/__git/explorer/needs-update diff --git a/cdist/conf/type/__git/explorer/branch b/cdist/conf/type/__git/explorer/branch new file mode 100755 index 00000000..483edb2a --- /dev/null +++ b/cdist/conf/type/__git/explorer/branch @@ -0,0 +1,22 @@ +#!/bin/sh -e + +destination="/$__object_id" + +os="$(cat "$__global/explorer/os")" +state_should="$(cat "$__object/parameter/state")" +owner="$(cat "$__object/parameter/owner")" + +# If the user did not provide an owner, cdist defaults to root. +git_user="${owner:-root}" + +# Only do something if we are not removing the repo and it is not the first run +if [ "$state_should" = "present" ] && [ -d "$destination/.git" ]; then + # Whenever possible run git as non-root, see history of CVEs. + branch="$(su -m "$git_user" -c "git -C '$destination' rev-parse --abbrev-ref HEAD")" + if [ "$branch" != "HEAD" ]; then + echo $branch + else + # We are using tags + su -m "$git_user" -c "git -C '$destination' describe --always --tags --abbrev=0" + fi +fi diff --git a/cdist/conf/type/__git/explorer/needs-update b/cdist/conf/type/__git/explorer/needs-update new file mode 100755 index 00000000..d055b794 --- /dev/null +++ b/cdist/conf/type/__git/explorer/needs-update @@ -0,0 +1,27 @@ +#!/bin/sh -e + +destination="/$__object_id" + +os="$(cat "$__global/explorer/os")" +state_should="$(cat "$__object/parameter/state")" +branch_should="$(cat "$__object/parameter/branch")" +owner="$(cat "$__object/parameter/owner")" + +# If the user did not provide an owner, cdist defaults to root. +git_user="${owner:-root}" + +# Only do something if we are not removing the repo and it is not the first run +if [ "$state_should" = "present" ] && [ -d "$destination/.git" ]; then + # First fetch the remote + # Whenever possible run git as non-root, see history of CVEs. + su -m "$git_user" -c "git -C '$destination' fetch -q" + head="$(su -m "$git_user" -c "git -C '$destination' rev-parse HEAD")" + # Try first to get the latest commit in the remote current branch, + # if it fails try to get the commit for the expected tag name + upstream="$(su -m "$git_user" -c "git -C '$destination' rev-parse @{u}" 2>/dev/null || + su -m "$git_user" -c "git -C '$destination' rev-parse '${branch_should}^{}'")" + if [ "${head}" != "$upstream" ]; then + echo "YES" + exit + fi +fi diff --git a/cdist/conf/type/__git/gencode-remote b/cdist/conf/type/__git/gencode-remote index edc25aae..d52d44e1 100755 --- a/cdist/conf/type/__git/gencode-remote +++ b/cdist/conf/type/__git/gencode-remote @@ -19,13 +19,15 @@ # # +branch_is=$(cat "$__object/explorer/branch") state_is=$(cat "$__object/explorer/state") owner_is=$(cat "$__object/explorer/owner") group_is=$(cat "$__object/explorer/group") +needs_update=$(cat "$__object/explorer/needs-update") state_should=$(cat "$__object/parameter/state") -branch=$(cat "$__object/parameter/branch") +branch_should=$(cat "$__object/parameter/branch") source=$(cat "$__object/parameter/source") @@ -47,10 +49,35 @@ fi && [ -z "$needs_chown" ] \ && [ -n "$mode" ] && exit 0 +# Whenever possible run git as non-root, see history of CVEs. +if [ -n "$owner" ]; then + git_user="$owner" +else + git_user="root" +fi + case $state_should in present) if [ "$state_should" != "$state_is" ]; then - echo git clone --quiet "$recursive" "$shallow" --branch "$branch" "$source" "$destination" + if [ "$git_user" != "root" ]; then + # If we execute git as non-root, it is not obvious that we'll be able + # to create the output directory, so we have to ensure that. + cat << EOF +if [ ! -d '$destination' ]; then + mkdir '$destination' +fi +chown '${owner}:${group}' '$destination' +EOF + fi + # Actually clone the repository + su -m "$git_user" -c "git clone --quiet '$recursive' '$shallow' --branch '$branch' '$source' '$destination'" + elif [ "$branch_should" != "$branch_is" ]; then + # User has changed tag / branch, let's update that + echo su -m "$git_user" -c "git checkout '$branch_should'" + elif [ "$needs_update" = "YES" ]; then + # The remote has newer information than our repository. + # Fetch was done in the explorer, here we can just pull + echo su -m "$git_user" -c "git -C '$destination' pull" fi if [ -n "$needs_chown" ]; then echo chown -R "${owner}:${group}" "$destination"