@polderlabs/bizar 5.3.0 → 5.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":"4.1.9","results":[[":tests/lib/utils.test.ts",{"duration":20.318142999999964,"failed":false}],[":tests/components/Button.test.tsx",{"duration":97.09901500000001,"failed":false}],[":tests/components/Card.test.tsx",{"duration":25.56895700000001,"failed":false}],[":tests/hooks/useModal.test.tsx",{"duration":156.274812,"failed":false}],[":tests/components/Toast.test.tsx",{"duration":170.42815400000006,"failed":false}],[":tests/components/Modal.test.tsx",{"duration":189.45819300000005,"failed":false}],[":tests/lib/i18n.test.ts",{"duration":4.330512999999996,"failed":false}],[":tests/components/StatusBadge.test.tsx",{"duration":25.465268000000037,"failed":false}],[":tests/hooks/useToast.test.tsx",{"duration":124.75983200000007,"failed":false}],[":tests/components/Spinner.test.tsx",{"duration":56.78095799999994,"failed":false}],[":tests/backup-restore.test.tsx",{"duration":203.898414,"failed":false}],[":tests/a11y.test.tsx",{"duration":896.8848140000001,"failed":false}],[":tests/lib/search-fuzzy.test.ts",{"duration":6.686229000000026,"failed":false}],[":tests/components/settings-search.test.tsx",{"duration":722.1675959999999,"failed":false}],[":tests/memory-graph-view.test.tsx",{"duration":40.353496000000064,"failed":false}],[":tests/components/workspace-selector.test.tsx",{"duration":143.099331,"failed":false}],[":tests/components/screenshot-ocr.test.tsx",{"duration":30.485972000000004,"failed":false}],[":tests/voice-recorder.test.tsx",{"duration":139.93698299999994,"failed":false}],[":tests/autosave.test.tsx",{"duration":268.4993979999999,"failed":false}],[":tests/settings-layout.test.tsx",{"duration":246.68477299999995,"failed":false}],[":tests/settings-nav.test.tsx",{"duration":330.9125980000001,"failed":false}],[":tests/components/doctor-panel.test.tsx",{"duration":82.28221499999995,"failed":false}],[":tests/chat-composer.test.tsx",{"duration":279.32558600000004,"failed":false}],[":tests/settings-mode-wiring.test.tsx",{"duration":283.47341000000006,"failed":false}],[":tests/minimax-bar.test.ts",{"duration":0,"failed":true}],[":tests/minimax-bar.test.tsx",{"duration":23.41428499999995,"failed":false}],[":tests/components/plugin-permissions.test.tsx",{"duration":127.94786099999999,"failed":false}],[":tests/eval-web-ui.test.tsx",{"duration":147.663952,"failed":false}],[":tests/components/marketplace-plugin-card.test.tsx",{"duration":175.07474200000001,"failed":false}],[":tests/a11y/components.test.tsx",{"duration":128.34057200000007,"failed":false}],[":tests/a11y/forms.test.tsx",{"duration":86.17374700000005,"failed":true}],[":tests/a11y/navigation.test.tsx",{"duration":136.026924,"failed":true}]]}
1
+ {"version":"4.1.9","results":[[":tests/lib/utils.test.ts",{"duration":15.788036999999974,"failed":false}],[":tests/components/Button.test.tsx",{"duration":84.90294800000004,"failed":false}],[":tests/components/Card.test.tsx",{"duration":18.837508999999955,"failed":false}],[":tests/hooks/useModal.test.tsx",{"duration":120.20212400000003,"failed":false}],[":tests/components/Toast.test.tsx",{"duration":161.860364,"failed":false}],[":tests/components/Modal.test.tsx",{"duration":169.36771700000008,"failed":false}],[":tests/lib/i18n.test.ts",{"duration":2.9599100000000362,"failed":false}],[":tests/components/StatusBadge.test.tsx",{"duration":22.451562999999965,"failed":false}],[":tests/hooks/useToast.test.tsx",{"duration":113.03238799999997,"failed":false}],[":tests/components/Spinner.test.tsx",{"duration":56.80167199999994,"failed":false}],[":tests/backup-restore.test.tsx",{"duration":209.892064,"failed":false}],[":tests/a11y.test.tsx",{"duration":679.8717469999999,"failed":false}],[":tests/lib/search-fuzzy.test.ts",{"duration":5.03047799999996,"failed":false}],[":tests/components/settings-search.test.tsx",{"duration":718.4375819999999,"failed":false}],[":tests/memory-graph-view.test.tsx",{"duration":29.26699000000002,"failed":false}],[":tests/components/workspace-selector.test.tsx",{"duration":120.47785299999998,"failed":false}],[":tests/components/screenshot-ocr.test.tsx",{"duration":27.81256400000001,"failed":false}],[":tests/voice-recorder.test.tsx",{"duration":114.61372900000003,"failed":false}],[":tests/autosave.test.tsx",{"duration":254.917053,"failed":false}],[":tests/settings-layout.test.tsx",{"duration":217.68918099999996,"failed":false}],[":tests/settings-nav.test.tsx",{"duration":290.68972699999995,"failed":false}],[":tests/components/doctor-panel.test.tsx",{"duration":70.02781100000004,"failed":false}],[":tests/chat-composer.test.tsx",{"duration":232.71696299999996,"failed":false}],[":tests/settings-mode-wiring.test.tsx",{"duration":276.79545799999994,"failed":false}],[":tests/minimax-bar.test.ts",{"duration":0,"failed":true}],[":tests/minimax-bar.test.tsx",{"duration":22.24368499999997,"failed":false}],[":tests/components/plugin-permissions.test.tsx",{"duration":92.75674500000002,"failed":false}],[":tests/eval-web-ui.test.tsx",{"duration":117.119639,"failed":false}],[":tests/components/marketplace-plugin-card.test.tsx",{"duration":188.3587500000001,"failed":false}],[":tests/a11y/components.test.tsx",{"duration":127.70726300000001,"failed":false}],[":tests/a11y/forms.test.tsx",{"duration":103.14186000000007,"failed":true}],[":tests/a11y/navigation.test.tsx",{"duration":120.83297300000004,"failed":true}]]}
@@ -484,7 +484,20 @@ function extractToken(req) {
484
484
  */
485
485
  export function getCurrentUserId(req) {
486
486
  const token = extractToken(req);
487
- if (!token) return null;
487
+ if (!token) {
488
+ // v5.3.1 — Tailscale trust: when the dashboard is reached via
489
+ // tailscale serve and the operator has opted in to trust tailnet
490
+ // clients, derive a deterministic userId from the tailnet hostname
491
+ // so the rest of the v5.0 multi-user code paths (workspaces, etc.)
492
+ // work without requiring an explicit token.
493
+ if (process.env.BIZAR_DASHBOARD_TRUST_TAILSCALE === '1' && isLoopback(req)) {
494
+ const hostname = String(req?.headers?.host || '').split(':')[0];
495
+ if (hostname && hostname.endsWith('.ts.net')) {
496
+ return 'usr_ts_' + createHash('sha256').update(hostname).digest('hex').slice(0, 12);
497
+ }
498
+ }
499
+ return null;
500
+ }
488
501
 
489
502
  const secret = getOrCreateSecret();
490
503
 
@@ -26,7 +26,25 @@ export function createUsersRouter() {
26
26
  return res.status(401).json({ error: 'unauthorized', message: 'Not authenticated' });
27
27
  }
28
28
  const user = await getUser(userId);
29
+ // v5.3.1 — Tailscale-trust: when getCurrentUserId returns a derived
30
+ // userId (usr_ts_*) that doesn't exist in the store, synthesize a
31
+ // minimal user record from the request Host header so the dashboard
32
+ // can render a profile without needing a full signup.
29
33
  if (!user) {
34
+ if (userId.startsWith('usr_ts_')) {
35
+ const host = String(req.headers?.host || '').split(':')[0] || 'tailnet';
36
+ const tailnetName = host.split('.')[0] || 'tailnet';
37
+ const workspaces = await listWorkspacesWithRoles(userId);
38
+ return res.json({
39
+ user: {
40
+ id: userId,
41
+ email: `${tailnetName}@tailscale.local`,
42
+ name: `Tailnet user (${tailnetName})`,
43
+ tailnet: true
44
+ },
45
+ workspaces
46
+ });
47
+ }
30
48
  return res.status(404).json({ error: 'not_found', message: 'User not found' });
31
49
  }
32
50
  const workspaces = await listWorkspacesWithRoles(userId);
@@ -138,6 +138,11 @@ export async function runDash(dashArgs) {
138
138
  const serveResult = await setupTailscaleServe({ dashboardPort: usePort });
139
139
  if (serveResult.ok) {
140
140
  console.log(chalk.green(` ✓ Tailscale serve: ${serveResult.url}`));
141
+ // v5.3.1 — Auto-trust Tailscale clients so they don't need
142
+ // a bearer token. Tailscale users are already authenticated
143
+ // on the tailnet before they reach the dashboard.
144
+ process.env.BIZAR_DASHBOARD_TRUST_TAILSCALE = '1';
145
+ console.log(chalk.dim(' ✓ Tailscale clients auto-trusted (BIZAR_DASHBOARD_TRUST_TAILSCALE=1)'));
141
146
  }
142
147
  }
143
148
  } catch (err) {
@@ -83,9 +83,16 @@ export async function setupTailscaleServe({ dashboardPort = 4097, path = '/', ht
83
83
  } catch { /* ignore — might not have existing config */ }
84
84
 
85
85
  // Set up new serve config
86
+ // v5.3.1 — Use --set-x-forwarded-for=trailing so the dashboard sees
87
+ // the original client IP (a 100.x Tailscale address) in X-Forwarded-For.
88
+ // Without this, the dashboard can't tell that the request came from
89
+ // a trusted tailnet client and demands a bearer token.
86
90
  try {
87
91
  execFileSync('tailscale', [
88
- 'serve', '--bg', `--https=${https}`, `--set-path=${path}`,
92
+ 'serve', '--bg',
93
+ `--https=${https}`,
94
+ `--set-path=${path}`,
95
+ '--set-x-forwarded-for=trailing',
89
96
  `http://localhost:${dashboardPort}`,
90
97
  ], { encoding: 'utf8', timeout: 30000 });
91
98
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polderlabs/bizar",
3
- "version": "5.3.0",
3
+ "version": "5.3.1",
4
4
  "description": "Norse-pantheon multi-agent system for opencode — 13 agents across 4 cost tiers with cost-aware routing, plans, and a configurable agent harness. v4 ships as a single npm package bundling the dashboard server, opencode plugin, and typed SDK.",
5
5
  "type": "module",
6
6
  "bin": {