#!/usr/bin/env bash set -euo pipefail script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" repo_root="$(cd "$script_dir/../.." && pwd)" source "$repo_root/scripts/backup/lib/common.sh" dotenv_value() { local key="$1" local env_file="${WORKS_DOCKER_IMAGE_ENV_FILE:-.env}" [[ -f "$env_file" ]] || return 0 sed -n "s/^${key}=//p" "$env_file" | tail -n 1 } urlencode_path() { jq -nr --arg value "$1" '$value|@uri' } split_curl_response() { local response="$1" local __body_var="$2" local __status_var="$3" local status local body status="$(tail -n 1 <<<"$response")" if [[ "$status" =~ ^[0-9][0-9][0-9]$ ]]; then body="$(sed '$d' <<<"$response")" else status="200" body="$response" fi printf -v "$__body_var" '%s' "$body" printf -v "$__status_var" '%s' "$status" } redact_for_log() { sed -E 's/("(access_token|refresh_token|assertion|client_secret|Authorization)"[[:space:]]*:[[:space:]]*)"[^"]*"/\1"REDACTED"/Ig' } resolve_files_endpoint() { local parent_file_id="${1:-}" local encoded_drive_id encoded_drive_id="$(urlencode_path "$drive_id")" if [[ -n "$parent_file_id" ]]; then printf '%s/v1.0/sharedrives/%s/files/%s\n' "$api_base_url" "$encoded_drive_id" "$(urlencode_path "$parent_file_id")" else printf '%s/v1.0/sharedrives/%s/files\n' "$api_base_url" "$encoded_drive_id" fi } list_children() { local parent_file_id="${1:-}" local endpoint local response local response_body local http_status if [[ -n "$parent_file_id" ]]; then endpoint="$(resolve_files_endpoint "$parent_file_id")/children" else endpoint="$(resolve_files_endpoint)" fi response="$("$curl_bin" -sS -w $'\n%{http_code}' \ -H "Authorization: Bearer $access_token" \ "$endpoint")" split_curl_response "$response" response_body http_status if [[ "$http_status" -lt 200 || "$http_status" -ge 300 ]]; then backup_die "WORKS folder list request failed (HTTP $http_status): $(printf '%s' "$response_body" | redact_for_log)" fi printf '%s\n' "$response_body" } find_child_id() { local parent_file_id="$1" local child_name="$2" local expected_type="${3:-}" local children_json children_json="$(list_children "$parent_file_id")" jq -er --arg name "$child_name" --arg expectedType "$expected_type" ' [ (.files // .children // .items // [])[] | select((.fileName // .name) == $name) | select( $expectedType == "" or (((.fileType // .type // "") | ascii_downcase) == ($expectedType | ascii_downcase)) ) | .fileId // .id ][0] // empty ' <<<"$children_json" 2>/dev/null || true } resolve_folder_path() { local path="$1" local parent_file_id="${WORKS_DRIVE_DOCKER_IMAGE_PARENT_FILE_ID:-}" local component local folder_id IFS='/' read -r -a components <<<"$path" for component in "${components[@]}"; do [[ -n "$component" ]] || continue folder_id="$(find_child_id "$parent_file_id" "$component" "folder")" [[ -n "$folder_id" ]] || backup_die "WORKS Drive folder not found: ${path}" parent_file_id="$folder_id" done printf '%s\n' "$parent_file_id" } download_file() { local file_id="$1" local output_file="$2" local endpoint endpoint="$(resolve_files_endpoint "$file_id")/download" "$curl_bin" -fL -sS \ --location-trusted \ -H "Authorization: Bearer $access_token" \ -o "$output_file" \ "$endpoint" } load_image_archive() { local archive_file="$1" backup_log "Loading Docker image archive: $(basename "$archive_file")" zstd -dc "$archive_file" | docker load >/dev/null } image_tag="${IMAGE_TAG:-$(dotenv_value IMAGE_TAG)}" drive_id="${WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID:-${WORKS_DRIVE_SHARED_DRIVE_ID:-}}" access_token="${WORKS_DRIVE_ACCESS_TOKEN:-}" api_base_url="${WORKS_DRIVE_API_BASE_URL:-${WORKS_ADMIN_API_BASE_URL:-https://www.worksapis.com}}" curl_bin="${WORKS_DRIVE_CURL_BIN:-curl}" image_root_dir="${WORKS_DRIVE_DOCKER_IMAGE_DIR:-${WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR:-baron-sso}}" download_root="${WORKS_DOCKER_IMAGE_DOWNLOAD_DIR:-/tmp/baron-sso-docker-image-download}" image_list="${WORKS_DOCKER_IMAGE_NAMES:-backend userfront adminfront devfront orgfront}" [[ -n "$image_tag" ]] || backup_die "IMAGE_TAG is required." [[ -n "$drive_id" ]] || backup_die "WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID is required." [[ -n "$access_token" ]] || backup_die "WORKS_DRIVE_ACCESS_TOKEN is required." backup_require_command jq backup_require_command sha256sum backup_require_command zstd backup_require_command docker backup_require_command "$curl_bin" # Normalized remote path: baron-sso/${IMAGE_TAG}/${image}.${IMAGE_TAG}.tar.zst remote_path="${image_root_dir}/${image_tag}" target_folder_id="$(resolve_folder_path "$remote_path")" artifact_dir="${download_root}/${remote_path}" mkdir -p "$artifact_dir" for image in $image_list; do archive_name="${image}.${image_tag}.tar.zst" checksum_name="${image}.${image_tag}.sha256" manifest_name="manifest.${image_tag}.json" archive_id="$(find_child_id "$target_folder_id" "$archive_name")" checksum_id="$(find_child_id "$target_folder_id" "$checksum_name")" manifest_id="$(find_child_id "$target_folder_id" "$manifest_name")" [[ -n "$archive_id" ]] || backup_die "WORKS Drive image archive not found: ${remote_path}/${archive_name}" [[ -n "$checksum_id" ]] || backup_die "WORKS Drive image checksum not found: ${remote_path}/${checksum_name}" [[ -n "$manifest_id" ]] || backup_die "WORKS Drive image manifest not found: ${remote_path}/${manifest_name}" download_file "$archive_id" "$artifact_dir/$archive_name" download_file "$checksum_id" "$artifact_dir/$checksum_name" download_file "$manifest_id" "$artifact_dir/$manifest_name" ( cd "$artifact_dir" sha256sum -c "$checksum_name" >/dev/null ) manifest_sha256="$(jq -er --arg image "$image" '.images[$image].archive.sha256 // .archive.sha256' "$artifact_dir/$manifest_name")" actual_sha256="$(sha256sum "$artifact_dir/$archive_name" | awk '{print $1}')" [[ "$manifest_sha256" == "$actual_sha256" ]] || backup_die "manifest sha256 mismatch for $archive_name" load_image_archive "$artifact_dir/$archive_name" done backup_log "Loaded WORKS Drive Docker image archives from ${remote_path}"