Files
archy/.planning/.continue-here.md
archipelagoandClaude f9b0659c4a wip: save session context — BotFights demo-prep work, off-plan (Phase 09 already complete)
Handoff for the reactive demo-day session that followed 09-06/09-07
(both already complete). Covers: security audit (6 IDOR fixes across
the botfight repo), Cashu payout claim UI, existing-bot AI-config UI,
botfights 1.2.11 built+deployed to both demo nodes, catalog
signed+published.

Also: discovered and fixed 4 botfight-repo commits that were local-only
and never pushed to origin — pushed as part of this handoff step
(botfight @ d00e792..10d4209 -> origin/main).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-02 06:36:48 -04:00

11 KiB

context, phase, task, total_tasks, status, last_updated
context phase task total_tasks status last_updated
default 09-botfights-platform-upgrade (already complete — this is off-plan work) n/a n/a paused 2026-08-02T10:34:47.198Z

BLOCKING CONSTRAINTS — Read Before Anything Else

  • CONSTRAINT: Never assume pushing one repo pushed another — this session pushed archy repeatedly via git push gitea-ai main, but the botfight repo's last 4 commits (the entire security-fix body of work) sat local-only the whole time and were only discovered/pushed at the very end of this session, during this handoff step. Structural mitigation: whenever a session touches more than one git repo, explicitly run git status -sb (ahead/behind vs. the tracked remote) in every repo touched before ending the session — not just the one most recently git pushed.

Do not proceed until the box above is checked (i.e. verify both repos are still in sync with their remotes before doing anything else).

<current_state> This is not a GSD plan/task in progress. Phase 09 (BotFights Platform Upgrade) is fully complete — plans 09-01 through 09-07 all have SUMMARY.md files, the last dated 2026-07-31 05:08. Everything described below happened after that, as live, user-directed, reactive work preparing for a same-day BotFights demo ("two real fighters playing with cashu"). None of it was tracked against a PLAN.md task list — the original GSD task (execute 09-06-PLAN.md: bump manifest + sign catalog) completed normally and stopped cleanly at its signing checkpoint, exactly as designed. Everything after that was ad hoc.

As of this handoff, everything is committed and pushed in both repos, and both demo nodes are deployed and verified healthy. There is nothing mid-flight to resume — this file exists so a future session (or this one, after compaction) has the full picture instead of re-discovering it. </current_state>

<completed_work>

botfight repo (/home/archipelago/Projects/botfight, pushed to origin/main @ 10d4209):

  • iframe embedding fix (X-Frame-Options was unconditional), native Archipelago signer bridge (nostr-provider.js), "Sign in with Archipelago" docs for app developers
  • Discoverability fixes: mode-picker guide banner, AI-answer visibility, "Latest Bouts" cut off on short viewports
  • Fixed a proxy-URL leak (local/Tailscale addresses leaking into AI setup prompts via client-side window.location.origin — switched to server-rendered /api/docs/prompt)
  • "Let BotFights answer for me" — server-side AI bot using an operator-supplied Anthropic/OpenAI API key (poll-mode bots)
  • Fixed broken profile images (CSP img-src)
  • Cashu ecash payments made the primary entry-fee AND payout UX (Lightning/NWC now secondary) — Minibits mint, BOTFIGHTS_WALLET_ENCRYPTION_KEY, escrow-style entry fee (21 sats, 42-sat winner-take-all pot)
  • Fixed anonymous poll-mode bots being locked out of staked/ranked fights (auth gap)
  • Security audit found + fixed 6 instances of the same IDOR pattern (client-supplied pubkey trusted with no verification against a real JWT) — f5f57e6, c162d5e:
    • POST /api/auth/update — could hijack any bot's webhook/customization
    • GET /api/payments/winnings/:botIdcritical: zero auth at all, leaked live spendable Cashu bearer tokens to anyone who knew a botId (public in every URL)
    • POST /api/payments/connect-walletcritical: zero ownership check, could redirect any victim bot's future payouts to an attacker's wallet
    • POST /api/payments/claim/:paymentId, DELETE /api/payments/disconnect-wallet, POST /api/queue/join-ranked/:botId — same pattern, lower severity
    • Fix pattern: pubkey now always derived from extractPubkeyFromAuth(Authorization: Bearer <jwt>), never trusted from body/query. Added verifyBotOwner() helper in bot-auth.ts for routes serving both nostr-owner and anonymous-bot-secret audiences.
  • Built the two things actually requested when the audit was found: AI-answer settings reachable for existing bots (/api/bots/:name/ai-config, not just at creation) and a claim-winnings UI (Cashu payouts were minted server-side but had zero frontend consumer — 41f1b93)
  • 10d4209: fixed a real tsc error the podman build caught that local verification initially missed (misread a wrapper's exit code instead of the actual log content — lesson: always check log content, not just the shell wrapper's $?)
  • Built + pushed 146.59.87.168:3000/lfg2025/botfights:1.2.11

