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:
193
operator-bootstrap/scripts/31_gitops_apply.sh
Executable file
193
operator-bootstrap/scripts/31_gitops_apply.sh
Executable file
@@ -0,0 +1,193 @@
|
||||
#!/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 "$@"
|
||||
Reference in New Issue
Block a user