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:
23
container-registry/scripts/00_preflight.sh
Normal file
23
container-registry/scripts/00_preflight.sh
Normal file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
source "$SCRIPT_DIR/_common.sh"
|
||||
|
||||
: "${REGISTRY_USER:=}"
|
||||
: "${DATA_DIR:=$HOME/registry}"
|
||||
: "${AUTH_DIR:=$HOME/registry/auth}"
|
||||
: "${REGISTRY_PORT:=5000}"
|
||||
|
||||
main() {
|
||||
[[ -n "$REGISTRY_USER" ]] || die "REGISTRY_USER is required."
|
||||
need docker
|
||||
need curl
|
||||
need htpasswd || log_warn "htpasswd not found (apache2-utils). Will attempt install guidance only."
|
||||
|
||||
mkdir -p "$SKILL_ROOT/outputs" "$SKILL_ROOT/outputs/backups"
|
||||
mkdir -p "$DATA_DIR" "$AUTH_DIR"
|
||||
|
||||
log_info "Preflight OK."
|
||||
}
|
||||
main "$@"
|
||||
21
container-registry/scripts/10_plan.sh
Normal file
21
container-registry/scripts/10_plan.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
source "$SCRIPT_DIR/_common.sh"
|
||||
|
||||
: "${REGISTRY_PORT:=5000}"
|
||||
: "${DATA_DIR:=$HOME/registry}"
|
||||
: "${AUTH_DIR:=$HOME/registry/auth}"
|
||||
: "${REGISTRY_USER:=}"
|
||||
|
||||
main() {
|
||||
[[ -n "$REGISTRY_USER" ]] || die "REGISTRY_USER is required."
|
||||
echo "[PLAN] $(date -Iseconds) Container Registry"
|
||||
echo "[PLAN] Port: $REGISTRY_PORT"
|
||||
echo "[PLAN] Data: $DATA_DIR"
|
||||
echo "[PLAN] Auth: $AUTH_DIR (basic auth)"
|
||||
echo "[PLAN] Compose file: outputs/compose.yml"
|
||||
echo "[PLAN] Next: export DRY_RUN=0 && ./scripts/11_apply.sh"
|
||||
}
|
||||
main "$@"
|
||||
63
container-registry/scripts/11_apply.sh
Normal file
63
container-registry/scripts/11_apply.sh
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
source "$SCRIPT_DIR/_common.sh"
|
||||
|
||||
: "${REGISTRY_PORT:=5000}"
|
||||
: "${DATA_DIR:=$HOME/registry}"
|
||||
: "${AUTH_DIR:=$HOME/registry/auth}"
|
||||
: "${REGISTRY_USER:=}"
|
||||
|
||||
compose_cmd() {
|
||||
if command -v docker-compose >/dev/null 2>&1; then
|
||||
echo "docker-compose"
|
||||
else
|
||||
echo "docker compose"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
confirm_gate
|
||||
need docker
|
||||
[[ -n "$REGISTRY_USER" ]] || die "REGISTRY_USER is required."
|
||||
|
||||
local ts; ts="$(date -Iseconds | tr ':' '-')"
|
||||
local backup_dir="$SKILL_ROOT/outputs/backups/$ts"
|
||||
mkdir -p "$backup_dir"
|
||||
|
||||
# Auth
|
||||
if command -v htpasswd >/dev/null 2>&1; then
|
||||
log_warn "Creating htpasswd entry for $REGISTRY_USER"
|
||||
htpasswd -B -c "$AUTH_DIR/htpasswd" "$REGISTRY_USER"
|
||||
cp -a "$AUTH_DIR/htpasswd" "$backup_dir/htpasswd"
|
||||
else
|
||||
die "htpasswd not available; install apache2-utils."
|
||||
fi
|
||||
|
||||
# Compose
|
||||
cat > "$SKILL_ROOT/outputs/compose.yml" <<EOF
|
||||
version: "3"
|
||||
services:
|
||||
registry:
|
||||
image: registry:2
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${REGISTRY_PORT}:5000"
|
||||
environment:
|
||||
REGISTRY_AUTH: htpasswd
|
||||
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
|
||||
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
|
||||
volumes:
|
||||
- ${DATA_DIR}:/var/lib/registry
|
||||
- ${AUTH_DIR}:/auth
|
||||
EOF
|
||||
|
||||
cp -a "$SKILL_ROOT/outputs/compose.yml" "$backup_dir/compose.yml"
|
||||
|
||||
cd "$SKILL_ROOT/outputs"
|
||||
$(compose_cmd) -f compose.yml up -d
|
||||
|
||||
log_info "Registry started on port $REGISTRY_PORT"
|
||||
}
|
||||
main "$@"
|
||||
42
container-registry/scripts/90_verify.sh
Normal file
42
container-registry/scripts/90_verify.sh
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
source "$SCRIPT_DIR/_common.sh"
|
||||
|
||||
: "${REGISTRY_PORT:=5000}"
|
||||
|
||||
main() {
|
||||
local status="$SKILL_ROOT/outputs/status_matrix.json"
|
||||
local ok_container=false ok_http=false
|
||||
|
||||
if docker ps --format '{{.Names}}' | grep -q registry; then ok_container=true; fi
|
||||
if curl -fsS "http://127.0.0.1:${REGISTRY_PORT}/v2/" >/dev/null 2>&1; then ok_http=true; fi
|
||||
|
||||
blockers="[]"
|
||||
if [[ "$ok_container" != "true" ]]; then blockers='["registry_not_running"]'
|
||||
elif [[ "$ok_http" != "true" ]]; then blockers='["registry_http_unreachable"]'
|
||||
fi
|
||||
|
||||
cat > "$status" <<EOF
|
||||
{
|
||||
"skill": "container-registry",
|
||||
"timestamp": "$(date -Iseconds)",
|
||||
"checks": [
|
||||
{"name":"container_running", "ok": $ok_container},
|
||||
{"name":"registry_http", "ok": $ok_http}
|
||||
],
|
||||
"blockers": $blockers,
|
||||
"warnings": [],
|
||||
"next_steps": [
|
||||
"Configure TLS via reverse proxy or tunnel",
|
||||
"Integrate image signing (cosign/notation)",
|
||||
"Proceed to dns-sovereign"
|
||||
]
|
||||
}
|
||||
EOF
|
||||
|
||||
log_info "Wrote $status"
|
||||
cat "$status"
|
||||
}
|
||||
main "$@"
|
||||
61
container-registry/scripts/99_report.sh
Normal file
61
container-registry/scripts/99_report.sh
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
source "$SCRIPT_DIR/_common.sh"
|
||||
|
||||
: "${REGISTRY_PORT:=5000}"
|
||||
: "${DATA_DIR:=$HOME/registry}"
|
||||
|
||||
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
|
||||
# Container Registry Audit Report
|
||||
|
||||
**Generated:** $(date -Iseconds)
|
||||
**Port:** $REGISTRY_PORT
|
||||
**Data Dir:** $DATA_DIR
|
||||
**Skill Version:** 1.0.0
|
||||
|
||||
---
|
||||
|
||||
## Artifacts
|
||||
|
||||
| Item | Path |
|
||||
|---|---|
|
||||
| Compose | \`$SKILL_ROOT/outputs/compose.yml\` |
|
||||
| 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 |
|
||||
| Registry | Self-hosted |
|
||||
| Access | Authenticated (basic) |
|
||||
|
||||
EOF
|
||||
|
||||
log_info "Wrote $report"
|
||||
cat "$report"
|
||||
}
|
||||
main "$@"
|
||||
19
container-registry/scripts/_common.sh
Normal file
19
container-registry/scripts/_common.sh
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/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"; }
|
||||
confirm_gate() {
|
||||
: "${DRY_RUN:=1}"
|
||||
: "${REQUIRE_CONFIRM:=1}"
|
||||
: "${CONFIRM_PHRASE:=I UNDERSTAND THIS WILL DEPLOY A CONTAINER REGISTRY}"
|
||||
[[ "$DRY_RUN" == "0" ]] || die "DRY_RUN=$DRY_RUN (set DRY_RUN=0)."
|
||||
if [[ "$REQUIRE_CONFIRM" == "1" ]]; then
|
||||
echo "Type to confirm:"
|
||||
echo " $CONFIRM_PHRASE"
|
||||
read -r input
|
||||
[[ "$input" == "$CONFIRM_PHRASE" ]] || die "Confirmation phrase mismatch."
|
||||
fi
|
||||
}
|
||||
15
container-registry/scripts/rollback/undo.sh
Normal file
15
container-registry/scripts/rollback/undo.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/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"
|
||||
|
||||
main() {
|
||||
confirm_gate
|
||||
if docker ps --format '{{.Names}}' | grep -q registry; then
|
||||
log_warn "Stopping registry container..."
|
||||
docker rm -f registry || true
|
||||
fi
|
||||
log_info "Rollback complete. Data preserved."
|
||||
}
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user