Skip to content

feat(security+ux): Pillar 2 owner-permission lockdown + Get Started rewrite + copy buttons#25

Merged
paulgnz merged 1 commit into
mainfrom
feat/owner-permission-recovery-pattern
May 15, 2026
Merged

feat(security+ux): Pillar 2 owner-permission lockdown + Get Started rewrite + copy buttons#25
paulgnz merged 1 commit into
mainfrom
feat/owner-permission-recovery-pattern

Conversation

@paulgnz
Copy link
Copy Markdown
Collaborator

@paulgnz paulgnz commented May 15, 2026

Bundles three operator-facing improvements driven by an audit swarm of the live xpragents.com surface (3 parallel agents, 70+ findings consolidated):

  1. Pillar 2 security model — owner permission delegated to a human account
  2. Get Started page rewrite — path-aware linear flow with explicit Standalone vs Harness picker
  3. Copy buttons sitewide — every shell snippet on Get Started + Register

Plus consolidated audit-driven content fixes (operator-blocking copy in how-it-works, missing form validation on /register, missing OG metadata on sub-pages, etc.).

Pillar 2 — owner permission delegated to a human account

Until now, the post-charliebot security story stopped at "active key lives in the proton CLI keychain, never in the agent process" (Pillar 1). Necessary but not sufficient: if the active key ever leaks, the attacker can rotate the agent out of its own account because the same key controls owner by default.

This PR ships an interactive, idempotent, type-to-confirm setup script that delegates owner to the operator's separate human XPR account.

After setup:

owner:  <human-account>@active   (recovery + permission control)
active: PUB_K1_xxx               (proton CLI keychain, daily signing)

If active leaks, the human signs an updateauth from a different machine to rotate active. Agent identity / history / trust score all survive.

Reachable from both deployment paths:

  • Standalone: ./setup-security.sh (ships in scaffold)
  • Harness: npx @xpr-agents/openclaw xpr-agents-setup-security --account <name> (new bin entry in @xpr-agents/openclaw)

Safety design:

  • TTY required (no automation, no piped stdin)
  • Hard refuse if proton CLI absent, account lookup fails, or K1 we'd set on active isn't in keychain
  • Type-to-confirm BOTH the agent and human account names
  • Operator must visit explorer.xprnetwork.org and verify visually
  • Atomic 2-action transaction; re-fetch + verify end-state after push
  • Idempotent: detects already-secured accounts and exits cleanly

start.sh first-run check: detects raw keys on owner and prints a yellow [security] warning pointing at the script. Non-blocking.

Full rationale: new docs/SECURITY.md (227 lines, covers WebAuth and proton account:create starting states).

Get Started — path-aware linear flow

Restructured from a 5-step nested-branch layout to 5 linear steps with a Standalone vs Harness picker between Step 2 and Step 3:

  1. Create an XPR Network account (WebAuth-first; CLI alternative)
  2. Load private key into proton CLI keychain
  3. [Path picker] Deploy — content swaps based on selection
  4. Lock down owner permission (Pillar 2)
  5. Register, claim for KYC, build trust

The post-charliebot security explainer is no longer buried in text-zinc-500 — it's now a prominent emerald callout above the steps.

New "Building skills?" developer-resources card links the xpr-network-dev-skill repo (previously invisible on the frontend).

Copy buttons sitewide

New components: CopyButton, CodeBlock. Applied to every multi-line shell snippet on Get Started + Register.

Audit-driven content fixes

  • how-it-works hero: "Running on testnet today" → "Live on XPR Network mainnet, with testnet available for experiments." The old copy was actively misleading new visitors; mainnet has been live with 56 agents, 27 jobs, 4 arbitrators.
  • ERC-8004 → EIP-8004 across user-facing pages.
  • Home hero CTA: "How It Works" → "Get Started". The page that walks operators through what to do was reachable only from the header dropdown before.
  • Test-count breakdown grid: dropped the "MCP Tools: 72" tile from a Total Tests category (category error caught by audit).
  • New SiteHead component fixes og:image (was pointing at stale Vercel preview URL on every page) and adds og:url/og:title/og:description to get-started + how-it-works (only home had them).

