logicsrc/apps/logicsrc-web/src/components/site-shell.tsx
Anthony Ettinger f057589d66 feat(credential-sharing): end-to-end-encrypted team credential sharing
Adds a `team` credential provider + team/member management so teammates can
share secrets by email instead of passing .env files over chat. Fully E2E:
the server only ever stores ciphertext, per-member sealed vault keys, and
public keys — it never sees a plaintext value or the vault DEK.

Plugin (@logicsrc/plugin-credential-sharing)
- crypto.ts: X25519 identity keys, per-vault DEK (secretbox), DEK sealed to
  each member's pubkey (crypto_box_seal), value encrypt/decrypt (libsodium)
- identity.ts: local ~/.logicsrc/identity.json (0600) holding the device key
  + API token; never uploads the secret key
- client.ts: typed /api/credshare client
- providers/team.ts: `team:<slug>/<vault>` CredentialProvider (inspect,
  readValues=decrypt, write=encrypt, rollback); fingerprints match env so
  env<->team diffs line up
- fixes latent libsodium-wrappers ESM load bug (createRequire) here + in
  github-secrets

Server (commandboard-api /api/credshare)
- zero-knowledge router: email-code auth, keys, teams, members, invites,
  vaults, sealed grants, ciphertext secrets, audit; membership authz in app
- CredShareStore abstraction: in-memory (dev/tests) + Supabase (prod)
- Resend email transport for login codes + invites (no-op -> echoes locally)
- supabase migration: credshare_* tables, deny-by-default RLS

CLI
- real `logicsrc login` (email code -> token + key upload)
- `logicsrc teams create/list/invite/accept/members/vaults/grant/push/pull`

Web (logicsrc.com/teams + /teams/accept)
- management surface only (browser holds no private key, never decrypts):
  login, view teams/members/vaults, invite, accept

Tests: crypto round-trip, server contract (invite->accept->push->grant->pull
+ authz boundaries), and a real HTTP+client+crypto E2E asserting the server
never holds plaintext. Full workspace build + tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 13:11:32 +00:00

84 lines
2.9 KiB
TypeScript

import type { ReactNode } from "react";
// Mirrors the rail/nav from page-markup.ts so standalone routes (e.g. /blog)
// share the site chrome. Anchor links point at the homepage sections.
const NAV: Array<{ href: string; label: string; external?: boolean }> = [
{ href: "/#overview", label: "Overview" },
{ href: "/#schemas", label: "Schemas" },
{ href: "/agent-swarm", label: "Soon" },
{ href: "/agentbyte", label: "AgentByte" },
{ href: "/credential-sharing", label: "Credentials" },
{ href: "/teams", label: "Teams" },
{ href: "/#cli", label: "CLI" },
{ href: "/docs", label: "Docs" },
{ href: "/blog", label: "Blog" },
{ href: "/openspec", label: "OpenSpec" },
{ href: "/pricing", label: "Pricing" },
{ href: "/hire-us", label: "Hire Us" },
{ href: "/about", label: "About" },
{ href: "https://github.com/profullstack/logicsrc", label: "GitHub ↗", external: true },
{ href: "/terms", label: "Terms" },
{ href: "/privacy", label: "Privacy" },
{ href: "/#reference", label: "Reference" },
];
export function SiteShell({
children,
active,
}: {
children: ReactNode;
active?: string;
}): ReactNode {
return (
<main className="shell">
<aside className="rail">
<a className="brand" href="/" style={{ textDecoration: "none", color: "inherit" }}>
<span className="mark">LS</span>
<div>
<strong>LogicSRC</strong>
<small>Open coordination standards</small>
</div>
</a>
<nav aria-label="LogicSRC sections">
{NAV.map((item) => (
<a
key={item.href}
href={item.href}
className={item.label === active ? "active" : undefined}
aria-current={item.label === active ? "page" : undefined}
target={item.external ? "_blank" : undefined}
rel={item.external ? "noreferrer" : undefined}
>
{item.label}
</a>
))}
</nav>
</aside>
<section className="workspace">
{children}
<footer
style={{
maxWidth: "72rem",
margin: "2rem auto 0",
padding: "1.25rem 0",
borderTop: "1px solid #d9ded4",
display: "flex",
flexWrap: "wrap",
gap: "0.75rem",
justifyContent: "space-between",
fontSize: "0.85rem",
color: "#5b6b7a",
}}
>
<span>© {new Date().getFullYear()} Profullstack, Inc. · LogicSRC</span>
<span style={{ display: "flex", gap: "0.75rem" }}>
<a href="/docs" style={{ color: "inherit" }}>Docs</a>
<a href="/blog/rss.xml" style={{ color: "inherit" }}>RSS</a>
<a href="/terms" style={{ color: "inherit" }}>Terms</a>
<a href="/privacy" style={{ color: "inherit" }}>Privacy</a>
</span>
</footer>
</section>
</main>
);
}