summaryrefslogtreecommitdiff
path: root/scripts/release-check.sh
blob: 223c6b6e624883f947201c68eb8dac002b8b4bcd (plain)
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
#!/usr/bin/env bash
# release-check.sh — MAX25-Stack-Lite offline release gates (no root, no live RF TX).
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"

PASS=0
FAIL=0
WARN=0

ok()   { echo "OK:   $*"; PASS=$((PASS + 1)); }
fail() { echo "FAIL: $*" >&2; FAIL=$((FAIL + 1)); }
warn() { echo "WARN: $*"; WARN=$((WARN + 1)); }

echo "======== MAX25-Stack-Lite release-check ($(tr -d '[:space:]' < VERSION 2>/dev/null || echo '?')) ========"

# --- version ---
if [[ -f VERSION ]]; then
  VER="$(tr -d '[:space:]' < VERSION)"
  if [[ "$VER" == "1.8.0" ]]; then
    ok "VERSION=${VER}"
  elif [[ -n "$VER" ]]; then
    fail "VERSION=${VER} (expected 1.8.0)"
  else
    fail "VERSION file empty"
  fi
else
  fail "VERSION file missing"
fi

# --- required docs (Lite ships a stub docs/, depth lives in the research vault) ---
for doc in README.md CONTRIBUTING.md CHANGELOG.md docs/README.md local/README.md stacks/daemon/README.md stacks/max25-bcpr/README.md include/max25/protocol.md include/max25/packet-radio.md; do
  [[ -f "$doc" ]] && ok "doc $doc" || fail "missing $doc"
done

# --- scripts present + executable (Lite scope only) ---
for script in scripts/max25-lite-setup.sh scripts/test-wizard.sh scripts/run-max25d.sh scripts/run-max25-terminal.sh scripts/max25-ctl scripts/discover-plugins.sh scripts/build.sh scripts/build-all.sh scripts/clean.sh scripts/test.sh scripts/release-check.sh scripts/tx-rx-test.sh scripts/terminology-check.sh scripts/install-max25.sh; do
  if [[ -x "$script" ]]; then
    ok "executable $script"
  else
    fail "not executable: $script"
  fi
done

# --- public terminology gate (§0.16 / §0.19) ---
if [[ -x scripts/terminology-check.sh ]]; then
  if scripts/terminology-check.sh; then
    ok "terminology-check"
  else
    fail "terminology-check"
  fi
else
  fail "scripts/terminology-check.sh missing or not executable"
fi

# --- daemon core files ---
if [[ -x stacks/daemon/max25d ]] && [[ -f stacks/daemon/max25d.py ]]; then
  ok "executable stacks/daemon/max25d launcher + max25d.py"
else
  fail "stacks/daemon/max25d launcher or max25d.py missing"
fi
for f in kiss_bridge.py ax25_codec.py privilege_drop.py; do
  [[ -f "stacks/daemon/${f}" ]] && ok "stacks/daemon/${f}" || fail "missing stacks/daemon/${f}"
done
if python3 stacks/daemon/test_ax25_codec.py >/dev/null 2>&1; then
  ok "ax25_codec unit tests"
else
  fail "ax25_codec unit tests"
fi

# --- Lite INI examples (localhost-only model) ---
for ini in share/max25/max25d.ini.example share/max25/max25d.lite.ini.example share/max25/max25d.lite.bcpr.ini.example share/max25/max25d.lite.crdop.ini.example share/max25-bcpr/max25-bcpr.ini.example stacks/max25-bcpr/share/max25-bcpr.ini.example stacks/crdop/share/crdop.ini.example; do
  [[ -f "$ini" ]] && ok "ini $ini" || fail "missing $ini"
done

# --- localhost TCP in shipped max25d examples ---
for ini in share/max25/max25d.ini.example share/max25/max25d.lite.ini.example share/max25/max25d.lite.bcpr.ini.example share/max25/max25d.lite.crdop.ini.example; do
  if grep -Eq '^[[:space:]]*tcp_host[[:space:]]*=[[:space:]]*0\.0\.0\.0[[:space:]]*$' "$ini"; then
    fail "ini $ini has tcp_host=0.0.0.0 (Lite localhost-only)"
  elif grep -Eq '^[[:space:]]*tcp_host[[:space:]]*=[[:space:]]*127\.0\.0\.1[[:space:]]*$' "$ini"; then
    ok "ini $ini tcp_host=127.0.0.1"
  else
    fail "ini $ini missing tcp_host=127.0.0.1"
  fi
