Skip to content

feat: add the optional local OAuth dashboard - #191

Merged
mohanagy merged 3 commits into
developmentfrom
feat/86-console
Jul 22, 2026
Merged

feat: add the optional local OAuth dashboard#191
mohanagy merged 3 commits into
developmentfrom
feat/86-console

Conversation

@mohanagy

@mohanagy mohanagy commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Closes #86

Outcome

Adds an optional, foreground-only browser-local Console launched with miftah dashboard. It turns first-run connection/profile setup, OAuth onboarding, status, recovery, and copyable client configuration into a guided local workflow while keeping the CLI and hand-written config fully supported.

Product and security boundary

  • binds only to the loopback interface and exits with the foreground command
  • uses an authenticated bootstrap/session flow with origin checks and CSRF protection
  • opens OAuth in the system browser; it never embeds a provider login or password form
  • creates and validates first-run configuration transactionally without exposing credentials
  • distinguishes native remote OAuth, adapter-backed, upstream/manual, and unsupported authentication modes
  • shows active versus durable profile state and restart/new-connection guidance
  • provides client configuration for explicit review and copy only; no silent client-file writes
  • never returns or renders raw tokens, secrets, or credential material
  • preserves all existing policy, approval, routing, identity, and audit controls

Tests and documentation

Adds focused CLI parsing/exit-code, browser launch, Console service, loopback HTTP security, accessibility/recovery, package-contract, and threat-model contract coverage. Updates the README and Console/OAuth/CLI/security/architecture documentation.

Validation on rebased head e32bac9

  • npm test: 1,261 passed, 20 platform-gated skips
  • npm run test:core: 404 passed, 20 platform-gated skips
  • npm run test:coverage: 95.41% statements, 91.90% branches
  • npm run lint
  • npm run typecheck
  • npm run build
  • npm run smoke:cli
  • npm run check:pack: 46-file package contract verified
  • npm run test:package: 20 passed
  • git diff --check

The first full-suite attempt hit the already tracked intermittent synchronization boundary in #113. The exact case then passed 11/11 focused quiet-host repetitions and passed the clean full-suite and coverage runs; no timeout or source workaround was applied.

The base merge commit e6a53bf also passed exact-head development run 29958797299 across Linux, macOS, Windows, Node 20/22/24, and final Verify.

Summary by CodeRabbit

  • New Features

    • Added an optional local Console dashboard launched with miftah dashboard.
    • Added browser-based native OAuth setup and connection management.
    • Added client configuration snippet generation and connection testing.
    • Added automatic browser opening, with support for --config, --port, and --no-open.
  • Security

    • Strengthened local dashboard session, CSRF, origin, and audit protections.
    • Sensitive credentials and upstream metadata remain redacted from the dashboard.
  • Documentation

    • Updated CLI, OAuth, architecture, security, and Console API documentation.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds miftah dashboard, a browser-local Console UI, native OAuth first-run onboarding, client snippet generation, connection testing, stricter Console routing, and updated documentation and contract tests.

Changes

Console dashboard and OAuth onboarding