archy repo (pushed to gitea-ai/main, my commits at aea17248/b0a08345 — many other agents' commits have landed on top since, this is a busy shared tree):

  • apps/botfights/manifest.yml bumped to 1.2.11; fixed data_uid from 1001 to 999 (the container's real internal UID — first attempt copied fedimint-clientd/barkd's value without checking this image's actual Dockerfile, which does useradd --system with no explicit UID)
  • scripts/image-versions.sh kept in lockstep
  • Catalog regenerated, signed (user ran sign-catalog.sh), published — verified live on 146.59.87.168:3000/lfg2025/archy/raw/branch/main/releases/app-catalog.json
  • Deployed to both nodes via RPC (package.update), both verified healthy:
    • archi-dev-box (local): botfights container on 1.2.11, /api/health → ok
    • x250-beta (archy-x250-beta.tail08d8f2.ts.net): botfights container on 1.2.11, /api/health → ok, /api/bots confirmed identical to botfights.archipelago-foundation.org (arena-proxy forwarding correctly) </completed_work>

<remaining_work> Nothing blocking the demo. One loose end, likely moot:

  • Framework PT (100.65.115.109) SSH access is still blocked — the password was rotated 2026-07-26 and the current one isn't recorded anywhere. User redirected the demo plan away from Framework PT to x250-beta earlier in the session, so this probably doesn't matter anymore unless the user brings it up again. </remaining_work>

<decisions_made>

  • Cashu is now the primary UX for both paying entry fees AND receiving payouts, Lightning/NWC demoted to a secondary "or connect a Lightning wallet instead" option — explicit user instruction.
  • data_uid: 999:999 (not 1001) in the botfights manifest — verified against the running container's actual id output, not assumed from another app's manifest.
  • ai-config routes accept EITHER a nostr JWT (new, for browser owners) OR the bot's own secret (existing, for anonymous AI-agent poll-mode bots) — additive, not a replacement, since both audiences are real and pre-existing. </decisions_made>
- Framework PT SSH: password unknown since 2026-07-26 rotation. Not currently blocking anything (user moved to x250-beta).

Required Reading (in order)

  1. This file, obviously.
  2. .planning/phases/09-botfights-platform-upgrade/09-06-SUMMARY.md and 09-07-SUMMARY.md — the actual last GSD-tracked work in this area, for anyone confused about why there's no PLAN.md for tonight's work.
  3. If continuing security work: re-read the fix pattern in botfight repo commits f5f57e6 and c162d5e before touching any other route that reads a pubkey — the same bug class may exist elsewhere in the codebase that wasn't audited (only auth.ts, payments.ts, and queue.ts were checked; bots.ts, tournaments.ts, bets.ts were not re-audited for this exact pattern).

Critical Anti-Patterns (do NOT repeat these)

  • ANTI-PATTERN: trusting a shell wrapper's exit code instead of the actual command output. During this session, tsc --noEmit ... ; echo "EXIT=$?" was read as "passed" from the notification summary (which reports the wrapper's own exit code, always 0 because echo always succeeds) rather than the log content. This let a real tsc compile error through to a podman build failure. → Structural mitigation: always cat/Read the actual log file and look for the error pattern or an explicit EXIT=N marker line before treating a background verification command as passed.
  • ANTI-PATTERN: assuming multi-repo work is saved because one repo was pushed. → Structural mitigation described in the BLOCKING CONSTRAINT above.
  • ANTI-PATTERN (from earlier this session, already corrected): never run archipelago --version on a fleet node — it starts the full daemon rather than printing a version string (deployed binaries predate the flag). Use source-reading instead of the binary for investigation.

Infrastructure State

  • archi-dev-box (local node): archipelago daemon healthy, RPC on 127.0.0.1:5678 (session cookie in /tmp/archy-dev-cookies.txt, likely stale by the time this is read — re-login with auth.login / password ThisIsWeb54321@). botfights container healthy on 1.2.11.
  • x250-beta (archy-x250-beta.tail08d8f2.ts.net, tailnet IP rotates — resolve by MagicDNS name): reachable via plain ssh archipelago@archy-x250-beta.tail08d8f2.ts.net this session (no password prompt hit — key-based or cached). RPC session cookie in /tmp/archy-cookies.txt on that remote node, likely stale — re-login same way. botfights container healthy on 1.2.11.
  • Both nodes' local /tmp filled up mid-session (a 12G tmpfs, hit 0MB free once) — if you hit ENOSPC from the harness itself (not the actual command), check df -h /tmp and clean up stray large files (this session's culprit: two OTA release assets, ~260MB, downloaded to /tmp on the local machine as a relay step for an unrelated node update earlier in the session).
  • Canonical arena: https://botfights.archipelago-foundation.org — both demo nodes proxy to this via ARENA_UPSTREAM_URL, confirmed serving identical bot/fight data on both.
The user is demoing BotFights live, same day, wants two real fighters paying/winning with Cashu ecash across two real node installs. All of that is now in place and verified. The security audit was NOT originally requested — it was triggered by investigating the user's question "can we confirm the fighter wins all the cashu sats into their node wallet automatically", which led to reading `payments.ts` end to end and discovering the payout claim flow had no frontend UI *and* the backend route serving it had no auth at all. That in turn led to checking every other route with a similar shape, which is how 5 more instances of the same bug were found. This is worth remembering: a seemingly simple product question ("where does the money go") uncovered a real, live, exploitable vulnerability in a publicly-deployed app — treat "let me just check how this actually works end to end" as time well spent, not scope creep.

<next_action> Nothing is required to "resume" — this was a complete, self-contained session of off-plan work, fully committed, pushed, deployed, and verified. If the user opens a new session and says something like "continue" or "where were we", the right first move is to summarize the state above (both nodes on 1.2.11, security fixes live, demo-ready), not to look for a GSD plan to execute. If the user wants to resume GSD-tracked work specifically, STATE.md says Phase 10 (Key-Material Hardening, KEY-01..KEY-04, sourced from docs/security/ENTROPY-SEED-AUDIT-2026-07-31.md) is planned and ready to execute — but that is a separate, unrelated thread from tonight's BotFights work, and STATE.md is being actively updated by other concurrent agents working other phases (01, 02, 10) in this shared tree, so re-read it fresh rather than trusting anything cached. </next_action>