mirror of
https://github.com/AeThex-Corporation/AeThex-OS.git
synced 2026-04-17 22:27:19 +00:00
new file: script/seed.ts
This commit is contained in:
parent
f97122135d
commit
670aec8068
4 changed files with 188 additions and 0 deletions
|
|
@ -6,6 +6,7 @@ import { ArrowLeft, Terminal as TerminalIcon, Copy, Trash2 } from "lucide-react"
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@/components/ui/select";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
|
||||
interface TerminalLine {
|
||||
type: 'input' | 'output' | 'error' | 'system';
|
||||
|
|
@ -27,6 +28,7 @@ export default function Terminal() {
|
|||
const [cliLabel, setCliLabel] = useState<string>("");
|
||||
const eventSourceRef = useRef<EventSource | null>(null);
|
||||
const currentRunId = useRef<string | null>(null);
|
||||
const { toast } = useToast();
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
|
|
@ -188,6 +190,7 @@ export default function Terminal() {
|
|||
if (cliStatus === "running") return;
|
||||
setCliStatus("running");
|
||||
appendCliLine('system', `▸ Running ${cliCommand}...`);
|
||||
toast({ title: "CLI", description: `Started ${cliCommand}`, variant: "default" });
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/admin/cli/start', {
|
||||
|
|
@ -201,6 +204,7 @@ export default function Terminal() {
|
|||
const text = await res.text();
|
||||
appendCliLine('error', `Start failed: ${text || res.status}`);
|
||||
setCliStatus("error");
|
||||
toast({ title: "CLI Error", description: `Failed to start ${cliCommand}`, variant: "destructive" });
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -218,6 +222,7 @@ export default function Terminal() {
|
|||
es.addEventListener('error', (evt) => {
|
||||
appendCliLine('error', 'Stream error');
|
||||
setCliStatus("error");
|
||||
toast({ title: "CLI Error", description: `Stream error for ${cliCommand}`, variant: "destructive" });
|
||||
es.close();
|
||||
});
|
||||
|
||||
|
|
@ -225,6 +230,7 @@ export default function Terminal() {
|
|||
const status = evt.data === 'success' ? 'done' : 'error';
|
||||
setCliStatus(status as any);
|
||||
appendCliLine(status === 'done' ? 'system' : 'error', `▸ ${cliLabel || cliCommand} ${status}`);
|
||||
toast({ title: status === 'done' ? "CLI Success" : "CLI Failed", description: `${cliLabel || cliCommand} ${status}` });
|
||||
es.close();
|
||||
currentRunId.current = null;
|
||||
});
|
||||
|
|
@ -232,6 +238,7 @@ export default function Terminal() {
|
|||
} catch (err) {
|
||||
appendCliLine('error', 'Failed to start CLI command');
|
||||
setCliStatus("error");
|
||||
toast({ title: "CLI Error", description: `Failed to start ${cliCommand}`, variant: "destructive" });
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
141
docs/ENTITLEMENTS_QUICKSTART.md
Normal file
141
docs/ENTITLEMENTS_QUICKSTART.md
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
# Entitlements Quickstart
|
||||
|
||||
This guide helps you set up the OS Kernel (identity + entitlements) and use the API to issue, verify, resolve, and revoke entitlements.
|
||||
|
||||
## 1) Run OS Kernel Migration
|
||||
|
||||
Ensure `DATABASE_URL` is set in your environment (Railway/Supabase Postgres). Then run the OS Kernel migration. You can do this either from the dev shell or the in-app Terminal (Admin only).
|
||||
|
||||
- Dev shell:
|
||||
- `npx ts-node script/run-os-migration.ts`
|
||||
- In-app Terminal:
|
||||
- Command: `migrate-os` (now available in the command dropdown)
|
||||
|
||||
This creates tables:
|
||||
- `aethex_subjects`, `aethex_subject_identities`
|
||||
- `aethex_issuers`, `aethex_issuer_keys`
|
||||
- `aethex_entitlements`, `aethex_entitlement_events`
|
||||
- `aethex_audit_log`
|
||||
|
||||
## 2) Create an Issuer
|
||||
|
||||
Insert an issuer record with a `public_key` and optional metadata. You can use SQL or your DB console (Supabase) for now.
|
||||
|
||||
Example SQL:
|
||||
|
||||
```sql
|
||||
INSERT INTO public.aethex_issuers (name, issuer_class, scopes, public_key, is_active)
|
||||
VALUES ('AeThex Platform', 'platform', '["issue","revoke"]'::json, 'PUBLIC_KEY_STRING', true)
|
||||
RETURNING id;
|
||||
```
|
||||
|
||||
Save the returned `id` as your `issuer_id`.
|
||||
|
||||
## 3) Issue an Entitlement
|
||||
|
||||
Endpoint: `POST /api/os/entitlements/issue`
|
||||
|
||||
Headers:
|
||||
- `x-issuer-id: <issuer_id>`
|
||||
|
||||
Body:
|
||||
```json
|
||||
{
|
||||
"subject_id": "<optional: internal subject id>",
|
||||
"external_subject_ref": "roblox:12345",
|
||||
"entitlement_type": "achievement",
|
||||
"scope": "project",
|
||||
"data": { "name": "Alpha Access" },
|
||||
"expires_at": null
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"entitlement": {
|
||||
"id": "...",
|
||||
"type": "achievement",
|
||||
"scope": "project",
|
||||
"created_at": "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4) Verify an Entitlement
|
||||
|
||||
Endpoint: `POST /api/os/entitlements/verify`
|
||||
|
||||
Body:
|
||||
```json
|
||||
{ "entitlement_id": "..." }
|
||||
```
|
||||
|
||||
Response (valid):
|
||||
```json
|
||||
{
|
||||
"valid": true,
|
||||
"entitlement": {
|
||||
"id": "...",
|
||||
"type": "achievement",
|
||||
"scope": "project",
|
||||
"data": { "name": "Alpha Access" },
|
||||
"issuer": { "id": "...", "name": "AeThex Platform", "class": "platform" },
|
||||
"issued_at": "...",
|
||||
"expires_at": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response (revoked/expired):
|
||||
```json
|
||||
{ "valid": false, "reason": "revoked|expired", ... }
|
||||
```
|
||||
|
||||
## 5) Resolve Entitlements (by subject or external ref)
|
||||
|
||||
Endpoint: `GET /api/os/entitlements/resolve`
|
||||
|
||||
Query params (choose one path):
|
||||
- `?subject_id=<internal_subject_id>`
|
||||
- `?platform=roblox&id=12345`
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"entitlements": [
|
||||
{
|
||||
"id": "...",
|
||||
"type": "achievement",
|
||||
"scope": "project",
|
||||
"data": { "name": "Alpha Access" },
|
||||
"issuer": { "name": "AeThex Platform", "class": "platform" },
|
||||
"issued_at": "...",
|
||||
"expires_at": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 6) Revoke an Entitlement
|
||||
|
||||
Endpoint: `POST /api/os/entitlements/revoke`
|
||||
|
||||
Headers:
|
||||
- `x-issuer-id: <issuer_id>`
|
||||
|
||||
Body:
|
||||
```json
|
||||
{ "entitlement_id": "...", "reason": "Fraudulent use" }
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{ "success": true, "message": "Entitlement revoked" }
|
||||
```
|
||||
|
||||
## Notes
|
||||
- All OS routes are protected by the capability guard and expect authenticated context where relevant.
|
||||
- Use Supabase console to inspect tables and audit logs.
|
||||
- For production, plan issuer key rotation via `aethex_issuer_keys`; rotation endpoints can be added similarly.
|
||||
39
script/seed.ts
Normal file
39
script/seed.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import dotenv from "dotenv";
|
||||
import pkg from "pg";
|
||||
|
||||
dotenv.config();
|
||||
const { Client } = pkg as any;
|
||||
|
||||
async function main() {
|
||||
const client = new Client({ connectionString: process.env.DATABASE_URL, ssl: { rejectUnauthorized: false } });
|
||||
await client.connect();
|
||||
|
||||
try {
|
||||
console.log("Seeding default issuer if missing...");
|
||||
const name = "AeThex Platform";
|
||||
|
||||
const existing = await client.query(
|
||||
'SELECT id FROM public.aethex_issuers WHERE name = $1 LIMIT 1;',
|
||||
[name]
|
||||
);
|
||||
|
||||
if (existing.rows.length) {
|
||||
console.log(`Issuer exists: ${existing.rows[0].id}`);
|
||||
} else {
|
||||
const insert = await client.query(
|
||||
'INSERT INTO public.aethex_issuers (name, issuer_class, scopes, public_key, is_active) VALUES ($1, $2, $3::json, $4, $5) RETURNING id;',
|
||||
[name, 'platform', JSON.stringify(["issue","revoke"]), 'PUBLIC_KEY_STRING', true]
|
||||
);
|
||||
console.log(`Issuer created: ${insert.rows[0].id}`);
|
||||
}
|
||||
|
||||
console.log("Done.");
|
||||
} catch (err: any) {
|
||||
console.error("Seed failed:", err.message || err);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await client.end();
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
@ -47,6 +47,7 @@ export async function registerRoutes(
|
|||
build: { cmd: "npm", args: ["run", "build"], label: "npm run build" },
|
||||
"migrate-status": { cmd: "npx", args: ["drizzle-kit", "status"], label: "drizzle status" },
|
||||
migrate: { cmd: "npx", args: ["drizzle-kit", "migrate:push"], label: "drizzle migrate" },
|
||||
"migrate-os": { cmd: "npx", args: ["ts-node", "script/run-os-migration.ts"], label: "os kernel migrate" },
|
||||
seed: { cmd: "npx", args: ["ts-node", "script/seed.ts"], label: "seed" },
|
||||
test: { cmd: "bash", args: ["./test-implementation.sh"], label: "test-implementation" },
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue