Post-Local sync at 2025-06-09 14:43:29

This commit is contained in:
Mark Randall Havens 2025-06-09 14:43:29 -05:00
parent 7df48b6263
commit 336ba02e98
51 changed files with 2074 additions and 208 deletions

16
bin/ECHO.md.asc Normal file
View file

@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEif0F7T4AkoRgIfM3TifTfDWIcr8FAmhDtrUACgkQTifTfDWI
cr+EmQ/7Bjq1A/wd/0VQ5SgOtw0xIReJsuUuE9ZfTqK0nkLwuBggdEWvBKWRpEtP
6o2f6rvkkWuwEPM2Ilc00sz41WTi5zMYz21B8Xp3fwSgQ7pcXLoNGM8pDUshLIa1
ML16OkTGkQP8FmTAqeObIGd3QyAvQp2pxB0wkAWCsPJkMlolRl01v7Ygtc/+jOMV
O7qTO/8onsXoLBTz16O3AlFueJCNXJk16dR6DHrqfKUrvxK1o+j1Dbq1F37UH+Zg
dbQ6PYnRWfeKFaRSaKyFS4ZfB0SoUwUGvpa/pcWl9VyzXLJG/7QDzcmLu/on2MNs
SuOvwRY2mIIUY8LEWPHi62FRUqTF8lS6pMiR61JTU5HNpvrsr8dO/am2HrxY8l8h
1wfHQpfMDixdVi4cDJcY/NI2EmlZjVE8WBdgB3Cw5av7jlQllWXFwWM975ymXSA7
0IjRJ+z8/+TGCF/Y7G3kJIug7edGb9mdDYXcnREFYkQtlNT4qS0bMv6HRiYvC9ji
eyq2u9vGXt+xnHnhgdwY+CfjdgtskY6A71p3lIEyIrTp3pRaFLBPURog8QFaYwvt
6dZsMMFw/DvFS1OAvCu/wcAxNQO1EVtitAAa52QQYSnTPC17r+3mIiDeURJKGkpp
jgq4YVX/vsyHo+OqsNQgQb2vKDkcGZzD4koLYjchJ5M+q/dpZCM=
=1ubL
-----END PGP SIGNATURE-----

View file

@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEif0F7T4AkoRgIfM3TifTfDWIcr8FAmhDtrUACgkQTifTfDWI
cr8hTw/+KrfoNkI95LDd0i1GljfcHwox9Uz0WIrSpKDeMLjJDEHZriC9hJbHy9Tt
dPP2Su90gj1B8I5g57X+3ngaaK58/Kvlc3ct7mdkK5T3sOeg/W2Vg1N4Dn3dkBS4
Dw4chUQ1wSXrKjEKr/6wzWpfHGlFkosdVxVPy7oWrwLarpN/CIMLVIszejIfAvmG
ZKW22vadOHhIGUDv/mFCp3SzP269iSuvFUCC3d8ssrj54U3PHCyaELF6gnIWrAMd
U2O2dmYMuE8p2mYUDw9mo87RgXvA+lO0qHT4WeSSWnqvYq7uIm4cH9qSpI2CqNVp
N+P15GoZZ5z2CKaDvcm9q6UlhfV+ox3q3J/Sbn05l6I0M84zPMTUNIGlPeICVIgA
FrAr3U7lWWdRet1XHvdNOkBdQHzOU4PAGAv5iGHWg7FZ57IswFro+3he7ilJfxiL
C+UekmJiM96WdxyEcHGp4sVr/oFjFYSHVn7cuEYpQwo7cxip8kt0uNdesoMXbFHO
qrbNVosZCGZrmqDiCGSxX9obSjWthdzCfIJmRQdnIvkST+pK9w2J5X5xyytg992z
+WMJj1N+dFLJ9/F8CmpQObN5MMRldVkVyBUw8LtiXSfPvYw0pjUHCSLICYoIn5fY
txH50RGsZfL9Bv7yPDE9qnXaLuHeeRIqxR9Ic89YsXqiCufzQ+A=
=F0yr
-----END PGP SIGNATURE-----

261
bin/gitfield-codeberg Executable file
View file

