Initial commit: VaultMesh Skills collection
Collection of operational skills for VaultMesh infrastructure including: - backup-sovereign: Backup and recovery operations - btc-anchor: Bitcoin anchoring - cloudflare-tunnel-manager: Cloudflare tunnel management - container-registry: Container registry operations - disaster-recovery: Disaster recovery procedures - dns-sovereign: DNS management - eth-anchor: Ethereum anchoring - gitea-bootstrap: Gitea setup and configuration - hetzner-bootstrap: Hetzner server provisioning - merkle-forest: Merkle tree operations - node-hardening: Node security hardening - operator-bootstrap: Operator initialization - proof-verifier: Cryptographic proof verification - rfc3161-anchor: RFC3161 timestamping - secrets-vault: Secrets management 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
49
gitea-bootstrap/scripts/00_preflight.sh
Normal file
49
gitea-bootstrap/scripts/00_preflight.sh
Normal file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
source "$SCRIPT_DIR/_common.sh"
|
||||
|
||||
: "${MODE:=docker}"
|
||||
: "${ADMIN_USER:=}"
|
||||
: "${ADMIN_EMAIL:=}"
|
||||
: "${DATA_DIR:=$HOME/gitea}"
|
||||
: "${HTTP_PORT:=3000}"
|
||||
: "${SSH_PORT:=2222}"
|
||||
|
||||
main() {
|
||||
log_info "Starting 00_preflight.sh"
|
||||
[[ -n "$ADMIN_USER" ]] || die "ADMIN_USER is required."
|
||||
[[ -n "$ADMIN_EMAIL" ]] || die "ADMIN_EMAIL is required."
|
||||
|
||||
need curl
|
||||
need jq
|
||||
|
||||
if [[ "$MODE" == "docker" ]]; then
|
||||
need docker
|
||||
need docker-compose || log_warn "docker-compose not found; will use 'docker compose' if available."
|
||||
docker version >/dev/null 2>&1 || die "Docker not working."
|
||||
elif [[ "$MODE" == "native" ]]; then
|
||||
need sudo
|
||||
need systemctl
|
||||
else
|
||||
die "MODE must be 'docker' or 'native' (got: $MODE)"
|
||||
fi
|
||||
|
||||
mkdir -p "$SKILL_ROOT/outputs"
|
||||
mkdir -p "$SKILL_ROOT/outputs/backups"
|
||||
mkdir -p "$DATA_DIR"
|
||||
|
||||
# lightweight port sanity
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
if ss -ltn | awk '{print $4}' | grep -q ":$HTTP_PORT$"; then
|
||||
log_warn "HTTP_PORT $HTTP_PORT already in use."
|
||||
fi
|
||||
if ss -ltn | awk '{print $4}' | grep -q ":$SSH_PORT$"; then
|
||||
log_warn "SSH_PORT $SSH_PORT already in use."
|
||||
fi
|
||||
fi
|
||||
|
||||
log_info "Preflight OK."
|
||||
}
|
||||
main "$@"
|
||||
36
gitea-bootstrap/scripts/10_plan.sh
Normal file
36
gitea-bootstrap/scripts/10_plan.sh
Normal file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
source "$SCRIPT_DIR/_common.sh"
|
||||
|
||||
: "${MODE:=docker}"
|
||||
: "${NODE_NAME:=node-b}"
|
||||
: "${HTTP_PORT:=3000}"
|
||||
: "${SSH_PORT:=2222}"
|
||||
: "${DOMAIN:=}"
|
||||
: "${DATA_DIR:=$HOME/gitea}"
|
||||
: "${ADMIN_USER:=}"
|
||||
: "${ADMIN_EMAIL:=}"
|
||||
|
||||
main() {
|
||||
[[ -n "$ADMIN_USER" ]] || die "ADMIN_USER is required."
|
||||
[[ -n "$ADMIN_EMAIL" ]] || die "ADMIN_EMAIL is required."
|
||||
|
||||
echo "[PLAN] $(date -Iseconds) Gitea Bootstrap ($MODE)"
|
||||
echo "[PLAN] Node: $NODE_NAME"
|
||||
echo "[PLAN] Data dir: $DATA_DIR"
|
||||
echo "[PLAN] Web: http://<host>:$HTTP_PORT (or https://$DOMAIN via reverse proxy)"
|
||||
if [[ "$MODE" == "docker" ]]; then
|
||||
echo "[PLAN] SSH (git): <host>:$SSH_PORT (container maps to 22)"
|
||||
echo "[PLAN] Will generate: outputs/compose.yml and outputs/gitea_app.ini"
|
||||
echo "[PLAN] Will run: docker compose up -d"
|
||||
else
|
||||
echo "[PLAN] Native install: package + systemd"
|
||||
echo "[PLAN] Will write: /etc/gitea/app.ini (backup first)"
|
||||
fi
|
||||
echo "[PLAN] Admin bootstrap:"
|
||||
echo " username=$ADMIN_USER email=$ADMIN_EMAIL"
|
||||
echo "[PLAN] Next: export DRY_RUN=0 && ./scripts/11_apply.sh"
|
||||
}
|
||||
main "$@"
|
||||
112
gitea-bootstrap/scripts/11_apply.sh
Normal file
112
gitea-bootstrap/scripts/11_apply.sh
Normal file
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
source "$SCRIPT_DIR/_common.sh"
|
||||
|
||||
: "${MODE:=docker}"
|
||||
: "${NODE_NAME:=node-b}"
|
||||
: "${HTTP_PORT:=3000}"
|
||||
: "${SSH_PORT:=2222}"
|
||||
: "${DOMAIN:=}"
|
||||
: "${DATA_DIR:=$HOME/gitea}"
|
||||
: "${ADMIN_USER:=}"
|
||||
: "${ADMIN_EMAIL:=}"
|
||||
|
||||
compose_cmd() {
|
||||
if command -v docker-compose >/dev/null 2>&1; then
|
||||
echo "docker-compose"
|
||||
else
|
||||
echo "docker compose"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
confirm_gate
|
||||
[[ -n "$ADMIN_USER" ]] || die "ADMIN_USER is required."
|
||||
[[ -n "$ADMIN_EMAIL" ]] || die "ADMIN_EMAIL is required."
|
||||
|
||||
local ts; ts="$(date -Iseconds | tr ':' '-')"
|
||||
local backup_dir="$SKILL_ROOT/outputs/backups/$ts"
|
||||
mkdir -p "$backup_dir"
|
||||
|
||||
if [[ "$MODE" == "docker" ]]; then
|
||||
need docker
|
||||
mkdir -p "$SKILL_ROOT/outputs"
|
||||
|
||||
# Render minimal app.ini (Gitea will expand defaults)
|
||||
cat > "$SKILL_ROOT/outputs/gitea_app.ini" <<EOF
|
||||
APP_NAME = VaultMesh Gitea
|
||||
RUN_MODE = prod
|
||||
|
||||
[server]
|
||||
DOMAIN = ${DOMAIN}
|
||||
HTTP_PORT = ${HTTP_PORT}
|
||||
ROOT_URL = ${DOMAIN:+https://${DOMAIN}/}${DOMAIN:+" "}${DOMAIN:-http://localhost:${HTTP_PORT}/}
|
||||
SSH_DOMAIN = ${DOMAIN:-localhost}
|
||||
SSH_PORT = ${SSH_PORT}
|
||||
DISABLE_SSH = false
|
||||
START_SSH_SERVER = true
|
||||
|
||||
[database]
|
||||
DB_TYPE = sqlite3
|
||||
PATH = /data/gitea/gitea.db
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK = true
|
||||
EOF
|
||||
|
||||
# Render compose.yml
|
||||
cat > "$SKILL_ROOT/outputs/compose.yml" <<EOF
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- GITEA__server__HTTP_PORT=${HTTP_PORT}
|
||||
- GITEA__server__SSH_PORT=${SSH_PORT}
|
||||
volumes:
|
||||
- ${DATA_DIR}:/data
|
||||
- ${SKILL_ROOT}/outputs/gitea_app.ini:/data/gitea/conf/app.ini
|
||||
ports:
|
||||
- "${HTTP_PORT}:${HTTP_PORT}"
|
||||
- "${SSH_PORT}:22"
|
||||
EOF
|
||||
|
||||
cp -a "$SKILL_ROOT/outputs/compose.yml" "$backup_dir/compose.yml"
|
||||
cp -a "$SKILL_ROOT/outputs/gitea_app.ini" "$backup_dir/gitea_app.ini"
|
||||
|
||||
log_info "Starting Gitea via compose..."
|
||||
cd "$SKILL_ROOT/outputs"
|
||||
$(compose_cmd) -f compose.yml up -d
|
||||
|
||||
log_info "Waiting for HTTP..."
|
||||
for i in $(seq 1 30); do
|
||||
if curl -fsS "http://127.0.0.1:${HTTP_PORT}/" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
log_warn "Admin creation is interactive via web UI on first run (recommended)."
|
||||
log_warn "Open: http://<host>:${HTTP_PORT}/ and create admin user: $ADMIN_USER"
|
||||
log_warn "Then lock install is already set in app.ini (INSTALL_LOCK=true)."
|
||||
|
||||
elif [[ "$MODE" == "native" ]]; then
|
||||
need sudo
|
||||
need systemctl
|
||||
log_warn "Native mode is a scaffold in v1.0.0."
|
||||
log_warn "It intentionally does not auto-install packages to avoid distro variance."
|
||||
log_warn "Next action: follow references/gitea_hardening_notes.md and extend apply script for your distro."
|
||||
else
|
||||
die "MODE must be docker|native"
|
||||
fi
|
||||
|
||||
log_info "Apply complete."
|
||||
}
|
||||
main "$@"
|
||||
59
gitea-bootstrap/scripts/90_verify.sh
Normal file
59
gitea-bootstrap/scripts/90_verify.sh
Normal file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
source "$SCRIPT_DIR/_common.sh"
|
||||
|
||||
: "${MODE:=docker}"
|
||||
: "${HTTP_PORT:=3000}"
|
||||
: "${DATA_DIR:=$HOME/gitea}"
|
||||
|
||||
main() {
|
||||
local status="$SKILL_ROOT/outputs/status_matrix.json"
|
||||
local ok_http=false ok_data=false ok_compose=false ok_container=false
|
||||
|
||||
[[ -d "$DATA_DIR" ]] && ok_data=true
|
||||
[[ -f "$SKILL_ROOT/outputs/compose.yml" ]] && ok_compose=true
|
||||
|
||||
if curl -fsS "http://127.0.0.1:${HTTP_PORT}/" >/dev/null 2>&1; then
|
||||
ok_http=true
|
||||
fi
|
||||
|
||||
if [[ "$MODE" == "docker" ]]; then
|
||||
if docker ps --format '{{.Names}}' | grep -q '^gitea$'; then
|
||||
ok_container=true
|
||||
fi
|
||||
fi
|
||||
|
||||
blockers="[]"
|
||||
if [[ "$ok_data" != "true" ]]; then blockers='["data_dir_missing"]'
|
||||
elif [[ "$ok_compose" != "true" && "$MODE" == "docker" ]]; then blockers='["compose_missing"]'
|
||||
elif [[ "$ok_http" != "true" ]]; then blockers='["http_unreachable"]'
|
||||
fi
|
||||
|
||||
cat > "$status" <<EOF
|
||||
{
|
||||
"skill": "gitea-bootstrap",
|
||||
"timestamp": "$(date -Iseconds)",
|
||||
"checks": [
|
||||
{"name":"data_dir_present", "ok": $ok_data},
|
||||
{"name":"compose_present", "ok": $ok_compose},
|
||||
{"name":"container_running", "ok": $ok_container},
|
||||
{"name":"http_reachable", "ok": $ok_http}
|
||||
],
|
||||
"blockers": $blockers,
|
||||
"warnings": [
|
||||
"Admin user creation is recommended via first-run web UI in v1"
|
||||
],
|
||||
"next_steps": [
|
||||
"Create admin via web UI and record admin creation in your ops log",
|
||||
"Put Gitea behind reverse proxy + TLS (optional)",
|
||||
"Proceed to container-registry or dns-sovereign"
|
||||
]
|
||||
}
|
||||
EOF
|
||||
|
||||
log_info "Wrote $status"
|
||||
cat "$status"
|
||||
}
|
||||
main "$@"
|
||||
79
gitea-bootstrap/scripts/99_report.sh
Normal file
79
gitea-bootstrap/scripts/99_report.sh
Normal file
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
source "$SCRIPT_DIR/_common.sh"
|
||||
|
||||
: "${NODE_NAME:=node-b}"
|
||||
: "${MODE:=docker}"
|
||||
: "${HTTP_PORT:=3000}"
|
||||
: "${SSH_PORT:=2222}"
|
||||
: "${DOMAIN:=}"
|
||||
: "${DATA_DIR:=$HOME/gitea}"
|
||||
: "${ADMIN_USER:=}"
|
||||
: "${ADMIN_EMAIL:=}"
|
||||
|
||||
main() {
|
||||
mkdir -p "$SKILL_ROOT/outputs"
|
||||
local report="$SKILL_ROOT/outputs/audit_report.md"
|
||||
local status="$SKILL_ROOT/outputs/status_matrix.json"
|
||||
|
||||
cat > "$report" <<EOF
|
||||
# Gitea Bootstrap Audit Report
|
||||
|
||||
**Generated:** $(date -Iseconds)
|
||||
**Node:** $(json_escape "$NODE_NAME")
|
||||
**Mode:** $(json_escape "$MODE")
|
||||
**Web Port:** $HTTP_PORT
|
||||
**SSH Port:** $SSH_PORT
|
||||
**Domain:** $(json_escape "$DOMAIN")
|
||||
**Data Dir:** $(json_escape "$DATA_DIR")
|
||||
**Admin (planned):** $(json_escape "${ADMIN_USER:-}") / $(json_escape "${ADMIN_EMAIL:-}")
|
||||
**Skill Version:** 1.0.0
|
||||
|
||||
---
|
||||
|
||||
## Artifacts
|
||||
|
||||
| Item | Path |
|
||||
|---|---|
|
||||
| Compose | \`$SKILL_ROOT/outputs/compose.yml\` |
|
||||
| app.ini | \`$SKILL_ROOT/outputs/gitea_app.ini\` |
|
||||
| Status Matrix | \`$SKILL_ROOT/outputs/status_matrix.json\` |
|
||||
| Backups | \`$SKILL_ROOT/outputs/backups/\` |
|
||||
|
||||
---
|
||||
|
||||
## Status Matrix
|
||||
|
||||
$(if [[ -f "$status" ]]; then
|
||||
echo '```json'
|
||||
cat "$status"
|
||||
echo '```'
|
||||
else
|
||||
echo "_Missing status_matrix.json — run 90_verify.sh first._"
|
||||
fi)
|
||||
|
||||
---
|
||||
|
||||
## EU Compliance Declaration
|
||||
|
||||
| Aspect | Value |
|
||||
|---|---|
|
||||
| Data Residency | EU (Ireland - Dublin) |
|
||||
| Jurisdiction | Irish Law |
|
||||
| Git Authority | Self-hosted on Node B |
|
||||
| Backups | Local outputs; optional offsite via backup-sovereign |
|
||||
|
||||
---
|
||||
|
||||
## Rollback
|
||||
|
||||
- Docker/native undo: \`./scripts/rollback/undo.sh\`
|
||||
|
||||
EOF
|
||||
|
||||
log_info "Wrote $report"
|
||||
cat "$report"
|
||||
}
|
||||
main "$@"
|
||||
32
gitea-bootstrap/scripts/_common.sh
Normal file
32
gitea-bootstrap/scripts/_common.sh
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
log_info(){ echo "[INFO] $(date -Iseconds) $*"; }
|
||||
log_warn(){ echo "[WARN] $(date -Iseconds) $*" >&2; }
|
||||
log_error(){ echo "[ERROR] $(date -Iseconds) $*" >&2; }
|
||||
die(){ log_error "$*"; exit 1; }
|
||||
|
||||
need(){ command -v "$1" >/dev/null 2>&1 || die "Missing required tool: $1"; }
|
||||
|
||||
json_escape() {
|
||||
local s="$1"
|
||||
s="${s//\\/\\\\}"
|
||||
s="${s//\"/\\\"}"
|
||||
s="${s//$'\n'/\\n}"
|
||||
s="${s//$'\r'/\\r}"
|
||||
s="${s//$'\t'/\\t}"
|
||||
printf "%s" "$s"
|
||||
}
|
||||
|
||||
confirm_gate() {
|
||||
: "${DRY_RUN:=1}"
|
||||
: "${REQUIRE_CONFIRM:=1}"
|
||||
: "${CONFIRM_PHRASE:=I UNDERSTAND THIS WILL INSTALL AND CONFIGURE GITEA}"
|
||||
[[ "$DRY_RUN" == "0" ]] || die "DRY_RUN=$DRY_RUN (set DRY_RUN=0 to apply)."
|
||||
if [[ "$REQUIRE_CONFIRM" == "1" ]]; then
|
||||
echo "Type to confirm:"
|
||||
echo " $CONFIRM_PHRASE"
|
||||
read -r input
|
||||
[[ "$input" == "$CONFIRM_PHRASE" ]] || die "Confirmation phrase mismatch."
|
||||
fi
|
||||
}
|
||||
34
gitea-bootstrap/scripts/rollback/undo.sh
Normal file
34
gitea-bootstrap/scripts/rollback/undo.sh
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SKILL_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
|
||||
source "$SKILL_ROOT/scripts/_common.sh"
|
||||
|
||||
: "${MODE:=docker}"
|
||||
: "${DATA_DIR:=$HOME/gitea}"
|
||||
|
||||
compose_cmd() {
|
||||
if command -v docker-compose >/dev/null 2>&1; then
|
||||
echo "docker-compose"
|
||||
else
|
||||
echo "docker compose"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
confirm_gate
|
||||
if [[ "$MODE" == "docker" ]]; then
|
||||
if [[ -f "$SKILL_ROOT/outputs/compose.yml" ]]; then
|
||||
log_warn "Stopping compose stack..."
|
||||
cd "$SKILL_ROOT/outputs"
|
||||
$(compose_cmd) -f compose.yml down || true
|
||||
else
|
||||
log_warn "No compose.yml found; attempting to stop container 'gitea'..."
|
||||
docker rm -f gitea 2>/dev/null || true
|
||||
fi
|
||||
else
|
||||
log_warn "Native mode rollback scaffold (stop gitea service manually if configured)."
|
||||
fi
|
||||
log_info "Rollback complete. Data dir preserved at: $DATA_DIR"
|
||||
}
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user