From b7b09db4c512880b2e964b99126ce148b5f2b57c Mon Sep 17 00:00:00 2001 From: Pallav Vasa Date: Sat, 17 May 2025 16:10:00 +0000 Subject: [PATCH] chore: remove files related to workspace pipelines --- .bin/generate-user-config.sh | 39 ----- gitops_router.sh | 178 ---------------------- ssh_router.sh | 208 -------------------------- tests/test_validate_command_access.sh | 47 ------ validate_command_access.sh | 83 ---------- 5 files changed, 555 deletions(-) delete mode 100755 .bin/generate-user-config.sh delete mode 100644 gitops_router.sh delete mode 100755 ssh_router.sh delete mode 100755 tests/test_validate_command_access.sh delete mode 100644 validate_command_access.sh diff --git a/.bin/generate-user-config.sh b/.bin/generate-user-config.sh deleted file mode 100755 index fc32b86..0000000 --- a/.bin/generate-user-config.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -YAML_FILE="access.yml" -TEMPLATE_FILE="gitconfig.template" -USER="$1" - -# Extract user fields from YAML -GIT_NAME=$(yq ".\"$USER\".name" "$YAML_FILE") -GIT_EMAIL=$(yq ".\"$USER\".email" "$YAML_FILE") - -# Ensure fields are not empty -if [[ -z "$GIT_NAME" || -z "$GIT_EMAIL" ]]; then - echo "❌ Error: User '$USER' not found or missing name/email in $YAML_FILE" - exit 1 -fi - -# Create output directory -USER_DIR="files/$USER" -mkdir -p "$USER_DIR" - -# Generate .gitconfig -env GIT_NAME="$GIT_NAME" GIT_EMAIL="$GIT_EMAIL" \ - envsubst <"$TEMPLATE_FILE" >"$USER_DIR/gitconfig" - -echo "βœ… .gitconfig created at $USER_DIR/gitconfig" - -# Generate SSH keypair if it doesn't exist -KEYFILE="$USER_DIR/id_ed25519" - -if [[ -f "$KEYFILE" ]]; then - echo "πŸ”‘ SSH key already exists for $USER at $KEYFILE" -else - ssh-keygen -t ed25519 -N "" -C "$GIT_EMAIL" -f "$KEYFILE" - echo "βœ… SSH keypair generated at:" - echo " πŸ” Private: $KEYFILE" - echo " πŸ”“ Public : $KEYFILE.pub" -fi diff --git a/gitops_router.sh b/gitops_router.sh deleted file mode 100644 index 714ac2a..0000000 --- a/gitops_router.sh +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -PERSON="${1:?Missing PERSON argument}" -HOST="alps:3222" -PROTOCOL="http" -REPO=("babbarc/workspaces" "babbarc/workspaces-sec-alps-infilytics") -BRANCH="master" -LOG_FILE="/tmp/.gitops-router-${PERSON}.log" - -# ───────────────────────────────────────────── -# ANSI color codes -readonly C_RESET='\033[0m' -readonly C_INFO='\033[1;34m' # bold blue -readonly C_WARN='\033[1;33m' # bold yellow -readonly C_ERROR='\033[1;31m' # bold red - -# ───────────────────────────────────────────── -# log with emojis -log() { - local lvl="${1^^}" - shift - local icon color - - case "$lvl" in - INFO) icon="ℹ️" color="$C_INFO" ;; - WARN) icon="⚠️" color="$C_WARN" ;; - ERROR) icon="❌" color="$C_ERROR" ;; - *) icon="πŸ”Ή" color="$C_RESET" ;; - esac - - local ts - ts="$(date '+%Y-%m-%d %H:%M:%S')" - printf '%b%s [%s] [%s] %s%b\n' \ - "$color" "$icon" "$ts" "$lvl" "$*" "$C_RESET" | - tee -a "$LOG_FILE" -} - -# ───────────────────────────────────────────── -# Build the raw URL for fetching files -geturl() { - local repo="$1" type="$2" file="$3" - printf '%s://%s/%s/%s/branch/%s/%s\n' \ - "$PROTOCOL" "$HOST" "${REPO[$repo]}" "$type" "$BRANCH" "$file" -} - -# ───────────────────────────────────────────── -# Run a local script -run() { - local script="$1" - "$HOME/.local/bin/$script" -} - -# ───────────────────────────────────────────── -# Download & install an artifact -# update [] -update() { - local repo="$1" file="$2" dir="$3" mode="$4" type="${5:-raw}" - local url out - - out="$HOME/$dir/$(basename "$file")" - url="$(geturl "$repo" "$type" "$file")" - - [[ -f "$out" ]] && chmod 700 "$out" - - if curl -fsSL "$url" -o "$out"; then - log INFO "Downloaded $url β†’ $out" - chmod "$mode" "$out" - else - log ERROR "Failed to download $url" - return 1 - fi -} - -# ───────────────────────────────────────────── -# Clean up dangling podman images -clean_images() { - local dangling - dangling="$(podman images -f dangling=true -q)" - if [[ -z "$dangling" ]]; then - log INFO "No dangling images to remove." - else - log WARN "Removing dangling images..." - echo "$dangling" | xargs podman rmi - log INFO "Dangling images removed." - fi -} - -# ───────────────────────────────────────────── -# Remove host podman containers -remove_containers() { - local tokens=("$@") - local flags=() patterns=() containers=() - local valid='^[A-Za-z0-9._-]+$' - - # allow unmatched globs to disappear - shopt -s nullglob - - # separate flags (-f, etc.) from name patterns - for tok in "${tokens[@]}"; do - if [[ "$tok" == -* ]]; then - flags+=("$tok") - else - patterns+=("$tok") - fi - done - - # validate & expand each pattern - for pat in "${patterns[@]}"; do - if [[ ! "$pat" =~ $valid ]]; then - log ERROR "Invalid container name: '$pat'" - shopt -u nullglob - return 1 - fi - containers+=("$pat") - done - - shopt -u nullglob - - if ((${#containers[@]} == 0)); then - log WARN "No containers matched: ${patterns[*]}" - return 0 - fi - - # pass flags *then* containers to podman rm - podman rm "${flags[@]}" "${containers[@]}" -} - -# ───────────────────────────────────────────── -# validate_command [ …] -source "$HOME"/.local/bin/validate_command_access.sh - -# ───────────────────────────────────────────── -# Entry & command parsing -if [[ -z "${SSH_ORIGINAL_COMMAND:-}" ]]; then - log ERROR "No SSH_ORIGINAL_COMMAND provided." - exit 1 -fi - -log INFO "SSH_ORIGINAL_COMMAND: $SSH_ORIGINAL_COMMAND" -read -ra parts <<<"$SSH_ORIGINAL_COMMAND" -cmd="${parts[0]}" -args=("${parts[@]:1}") - -validate_command "$PERSON" "$cmd" "${args[@]}" - -# ───────────────────────────────────────────── -# Dispatch -case "$cmd" in -build) - case "${args[0]}" in - base) podman build --target base -t analytics-backend-base . ;; - workspace) podman build --target base -t analytics-backend-base . ;; - all) podman build -t analytics-backend-workspace . ;; - *) log ERROR "build: invalid arg '${args[0]}'" ;; - esac - ;; -update) - case "${args[0]}" in - containerfile) update 0 Containerfile . 500 ;; - access) update 1 access.yml . 400 ;; - authorized_keys) update 1 access.yml . 400 ;; - ssh_router) update 0 ssh_router.sh .local/bin 500 ;; - gitops_router) update 0 gitops_router.sh .local/bin 500 ;; - validate_command) update 0 validate_command_access.sh .local/bin 500 ;; - home_tar) update 0 home.tar.gz . 500 media ;; - gitconfig) update 0 gitconfig.template . 500 ;; - *) log ERROR "update: invalid arg '${args[0]}'" ;; - esac - ;; -clean) clean_images ;; -status) podman images ;; -remove) remove_containers "${args[@]}" ;; -*) - log ERROR "Unknown command: '$cmd'" - exit 127 - ;; -esac diff --git a/ssh_router.sh b/ssh_router.sh deleted file mode 100755 index 04468e8..0000000 --- a/ssh_router.sh +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -PERSON="${1:?Usage: $0 }" -WORKSPACE="${SSH_ORIGINAL_COMMAND:-}" -IMAGE="localhost/analytics-backend-workspace:latest" -DEV_USER="devuser" -XDG_RUNTIME_DIR="/run/user/$(id -u)" -LOG_FILE="/tmp/.ssh-router-${PERSON}.log" - -# ───────────────────────────────────────────── -# ANSI colors & emojis -readonly C_RESET='\033[0m' -readonly C_INFO='\033[1;34m' # blue -readonly C_WARN='\033[1;33m' # yellow -readonly C_ERROR='\033[1;31m' # red - -log() { - local level="${1^^}" - shift - local icon color - case "$level" in - INFO) icon="ℹ️" color="$C_INFO" ;; - WARN) icon="⚠️" color="$C_WARN" ;; - ERROR) icon="❌" color="$C_ERROR" ;; - *) icon="πŸ”Ή" color="$C_RESET" ;; - esac - local ts - ts="$(date '+%Y-%m-%d %H:%M:%S')" - printf '%b%s [%s] %s%b\n' \ - "$color" "$icon" "$ts" "[$level] $*" "$C_RESET" | - tee -a "$LOG_FILE" -} - -# ───────────────────────────────────────────── -# Check for interactive TTY -if [[ ! -t 0 ]]; then - log ERROR "No TTY allocatedβ€”refusing to run without an interactive terminal" - echo "Error: No TTY. Use 'ssh -t'" >&2 - exit 1 -fi - -# ───────────────────────────────────────────── -# Default WORKSPACE if empty -if [[ -z "$WORKSPACE" ]]; then - WORKSPACE="$PERSON" - log INFO "Defaulted WORKSPACE β†’ $WORKSPACE" -fi -TMUX_SESSION="${WORKSPACE}|analytics-backend" - -# ───────────────────────────────────────────── -# Ensure Podman socket is up -ensure_podman() { - local sock="$XDG_RUNTIME_DIR/podman/podman.sock" - if [[ ! -S "$sock" ]]; then - log INFO "Starting podman.socket for user $(id -un)" - systemctl --user start podman.socket || { - log ERROR "Failed to start podman.socket" - exit 1 - } - sleep 1 - fi - [[ -S "$sock" ]] || { - log ERROR "Podman socket still missing" - exit 1 - } -} -ensure_podman - -# ───────────────────────────────────────────── -# Ensure IMAGE is present -ensure_image() { - if ! podman image exists "$IMAGE"; then - log WARN "Image $IMAGE not foundβ€”pulling" - podman pull --tls-verify=false "$IMAGE" || { - log ERROR "Failed to pull $IMAGE" - exit 1 - } - log INFO "Pulled $IMAGE" - fi -} -ensure_image - -# ───────────────────────────────────────────── -# Disallow file transfers -case "$SSH_ORIGINAL_COMMAND" in -*scp* | *sftp* | *rsync* | *tar*) - log ERROR "File transfers are disabled" - exit 1 - ;; -esac - -# ───────────────────────────────────────────── -# Generate per-user gitconfig -generate_gitconfig() { - local access="$HOME/access.yml" - local template="$HOME/gitconfig.template" - local userdir="$HOME/secrets/$PERSON" - local name email - - name=$(yq -r ".\"$PERSON\".name" "$access" 2>/dev/null || echo) - email=$(yq -r ".\"$PERSON\".email" "$access" 2>/dev/null || echo) - - if [[ -z "$name" || -z "$email" ]]; then - log ERROR "Missing name/email for '$PERSON' in $access" - exit 1 - fi - - mkdir -p "$userdir" - GIT_NAME="$name" GIT_EMAIL="$email" \ - envsubst <"$template" >"$userdir/gitconfig" - log INFO ".gitconfig created β†’ $userdir/gitconfig" -} - -# ───────────────────────────────────────────── -# Start container if absent or stopped -start_container_if_needed() { - if ! podman container exists "$WORKSPACE"; then - log INFO "Creating container '$WORKSPACE'" - generate_gitconfig - podman run -dit \ - --name "$WORKSPACE" \ - --userns=keep-id \ - --user "$DEV_USER" \ - --hostname "$WORKSPACE" \ - --label auto-cleanup=true \ - -v "$HOME/data/$WORKSPACE:/app:Z" \ - -v "$HOME/secrets/$WORKSPACE/gitconfig:/home/$DEV_USER/.gitconfig:ro,Z" \ - -v "$HOME/secrets/$WORKSPACE/id_ed25519:/home/$DEV_USER/.ssh/id_ed25519:ro,Z" \ - -v "$HOME/secrets/$WORKSPACE/id_ed25519.pub:/home/$DEV_USER/.ssh/id_ed25519.pub:ro,Z" \ - --entrypoint "/home/$DEV_USER/start.sh" \ - "$IMAGE" "$TMUX_SESSION" - elif ! podman inspect -f '{{.State.Running}}' "$WORKSPACE" | grep -q true; then - log INFO "Starting existing container '$WORKSPACE'" - podman start "$WORKSPACE" >/dev/null - fi - sleep 1 -} - -# ───────────────────────────────────────────── -# Detach logic: stop container when devuser has left -check_devuser_attached() { - local clients - clients=$(podman exec "$WORKSPACE" tmux list-clients -t "$TMUX_SESSION" -F "#{client_user}" 2>/dev/null) - if grep -q "^${DEV_USER}\$" <<<"$clients"; then - log INFO "devuser still attachedβ€”keeping container running" - else - log INFO "devuser detachedβ€”stopping container" - podman stop "$WORKSPACE" >/dev/null - fi -} - -# ───────────────────────────────────────────── -# Determine access mode (rw|ro) or exit -get_access_mode() { - local yaml="access.yml" user="$PERSON" ws="$WORKSPACE" - [[ ! "$ws" =~ ^[A-Za-z0-9._-]+$ ]] && { - log ERROR "Invalid workspace name" - exit 1 - } - if [[ "$user" == "$ws" ]]; then - echo rw - elif yq -e '.["'"$user"'"].rw[]?' "$yaml" | grep -qx "$ws"; then - echo rw - elif yq -e '.["'"$user"'"].ro[]?' "$yaml" | grep -qx "$ws"; then - echo ro - else - log ERROR "$user has no access to $ws" - exit 1 - fi -} - -MODE="$(get_access_mode)" - -# ───────────────────────────────────────────── -# Main dispatch -case "$MODE" in -rw) - start_container_if_needed - - # Ensure tmux session exists - if ! podman exec -it --user "$DEV_USER" "$WORKSPACE" tmux has-session -t "$TMUX_SESSION" 2>/dev/null; then - podman exec -it --user "$DEV_USER" "$WORKSPACE" \ - tmux new-session -d -s "$TMUX_SESSION" - fi - - log INFO "$PERSON attaching to workspace '$WORKSPACE'" - podman exec -it -e TERM="$TERM" --user "$DEV_USER" "$WORKSPACE" \ - tmux attach -t "$TMUX_SESSION" - log INFO "$PERSON detached from '$WORKSPACE'" - check_devuser_attached - ;; -ro) - if podman inspect -f '{{.State.Running}}' "$WORKSPACE" 2>/dev/null | grep -q true; then - log INFO "$PERSON viewing workspace '$WORKSPACE'" - podman exec -it -e TERM="$TERM" --user "$DEV_USER" "$WORKSPACE" \ - tmux attach -r -t "$TMUX_SESSION" - log INFO "$PERSON stopped viewing '$WORKSPACE'" - else - log ERROR "Workspace '$WORKSPACE' is not running" - exit 1 - fi - ;; -*) - log ERROR "Unknown access mode: '$MODE'" - exit 1 - ;; -esac diff --git a/tests/test_validate_command_access.sh b/tests/test_validate_command_access.sh deleted file mode 100755 index b5893f8..0000000 --- a/tests/test_validate_command_access.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bash -set -e - -cat >access.yml < exists - local is_fixed - is_fixed="$(yq e ".\"$PERSON\".fixedArgsCommands | has(\"$cmd\")" "$yaml")" - # Check if multiArgsCommands. exists - local is_multi - is_multi="$(yq e ".\"$PERSON\".multiArgsCommands | has(\"$cmd\")" "$yaml")" - - if [[ "$is_fixed" != "true" && "$is_multi" != "true" ]]; then - echo "ERROR: Command '$cmd' not allowed for $PERSON" >&2 - return 1 - fi - - # Exclude flags from positional args - local args=() - for tok in "${tokens[@]}"; do - [[ "$tok" == -* ]] && continue - args+=("$tok") - done - - if [[ "$is_fixed" == "true" ]]; then - mapfile -t allowed < <(yq e ".\"$PERSON\".fixedArgsCommands.\"$cmd\"[]" "$yaml" 2>/dev/null) - local n_allowed="${#allowed[@]}" - if [[ $n_allowed -eq 0 ]]; then - # zero-arg command - if [[ ${#args[@]} -ne 0 ]]; then - echo "ERROR: Command '$cmd' takes no arguments" >&2 - return 1 - fi - else - # depth is 1: only one of the allowed choices must be present - if [[ ${#args[@]} -ne 1 ]]; then - echo "ERROR: Command '$cmd' requires exactly 1 argument: (${allowed[*]})" >&2 - return 1 - fi - local found=0 - for want in "${allowed[@]}"; do - [[ "${args[0]}" == "$want" ]] && found=1 && break - done - if [[ $found -eq 0 ]]; then - echo "ERROR: Invalid argument '${args[0]}' for '$cmd'; allowed: (${allowed[*]})" >&2 - return 1 - fi - fi - return 0 - fi - - if [[ "$is_multi" == "true" ]]; then - mapfile -t allowed < <(yq e ".\"$PERSON\".multiArgsCommands.\"$cmd\"[]" "$yaml" 2>/dev/null) - local n_allowed="${#allowed[@]}" - if [[ ${#args[@]} -lt 1 || ${#args[@]} -gt $n_allowed ]]; then - echo "ERROR: Command '$cmd' requires 1 to $n_allowed arguments: (${allowed[*]})" >&2 - return 1 - fi - - # Order doesn't matter, but all must be unique and from allowed. - # Build a set of allowed args. - declare -A allowed_set=() - for want in "${allowed[@]}"; do allowed_set["$want"]=1; done - - declare -A seen=() - for a in "${args[@]}"; do - [[ -z "${allowed_set[$a]}" ]] && { - echo "ERROR: Invalid argument '$a' for '$cmd'; allowed: (${allowed[*]})" >&2 - return 1 - } - [[ -n "${seen[$a]}" ]] && { - echo "ERROR: Duplicate argument '$a' for '$cmd'" >&2 - return 1 - } - seen["$a"]=1 - done - return 0 - fi -}