b941223c88
Three plumbing fixes + one ops doc that close the gaps from the audit. scripts/rescore_v5.py Was overwriting only signal/conf/reasoning/sentiment/relevant/ prefilter_reason/analysis_version. Now also persists target_asset, category, expected_move_pct — without these the bot can't route rescored posts correctly (would silently fall back to BTC). app/schemas.py + app/api/posts.py TrumpPost response model didn't expose target_asset/category/ expected_move_pct, so the frontend had no way to display "this signal will trade SOL". Added the three fields + mapping in _post_to_schema(). Pre-v5 posts return null. No frontend changes yet — display work is a follow-up. app/services/hyperliquid.py HL caps max leverage per asset (BTC/ETH 50×, SOL 20×, memes 3-5×). set_leverage() always tried to push self._leverage — if user set 30× and bot routed to TRUMP, HL rejected the order and the trade silently dropped. Added _get_max_leverage() (queries meta()'s maxLeverage field) and _clip_leverage() that caps to HL's max. set_leverage now returns the effective leverage so callers can use it for notional sizing if needed. deploy/ENCRYPTION_KEY_BACKUP.md Documented mandatory backup procedure for the symmetric key that encrypts every user's HL API key. Lost key = all users' bots dead with no recovery. Includes rotation procedure + quarterly test step + things-not-to-do list. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
75 lines
2.9 KiB
Markdown
75 lines
2.9 KiB
Markdown
# ENCRYPTION_KEY backup procedure — DO NOT SKIP
|
|
|
|
The `ENCRYPTION_KEY` env var encrypts every user's Hyperliquid API key
|
|
before it touches the database. If this key is **lost** or **rotated
|
|
without re-encrypting** the existing rows, every active user's bot
|
|
permanently stops trading — there is no recovery path. This is the
|
|
single most-load-bearing secret in the project.
|
|
|
|
## What it looks like
|
|
|
|
```
|
|
ENCRYPTION_KEY=1cf813d6790cc1b1c0981951703ca387d58321d81dc9b5b4982c07487edc478e
|
|
```
|
|
|
|
A 64-char hex string (32 bytes). Used by `app/services/crypto.py` via
|
|
Fernet-equivalent symmetric encryption.
|
|
|
|
## Backup requirements (mandatory before going live)
|
|
|
|
Store the production value in **at least two locations**, at least one
|
|
of which is **offline / non-cloud**:
|
|
|
|
### 1. Password manager (1Password / Bitwarden / KeePass)
|
|
- Item type: "Secure Note"
|
|
- Title: `TrumpSignal — ENCRYPTION_KEY (production)`
|
|
- Body: the 64-char hex value
|
|
- Add note: "Lost = every user's bot dead. No way to recover."
|
|
- Tag/folder for fast retrieval
|
|
|
|
### 2. Offline physical backup
|
|
Pick one (or do both):
|
|
- **Paper**: print the key on a single sheet, store in a locked drawer
|
|
/ safe / safety deposit box. Label: "TrumpSignal encryption key —
|
|
do not discard, do not photograph, do not type into computers."
|
|
- **Hardware key**: write to a USB drive that lives offline, kept in
|
|
the same safe. Label and date it.
|
|
|
|
### 3. (Optional) Co-founder / trusted-party split
|
|
If multiple humans run the project: split the key (Shamir's Secret
|
|
Sharing or just give halves to two people) so no single person can
|
|
walk off with it AND no single person can lose all copies.
|
|
|
|
## Before any rotation
|
|
|
|
Rotating the key is **not free**. To rotate:
|
|
|
|
1. Generate `NEW_KEY`.
|
|
2. **Decrypt every existing `subscriptions.hl_api_key` with the old
|
|
key**, re-encrypt with the new key, write back. (Script not
|
|
shipped — has to be written carefully.)
|
|
3. Only after the migration completes, swap env var and restart.
|
|
4. Update both backup locations with `NEW_KEY`.
|
|
5. Securely destroy the old key copies after a 30-day cool-off
|
|
(during which you confirm no users got broken).
|
|
|
|
If you skip step 2, every existing user's HL key becomes garbage on
|
|
the new server and their bot silently stops working.
|
|
|
|
## How to test backups (do this once a quarter)
|
|
|
|
1. Pull the key out of password manager → match against the env var
|
|
on the running server.
|
|
2. Pull the offline copy → match against the password-manager copy.
|
|
3. Confirm both match. If any drift, sync immediately — never assume
|
|
the running server has the "true" copy without verifying.
|
|
|
|
## What NOT to do
|
|
|
|
- ❌ Don't paste the key into Slack / Discord / email.
|
|
- ❌ Don't commit the key to git (`.env` is in `.gitignore`, but
|
|
double-check before any `git add -A`).
|
|
- ❌ Don't share via screenshot — keys can be OCR'd from anywhere.
|
|
- ❌ Don't store only on the server — if the server dies, you lose it.
|
|
- ❌ Don't rotate "just because" — it's expensive and risky.
|