Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .github/workflows/example-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:
types: [opened, synchronize, reopened]
paths:
- "examples/status-message-dapp/**"
- "examples/perch-authz-console/**"
- ".github/workflows/example-preview.yml"
# The example exercises the wallet's connect / delegation-handover /
# session-signing flows, so a wallet or SDK PR needs the example preview
Expand Down Expand Up @@ -60,6 +61,7 @@ jobs:
npm run build -w @nidohq/passkey-sdk
npm run build -w @nidohq/stellar-wallets-kit-module
npm run build -w status_message
npm run build -w @nidohq/testkit

- name: Build the example (apex base)
run: npx vite build
Expand All @@ -69,6 +71,15 @@ jobs:
run: echo "/* /index.html 200" > dist/_redirects
working-directory: examples/status-message-dapp

# Extra examples nested under their own subpath in the same deploy.
# Relative base (--base=./) so each loads correctly from its subpath.
- name: Build perch-authz-console (nested)
run: npm run build:preview
working-directory: examples/perch-authz-console

- name: Nest extra examples under the deploy
run: cp -r examples/perch-authz-console/dist examples/status-message-dapp/dist/perch-authz-console

# Deploy to a branch alias of the mysoroban project. The custom-domain
# wildcard (*.mysoroban.xyz) only serves the project's PRODUCTION branch,
# so for the example we use wrangler's branch-alias *.pages.dev URL — the
Expand Down Expand Up @@ -101,7 +112,10 @@ jobs:
const previewUrl = process.env.PREVIEW_URL
|| `https://example-pr-${prNum}.mysoroban.pages.dev`;
const liveUrl = `https://${context.repo.owner}.github.io/${context.repo.repo}/`;
const body = `**Example dApp preview deployed!**\n\n${previewUrl}\n\nThe \`status-message\` example (testnet), wallet = THIS PR's preview (https://${prNum}.nido.fyi). The live home is ${liveUrl} once merged.`;
const body = `**Example dApp preview deployed!**\n\n`
+ `- \`status-message\` — ${previewUrl}\n`
+ `- \`perch-authz-console\` — ${previewUrl.replace(/\/?$/, '/')}perch-authz-console/\n\n`
+ `status-message runs on testnet, wallet = THIS PR's preview (https://${prNum}.nido.fyi); perch-authz-console runs fully local. The live home is ${liveUrl} once merged.`;

const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
Expand Down
42 changes: 29 additions & 13 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
name: Deploy Example to GitHub Pages
name: Deploy examples to GitHub Pages

# Deploys examples/status-message-dapp/ as a live testnet demo at the GitHub
# Pages project URL for this repository. Independent of the Cloudflare deploy of
# the main Nido frontend (see deploy.yml / preview.yml).
# Deploys the repo's example dApps as a live testnet demo at the GitHub Pages
# project URL. status-message-dapp is the home (project root); each additional
# example is nested under its own subpath. To add an example: build it into a
# subfolder of the uploaded site (see the "extra examples" step). Independent of
# the Cloudflare deploy of the main Nido frontend (deploy.yml / preview.yml).
#
# /<repo>/ → status-message-dapp
# /<repo>/perch-authz-console/ → perch × Nido authorization console

on:
push:
branches: [main]
paths:
- "examples/status-message-dapp/**"
- "examples/perch-authz-console/**"
- "packages/**"
- ".github/workflows/pages.yml"
workflow_dispatch:

Expand All @@ -17,14 +24,11 @@ permissions:
pages: write
id-token: write

# Allow one concurrent deployment; don't cancel an in-progress publish.
concurrency:
group: pages
cancel-in-progress: false

# Build-time config for the live demo. All public (no secrets). The committed
# client is bound to the testnet contract id; these point the frontend at
# testnet and at the production Nido passkey wallet.
# Build-time config for the status-message live demo. All public (no secrets).
env:
PAGES_BASE_PATH: "/${{ github.event.repository.name }}/"
PUBLIC_STELLAR_NETWORK: TESTNET
Expand All @@ -47,24 +51,36 @@ jobs:
- name: Install dependencies
run: npm ci

# The example imports these workspace packages, which publish built dist/.
# The status_message client is committed as source and built here too.
# Workspace packages the examples import (each publishes a built dist/).
- name: Build workspace dependencies
run: |
npm run build -w @nidohq/passkey-sdk
npm run build -w @nidohq/stellar-wallets-kit-module
npm run build -w status_message
npm run build -w @nidohq/testkit

- name: Build the example (GitHub Pages base)
# --- home: status-message-dapp at the project root ---
- name: Build status-message-dapp (GitHub Pages base)
run: npm run build:pages
working-directory: examples/status-message-dapp

# GitHub Pages serves 404.html for unmatched paths; making it the SPA
# shell lets client-side routes under the project path survive a direct reload.
# GitHub Pages serves 404.html for unmatched paths; making it the SPA shell
# lets status-message's client-side routes survive a direct reload.
- name: SPA fallback
run: cp dist/index.html dist/404.html
working-directory: examples/status-message-dapp

