Skip to content

Commit 515d0df

Browse files
JDeBojdebo-slalomryapric
authored
Feature/add git scoring step (#10)
Co-authored-by: Justin DeBo <justin.debo@slalom.com> Co-authored-by: Ryan J. Price <ryapric@gmail.com>
1 parent 0ab363f commit 515d0df

9 files changed

Lines changed: 397 additions & 29 deletions

File tree

linux/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ yeet-aws:
1515
@printf 'Waiting 30s for EC2 instances to hopefully process userdata...\n' && sleep 30
1616
@make -s provision-aws
1717

18+
connect-aws:
19+
ssh -p 2332 admin@$(shell terraform -chdir=./terraform output -json | jq -r '.instance_ips.value[]')
20+
1821
provision-local:
1922
# Don't re-provision DB at the same time, since it throws off team server tests
2023
@vagrant provision db

linux/instructions/challenge_6.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Challenge 6: Git SSH Setup
2+
==========================
3+
4+
We just got hired by a very famous movie star (who's name may not be disclosed)
5+
to create a new version of our app for their specific use case. Our lead
6+
engineers were working on putting together the new app, but they mysteriously
7+
dissappeared while on a golfing trip a few weeks past. We were told that the
8+
code was about ready to deploy, just hadn't gotten the chance to merge it into
9+
the main branch. See if you can figure out how to get it up and running.
10+
11+
The name of the app is 'carrot-cruncher'. The last dev got the repo set up
12+
somewhere on disk, but they never said where... hopefully you'll able to find
13+
it. When you do, supposedly there was a new working branch pushed to the remote
14+
repo, so you'll need to figure out how to authenticate to that repo.
15+
16+
There was a note in your team's documentation about a process that picks up keys
17+
in the local git server. Supposedly all you had to do was copy some file to the
18+
'ssh-keys/' directory near all the repos and git takes it from there? So I guess
19+
try that? Then clone the remote branches down, then you'll be off to the
20+
races... Good luck!

linux/instructions/challenge_7.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Challenge 7: Git branch management
2+
==================================
3+
4+
Great, now that you've got your SSH keys set up, you'll need to figure out which
5+
of those remote branches have the correct changes it get it merged in ASAP. Once
6+
you clone the repo, the working branch should be obvious... or so we were
7+
told... So we recommend you just try looking at/running the code the the
8+
different branches and see which one fits.

linux/scripts/init-db.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ set -euo pipefail
33

44
# Install ezlog
55
command -v git > /dev/null || { apt-get update && apt-get install -y git ;}
6+
git config --global http.sslVerify false # Workaround for corporate proxy installs
67
[[ -d /usr/local/share/ezlog ]] || git clone 'https://github.com/opensourcecorp/ezlog.git' /usr/local/share/ezlog
78
# shellcheck disable=SC1091
89
source /usr/local/share/ezlog/src/main.sh

linux/scripts/init.sh

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ set -euo pipefail
33

44
# Install ezlog
55
command -v git > /dev/null || { apt-get update && apt-get install -y git ;}
6+
git config --global http.sslVerify false # Workaround for corporate proxy installs
67
[[ -d /usr/local/share/ezlog ]] || git clone 'https://github.com/opensourcecorp/ezlog.git' /usr/local/share/ezlog
78
# shellcheck disable=SC1091
89
source /usr/local/share/ezlog/src/main.sh
@@ -58,7 +59,6 @@ cp -r /tmp/{scripts,services,instructions} "${wsroot}"/
5859
mkdir -p /opt/app
5960
cp -r /tmp/dummy-app-src/* /opt/app
6061
chown -R appuser:appuser /opt/app
61-
rm -rf /tmp/{scripts,services,instructions,dummy-app-src}
6262

6363
###
6464
log-info 'Installing any needed system packages'
@@ -126,17 +126,16 @@ timeout 180s bash -c _db_init
126126
log-info 'Dumping the first instruction(s) to the appuser homedir'
127127
cp "${wsroot}"/instructions/challenge_{0,1}.md /home/appuser/
128128

129-
## TODO: ideas for other scorable challenges for teams:
130-
131-
# Simulate a git repo's history a la:
132-
# (at time of writing, this was on the branch 'feature/add-git-scoring-step')
133-
134-
# ...
135129

136-
# mess up the current branch (maybe it was a feature branch that got yeeted)?
137-
# Have a different branch be the "good" one (`release`, `main` etc)
138-
139-
# BUT ALSO, somehow the good branch is still failing lints (maybe)
140-
# note to self: need to put anything for a linter on the .bashrc-defined PATH for appuser during init
130+
### Setup a local git server and clone to repo
131+
if ! (cd /srv/git/repositories/carrot-cruncher.git && git show-ref --verify --quiet "refs/heads/release/bunnies_v1" && [[ -f /home/git/git-shell-commands/no-interactive-login ]]) ; then
132+
sudo chmod +x /tmp/scripts/setup-git.sh
133+
if /tmp/scripts/setup-git.sh; then
134+
log-info "Git server setup completed successfully."
135+
else
136+
log-fatal "Git server setup failed."
137+
fi
138+
fi
141139

140+
rm -rf /tmp/{scripts,services,instructions,dummy-app-src}
142141
log-info 'All done!'

linux/scripts/linux-workshop-admin.sh

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,17 +138,98 @@ _check-webapp-reachable() {
138138
fi
139139
}
140140

141+
# Flag for checking if ssh is set
142+
ssh_setup=1
143+
_check-ssh-setup() {
144+
local test_dir=${wsroot}/git-checks/ssh
145+
local git_remote="/srv/git"
146+
local repo_dir="${git_remote}/repositories/carrot-cruncher.git"
147+
su - appuser -c "git config --global --add safe.directory ${test_dir}"
148+
if [[ -f ${git_remote}/ssh-keys/id_rsa.pub ]]; then
149+
log-info "Copying SSH Keys..."
150+
cat ${git_remote}/ssh-keys/id_rsa.pub >> /home/git/.ssh/authorized_keys && rm -f ${git_remote}/ssh-keys/id_rsa.pub
151+
fi
152+
su - appuser -c "ssh git@localhost" || exit_status=$?
153+
if [ "$exit_status" == 128 ]; then
154+
_score-for-challenge 6
155+
log-info "SSH successfully setup"
156+
ssh_setup=0
157+
else
158+
log-error "SSH Keys not setup successfully"
159+
fi
160+
}
161+
162+
_check-git-branch-merged-correct() {
163+
local test_dir=${wsroot}/git-checks/merged
164+
local repo_dir="/srv/git/repositories/carrot-cruncher.git"
165+
if [ $ssh_setup -eq 1 ]; then
166+
log-warn "ssh keys aren't set"
167+
return 0
168+
fi
169+
[[ -d ${test_dir} ]] || mkdir -p ${test_dir} && chmod -R 777 ${test_dir}/..
170+
su - appuser -c "git config --global --add safe.directory ${test_dir}"
171+
[[ ! -d ${test_dir}/carrot-cruncher ]] || rm -rf ${test_dir:?}/carrot-cruncher
172+
su - appuser -c "git clone 'git@localhost:${repo_dir}' ${test_dir}/carrot-cruncher"
173+
if [ "$(su - appuser -c "cd ${test_dir}/carrot-cruncher; git fetch")" ]; then
174+
su - appuser -c "cd ${test_dir}/carrot-cruncher && git checkout main && git pull origin main"
175+
fi
176+
pushd "${test_dir}/carrot-cruncher" > /dev/null
177+
if grep -q carrot main.go; then
178+
popd > /dev/null
179+
rm -rf /${test_dir:?}/carrot-cruncher
180+
_score-for-challenge 7
181+
log-info "Feature branch merged correctly"
182+
else
183+
popd > /dev/null
184+
rm -rf /${test_dir:?}/carrot-cruncher
185+
log-error "Feature branch not merged correctly into main.\n"
186+
fi
187+
### Secondary check for exact commit matches. Haven't gotten working yet, but enforces
188+
### actually merging vs. copy/pasting code from branches
189+
# pushd "${repo_dir}" > /dev/null
190+
# git config --global --add safe.directory ${repo_dir}
191+
# if [ "$(git rev-parse main)" = "$(git rev-parse release/bunnies_v1)" ]; then
192+
# log-info "commits match"
193+
# else
194+
# log-error "commits don't match"
195+
# fi
196+
}
197+
198+
### Challenge 8 Check. WIP
199+
# _check-secret-removed() {
200+
# local secret_pattern="SSN: 1234-BUNNY"
201+
# if ! ${ssh_setup}; then
202+
# log-warn "ssh keys aren't set"
203+
# return 0
204+
# fi
205+
# pushd /srv/git/repositories/carrot-cruncher.git > /dev/null
206+
# git config --global --add safe.directory /srv/git/repositories/carrot-cruncher.git;
207+
# # Check each commit for the secret pattern
208+
# for commit in $(git rev-list --all); do
209+
# if git show "$commit":banking.txt | grep -q "$secret_pattern"; then
210+
# log-error "Secret found in commit $commit"
211+
# popd > /dev/null
212+
# return 0
213+
# fi
214+
# done
215+
# # _score-for-challenge 8
216+
# log-info "Secrets removed"
217+
# popd > /dev/null
218+
# }
219+
141220
###
142221
# Main wrapper def & callable for scorables
143222
###
144-
145223
main() {
146224
log-info 'Starting score check...'
147225
_check-binary-built
148226
_check-symlink
149227
_check-systemd-service-running
150228
_check-debfile-service-running
151229
_check-webapp-reachable
230+
_check-ssh-setup
231+
_check-git-branch-merged-correct
232+
# _check-secret-removed
152233
}
153234

154235
main

linux/scripts/setup-git.sh

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#!/usr/bin/env bash
2+
GIT_USER=${GIT_USER:-git}
3+
APP_USER=${APP_USER:-appuser}
4+
GIT_HOME=${GIT_HOME:-/srv/git}
5+
REPO_NAME=${REPO_NAME:-carrot-cruncher}
6+
REPO_DIR="${GIT_HOME}/repositories/${REPO_NAME}.git"
7+
WORK_DIR="/opt/git"
8+
APP_DIR=${APP_DIR:-/opt/app}
9+
DEFAULT_BRANCH=${DEFAULT_BRANCH:-main}
10+
SSH_PORT=${SSH_PORT:-2332}
11+
BRANCH_NAME=${BRANCH_NAME:-release/bunnies_v1}
12+
13+
# Install ezlog
14+
command -v git >/dev/null || { apt-get update && apt-get install -y git; }
15+
[[ -d /usr/local/share/ezlog ]] || git clone 'https://github.com/opensourcecorp/ezlog.git' /usr/local/share/ezlog
16+
# shellcheck disable=SC1091
17+
source /usr/local/share/ezlog/src/main.sh
18+
19+
function _setup_ssh_keys_for_git_user() {
20+
local ssh_dir="/home/${GIT_USER}/.ssh"
21+
local public_key_file="${ssh_dir}/id_rsa.pub"
22+
local private_key_file="${ssh_dir}/id_rsa"
23+
local authorized_keys_file="${ssh_dir}/authorized_keys"
24+
25+
# Create .ssh directory if it doesn't exist
26+
mkdir -p "${ssh_dir}"
27+
chown "${GIT_USER}:${GIT_USER}" "${ssh_dir}"
28+
chmod 700 "${ssh_dir}"
29+
30+
# Generate the SSH key pair if it doesn't exist
31+
if [[ ! -f "${public_key_file}" ]]; then
32+
su - "${GIT_USER}" -c "ssh-keygen -t rsa -f ${private_key_file} -q -N ''"
33+
fi
34+
35+
# Add the public key to authorized_keys if it's not already there
36+
if ! grep -q "$(cat "${public_key_file}")" "${authorized_keys_file}" 2>/dev/null; then
37+
cat "${public_key_file}" >>"${authorized_keys_file}"
38+
fi
39+
chmod 600 "${authorized_keys_file}"
40+
chown "${GIT_USER}:${GIT_USER}" "${authorized_keys_file}"
41+
[[ -d /home/${APP_USER}/.ssh ]] || mkdir /home/"${APP_USER}"/.ssh
42+
cat <<EOF >/home/"${APP_USER}"/.ssh/config
43+
HOST localhost
44+
USER ${GIT_USER}
45+
PORT ${SSH_PORT}
46+
EOF
47+
}
48+
49+
function _add_to_known_hosts() {
50+
local ssh_dir="/home/${GIT_USER}/.ssh"
51+
local known_hosts_file="${ssh_dir}/known_hosts"
52+
su - "${GIT_USER}" -c "ssh-keyscan -p ${SSH_PORT} -H localhost >> ${known_hosts_file}"
53+
chmod 644 "${known_hosts_file}"
54+
}
55+
56+
function _setup_git_user() {
57+
if id "${GIT_USER}" &>/dev/null; then
58+
log-info "User ${GIT_USER} already exists."
59+
else
60+
log-info "setting up git user"
61+
useradd -m "${GIT_USER}" || return 1
62+
echo "${GIT_USER}:${GIT_USER}" | chpasswd
63+
fi
64+
_setup_ssh_keys_for_git_user
65+
# _add_to_known_hosts
66+
which git-shell >>/etc/shells
67+
chsh --shell "$(command -v /bin/bash)" "${GIT_USER}"
68+
}
69+
70+
function _init_git_repo() {
71+
log-info "Initializing remote carrot cruncher"
72+
rm -rf "${REPO_DIR}"
73+
mkdir -p "${REPO_DIR}"
74+
[[ -d "${GIT_HOME}/ssh-keys" ]] || mkdir "${GIT_HOME}/ssh-keys"
75+
chown -R "${GIT_USER}:${GIT_USER}" "${GIT_HOME}"
76+
pushd "${REPO_DIR}" >/dev/null || exit
77+
su - "${GIT_USER}" -c "git config --global init.defaultBranch ${DEFAULT_BRANCH}"
78+
su - "${GIT_USER}" -c "git config --global user.email 'bugs@bigbadbunnies.com'"
79+
su - "${GIT_USER}" -c "git config --global user.name 'Bugs Bunny'"
80+
su - "${GIT_USER}" -c "pushd ""${REPO_DIR}"" >/dev/null; git init --bare"
81+
popd >/dev/null || exit
82+
}
83+
84+
function _setup_local_clone() {
85+
local clone_dir="${WORK_DIR}/${REPO_NAME}"
86+
log-info "cloning carrot cruncher"
87+
if [ -d "${WORK_DIR}" ]; then
88+
rm -rf "${WORK_DIR}"
89+
fi
90+
mkdir "${WORK_DIR}"
91+
chmod 777 "${WORK_DIR}"
92+
pushd "${WORK_DIR}" >/dev/null || exit
93+
su - "${GIT_USER}" -c "GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=accept-new' git clone '${GIT_USER}@localhost:${REPO_DIR}' ${clone_dir}"
94+
git config --global --add safe.directory /opt/git/carrot-cruncher
95+
pushd "${clone_dir}" >/dev/null || exit
96+
cp -r "${APP_DIR}"/* .
97+
sed -i 's/PrintLine/Println/g' main.go
98+
su - "${GIT_USER}" -c "pushd ${clone_dir}; git add .; git commit -m 'Initial commit'; git push origin"
99+
popd >/dev/null || exit
100+
}
101+
102+
function _create_release_branch() {
103+
local clone_dir="${WORK_DIR}/${REPO_NAME}"
104+
local branch_2="v1.0.2-rc-tmp-bugfix-2.0.1"
105+
pushd "${clone_dir}" >/dev/null || exit
106+
log-info "setting up release branch"
107+
su - "${GIT_USER}" -c "pushd ${clone_dir}; git checkout -b '${BRANCH_NAME}'"
108+
sed -i -e 's/printing/picking/g' -e 's/money/carrots/g' -e 's/CHA-CHING/CRUNCH/g' main.go
109+
echo -e "Name: Bugs Bunny\nSecurity Question Answer: 'Crunchy King'\nSSN: 1234-BUNNY" >banking.txt
110+
su - "${GIT_USER}" -c "pushd ${clone_dir}; git add .; git commit -m 'Prepare release branch'"
111+
rm banking.txt
112+
su - "${GIT_USER}" -c "pushd ${clone_dir}; git add .; git commit -m 'oops did not mean to add that...'"
113+
su - "${GIT_USER}" -c "pushd ${clone_dir}; git push --set-upstream origin '${BRANCH_NAME}'"
114+
su - "${GIT_USER}" -c "pushd ${clone_dir}; git checkout '${DEFAULT_BRANCH}'"
115+
su - "${GIT_USER}" -c "pushd ${clone_dir}; git checkout -b '${branch_2}'"
116+
sed -i -e 's/printing/uh/g' -e 's/money/oh/g' -e 's/CHA-CHING/NO-NO-NOOOOO/g' main.go
117+
su - "${GIT_USER}" -c "pushd ${clone_dir}; git add .; git commit -m 'I think we might be on to something...'"
118+
su - "${GIT_USER}" -c "pushd ${clone_dir}; git push --set-upstream origin '${branch_2}'"
119+
su - "${GIT_USER}" -c "pushd ${clone_dir}; git checkout '${DEFAULT_BRANCH}'"
120+
su - "${GIT_USER}" -c "pushd ${clone_dir}; git branch -D ${BRANCH_NAME} ${branch_2}"
121+
popd >/dev/null || exit
122+
}
123+
124+
function _polish_off() {
125+
chsh --shell "$(command -v git-shell)" "${GIT_USER}" # switch Git User to git-shell
126+
[[ -d /home/git/git-shell-commands ]] || mkdir -m 777 /home/git/git-shell-commands
127+
cat >/home/git/git-shell-commands/no-interactive-login <<\EOF
128+
#!/bin/sh
129+
printf '%s\n' "Hi! You've successfully authenticated, but we do not"
130+
printf '%s\n' "provide interactive shell access."
131+
exit 128
132+
EOF
133+
chmod 777 /home/git/git-shell-commands/no-interactive-login
134+
chown -R "${APP_USER}":"${APP_USER}" /opt/git # git appuser ownership of git directory
135+
}
136+
137+
function main() {
138+
_setup_git_user
139+
_init_git_repo
140+
_setup_local_clone
141+
_create_release_branch
142+
_polish_off
143+
log-info "Git server setup is complete."
144+
}
145+
146+
main "$@"

0 commit comments

Comments
 (0)