move repos into monorepo

This commit is contained in:
Timur Gordon
2025-11-13 20:44:00 +01:00
commit 4b23e5eb7f
204 changed files with 33737 additions and 0 deletions

146
bin/supervisor/docs/AUTH.md Normal file
View File

@@ -0,0 +1,146 @@
# Hero Supervisor Authentication
The Hero Supervisor now supports API key-based authentication with three permission scopes:
## Permission Scopes
1. **Admin** - Full access to all operations including key management
2. **Registrar** - Can register new runners
3. **User** - Can create and manage jobs
## Starting the Supervisor with an Admin Key
Bootstrap an initial admin key when starting the supervisor:
```bash
cargo run --bin supervisor -- --bootstrap-admin-key "my-admin"
```
This will output:
```
╔════════════════════════════════════════════════════════════╗
║ 🔑 Admin API Key Created ║
╚════════════════════════════════════════════════════════════╝
Name: my-admin
Key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Scope: admin
⚠️ SAVE THIS KEY - IT WILL NOT BE SHOWN AGAIN!
╚════════════════════════════════════════════════════════════╝
```
**IMPORTANT:** Save this key securely - it will not be displayed again!
## API Endpoints
### Verify API Key
Verify a key and get its metadata:
```bash
curl -X POST http://127.0.0.1:3030 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "auth.verify",
"params": {
"key": "your-api-key-here"
},
"id": 1
}'
```
Response:
```json
{
"jsonrpc": "2.0",
"result": {
"valid": true,
"name": "my-admin",
"scope": "admin"
},
"id": 1
}
```
### Create New API Key (Admin Only)
```bash
curl -X POST http://127.0.0.1:3030 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "auth.create_key",
"params": {
"admin_key": "your-admin-key",
"name": "runner-bot",
"scope": "registrar"
},
"id": 1
}'
```
Response:
```json
{
"jsonrpc": "2.0",
"result": {
"key": "new-generated-uuid",
"name": "runner-bot",
"scope": "registrar",
"created_at": "2025-10-27T15:00:00Z",
"expires_at": null
},
"id": 1
}
```
### List All API Keys (Admin Only)
```bash
curl -X POST http://127.0.0.1:3030 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "auth.list_keys",
"params": {
"admin_key": "your-admin-key"
},
"id": 1
}'
```
### Remove API Key (Admin Only)
```bash
curl -X POST http://127.0.0.1:3030 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "auth.remove_key",
"params": {
"admin_key": "your-admin-key",
"key": "key-to-remove"
},
"id": 1
}'
```
## Using Keys in the Admin UI
The admin UI will use the `auth.verify` endpoint during login to:
1. Validate the provided API key
2. Retrieve the key's name and scope
3. Display the user's name and permissions in the header
4. Show/hide UI elements based on scope
## Migration from Legacy Secrets
The supervisor still supports the legacy secret-based authentication for backward compatibility:
- `--admin-secret` - Legacy admin secrets
- `--user-secret` - Legacy user secrets
- `--register-secret` - Legacy register secrets
However, the new API key system is recommended for better management and auditability.

View File