# --- extra examples: each nested under its own subpath ---
# Relative base (--base=./) so the bundle loads correctly from the subpath.
- name: Build perch-authz-console (nested)
run: npm run build:preview
working-directory: examples/perch-authz-console

- name: Nest extra examples under the site
run: |
cp -r examples/perch-authz-console/dist \
examples/status-message-dapp/dist/perch-authz-console

- uses: actions/configure-pages@v5

- uses: actions/upload-pages-artifact@v3
Expand Down
7 changes: 7 additions & 0 deletions examples/perch-authz-console/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules/
dist/
artifacts/
test-results/
playwright-report/
.playwright/
*.local
62 changes: 62 additions & 0 deletions examples/perch-authz-console/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# perch × Nido — Authorization Console

A dApp that **logs in a local-key Nido smart account** (no passkey), visualizes
its perch authorization policy, simulates `__check_auth` locally, and lets you
build more complex policies — including a **post-quantum ML-DSA** signer.

Everything is real and local: the account C-address, the signatures, the perch
`doc_hash`, and the allow/deny verdicts all come from
[`@nidohq/testkit`](../../packages/testkit) (nidohq/nido#188). No network, no
contracts deployed.

## Run it

```sh
npm install # from the repo root (workspaces)
npm run dev -w perch-authz-console
```

## What it shows

- **Wallet login including Nido** — a `NidoLocalModule` implementing the
`@creit.tech/stellar-wallets-kit` `ModuleInterface`, so Nido is a wallet any
kit dApp can connect — here with a **local key** instead of a passkey.
- **Every verifier** — one signer each for **secp256r1** (the real
`webauthn-verifier`, driven by a local P-256 key), **ed25519**, and
**ML-DSA-65** (post-quantum). The last two, and perch on-chain, are simulated
ahead of their contracts (ML-DSA groundwork: nido#143).
- **Reachable calls** — what each key can actually do, derived from the policy.
- **Simulate `__check_auth`** — pick a call + signers → Kleene verdict + trace.
- **Build a policy** — add rules (scope, functions, arg predicates, spend cap);
the `doc_hash` updates live.
- **Attenuate** — narrow a rule with the fail-closed subset check
(`reachable(child) ⊆ reachable(parent)`); widening is refused.

## Verify (browser snapshots)

```sh
npx playwright install chromium
npm run test:e2e -w perch-authz-console # drives the full flow, writes artifacts/*.png
```

## Deploy

- `npm run build` — local/apex build (base `/`).
- `npm run build:preview` — relative base (`./`), used when nested under a subpath.

This example is hosted **alongside** `status-message-dapp` by the shared example
workflows — no per-example workflow:

- `.github/workflows/pages.yml` — the GitHub Pages home; this example lives at
`/<repo>/perch-authz-console/` (status-message stays at the root).
- `.github/workflows/example-preview.yml` — the per-PR Cloudflare preview, which
deploys both examples and comments both URLs.

Add another example by nesting its build in those two workflows the same way.

## Roadmap

The simulator is a faithful TS model. Next, behind the same call: run the real
`soroban-env` in the browser (wasmi) backed by
[rs-soroban-sdk#1657](https://github.com/stellar/rs-soroban-sdk/pull/1657)'s
local-storage cache — lazy testnet pulls, otherwise fully offline.
14 changes: 14 additions & 0 deletions examples/perch-authz-console/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>perch × Nido — Authorization Console</title>
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230C8B99' stroke-width='2'%3E%3Cpath d='M4 20V10a8 8 0 0 1 16 0v10'/%3E%3Cpath d='M4 20h16'/%3E%3Ccircle cx='12' cy='10' r='2.4'/%3E%3C/svg%3E" />
<link rel="stylesheet" href="/src/styles.css" />
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
26 changes: 26 additions & 0 deletions examples/perch-authz-console/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "perch-authz-console",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"build:pages": "tsc && vite build --base=/${REPO_NAME:-nido}/",
"build:preview": "tsc && vite build --base=./",
"preview": "vite preview",
"typecheck": "tsc --noEmit",
"test:e2e": "playwright test"
},
"dependencies": {
"@creit.tech/stellar-wallets-kit": "^2.2.0",
"@nidohq/testkit": "*",
"@noble/hashes": "^2.2.0"
},
"devDependencies": {
"@playwright/test": "^1.50.0",
"typescript": "~5.9.3",
"vite": "^7.3.1",
"vite-plugin-node-polyfills": "^0.25.0"
}
}
18 changes: 18 additions & 0 deletions examples/perch-authz-console/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
testDir: './tests',
fullyParallel: true,
reporter: [['list']],
use: {
baseURL: 'http://localhost:5177',
viewport: { width: 1200, height: 1400 },
},
webServer: {
command: 'npx vite --port 5177 --strictPort',
url: 'http://localhost:5177',
reuseExistingServer: !process.env.CI,
timeout: 60_000,
},
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
});
Loading
Loading