-
-
Save tionis/a0f23a7a33b0e289f1b03cc6ff503f86 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env bash | |
#{"deps": ["jq", "openssh", "bash", "gpg", "git", "tree"]} | |
#-------------------------------------------- | |
set -Eeuo pipefail | |
if [[ -n "${DEBUG:-}" ]]; then | |
set -x | |
fi | |
trap stack_trace ERR | |
function stack_trace() { | |
echo -e "\nThe command '$BASH_COMMAND' triggered a stacktrace:\nStack Trace:" | |
for (( i = 1; i < ${#FUNCNAME[@]}; i++ )); do | |
echo " ($i) ${FUNCNAME[$i]:-(top level)} ${BASH_SOURCE[$i]:-(no file)}:${BASH_LINENO[$(( i - 1 ))]}" | |
done | |
} | |
error(){ printf "\e[1;31m[ERROR]\e[0m %s\n" "${1:-error message missing}" && trap true ERR && exit 1; } | |
warning(){ printf "\e[1;33m[WARNING]\e[0m %s\n" "$1" >&2; } | |
success(){ printf "\e[1;32m[SUCCESS]\e[0m %s\n" "$1" >&2; } | |
info(){ printf "\e[1;34m[INFO]\e[0m %s\n" "$1" >&2; } | |
log(){ if [[ -n "${VERBOSE:-}" ]]; then printf "\e[1;34m[INFO]\e[0m %s\n" "$1" >&2; fi } | |
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" | |
export SCRIPT_DIR | |
#-------------------------------------------- | |
# deps: | |
##################### General Helper Funcs ############################ | |
join_elements() { | |
local index="$1" | |
shift | |
local array=("$@") | |
# Check if index is within array bounds | |
if (( index < 0 || index >= ${#array[@]} )); then | |
echo "Index out of bounds" | |
return 1 | |
fi | |
local result="" | |
for ((i = 0; i <= index; i++)); do | |
if [ -n "$result" ]; then | |
result="${result}.${array[$i]}" | |
else | |
result="${array[$i]}" | |
fi | |
done | |
echo "$result" | |
} | |
git_cfg(){ | |
git "--git-dir=$HOME/.cfg" "--work-tree=$HOME" "$@" | |
} | |
get_worktree_dir(){ # gets worktree of branch, creating it if needed | |
worktree_info="$(git_cfg worktree list | grep "\[$1\]\$")" 2>/dev/null || worktree_info="" | |
if [ -n "$worktree_info" ]; then | |
worktree_path=$(echo "$worktree_info" | awk '{print $1}') | |
echo "$worktree_path" | |
else | |
worktree_path="$HOME/.cfg/non-main-worktrees/$1" | |
cfg worktree add "$worktree_path" "$1" >&2 | |
echo "$worktree_path" | |
fi | |
} | |
sha256(){ | |
sha256sum <(printf "%s" "$1") | grep -o '^[a-z0-9]*' | |
} | |
sha256:file(){ | |
sha256sum "$1" | grep -o '^[a-z0-9]*' | |
} | |
tree(){ | |
if command -v tree >/dev/null; then | |
command tree "$@" | |
else | |
old_pwd="$PWD" | |
cd "$1" | |
find . -type f -printf "%P\n" | |
cd "$old_pwd" | |
fi | |
} | |
trim_prefix_from_list() { | |
local prefix=$1 | |
shift | |
local list=("$@") | |
for i in "${!list[@]}"; do | |
list[i]="${list[$i]#"$prefix"}" | |
done | |
if [[ "${#list[@]}" -gt 0 ]]; then | |
printf "%s\n" "${list[@]}" | |
fi | |
} | |
run(){ | |
executable="$1" | |
shift | |
if test -x "$executable"; then | |
"$executable" "$@" | |
else | |
IFS=' ' read -r -a interpreter <<< "$(head -n 1 "$executable" | sed -n 's|^#! *\(.*\)|\1|p')" | |
if [[ -z "${interpreter[*]}" ]]; then | |
interpreter=(bash) | |
fi | |
"${interpreter[@]}" "$executable" "$@" | |
fi | |
} | |
##################################### Constants ###################################### | |
CACHE_ROOT_DIR="$HOME/.cache/cfg/cache" | |
test -d "$CACHE_ROOT_DIR" || mkdir -p "$CACHE_ROOT_DIR" | |
STORE_ROOT_DIR="$HOME/.config/store" | |
MAIN_GPG_KEY=995DFE267EA741AD6429131E2A3880E05C5DC4B8 | |
##################################### Cache Management ################################ | |
cache_key_exists(){ # check ttl signature? | |
if test -f "$CACHE_ROOT_DIR/${1:?}"; then | |
if [[ -f "$CACHE_ROOT_DIR.ttl/${1:?}" ]] && [[ "$(date +%s)" -gt "$(cat "$CACHE_ROOT_DIR.ttl/${1:?}")" ]]; then | |
echo "Key expired, deleting it" | |
rm "$CACHE_ROOT_DIR/${1:?}" | |
log "Key expired: ${1:?}" | |
return 1 | |
else | |
log "Key exists: ${1:?}" | |
return 0 | |
fi | |
else | |
log "Key not found: ${1:?}" | |
return 1 | |
fi | |
} | |
cache_key_set(){ # TODO encrypt as needed | |
while [[ "$#" -gt 0 ]]; do | |
case "$1" in | |
--ttl) | |
ttl="$2" | |
shift 2;; | |
-h|--help) | |
echo "Usage: set [--ttl <seconds>] <path> <value>" | |
return 0;; | |
*) | |
key="$1" | |
value="$2" | |
shift 2;; | |
esac | |
done | |
if [[ -z "${key:-}" ]] || [[ -z "${value:-}" ]]; then | |
error "No key or value provided" | |
fi | |
mkdir -p "$CACHE_ROOT_DIR/$(dirname "$key")" | |
echo "$value" > "$CACHE_ROOT_DIR/$key" | |
if [[ -n "${ttl:-}" ]]; then | |
mkdir -p "$CACHE_ROOT_DIR.ttl/$(dirname "${1:?}")" | |
echo "$(($(date +%s) + "$ttl"))" > "$CACHE_ROOT_DIR.ttl/$key" | |
fi | |
} | |
cache_key_get(){ # TODO decrypt as needed | |
if cache_key_exists "${1:?}"; then | |
cat "$CACHE_ROOT_DIR/${1:?}" | |
else | |
error "Key not found or expired: '${1:?}'" | |
fi | |
} | |
cache_key_rm(){ | |
if [[ -e "$CACHE_ROOT_DIR.ttl/${1:?}" ]]; then | |
rm -r "$CACHE_ROOT_DIR.ttl/${1:?}" | |
fi | |
rm -r "$CACHE_ROOT_DIR/${1:?}" | |
} | |
cache_check_expiry(){ | |
prev_dir="$PWD" | |
cd "$CACHE_ROOT_DIR" | |
pattern="${1:-.*}" | |
while read -r file; do | |
if [[ -f "$CACHE_ROOT_DIR.ttl/$file" ]] && [[ "$(date +%s)" -gt "$(cat "$CACHE_ROOT_DIR.ttl/$file")" ]]; then | |
echo "Key expired, deleting it" | |
rm "$CACHE_ROOT_DIR/$file" | |
fi | |
done < <(find . -regextype posix-extended -regex "$pattern") | |
cd "$prev_dir" | |
} | |
cache_exec(){ # TODO use unified hash cache? | |
while [[ "$#" -gt 0 ]]; do | |
case "$1" in | |
--ttl) | |
ttl="$2" | |
shift 2;; | |
-h|--help) | |
echo "Usage: exec [--ttl <seconds>] <command>" | |
return 0;; | |
*) | |
command="$1" | |
shift;; | |
esac | |
done | |
if [[ -z "${command:-}" ]]; then | |
error "No command provided" | |
fi | |
hash="$(sha256 "$command")" | |
log "Hash: $hash" | |
result_file="$CACHE_ROOT_DIR/hash-cache/$hash" | |
if ! cache_key_exists "hash-cache/$hash"; then | |
mkdir -p "$CACHE_ROOT_DIR/hash-cache/" | |
bash -c "$command" > "$result_file" | |
if [[ -n "${ttl:-}" ]]; then | |
mkdir -p "$CACHE_ROOT_DIR.ttl/hash-cache/" | |
echo "$(($(date +%s) + "$ttl"))" > "$CACHE_ROOT_DIR.ttl/hash-cache/$hash" | |
fi | |
fi | |
cat "$result_file" | |
} | |
cache_exec_file(){ | |
file="$1" | |
shift || true | |
args=("$@") | |
file_hash="$(sha256:file "$file")" | |
args_hash="$(sha256 "$(printf "%s\n" "${args[@]}")")" | |
hash="$(sha256 "$file_hash$args_hash")" | |
if ! cache_key_exists "hash-cache/$hash"; then | |
cache_key_set "hash-cache/$hash" "$("$file" "${args[@]}")" | |
fi | |
cache_key_get "hash-cache/$hash" | |
} | |
cache_ls(){ | |
prev_dir="$PWD" | |
cd "$CACHE_ROOT_DIR" | |
dir="." | |
while [[ "$#" -gt 0 ]]; do | |
case "$1" in | |
-h|--help) | |
echo "Usage: find [options] <dir>" | |
echo " -n <glob>, --name <glob> - list only files matching the glob" | |
echo " -r <regex>, --regex <regex> - list only files matching the regex (applies to full path)" | |
echo " -t, --trim - trim the dir prefix from the output" | |
cd "$prev_dir" | |
return 0;; | |
-n|--name) | |
name="$2" | |
shift 2;; | |
-r|--regex) | |
regex="$2" | |
shift 2;; | |
-t|--trim) | |
trim=1 | |
shift;; | |
*) | |
dir="$1" | |
shift;; | |
esac | |
done | |
if [[ ! -d "$dir" ]]; then | |
return 0 | |
fi | |
find_args=() | |
if [[ -n "${name:-}" ]]; then | |
find_args+=("-name" "$name") | |
fi | |
if [[ -n "${regex:-}" ]]; then | |
find_args+=("-regex" "$regex") | |
fi | |
key_list=() | |
while IFS=$'\n' read -r -d '' file; do | |
key_list+=("$file") | |
done < <(find "$dir" -type f -regextype posix-extended "${find_args[@]}" -print0) | |
if [[ "${trim:-0}" -gt 0 ]]; then | |
trim_prefix_from_list "$dir/" "${key_list[@]}" | |
elif [[ "$dir" = "." ]]; then | |
trim_prefix_from_list "./" "${key_list[@]}" | |
else | |
printf '%s\n' "${key_list[@]}" | |
fi | |
cd "$prev_dir" | |
} | |
cfg_cache(){ | |
case ${1:-help} in | |
get) | |
shift || true | |
cache_key_get "$@";; | |
exec) | |
shift || true | |
cache_exec "$@";; | |
exec_file) | |
shift || true | |
cache_exec_file "$@";; | |
exists) | |
shift || true | |
cache_key_exists "$@";; | |
set) | |
shift || true | |
cache_key_set "$@";; | |
rm) | |
shift || true | |
cache_key_rm "$@";; | |
ls) | |
shift || true | |
cache_check_expiry ".*" | |
cache_ls "$@";; | |
tree) | |
cache_check_expiry ".*" | |
tree "$CACHE_ROOT_DIR/${2:-""}";; | |
help) | |
echo "Available commands:" | |
echo " get \$path" | |
echo " exec \$command - exec a command and cache the result" | |
echo " exec_file \$script_path - exec a script and cache it's result based on file content" | |
echo " set \$path \$value" | |
echo " rm \$path" | |
echo " ls \$opt_dir" | |
;; | |
*) | |
echo "Unknown subcommand: '${1:-}'" | |
exit 1;; | |
esac | |
} | |
##################################### Store Handling ################################### | |
cfg_store_set(){ | |
recipients=("$MAIN_GPG_KEY") | |
while [[ "$#" -gt 0 ]]; do | |
case "$1" in | |
--recipient|-r) | |
recipients+=("$2") | |
encrypt=1 | |
shift 2 | |
;; | |
--encrypt|-e) | |
encrypt=1 | |
shift | |
;; | |
--commit|-c) | |
commit=1 | |
shift | |
;; | |
-h|--help) | |
echo "Usage: store set [-r|--recipient <gpg-recipient>] [-c|--commit] [-e|--encrypt] <key> <value>" | |
echo "main gpg key is always in the recipient list per default" | |
echo "if any recipients are added encryption is enabled by default" | |
return 0 | |
;; | |
*) | |
key="$1" | |
value="$2" | |
shift 2 | |
;; | |
esac | |
done | |
mkdir -p "$(dirname "$STORE_ROOT_DIR/$key")" | |
if [[ "${encrypt:-0}" -eq 1 ]]; then | |
gpg_cmd="gpg --encrypt --armor" | |
for recipient in "${recipients[@]}"; do | |
gpg_cmd+=" --recipient $recipient" | |
done | |
gpg_cmd+=" --output -" | |
printf "%s" "$value" | $gpg_cmd > "$STORE_ROOT_DIR/$key" | |
else | |
printf "%s" "$value" > "$STORE_ROOT_DIR/$key" | |
fi | |
if [[ "${commit:-0}" -eq 1 ]]; then | |
git_cfg add "$STORE_ROOT_DIR/$key" | |
case "$(git_cfg status --short "$STORE_ROOT_DIR/$key" | awk '{ print $1 }')" in | |
A) | |
git_cfg commit -m "added $key to store";; | |
*) | |
git_cfg commit -m "modified $key in store";; | |
esac | |
fi | |
} | |
cfg_store_get(){ | |
if [[ "$(head -n 1 "$STORE_ROOT_DIR/$1")" = "-----BEGIN PGP MESSAGE-----" ]]; then | |
hash="$(sha256:file "$STORE_ROOT_DIR/$1")" | |
if cache_key_exists "hash-cache/$hash"; then | |
cache_key_get "hash-cache/$hash" | |
else | |
# TODO if gpg key is not available either tell user or request the secret via some other channel | |
result="$(gpg --default-key "$NODE_NAME@tionis.dev" -d < "$STORE_ROOT_DIR/$1" 2>/dev/null)" | |
cache_key_set "hash-cache/$hash" "$result" | |
echo "$result" | |
fi | |
else | |
cat "$STORE_ROOT_DIR/$1" | |
fi | |
} | |
cfg_store(){ | |
case "${1:-help}" in | |
get) | |
shift | |
cfg_store_get "$@" | |
;; | |
set) | |
shift | |
cfg_store_set "$@" | |
;; | |
rm) | |
shift | |
rm -r "${STORE_ROOT_DIR:?}/${1:?}" | |
;; | |
ls) | |
if [[ -n "${2:-}" ]]; then | |
ls "$STORE_ROOT_DIR/$2" | |
else | |
tree "$STORE_ROOT_DIR" | |
fi;; | |
exists) | |
shift | |
test -f "$STORE_ROOT_DIR/$1";; | |
help) | |
echo "Available commands:" | |
echo " get \$path" | |
echo " set \$path" | |
echo " rm \$path" | |
echo " ls \$path" | |
;; | |
*) | |
echo "Unknown subcommand" | |
exit 1;; | |
esac | |
} | |
##################################### Sync and Git funcs ############################### | |
apply-commit(){ | |
commit=${1:-$(git_cfg rev-parse --abbrev-ref HEAD)} | |
parents="$(cfg cat-file -p "$commit" | head -n 3 | grep -cE '^parent [a-z0-9]{40}$')" | |
if [[ $parents -gt 1 ]]; then | |
echo "Detected merge commit, defaulting to merging using first parent (-m 1)" | |
fi | |
target=${2:-""} | |
IFS='.' read -ra branch_path <<< "$(git_cfg rev-parse --abbrev-ref HEAD)" | |
branch_count=${#branch_path[@]} | |
max="$((branch_count - 2))" | |
# Iterate over the branch array in reverse, starting from the one before the last | |
for ((i = max; i >= 0; i--)); do | |
branch=$(join_elements "$i" "${branch_path[@]}") | |
if test "$i" = "$max"; then | |
child="$commit" | |
else | |
child=$(join_elements "$((i+1))" "${branch_path[@]}") | |
fi | |
cd "$(get_worktree_dir "$branch")" | |
if [[ $parents -gt 1 ]]; then | |
echo "cherry-picking merge in $branch" | |
git cherry-pick -m 1 "$child" | |
else | |
echo "cherry-picking in $branch" | |
git cherry-pick "$child" | |
fi || (echo "Cherry picking encountered a problem, exit shell when it is fixed" && "${SHELL:-bash}") | |
if test "$branch" = "$target"; then | |
break | |
fi | |
done | |
cd | |
git_cfg push --all || error "Error during pushing, commits where applied though" | |
} | |
cfg_sync(){ | |
# Environment should already be loaded here | |
#head_before_sync="$(cfg_git rev-parse HEAD)" | |
echo "===> Starting cfg Sync @[$(date --iso-8601=seconds)]" | |
if type -v systemctl >/dev/null 2>&1; then | |
( (systemctl --user --failed | grep -oP '(?<=^● ).*') || true) > ~/.cache/systemd-failed-user-services 2>&1 | |
fi | |
cfg fetch || error "Fetch failed (No internet connection?)" | |
IFS='.' read -ra branch_path <<< "$(cfg rev-parse --abbrev-ref HEAD)" | |
branch_count=${#branch_path[@]} | |
sources=("${branch_path[@]:0:$((branch_count-1))}") # Use array slicing to get all but the last element | |
echo "Processing parent branches:" | |
for index in "${!sources[@]}"; do | |
branch=$(join_elements "$index" "${branch_path[@]}") | |
echo "[$index] Merging $branch..." | |
cd "$(get_worktree_dir "$branch")" | |
git merge "origin/$branch" --no-edit --autostash | |
if test "$index" -gt 0; then | |
previous_branch="${branch_path[$((index-1))]}" | |
git merge "$previous_branch" --no-edit --autostash | |
fi | |
done | |
echo "Processing active branch:" | |
main_branch="$(cfg rev-parse --abbrev-ref HEAD)" | |
echo "Merging origin/$main_branch into $main_branch" | |
cfg merge "origin/$main_branch" --no-edit --autostash | |
if test "$branch_count" -gt 1; then | |
branch=$(join_elements "$((branch_count-2))" "${branch_path[@]}") | |
echo "Merging $branch into $main_branch" | |
cfg merge "$branch" --no-edit --autostash | |
fi | |
echo "Finished merging, starting pushing..." | |
cfg push --all | |
if test -f ~/.glyph/.main; then | |
echo "===> Starting Glyph Sync @[$(date --iso-8601=seconds)]" | |
~/.glyph/.main sync | |
fi | |
echo "===> Generating ssh authorized_keys file from allowed_signers @[$(date --iso-8601=seconds)]" | |
# TODO replace this with a call to ssh-sigchain once its ready | |
ssh:authorized_keys:generate | |
} | |
##################################### Vars ################################### | |
vars_print_var(){ | |
case "${VAR_EXPORT_MODE:-posix}" in | |
posix) | |
echo "export $1=\"$2\";";; | |
fish) | |
echo "set -x $1 \"$2\";";; | |
*) | |
error "Unknown VAR_EXPORT_MODE: ${VAR_EXPORT_MODE:-posix}";; | |
esac | |
declare "$1"="$2" | |
} | |
handle_ssh_agent_startup(){ | |
# Look into overrides | |
if cache_key_exists "cfg/use-gpg-agent" && [[ "$(cache_key_get "cfg/use-gpg-agent")" -gt 0 ]]; then | |
log "Using gpg-agent" | |
if command -v okc-ssh-agent >/dev/null; then | |
if [[ -f "$HOME/.cache/okc-ssh-agent.env" ]]; then | |
source "$HOME/.cache/okc-ssh-agent.env" | |
else | |
warning "okc-ssh-agent is available but no env file found" | |
fi | |
else | |
SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)" | |
export SSH_AUTH_SOCK | |
fi | |
result="$(echo UPDATESTARTUPTTY | gpg-connect-agent 2>/dev/null)" | |
if [[ "$result" != "OK" ]]; then | |
warning "Failed to update gpg-agent's TTY:" | |
fi | |
fi | |
# Then try using existing agents | |
if [[ -n "${SSH_AUTH_SOCK:-}" && -S "$SSH_AUTH_SOCK" ]]; then | |
log "Using existing ssh-agent" | |
status=0 | |
timeout 0.3 ssh-add -l > /dev/null 2>&1 || status=$? | |
if [[ ! "$status" -eq 2 ]]; then | |
return | |
fi | |
log "ssh-agent is dead, starting new one" | |
fi | |
if [[ -n "${XDG_RUNTIME_DIR:-}" && -S "$XDG_RUNTIME_DIR/gcr/.ssh" ]]; then | |
log "Using gnome keyring ssh-agent" | |
export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/gcr/.ssh" | |
return | |
fi | |
# Finally try starting own agent | |
log "Starting new ssh-agent" | |
eval "$(ssh-agent -s)" >/dev/null # TODO replace this later with static/dynamic approach | |
} | |
ssh:cert:time_remaining(){ | |
cert_expiry_secs="$(date --date "$(ssh-keygen -L -f "$cert_path" | grep 'Valid: from' | grep -oP '(?<= to ).*$')" +%s)" | |
now_secs="$(date +%s)" | |
remaining_secs="$((cert_expiry_secs - now_secs))" | |
echo "$remaining_secs" | |
} | |
cert_path="$HOME/.ssh/id_ed25519-cert.pub" | |
ssh:add-keys(){ | |
if ! ssh-add -l >/dev/null; then | |
echo "Adding on-disk ssh keys..." | |
ssh-add | |
fi | |
if [[ -f "$cert_path" ]]; then | |
secs_remaining="$(ssh:cert:time_remaining "$cert_path")" | |
if [[ "$secs_remaining" -lt 0 ]]; then | |
warning "Certificate expired!" | |
ssh-add -d "$cert_path" | |
elif [[ "$secs_remaining" -lt 43200 ]]; then | |
warning "Certificate about to expire ($(date -d "@$secs_remaining" -u +%H:%M:%S) remaining)" | |
fi | |
fi | |
} | |
ssh_agent_ensure_keys_loaded(){ | |
ssh:add-keys | |
} | |
vars_export(){ | |
VAR_EXPORT_MODE="posix" | |
while [[ "$#" -gt 0 ]]; do | |
case "$1" in | |
-h|--help) | |
echo "Usage: export [options]" | |
echo " --shell - set the shell for which to export the vars" | |
echo " valid values are: posix, fish" | |
return 0 | |
;; | |
--shell) | |
VAR_EXPORT_MODE="$2" | |
shift 2 | |
;; | |
*) | |
echo "Unknown argument: $1" | |
return 1 | |
;; | |
esac | |
done | |
handle_ssh_agent_startup | |
vars_print_var SSH_AUTH_SOCK "$SSH_AUTH_SOCK" | |
if ! test -f "$CACHE_ROOT_DIR.vars/NODE_NAME"; then | |
mkdir -p "$CACHE_ROOT_DIR.vars" | |
if command -v hostnamectl >/dev/null 2>&1; then | |
hostnamectl hostname > "$CACHE_ROOT_DIR.vars/NODE_NAME" | |
else | |
hostname > "$CACHE_ROOT_DIR.vars/NODE_NAME" | |
fi | |
fi | |
for file in "$CACHE_ROOT_DIR.vars"/*; do | |
vars_print_var "$(basename "$file")" "$(cat "$file")" | |
done | |
ssh_agent_ensure_keys_loaded >&2 | |
} | |
cfg_vars(){ | |
case "${1:-help}" in | |
export) | |
shift || true | |
vars_export "$@";; | |
set) | |
shift || true | |
mkdir -p "$CACHE_ROOT_DIR.vars" | |
echo "$2" > "$CACHE_ROOT_DIR.vars/$1";; | |
rm) | |
shift || true | |
rm -r "$CACHE_ROOT_DIR.vars/$1";; | |
ls) | |
ls "$CACHE_ROOT_DIR.vars";; | |
help) | |
echo "Available Subcommands:" | |
echo " set \$key \$value - set a env var to a value" | |
echo " rm \$key - remove an env var" | |
echo " export - export static and dynamic vars" | |
esac | |
} | |
##################################### SSH ################################### | |
ssh:authorized_keys:generate(){ # TODO replace with call to ssh-sigchain like e.g. ssh-sigchain get_authorized_keys tionis.dev | |
trust_anchor="*tionis.dev,*tasadar.net,*wendland.dev,*construct-rpg.net valid-after=\"20221007\" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDU1dl1LIBDFZ5aKALIUGdUHB70VuBqGH2+BbLvioaUWBnDCSB8mrr75EY1FpyxDIW7q/Gvc43wnc2bLXuGyLEY78gm7chBzVcajJCST7Dq8TNiezp4mnBagRixreMBk8M29ld9p6J6aGejbysc8vLta3xXnYmRKfWeZKayegtIm3/KciLvPuK4+UrMiKO0fC17wukuqUvDZVklDeFBFLSO/lee7oPvTI5f/KBeVF0rs21ZSDKZN+8Q7VPIohI/xVlCvdEyqDTICOUKroaAPGa1/1NkSd4fe5F02C5h7WChHad8btWNSu8nTP86KUAOFOYa8UUpoaHt2GuUCU87pHosQ08tTijAAx8bDyq2KdnJl9kgXh/2LaRnu3/DJDQXBJpV821Gyzt8hlqXA0cdrbyE6x13yIA+Ta1WXlR2Igzai3UOTkLL6POJBCOycO4dxd9fS7l8WNic6TIQmQDl2ecUECgSYWvBH2TJiltCUQEy0V2Rx8I28RvtuyzkmGbR4Tz5mQiwEuk0dyxRCoct6z9CpC9FSZRiXH7+qUHlaleZLEI6EYqMWFMj0VncQ3ddklEEzEOP9weUWvdgIWy8woCQuZ/YuW4lNS2Qt25jqFgv9XVddzsTDdSt1GFsdDnyHyhrnaSf0bayYtCo2849GI/QKR3dvjGogpYz/5jspxZZEQ== pgp.tionis.dev" | |
if ! ssh-keygen -Y verify -f <(echo "$trust_anchor") -n allowed_signers -s ~/.ssh/allowed_signers.sig -I tionis.dev < "$HOME/.ssh/allowed_signers"; then | |
error "Failed to verify signature of allowed_signers file using static trust_anchor" | |
fi | |
authorized_principals="$(cfg cache get ssh/authorized_principals || (cfg cache set ssh/authorized_principals "tionis.dev,$NODE_NAME.tionis.dev"; printf "tionis.dev,%s.tionis.dev" "$NODE_NAME"))" | |
ssh:authorized_keys_from_allowed_signers --principals "$authorized_principals" # TODO replace janet? | |
} | |
cfg_ssh(){ | |
case "${1:-help}" in | |
help) | |
echo "Available commands:" | |
echo " help - show this help" | |
echo " authorized_keys:generate - generate the authorized_keys file from allowed_signers" | |
echo " set_principals \$comma_separated_principals - set the principals that have access to this machine" | |
echo " get_principals - get the principals that have access to this machine" | |
return 0 | |
;; | |
authorized_keys:generate) | |
ssh:authorized_keys:generate | |
;; | |
set_principals) | |
shift || true | |
if test -z "$1"; then | |
error "No principals provided" | |
fi | |
cfg cache set ssh/authorized_principals "$1" | |
;; | |
get_principals) | |
cfg cache get ssh/authorized_principals || (cfg cache set ssh/authorized_principals "tionis.dev,$NODE_NAME.tionis.dev"; printf "tionis.dev,%s.tionis.dev" "$NODE_NAME") | |
;; | |
*) | |
echo "Unknown subcommand" | |
exit 1;; | |
esac | |
} | |
#################################### Util ################################### | |
cfg_util(){ | |
case "${1:-help}" in | |
fetch-main-gpg-key) | |
gpg --recv-keys "$MAIN_GPG_KEY";; | |
update_embedded) | |
for file in "$STORE_ROOT_DIR/cfg/embedded_deps/"*; do | |
run "$file" | |
done;; | |
ssh:add-keys) | |
ssh:add-keys;; | |
ssh:cert:time_remaining) | |
shift || true | |
ssh:cert:time_remaining "$1";; | |
help) | |
echo "Available commands:" | |
echo " fetch-main-gpg-key" | |
echo " update_embedded - update the embedded dependencies using scripts in store (cfg/embedded_deps/*)" | |
;; | |
*) | |
echo "Unknown subcommand" | |
exit 1;; | |
esac | |
} | |
#################################### Main ################################### | |
case "${1:-help}" in | |
git) | |
shift || true | |
git_cfg "$@";; | |
apply|apply-commit) | |
shift | |
apply-commit "$@";; | |
sync) | |
cfg_sync "$@";; | |
cache) | |
shift || true | |
cfg_cache "$@";; | |
vars) | |
shift || true | |
cfg_vars "$@";; | |
store) | |
shift || true | |
cfg_store "$@";; | |
ssh) | |
shift || true | |
cfg_ssh "$@";; | |
help) | |
echo "Available commands:" | |
echo " prompt ... - config status prompt for shell" | |
echo " cache ... - a key value store local to this machine" | |
echo " store ... - a key value store shared between all nodes" | |
echo " vars ... - manage universal env vars" | |
echo " ssh ... - manage ssh auth to this node" | |
echo " apply \$OPT_COMMIT \$OPT_UPSTREAM_TARGET_BRANCH - apply (cherry-pick) last commit backwards to upstream branches" | |
echo " todo - list todos" | |
echo " prompt - get a line for your shell prompt, please note that this is only for demonstation, shell inline code will run faster" | |
echo " help - show this help" | |
;; | |
prompt) | |
changes="$(git "--git-dir=$HOME/.cfg" "--work-tree=$HOME" status --short | wc -l)" | |
if test "$changes" -gt 0; then | |
printf "\x1b[31m%d uncommited changes \x1b[37m" "$changes" | |
else | |
printf "" | |
fi | |
if test -f "$cert_path"; then | |
remaining_secs="$(ssh:cert:time_remaining "$cert_path")" | |
if [[ "$remaining_secs" -lt 0 ]]; then | |
printf "\x1b[31mCertificate expired! \x1b[37m" | |
elif [[ "$remaining_secs" -lt 43200 ]]; then | |
printf "\x1b[31mCertificate expires in %s \x1b[37m" "$(date -d "@$remaining_secs" -u +%H:%M:%S)" | |
fi | |
fi | |
;; | |
util) | |
shift || true | |
cfg_util "$@";; | |
todo) | |
cd && git_cfg grep "# TODO";; | |
*) | |
git_cfg "$@";; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment