aboutsummaryrefslogtreecommitdiff
path: root/straper/lint-db.sh
blob: 0b961bc189aa02c51d9b582f5db312d8213f4857 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/env bash
set -Eeuo pipefail

SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/lib/common.sh"

SCRIPT_NAME="lint-db.sh"
ISSUES=0

usage() {
  cat <<'USAGE'
Usage: sudo ./lint-db.sh [options]

Purpose:
  Non-destructively lint a rebuild DB for structural problems that can pollute
  restore results.

Checks:
  - backup directories captured into DB (e.g. *.bak.*)
  - nested duplicate service roots (e.g. nginx/nginx, i2pd/i2pd)
  - overlapping category roots (e.g. etc-i2pd plus sibling tunnels.d)
  - duplicate canonical files at two depths within the same category

Options:
  --db-dir PATH
  --verbose
  --help
USAGE
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --db-dir) DB_DIR="$2"; PUBLIC_DIR="${DB_DIR}/db/public"; SECRET_DIR="${DB_DIR}/db/secret"; shift ;;
    --verbose) VERBOSE=true ;;
    --help) usage; exit 0 ;;
    *) die "unknown option: $1" ;;
  esac
  shift
done

load_optional_config
ensure_runtime_dirs

[[ -d "${PUBLIC_DIR}" ]] || die "public DB not found: ${PUBLIC_DIR}"

say()   { printf '%s\n' "$*"; }
warnx() { printf 'WARN  | %s\n' "$*"; ISSUES=1; }
okx()   { printf 'OK    | %s\n' "$*"; }

emit_section() {
  printf '\n%s\n' "$1"
}

find_matches() {
  local base="$1" pattern="$2"
  find "$base" -path "$pattern" -print 2>/dev/null | sort || true
}

check_backup_dirs() {
  local hits
  hits="$(find "${PUBLIC_DIR}" "${SECRET_DIR}" \
    -type d -name '*.bak.*' -print 2>/dev/null | sort || true)"

  if [[ -n "${hits}" ]]; then
    warnx "captured backup directories found"
    printf '%s\n' "${hits}"
  else
    okx "no captured backup directories found"
  fi
}

check_nested_duplicate_roots() {
  local name hits
  local names=(nginx i2pd grafana loki prometheus alloy tor postfix prosody mysql docker)

  for name in "${names[@]}"; do
    hits="$(find "${PUBLIC_DIR}" "${SECRET_DIR}" \
      -type d -path "*/${name}/${name}" -print 2>/dev/null | sort || true)"
    if [[ -n "${hits}" ]]; then
      warnx "nested duplicate root '${name}/${name}' found"
      printf '%s\n' "${hits}"
    fi
  done
}

check_overlapping_i2pd_capture() {
  local has_root=false has_tunnels=false has_tunnels_conf=false

  [[ -d "${PUBLIC_DIR}/i2pd/etc-i2pd" ]] && has_root=true
  [[ -e "${PUBLIC_DIR}/i2pd/tunnels.d" ]] && has_tunnels=true
  [[ -e "${PUBLIC_DIR}/i2pd/tunnels.conf" ]] && has_tunnels_conf=true

  if [[ "${has_root}" == true && ( "${has_tunnels}" == true || "${has_tunnels_conf}" == true ) ]]; then
    warnx "overlapping i2pd capture roots found (etc-i2pd plus sibling tunnels paths)"
    [[ -d "${PUBLIC_DIR}/i2pd/etc-i2pd" ]] && printf '%s\n' "${PUBLIC_DIR}/i2pd/etc-i2pd"
    [[ -e "${PUBLIC_DIR}/i2pd/tunnels.conf" ]] && printf '%s\n' "${PUBLIC_DIR}/i2pd/tunnels.conf"
    [[ -e "${PUBLIC_DIR}/i2pd/tunnels.d" ]] && printf '%s\n' "${PUBLIC_DIR}/i2pd/tunnels.d"
  else
    okx "no overlapping i2pd capture roots found"
  fi
}

check_duplicate_canonical_files() {
  emit_section "Duplicate canonical file checks"

  check_dup_pair() {
    local a="$1" b="$2" label="$3"
    local ha=false hb=false
    [[ -e "${a}" ]] && ha=true
    [[ -e "${b}" ]] && hb=true

    if [[ "${ha}" == true && "${hb}" == true ]]; then
      warnx "${label} exists at two depths"
      printf '%s\n%s\n' "${a}" "${b}"
    else
      okx "${label} not duplicated across checked depths"
    fi
  }

  check_dup_pair \
    "${PUBLIC_DIR}/prometheus/etc-prometheus/prometheus.yml" \
    "${PUBLIC_DIR}/prometheus/etc-prometheus/prometheus/prometheus.yml" \
    "prometheus.yml"

  check_dup_pair \
    "${PUBLIC_DIR}/loki/etc-loki/config.yml" \
    "${PUBLIC_DIR}/loki/etc-loki/loki/config.yml" \
    "loki config.yml"

  check_dup_pair \
    "${PUBLIC_DIR}/grafana/etc-grafana/grafana.ini" \
    "${PUBLIC_DIR}/grafana/etc-grafana/grafana/grafana.ini" \
    "grafana.ini"

  check_dup_pair \
    "${SECRET_DIR}/alloy/etc-alloy/config.alloy" \
    "${SECRET_DIR}/alloy/etc-alloy/alloy/config.alloy" \
    "alloy config.alloy"

  check_dup_pair \
    "${PUBLIC_DIR}/i2pd/etc-i2pd/i2pd.conf" \
    "${PUBLIC_DIR}/i2pd/etc-i2pd/i2pd/i2pd.conf" \
    "i2pd.conf"

  check_dup_pair \
    "${PUBLIC_DIR}/nginx/etc-nginx/nginx.conf" \
    "${PUBLIC_DIR}/nginx/etc-nginx/nginx/nginx.conf" \
    "nginx.conf"
}

emit_section "labunix/sanctum rebuild DB lint"
say "db: ${DB_DIR}"
say "public: ${PUBLIC_DIR}"
say "secret: ${SECRET_DIR}"

emit_section "Backup junk checks"
check_backup_dirs

emit_section "Nested duplicate root checks"
check_nested_duplicate_roots

emit_section "Overlapping capture-root checks"
check_overlapping_i2pd_capture

check_duplicate_canonical_files

emit_section "Summary"
if [[ ${ISSUES} -eq 0 ]]; then
  okx "no DB shape issues detected"
  exit 0
else
  warnx "DB shape issues detected"
  exit 1
fi