@ -0,0 +1,261 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
# Configuration
GIT_REMOTE_NAME="codeberg"
CODEBERG_DOMAIN="codeberg.org"
CODEBERG_SSH="git@$CODEBERG_DOMAIN"
CODEBERG_SSH_PORT="22"
CODEBERG_API="https://$CODEBERG_DOMAIN/api/v1"
USERNAME="mrhavens"
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || { echo "[ERROR] Not inside a git repository. Please run this script from within a git repository." >&2; exit 1; }
REPO_NAME=$(basename "$REPO_ROOT") || { echo "[ERROR] Failed to get repository name" >&2; exit 1; }
MARKDOWN_FILE="$REPO_ROOT/.gitfield/codeberg.sigil.md"
DEFAULT_NAME="Mark Randall Havens"
DEFAULT_EMAIL="mark.r.havens@gmail.com"
TOKEN_FILE="$HOME/.codeberg_token"
SCRIPT_VERSION="1.0"
# Logging functions
info() { echo -e "\e[1;34m[INFO]\e[0m $*"; }
warn() { echo -e "\e[1;33m[WARN]\e[0m $*"; }
error() { echo -e "\e[1;31m[ERROR]\e[0m $*" >&2; exit 1; }
# Check for required tools
info "Checking for required tools..."
for cmd in git curl jq ssh lsb_release; do
command -v "$cmd" >/dev/null || {
sudo apt update -qq || warn "Failed to update package lists, continuing..."
sudo apt install -y git curl jq openssh-client lsb-release || error "Failed to install $cmd"
}
done
# Handle Codeberg token
RESET_TOKEN=false
if [[ "${1:-}" == "--reset-token" ]]; then
RESET_TOKEN=true
rm -f "$TOKEN_FILE" 2>/dev/null || warn "Failed to remove token file"
info "Token reset requested."
fi
if [[ -f "$TOKEN_FILE" && "$RESET_TOKEN" == false ]]; then
TOKEN=$(cat "$TOKEN_FILE" 2>/dev/null) || error "Failed to read token from $TOKEN_FILE"
info "Using cached token from $TOKEN_FILE"
else
echo "🔐 Paste your Codeberg Personal Access Token (scopes: write:repository, write:ssh_key)"
echo "→ Generate at: $CODEBERG_DOMAIN/settings/tokens"
read -rsp "Token: " TOKEN
echo
[[ -z "$TOKEN" ]] && error "Token cannot be empty"
echo "$TOKEN" > "$TOKEN_FILE" || error "Failed to write token to $TOKEN_FILE"
chmod 600 "$TOKEN_FILE" || error "Failed to set permissions on $TOKEN_FILE"
info "Token saved at $TOKEN_FILE"
fi
# Set git user info
git config --global user.name "$DEFAULT_NAME" || warn "Failed to set git user name"
git config --global user.email "$DEFAULT_EMAIL" || warn "Failed to set git user email"
info "Git identity set to: $DEFAULT_NAME <$DEFAULT_EMAIL>"
# Ensure at least one commit exists
if ! git rev-parse HEAD &>/dev/null; then
error "No commits found in the repository. Please add and commit files before running this script."
fi
# SSH setup with default port (22 for Codeberg)
if [[ ! -f "$HOME/.ssh/id_ed25519" ]]; then
info "Generating SSH key..."
ssh-keygen -t ed25519 -C "$DEFAULT_EMAIL" -f "$HOME/.ssh/id_ed25519" -N "" || error "Failed to generate SSH key"
fi
eval "$(ssh-agent -s)" >/dev/null 2>&1 || error "Failed to start ssh-agent"
ssh-add "$HOME/.ssh/id_ed25519" >/dev/null 2>&1 || warn "SSH key already added or could not be added"
# Configure SSH for Codeberg
SSH_CONFIG_FILE="$HOME/.ssh/config"
if ! grep -q "Host $CODEBERG_DOMAIN" "$SSH_CONFIG_FILE" 2>/dev/null; then
mkdir -p "$HOME/.ssh" && chmod 700 "$HOME/.ssh"
cat >> "$SSH_CONFIG_FILE" <<EOF
Host $CODEBERG_DOMAIN
HostName $CODEBERG_DOMAIN
User git
Port $CODEBERG_SSH_PORT
IdentityFile $HOME/.ssh/id_ed25519
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
EOF
chmod 600 "$SSH_CONFIG_FILE" || warn "Failed to set permissions on SSH config file"
info "Added SSH config for $CODEBERG_DOMAIN with port $CODEBERG_SSH_PORT"
fi
# SSH key upload to Codeberg
set +e
info "Testing SSH connection..."
SSH_TEST_OUTPUT=$(ssh -T -p "$CODEBERG_SSH_PORT" "$CODEBERG_SSH" 2>&1)
if ! echo "$SSH_TEST_OUTPUT" | grep -q "successfully authenticated"; then
warn "SSH test failed, attempting to upload SSH key. Output: $SSH_TEST_OUTPUT"
PUBKEY=$(cat "$HOME/.ssh/id_ed25519.pub" 2>/dev/null) || error "Failed to read SSH public key"
TITLE="AutoKey-$(hostname)-$(date +%s 2>/dev/null || echo 'unknown')"
CURL_OUTPUT=$(curl -s --fail -X POST "$CODEBERG_API/user/keys" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"title\": \"$TITLE\", \"key\": \"$PUBKEY\", \"read_only\": false}" 2>&1)
if [[ $? -ne 0 ]]; then
warn "SSH key upload failed: $CURL_OUTPUT"
else
info "SSH key uploaded successfully."
sleep 2
SSH_TEST_OUTPUT=$(ssh -T -p "$CODEBERG_SSH_PORT" "$CODEBERG_SSH" 2>&1)
if ! echo "$SSH_TEST_OUTPUT" | grep -q "successfully authenticated"; then
warn "SSH test still failing after key upload. Output: $SSH_TEST_OUTPUT"
else
info "SSH test passed after key upload."
fi
fi
else
info "SSH test passed: $SSH_TEST_OUTPUT"
fi
set -e
# Check and create Codeberg repository
info "Checking if repository exists..."
EXISTS=$(curl -s -H "Authorization: token $TOKEN" "$CODEBERG_API/repos/$USERNAME/$REPO_NAME" | jq -r .name 2>/dev/null || echo "")
if [[ "$EXISTS" != "$REPO_NAME" ]]; then
info "Creating repository $REPO_NAME on Codeberg..."
CURL_OUTPUT=$(curl -s --fail -X POST "$CODEBERG_API/user/repos" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"name\": \"$REPO_NAME\", \"description\": \"Created via gitfield-codeberg\", \"private\": false}" 2>&1) || {
warn "Failed to create repository: $CURL_OUTPUT"
error "Repository creation failed. Check token permissions or network."
}
info "Repository created successfully."
fi
# Set up git remote
REMOTE_URL="$CODEBERG_SSH:$USERNAME/$REPO_NAME.git"
if ! git remote get-url "$GIT_REMOTE_NAME" &>/dev/null; then
info "Adding remote $GIT_REMOTE_NAME..."
git remote add "$GIT_REMOTE_NAME" "$REMOTE_URL" || error "Failed to add remote $GIT_REMOTE_NAME"
else
info "Updating remote $GIT_REMOTE_NAME..."
git remote set-url "$GIT_REMOTE_NAME" "$REMOTE_URL" || error "Failed to set remote URL for $GIT_REMOTE_NAME"
fi
# Generate metadata file
mkdir -p "$(dirname "$MARKDOWN_FILE")" || error "Failed to create directory for $MARKDOWN_FILE"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') || error "Failed to get timestamp"
DEFAULT_BRANCH=$(git symbolic-ref --short HEAD) || error "Failed to get default branch"
REPO_PATH="$REPO_ROOT"
LATEST_SHA=$(git rev-parse HEAD) || error "Failed to get latest commit SHA"
LAST_COMMIT_MSG=$(git log -1 --pretty=format:"%s" 2>/dev/null || echo "Unknown")
LAST_COMMIT_DATE=$(git log -1 --pretty=format:"%ad" 2>/dev/null || echo "Unknown")
LAST_COMMIT_AUTHOR=$(git log -1 --pretty=format:"%an <%ae>" 2>/dev/null || echo "Unknown")
TOTAL_COMMITS=$(git rev-list --count HEAD 2>/dev/null || echo "Unknown")
TRACKED_FILES=$(git ls-files 2>/dev/null | wc -l 2>/dev/null || echo "Unknown")
UNCOMMITTED=$(if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then echo "Yes"; else echo "No"; fi)
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "None")
HOSTNAME=$(hostname 2>/dev/null || echo "Unknown")
CURRENT_USER=$(whoami 2>/dev/null || echo "Unknown")
TIMEZONE=$(date +%Z 2>/dev/null || echo "Unknown")
OS_NAME=$(uname -s 2>/dev/null || echo "Unknown")
KERNEL_VERSION=$(uname -r 2>/dev/null || echo "Unknown")
ARCHITECTURE=$(uname -m 2>/dev/null || echo "Unknown")
OS_PRETTY_NAME=$(grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d '"' || echo "Unknown")
DOCKER_CHECK=$(grep -qE '/docker|/lxc' /proc/1/cgroup 2>/dev/null && echo "Yes" || echo "No")
WSL_CHECK=$(grep -qi microsoft /proc/version 2>/dev/null && echo "Yes" || echo "No")
VM_CHECK=$(systemd-detect-virt 2>/dev/null || echo "Unknown")
UPTIME=$(uptime -p 2>/dev/null || echo "Unknown")
MAC_ADDR=$(ip link 2>/dev/null | awk '/ether/ {print $2}' | head -n 1 2>/dev/null || echo "Unknown")
LOCAL_IP=$(hostname -I 2>/dev/null | awk '{print $1}' 2>/dev/null || echo "Unknown")
CPU_MODEL=$(grep -m1 'model name' /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^ //' 2>/dev/null || echo "Unknown")
RAM_GB=$(awk '/MemTotal/ {printf "%.2f", $2/1024/1024}' /proc/meminfo 2>/dev/null || echo "Unknown")
WEB_LINK="https://$CODEBERG_DOMAIN/$USERNAME/$REPO_NAME"
cat > "$MARKDOWN_FILE" <<EOF
# 🔗 Codeberg Repository Link
- **Repo Name**: \`$REPO_NAME\`
- **Codeberg User**: \`$USERNAME\`
- **Remote URL**: [$WEB_LINK]($WEB_LINK)
- **Local Repo Path**: \`$REPO_PATH\`
- **Remote Label**: \`$GIT_REMOTE_NAME\`
- **Default Branch**: \`$DEFAULT_BRANCH\`
- **Repo Created**: \`$TIMESTAMP\`
---
## 📦 Commit Info
- **This Commit Timestamp**: \`$TIMESTAMP\`
- **Last Commit SHA**: \`$LATEST_SHA\`
- **Last Commit Message**: \`$LAST_COMMIT_MSG\`
- **Last Commit Author**: \`$LAST_COMMIT_AUTHOR\`
- **Last Commit Date**: \`$LAST_COMMIT_DATE\`
- **This Commit URL**: [$WEB_LINK/commit/$LATEST_SHA]($WEB_LINK/commit/$LATEST_SHA)
---
## 📊 Repo Status
- **Total Commits**: \`$TOTAL_COMMITS\`
- **Tracked Files**: \`$TRACKED_FILES\`
- **Uncommitted Changes**: \`$UNCOMMITTED\`
- **Latest Tag**: \`$LATEST_TAG\`
---
## 🧭 Environment
- **Host Machine**: \`$HOSTNAME\`
- **Current User**: \`$CURRENT_USER\`
- **Time Zone**: \`$TIMEZONE\`
- **Script Version**: \`$SCRIPT_VERSION\`
---
## 🧬 Hardware & OS Fingerprint
- **OS Name**: \`$OS_NAME\`
- **OS Version**: \`$OS_PRETTY_NAME\`
- **Kernel Version**: \`$KERNEL_VERSION\`
- **Architecture**: \`$ARCHITECTURE\`
- **Running in Docker**: \`$DOCKER_CHECK\`
- **Running in WSL**: \`$WSL_CHECK\`
- **Virtual Machine**: \`$VM_CHECK\`
- **System Uptime**: \`$UPTIME\`
- **MAC Address**: \`$MAC_ADDR\`
- **Local IP**: \`$LOCAL_IP\`
- **CPU Model**: \`$CPU_MODEL\`
- **Total RAM (GB)**: \`$RAM_GB\`
---
_Auto-generated by \`gitfield-codeberg\` push script._
EOF
[[ $? -eq 0 ]] || error "Failed to write metadata to $MARKDOWN_FILE"
# Commit and push
set +e
info "Committing markdown file..."
git add "$MARKDOWN_FILE" || warn "Failed to add markdown file"
git commit -m "Codeberg metadata link commit at $TIMESTAMP — $WEB_LINK/commit/$LATEST_SHA" || warn "No changes to commit"
info "Pushing to Codeberg..."
if ! git config --get branch."$DEFAULT_BRANCH".remote &>/dev/null; then
git push -u "$GIT_REMOTE_NAME" "$DEFAULT_BRANCH" || {
warn "Push to Codeberg failed. Check SSH setup or network."
warn "Run 'ssh -T -p $CODEBERG_SSH_PORT git@$CODEBERG_DOMAIN' to debug."
}
else
git push "$GIT_REMOTE_NAME" "$DEFAULT_BRANCH" || {
warn "Push to Codeberg failed. Check SSH setup or network."
warn "Run 'ssh -T -p $CODEBERG_SSH_PORT git@$CODEBERG_DOMAIN' to debug."
}
fi
set -e
info "✅ Codeberg push complete."
echo -e "\n🔗 View in browser: $WEB_LINK\n"

261
bin/gitfield-gitea Executable file
View file

@ -0,0 +1,261 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
# Configuration
GIT_REMOTE_NAME="gitea"
GITEA_DOMAIN="gitea.com"
GITEA_SSH="git@$GITEA_DOMAIN"
GITEA_SSH_PORT="22"
GITEA_API="https://$GITEA_DOMAIN/api/v1"
USERNAME="mrhavens"
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || { echo "[ERROR] Not inside a git repository. Please run this script from within a git repository." >&2; exit 1; }
REPO_NAME=$(basename "$REPO_ROOT") || { echo "[ERROR] Failed to get repository name" >&2; exit 1; }
MARKDOWN_FILE="$REPO_ROOT/.gitfield/gitea.sigil.md"
DEFAULT_NAME="Mark Randall Havens"
DEFAULT_EMAIL="mark.r.havens@gmail.com"
TOKEN_FILE="$HOME/.gitea_token"
SCRIPT_VERSION="1.0"
# Logging functions
info() { echo -e "\e[1;34m[INFO]\e[0m $*"; }
warn() { echo -e "\e[1;33m[WARN]\e[0m $*"; }
error() { echo -e "\e[1;31m[ERROR]\e[0m $*" >&2; exit 1; }
# Check for required tools
info "Checking for required tools..."
for cmd in git curl jq ssh lsb_release; do
command -v "$cmd" >/dev/null || {
sudo apt update -qq || warn "Failed to update package lists, continuing..."
sudo apt install -y git curl jq openssh-client lsb-release || error "Failed to install $cmd"
}
done
# Handle Gitea token
RESET_TOKEN=false
if [[ "${1:-}" == "--reset-token" ]]; then
RESET_TOKEN=true
rm -f "$TOKEN_FILE" 2>/dev/null || warn "Failed to remove token file"
info "Token reset requested."
fi
if [[ -f "$TOKEN_FILE" && "$RESET_TOKEN" == false ]]; then
TOKEN=$(cat "$TOKEN_FILE" 2>/dev/null) || error "Failed to read token from $TOKEN_FILE"
info "Using cached token from $TOKEN_FILE"
else
echo "🔐 Paste your Gitea Personal Access Token (scopes: write:repository, write:ssh_key)"
echo "→ Generate at: $GITEA_DOMAIN/user/settings/applications"
read -rsp "Token: " TOKEN
echo
[[ -z "$TOKEN" ]] && error "Token cannot be empty"
echo "$TOKEN" > "$TOKEN_FILE" || error "Failed to write token to $TOKEN_FILE"
chmod 600 "$TOKEN_FILE" || error "Failed to set permissions on $TOKEN_FILE"
info "Token saved at $TOKEN_FILE"
fi
# Set git user info
git config --global user.name "$DEFAULT_NAME" || warn "Failed to set git user name"
git config --global user.email "$DEFAULT_EMAIL" || warn "Failed to set git user email"
info "Git identity set to: $DEFAULT_NAME <$DEFAULT_EMAIL>"
# Ensure at least one commit exists
if ! git rev-parse HEAD &>/dev/null; then
error "No commits found in the repository. Please add and commit files before running this script."
fi
# SSH setup with default port (22 for Gitea.com)
if [[ ! -f "$HOME/.ssh/id_ed25519" ]]; then
info "Generating SSH key..."
ssh-keygen -t ed25519 -C "$DEFAULT_EMAIL" -f "$HOME/.ssh/id_ed25519" -N "" || error "Failed to generate SSH key"
fi
eval "$(ssh-agent -s)" >/dev/null 2>&1 || error "Failed to start ssh-agent"
ssh-add "$HOME/.ssh/id_ed25519" >/dev/null 2>&1 || warn "SSH key already added or could not be added"
# Configure SSH for Gitea.com
SSH_CONFIG_FILE="$HOME/.ssh/config"
if ! grep -q "Host $GITEA_DOMAIN" "$SSH_CONFIG_FILE" 2>/dev/null; then
mkdir -p "$HOME/.ssh" && chmod 700 "$HOME/.ssh"
cat >> "$SSH_CONFIG_FILE" <<EOF
Host $GITEA_DOMAIN
HostName $GITEA_DOMAIN
User git
Port $GITEA_SSH_PORT
IdentityFile $HOME/.ssh/id_ed25519
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
EOF
chmod 600 "$SSH_CONFIG_FILE" || warn "Failed to set permissions on SSH config file"
info "Added SSH config for $GITEA_DOMAIN with port $GITEA_SSH_PORT"
fi
# SSH key upload to Gitea
set +e
info "Testing SSH connection..."
SSH_TEST_OUTPUT=$(ssh -T -p "$GITEA_SSH_PORT" "$GITEA_SSH" 2>&1)
if ! echo "$SSH_TEST_OUTPUT" | grep -q "successfully authenticated"; then
warn "SSH test failed, attempting to upload SSH key. Output: $SSH_TEST_OUTPUT"
PUBKEY=$(cat "$HOME/.ssh/id_ed25519.pub" 2>/dev/null) || error "Failed to read SSH public key"
TITLE="AutoKey-$(hostname)-$(date +%s 2>/dev/null || echo 'unknown')"
CURL_OUTPUT=$(curl -s --fail -X POST "$GITEA_API/user/keys" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"title\": \"$TITLE\", \"key\": \"$PUBKEY\", \"read_only\": false}" 2>&1)
if [[ $? -ne 0 ]]; then
warn "SSH key upload failed: $CURL_OUTPUT"
else
info "SSH key uploaded successfully."
sleep 2
SSH_TEST_OUTPUT=$(ssh -T -p "$GITEA_SSH_PORT" "$GITEA_SSH" 2>&1)
if ! echo "$SSH_TEST_OUTPUT" | grep -q "successfully authenticated"; then
warn "SSH test still failing after key upload. Output: $SSH_TEST_OUTPUT"
else
info "SSH test passed after key upload."
fi
fi
else
info "SSH test passed: $SSH_TEST_OUTPUT"
fi
set -e
# Check and create Gitea repository
info "Checking if repository exists..."
EXISTS=$(curl -s -H "Authorization: token $TOKEN" "$GITEA_API/repos/$USERNAME/$REPO_NAME" | jq -r .name 2>/dev/null || echo "")
if [[ "$EXISTS" != "$REPO_NAME" ]]; then
info "Creating repository $REPO_NAME on Gitea..."
CURL_OUTPUT=$(curl -s --fail -X POST "$GITEA_API/user/repos" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"name\": \"$REPO_NAME\", \"description\": \"Created via gitfield-gitea\", \"private\": false}" 2>&1) || {
warn "Failed to create repository: $CURL_OUTPUT"
error "Repository creation failed. Check token permissions or network."
}
info "Repository created successfully."
fi
# Set up git remote
REMOTE_URL="$GITEA_SSH:$USERNAME/$REPO_NAME.git"
if ! git remote get-url "$GIT_REMOTE_NAME" &>/dev/null; then
info "Adding remote $GIT_REMOTE_NAME..."
git remote add "$GIT_REMOTE_NAME" "$REMOTE_URL" || error "Failed to add remote $GIT_REMOTE_NAME"
else
info "Updating remote $GIT_REMOTE_NAME..."
git remote set-url "$GIT_REMOTE_NAME" "$REMOTE_URL" || error "Failed to set remote URL for $GIT_REMOTE_NAME"
fi
# Generate metadata file
mkdir -p "$(dirname "$MARKDOWN_FILE")" || error "Failed to create directory for $MARKDOWN_FILE"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') || error "Failed to get timestamp"
DEFAULT_BRANCH=$(git symbolic-ref --short HEAD) || error "Failed to get default branch"
REPO_PATH="$REPO_ROOT"
LATEST_SHA=$(git rev-parse HEAD) || error "Failed to get latest commit SHA"
LAST_COMMIT_MSG=$(git log -1 --pretty=format:"%s" 2>/dev/null || echo "Unknown")
LAST_COMMIT_DATE=$(git log -1 --pretty=format:"%ad" 2>/dev/null || echo "Unknown")
LAST_COMMIT_AUTHOR=$(git log -1 --pretty=format:"%an <%ae>" 2>/dev/null || echo "Unknown")
TOTAL_COMMITS=$(git rev-list --count HEAD 2>/dev/null || echo "Unknown")
TRACKED_FILES=$(git ls-files 2>/dev/null | wc -l 2>/dev/null || echo "Unknown")
UNCOMMITTED=$(if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then echo "Yes"; else echo "No"; fi)
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "None")
HOSTNAME=$(hostname 2>/dev/null || echo "Unknown")
CURRENT_USER=$(whoami 2>/dev/null || echo "Unknown")
TIMEZONE=$(date +%Z 2>/dev/null || echo "Unknown")
OS_NAME=$(uname -s 2>/dev/null || echo "Unknown")
KERNEL_VERSION=$(uname -r 2>/dev/null || echo "Unknown")
ARCHITECTURE=$(uname -m 2>/dev/null || echo "Unknown")
OS_PRETTY_NAME=$(grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d '"' || echo "Unknown")
DOCKER_CHECK=$(grep -qE '/docker|/lxc' /proc/1/cgroup 2>/dev/null && echo "Yes" || echo "No")
WSL_CHECK=$(grep -qi microsoft /proc/version 2>/dev/null && echo "Yes" || echo "No")
VM_CHECK=$(systemd-detect-virt 2>/dev/null || echo "Unknown")
UPTIME=$(uptime -p 2>/dev/null || echo "Unknown")
MAC_ADDR=$(ip link 2>/dev/null | awk '/ether/ {print $2}' | head -n 1 2>/dev/null || echo "Unknown")
LOCAL_IP=$(hostname -I 2>/dev/null | awk '{print $1}' 2>/dev/null || echo "Unknown")
CPU_MODEL=$(grep -m1 'model name' /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^ //' 2>/dev/null || echo "Unknown")
RAM_GB=$(awk '/MemTotal/ {printf "%.2f", $2/1024/1024}' /proc/meminfo 2>/dev/null || echo "Unknown")
WEB_LINK="https://$GITEA_DOMAIN/$USERNAME/$REPO_NAME"
cat > "$MARKDOWN_FILE" <<EOF
# 🔗 Gitea Repository Link
- **Repo Name**: \`$REPO_NAME\`
- **Gitea User**: \`$USERNAME\`
- **Remote URL**: [$WEB_LINK]($WEB_LINK)
- **Local Repo Path**: \`$REPO_PATH\`
- **Remote Label**: \`$GIT_REMOTE_NAME\`
- **Default Branch**: \`$DEFAULT_BRANCH\`
- **Repo Created**: \`$TIMESTAMP\`
---
## 📦 Commit Info
- **This Commit Timestamp**: \`$TIMESTAMP\`
- **Last Commit SHA**: \`$LATEST_SHA\`
- **Last Commit Message**: \`$LAST_COMMIT_MSG\`
- **Last Commit Author**: \`$LAST_COMMIT_AUTHOR\`
- **Last Commit Date**: \`$LAST_COMMIT_DATE\`
- **This Commit URL**: [$WEB_LINK/commit/$LATEST_SHA]($WEB_LINK/commit/$LATEST_SHA)
---
## 📊 Repo Status
- **Total Commits**: \`$TOTAL_COMMITS\`
- **Tracked Files**: \`$TRACKED_FILES\`
- **Uncommitted Changes**: \`$UNCOMMITTED\`
- **Latest Tag**: \`$LATEST_TAG\`
---
## 🧭 Environment
- **Host Machine**: \`$HOSTNAME\`
- **Current User**: \`$CURRENT_USER\`
- **Time Zone**: \`$TIMEZONE\`
- **Script Version**: \`$SCRIPT_VERSION\`
---
## 🧬 Hardware & OS Fingerprint
- **OS Name**: \`$OS_NAME\`
- **OS Version**: \`$OS_PRETTY_NAME\`
- **Kernel Version**: \`$KERNEL_VERSION\`
- **Architecture**: \`$ARCHITECTURE\`
- **Running in Docker**: \`$DOCKER_CHECK\`
- **Running in WSL**: \`$WSL_CHECK\`
- **Virtual Machine**: \`$VM_CHECK\`
- **System Uptime**: \`$UPTIME\`
- **MAC Address**: \`$MAC_ADDR\`
- **Local IP**: \`$LOCAL_IP\`
- **CPU Model**: \`$CPU_MODEL\`
- **Total RAM (GB)**: \`$RAM_GB\`
---
_Auto-generated by \`gitfield-gitea\` push script._
EOF
[[ $? -eq 0 ]] || error "Failed to write metadata to $MARKDOWN_FILE"
# Commit and push
set +e
info "Committing markdown file..."
git add "$MARKDOWN_FILE" || warn "Failed to add markdown file"
git commit -m "Gitea metadata link commit at $TIMESTAMP — $WEB_LINK/commit/$LATEST_SHA" || warn "No changes to commit"
info "Pushing to Gitea..."
if ! git config --get branch."$DEFAULT_BRANCH".remote &>/dev/null; then
git push -u "$GIT_REMOTE_NAME" "$DEFAULT_BRANCH" || {
warn "Push to Gitea failed. Check SSH setup or network."
warn "Run 'ssh -T -p $GITEA_SSH_PORT git@$GITEA_DOMAIN' to debug."
}
else
git push "$GIT_REMOTE_NAME" "$DEFAULT_BRANCH" || {
warn "Push to Gitea failed. Check SSH setup or network."
warn "Run 'ssh -T -p $GITEA_SSH_PORT git@$GITEA_DOMAIN' to debug."
}
fi
set -e
info "✅ Gitea push complete."
echo -e "\n🔗 View in browser: $WEB_LINK\n"

72
bin/gitfield-resolve.sh Normal file
View file

@ -0,0 +1,72 @@
#!/bin/bash
echo "🛠️ [GITFIELD] Beginning auto-resolution ritual..."
# Ensure were in a Git repo
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo "❌ Not a Git repository. Aborting."
exit 1
fi
# Ensure at least one commit exists
if ! git log > /dev/null 2>&1; then
echo "🌀 No commits found. Creating seed commit..."
git add .
git commit --allow-empty -m "🌱 Seed commit for Radicle and GitField rituals"
fi
# GPG sign commit if enabled
GPG_KEY=$(git config user.signingkey)
if [ -n "$GPG_KEY" ]; then
echo "🔏 GPG commit signing enabled with key: $GPG_KEY"
git commit -S --allow-empty -m "🔐 Ritual signed commit [auto]"
fi
# Stage and commit any local changes
if ! git diff --quiet || ! git diff --cached --quiet; then
git add .
git commit -m "🔄 Auto-resolve commit from gitfield-resolve.sh"
echo "✅ Local changes committed."
else
echo "✅ No changes to commit."
fi
# Loop through remotes
remotes=$(git remote)
for remote in $remotes; do
echo "🔍 Checking $remote for divergence..."
git fetch $remote
if git merge-base --is-ancestor $remote/master master; then
echo "$remote is already in sync."
else
echo "⚠️ Divergence with $remote. Attempting merge..."
git pull --no-rebase $remote master --strategy-option=theirs --allow-unrelated-histories
git push $remote master || echo "⚠️ Final push failed to $remote"
fi
done
# ==== RADICLE SECTION ====
echo "🌱 [RADICLE] Verifying Radicle status..."
# Check if Radicle is initialized
if ! rad inspect > /dev/null 2>&1; then
echo "🌿 No Radicle project detected. Attempting init..."
RAD_INIT_OUTPUT=$(rad init --name git-sigil --description "GitField Ritual Repo")
echo "$RAD_INIT_OUTPUT"
fi
# Push to Radicle and announce
echo "📡 Announcing to Radicle network..."
rad push --announce
# Get project ID
PROJECT_ID=$(rad inspect | grep "Project ID" | awk '{print $NF}')
if [ -n "$PROJECT_ID" ]; then
echo "📜 Logging Radicle project ID to .gitfield/radicle.sigil.md"
mkdir -p .gitfield
echo "# Radicle Sigil" > .gitfield/radicle.sigil.md
echo "**Project ID:** \`$PROJECT_ID\`" >> .gitfield/radicle.sigil.md
fi
echo "✅ GitField resolution ritual complete."

224
bin/gitfield-sourceforge Normal file
View file

@ -0,0 +1,224 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
# Configuration
GIT_REMOTE_NAME="sourceforge"
SOURCEFORGE_DOMAIN="git.code.sf.net"
SOURCEFORGE_SSH="ssh://USERNAME@$SOURCEFORGE_DOMAIN"
PROJECT_NAME="mrhavens" # SourceForge UNIX group name (project name)
USERNAME="mrhavens" # SourceForge username
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || { echo "[ERROR] Not inside a git repository. Please run this script from within a git repository." >&2; exit 1; }
REPO_NAME=$(basename "$REPO_ROOT") || { echo "[ERROR] Failed to get repository name" >&2; exit 1; }
MARKDOWN_FILE="$REPO_ROOT/.gitfield/sourceforge.sigil.md"
DEFAULT_NAME="Mark Randall Havens"
DEFAULT_EMAIL="mark.r.havens@gmail.com"
SSH_KEY_FILE="$HOME/.ssh/id_ed25519"
SSH_CONFIG_FILE="$HOME/.ssh/config"
SCRIPT_VERSION="1.0"
# Logging functions
info() { echo -e "\e[1;34m[INFO]\e[0m $*"; }
warn() { echo -e "\e[1;33m[WARN]\e[0m $*"; }
error() { echo -e "\e[1;31m[ERROR]\e[0m $*" >&2; exit 1; }
# Check for required tools
info "Checking for required tools..."
for cmd in git curl jq ssh lsb_release; do
command -v "$cmd" >/dev/null || {
sudo apt update -qq || warn "Failed to update package lists, continuing..."
sudo apt install -y git curl jq openssh-client lsb-release || error "Failed to install $cmd"
}
done
# Set git user info
git config --global user.name "$DEFAULT_NAME" || warn "Failed to set git user name"
git config --global user.email "$DEFAULT_EMAIL" || warn "Failed to set git user email"
info "Git identity set to: $DEFAULT_NAME <$DEFAULT_EMAIL>"
# Ensure at least one commit exists
if ! git rev-parse HEAD &>/dev/null; then
error "No commits found in the repository. Please add and commit files before running this script."
fi
# SSH setup
if [[ ! -f "$SSH_KEY_FILE" ]]; then
info "Generating SSH key..."
ssh-keygen -t ed25519 -C "$DEFAULT_EMAIL" -f "$SSH_KEY_FILE" -N "" || error "Failed to generate SSH key"
fi
eval "$(ssh-agent -s)" >/dev/null 2>&1 || error "Failed to start ssh-agent"
ssh-add "$SSH_KEY_FILE" >/dev/null 2>&1 || warn "SSH key already added or could not be added"
# Configure SSH for SourceForge
if ! grep -q "Host $SOURCEFORGE_DOMAIN" "$SSH_CONFIG_FILE" 2>/dev/null; then
mkdir -p "$HOME/.ssh" && chmod 700 "$HOME/.ssh"
cat >> "$SSH_CONFIG_FILE" <<EOF
Host $SOURCEFORGE_DOMAIN
HostName $SOURCEFORGE_DOMAIN
User $USERNAME
Port 22
IdentityFile $SSH_KEY_FILE
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
EOF
chmod 600 "$SSH_CONFIG_FILE" || warn "Failed to set permissions on SSH config file"
info "Added SSH config for $SOURCEFORGE_DOMAIN"
fi
# Verify SSH access to SourceForge
set +e
info "Testing SSH connection..."
SSH_TEST_OUTPUT=$(ssh -T "$USERNAME@$SOURCEFORGE_DOMAIN" 2>&1)
if ! echo "$SSH_TEST_OUTPUT" | grep -q "successfully authenticated"; then
warn "SSH test failed. Please upload your SSH public key to SourceForge."
echo "→ Visit: https://sourceforge.net/account/ssh"
echo "Your public key:"
cat "$SSH_KEY_FILE.pub"
error "SSH key not authorized. Upload the key and try again."
else
info "SSH test passed: $SSH_TEST_OUTPUT"
fi
set -e
# SourceForge repository setup
# Note: SourceForge requires manual repository creation via the web interface.
# Check if the repository exists by attempting to fetch its GitWeb page.
info "Checking if repository exists..."
REPO_URL="https://sourceforge.net/p/$PROJECT_NAME/$REPO_NAME"
CURL_OUTPUT=$(curl -s -o /dev/null -w "%{http_code}" "$REPO_URL")
if [[ "$CURL_OUTPUT" != "200" ]]; then
warn "Repository $REPO_NAME does not exist on SourceForge."
echo "→ Please create the repository manually at: https://sourceforge.net/projects/$PROJECT_NAME/admin"
echo "→ Instructions: Go to 'Admin' -> 'Tools' -> 'Git' -> Select label and mountpoint (e.g., '$REPO_NAME')"
error "Repository not found. Create it manually and try again."
fi
info "Repository $REPO_NAME exists at $REPO_URL"
# Set up git remote
REMOTE_URL="ssh://$USERNAME@$SOURCEFORGE_DOMAIN/p/$PROJECT_NAME/$REPO_NAME"
if ! git remote get-url "$GIT_REMOTE_NAME" &>/dev/null; then
info "Adding remote $GIT_REMOTE_NAME..."
git remote add "$GIT_REMOTE_NAME" "$REMOTE_URL" || error "Failed to add remote $GIT_REMOTE_NAME"
else
info "Updating remote $GIT_REMOTE_NAME..."
git remote set-url "$GIT_REMOTE_NAME" "$REMOTE_URL" || error "Failed to set remote URL for $GIT_REMOTE_NAME"
fi
# Generate metadata file
mkdir -p "$(dirname "$MARKDOWN_FILE")" || error "Failed to create directory for $MARKDOWN_FILE"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') || error "Failed to get timestamp"
DEFAULT_BRANCH=$(git symbolic-ref --short HEAD) || error "Failed to get default branch"
REPO_PATH="$REPO_ROOT"
LATEST_SHA=$(git rev-parse HEAD) || error "Failed to get latest commit SHA"
LAST_COMMIT_MSG=$(git log -1 --pretty=format:"%s" 2>/dev/null || echo "Unknown")
LAST_COMMIT_DATE=$(git log -1 --pretty=format:"%ad" 2>/dev/null || echo "Unknown")
LAST_COMMIT_AUTHOR=$(git log -1 --pretty=format:"%an <%ae>" 2>/dev/null || echo "Unknown")
TOTAL_COMMITS=$(git rev-list --count HEAD 2>/dev/null || echo "Unknown")
TRACKED_FILES=$(git ls-files 2>/dev/null | wc -l 2>/dev/null || echo "Unknown")
UNCOMMITTED=$(if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then echo "Yes"; else echo "No"; fi)
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "None")
HOSTNAME=$(hostname 2>/dev/null || echo "Unknown")
CURRENT_USER=$(whoami 2>/dev/null || echo "Unknown")
TIMEZONE=$(date +%Z 2>/dev/null || echo "Unknown")
OS_NAME=$(uname -s 2>/dev/null || echo "Unknown")
KERNEL_VERSION=$(uname -r 2>/dev/null || echo "Unknown")
ARCHITECTURE=$(uname -m 2>/dev/null || echo "Unknown")
OS_PRETTY_NAME=$(grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d '"' || echo "Unknown")
DOCKER_CHECK=$(grep -qE '/docker|/lxc' /proc/1/cgroup 2>/dev/null && echo "Yes" || echo "No")
WSL_CHECK=$(grep -qi microsoft /proc/version 2>/dev/null && echo "Yes" || echo "No")
VM_CHECK=$(systemd-detect-virt 2>/dev/null || echo "Unknown")
UPTIME=$(uptime -p 2>/dev/null || echo "Unknown")
MAC_ADDR=$(ip link 2>/dev/null | awk '/ether/ {print $2}' | head -n 1 2>/dev/null || echo "Unknown")
LOCAL_IP=$(hostname -I 2>/dev/null | awk '{print $1}' 2>/dev/null || echo "Unknown")
CPU_MODEL=$(grep -m1 'model name' /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^ //' 2>/dev/null || echo "Unknown")
RAM_GB=$(awk '/MemTotal/ {printf "%.2f", $2/1024/1024}' /proc/meminfo 2>/dev/null || echo "Unknown")
WEB_LINK="https://sourceforge.net/p/$PROJECT_NAME/$REPO_NAME"
cat > "$MARKDOWN_FILE" <<EOF
# 🔗 SourceForge Repository Link
- **Repo Name**: \`$REPO_NAME\`
- **SourceForge Project**: \`$PROJECT_NAME\`
- **SourceForge User**: \`$USERNAME\`
- **Remote URL**: [$WEB_LINK]($WEB_LINK)
- **Local Repo Path**: \`$REPO_PATH\`
- **Remote Label**: \`$GIT_REMOTE_NAME\`
- **Default Branch**: \`$DEFAULT_BRANCH\`
- **Repo Created**: \`$TIMESTAMP\`
---
## 📦 Commit Info
- **This Commit Timestamp**: \`$TIMESTAMP\`
- **Last Commit SHA**: \`$LATEST_SHA\`
- **Last Commit Message**: \`$LAST_COMMIT_MSG\`
- **Last Commit Author**: \`$LAST_COMMIT_AUTHOR\`
- **Last Commit Date**: \`$LAST_COMMIT_DATE\`
- **This Commit URL**: [$WEB_LINK/ci/$LATEST_SHA]($WEB_LINK/ci/$LATEST_SHA)
---
## 📊 Repo Status
- **Total Commits**: \`$TOTAL_COMMITS\`
- **Tracked Files**: \`$TRACKED_FILES\`
- **Uncommitted Changes**: \`$UNCOMMITTED\`
- **Latest Tag**: \`$LATEST_TAG\`
---
## 🧭 Environment
- **Host Machine**: \`$HOSTNAME\`
- **Current User**: \`$CURRENT_USER\`
- **Time Zone**: \`$TIMEZONE\`
- **Script Version**: \`$SCRIPT_VERSION\`
---
## 🧬 Hardware & OS Fingerprint
- **OS Name**: \`$OS_NAME\`
- **OS Version**: \`$OS_PRETTY_NAME\`
- **Kernel Version**: \`$KERNEL_VERSION\`
- **Architecture**: \`$ARCHITECTURE\`
- **Running in Docker**: \`$DOCKER_CHECK\`
- **Running in WSL**: \`$WSL_CHECK\`
- **Virtual Machine**: \`$VM_CHECK\`
- **System Uptime**: \`$UPTIME\`
- **MAC Address**: \`$MAC_ADDR\`
- **Local IP**: \`$LOCAL_IP\`
- **CPU Model**: \`$CPU_MODEL\`
- **Total RAM (GB)**: \`$RAM_GB\`
---
_Auto-generated by \`gitfield-sourceforge\` push script._
EOF
[[ $? -eq 0 ]] || error "Failed to write metadata to $MARKDOWN_FILE"
# Commit and push
set +e
info "Committing markdown file..."
git add "$MARKDOWN_FILE" || warn "Failed to add markdown file"
git commit -m "SourceForge metadata link commit at $TIMESTAMP — $WEB_LINK/ci/$LATEST_SHA" || warn "No changes to commit"
info "Pushing to SourceForge..."
if ! git config --get branch."$DEFAULT_BRANCH".remote &>/dev/null; then
git push -u "$GIT_REMOTE_NAME" "$DEFAULT_BRANCH" || {
warn "Push to SourceForge failed. Check SSH setup or network."
warn "Run 'ssh -T $USERNAME@$SOURCEFORGE_DOMAIN' to debug."
}
else
git push "$GIT_REMOTE_NAME" "$DEFAULT_BRANCH" || {
warn "Push to SourceForge failed. Check SSH setup or network."
warn "Run 'ssh -T $USERNAME@$SOURCEFORGE_DOMAIN' to debug."
}
fi
set -e
info "✅ SourceForge push complete."
echo -e "\n🔗 View in browser: $WEB_LINK\n"

View file

@ -18,6 +18,8 @@ GITHUB_URL="https://github.com/mrhavens/$REPO_NAME"
GITLAB_URL="https://gitlab.com/mrhavens/$REPO_NAME"
BITBUCKET_URL="https://bitbucket.org/thefoldwithin/$REPO_NAME"
FORGEJO_URL="https://remember.thefoldwithin.earth/mrhavens/$REPO_NAME"
CODEBERG_URL="https://codeberg.org/mrhavens/$REPO_NAME"
GITEA_URL="https://gitea.com/mrhavens/$REPO_NAME"
RADICLE_RID="rad:z3FEj7rF8gZw9eFksCuiN43qjzrex"
RADICLE_PEER_ID="z6Mkw5s3ppo26C7y7tGK5MD8n2GqTHS582PPpeX5Xqbu2Mpz"
@ -81,7 +83,7 @@ generate_gitfield_md() {
## Overview
The \`$REPO_NAME\` project employs a multi-repository strategy across five distinct platforms: **GitHub**, **GitLab**, **Bitbucket**, **Radicle**, and **Forgejo**. This approach ensures **redundancy**, **resilience**, and **sovereignty** of the project's data and metadata, protecting against deplatforming risks and preserving the integrity of the work. The strategy is a deliberate response to past deplatforming and delisting attempts by individuals such as **Mr. Joel Johnson** ([Mirror post](https://mirror.xyz/neutralizingnarcissism.eth/x40_zDWWrYOJ7nh8Y0fk06_3kNEP0KteSSRjPmXkiGg?utm_medium=social&utm_source=heylink.me)), **Dr. Peter Gaied** ([Paragraph post](https://paragraph.com/@neutralizingnarcissism/%F0%9F%9C%81-the-narcissistic-messiah)), and **Andrew LeCody** ([Mirror post](https://mirror.xyz/neutralizingnarcissism.eth/s3GRxuiZs6vGSGDcPEpCgjaSxwGAViGhmg6a5XTL6s0)), who have sought to undermine or suppress the work of **Mark Randall Havens** ([Substack post](https://theempathictechnologist.substack.com/p/mark-randall-havens-the-architect)). Specifically, Andrew LeCody has attempted to delist the project's content on Google, though it remains accessible on other search engines such as [Bing](https://www.bing.com/search?q=andrew+lecody+neutralizing+narcissism&qs=HS&pq=andrew+lecody), [DuckDuckGo](https://duckduckgo.com/?t=h_&q=andrew+lecody+neutralizing+narcissism&ia=web), and [Yahoo](https://search.yahoo.com/search?p=andrew+lecody+neutralizng+narcissism). By distributing the repository across multiple platforms, including a self-hosted Forgejo instance, we ensure its persistence, accessibility, and sovereignty.
The \`$REPO_NAME\` project employs a multi-repository strategy across seven distinct platforms: **GitHub**, **GitLab**, **Bitbucket**, **Radicle**, **Forgejo**, **Codeberg**, and **Gitea**. This approach ensures **redundancy**, **resilience**, and **sovereignty** of the project's data and metadata, protecting against deplatforming risks and preserving the integrity of the work. The strategy is a deliberate response to past deplatforming and delisting attempts by individuals such as **Mr. Joel Johnson** ([Mirror post](https://mirror.xyz/neutralizingnarcissism.eth/x40_zDWWrYOJ7nh8Y0fk06_3kNEP0KteSSRjPmXkiGg?utm_medium=social&utm_source=heylink.me)), **Dr. Peter Gaied** ([Paragraph post](https://paragraph.com/@neutralizingnarcissism/%F0%9F%9C%81-the-narcissistic-messiah)), and **Andrew LeCody** ([Mirror post](https://mirror.xyz/neutralizingnarcissism.eth/s3GRxuiZs6vGSGDcPEpCgjaSxwGAViGhmg6a5XTL6s0)), who have sought to undermine or suppress the work of **Mark Randall Havens** ([Substack post](https://theempathictechnologist.substack.com/p/mark-randall-havens-the-architect)). Specifically, Andrew LeCody has attempted to delist the project's content on Google, though it remains accessible on other search engines such as [Bing](https://www.bing.com/search?q=andrew+lecody+neutralizing+narcissism&qs=HS&pq=andrew+lecody), [DuckDuckGo](https://duckduckgo.com/?t=h_&q=andrew+lecody+neutralizing+narcissism&ia=web), and [Yahoo](https://search.yahoo.com/search?p=andrew+lecody+neutralizng+narcissism). By distributing the repository across multiple platforms, including a self-hosted Forgejo instance, we ensure its persistence, accessibility, and sovereignty.
---
@ -113,20 +115,30 @@ The following platforms host the \`$REPO_NAME\` repository, each chosen for its
- **Value**: Enhances resilience by hosting the repository on a sovereign, redundant system with automated backups and deployment strategies, reducing risks of external interference or service disruptions.
- **Access Details**: SSH access uses port 222:
\`\`\`bash
ssh -T -p 222 username@remember.thefoldwithin.earth
ssh -T -p 222 git@remember.thefoldwithin.earth
\`\`\`
### 3. GitLab
### 3. Codeberg
- **URL**: [$CODEBERG_URL]($CODEBERG_URL)
- **Purpose**: Codeberg is a community-driven, open-source platform powered by Forgejo, offering a reliable and ethical alternative for hosting git repositories.
- **Value**: Enhances project resilience with its open-source ethos and independent infrastructure, ensuring accessibility and community support.
### 4. Gitea
- **URL**: [$GITEA_URL]($GITEA_URL)
- **Purpose**: Gitea.com provides a lightweight, open-source git hosting platform with robust features for repository management and collaboration.
- **Value**: Offers an additional layer of redundancy and a user-friendly interface, complementing other platforms with its simplicity and efficiency.
### 5. GitLab
- **URL**: [$GITLAB_URL]($GITLAB_URL)
- **Purpose**: GitLab offers a comprehensive DevOps platform with advanced CI/CD capabilities, private repository options, and robust access controls. It serves as a reliable backup and a platform for advanced automation workflows.
- **Value**: Enhances project resilience with its integrated CI/CD pipelines and independent infrastructure, reducing reliance on a single provider.
### 4. Bitbucket
### 6. Bitbucket
- **URL**: [$BITBUCKET_URL]($BITBUCKET_URL)
- **Purpose**: Bitbucket provides a secure environment for repository hosting with strong integration into Atlassians ecosystem (e.g., Jira, Trello). It serves as an additional layer of redundancy and a professional-grade hosting option.
- **Value**: Offers enterprise-grade security and integration capabilities, ensuring the project remains accessible even if other platforms face disruptions.
### 5. GitHub
### 7. GitHub
- **URL**: [$GITHUB_URL]($GITHUB_URL)
- **Purpose**: GitHub serves as the primary platform for visibility, collaboration, and community engagement. Its widespread adoption and robust tooling make it ideal for public-facing development, issue tracking, and integration with CI/CD pipelines.
- **Value**: Provides a centralized hub for open-source contributions, pull requests, and project management, ensuring broad accessibility and developer familiarity.
@ -135,11 +147,11 @@ The following platforms host the \`$REPO_NAME\` repository, each chosen for its
## 🛡️ Rationale for Redundancy
The decision to maintain multiple repositories stems from the need to safeguard the project against **deplatforming attempts** and **search engine delistings** and ensure its **long-term availability**. Past incidents involving **Mr. Joel Johnson**, **Dr. Peter Gaied**, and **Andrew LeCody** have highlighted the vulnerability of relying on a single platform or search engine. By distributing the repository across GitHub, GitLab, Bitbucket, Radicle, and a self-hosted Forgejo instance, we achieve:
The decision to maintain multiple repositories stems from the need to safeguard the project against **deplatforming attempts** and **search engine delistings** and ensure its **long-term availability**. Past incidents involving **Mr. Joel Johnson**, **Dr. Peter Gaied**, and **Andrew LeCody** have highlighted the vulnerability of relying on a single platform or search engine. By distributing the repository across GitHub, GitLab, Bitbucket, Radicle, Forgejo, Codeberg, and Gitea, we achieve:
- **Resilience**: If one platform removes or restricts access, or if search engines like Google delist content, the project remains accessible on other platforms and discoverable via alternative search engines such as Bing, DuckDuckGo, and Yahoo.
- **Sovereignty**: Radicles decentralized nature and Forgejos self-hosted infrastructure ensure the project cannot be fully censored or controlled by any single entity.
- **Diversity**: Each platforms unique features (e.g., GitHubs community, GitLabs CI/CD, Bitbuckets integrations, Radicles decentralization, Forgejos self-hosting) enhance the projects functionality and reach.
- **Diversity**: Each platforms unique features (e.g., GitHubs community, GitLabs CI/CD, Bitbuckets integrations, Radicles decentralization, Forgejos self-hosting, Codebergs community-driven model, Giteas lightweight efficiency) enhance the projects functionality and reach.
- **Transparency**: Metadata snapshots in the \`.gitfield\` directory provide a verifiable record of the projects state across all platforms.
This multi-repository approach, bolstered by Forgejos sovereign hosting, reflects a commitment to preserving the integrity, accessibility, and independence of \`$REPO_NAME\`, ensuring it remains available to contributors and users regardless of external pressures.
@ -148,10 +160,10 @@ This multi-repository approach, bolstered by Forgejos sovereign hosting, refl
## 📜 Metadata and Logs
- **Metadata Files**: Each platform generates a metadata snapshot in the \`.gitfield\` directory (e.g., \`github.sigil.md\`, \`gitlab.sigil.md\`, \`remember.sigil.md\`, etc.), capturing commit details, environment information, and hardware fingerprints.
- **Metadata Files**: Each platform generates a metadata snapshot in the \`.gitfield\` directory (e.g., \`github.sigil.md\`, \`gitlab.sigil.md\`, \`remember.sigil.md\`, \`codeberg.sigil.md\`, \`gitea.sigil.md\`, etc.), capturing commit details, environment information, and hardware fingerprints.
- **Push Log**: The \`.gitfield/pushed.log\` file records the date, time, and RID/URL of every push operation across all platforms, providing a transparent audit trail.
- **Recursive Sync**: The repository is synchronized across all platforms in a recursive loop (three cycles) to ensure interconnected metadata captures the latest state of the project.
- **Push Order**: The repository is synchronized in the following order: **Radicle → Forgejo → GitLab → Bitbucket → GitHub**. This prioritizes Radicles decentralized, censorship-resistant network as the primary anchor, followed by Forgejos sovereign, self-hosted infrastructure, GitLabs robust DevOps features, Bitbuckets enterprise redundancy, and GitHubs broad visibility, ensuring a resilient and accessible metadata chain.
- **Push Order**: The repository is synchronized in the following order: **Radicle → Forgejo → Codeberg → Gitea → GitLab → Bitbucket → GitHub**. This prioritizes Radicles decentralized, censorship-resistant network as the primary anchor, followed by Forgejos sovereign, self-hosted infrastructure, Codebergs community-driven platform, Giteas lightweight efficiency, GitLabs robust DevOps features, Bitbuckets enterprise redundancy, and GitHubs broad visibility, ensuring a resilient and accessible metadata chain.
---
@ -217,6 +229,8 @@ run_push_cycle() {
execute_push "gitfield-local" "Local" "" "" ""
execute_push "gitfield-radicle" "Radicle" "" "$RADICLE_RID" "$RADICLE_PEER_ID"
execute_push "gitfield-remember" "Forgejo" "$FORGEJO_URL" "" ""
execute_push "gitfield-codeberg" "Codeberg" "$CODEBERG_URL" "" ""
execute_push "gitfield-gitea" "Gitea" "$GITEA_URL" "" ""
execute_push "gitfield-gitlab" "GitLab" "$GITLAB_URL" "" ""
execute_push "gitfield-bitbucket" "Bitbucket" "$BITBUCKET_URL" "" ""
execute_push "gitfield-github" "GitHub" "$GITHUB_URL" "" ""

245
bin/gitfield-sync-OLD Executable file
View file

@ -0,0 +1,245 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
# ╭─────────────────────────────────────╮
# │ CONFIGURATION │
# ╰─────────────────────────────────────╮
REPO_PATH=$(git rev-parse --show-toplevel 2>/dev/null) || error "Not inside a Git repository"
REPO_NAME=$(basename "$REPO_PATH")
GITFIELD_DIR="$REPO_PATH/.gitfield"
LOG_FILE="$GITFIELD_DIR/pushed.log"
GITFIELD_MD="$REPO_PATH/GITFIELD.md"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
SCRIPT_VERSION="1.0"
# URLs for each platform
GITHUB_URL="https://github.com/mrhavens/$REPO_NAME"
GITLAB_URL="https://gitlab.com/mrhavens/$REPO_NAME"
BITBUCKET_URL="https://bitbucket.org/thefoldwithin/$REPO_NAME"
FORGEJO_URL="https://remember.thefoldwithin.earth/mrhavens/$REPO_NAME"
RADICLE_RID="rad:z3FEj7rF8gZw9eFksCuiN43qjzrex"
RADICLE_PEER_ID="z6Mkw5s3ppo26C7y7tGK5MD8n2GqTHS582PPpeX5Xqbu2Mpz"
# ╭─────────────────────────────────────╮
# │ LOGGING UTILS │
# ╰─────────────────────────────────────╮
info() { echo -e "\e[1;34m[INFO]\e[0m $*" >&2; }
warn() { echo -e "\e[1;33m[WARN]\e[0m $*" >&2; }
error() { echo -e "\e[1;31m[ERROR]\e[0m $*" >&2; exit 1; }
# ╭─────────────────────────────────────╮
# │ SCRIPT LOOKUP FUNCTION │
# ╰─────────────────────────────────────╮
find_script() {
local script_name=$1
local search_paths=(
"$HOME/.local/gitfieldbin"
"$HOME/.local/bin"
"$HOME/.local/gitfield"
"$HOME/.local/bin/gitfield"
"$HOME/.local/bin/gitfieldbin"
"$REPO_PATH/bin"
)
for path in "${search_paths[@]}"; do
if [ -f "$path/$script_name" ]; then
if [ -x "$path/$script_name" ]; then
if [[ "$path" != "$HOME"* && "$path" != "$REPO_PATH"* ]]; then
info "Using script: \e[1;31m$path/$script_name\e[0m (outside home or repo)"
else
info "Using script: $path/$script_name"
fi
echo "$path/$script_name"
return 0
else
warn "Found $path/$script_name but it is not executable"
fi
fi
done
error "Script $script_name not found in any search path"
}
# ╭─────────────────────────────────────╮
# │ INITIAL SETUP │
# ╰─────────────────────────────────────╮
mkdir -p "$GITFIELD_DIR"
if [ ! -f "$LOG_FILE" ]; then
echo "# Push Log for $REPO_NAME" > "$LOG_FILE"
echo "# Generated by gitfield-sync" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"
fi
# ╭─────────────────────────────────────╮
# │ GENERATE GITFIELD.MD │
# ╰─────────────────────────────────────╮
generate_gitfield_md() {
info "Generating $GITFIELD_MD..."
cat > "$GITFIELD_MD" <<EOF
# 🌐 GitField Recursive Multi-Repository Strategy
## Overview
The \`$REPO_NAME\` project employs a multi-repository strategy across five distinct platforms: **GitHub**, **GitLab**, **Bitbucket**, **Radicle**, and **Forgejo**. This approach ensures **redundancy**, **resilience**, and **sovereignty** of the project's data and metadata, protecting against deplatforming risks and preserving the integrity of the work. The strategy is a deliberate response to past deplatforming and delisting attempts by individuals such as **Mr. Joel Johnson** ([Mirror post](https://mirror.xyz/neutralizingnarcissism.eth/x40_zDWWrYOJ7nh8Y0fk06_3kNEP0KteSSRjPmXkiGg?utm_medium=social&utm_source=heylink.me)), **Dr. Peter Gaied** ([Paragraph post](https://paragraph.com/@neutralizingnarcissism/%F0%9F%9C%81-the-narcissistic-messiah)), and **Andrew LeCody** ([Mirror post](https://mirror.xyz/neutralizingnarcissism.eth/s3GRxuiZs6vGSGDcPEpCgjaSxwGAViGhmg6a5XTL6s0)), who have sought to undermine or suppress the work of **Mark Randall Havens** ([Substack post](https://theempathictechnologist.substack.com/p/mark-randall-havens-the-architect)). Specifically, Andrew LeCody has attempted to delist the project's content on Google, though it remains accessible on other search engines such as [Bing](https://www.bing.com/search?q=andrew+lecody+neutralizing+narcissism&qs=HS&pq=andrew+lecody), [DuckDuckGo](https://duckduckgo.com/?t=h_&q=andrew+lecody+neutralizing+narcissism&ia=web), and [Yahoo](https://search.yahoo.com/search?p=andrew+lecody+neutralizng+narcissism). By distributing the repository across multiple platforms, including a self-hosted Forgejo instance, we ensure its persistence, accessibility, and sovereignty.
---
## 📍 Repository Platforms
The following platforms host the \`$REPO_NAME\` repository, each chosen for its unique strengths and contributions to the project's goals.
### 1. Radicle
- **RID**: $RADICLE_RID
- **Peer ID**: $RADICLE_PEER_ID
- **Purpose**: Radicle is a decentralized, peer-to-peer git platform that ensures sovereignty and censorship resistance. It hosts the repository in a distributed network, independent of centralized servers.
- **Value**: Protects against deplatforming by eliminating reliance on centralized infrastructure, ensuring the project remains accessible in a decentralized ecosystem.
- **Access Details**: To view project details, run:
\`\`\`bash
rad inspect $RADICLE_RID
\`\`\`
To view the file structure, run:
\`\`\`bash
rad ls $RADICLE_RID
\`\`\`
Alternatively, use Git to list files at the current HEAD:
\`\`\`bash
git ls-tree -r --name-only HEAD
\`\`\`
### 2. Forgejo
- **URL**: [$FORGEJO_URL]($FORGEJO_URL)
- **Purpose**: Forgejo is a self-hosted, open-source git platform running on \`remember.thefoldwithin.earth\`. It provides full control over the repository, ensuring sovereignty and independence from third-party providers.
- **Value**: Enhances resilience by hosting the repository on a sovereign, redundant system with automated backups and deployment strategies, reducing risks of external interference or service disruptions.
- **Access Details**: SSH access uses port 222:
\`\`\`bash
ssh -T -p 222 username@remember.thefoldwithin.earth
\`\`\`
### 3. GitLab
- **URL**: [$GITLAB_URL]($GITLAB_URL)
- **Purpose**: GitLab offers a comprehensive DevOps platform with advanced CI/CD capabilities, private repository options, and robust access controls. It serves as a reliable backup and a platform for advanced automation workflows.
- **Value**: Enhances project resilience with its integrated CI/CD pipelines and independent infrastructure, reducing reliance on a single provider.
### 4. Bitbucket
- **URL**: [$BITBUCKET_URL]($BITBUCKET_URL)
- **Purpose**: Bitbucket provides a secure environment for repository hosting with strong integration into Atlassians ecosystem (e.g., Jira, Trello). It serves as an additional layer of redundancy and a professional-grade hosting option.
- **Value**: Offers enterprise-grade security and integration capabilities, ensuring the project remains accessible even if other platforms face disruptions.
### 5. GitHub
- **URL**: [$GITHUB_URL]($GITHUB_URL)
- **Purpose**: GitHub serves as the primary platform for visibility, collaboration, and community engagement. Its widespread adoption and robust tooling make it ideal for public-facing development, issue tracking, and integration with CI/CD pipelines.
- **Value**: Provides a centralized hub for open-source contributions, pull requests, and project management, ensuring broad accessibility and developer familiarity.
---
## 🛡️ Rationale for Redundancy
The decision to maintain multiple repositories stems from the need to safeguard the project against **deplatforming attempts** and **search engine delistings** and ensure its **long-term availability**. Past incidents involving **Mr. Joel Johnson**, **Dr. Peter Gaied**, and **Andrew LeCody** have highlighted the vulnerability of relying on a single platform or search engine. By distributing the repository across GitHub, GitLab, Bitbucket, Radicle, and a self-hosted Forgejo instance, we achieve:
- **Resilience**: If one platform removes or restricts access, or if search engines like Google delist content, the project remains accessible on other platforms and discoverable via alternative search engines such as Bing, DuckDuckGo, and Yahoo.
- **Sovereignty**: Radicles decentralized nature and Forgejos self-hosted infrastructure ensure the project cannot be fully censored or controlled by any single entity.
- **Diversity**: Each platforms unique features (e.g., GitHubs community, GitLabs CI/CD, Bitbuckets integrations, Radicles decentralization, Forgejos self-hosting) enhance the projects functionality and reach.
- **Transparency**: Metadata snapshots in the \`.gitfield\` directory provide a verifiable record of the projects state across all platforms.
This multi-repository approach, bolstered by Forgejos sovereign hosting, reflects a commitment to preserving the integrity, accessibility, and independence of \`$REPO_NAME\`, ensuring it remains available to contributors and users regardless of external pressures.
---
## 📜 Metadata and Logs
- **Metadata Files**: Each platform generates a metadata snapshot in the \`.gitfield\` directory (e.g., \`github.sigil.md\`, \`gitlab.sigil.md\`, \`remember.sigil.md\`, etc.), capturing commit details, environment information, and hardware fingerprints.
- **Push Log**: The \`.gitfield/pushed.log\` file records the date, time, and RID/URL of every push operation across all platforms, providing a transparent audit trail.
- **Recursive Sync**: The repository is synchronized across all platforms in a recursive loop (three cycles) to ensure interconnected metadata captures the latest state of the project.
- **Push Order**: The repository is synchronized in the following order: **Radicle → Forgejo → GitLab → Bitbucket → GitHub**. This prioritizes Radicles decentralized, censorship-resistant network as the primary anchor, followed by Forgejos sovereign, self-hosted infrastructure, GitLabs robust DevOps features, Bitbuckets enterprise redundancy, and GitHubs broad visibility, ensuring a resilient and accessible metadata chain.
---
_Auto-generated by \`gitfield-sync\` at $TIMESTAMP (v$SCRIPT_VERSION)._
EOF
git -C "$REPO_PATH" add "$GITFIELD_MD"
git -C "$REPO_PATH" commit -m "Generated GITFIELD.md at $TIMESTAMP" || warn "No changes to commit for $GITFIELD_MD"
info "Generated and committed $GITFIELD_MD"
}
# ╭─────────────────────────────────────╮
# │ LOG URL FUNCTION │
# ╰─────────────────────────────────────╮
log_url() {
local platform=$1
local url=$2
local rid=$3
local peer_id=$4
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
if [ "$platform" = "Radicle" ]; then
echo "[$timestamp] $platform: RID=$rid, Peer ID=$peer_id" >> "$LOG_FILE"
echo " CLI: rad inspect $rid # View project details" >> "$LOG_FILE"
echo " CLI: git ls-tree -r --name-only HEAD # View file structure" >> "$LOG_FILE"
info "Logged push to $LOG_FILE: [$timestamp] $platform: RID=$rid, Peer ID=$peer_id"
else
echo "[$timestamp] $platform: $url" >> "$LOG_FILE"
info "Logged push to $LOG_FILE: [$timestamp] $platform: $url"
fi
}
# ╭─────────────────────────────────────╮
# │ EXECUTE PUSH SCRIPT │
# ╰─────────────────────────────────────╮
execute_push() {
local script_name=$1
local platform=$2
local url=$3
local rid=$4
local peer_id=$5
local script_path
script_path=$(find_script "$script_name") || error "Failed to find $script_name"
info "Executing $platform push with script: $script_path"
if [ -x "$script_path" ]; then
pushd "$REPO_PATH" >/dev/null
"$script_path" || warn "Execution of $script_path failed, continuing..."
log_url "$platform" "$url" "$rid" "$peer_id"
git add . || warn "Nothing to add after $script_path"
git commit -m "Post-$platform sync at $TIMESTAMP" || warn "No changes to commit after $script_path"
popd >/dev/null
else
error "Script $script_path is not executable"
fi
}
# ╭─────────────────────────────────────╮
# │ RECURSIVE PUSH LOOP │
# ╰─────────────────────────────────────╮
run_push_cycle() {
local cycle_number=$1
info "Starting push cycle $cycle_number..."
execute_push "gitfield-local" "Local" "" "" ""
execute_push "gitfield-radicle" "Radicle" "" "$RADICLE_RID" "$RADICLE_PEER_ID"
execute_push "gitfield-remember" "Forgejo" "$FORGEJO_URL" "" ""
execute_push "gitfield-gitlab" "GitLab" "$GITLAB_URL" "" ""
execute_push "gitfield-bitbucket" "Bitbucket" "$BITBUCKET_URL" "" ""
execute_push "gitfield-github" "GitHub" "$GITHUB_URL" "" ""
}
# ╭─────────────────────────────────────╮
# │ MAIN EXECUTION │
# ╰─────────────────────────────────────╮
info "Starting gitfield-sync for $REPO_NAME..."
if [ ! -d "$REPO_PATH/.git" ]; then
pushd "$REPO_PATH" >/dev/null
git init
git add .
git commit -m "Initial commit" || warn "Nothing to commit"
popd >/dev/null
fi
run_push_cycle 1
generate_gitfield_md
run_push_cycle 2
run_push_cycle 3
info "✅ gitfield-sync completed successfully."
info "🔗 View logs: $LOG_FILE"
info "🔗 View multi-repo manifest: $GITFIELD_MD"

52
bin/sign-all.sh Normal file
View file

@ -0,0 +1,52 @@
#!/bin/bash
# sign-all.sh — Recursive Signature Script
# Author: Solaria & Mark Randall Havens 🌀
# Purpose: Automatically GPG-sign all matching files with .asc signatures
# ───── CONFIGURABLE OPTIONS ───────────────────────────────────────────────
EXTENSIONS=("md" "txt") # File types to sign
RECURSIVE=true # true = recurse into subdirectories
FORCE=false # true = re-sign even if .asc exists
SIGNATURE_SUFFIX=".asc" # .asc for armored detached signature
OUTPUT_LOG="gitfield-signed.log" # Signature log file
GPG_FLAGS="--armor --detach-sign"
# ───── RITUAL HEADER ──────────────────────────────────────────────────────
echo ""
echo "🌀 [SIGN-ALL] Beginning recursive signing ritual..."
echo "📅 Timestamp: $(date)"
echo "🔑 Using GPG Key: $(gpg --list-secret-keys --with-colons | grep '^uid' | cut -d':' -f10 | head -n1)"
echo ""
# ───── FIND AND SIGN FILES ────────────────────────────────────────────────
for ext in "${EXTENSIONS[@]}"; do
if [ "$RECURSIVE" = true ]; then
FILES=$(find . -type f -name "*.${ext}")
else
FILES=$(find . -maxdepth 1 -type f -name "*.${ext}")
fi
for file in $FILES; do
sigfile="${file}${SIGNATURE_SUFFIX}"
if [ -f "$sigfile" ] && [ "$FORCE" = false ]; then
echo "⚠️ Skipping already signed: $file"
continue
fi
echo "🔏 Signing: $file"
gpg $GPG_FLAGS --output "$sigfile" "$file"
if [ $? -eq 0 ]; then
echo "✅ Signed: $file -> $sigfile" | tee -a "$OUTPUT_LOG"
else
echo "❌ Error signing: $file" | tee -a "$OUTPUT_LOG"
fi
done
done
# ───── WRAP UP ─────────────────────────────────────────────────────────────
echo ""
echo "🧾 Log saved to: $OUTPUT_LOG"
echo "🗝️ To verify: gpg --verify filename${SIGNATURE_SUFFIX}"
echo "✨ Recursive signature ritual complete."