diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl deleted file mode 100644 index e28842b..0000000 --- a/.beads/issues.jsonl +++ /dev/null @@ -1,49 +0,0 @@ -{"_type":"issue","id":"risus-cli-r9j","title":"Fix duplicate battle state screen on connect and after actions","description":"When connecting as test user, battle state screen renders twice: first with full menu (items 1-6), then 1-3 seconds later a second render appears below without menu options. Same happens after any action (add player, switch cliche, reduce dice, save, load). Always exactly two screens total. Only the second prompt accepts input.\n\nRoot cause: _input_with_refresh() (risus.py:77) calls show_state() on server broadcast without calling clear() first and without reprinting the menu. The old render stays, new state appends below.\n\nFix needed: on refresh in _input_with_refresh, clear screen and reprint full menu + state, not just state. Consider accepting a redraw callable parameter.","status":"closed","priority":1,"issue_type":"bug","assignee":"galadriel","owner":"galadriel@example.com","created_at":"2026-05-04T17:41:29Z","created_by":"galadriel","updated_at":"2026-05-04T17:48:10Z","started_at":"2026-05-04T17:48:08Z","closed_at":"2026-05-04T17:48:10Z","close_reason":"Fixed: _input_with_refresh now accepts redraw callable; main() passes _redraw_main which calls clear()+show_state()+menu. Regression test T007b added.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-7n5","title":"Fix macOS zip: unzip into named directory not dist/","description":"When a user unzips risus-macos-arm64.zip they get a dist/ directory — this is a CI build artifact path leaking into the release. Fix: stage the binary into /tmp/risus-macos-arm64/ before running ditto, so the zip contains risus-macos-arm64/risus-macos-arm64 and extracts into a sensibly named directory.\n\nChange is one step in .github/workflows/release.yml (Package signed binary). See specs/006-zip-directory-structure/ for spec, plan, and tasks.","status":"closed","priority":2,"issue_type":"feature","assignee":"galadriel","owner":"galadriel@example.com","created_at":"2026-05-04T07:00:22Z","created_by":"galadriel","updated_at":"2026-05-04T12:32:59Z","started_at":"2026-05-04T12:31:07Z","closed_at":"2026-05-04T12:32:59Z","close_reason":"Stage binary in /tmp/risus-macos-arm64/ before ditto; zip now extracts to risus-macos-arm64/ not dist/","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-70j","title":"Conditional signing: gate macOS steps on APPLE_CERTIFICATE secret","description":"Gate all macOS signing steps in release.yml on env.APPLE_CERTIFICATE != '' so branches/PRs without secrets produce an unsigned binary instead of failing. Add an assert step on tag pushes that fails loudly if secrets are missing, preventing accidental unsigned release artifact.\n\nChanges to .github/workflows/release.yml:\n- All macOS signing steps (import-codesign-certs, sign, package, notarize, clean up, verify): add env.APPLE_CERTIFICATE != '' to the if condition\n- Add 'Assert signing secrets' step with if: runner.os == 'macOS' \u0026\u0026 github.ref_type == 'tag' that checks APPLE_CERTIFICATE env var and exits 1 with clear error if empty\n\nSpec: specs/005-macos-signed-release/tasks.md T015","status":"closed","priority":2,"issue_type":"task","assignee":"galadriel","owner":"galadriel@example.com","created_at":"2026-05-04T06:31:24Z","created_by":"galadriel","updated_at":"2026-05-04T12:32:57Z","started_at":"2026-05-04T12:31:05Z","closed_at":"2026-05-04T12:32:57Z","close_reason":"Gated all macOS signing steps on env.APPLE_CERTIFICATE != ''; added Assert step for tag pushes; unsigned fallback for branch builds","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-q0d","title":"T009: Add post-notarization codesign/spctl verification step","description":"speckit:005-macos-signed-release | T009 | Add post-notarization verification step (if: runner.os == macOS) in .github/workflows/release.yml running codesign --verify and spctl --assess","status":"closed","priority":2,"issue_type":"task","owner":"galadriel@example.com","created_at":"2026-05-03T19:21:13Z","created_by":"galadriel","updated_at":"2026-05-03T19:26:09Z","closed_at":"2026-05-03T19:26:09Z","close_reason":"Closed","dependencies":[{"issue_id":"risus-cli-q0d","depends_on_id":"risus-cli-77n","type":"blocks","created_at":"2026-05-03T21:22:15Z","created_by":"galadriel","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"risus-cli-sa3","title":"T008: Update macOS artifact upload to use zip in release.yml","description":"speckit:005-macos-signed-release | T008 | Update macOS artifact upload step in .github/workflows/release.yml to upload risus-macos-arm64.zip and .sha256","status":"closed","priority":2,"issue_type":"task","owner":"galadriel@example.com","created_at":"2026-05-03T19:21:12Z","created_by":"galadriel","updated_at":"2026-05-03T19:26:09Z","closed_at":"2026-05-03T19:26:09Z","close_reason":"Closed","dependencies":[{"issue_id":"risus-cli-sa3","depends_on_id":"risus-cli-457","type":"blocks","created_at":"2026-05-03T21:22:20Z","created_by":"galadriel","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"risus-cli-457","title":"T007: Update checksum step to hash zip on macOS in release.yml","description":"speckit:005-macos-signed-release | T007 | Update Compute checksum step in .github/workflows/release.yml to hash risus-macos-arm64.zip on macOS","status":"closed","priority":2,"issue_type":"task","owner":"galadriel@example.com","created_at":"2026-05-03T19:21:10Z","created_by":"galadriel","updated_at":"2026-05-03T19:26:08Z","closed_at":"2026-05-03T19:26:08Z","close_reason":"Closed","dependencies":[{"issue_id":"risus-cli-457","depends_on_id":"risus-cli-77n","type":"blocks","created_at":"2026-05-03T21:22:14Z","created_by":"galadriel","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"risus-cli-77n","title":"T006: Add xcrun notarytool submit step to release.yml","description":"speckit:005-macos-signed-release | T006 | Add xcrun notarytool submit --wait step (if: runner.os == macOS, timeout-minutes: 15) in .github/workflows/release.yml","status":"closed","priority":2,"issue_type":"task","owner":"galadriel@example.com","created_at":"2026-05-03T19:21:09Z","created_by":"galadriel","updated_at":"2026-05-03T19:26:08Z","closed_at":"2026-05-03T19:26:08Z","close_reason":"Closed","dependencies":[{"issue_id":"risus-cli-77n","depends_on_id":"risus-cli-7bc","type":"blocks","created_at":"2026-05-03T21:22:13Z","created_by":"galadriel","metadata":"{}"}],"dependency_count":1,"dependent_count":2,"comment_count":0} -{"_type":"issue","id":"risus-cli-7bc","title":"T005: Add ditto zip step to release.yml after signing","description":"speckit:005-macos-signed-release | T005 | Add ditto -c -k --keepParent step (if: runner.os == macOS) after signing in .github/workflows/release.yml","status":"closed","priority":2,"issue_type":"task","owner":"galadriel@example.com","created_at":"2026-05-03T19:21:08Z","created_by":"galadriel","updated_at":"2026-05-03T19:26:07Z","closed_at":"2026-05-03T19:26:07Z","close_reason":"Closed","dependencies":[{"issue_id":"risus-cli-7bc","depends_on_id":"risus-cli-161","type":"blocks","created_at":"2026-05-03T21:22:08Z","created_by":"galadriel","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"risus-cli-161","title":"T004: Add codesign step to release.yml after binary rename","description":"speckit:005-macos-signed-release | T004 | Add codesign --force --verbose --timestamp --sign step (if: runner.os == macOS) after binary rename in .github/workflows/release.yml","status":"closed","priority":2,"issue_type":"task","owner":"galadriel@example.com","created_at":"2026-05-03T19:21:06Z","created_by":"galadriel","updated_at":"2026-05-03T19:26:07Z","closed_at":"2026-05-03T19:26:07Z","close_reason":"Closed","dependencies":[{"issue_id":"risus-cli-161","depends_on_id":"risus-cli-p7l","type":"blocks","created_at":"2026-05-03T21:22:07Z","created_by":"galadriel","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"risus-cli-p7l","title":"T002: Add apple-actions/import-codesign-certs@v7 to release.yml","description":"speckit:005-macos-signed-release | T002 | Add apple-actions/import-codesign-certs@v7 step (if: runner.os == macOS) to macOS matrix job in .github/workflows/release.yml","status":"closed","priority":2,"issue_type":"task","owner":"galadriel@example.com","created_at":"2026-05-03T19:21:05Z","created_by":"galadriel","updated_at":"2026-05-03T19:26:06Z","closed_at":"2026-05-03T19:26:06Z","close_reason":"Closed","dependencies":[{"issue_id":"risus-cli-p7l","depends_on_id":"risus-cli-2my","type":"blocks","created_at":"2026-05-03T21:21:59Z","created_by":"galadriel","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"risus-cli-6rk","title":"T014: Run manual end-to-end verification per quickstart.md","description":"speckit:005-macos-signed-release | T014 | Run manual end-to-end verification per specs/005-macos-signed-release/quickstart.md against first notarized release artifact","status":"open","priority":2,"issue_type":"task","owner":"galadriel@example.com","created_at":"2026-05-03T19:20:59Z","created_by":"galadriel","updated_at":"2026-05-03T19:20:59Z","dependencies":[{"issue_id":"risus-cli-6rk","depends_on_id":"risus-cli-t58","type":"blocks","created_at":"2026-05-03T21:22:33Z","created_by":"galadriel","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-t58","title":"T013: Update macOS job name to Build \u0026 Sign in release.yml","description":"speckit:005-macos-signed-release | T013 | Update macOS entry in release workflow job name from Build (macos-latest) to Build \u0026 Sign (macos-latest)","status":"closed","priority":2,"issue_type":"task","owner":"galadriel@example.com","created_at":"2026-05-03T19:20:58Z","created_by":"galadriel","updated_at":"2026-05-03T19:26:11Z","closed_at":"2026-05-03T19:26:11Z","close_reason":"Closed","dependencies":[{"issue_id":"risus-cli-t58","depends_on_id":"risus-cli-0op","type":"blocks","created_at":"2026-05-03T21:22:24Z","created_by":"galadriel","metadata":"{}"},{"issue_id":"risus-cli-t58","depends_on_id":"risus-cli-92w","type":"blocks","created_at":"2026-05-03T21:22:26Z","created_by":"galadriel","metadata":"{}"},{"issue_id":"risus-cli-t58","depends_on_id":"risus-cli-hb2","type":"blocks","created_at":"2026-05-03T21:22:25Z","created_by":"galadriel","metadata":"{}"},{"issue_id":"risus-cli-t58","depends_on_id":"risus-cli-q0d","type":"blocks","created_at":"2026-05-03T21:22:23Z","created_by":"galadriel","metadata":"{}"},{"issue_id":"risus-cli-t58","depends_on_id":"risus-cli-sa3","type":"blocks","created_at":"2026-05-03T21:22:21Z","created_by":"galadriel","metadata":"{}"}],"dependency_count":5,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"risus-cli-92w","title":"T012: Add pre-tag secrets check to AGENTS.md Release Checklist","description":"speckit:005-macos-signed-release | T012 | Add pre-tag check to Release Checklist in AGENTS.md: verify all 6 Apple signing secrets configured","status":"closed","priority":2,"issue_type":"task","assignee":"galadriel","owner":"galadriel@example.com","created_at":"2026-05-03T19:20:57Z","created_by":"galadriel","updated_at":"2026-05-03T19:26:11Z","started_at":"2026-05-03T19:24:04Z","closed_at":"2026-05-03T19:26:11Z","close_reason":"Closed","dependencies":[{"issue_id":"risus-cli-92w","depends_on_id":"risus-cli-2my","type":"blocks","created_at":"2026-05-03T21:22:02Z","created_by":"galadriel","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"risus-cli-hb2","title":"T011: Update build.yml on.push.branches for feature branch CI","description":"speckit:005-macos-signed-release | T011 | Update on.push.branches in .github/workflows/build.yml to add 005-macos-signed-release","status":"closed","priority":2,"issue_type":"task","assignee":"galadriel","owner":"galadriel@example.com","created_at":"2026-05-03T19:20:55Z","created_by":"galadriel","updated_at":"2026-05-03T19:26:10Z","started_at":"2026-05-03T19:24:03Z","closed_at":"2026-05-03T19:26:10Z","close_reason":"Closed","dependencies":[{"issue_id":"risus-cli-hb2","depends_on_id":"risus-cli-2my","type":"blocks","created_at":"2026-05-03T21:22:01Z","created_by":"galadriel","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"risus-cli-0op","title":"T010: Add Signing Setup subsection to AGENTS.md Release Checklist","description":"speckit:005-macos-signed-release | T010 | Add Signing Setup subsection to Release Checklist in AGENTS.md documenting 6 required GitHub Actions secrets","status":"closed","priority":2,"issue_type":"task","assignee":"galadriel","owner":"galadriel@example.com","created_at":"2026-05-03T19:20:54Z","created_by":"galadriel","updated_at":"2026-05-03T19:26:10Z","started_at":"2026-05-03T19:24:03Z","closed_at":"2026-05-03T19:26:10Z","close_reason":"Closed","dependency_count":0,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"risus-cli-2my","title":"T001: Create build/entitlements.plist with 4 Hardened Runtime entitlements","description":"speckit:005-macos-signed-release | T001 | Create build/entitlements.plist with 4 entitlements required for PyInstaller Python runtime under Hardened Runtime","status":"closed","priority":2,"issue_type":"task","assignee":"galadriel","owner":"galadriel@example.com","created_at":"2026-05-03T19:20:52Z","created_by":"galadriel","updated_at":"2026-05-03T19:26:06Z","started_at":"2026-05-03T19:24:01Z","closed_at":"2026-05-03T19:26:06Z","close_reason":"Closed","dependency_count":0,"dependent_count":3,"comment_count":0} -{"_type":"issue","id":"risus-cli-znu","title":"Fix silent connection failure in WSClient.start()","description":"WSClient.start() treats a 'disconnected' frame as a successful connection. When the WebSocket handshake fails (SSL, DNS, network), _async_run swallows the exception and puts a 'disconnected' frame in the inbox. start() reads it, doesn't recognise it as failure, puts it back and returns — showing the user a working menu that is not actually connected to any server.","acceptance_criteria":"1. When connection fails for any reason (SSL, DNS, network), the program exits immediately with a clear error message instead of showing the menu. 2. Error message reads: 'Connection to {server} failed — check address, network, and that the server is running.' 3. WSClient emits a 'connected' sentinel frame after successful WebSocket handshake, before reader starts. 4. start() raises TimeoutError immediately on 'disconnected' frame rather than waiting the full timeout. 5. Existing tests pass. 6. Manual test: wrong server address → immediate exit with correct message.","status":"closed","priority":2,"issue_type":"bug","owner":"galadriel@example.com","created_at":"2026-05-03T17:23:42Z","created_by":"galadriel","updated_at":"2026-05-03T17:26:45Z","closed_at":"2026-05-03T17:26:45Z","close_reason":"connected sentinel + immediate TimeoutError on disconnected + updated error message; 77 unit tests pass","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-cn0","title":"T026: Validate quickstart.md local dev scenario","description":"speckit:004-secure-session | T026 | Validate quickstart.md scenario with --token dev-token-for-testing uses ws://","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:54Z","created_by":"Eudicy","updated_at":"2026-05-03T08:07:52Z","started_at":"2026-05-03T08:07:10Z","closed_at":"2026-05-03T08:07:52Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-ddm","title":"T025: Verify server logs show reason but not token","description":"speckit:004-secure-session | T025 | Verify server logs show reason=token_absent or reason=token_mismatch but never token value","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:53Z","created_by":"Eudicy","updated_at":"2026-05-03T08:07:52Z","started_at":"2026-05-03T08:07:10Z","closed_at":"2026-05-03T08:07:52Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-w49","title":"T024: Run E2E test suite with container stack","description":"speckit:004-secure-session | T024 | Run E2E tests with RISUS_TOKEN=testtoken and container stack","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:52Z","created_by":"Eudicy","updated_at":"2026-05-03T10:47:30Z","started_at":"2026-05-03T08:07:09Z","closed_at":"2026-05-03T10:47:30Z","close_reason":"E2E suite passed: 11 tests in 42s (CONTAINER_ENGINE=podman RISUS_TOKEN=testtoken)","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-6pw","title":"T023: Run full unit test suite","description":"speckit:004-secure-session | T023 | Run pytest tests/unit -q and verify all pass","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:51Z","created_by":"Eudicy","updated_at":"2026-05-03T08:07:51Z","started_at":"2026-05-03T08:07:08Z","closed_at":"2026-05-03T08:07:51Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-wqr","title":"T022: Write load_battle() URL derivation unit tests","description":"speckit:004-secure-session | T022 | Write load_battle() URL derivation unit tests in tests/unit/test_token_auth.py for US4","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:50Z","created_by":"Eudicy","updated_at":"2026-05-03T08:06:57Z","started_at":"2026-05-03T08:03:57Z","closed_at":"2026-05-03T08:06:57Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-ngh","title":"T021: Write scheme detection unit tests","description":"speckit:004-secure-session | T021 | Write scheme detection unit tests in tests/unit/test_token_auth.py for US4","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:48Z","created_by":"Eudicy","updated_at":"2026-05-03T08:06:57Z","started_at":"2026-05-03T08:03:56Z","closed_at":"2026-05-03T08:06:57Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-8n5","title":"T020: Create Caddyfile reverse proxy config","description":"speckit:004-secure-session | T020 | Create Caddyfile with TLS via Let's Encrypt and reverse proxy to 127.0.0.1:8765","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:47Z","created_by":"Eudicy","updated_at":"2026-05-03T08:06:56Z","started_at":"2026-05-03T08:03:55Z","closed_at":"2026-05-03T08:06:56Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-5qy","title":"T019: Update docker-compose.yml for secure deployment","description":"speckit:004-secure-session | T019 | Update docker-compose.yml with 127.0.0.1 binding, RISUS_TOKEN env, and Caddy service","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:46Z","created_by":"Eudicy","updated_at":"2026-05-03T08:06:56Z","started_at":"2026-05-03T08:03:54Z","closed_at":"2026-05-03T08:06:56Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-vwp","title":"T018: Fix load_battle() URL derivation in risus.py","description":"speckit:004-secure-session | T018 | Fix load_battle() to replace wss:// before ws:// to avoid double-replace bug in risus.py","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:45Z","created_by":"Eudicy","updated_at":"2026-05-03T08:06:55Z","started_at":"2026-05-03T08:03:54Z","closed_at":"2026-05-03T08:06:55Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-849","title":"T017: Implement scheme detection in ws_client.py","description":"speckit:004-secure-session | T017 | Implement ws:// vs wss:// scheme detection via colon heuristic in client/ws_client.py","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:44Z","created_by":"Eudicy","updated_at":"2026-05-03T08:06:55Z","started_at":"2026-05-03T08:03:52Z","closed_at":"2026-05-03T08:06:55Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-nrn","title":"T016: Add --token test cases to test_startup.py","description":"speckit:004-secure-session | T016 | Add --token unit test cases to tests/unit/test_startup.py for US3","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:42Z","created_by":"Eudicy","updated_at":"2026-05-03T08:03:08Z","started_at":"2026-05-03T08:02:32Z","closed_at":"2026-05-03T08:03:08Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-hsw","title":"T015: Add --token argument to argparse in risus.py","description":"speckit:004-secure-session | T015 | Add --token CLI argument to argparse with precedence: CLI \u003e config \u003e prompt in risus.py","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:41Z","created_by":"Eudicy","updated_at":"2026-05-03T08:03:08Z","started_at":"2026-05-03T08:02:31Z","closed_at":"2026-05-03T08:03:08Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-4hd","title":"T014: Add token prompt cases to test_startup.py","description":"speckit:004-secure-session | T014 | Add token prompt unit test cases to tests/unit/test_startup.py for US2","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:40Z","created_by":"Eudicy","updated_at":"2026-05-03T08:02:18Z","started_at":"2026-05-03T07:46:29Z","closed_at":"2026-05-03T08:02:18Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-pre","title":"T013: Add token read/write cases to test_config.py","description":"speckit:004-secure-session | T013 | Add token read/write unit test cases to tests/unit/test_config.py for US2","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:37Z","created_by":"Eudicy","updated_at":"2026-05-03T08:02:17Z","started_at":"2026-05-03T07:46:28Z","closed_at":"2026-05-03T08:02:17Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-bjf","title":"T012: Wire token into risus.py startup flow","description":"speckit:004-secure-session | T012 | Wire token read from config, _prompt_token, atexit write_config, and rejected token not saved in risus.py","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:36Z","created_by":"Eudicy","updated_at":"2026-05-03T08:02:17Z","started_at":"2026-05-03T07:46:26Z","closed_at":"2026-05-03T08:02:17Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-jxu","title":"T011: Write E2E tests for User Story 1","description":"speckit:004-secure-session | T011 | Write E2E tests in tests/e2e/test_token_auth.py for correct/wrong/absent token scenarios","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:34Z","created_by":"Eudicy","updated_at":"2026-05-03T07:45:24Z","started_at":"2026-05-03T07:39:34Z","closed_at":"2026-05-03T07:45:24Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-f22","title":"T010: Write server token validation unit tests","description":"speckit:004-secure-session | T010 | Write server token validation unit tests in tests/unit/test_token_auth.py for US1","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:33Z","created_by":"Eudicy","updated_at":"2026-05-03T07:45:23Z","started_at":"2026-05-03T07:39:33Z","closed_at":"2026-05-03T07:45:23Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-2q9","title":"T009: Implement connect_or_die() in risus.py","description":"speckit:004-secure-session | T009 | Implement connect_or_die(server, name, token) in risus.py that catches AuthError and re-prompts","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:32Z","created_by":"Eudicy","updated_at":"2026-05-03T07:45:23Z","started_at":"2026-05-03T07:39:32Z","closed_at":"2026-05-03T07:45:23Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-018","title":"T008: Catch 4401 ConnectionClosedError in ws_client.py","description":"speckit:004-secure-session | T008 | Catch websockets.exceptions.ConnectionClosedError with rcvd.code==4401 in ws_client.py _async_run(), put auth_failed in inbox","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:31Z","created_by":"Eudicy","updated_at":"2026-05-03T07:45:22Z","started_at":"2026-05-03T07:39:31Z","closed_at":"2026-05-03T07:45:22Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-gsd","title":"T007: Pass ?token= query param in ws_client.py start()","description":"speckit:004-secure-session | T007 | Pass ?token={token} query parameter when building WebSocket URI in client/ws_client.py start() method","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:30Z","created_by":"Eudicy","updated_at":"2026-05-03T07:45:22Z","started_at":"2026-05-03T07:39:31Z","closed_at":"2026-05-03T07:45:22Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-lsk","title":"T006: Add token validation to server/ws.py handle()","description":"speckit:004-secure-session | T006 | Add token validation after ws.accept() with 3s delay and 4401 close in server/ws.py","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:28Z","created_by":"Eudicy","updated_at":"2026-05-03T07:45:21Z","started_at":"2026-05-03T07:39:29Z","closed_at":"2026-05-03T07:45:21Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-107","title":"T005: Extend read_config/write_config with token field","description":"speckit:004-secure-session | T005 | Extend read_config() and write_config() in client/config.py to accept and return a token field","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:27Z","created_by":"Eudicy","updated_at":"2026-05-03T07:38:17Z","started_at":"2026-05-03T07:36:22Z","closed_at":"2026-05-03T07:38:17Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-ebk","title":"T004: Implement _prompt_token() in risus.py","description":"speckit:004-secure-session | T004 | Implement _prompt_token(saved: str | None) -\u003e str in risus.py with 16-char minimum validation","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:26Z","created_by":"Eudicy","updated_at":"2026-05-03T07:38:16Z","started_at":"2026-05-03T07:36:22Z","closed_at":"2026-05-03T07:38:16Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-2es","title":"T003: Add AuthError class to client/ws_client.py","description":"speckit:004-secure-session | T003 | Add class AuthError(Exception): pass to client/ws_client.py","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:25Z","created_by":"Eudicy","updated_at":"2026-05-03T07:38:16Z","started_at":"2026-05-03T07:36:21Z","closed_at":"2026-05-03T07:38:16Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-5nk","title":"T002: Create tests/e2e/test_token_auth.py","description":"speckit:004-secure-session | T002 | Create tests/e2e/test_token_auth.py with module-level docstring and empty test skeleton","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:24Z","created_by":"Eudicy","updated_at":"2026-05-03T07:38:15Z","started_at":"2026-05-03T07:36:20Z","closed_at":"2026-05-03T07:38:15Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-6dr","title":"T001: Create tests/unit/test_token_auth.py","description":"speckit:004-secure-session | T001 | Create tests/unit/test_token_auth.py with module-level docstring and empty test skeleton","status":"closed","priority":2,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T07:33:21Z","created_by":"Eudicy","updated_at":"2026-05-03T07:38:15Z","started_at":"2026-05-03T07:36:18Z","closed_at":"2026-05-03T07:38:15Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-255","title":"Update quickstart.md with cert export corrections","description":"Update specs/005-macos-signed-release/quickstart.md with corrections from setup walkthrough session.\n\nCorrections to apply:\n1. Keychain Access shows Developer ID cert under 'Certificates' tab, NOT 'My Certificates' (two nearly identical tabs exist — common confusion point)\n2. After adding APPLE_CERTIFICATE secret to GitHub, remind user to delete the local .p12 file — it is NOT encrypted at rest and contains the private key\n\nSee AGENTS.md for session workflow.","notes":"Also add to quickstart: APPLE_SIGNING_IDENTITY secret = full cert identity string (format: 'Developer ID Application: Name (TeamID)'). Verify exact string via: security find-identity -v -p codesigning. Do NOT use APPLE_TEAM_ID for --sign flag — team ID alone is not a valid identity.","status":"closed","priority":3,"issue_type":"task","owner":"galadriel@example.com","created_at":"2026-05-04T03:36:39Z","created_by":"galadriel","updated_at":"2026-05-04T04:47:54Z","closed_at":"2026-05-04T04:47:54Z","close_reason":"All corrections applied: quickstart rewritten with Xcode export method, APPLE_SIGNING_IDENTITY, Request Access gate, .p12 delete warning, version bump step, spctl note. PLAYER.md, AGENTS.md, spec003 quickstart all updated for notarized binary.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-m6m","title":"Bump version to 1.0.3 after fixing silent connection failure","description":"After risus-cli-znu (silent connection failure fix) and risus-cli-7yn (troubleshooting docs) are merged, bump pyproject.toml version to 1.0.3 and tag a release so users get updated binaries.","status":"closed","priority":3,"issue_type":"task","owner":"galadriel@example.com","created_at":"2026-05-03T17:24:57Z","created_by":"galadriel","updated_at":"2026-05-03T17:27:28Z","closed_at":"2026-05-03T17:27:28Z","close_reason":"pyproject.toml bumped to 1.0.3; 77 unit tests pass","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-7yn","title":"Add troubleshooting note for silent connection failure symptom","description":"Users who download the binary may see the menu appear instantly with no players and no server delay, which looks like a successful launch but means the client is not actually connected to the server. This symptom is hard to self-diagnose without documentation. Add a troubleshooting section to PLAYER.md or README.md describing: symptom (menu instant, no players, no delay), what it means (connection failed silently), and how to verify/fix (check risus.cfg is next to binary, check server address has no port if using TLS).","status":"closed","priority":3,"issue_type":"task","owner":"galadriel@example.com","created_at":"2026-05-03T17:21:14Z","created_by":"galadriel","updated_at":"2026-05-03T17:27:09Z","closed_at":"2026-05-03T17:27:09Z","close_reason":"Added troubleshooting row to PLAYER.md: symptom, cause, and two actionable fixes","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-5af","title":"Clean up docs/features/secure-session/ — verify content covered by specs/004-secure-session/ then delete","description":"docs/features/secure-session/ contains prd.md and concept.md. Before deleting, verify all relevant details are present in specs/004-secure-session/ (spec.md, plan.md, research.md, data-model.md, contracts/). If anything is missing, move it first. Then delete the docs/features/secure-session/ directory.","status":"open","priority":3,"issue_type":"task","owner":"eudicy@boos.systems","created_at":"2026-05-03T12:34:13Z","created_by":"Eudicy","updated_at":"2026-05-03T12:34:13Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-map","title":"Set initial version number in pyproject.toml","description":"Version is currently 0.1.0 — decide on versioning strategy and set appropriate initial release version before first tagged release.","status":"closed","priority":3,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T11:56:20Z","created_by":"Eudicy","updated_at":"2026-05-03T12:04:44Z","started_at":"2026-05-03T12:03:18Z","closed_at":"2026-05-03T12:04:44Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"risus-cli-a1v","title":"Clarify dev/production dependency setup for podman-compose and other tools","description":"During smoke testing, user needed to source .venv/bin/activate to get podman-compose. Need to clarify: should podman-compose be in pyproject.toml optional-dependencies? Should CONTRIBUTING.md/quickstart document the venv activation requirement? Also check if other tools (e.g. ruff, pytest) need similar documentation.","status":"closed","priority":3,"issue_type":"task","assignee":"Eudicy","owner":"eudicy@boos.systems","created_at":"2026-05-03T11:48:14Z","created_by":"Eudicy","updated_at":"2026-05-03T12:04:44Z","started_at":"2026-05-03T12:03:16Z","closed_at":"2026-05-03T12:04:44Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} diff --git a/.gitignore b/.gitignore index 2b91419..5a2740a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Secrets +.env* + # MCP secrets .mcp.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 78ce252..cad12e5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,6 +17,21 @@ pip install -e ".[dev]" This installs all development tools including `podman-compose`, `ruff`, and `pytest`. +### Environment Variables + +The next sections specify required environment variables. The +[envrc.example](./envrc.example) file can be copied to `.envrc` and +[direnv](https://direnv.net/) can automatically apply the file. + +> [!CAUTION] +> Never commit `.envrc` to git. It contains secrets. + +```bash +cp env.example .envrc + +# edit .envrc +``` + ### Rootless Podman (optional) For rootless Podman, expose the socket so `pytest-docker` can reach it: diff --git a/env.example b/env.example new file mode 100644 index 0000000..5c65495 --- /dev/null +++ b/env.example @@ -0,0 +1,18 @@ +#!/bin/sh +# +# direnv automatically loads the python virtual environment and configures +# shell variables. +# +# see https://github.com/direnv/direnv/wiki/Python +# +export VIRTUAL_ENV=.venv +layout python3 + +# Configure podman to host the server +export DOCKER_HOST=unix:///run/user/$UID/podman/podman.sock +export CONTAINER_ENGINE=podman + +# Server configuration +export RISUS_TOKEN=your-16-character-password-here +export DOMAIN=risus.example.com +