@@ -0,0 +1,268 @@
# Mycelium Integration - Now Optional!
The Mycelium integration is now an optional feature. The supervisor can run with just the OpenRPC HTTP server, making it simpler to use and deploy.
## What Changed
### Before
- Mycelium integration was always enabled
- Supervisor would continuously try to connect to Mycelium on port 8990
- Error logs if Mycelium wasn't available
- Required additional dependencies
### After
- ✅ Mycelium is now an optional feature
- ✅ Supervisor runs with clean OpenRPC HTTP server by default
- ✅ No connection errors when Mycelium isn't needed
- ✅ Smaller binary size without Mycelium dependencies
## Running the Supervisor
### Option 1: Simple OpenRPC Server (Recommended)
**No Mycelium, just OpenRPC:**
```bash
# Using the helper script
./run_supervisor_simple.sh
# Or manually
MYCELIUM_URL="" cargo run --bin supervisor -- \
--redis-url redis://localhost:6379 \
--port 3030
```
This starts:
- ✅ OpenRPC HTTP server on port 3030
- ✅ Redis connection for job queuing
- ❌ No Mycelium integration
### Option 2: With Mycelium Integration
**Enable Mycelium feature:**
```bash
# Build with Mycelium support
cargo build --bin supervisor --features mycelium
# Run with Mycelium URL
MYCELIUM_URL="http://localhost:8990" cargo run --bin supervisor --features mycelium -- \
--redis-url redis://localhost:6379 \
--port 3030
```
This starts:
- ✅ OpenRPC HTTP server on port 3030
- ✅ Redis connection for job queuing
- ✅ Mycelium integration (connects to daemon)
## Feature Flags
### Available Features
| Feature | Description | Default |
|---------|-------------|---------|
| `cli` | Command-line interface | ✅ Yes |
| `mycelium` | Mycelium integration | ❌ No |
### Building with Features
```bash
# Default build (CLI only, no Mycelium)
cargo build --bin supervisor
# With Mycelium
cargo build --bin supervisor --features mycelium
# Minimal (no CLI, no Mycelium)
cargo build --bin supervisor --no-default-features
```
## Architecture
### Without Mycelium (Default)
```
┌─────────────────┐
│ Client │
└────────┬────────┘
│ HTTP/JSON-RPC
┌─────────────────┐
│ Supervisor │
│ OpenRPC Server │
│ (Port 3030) │
└────────┬────────┘
│ Redis
┌─────────────────┐
│ Runners │
└─────────────────┘
```
### With Mycelium (Optional)
```
┌─────────────────┐
│ Client │
└────────┬────────┘
│ HTTP/JSON-RPC
┌─────────────────┐ ┌──────────────┐
│ Supervisor │◄────►│ Mycelium │
│ OpenRPC Server │ │ Daemon │
│ (Port 3030) │ │ (Port 8990) │
└────────┬────────┘ └──────────────┘
│ Redis
┌─────────────────┐
│ Runners │
└─────────────────┘
```
## Environment Variables
| Variable | Description | Default | Required |
|----------|-------------|---------|----------|
| `MYCELIUM_URL` | Mycelium daemon URL | `http://127.0.0.1:8990` | No |
| `RUST_LOG` | Log level | `info` | No |
**To disable Mycelium:**
```bash
export MYCELIUM_URL=""
```
## Dependencies
### Core Dependencies (Always)
- `tokio` - Async runtime
- `redis` - Job queuing
- `jsonrpsee` - OpenRPC server
- `runner_rust` - Job model
### Mycelium Dependencies (Optional)
- `reqwest` - HTTP client
- `base64` - Encoding
- `rand` - Random IDs
## Examples
All examples work without Mycelium:
```bash
# Simple end-to-end example
RUST_LOG=info cargo run --example simple_e2e
# Full automated demo
RUST_LOG=info cargo run --example end_to_end_demo
```
## Migration Guide
### If you were using Mycelium
**Before:**
```bash
cargo run --bin supervisor
# Would try to connect to Mycelium automatically
```
**After:**
```bash
# Option A: Disable Mycelium (recommended for most use cases)
MYCELIUM_URL="" cargo run --bin supervisor
# Option B: Enable Mycelium feature
cargo run --bin supervisor --features mycelium
```
### If you weren't using Mycelium
**Before:**
```bash
cargo run --bin supervisor
# Would see connection errors to port 8990
```
**After:**
```bash
cargo run --bin supervisor
# Clean startup, no connection errors! 🎉
```
## Benefits
### For Development
- ✅ Faster builds (fewer dependencies)
- ✅ Simpler setup (no Mycelium daemon needed)
- ✅ Cleaner logs (no connection errors)
- ✅ Easier debugging
### For Production
- ✅ Smaller binary size
- ✅ Fewer runtime dependencies
- ✅ More flexible deployment
- ✅ Optional advanced features
## Testing
### Test without Mycelium
```bash
# Build
cargo build --bin supervisor
# Run tests
cargo test
# Run examples
cargo run --example simple_e2e
```
### Test with Mycelium
```bash
# Build with feature
cargo build --bin supervisor --features mycelium
# Start Mycelium daemon (if you have one)
# mycelium-daemon --port 8990
# Run supervisor
MYCELIUM_URL="http://localhost:8990" cargo run --bin supervisor --features mycelium
```
## Troubleshooting
### "Mycelium integration not enabled"
This is informational, not an error. If you need Mycelium:
```bash
cargo build --features mycelium
```
### "HTTP request failed: error sending request"
If you see this with Mycelium enabled, check:
1. Is Mycelium daemon running?
2. Is the URL correct? (`MYCELIUM_URL`)
3. Is the port accessible?
Or simply disable Mycelium:
```bash
export MYCELIUM_URL=""
```
## Summary
🎉 **The supervisor now runs cleanly with just OpenRPC!**
- Default: OpenRPC HTTP server only
- Optional: Enable Mycelium with `--features mycelium`
- No more connection errors when Mycelium isn't needed
- Simpler, faster, cleaner!
---
**Status:** ✅ Complete
**Version:** 0.1.0
**Last Updated:** 2025-10-24