Layer / File(s) Summary
Dashboard CLI and browser launch
src/cli/*, src/console/open-browser.ts, tests/cli-*, tests/package-contract.test.ts
Adds dashboard parsing, foreground startup, optional trusted browser opening, missing-config handling, and related exit-code and smoke tests.
Native OAuth application workflow
src/console/console-application-service.ts, src/cli/migrate-config.ts, tests/console-application-service.test.ts
Adds validated first-run OAuth configuration creation, initialization metadata, client snippets, and testConnection support.
Console assets and API routing
src/console/console-assets.ts, src/console/console-server.ts, tests/console-server.test.ts
Adds embedded dashboard assets, onboarding and snippet endpoints, asset security headers, trusted-origin rules, missing-config startup, and expanded connection actions.
Console and OAuth contract documentation
README.md, docs/*.md, tests/oauth-console-threat-model-docs-contract.test.ts
Documents dashboard usage, browser-session protections, API boundaries, onboarding contracts, and audit behavior.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant DashboardCLI
  participant ConsoleServer
  participant ConsoleApplicationService
  participant ConfigFile
  Operator->>DashboardCLI: run miftah dashboard
  DashboardCLI->>ConsoleServer: start foreground loopback server
  ConsoleServer-->>DashboardCLI: URL and one-time bootstrap code
  DashboardCLI-->>Operator: print startup details and optionally open browser
  Operator->>ConsoleServer: submit native OAuth onboarding
  ConsoleServer->>ConsoleApplicationService: validate and create connection
  ConsoleApplicationService->>ConfigFile: write new configuration
  ConfigFile-->>ConsoleApplicationService: configuration created
  ConsoleApplicationService-->>ConsoleServer: onboarding report
  ConsoleServer-->>Operator: return dashboard response
Loading

Poem

A rabbit hops where dashboards glow,
OAuth paths now neatly flow.
CSRF guards the local door,
Snippets copy secrets no more.
Configs bloom with audit light—
Console keeps the loopback right.


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Docstring Coverage ❌ Error Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately points to the new optional local dashboard feature.
Description check ✅ Passed The description covers the feature, security boundary, tests, and validation, though its headings differ from the template.
Linked Issues check ✅ Passed The PR implements the optional dashboard flow, onboarding, status, copy-only config, security boundaries, and regression tests requested in #86.
Out of Scope Changes check ✅ Passed No clear out-of-scope changes stand out; the code, docs, and tests all align with the dashboard and Console objectives.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/86-console

Comment @coderabbitai help to get the list of available commands.

@mohanagy

Copy link
Copy Markdown
Owner Author

Self-review follow-up on current head c074c94:

  • Found that the dashboard connection cards were reading static binding metadata, so credential and identity state would always render as unknown.
  • Added a focused regression test and observed the expected pre-fix failure.
  • The service now returns live redacted lifecycle state when available.
  • If lifecycle state cannot be loaded, the list remains usable with static redacted binding metadata plus an explicit stable statusErrorCode; raw provider/store errors are not exposed or swallowed.
  • The UI now displays resource, issuer, scopes, credential/identity state, and the stable unavailable diagnostic using textContent only.

Focused Console suite: 14/14 passed. Lint, typecheck, build, and diff checks pass. A simultaneous full-suite run was invalidated by a confirmed unrelated Madar Vitest worker saturating the host and causing 17 broad 5-second timeouts; that evidence is recorded under existing #113, and no timeout was increased. A quiet-host full repeat is pending while current-head CI runs.

coderabbitai[bot]
coderabbitai Bot previously requested changes Jul 22, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/cli/main.ts (1)

94-106: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Extract shared shutdown/SIGHUP wiring from consoleServe and dashboardServe.

The shutdown handler and SIGINT/SIGTERM/SIGHUP registration in dashboardServe (Lines 134-146) is a verbatim copy of the same block in consoleServe (Lines 94-106). Any future change to lifecycle handling has to be applied in both places.

♻️ Proposed refactor to share lifecycle wiring
+function registerServerLifecycle(server: { close: () => Promise<void>; rotateCredential: () => string }): void {
+  const shutdown = (): void => {
+    void server.close().catch(() => {
+      process.stderr.write("Miftah Console shutdown failed.\n");
+      process.exitCode = 1;
+    });
+  };
+  process.once("SIGINT", shutdown);
+  process.once("SIGTERM", shutdown);
+  if (process.platform !== "win32") {
+    process.on("SIGHUP", () => {
+      process.stdout.write(`Replacement one-time bootstrap code: ${server.rotateCredential()}\n`);
+    });
+  }
+}
+
 async function consoleServe(configPath: string, port: string | undefined): Promise<void> {
   const server = await startConsoleServer(configPath, {
     port: consolePort(port),
     launcher: { command: process.execPath, args: [fileURLToPath(import.meta.url), "serve"] }
   });
   process.stdout.write(...);
-  const shutdown = (): void => { ... };
-  process.once("SIGINT", shutdown);
-  process.once("SIGTERM", shutdown);
-  if (process.platform !== "win32") { ... }
+  registerServerLifecycle(server);
 }

Apply the same replacement in dashboardServe.

Also applies to: 134-146

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/main.ts` around lines 94 - 106, Extract the duplicated shutdown and
signal-registration logic from consoleServe and dashboardServe into a shared
lifecycle-wiring helper, preserving the existing server.close error handling,
SIGINT/SIGTERM registration, and non-Windows SIGHUP credential rotation
behavior. Replace both inline blocks with calls to the shared helper and pass
each serve function’s server instance.
src/console/console-server.ts (1)

162-188: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

CONSOLE_LAUNCHER_UNAVAILABLE has no dedicated HTTP mapping.

This new error code (thrown by clientSnippets when no launcher is configured) falls through to the generic 502 "operation could not be completed" branch. 502 implies an upstream/gateway failure, but this is a local console misconfiguration — closer to CONFIG_CREATE_FAILED's 503 treatment.

🐛 Proposed fix
   if (error.code === "CONFIG_CREATE_FAILED") {
     return new ConsoleHttpError(503, "config_create_failed", "The initial configuration could not be created.");
   }
+  if (error.code === "CONSOLE_LAUNCHER_UNAVAILABLE") {
+    return new ConsoleHttpError(503, "console_launcher_unavailable", "Client snippets are unavailable because no launcher is configured.");
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/console/console-server.ts` around lines 162 - 188, Add a dedicated
CONSOLE_LAUNCHER_UNAVAILABLE case in publicApplicationError, mapping it to a 503
response with a stable launcher-unavailable error identifier and a message
indicating the Console launcher is unavailable. Keep the existing generic
mappings unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/oauth-console-threat-model.md`:
- Line 70: Update docs/oauth-console-threat-model.md:70 and docs/security.md:41
to state that Console requests require the exact listener Origin, including
scheme, host, and port. Extend the contract assertions in
tests/oauth-console-threat-model-docs-contract.test.ts:35-46 to verify exact
listener Host and full Origin validation, CSRF requirements for state-changing
requests, and the existing omission rule for permitted reads.

In `@src/console/console-application-service.ts`:
- Around line 125-129: Consolidate the duplicate error-code narrowing by
exporting the existing errorCode(error) helper from migrate-config and reusing
it in console-application-service.ts, including within the fileErrorCode call
sites. Remove the local fileErrorCode implementation while preserving the
current undefined behavior for errors without a string code.

In `@tests/oauth-console-threat-model-docs-contract.test.ts`:
- Around line 29-46: Extend the contract assertions in the OAuth console
threat-model test to require that mutation requests use the exact listener Host
and matching Origin, and enforce the documented CSRF checks. Keep the existing
authenticated GET/HEAD Origin-omission assertion, and add consoleApi
expectations covering the exact-origin mutation rule so documentation cannot
weaken this boundary.

---

Outside diff comments:
In `@src/cli/main.ts`:
- Around line 94-106: Extract the duplicated shutdown and signal-registration
logic from consoleServe and dashboardServe into a shared lifecycle-wiring
helper, preserving the existing server.close error handling, SIGINT/SIGTERM
registration, and non-Windows SIGHUP credential rotation behavior. Replace both
inline blocks with calls to the shared helper and pass each serve function’s
server instance.

In `@src/console/console-server.ts`:
- Around line 162-188: Add a dedicated CONSOLE_LAUNCHER_UNAVAILABLE case in
publicApplicationError, mapping it to a 503 response with a stable
launcher-unavailable error identifier and a message indicating the Console
launcher is unavailable. Keep the existing generic mappings unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8754d23d-95c7-456a-865f-9a40c257d48e

📥 Commits

Reviewing files that changed from the base of the PR and between e6a53bf and e32bac9.

📒 Files selected for processing (23)
  • README.md
  • docs/architecture.md
  • docs/cli.md
  • docs/console-api.md
  • docs/oauth-console-threat-model.md
  • docs/oauth-support.md
  • docs/security.md
  • src/cli/exit-codes.ts
  • src/cli/main.ts
  • src/cli/migrate-config.ts
  • src/cli/parse.ts
  • src/console/console-application-service.ts
  • src/console/console-assets.ts
  • src/console/console-server.ts
  • src/console/open-browser.ts
  • src/utils/errors.ts
  • tests/cli-exit-codes.test.ts
  • tests/cli-parse.test.ts
  • tests/console-application-service.test.ts
  • tests/console-open-browser.test.ts
  • tests/console-server.test.ts
  • tests/oauth-console-threat-model-docs-contract.test.ts
  • tests/package-contract.test.ts

Comment thread docs/oauth-console-threat-model.md Outdated
Comment thread src/console/console-application-service.ts
Comment thread tests/oauth-console-threat-model-docs-contract.test.ts
@mohanagy

Copy link
Copy Markdown
Owner Author

Current-head quiet-host validation is complete on c074c94:

  • npm test: 1,263 passed, 20 platform-gated skips
  • npm run test:core: 404 passed, 20 platform-gated skips
  • npm run test:coverage: 95.39% statements, 91.87% branches
  • npm run lint
  • npm run typecheck
  • npm run build
  • npm run smoke:cli
  • npm run check:pack: 46-file contract verified
  • npm run test:package: 20 passed
  • focused Console tests: 14 passed
  • git diff --check

The quiet repeat passed every case that failed while the unrelated worker was active. No timeout, assertion, coverage threshold, or platform behavior was changed.

@mohanagy

Copy link
Copy Markdown
Owner Author

Review findings resolved on current head d2c93b9

Verified every finding from the historic CodeRabbit review rather than dismissing the review state:

  • exact listener Origin contract: fixed docs to require scheme, host, and port; added contract assertions for exact Host, exact Origin, CSRF, and the read-only omission rule;
  • launcher-unavailable HTTP mapping: added a focused regression test that first observed 502, then mapped CONSOLE_LAUNCHER_UNAVAILABLE to stable 503 console_launcher_unavailable without exposing internal details;
  • Console/dashboard lifecycle duplication: extracted the shared shutdown and SIGHUP wiring without changing signal behavior;
  • local error-code guard: intentionally retained locally; importing a CLI migration helper into the Console application layer would invert the dependency for no behavioral benefit.

TDD evidence:

  • red: focused suite failed with expected 502 vs 503 and missing exact-listener-origin documentation contract;
  • green: 13/13 focused Console and threat-model tests passed.

Full current-head local validation:

  • npm test: 1,264 passed, 20 platform-gated skips;
  • npm run test:core: 404 passed, 20 platform-gated skips;
  • npm run test:coverage: 1,264 passed, 20 platform-gated skips; 95.39% statements, 91.86% branches, 98.37% functions;
  • lint, typecheck, build, CLI smoke: green;
  • package contract: 46 files verified;
  • packaged artifact tests: 20/20 green;
  • git diff --check: green.

One earlier unchanged full-suite attempt hit the existing cross-suite readiness susceptibility under substantial unrelated host CPU load. The exact Doctor case passed 5/5 and the unchanged full rerun plus coverage run passed. The post-single-fork recurrence is documented by reopening canonical tracker #122; no timeout, worker, skip, assertion, coverage, or production behavior was weakened in this PR.

@mohanagy
mohanagy dismissed coderabbitai[bot]’s stale review July 22, 2026 22:12

Dismissed only after all five findings were verified: four were fixed in d2c93b9, the local helper consolidation was declined with an architectural rationale, all three inline threads are resolved, and the current-head CodeRabbit status is rate-limited rather than a new review. Full local validation is green; exact-head CI remains the merge gate.

@mohanagy
mohanagy merged commit cf36fdf into development Jul 22, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Console] Build the optional first-run Miftah Console

1 participant