Files
Shadowbroker/UPDATEPROTOCOL.md
T
anoracleofra-code fc9eff865e v0.9.0: in-app auto-updater, ship toggle split, stable entity IDs, performance fixes
New features:
- In-app auto-updater with confirmation dialog, manual download fallback,
  restart polling, and protected file safety net
- Ship layers split into 4 independent toggles (Military/Carriers, Cargo/Tankers,
  Civilian, Cruise/Passenger) with per-category counts
- Stable entity IDs using MMSI/callsign instead of volatile array indices
- Dismissible threat alert bubbles (session-scoped, survives data refresh)

Performance:
- GDELT title fetching is now non-blocking (background enrichment)
- Removed duplicate startup fetch jobs
- Docker healthcheck start_period 15s → 90s

Bug fixes:
- Removed fake intelligence assessment generator (OSINT-only policy)
- Fixed carrier tracker GDELT 429/TypeError crash
- Fixed ETag collision (full payload hash)
- Added concurrent /api/refresh guard

Contributors: @imqdcr (ship split + stable IDs), @csysp (dismissible alerts, PR #48)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Former-commit-id: a2c4c67da54345393f70a9b33b52e7e4fd6c049f
2026-03-13 11:32:16 -06:00

258 lines
8.0 KiB
Markdown

# ShadowBroker Release Protocol
> This document exists because API keys were leaked in release zips v0.5.0, v0.6.0, and briefly v0.8.0.
> Follow this exactly. No shortcuts.
---
## Pre-Release Checklist
### 1. Bump the Version
- **`frontend/package.json`** — update `"version"` field
- **`frontend/src/components/ChangelogModal.tsx`** — update `CURRENT_VERSION` and `STORAGE_KEY`
- **Update `NEW_FEATURES`, `BUG_FIXES`, and `CONTRIBUTORS` arrays** in the changelog modal
### 2. Pull Remote Changes First
```bash
git pull --rebase origin main
```
If there are merge conflicts, resolve them carefully. **Do not blindly delete files during rebase** — this is how the API proxy route (`frontend/src/app/api/[...path]/route.ts`) was accidentally deleted and broke the entire app.
After resolving conflicts, verify critical files still exist:
```bash
ls frontend/src/app/api/\[...path\]/route.ts # API proxy — app is dead without this
ls backend/main.py
ls frontend/src/app/page.tsx
```
### 3. Test Before Committing
```bash
# Backend
cd backend && python -c "import main; print('Backend OK')"
# Frontend
cd frontend && npm run build
```
If the backend fails with a missing module, install it:
```bash
pip install -r requirements.txt
```
---
## Building the Release Zip
### The Command
Run from the project root (`live-risk-dashboard/`):
```bash
7z a -tzip ../ShadowBroker_vX.Y.Z.zip \
-xr!node_modules -xr!.next -xr!__pycache__ -xr!venv -xr!.git -xr!.git_backup \
-xr!*.pyc -xr!*.db -xr!*.sqlite -xr!*.xlsx \
-xr!.env -xr!.env.local -xr!.env.production -xr!.env.development \
-xr!carrier_cache.json -xr!ais_cache.json \
-xr!tmp_fast.json -xr!dump.json -xr!debug_fast.json \
-xr!nyc_sample.json -xr!nyc_full.json \
-xr!server_logs.txt -xr!server_logs2.txt -xr!xlsx_analysis.txt -xr!liveua_test.html \
-xr!merged.txt -xr!recent_commits.txt \
-xr!build_error.txt -xr!build_logs*.txt -xr!build_output.txt -xr!errors.txt \
-xr!geocode_log.txt -xr!tsconfig.tsbuildinfo \
-xr!ShadowBroker_v*.zip \
.
```
### Critical Exclusions (NEVER ship these)
| Pattern | Why |
|---------|-----|
| `.env` | **Contains real API keys** (OpenSky, AIS Stream) |
| `.env.local` | **Contains real API keys** (TomTom, etc.) |
| `.env.production` / `.env.development` | May contain secrets |
| `carrier_cache.json` / `ais_cache.json` | Runtime cache, not source |
| `node_modules/` / `__pycache__/` / `.next/` | Build artifacts |
| `*.db` / `*.sqlite` / `*.xlsx` | Data files, not source |
| `ShadowBroker_v*.zip` | Previous release zips sitting in the project dir |
### What SHOULD Be in the Zip
| File | Required |
|------|----------|
| `frontend/src/app/api/[...path]/route.ts` | **YES** — API proxy, app is dead without it |
| `backend/.env.example` | YES — template for users |
| `.env.example` | YES — template for users |
| `backend/data/plane_alert_db.json` | YES — aircraft database |
| `backend/data/datacenters*.json` | YES — data center layer |
| `backend/data/tracked_names.json` | YES — tracked aircraft names |
| `frontend/src/lib/airlines.json` | YES — airline codes |
| `start.bat` / `start.sh` | YES — launcher scripts |
### Do NOT Use
- **`git archive`** — includes tracked junk, misses untracked essential files
- **`Compress-Archive` (PowerShell)** — has lock file issues, no exclusion control
- **Gemini's zip script** — included test files, debug outputs, `.env` with real keys, and 30+ unnecessary files
---
## Post-Build Audit (MANDATORY)
**Before uploading, always scan the zip for leaks:**
```bash
# Check for .env files (should only show .env.example files)
7z l ShadowBroker_vX.Y.Z.zip | grep -i "\.env" | grep "....A"
# Check for anything with "secret", "key", "token", "credential" in the filename
7z l ShadowBroker_vX.Y.Z.zip | grep -iE "secret|api.key|credential|token" | grep "....A"
# Check the largest files (look for unexpected blobs)
7z l ShadowBroker_vX.Y.Z.zip | grep "....A" | awk '{print $4, $NF}' | sort -rn | head -15
# Verify the API proxy route exists
7z l ShadowBroker_vX.Y.Z.zip | grep "route.ts"
```
**Expected results:**
- `.env` files: ONLY `.env.example` and `next-env.d.ts`
- No files with "secret"/"credential" in the name
- Largest files: `plane_alert_db.json` (~4.6MB), `datacenters_geocoded.json` (~1.2MB), `airlines.json` (~800KB)
- `route.ts` exists under `frontend/src/app/api/[...path]/`
- **Total zip size: ~1.7MB** (as of v0.8.0). If it's 5MB+ something leaked.
---
## Commit, Tag, and Push
```bash
# Stage specific files (NEVER use git add -A)
git add <specific files>
# Commit
git commit -m "v0.X.0: brief description of release"
# Tag
git tag v0.X.0
# Push (pull first if remote has new commits)
git pull --rebase origin main
git push origin main --tags
# If the tag was created before rebase, re-tag on the new HEAD:
git tag -f v0.X.0
git push origin v0.X.0 --force
```
---
## Creating the GitHub Release
### Via GitHub API (when `gh` CLI is unavailable)
```python
# 1. Create the release
import urllib.request, json
body = {
"tag_name": "v0.X.0",
"name": "v0.X.0 — Title Here",
"body": "Release notes here...",
"draft": False,
"prerelease": False
}
# Write to a temp file to avoid JSON escaping hell in bash
with open("release_body.json", "w") as f:
json.dump(body, f)
# POST to GitHub API...
# 2. Upload the zip asset to the release
# Use the upload_url from the release response
```
### Via `gh` CLI (if installed)
```bash
gh release create v0.X.0 ../ShadowBroker_v0.X.0.zip \
--title "v0.X.0 — Title" \
--notes-file RELEASE_NOTES.md
```
---
## Post-Release Verification
After uploading, download the release zip from GitHub and verify it:
```bash
# Download what GitHub is actually serving
curl -L -o /tmp/verify.zip "https://github.com/BigBodyCobain/Shadowbroker/releases/download/v0.X.0/ShadowBroker_v0.X.0.zip"
# Scan for leaks (same audit as above)
7z l /tmp/verify.zip | grep -i "\.env" | grep "....A"
# Compare hash to your local copy
md5sum /tmp/verify.zip ../ShadowBroker_v0.X.0.zip
```
---
## If You Discover a Leak
### Immediate Actions
1. **Rebuild the zip** without the leaked file
2. **Delete the old asset** from the GitHub release via API
3. **Upload the clean zip** as a replacement
4. **Rotate ALL leaked keys immediately:**
- OpenSky: https://opensky-network.org/
- AIS Stream: https://aisstream.io/
- Any other keys found in the leak
5. **Audit ALL other releases** — leaks tend to exist in multiple versions
### Audit All Releases Script
```python
import urllib.request, json
TOKEN = "your_token"
headers = {"Authorization": f"token {TOKEN}", "Accept": "application/vnd.github+json"}
# Get all releases
req = urllib.request.Request(
"https://api.github.com/repos/BigBodyCobain/Shadowbroker/releases",
headers=headers
)
releases = json.loads(urllib.request.urlopen(req).read())
for r in releases:
for asset in r.get("assets", []):
# Download via API
req2 = urllib.request.Request(
asset["url"],
headers={**headers, "Accept": "application/octet-stream"}
)
data = urllib.request.urlopen(req2).read()
filename = f"/tmp/{r['tag_name']}.zip"
with open(filename, "wb") as f:
f.write(data)
print(f"Downloaded {r['tag_name']}: {len(data)} bytes")
# Then run 7z l on each to check for .env files
```
---
## Lessons Learned (v0.8.0 Incident)
1. **Rebasing can silently delete files.** After `git pull --rebase`, always verify that critical files like the API proxy route still exist.
2. **The zip command must explicitly exclude `.env` and `.env.local`.** These files are not in `.gitignore` patterns that 7z understands — you must pass `-xr!.env -xr!.env.local` every time.
3. **Always audit the zip before uploading.** A 10-second grep saves a key rotation.
4. **Never trust another tool's zip output.** Gemini's zip included `.env` with real keys, 30+ test files, debug outputs, and sample JSON dumps.
5. **2,000+ stars means 2,000+ potential eyes on every release.** Treat every zip as if it will be decompiled line by line.