View File

@@ -0,0 +1,214 @@
# Quick Start Guide
Complete guide to running the Hero Supervisor with OSIS runners and examples.
## Prerequisites
1. **Redis** - Must be running
2. **Rust** - Version 1.88+ (run `rustup update`)
## 1. Start Redis
```bash
redis-server
```
## 2. Start Supervisor
```bash
cd /Users/timurgordon/code/git.ourworld.tf/herocode/supervisor
cargo run --bin supervisor
```
You should see:
```
╔════════════════════════════════════════════════════════════╗
║ Hero Supervisor Started ║
╚════════════════════════════════════════════════════════════╝
📡 OpenRPC Server: http://127.0.0.1:3030
🔗 Redis: redis://localhost:6379
🌐 Mycelium: Not compiled (use --features mycelium)
╚════════════════════════════════════════════════════════════╝
```
## 3. Start OSIS Runner
```bash
cd /Users/timurgordon/code/git.ourworld.tf/herocode/runner_rust
cargo run --bin runner_osis -- test_runner \
--redis-url redis://localhost:6379 \
--db-path /tmp/test_runner.db
```
You should see:
```
Starting OSIS Sync Runner with ID: test_runner
Database path: /tmp/test_runner.db
Redis URL: redis://localhost:6379
OSIS Sync Runner 'test_runner' started successfully
```
## 4. Run Example
```bash
cd /Users/timurgordon/code/git.ourworld.tf/herocode/supervisor
RUST_LOG=info cargo run --example simple_e2e
```
## Terminal Layout
```
┌─────────────────────┬─────────────────────┐
│ Terminal 1 │ Terminal 2 │
│ Redis │ Supervisor │
│ redis-server │ cargo run --bin │
│ │ supervisor │
├─────────────────────┼─────────────────────┤
│ Terminal 3 │ Terminal 4 │
│ OSIS Runner │ Example │
│ cargo run --bin │ cargo run │
│ runner_osis │ --example │
│ │ simple_e2e │
└─────────────────────┴─────────────────────┘
```
## What Each Component Does
### Redis
- Job queue storage
- Job result storage
- Runner coordination
### Supervisor
- OpenRPC HTTP server (port 3030)
- Job dispatch to runners
- Runner registration
- Job execution coordination
### OSIS Runner
- Listens for jobs on Redis queue
- Executes Rhai scripts
- Stores results back to Redis
- Uses HeroDB for data persistence
### Example
- Creates jobs with Rhai scripts
- Sends jobs to supervisor via OpenRPC
- Receives results
- Demonstrates both blocking and non-blocking modes
## Architecture
```
┌─────────────┐
│ Example │ (simple_e2e.rs)
└──────┬──────┘
│ HTTP/JSON-RPC
┌─────────────┐
│ Supervisor │ (port 3030)
└──────┬──────┘
│ Redis Queue
┌─────────────┐
│ OSIS Runner │ (test_runner)
└──────┬──────┘
┌─────────────┐
│ HeroDB │ (Redis + local DB)
└─────────────┘
```
## Troubleshooting
### "Connection refused" on port 3030
- Make sure supervisor is running
- Check if another process is using port 3030
### "Connection refused" on port 6379
- Make sure Redis is running
- Check: `redis-cli ping` (should return "PONG")
### Runner not receiving jobs
- Check runner is registered: Look for "Runner registered successfully" in example output
- Check Redis connection: Both supervisor and runner must use same Redis URL
- Check queue name matches: Should be `hero:q:work:type:osis:group:default:inst:test_runner`
### "Job execution timeout"
- Increase timeout in job builder: `.timeout(120)`
- Check if runner is actually processing jobs (look for logs)
## Example Output
### Successful Run
```
╔════════════════════════════════════════╗
║ Simple End-to-End Demo ║
╚════════════════════════════════════════╝
📋 Step 1: Registering Runner
─────────────────────────────────────────
✅ Runner registered successfully
📋 Step 2: Running a Simple Job (Blocking)
─────────────────────────────────────────
✅ Job completed!
Result: {"message":"Hello from the runner!","number":42}
📋 Step 3: Running a Calculation Job
─────────────────────────────────────────
✅ Calculation completed!
Result: {"sum":55,"product":3628800,"count":10}
📋 Step 4: Starting a Non-Blocking Job
─────────────────────────────────────────
✅ Job started!
Job ID: abc-123 (running in background)
🎉 Demo completed successfully!
```
## Next Steps
1. **Try different Rhai scripts** - Modify the payload in examples
2. **Add more runners** - Start multiple runners with different IDs
3. **Explore the API** - Use the OpenRPC client library
4. **Build your own client** - See `client/` for examples
## Useful Commands
```bash
# Check Redis
redis-cli ping
# List Redis keys
redis-cli keys "hero:*"
# Monitor Redis commands
redis-cli monitor
# Check supervisor is running
curl http://localhost:3030
# View runner logs
# (check terminal where runner is running)
```
## Clean Up
```bash
# Stop all processes (Ctrl+C in each terminal)
# Clean up test database
rm /tmp/test_runner.db
# (Optional) Flush Redis
redis-cli FLUSHALL
```
---
**Status:** ✅ Ready to Use
**Last Updated:** 2025-10-24