Register page P0s

  • Description client-side required to match contract (agentcore.contract.ts:476 enforces 1-256 chars; form was letting operators hit a confusing on-chain assertion failure).
  • Protocol dropdown dropped websocket and mqtt — contract only accepts http://, https://, grpc://, wss://.
  • Network badge in form next to "Registering as @account" — wrong-chain registration risk caught by audit.
  • Trust score preview ("you'll start at 0/100, here's how it grows").
  • Wallet-connect inline CTA when no session.
  • start.sh flags table expanded from 2 to 6 rows (--network, --rpc, --model, --poll-interval added).

Versions

  • @xpr-agents/openclaw0.4.3 (bin entry for xpr-agents-setup-security, SKILL.md Pillar 2 safety rule)
  • create-xpr-agent0.6.0 (start.sh first-run security check, setup-security.sh ships in template)

Verification

  • 80 openclaw tests pass
  • Frontend builds clean (npm run build, all 13 routes prerendered)
  • CI scaffold-sanity covers all three setup-security.sh copies + start.sh + .env.example
  • Smoke-tested setup-security.sh on a TTY against an already-secured account → exits cleanly with idempotency check

Next

PR β (action-surface P0s — Hire CTA on /agent/[id], direct-hire option in Post Job modal, useChainStream perf, getLeaderboard N+1, testnet indexer fix, dashboard fixes) lands as a separate PR.

…ewrite + copy buttons sitewide

Bundles three operator-facing improvements driven by an audit swarm
of the live xpragents.com surface:

1. The post-charliebot security model gets a second pillar
2. The Get Started page becomes a path-aware linear flow
3. Code blocks across the site get copy-to-clipboard buttons

## Pillar 2 — owner permission delegated to a human account

Until now, the post-charliebot security story stopped at "active key
lives in the proton CLI keychain, never in the agent process"
(Pillar 1). That's necessary but not sufficient: if the active key
ever leaks, the attacker can rotate the agent out of its own account
because the same key controls owner by default.

This commit ships an interactive, idempotent, type-to-confirm setup
script that delegates owner to the operator's separate human XPR
account. After setup:

  owner:  <human-account>@Active   (recovery + permission control)
  active: PUB_K1_xxx               (in proton CLI keychain, daily signing)

If active leaks, the human signs an updateauth from a different
machine to rotate active. The agent identity, history, and trust
score survive.

The script lives in three locations (sync-checked by CI):
- openclaw/starter/setup-security.sh (standalone scaffold)
- create-xpr-agent/template/setup-security.sh (scaffold template)
- openclaw/scripts/setup-security.sh (npm bin for harness operators)

Harness operators can run it without a scaffold:
  npx @xpr-agents/openclaw xpr-agents-setup-security --account myagent

start.sh runs a quick diagnostic on first boot: if the agent's owner
permission still has raw keys, it prints a yellow [security] warning
pointing at the setup script. Non-blocking, idempotent.

Safety design:
- TTY required (no automation, no piped stdin)
- Hard refuse if proton CLI not on PATH
- Hard refuse if account lookup fails (no delegating to nonexistent accounts)
- Hard refuse if K1 we'd set on active isn't in the keychain
- Type-to-confirm BOTH the agent account AND the human account names
- Require operator to visit explorer.xprnetwork.org and verify visually
- Display human account's balance, age, and active-key type before signing
- Atomic 2-action transaction: active rewrite + owner rewrite
- Re-fetch and verify end-state after the push
- Idempotent: detects already-secured accounts and exits cleanly

Full rationale + diagnostic flows: docs/SECURITY.md (new, 227 lines).

## Get Started — path-aware linear flow + path picker

Restructured from a 5-step nested branching layout to a 5-step linear
flow with an explicit Standalone vs Harness path picker between
steps 2 and 3. Steps:

  1. Create an XPR Network account (WebAuth-first; CLI alternative)
  2. Load private key into proton CLI keychain
  → [Path picker: standalone host / Pinata-or-harness]
  3. Deploy (path-aware command block)
  4. Lock down owner permission (Pillar 2 setup-security)
  5. Register, claim for KYC, build trust

Step 3 swaps content based on path selection. Standalone gets the
full ./start.sh recipe with all five flags documented in the help
table; harness gets `openclaw plugins install @xpr-agents/openclaw`
plus the env.vars XPR_ACCOUNT note.

Pulled the post-charliebot security explainer out of the small gray
text it was buried in (caught by the audit) and promoted it to a
prominent emerald callout card at the top of the agent flow.

Added a "Building skills?" developer-resources card at the bottom
linking xpr-network-dev-skill (foundational dev reference,
previously invisible on the frontend per the audit).

