This repository was archived by the owner on May 26, 2026. It is now read-only.
feat(KR-P2-RUNBOOKS-PANEL): operator runbooks viewer (12th admin panel)#84
Merged
Conversation
When DR fires at 2am, operator opens /runbooks and reads the
procedure inline. No tabbing to docs. Read-only — operators read
here, execute outside (runbooks may reference operational secrets
in text; never embed "execute this command" buttons).
§2 verification: of the 5 PM-pre-listed paths, only docs/deploy-fly-io.md
is currently vendored into this repo (5113 bytes; shipped by
KR-P2-F-pre ST3). The 4 kora_docs/* paths reference a separate repo
(rafe-walker/kora-docs); they surface as "[runbook pending]"
placeholders so operators see the manifest acknowledges them but
they're not authored yet.
Reused web/src/components/Markdown.tsx (already in the project —
code blocks / headers / lists / inline code / links / horizontal
rules). No new markdown lib added.
Backend (kora_cli/web_server.py):
* Explicit _RUNBOOK_MANIFEST: Dict[str, (title, repo-relative path)].
NOT auto-discovered — ops want a stable known index, not a
wandering scan of every .md.
* GET /api/runbooks — manifest endpoint. One entry per pinned tuple
with available + size_bytes + last_modified populated for files
actually present; nulls for placeholders.
* GET /api/runbooks/{runbook_id}/content — raw markdown response
(text/markdown content-type). Defensive on multiple axes:
1. id regex ^[a-z][a-z0-9_]*$ rejects ../etc/passwd, etc.
(WARN logged so ops can spot traversal attempts).
2. id is only ever a dict-key lookup against the manifest —
user input is never concatenated into a path.
3. Resolved path verified is_relative_to(repo_root) — belt+braces
against a future manifest typo using ".." absolute paths.
4. 1 MiB size cap (returns 413 if exceeded).
5. Manifest entry exists but file missing → 404 with
"not yet authored" message (FE renders placeholder card —
distinct from "unknown id").
* Repo root resolved via __file__ (stable across uvicorn launch dirs).
Frontend (web/):
* pages/RunbooksPage.tsx — sidebar/content 280px+1fr grid (single-
column on mobile). Sidebar lists runbooks with available/
unavailable icon + title + path; click selects. Content pane:
- No selection → empty-state "Select a runbook from the sidebar"
- Selected + unavailable → "[runbook pending]" placeholder card
with expected-path callout
- Selected + available + loading → spinner
- Selected + available + loaded → reused Markdown component
renders the body inside a max-h-[calc(100vh-260px)] scroll
container; header strip shows title + path + size + last-
modified relative+absolute + Print button
* Print button triggers window.print() — operators get a paper
copy at 2am if they want one (markdown renders fine through
default print styles).
* lib/api.ts — new fetchText() helper (mirrors fetchJSON's session
token injection + non-2xx-throws but returns res.text() instead
of res.json()). RunbookEntry + RunbooksManifest interfaces;
getRunbooks + getRunbookContent client methods.
* App.tsx — /runbooks route + nav entry (BookOpenCheck icon) at
END of nav per spec §3 (operator looks for it specifically;
doesn't need top placement).
Tests: tests/kora_cli/test_web_server_runbooks.py — 11 tests
covering all 7 §5 scenarios plus extras:
* deploy_fly_io always-available contract guard (pins the in-repo
runbook against future repo reorganization)
* Multiple traversal pattern guards (.., ../etc, foo/bar, foo\\bar,
UPPERCASE, leading digit, internal whitespace all 404)
* Manifest-path-outside-root refused (belt+braces against typo)
* Defensive size cap with mocked oversized file
* Unavailable-vs-unknown distinction: dr_runbook (manifest entry,
file missing) returns 404 with "not yet authored" — distinguishable
from "unknown id" so FE renders placeholder rather than error
140/140 admin-panel suite green (test_web_server_cron_profiles
omitted — 5 pre-existing failures from KR-P2-D ST2 work_class
requirement; not mine).
tsc -b + vite build clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9 tasks
rafe-walker
added a commit
that referenced
this pull request
May 22, 2026
… + truthful 11-source footer (#95) v1 row 1 (Health hero + 6 cards) untouched. Row 2 adds 4 cards in 4-col lg grid: Capabilities (total_tools + total_caps + escalating-badge for 17 unmapped C2 mirror groups) / Charter (mid-truncated revision_id + rules_hash + loaded_at + 'rules pending' fallback badge) / Recent events (last 5 chain events, stripped kora. prefix for density) / Runbooks (available vs pending counts + most-recently-modified). isStubbed loosened to LoadStatus<unknown> with property-check (caps + runbooks responses don't carry stub field). ALL_SOURCES array consolidates 11 sources for anyStubbed banner and footer aggregate. Footer reports truthful 11-source count (PM bucket said 13; corrected — dashboard fetches 11 endpoint-backed sources; matches DIAG-BUNDLE's allowlist). 150/151 admin-panel tests pass; 1 stale assertion from PR #86 vendoring dr_runbook.md auto-improving PR #84's 'unauthored' assertion — flagged for trivial follow-up.
3 tasks
rafe-walker
added a commit
that referenced
this pull request
May 22, 2026
…on (#97) PR #86 vendored dr_runbook.md + token_rotation_runbook.md; PR #84's test_get_runbook_content_404_for_unauthored_manifest_entry asserted dr_runbook as unauthored — stale. Swapped to kora_dna (still placeholder) + updated docstring explaining auto-improvement history. 151/151 admin-panel suite back to green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
12th admin panel. Operationally-critical surface — when DR fires at 2am, operator opens `/runbooks` and reads the procedure inline. No tabbing to docs.
Read-only by design: runbooks may reference operational secrets in their text (e.g. "rotate the wsk_* token via doppler secrets set"); panel renders verbatim, operator executes outside. Never an "execute this command" button.
§2 verifications (run before code)
Existing `web/src/components/Markdown.tsx` reused for content rendering — no new markdown lib added (code blocks / headers / lists / inline code / links / hr all already supported).
Backend
`kora_cli/web_server.py`:
Frontend
`pages/RunbooksPage.tsx` — sidebar/content layout (280px + 1fr grid on desktop; single-column on mobile):
`lib/api.ts` — new `fetchText()` helper (mirrors `fetchJSON` session token + non-2xx-throws semantics); `RunbookEntry` + `RunbooksManifest` interfaces; `getRunbooks` + `getRunbookContent` clients.
`App.tsx` — `/runbooks` route + nav entry (BookOpenCheck icon) at end of nav per spec (operator looks for it specifically; doesn't need top placement).
Canonical runbook IDs (per manifest)
When kora-docs runbooks land in this repo (or get vendored at deploy time), each placeholder auto-flips to available without any code change — the manifest entry already points at the expected path.
Test plan
Pre-existing test failures (NOT this PR)
5 `test_web_server_cron_profiles.py` failures pre-exist on main HEAD (KR-P2-D ST2 added a `work_class` requirement that broke the older cron tests). Confirmed in prior PRs; flagged for separate cleanup.
🤖 Generated with Claude Code