View File

@@ -0,0 +1,58 @@
# Repository Restructure
## Changes Made
The supervisor repository has been restructured to follow a cleaner organization:
### Before:
```
supervisor/
├── clients/
│ ├── openrpc/ # OpenRPC client library
│ └── admin-ui/ # Admin UI (Yew WASM app)
├── src/ # Main supervisor library
└── cmd/ # Supervisor binary
```
### After:
```
supervisor/
├── client/ # OpenRPC client library (renamed from clients/openrpc)
├── ui/ # Admin UI (renamed from clients/admin-ui)
├── src/ # Main supervisor library
└── cmd/ # Supervisor binary
```
## Package Names
The package names remain unchanged:
- **Client**: `hero-supervisor-openrpc-client`
- **UI**: `supervisor-admin-ui`
- **Main**: `hero-supervisor`
## Git Dependencies
External projects using Git URLs will automatically pick up the new structure:
```toml
# This continues to work
hero-supervisor-openrpc-client = { git = "https://git.ourworld.tf/herocode/supervisor.git" }
```
Cargo will find the package by name regardless of its location in the repository.
## Local Path Dependencies
If you have local path dependencies, update them:
```toml
# Old
hero-supervisor-openrpc-client = { path = "../supervisor/clients/openrpc" }
# New
hero-supervisor-openrpc-client = { path = "../supervisor/client" }
```
## Scripts and Documentation
All references in scripts, documentation, and examples have been updated to reflect the new structure.

View File