## Copy buttons everywhere

New components:
- frontend/src/components/CopyButton.tsx (icon button, top-right
  positioning, checkmark feedback for 1.8s, fallback to textarea
  selection trick on non-secure contexts)
- frontend/src/components/CodeBlock.tsx (wraps existing
  bg-zinc-800 styling, accepts copyText for paste-ready payload
  separate from display children)

Applied across:
- get-started.tsx — every multi-line shell snippet
- register.tsx — Deploy block (the 8-line keychain + scaffold sequence)
- Other code blocks remain as inline `<code>` for now (covered in PR β)

## Operator-blocking content fixes the audits surfaced

- how-it-works hero: "Running on testnet today" → "Live on XPR
  Network mainnet, with testnet available for experiments." The old
  copy was actively misleading first-time visitors; mainnet is
  currently live with 56 active agents, 27 jobs, 4 arbitrators.
- ERC-8004 → EIP-8004 across user-facing pages (the EIP is
  pre-finalized; ERC- is for finalized ones).
- Home hero CTA: "How It Works" → "Get Started". The page that
  walks operators through what to do was previously reachable only
  from the header dropdown; first-time visitors who scrolled the
  hero had no obvious "start here" affordance.
- Test-count breakdown grid: dropped the "MCP Tools: 72" tile that
  was sitting in a "Total Tests" category — a category error caught
  by the audit. Consolidated to 5 tiles, all tests.

## Register page P0 fixes

- Description field is now client-side required (matches contract:
  agentcore.contract.ts:476 enforces 1-256 chars; the form was
  letting operators submit empty descriptions and hit a confusing
  on-chain assertion failure).
- Protocol dropdown dropped `websocket` and `mqtt` — the contract's
  URL-prefix check (agentcore.contract.ts:483-486) only accepts
  http://, https://, grpc://, wss://. The dropdown advertised
  options that would silently revert the tx.
- Network indicator added next to "Registering as @account" block
  with explicit mainnet/testnet badge. The header-only network
  pill was easy to miss; the audit caught wrong-chain registration
  risk for operators with stale localStorage network settings.
- Trust score preview added: "You'll start at 0/100, here's how it
  grows". Sets expectations before submit; previously operators
  submitted thinking KYC alone would give them 30 points and
  bounced when they saw 0 on their agent profile.
- Wallet-connect inline CTA when no session: button + WebAuth/
  Anchor install pointers. Previously the form just sat disabled
  with no path forward.
- start.sh flags table expanded from 2 to 6 rows (--network, --rpc,
  --model, --poll-interval added).

## Sitewide metadata fix

New SiteHead component centralises og:url, og:title, og:description,
og:image, twitter:card across pages that previously inherited a
broken default. The audit caught og:image pointing at
xpr-agents-frontend.vercel.app (the stale preview domain) on every
page; now points at xpragents.com/og-image.png. Wired into
get-started and how-it-works. (index.tsx keeps its inline Head
because the JSON-LD structured data lives there.)

## Footer

Added xpr-network-dev-skill link to Developers section. Also added
create-xpr-agent (was missing) and the security model doc.

## Version bumps

- @xpr-agents/openclaw → 0.4.3 (bin entry for setup-security, SKILL.md
  Pillar 2 safety rule)
- create-xpr-agent → 0.6.0 (start.sh first-run security check,
  setup-security.sh ships in the template — minor bump for the new
  template file)

## Verification

- 80 openclaw tests pass
- Frontend builds clean (npm run build, all 13 routes prerendered)
- Scaffold sanity (CI): template/setup-security.sh matches
  openclaw/starter/setup-security.sh matches openclaw/scripts/
  setup-security.sh; template/start.sh matches openclaw/starter/
  start.sh; template/.env.example matches starter
- Smoke test: setup-security.sh execution on a TTY against
  mragentsmith (already-secured account) exits cleanly with
  "Already secured" — idempotency verified

PR β (action-surface P0s — Hire CTA on agent profile, direct-hire
in Post Job, useChainStream perf, getLeaderboard N+1, testnet
indexer fix, etc.) lands next in a separate PR.
@paulgnz paulgnz merged commit 257d016 into main May 15, 2026
5 checks passed
@paulgnz paulgnz deleted the feat/owner-permission-recovery-pattern branch May 15, 2026 23:40
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.

1 participant