#!/usr/bin/env sh set -eu REPO_URL="${REPO_URL:-http://100.64.0.1:30087/section0/rta-handbook.git}" TARGET_DIR="${TARGET_DIR:-$HOME/Developer/Section0/rta-handbook}" COMMAND_DIR="${COMMAND_DIR:-$HOME/.local/bin}" COMMAND_NAME="${COMMAND_NAME:-section0-docs}" COMMAND_PATH="$COMMAND_DIR/$COMMAND_NAME" SERVER_URL="${SECTION0_SERVER_URL:-https://ops.virgil.info/md-to-section0-api}" step() { printf "\n==> %s\n" "$*" } if ! command -v git >/dev/null 2>&1; then echo "git is required but was not found on PATH" >&2 exit 1 fi step "Preparing local Markdown workspace" if [ -d "$TARGET_DIR/.git" ]; then echo "Repo already exists: $TARGET_DIR" git -C "$TARGET_DIR" remote set-url origin "$REPO_URL" git -C "$TARGET_DIR" fetch origin git -C "$TARGET_DIR" checkout main git -C "$TARGET_DIR" pull --ff-only else mkdir -p "$(dirname "$TARGET_DIR")" git clone "$REPO_URL" "$TARGET_DIR" fi git -C "$TARGET_DIR" config pull.ff only step "Installing helper command" mkdir -p "$COMMAND_DIR" cat > "$COMMAND_PATH" </dev/null 2>&1 || { echo "python3 is required for Authentik login JSON handling" >&2 exit 1 } } json_get() { need_python python3 -c 'import json,sys; data=json.load(sys.stdin); cur=data for part in sys.argv[1].split("."): cur = cur.get(part, "") if isinstance(cur, dict) else "" print(cur if cur is not None else "")' "\$1" } open_url() { if command -v open >/dev/null 2>&1; then open "\$1" >/dev/null 2>&1 || true elif command -v xdg-open >/dev/null 2>&1; then xdg-open "\$1" >/dev/null 2>&1 || true fi } credential_host() { need_python python3 -c 'from urllib.parse import urlparse; import sys url=urlparse(sys.argv[1]) print(url.netloc)' "\$1" } install_git_credential() { remote="\$1" username="\$2" password="\$3" host="\$(credential_host "\$remote")" protocol="\$(printf "%s" "\$remote" | sed -n "s#^\\([^:/]*\\)://.*#\\1#p")" [ -n "\$protocol" ] || protocol="http" if [ "\$(uname -s 2>/dev/null || true)" = "Darwin" ]; then git -C "\$REPO_DIR" config credential.helper osxkeychain fi printf "protocol=%s\nhost=%s\nusername=%s\npassword=%s\n\n" "\$protocol" "\$host" "\$username" "\$password" \ | git -C "\$REPO_DIR" credential approve } auth_login() { need_python mkdir -p "\$SESSION_DIR" device_json="\$(curl -fsS -X POST "\$SERVER_URL/device")" code="\$(printf "%s" "\$device_json" | json_get code)" auth_url="\$(printf "%s" "\$device_json" | json_get authUrl)" [ -n "\$code" ] && [ -n "\$auth_url" ] || { echo "login server did not return a device code" >&2 exit 1 } echo "Opening Authentik login:" echo " \$auth_url" open_url "\$auth_url" echo "Waiting for login..." token_json="" i=0 while [ "\$i" -lt 90 ]; do token_json="\$(curl -fsS "\$SERVER_URL/device/\$code/token" 2>/dev/null || true)" access_token="\$(printf "%s" "\${token_json:-{}}" | json_get accessToken 2>/dev/null || true)" [ -n "\$access_token" ] && break i=\$((i + 1)) sleep 2 done [ -n "\${access_token:-}" ] || { echo "timed out waiting for Authentik login" >&2 exit 1 } access_json="\$(curl -fsS -X POST -H "Authorization: Bearer \$access_token" "\$SERVER_URL/section0/git/access")" ok="\$(printf "%s" "\$access_json" | json_get ok)" [ "\$ok" = "True" ] || [ "\$ok" = "true" ] || { echo "Git access broker did not return credentials:" >&2 printf "%s\n" "\$access_json" >&2 exit 1 } remote="\$(printf "%s" "\$access_json" | json_get remote)" git_username="\$(printf "%s" "\$access_json" | json_get git.username)" git_password="\$(printf "%s" "\$access_json" | json_get git.password)" author_name="\$(printf "%s" "\$access_json" | json_get author.name)" author_email="\$(printf "%s" "\$access_json" | json_get author.email)" [ -n "\$remote" ] && [ -n "\$git_username" ] && [ -n "\$git_password" ] || { echo "Git access broker response was incomplete" >&2 exit 1 } git -C "\$REPO_DIR" remote set-url origin "\$remote" git -C "\$REPO_DIR" config user.name "\$author_name" git -C "\$REPO_DIR" config user.email "\$author_email" install_git_credential "\$remote" "\$git_username" "\$git_password" python3 -c 'import json,sys token=json.loads(sys.argv[1]) access=json.loads(sys.argv[2]) print(json.dumps({ "authenticated": True, "serverUrl": sys.argv[3], "authentik": token.get("authentik", {}), "author": access.get("author", {}), "remote": access.get("remote", ""), "credentialUser": access.get("git", {}).get("username", "") }, indent=2))' "\$token_json" "\$access_json" "\$SERVER_URL" > "\$SESSION_PATH" chmod 600 "\$SESSION_PATH" echo "Authenticated: \$author_email" echo "Git remote: \$remote" echo "Git user: \$git_username" echo "Session: \$SESSION_PATH" } case "\${1:-help}" in auth) case "\${2:-}" in login) auth_login ;; status) if [ -f "\$SESSION_PATH" ]; then cat "\$SESSION_PATH" else echo "not authenticated; run: section0-docs auth login" >&2 exit 1 fi ;; *) echo "usage: section0-docs auth " >&2 exit 1 ;; esac ;; configure) current_name="\$(git -C "\$REPO_DIR" config user.name || true)" current_email="\$(git -C "\$REPO_DIR" config user.email || true)" printf "Git author name [%s]: " "\$current_name" IFS= read -r author_name printf "Git author email [%s]: " "\$current_email" IFS= read -r author_email if [ -n "\$author_name" ]; then git -C "\$REPO_DIR" config user.name "\$author_name" elif [ -z "\$current_name" ]; then echo "Git author name is required" >&2 exit 1 fi if [ -n "\$author_email" ]; then git -C "\$REPO_DIR" config user.email "\$author_email" elif [ -z "\$current_email" ]; then echo "Git author email is required" >&2 exit 1 fi ;; doctor) remote="\$(git -C "\$REPO_DIR" remote get-url origin)" branch="\$(git -C "\$REPO_DIR" branch --show-current)" author_name="\$(git -C "\$REPO_DIR" config user.name || true)" author_email="\$(git -C "\$REPO_DIR" config user.email || true)" echo "Repo: \$REPO_DIR" echo "Remote: \$remote" echo "Branch: \$branch" if [ -n "\$author_name" ] && [ -n "\$author_email" ]; then echo "Git author: \$author_name <\$author_email>" else echo "Git author: missing; run section0-docs configure" fi git -C "\$REPO_DIR" ls-remote --heads origin main >/dev/null echo "Read access: ok" ;; open) printf "%s\n" "\$REPO_DIR" ;; pull) git -C "\$REPO_DIR" pull --ff-only ;; status) git -C "\$REPO_DIR" status --short --branch ;; commit) : "\${MESSAGE:?Set MESSAGE before running commit}" git -C "\$REPO_DIR" add . git -C "\$REPO_DIR" commit -m "\$MESSAGE" ;; push) git -C "\$REPO_DIR" push ;; push-test) branch="section0-smoke-\${USER:-user}-\$(date +%Y%m%d%H%M%S)" git -C "\$REPO_DIR" push origin HEAD:refs/heads/"\$branch" git -C "\$REPO_DIR" push origin :refs/heads/"\$branch" echo "Write access: ok" ;; help|--help|-h) usage ;; *) usage >&2 exit 1 ;; esac EOF chmod +x "$COMMAND_PATH" cat <