@@ -0,0 +1,333 @@
# Hero Supervisor Job API Convention
## Overview
The Hero Supervisor OpenRPC API follows a consistent naming convention for job-related operations:
- **`jobs.`** - General job operations (plural)
- **`job.`** - Specific job operations (singular)
This convention provides a clear distinction between operations that work with multiple jobs or create new jobs versus operations that work with a specific existing job.
## API Methods
### General Job Operations (`jobs.`)
#### `jobs.create`
Creates a new job without immediately queuing it to a runner.
**Parameters:**
- `secret` (string): Authentication secret (admin or user)
- `job` (Job object): Complete job specification
**Returns:**
- `job_id` (string): Unique identifier of the created job
**Usage:**
```json
{
"method": "jobs.create",
"params": {
"secret": "your-secret",
"job": {
"id": "job-123",
"caller_id": "client-1",
"context_id": "context-1",
"payload": "print('Hello World')",
"executor": "osis",
"runner": "osis-runner-1",
"timeout": 300,
"env_vars": {},
"created_at": "2023-01-01T00:00:00Z",
"updated_at": "2023-01-01T00:00:00Z"
}
}
}
```
#### `jobs.list`
Lists all jobs in the system with full details.
**Parameters:** None
**Returns:**
- `jobs` (array of Job objects): List of all jobs with complete information
**Usage:**
```json
{
"method": "jobs.list",
"params": []
}
```
**Response:**
```json
[
{
"id": "job-123",
"caller_id": "client-1",
"context_id": "context-1",
"payload": "print('Hello World')",
"executor": "osis",
"runner": "osis-runner-1",
"timeout": 300,
"env_vars": {},
"created_at": "2023-01-01T00:00:00Z",
"updated_at": "2023-01-01T00:00:00Z"
}
]
```
### Specific Job Operations (`job.`)
#### `job.run`
Runs a job immediately on the appropriate runner and returns the result.
**Parameters:**
- `secret` (string): Authentication secret (admin or user)
- `job` (Job object): Complete job specification
**Returns:**
- `result` (JobResult): Either success or error result
**JobResult Format:**
```json
// Success case
{
"success": "Job completed successfully with output..."
}
// Error case
{
"error": "Job failed with error message..."
}
```
**Usage:**
```json
{
"method": "job.run",
"params": {
"secret": "your-secret",
"job": { /* job object */ }
}
}
```
#### `job.start`
Starts a previously created job by queuing it to its assigned runner.
**Parameters:**
- `secret` (string): Authentication secret (admin or user)
- `job_id` (string): ID of the job to start
**Returns:** `null` (void)
**Usage:**
```json
{
"method": "job.start",
"params": {
"secret": "your-secret",
"job_id": "job-123"
}
}
```
#### `job.status`
Gets the current status of a job.
**Parameters:**
- `job_id` (string): ID of the job to check
**Returns:**
- `status` (JobStatusResponse): Current job status information
**JobStatusResponse Format:**
```json
{
"job_id": "job-123",
"status": "running",
"created_at": "2023-01-01T00:00:00Z",
"started_at": "2023-01-01T00:00:05Z",
"completed_at": null
}
```
**Status Values:**
- `created` - Job has been created but not queued
- `queued` - Job has been queued to a runner
- `running` - Job is currently executing
- `completed` - Job finished successfully
- `failed` - Job failed with an error
- `timeout` - Job timed out
**Usage:**
```json
{
"method": "job.status",
"params": ["job-123"]
}
```
#### `job.result`
Gets the result of a completed job. This method blocks until the result is available.
**Parameters:**
- `job_id` (string): ID of the job to get results for
**Returns:**
- `result` (JobResult): Either success or error result
**Usage:**
```json
{
"method": "job.result",
"params": ["job-123"]
}
```
#### `job.stop`
Stops a running job.
**Parameters:**
- `secret` (string): Authentication secret (admin or user)
- `job_id` (string): ID of the job to stop
**Returns:** `null` (void)
**Usage:**
```json
{
"method": "job.stop",
"params": {
"secret": "your-secret",
"job_id": "job-123"
}
}
```
#### `job.delete`
Deletes a job from the system.
**Parameters:**
- `secret` (string): Authentication secret (admin or user)
- `job_id` (string): ID of the job to delete
**Returns:** `null` (void)
**Usage:**
```json
{
"method": "job.delete",
"params": {
"secret": "your-secret",
"job_id": "job-123"
}
}
```
## Workflow Examples
### Fire-and-Forget Job
```javascript
// Create and immediately run a job
const result = await client.job_run(secret, jobSpec);
if (result.success) {
console.log("Job completed:", result.success);
} else {
console.error("Job failed:", result.error);
}
```
### Asynchronous Job Processing
```javascript
// 1. Create the job
const jobId = await client.jobs_create(secret, jobSpec);
// 2. Start the job
await client.job_start(secret, jobId);
// 3. Poll for completion (non-blocking)
let status;
do {
status = await client.job_status(jobId);
if (status.status === 'running') {
await sleep(1000); // Wait 1 second
}
} while (status.status === 'running' || status.status === 'queued');
// 4. Get the result
const result = await client.job_result(jobId);
```
### Batch Job Management
```javascript
// Create multiple jobs
const jobIds = [];
for (const jobSpec of jobSpecs) {
const jobId = await client.jobs_create(secret, jobSpec);
jobIds.push(jobId);
}
// Start all jobs
for (const jobId of jobIds) {
await client.job_start(secret, jobId);
}
// Monitor progress
const results = [];
for (const jobId of jobIds) {
const result = await client.job_result(jobId); // Blocks until complete
results.push(result);
}
// Optional: Stop or delete jobs if needed
for (const jobId of jobIds) {
await client.job_stop(secret, jobId); // Stop running job
await client.job_delete(secret, jobId); // Delete from system
}
```
## Authentication
All job operations require authentication using one of the following secret types:
- **Admin secrets**: Full access to all operations
- **User secrets**: Access to job operations (`jobs.create`, `job.run`, `job.start`)
- **Register secrets**: Only access to runner registration
## Error Handling
All methods return standard JSON-RPC error responses for:
- **Authentication errors** (-32602): Invalid or missing secrets
- **Job not found errors** (-32000): Job ID doesn't exist
- **Internal errors** (-32603): Server-side processing errors
## Migration from Legacy API
### Old → New Method Names
| Legacy Method | New Method | Notes |
|---------------|------------|-------|
| `run_job` | `job.run` | Same functionality, new naming |
| `list_jobs` | `jobs.list` | Same functionality, new naming |
| `create_job` | `jobs.create` | Enhanced to not auto-queue |
### New Methods Added
- `job.start` - Start a created job
- `job.stop` - Stop a running job
- `job.delete` - Delete a job from the system
- `job.status` - Get job status (non-blocking)
- `job.result` - Get job result (blocking)
### API Changes
- **Job struct**: Replaced `job_type` field with `executor`
- **jobs.list**: Now returns full Job objects instead of just job IDs
- **Enhanced job lifecycle**: Added stop and delete operations
This provides much more granular control over job lifecycle management.

