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>
194 lines
5.4 KiB
Bash
Executable File
194 lines
5.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# === METADATA ===
|
|
SCRIPT_NAME="$(basename "$0")"
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
|
|
# === CONFIGURATION ===
|
|
: "${NODE_NAME:=node-a}"
|
|
: "${GITOPS_ROOT:=$HOME/infrastructure}"
|
|
: "${OUTPUT_DIR:=$SKILL_ROOT/outputs}"
|
|
|
|
# === FUNCTIONS ===
|
|
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; }
|
|
|
|
preflight() {
|
|
# Expand ~ in GITOPS_ROOT
|
|
GITOPS_ROOT="${GITOPS_ROOT/#\~/$HOME}"
|
|
[[ -d "$OUTPUT_DIR" ]] || mkdir -p "$OUTPUT_DIR"
|
|
[[ -d "$GITOPS_ROOT" ]] || mkdir -p "$GITOPS_ROOT"
|
|
}
|
|
|
|
create_bare_repo() {
|
|
local name="$1"
|
|
local description="$2"
|
|
local repo_path="$GITOPS_ROOT/${name}.git"
|
|
|
|
if [[ -d "$repo_path" ]]; then
|
|
log_info "Repository $name.git already exists - skipping"
|
|
return 0
|
|
fi
|
|
|
|
log_info "Creating bare repository: $name.git"
|
|
git init --bare "$repo_path"
|
|
|
|
# Set description
|
|
echo "$description" > "$repo_path/description"
|
|
|
|
# Create initial branch structure by setting HEAD
|
|
git -C "$repo_path" symbolic-ref HEAD refs/heads/main
|
|
|
|
log_info "Created $repo_path"
|
|
}
|
|
|
|
create_hook() {
|
|
local repo="$1"
|
|
local hook_name="$2"
|
|
local hook_content="$3"
|
|
local hook_path="$GITOPS_ROOT/${repo}.git/hooks/$hook_name"
|
|
|
|
if [[ -f "$hook_path" ]] && [[ -x "$hook_path" ]]; then
|
|
log_info "Hook $hook_name for $repo already exists - skipping"
|
|
return 0
|
|
fi
|
|
|
|
echo "$hook_content" > "$hook_path"
|
|
chmod +x "$hook_path"
|
|
log_info "Created hook: $repo.git/hooks/$hook_name"
|
|
}
|
|
|
|
setup_hooks() {
|
|
# Config repo hook - validate YAML
|
|
create_hook "config" "post-receive" '#!/usr/bin/env bash
|
|
# Post-receive hook for config repository
|
|
# Validates YAML files on push
|
|
|
|
echo "[config-hook] Validating pushed files..."
|
|
|
|
while read oldrev newrev refname; do
|
|
if [[ "$newrev" == "0000000000000000000000000000000000000000" ]]; then
|
|
continue # Branch deleted
|
|
fi
|
|
|
|
# List changed files
|
|
files=$(git diff-tree --no-commit-id --name-only -r "$newrev" 2>/dev/null || echo "")
|
|
|
|
for file in $files; do
|
|
if [[ "$file" == *.yml ]] || [[ "$file" == *.yaml ]]; then
|
|
echo "[config-hook] YAML file changed: $file"
|
|
fi
|
|
done
|
|
done
|
|
|
|
echo "[config-hook] Validation complete"
|
|
'
|
|
|
|
# Secrets repo hook - verify GPG
|
|
create_hook "secrets" "post-receive" '#!/usr/bin/env bash
|
|
# Post-receive hook for secrets repository
|
|
# Verifies that pushed files are GPG encrypted
|
|
|
|
echo "[secrets-hook] Verifying encryption..."
|
|
|
|
while read oldrev newrev refname; do
|
|
if [[ "$newrev" == "0000000000000000000000000000000000000000" ]]; then
|
|
continue
|
|
fi
|
|
|
|
files=$(git diff-tree --no-commit-id --name-only -r "$newrev" 2>/dev/null || echo "")
|
|
|
|
for file in $files; do
|
|
if [[ "$file" == *.gpg ]]; then
|
|
echo "[secrets-hook] Encrypted file: $file"
|
|
elif [[ "$file" != ".gitignore" ]] && [[ "$file" != "README"* ]]; then
|
|
echo "[secrets-hook] WARNING: Unencrypted file detected: $file"
|
|
fi
|
|
done
|
|
done
|
|
|
|
echo "[secrets-hook] Verification complete"
|
|
'
|
|
|
|
# Manifests repo hook - validate manifests
|
|
create_hook "manifests" "post-receive" '#!/usr/bin/env bash
|
|
# Post-receive hook for manifests repository
|
|
# Validates Kubernetes/deployment manifests on push
|
|
|
|
echo "[manifests-hook] Validating manifests..."
|
|
|
|
while read oldrev newrev refname; do
|
|
if [[ "$newrev" == "0000000000000000000000000000000000000000" ]]; then
|
|
continue
|
|
fi
|
|
|
|
files=$(git diff-tree --no-commit-id --name-only -r "$newrev" 2>/dev/null || echo "")
|
|
|
|
for file in $files; do
|
|
if [[ "$file" == *.yml ]] || [[ "$file" == *.yaml ]]; then
|
|
echo "[manifests-hook] Manifest changed: $file"
|
|
fi
|
|
done
|
|
done
|
|
|
|
echo "[manifests-hook] Validation complete"
|
|
'
|
|
}
|
|
|
|
generate_manifest() {
|
|
local manifest="$OUTPUT_DIR/gitops_manifest.json"
|
|
|
|
cat > "$manifest" <<EOF
|
|
{
|
|
"timestamp": "$(date -Iseconds)",
|
|
"node": "$NODE_NAME",
|
|
"gitops_root": "$GITOPS_ROOT",
|
|
"repositories": {
|
|
"config": "$GITOPS_ROOT/config.git",
|
|
"secrets": "$GITOPS_ROOT/secrets.git",
|
|
"manifests": "$GITOPS_ROOT/manifests.git"
|
|
},
|
|
"branches": ["main", "staging", "dev"],
|
|
"hooks_installed": true,
|
|
"clone_commands": [
|
|
"git clone $GITOPS_ROOT/config.git ~/config",
|
|
"git clone $GITOPS_ROOT/secrets.git ~/secrets",
|
|
"git clone $GITOPS_ROOT/manifests.git ~/manifests"
|
|
]
|
|
}
|
|
EOF
|
|
log_info "GitOps manifest written to $manifest"
|
|
}
|
|
|
|
main() {
|
|
preflight
|
|
log_info "Starting $SCRIPT_NAME..."
|
|
|
|
create_bare_repo "config" "Infrastructure configuration (YAML, TOML)"
|
|
create_bare_repo "secrets" "Encrypted secrets (GPG)"
|
|
create_bare_repo "manifests" "Kubernetes and deployment manifests"
|
|
setup_hooks
|
|
generate_manifest
|
|
|
|
echo ""
|
|
echo "============================================"
|
|
echo " GITOPS SETUP COMPLETE"
|
|
echo "============================================"
|
|
echo ""
|
|
echo " Root: $GITOPS_ROOT"
|
|
echo ""
|
|
echo " To clone and start working:"
|
|
echo " git clone $GITOPS_ROOT/config.git ~/config"
|
|
echo " git clone $GITOPS_ROOT/secrets.git ~/secrets"
|
|
echo " git clone $GITOPS_ROOT/manifests.git ~/manifests"
|
|
echo ""
|
|
|
|
log_info "Completed $SCRIPT_NAME"
|
|
}
|
|
|
|
[[ "${BASH_SOURCE[0]}" == "$0" ]] && main "$@"
|