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:
Vault Sovereign
2025-12-27 00:25:00 +00:00
commit eac77ef7b4
213 changed files with 11724 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
---
name: container-registry
description: >
Bootstrap a sovereign container registry (OCI/Docker) with plan/apply/rollback,
signature verification hooks, backups, and audit report. Designed to pair with
gitea-bootstrap on Node B. Triggers: 'container registry', 'docker registry',
'oci registry', 'self-host registry', 'registry plan'.
version: 1.0.0
---
# Container Registry (Sovereign)
Tier 2 skill: establish a **self-hosted OCI registry** you control.
This skill deploys a Docker Registry v2 (with optional UI) using
plan/apply gates and produces verifiable artifacts.
## Quick Start
```bash
cd ~/.claude/skills/container-registry
export MODE="docker" # docker only in v1
export NODE_NAME="node-b"
# Network
export REGISTRY_PORT=5000
export DOMAIN="registry.example.com" # optional (for reverse proxy)
# Storage
export DATA_DIR="$HOME/registry"
export AUTH_DIR="$HOME/registry/auth"
# Auth (basic auth for v1)
export REGISTRY_USER="sovereign"
# Safety
export DRY_RUN=1
export REQUIRE_CONFIRM=1
export CONFIRM_PHRASE="I UNDERSTAND THIS WILL DEPLOY A CONTAINER REGISTRY"
./scripts/00_preflight.sh
./scripts/10_plan.sh
export DRY_RUN=0
./scripts/11_apply.sh
./scripts/90_verify.sh
./scripts/99_report.sh
```
## Inputs
| Parameter | Required | Default | Description |
|---|---:|---|---|
| MODE | Yes | docker | docker |
| REGISTRY_PORT | No | 5000 | Registry port |
| DOMAIN | No | (empty) | Hostname if proxied |
| DATA_DIR | No | ~/registry | Registry storage |
| AUTH_DIR | No | ~/registry/auth | htpasswd storage |
| REGISTRY_USER | Yes | (none) | Registry username |
| DRY_RUN | No | 1 | Apply refuses unless DRY_RUN=0 |
| REQUIRE_CONFIRM | No | 1 | Require confirmation phrase |
| CONFIRM_PHRASE | No | I UNDERSTAND THIS WILL DEPLOY A CONTAINER REGISTRY | Safety phrase |
## Outputs
- `outputs/compose.yml`
- `outputs/htpasswd`
- `outputs/status_matrix.json`
- `outputs/audit_report.md`
- Backups under `outputs/backups/`
## Security Notes (v1)
- Basic auth (htpasswd)
- TLS termination expected via reverse proxy or Cloudflare Tunnel
- Image signing handled upstream (cosign/notation integration planned)
## EU Compliance
| Aspect | Value |
|---|---|
| Data Residency | EU (Ireland - Dublin) |
| Jurisdiction | Irish Law |
| Images | Stored on Node B |
| Access | Authenticated |
## References
- [OCI Registry Notes](references/registry_notes.md)

View File

@@ -0,0 +1,41 @@
{
"name": "container-registry",
"version": "1.0.0",
"description": "Bootstrap a sovereign container registry with plan/apply/rollback.",
"defaults": {
"MODE": "docker",
"REGISTRY_PORT": "5000",
"DATA_DIR": "~/registry",
"AUTH_DIR": "~/registry/auth",
"DRY_RUN": "1",
"REQUIRE_CONFIRM": "1",
"CONFIRM_PHRASE": "I UNDERSTAND THIS WILL DEPLOY A CONTAINER REGISTRY"
},
"phases": {
"preflight": [
"00_preflight.sh"
],
"registry": {
"plan": [
"10_plan.sh"
],
"apply": [
"11_apply.sh"
],
"rollback": [
"rollback/undo.sh"
]
},
"verify": [
"90_verify.sh"
],
"report": [
"99_report.sh"
]
},
"eu_compliance": {
"data_residency": "EU",
"jurisdiction": "Ireland",
"gdpr_applicable": true
}
}

View File

@@ -0,0 +1,17 @@
# OCI Registry Notes
## Why Self-Host
- Full sovereignty over artifacts
- Pair with Gitea for source + images
## TLS
Terminate TLS via:
- Reverse proxy (nginx/Traefik)
- Cloudflare Tunnel
## Signing (Next)
Integrate:
- cosign (Sigstore)
- Notation v2
These will be added as future skills or extensions.

View 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 "$@"

View 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 "$@"

View 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 "$@"

View 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 "$@"

View 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 "$@"

View 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
}

View 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 "$@"