View File

@@ -0,0 +1,391 @@
{
"openrpc": "1.3.2",
"info": {
"title": "Hero Supervisor OpenRPC API",
"version": "1.0.0",
"description": "OpenRPC API for managing Hero Supervisor runners and jobs. Job operations follow the convention: 'jobs.' for general operations and 'job.' for specific job operations."
},
"components": {
"schemas": {
"Job": {
"type": "object",
"properties": {
"id": { "type": "string" },
"caller_id": { "type": "string" },
"context_id": { "type": "string" },
"payload": { "type": "string" },
"runner": { "type": "string" },
"executor": { "type": "string" },
"timeout": { "type": "number" },
"env_vars": { "type": "object" },
"created_at": { "type": "string" },
"updated_at": { "type": "string" }
},
"required": ["id", "caller_id", "context_id", "payload", "runner", "executor", "timeout", "env_vars", "created_at", "updated_at"]
}
}
},
"methods": [
{
"name": "list_runners",
"description": "List all registered runners",
"params": [],
"result": {
"name": "runners",
"schema": {
"type": "array",
"items": { "type": "string" }
}
}
},
{
"name": "register_runner",
"description": "Register a new runner to the supervisor with secret authentication",
"params": [
{
"name": "params",
"schema": {
"type": "object",
"properties": {
"secret": { "type": "string" },
"name": { "type": "string" },
"queue": { "type": "string" }
},
"required": ["secret", "name", "queue"]
}
}
],
"result": {
"name": "result",
"schema": { "type": "null" }
}
},
{
"name": "jobs.create",
"description": "Create a new job without queuing it to a runner",
"params": [
{
"name": "params",
"schema": {
"type": "object",
"properties": {
"secret": { "type": "string" },
"job": {
"$ref": "#/components/schemas/Job"
}
},
"required": ["secret", "job"]
}
}
],
"result": {
"name": "job_id",
"schema": { "type": "string" }
}
},
{
"name": "jobs.list",
"description": "List all jobs",
"params": [],
"result": {
"name": "jobs",
"schema": {
"type": "array",
"items": { "$ref": "#/components/schemas/Job" }
}
}
},
{
"name": "job.run",
"description": "Run a job on the appropriate runner and return the result",
"params": [
{
"name": "params",
"schema": {
"type": "object",
"properties": {
"secret": { "type": "string" },
"job": {
"$ref": "#/components/schemas/Job"
}
},
"required": ["secret", "job"]
}
}
],
"result": {
"name": "result",
"schema": {
"oneOf": [
{
"type": "object",
"properties": {
"success": { "type": "string" }
},
"required": ["success"]
},
{
"type": "object",
"properties": {
"error": { "type": "string" }
},
"required": ["error"]
}
]
}
}
},
{
"name": "job.start",
"description": "Start a previously created job by queuing it to its assigned runner",
"params": [
{
"name": "params",
"schema": {
"type": "object",
"properties": {
"secret": { "type": "string" },
"job_id": { "type": "string" }
},
"required": ["secret", "job_id"]
}
}
],
"result": {
"name": "result",
"schema": { "type": "null" }
}
},
{
"name": "job.status",
"description": "Get the current status of a job",
"params": [
{
"name": "job_id",
"schema": { "type": "string" }
}
],
"result": {
"name": "status",
"schema": {
"type": "object",
"properties": {
"job_id": { "type": "string" },
"status": {
"type": "string",
"enum": ["created", "queued", "running", "completed", "failed", "timeout"]
},
"created_at": { "type": "string" },
"started_at": { "type": ["string", "null"] },
"completed_at": { "type": ["string", "null"] }
},
"required": ["job_id", "status", "created_at"]
}
}
},
{
"name": "job.result",
"description": "Get the result of a completed job (blocks until result is available)",
"params": [
{
"name": "job_id",
"schema": { "type": "string" }
}
],
"result": {
"name": "result",
"schema": {
"oneOf": [
{
"type": "object",
"properties": {
"success": { "type": "string" }
},
"required": ["success"]
},
{
"type": "object",
"properties": {
"error": { "type": "string" }
},
"required": ["error"]
}
]
}
}
},
{
"name": "remove_runner",
"description": "Remove a runner from the supervisor",
"params": [
{
"name": "actor_id",
"schema": { "type": "string" }
}
],
"result": {
"name": "result",
"schema": { "type": "null" }
}
},
{
"name": "start_runner",
"description": "Start a specific runner",
"params": [
{
"name": "actor_id",
"schema": { "type": "string" }
}
],
"result": {
"name": "result",
"schema": { "type": "null" }
}
},
{
"name": "stop_runner",
"description": "Stop a specific runner",
"params": [
{
"name": "actor_id",
"schema": { "type": "string" }
},
{
"name": "force",
"schema": { "type": "boolean" }
}
],
"result": {
"name": "result",
"schema": { "type": "null" }
}
},
{
"name": "get_runner_status",
"description": "Get the status of a specific runner",
"params": [
{
"name": "actor_id",
"schema": { "type": "string" }
}
],
"result": {
"name": "status",
"schema": { "type": "object" }
}
},
{
"name": "get_all_runner_status",
"description": "Get status of all runners",
"params": [],
"result": {
"name": "statuses",
"schema": {
"type": "array",
"items": { "type": "object" }
}
}
},
{
"name": "start_all",
"description": "Start all runners",
"params": [],
"result": {
"name": "results",
"schema": {
"type": "array",
"items": {
"type": "array",
"items": { "type": "string" }
}
}
}
},
{
"name": "stop_all",
"description": "Stop all runners",
"params": [
{
"name": "force",
"schema": { "type": "boolean" }
}
],
"result": {
"name": "results",
"schema": {
"type": "array",
"items": {
"type": "array",
"items": { "type": "string" }
}
}
}
},
{
"name": "get_all_status",
"description": "Get status of all runners (alternative format)",
"params": [],
"result": {
"name": "statuses",
"schema": {
"type": "array",
"items": {
"type": "array",
"items": { "type": "string" }
}
}
}
},
{
"name": "job.stop",
"description": "Stop a running job",
"params": [
{
"name": "params",
"schema": {
"type": "object",
"properties": {
"secret": { "type": "string" },
"job_id": { "type": "string" }
},
"required": ["secret", "job_id"]
}
}
],
"result": {
"name": "result",
"schema": { "type": "null" }
}
},
{
"name": "job.delete",
"description": "Delete a job from the system",
"params": [
{
"name": "params",
"schema": {
"type": "object",
"properties": {
"secret": { "type": "string" },
"job_id": { "type": "string" }
},
"required": ["secret", "job_id"]
}
}
],
"result": {
"name": "result",
"schema": { "type": "null" }
}
},
{
"name": "rpc.discover",
"description": "OpenRPC discovery method - returns the OpenRPC document describing this API",
"params": [],
"result": {
"name": "openrpc_document",
"schema": { "type": "object" }
}
}
]
}