done

if [[ -f share/clients/index.yaml ]] && [[ -f share/clients/tnc2c.yaml ]]; then
  ok "share/clients registry"
else
  warn "share/clients/ (index.yaml / tnc2c.yaml) missing (informational only in Lite)"
fi

# --- out-of-scope surfaces must stay inert (HyBBX co-host, hardware TNC stacks, plugin tree) ---
if [[ -d plugins ]]; then
  fail "plugins/ present — Lite configures devices directly in max25d.ini, no plugin tree expected"
else
  ok "no plugins/ tree (Lite: direct INI device config)"
fi
if [[ -d stacks/tncs ]]; then
  fail "stacks/tncs/ present — TNC2C/pktnc2 hardware stack is out of scope for Lite"
else
  ok "no stacks/tncs/ (hardware TNC stack out of scope for Lite)"
fi
if grep -rq 'hybbx' CMakeLists.txt 2>/dev/null; then
  fail "CMakeLists.txt references hybbx — HyBBX co-host build hooks are out of scope for Lite"
else
  ok "CMakeLists.txt free of hybbx references"
fi
if [[ -f share/hybbx/README.md ]]; then
  ok "share/hybbx/README.md scope note present (kept for upstream sync, not a Lite path)"
else
  warn "share/hybbx/ present without a scope note (see design-principles.md sync policy)"
fi

# --- build artifacts (CMake, Lite target set) ---
BUILD_DIR="build"
if ! cmake -B "${BUILD_DIR}" -DCMAKE_BUILD_TYPE=Release >/dev/null 2>&1; then
  BUILD_DIR="build-default"
  cmake -B "${BUILD_DIR}" -DCMAKE_BUILD_TYPE=Release >/dev/null 2>&1 \
    || fail "cmake configure"
fi
if cmake --build "${BUILD_DIR}" -j"$(nproc 2>/dev/null || echo 2)" >/dev/null 2>&1; then
  ok "cmake build (${BUILD_DIR}/bin/)"
else
  fail "cmake build"
fi
[[ -x "${BUILD_DIR}/bin/max25-terminal" ]] && ok "max25-terminal built" || fail "max25-terminal build"
if [[ -x "${BUILD_DIR}/bin/max25-bcprd" ]] && [[ -x "${BUILD_DIR}/bin/max25-bcprd-init" ]]; then
  ok "max25-bcprd + max25-bcprd-init built (default ON in Lite)"
else
  fail "max25-bcprd / max25-bcprd-init not built (expected default ON — see cmake/MAX25Platform.cmake)"
fi
[[ -f stacks/crdop/share/crdop.ini.example ]] && ok "CRDOP scaffold" || fail "CRDOP scaffold missing"
if [[ -x "${BUILD_DIR}/bin/audio-dummyd" ]]; then
  ok "audio-dummyd binary"
else
  ok "audio-dummyd not in build dir (launcher uses source tree path)"
fi

# --- install tree hygiene: no vendor/ARDOP artifacts, no out-of-scope leakage ---
INSTALL_DIR="${BUILD_DIR}/install-release-check"
rm -rf "${INSTALL_DIR}"
if cmake --install "${BUILD_DIR}" --prefix "${INSTALL_DIR}" >/dev/null 2>&1; then
  ok "cmake --install prefix"
  if find "${INSTALL_DIR}" \( -path '*/vendor/ardopcf/*' -o -name 'ardopcf' -o -name 'crdopc' \) 2>/dev/null | grep -q .; then
    fail "ARDOP vendor artifacts in install tree (forbidden in release)"
  else
    ok "install tree free of ARDOP vendor binaries/sources"
  fi
  if find "${INSTALL_DIR}" -type d -iname 'hybbx' 2>/dev/null | grep -q .; then
    fail "hybbx/ present in install tree (out of scope for Lite)"
  else
    ok "install tree free of hybbx/ directories"
  fi