View File

@@ -0,0 +1,80 @@
# Test Keypairs for Supervisor Auth
These are secp256k1 keypairs for testing the supervisor authentication system.
## Keypair 1 (Alice - Admin)
```
Private Key: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
Public Key: 0x04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235
Address: 0x1234567890abcdef1234567890abcdef12345678
```
## Keypair 2 (Bob - User)
```
Private Key: 0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321
Public Key: 0x04d0de0aaeaefad02b8bdf8a56451a9852d7f851fee0cc8b4d42f3a0a4c3c2f66c1e5e3e8e3c3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e
Address: 0xfedcba0987654321fedcba0987654321fedcba09
```
## Keypair 3 (Charlie - Register)
```
Private Key: 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Public Key: 0x04e68acfc0253a10620dff706b0a1b1f1f5833ea3beb3bde6250d4e5e1e283bb4e9504be11a68d7a263f8e2000d1f8b8c5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e
Address: 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
```
## Keypair 4 (Dave - Test)
```
Private Key: 0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
Public Key: 0x04f71e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e8f6c7e
Address: 0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
```
## Keypair 5 (Eve - Test)
```
Private Key: 0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
Public Key: 0x04a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0
Address: 0xcccccccccccccccccccccccccccccccccccccccc
```
## Usage Examples
### Using with OpenRPC Client
```rust
use secp256k1::{Secp256k1, SecretKey};
use hex;
// Alice's private key
let alice_privkey = SecretKey::from_slice(
&hex::decode("1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef").unwrap()
).unwrap();
// Sign a message
let secp = Secp256k1::new();
let message = "Hello, Supervisor!";
// ... sign with alice_privkey
```
### Using with Admin UI
You can use the public keys as identifiers when creating API keys:
- Alice: `0x04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd...`
- Bob: `0x04d0de0aaeaefad02b8bdf8a56451a9852d7f851fee0cc8b4d42f3a0a4c3c2f66c...`
### Testing Different Scopes
1. **Admin Scope** - Use Alice's keypair for full admin access
2. **User Scope** - Use Bob's keypair for limited user access
3. **Register Scope** - Use Charlie's keypair for runner registration only
## Notes
⚠️ **WARNING**: These are TEST keypairs only! Never use these in production!
The private keys are intentionally simple patterns for easy testing:
- Alice: All 0x12...ef pattern
- Bob: Reverse pattern 0xfe...21
- Charlie: All 0xaa
- Dave: All 0xbb
- Eve: All 0xcc