else
  warn "cmake --install skipped (non-fatal for dev trees)"
fi

# --- offline tests ---
if [[ -x "${BUILD_DIR}/bin/max25-bcprd" ]]; then
  if "${BUILD_DIR}/bin/max25-bcprd" -c stacks/max25-bcpr/share/max25-bcpr.ini.example --dry-run --once >/dev/null 2>&1; then
    ok "max25-bcpr dry-run once"
  else
    fail "max25-bcpr dry-run once"
  fi
else
  warn "max25-bcpr dry-run skipped (not built)"
fi

if python3 stacks/daemon/test_bcpr_backend.py >/dev/null 2>&1; then
  ok "bcpr backend unit tests"
else
  fail "bcpr backend unit tests"
fi

if python3 stacks/daemon/test_crdop_backend.py >/dev/null 2>&1; then
  ok "crdop backend unit tests"
else
  fail "crdop backend unit tests"
fi

if python3 stacks/daemon/test_paths.py >/dev/null 2>&1; then
  ok "daemon path layout unit tests"
else
  fail "daemon path layout unit tests"
fi

if bash scripts/test-wizard.sh >/dev/null 2>&1; then
  ok "wizard non-interactive smoke (serial/baycom/crdop)"
else
  fail "wizard non-interactive smoke"
fi

if bash scripts/discover-plugins.sh --type device >/dev/null 2>&1; then
  ok "discover-plugins.sh --type device"
else
  warn "discover-plugins.sh --type device (no manifest — expected in Lite, see script output)"
fi

chmod +x stacks/daemon/max25d stacks/daemon/max25d.py 2>/dev/null || true
[[ -x stacks/daemon/max25d ]] && [[ -f stacks/daemon/max25d.py ]] && ok "max25d ready" || fail "max25d"
if [[ -L "${BUILD_DIR}/bin/max25-client" ]] || [[ -x "${BUILD_DIR}/bin/max25-client" ]]; then
  ok "max25-client symlink"
else
  warn "max25-client symlink missing until cmake --install"
fi
if MAX25_TERMINAL="${PWD}/${BUILD_DIR}/bin/max25-terminal" \
   bash stacks/terminal/test-terminal.sh >/dev/null 2>&1; then
  ok "max25-terminal TCP probe"
else
  fail "max25-terminal TCP probe"
fi

if python3 stacks/daemon/test_proto.py >/dev/null 2>&1; then
  ok "max25d protocol smoke"
else
  fail "max25d protocol smoke"
fi

if python3 stacks/daemon/test_auth.py >/dev/null 2>&1; then
  ok "max25d TCP auth smoke"
else
  fail "max25d TCP auth smoke"
fi

# --- RX before TX gate (§0.20) — offline check only, no live RF TX here ---
if bash scripts/tx-rx-test.sh >/dev/null 2>&1; then
  ok "tx-rx-test L0 offline (RX before TX posture)"
else
  fail "tx-rx-test L0 offline"
fi

if python3 stacks/daemon/test_serial_watch.py >/dev/null 2>&1; then
  ok "max25d serial watch tests"
else
  fail "max25d serial watch tests"
fi

# --- AmigaOS terminal (optional cross-build) ---
if [[ -x /opt/amiga/bin/m68k-amigaos-gcc ]]; then
  if bash scripts/build-amiga-terminal.sh >/dev/null 2>&1; then
    ok "max25-terminal AmigaOS cross-build"
  else
    fail "max25-terminal AmigaOS cross-build"
  fi
else
  warn "Amiga SDK not at /opt/amiga; skip Amiga terminal build (optional)"
fi

# --- CI workflow ---
[[ -f .github/workflows/ci.yml ]] && ok "ci workflow" || warn "missing .github/workflows/ci.yml"

echo "======== release-check: ${PASS} passed, ${FAIL} failed, ${WARN} warnings ========"
if [[ "$FAIL" -gt 0 ]]; then
  exit 1
fi
exit 0
git clone -b <branch> https://cgit.mode42.com/<repo>.git
git clone -b <branch> git://cgit.mode42.com/<repo>.git

info@mode42.com