feat: secure enclave inference, x402 monetization, and ERC-8004 registration#218
feat: secure enclave inference, x402 monetization, and ERC-8004 registration#218
Conversation
When `obol stack up` creates a new cluster, k3d tries to bind host ports 80, 8080, 443, and 8443. If any are already in use, Docker fails with a cryptic error and rolls back the entire cluster. Add a `checkPortsAvailable()` pre-flight check that probes each required port with `net.Listen` before invoking k3d. On conflict, the error message lists the blocked port(s) and shows a `sudo lsof` command to identify the offending process.
Add custom regex manager to detect new ObolNetwork/llms releases and auto-bump the image tag in llm.yaml. Follows the same pattern used for obol-stack-front-end and OpenClaw version tracking.
The default model gpt-oss:120b-cloud does not exist and caused OpenClaw to deploy with a non-functional model configuration. Instead, query the host's Ollama server for actually available models and use those in the overlay. When no models are pulled, deploy with an empty model list and guide users to `obol model setup` or `ollama pull`.
…s' into integration
- Add `obol-stack-dev` skill with full reference docs for LLM smart-routing through llmspy (architecture, CLI wrappers, overlay generation, integration testing, troubleshooting) - Add integration tests (`//go:build integration`) that deploy 3 OpenClaw instances through obol CLI verbs and validate inference through Ollama, Anthropic, and OpenAI via llmspy - Expand README model providers section and add OpenClaw commands
Implements internal/enclave — a CGO bridge to Apple Security.framework providing hardware-backed P-256 key management for macOS Secure Enclave. Key capabilities: - NewKey/LoadKey: generate or retrieve SE-backed P-256 keys persisted in the macOS keychain (kSecAttrTokenIDSecureEnclave); falls back to an ephemeral in-process key when the binary lacks keychain entitlements (e.g. unsigned test binaries) - Sign: ECDSA-SHA256 via SecKeyCreateSignature — private key never leaves the Secure Enclave co-processor - ECDH: raw shared-secret exchange via SecKeyCopyKeyExchangeResult - Encrypt/Decrypt: ECIES using ephemeral ECDH + HKDF-SHA256 + AES-256-GCM Wire format: [1:version][65:ephPubKey][12:nonce][ciphertext+16:GCM-tag] - CheckSIP: verify System Integrity Protection is active via sysctl kern.csr_active_config; treats absent sysctl (macOS 26/Apple Silicon) as SIP fully enabled (hardware-enforced) Platform coverage: - darwin + cgo: full Security.framework implementation - all other platforms: stubs returning ErrNotSupported so the module builds cross-platform without conditional compilation at call sites Tests cover: key generation, load, sign, ECIES round-trip, tamper detection, idempotent NewKey, and SIP check. TestLoadKey / TestNewKeyIdempotent skip gracefully when running as an unsigned binary.
Adds SE-backed request encryption to the inference gateway, closing parity
with ecloud's JWE-encrypted deployment secrets — applied here at the
per-request level rather than deploy-time only.
Changes:
- internal/inference/enclave_middleware.go
New HTTP middleware (enclaveMiddleware) that:
• Decrypts Content-Type: application/x-obol-encrypted request bodies
using the SE private key (ECIES-P256-HKDF-SHA256-AES256GCM)
• Reconstructs the request as plain application/json before proxying
• If X-Obol-Reply-Pubkey header present, encrypts the upstream response
back to the client's ephemeral key (end-to-end confidentiality)
• Exposes handlePubkey() for GET /v1/enclave/pubkey
- internal/inference/gateway.go
• New GatewayConfig.EnclaveTag field (empty = plaintext mode, backward compatible)
• Registers GET /v1/enclave/pubkey when EnclaveTag is set
• Stacks layers: upstream → SE decrypt → x402 payment → client
(operator sees only that a paid request arrived, never its content)
- cmd/obol/inference.go
• --enclave-tag / -e / $OBOL_ENCLAVE_TAG flag on obol inference serve
• New obol inference pubkey <tag> subcommand: prints or JSON-dumps the
SE public key — equivalent to `ecloud compute app info` for identity
- internal/inference/enclave_middleware_test.go
Tests: pubkey JSON shape, encrypted response round-trip, plaintext
passthrough, gateway construction with EnclaveTag.
Implements a persistent inference deployment store and full lifecycle CLI
mirroring ecloud's 'compute app' surface:
ecloud compute app deploy → obol inference create / deploy
ecloud compute app list → obol inference list
ecloud compute app info → obol inference info
ecloud compute app terminate → obol inference delete
ecloud compute app info pubkey → obol inference pubkey
internal/inference/store.go:
- Deployment struct: name, enclave_tag, listen_addr, upstream_url,
wallet_address, price_per_request, chain, facilitator_url, timestamps
- Store: Create (with defaults + force flag), Get, List, Update, Delete
- Persisted at ~/.config/obol/inference/<name>/config.json (mode 0600)
- EnclaveTag auto-derived: "com.obol.inference.<name>" if not set
cmd/obol/inference.go (rewrites inference.go):
obol inference create <name> — register deployment config
obol inference deploy <name> — create-or-update + start gateway
obol inference list — tabular or JSON listing
obol inference info <name> — config + SE pubkey (--json)
obol inference delete <name> — remove config (--purge-key also
removes SE key from keychain)
obol inference pubkey <name> — resolve name → tag → SE pubkey
obol inference serve — low-level inline gateway (no store)
All commands accept --json flag for machine-readable output.
Extract pure-Go ECIES (encrypt + deriveKey) from enclave_darwin.go into enclave/ecies.go so the encryption half is available without CGO or Darwin. Add inference.Client — an http.RoundTripper that: - Fetches and caches the gateway's SE public key from GET /v1/enclave/pubkey - Transparently encrypts request bodies (ECIES) before forwarding - Optionally attaches X-Obol-Reply-Pubkey for end-to-end encrypted responses - Decrypts encrypted responses when EnableEncryptedReplies is active Mirrors ecloud's encryptRSAOAEPAndAES256GCM client pattern but for live per-request encryption rather than deploy-time secret encryption.
P0 — Duplicate flag panic on deploy/serve --help: --force moved to create-only; deploy uses deployFlags() only. --wallet duplicate in serve eliminated (deployFlags() already defines it). P1 — Encrypted reply Content-Length mismatch: After encrypting upstream response, refresh Content-Length to encrypted body size and clear Content-Encoding/ETag before writing headers. P1 — SIP not enforced at runtime: gateway.Start() now calls enclave.CheckSIP() before initialising enclaveMiddleware when EnclaveTag is set; refuses to start if SIP disabled. P2 — applyFlags overwrites existing config with flag defaults: Switch from c.String(...) to c.IsSet(...) guard so only flags the user explicitly set are merged into the stored Deployment. P2 — Shallow middleware test coverage: Replace placeholder tests with five real wrapper-path tests covering pubkey endpoint shape, encrypted-request decrypt, plaintext passthrough, encrypted-reply header refresh (Content-Length/Content-Encoding/ETag), and invalid reply pubkey rejection. Add CLI regression tests (inference_test.go): deploy --help and serve --help no-panic checks, serve wallet-required guard, applyFlags explicit-only mutation invariant.
…c claims Container integration (apple/container v0.9.0): - internal/inference/container.go: ContainerManager wraps `container` CLI to start/stop Ollama in an isolated Linux micro-VM; polls Ollama health endpoint before gateway accepts requests - internal/inference/store.go: add VMMode, VMImage, VMCPUs, VMMemoryMB, VMHostPort fields to Deployment - internal/inference/gateway.go: start ContainerManager on Start() when VMMode=true, override UpstreamURL to container's localhost-mapped port, stop container on Stop(); fix misleading operator-can't-read comment - cmd/obol/inference.go: add --vm, --vm-image, --vm-cpus, --vm-memory, --vm-host-port flags; wire through applyFlags and runGateway Doc fixes: - plans/pitch-diagrams.md: correct Diagram 1 (transit encryption not operator-blind), Diagram 5 (SIP blocks external attackers not operator), Diagram 7 (competitive matrix: Phase 1.5a at [0.85,0.20] not [0.85,0.88])
Two issues fixed:
1. applyFlags used c.IsSet("wallet") which could return false even when
--wallet was explicitly passed; changed to non-empty check for flags
that have no meaningful empty default (wallet, enclave-tag).
2. urfave/cli v2 stops flag parsing at the first positional arg, so
`deploy test-vm --wallet addr` silently ignored the wallet flag.
Fixed by adding a --name/-n flag to deployFlags() as an alternative
to the positional argument. Users can now use either:
obol inference deploy --wallet <addr> [flags] <name>
obol inference deploy --name <name> --wallet <addr> [flags]
Added wallet validation before store.Create to prevent writing bad configs.
Tested end-to-end: VM mode container starts, Ollama becomes ready in ~2s
(cached image), gateway serves /health 200 and /v1/chat/completions 402.
Previously `container run --detach` silently pulled the image inline, causing a 26-minute silent wait on first run with no user feedback. Now runs an explicit `container pull <image>` with stdout/stderr wired to the terminal before starting the container, so users see live download progress. On cache hit the pull completes in milliseconds.
Breaking changes applied across all cmd/obol files:
- cli.App{} → cli.Command{} (top-level app is now a Command)
- All Action signatures: func(*cli.Context) error →
func(context.Context, *cli.Command) error
- All Subcommands: → Commands:
- EnvVars: []string{...} → Sources: cli.EnvVars(...)
(X402_WALLET, OBOL_ENCLAVE_TAG, CLOUDFLARE_*, LLM_API_KEY)
- cli.AppHelpTemplate → cli.RootCommandHelpTemplate
- app.Run(os.Args) → app.Run(context.Background(), os.Args)
- All c.XXX() accessor calls → cmd.XXX() (~70 occurrences)
- cmd.Int() now returns int64; added casts for VMCPUs, VMMemoryMB,
VMHostPort, openclaw dashboard port
- Passthrough command local var renamed cmd → proc to avoid shadowing
the *cli.Command action parameter
- inference_test.go: rewrote deployContext() — cli.NewContext removed
in v3; new impl runs a real *cli.Command and captures parsed state
Removed v2 transitive deps: go-md2man, blackfriday, smetrics.
- Fix CLI framework reference: urfave/cli/v2 → v3 - Update passthrough command example to v3 Action signature (context.Context, *cli.Command) - Fix go.mod dependency listing - Expand inference command tree (create/deploy/list/info/delete/pubkey/serve) - Add Inference Gateway section: architecture, deployment lifecycle, SE integration, VM mode, flag patterns - Add inference/enclave key files to References
…ort) Adds install_container() that downloads and installs the signed pkg from github.com/apple/container releases. macOS-only, non-blocking (failure continues with a warning). Pins CONTAINER_VERSION=0.9.0. Enables 'obol inference deploy --vm' for running Ollama in an isolated Apple Containerization Linux micro-VM.
…litator Extracts buildHandler() from Start() so tests can inject the handler into an httptest.Server without requiring a real network listener. Adds VerifyOnly to GatewayConfig to skip on-chain settlement in staging/test environments. gateway_test.go implements a minimal mock facilitator (httptest.Server with /supported, /verify, /settle endpoints and atomic call counters) and covers: - Health check (no payment required) - Missing X-PAYMENT header → 402 - Valid payment → verify + settle → 200 - VerifyOnly=true → verify only, no settle → 200 - Facilitator rejects payment → 402, no settle - Upstream down → verify passes, proxy fails → 502 - GET /v1/models without payment → 402 - GET /v1/models with payment → 200
Resolves 6 merge conflicts: - CLAUDE.md: keep both inference docs and testing docs sections - cmd/obol/main.go: cli/v3 signature + backend param on stack init - cmd/obol/update.go: migrate from cli/v2 to cli/v3 API - go.mod: take bumped crypto/sys/term versions - internal/openclaw/integration_test.go: take .env loader + improved skip messages - internal/stack/stack.go: take backend-refactored Up() + permission denied fix - internal/stack/stack_test.go: take new backend switching tests
Introduce internal/tee/ package providing a hardware-agnostic TEE key and attestation API that mirrors the macOS Secure Enclave interface. The stub backend enables full integration testing on any platform without requiring TDX/SNP/Nitro hardware. - internal/tee/: key management, ECIES decrypt, attestation reports, user_data binding (SHA256(pubkey||modelHash)), verification helpers - Gateway: TEE vs SE key selection, GET /v1/attestation endpoint - Store: TEEType + ModelHash fields on Deployment - CLI: --tee and --model-hash flags on create/deploy/serve/info/pubkey - Tests: 14 tee unit tests + 4 gateway TEE integration tests
Replace TODO placeholders with real library calls for all three TEE backends, anchoring the code to actual APIs that compile and can be verified on hardware later. Attest backends (behind build tags, not compiled by default): - SNP: github.com/google/go-sev-guest/client — GetQuoteProvider() + GetRawQuote() via /dev/sev-guest or configfs-tsm - TDX: github.com/google/go-tdx-guest/client — GetQuoteProvider() + GetRawQuote() via /dev/tdx-guest or configfs-tsm - Nitro: github.com/hf/nsm — OpenDefaultSession() + Send(Attestation) via /dev/nsm with COSE_Sign1 attestation documents Verify functions (no build tag, compiles everywhere): - VerifySNP: go-sev-guest/verify + validate (VCEK cert chain, ECDSA-P384) - VerifyTDX: go-tdx-guest/verify + validate (DCAP PCK chain, ECDSA-256) - VerifyNitro: hf/nitrite (COSE/CBOR, AWS Nitro Root CA G1) - ExtractUserData: auto-detects SNP (1184 bytes), TDX (v4 + 0x81), Nitro (CBOR tag 0xD2), and stub (JSON) formats Tests: 22 passing (14 existing + 8 new verification surface tests)
…teps 8-9) Add Confidential Containers (CoCo) support to inference templates and integration tests for QEMU dev mode verification on bare-metal k3s. Pod templates: - Conditional runtimeClassName on both Ollama and gateway Deployments - TEE args/env vars passed to gateway container (--tee, --model-hash) - TEE metadata in discovery ConfigMap for frontend visibility - New values: teeRuntime, teeType, teeModelHash with CLI annotations CoCo helper (internal/tee/coco.go): - InstallCoCo/UninstallCoCo via Helm with k3s-specific flags - CheckCoCo returns operator status, runtime classes, KVM availability - ParseCoCoRuntime validates kata-qemu-coco-dev/snp/tdx runtime names Integration tests (go:build integration): - CoCo operator install verification - RuntimeClass existence check - Pod deployment with kata-qemu-coco-dev + kernel isolation proof - Inference gateway attestation from inside CoCo VM
Standalone x402 payment verification service designed for Traefik ForwardAuth. Enables monetising any HTTP route (RPC, inference, etc.) via x402 micropayments without modifying backend services. Components: - internal/x402: config loading, route pattern matching (exact/prefix/glob), ForwardAuth handler reusing mark3labs/x402-go middleware, poll-based config watcher for hot-reload - cmd/x402-verifier: standalone binary with signal handling + graceful shutdown - x402.yaml: K8s resources (Namespace, ConfigMap, Secret, Deployment, Service)
…ent gating - Add internal/erc8004 package: Go client for ERC-8004 Identity Registry on Base Sepolia using bind.NewBoundContract (register, setAgentURI, setMetadata, getMetadata, tokenURI, wallet functions) - ABI verified against canonical erc-8004-contracts R&D sources with all 3 register() overloads, agent wallet functions, and events (Registered, URIUpdated, MetadataSet) - Types match ERC-8004 spec: AgentRegistration with image, supportedTrust; ServiceDef with version; OnChainReg with numeric agentId - Add x402 CLI commands: obol x402 register/setup/status - Add well-known endpoint on x402 verifier (/.well-known/agent-registration.json) - Add conditional x402 Middleware CRD + ExtensionRef in infrastructure helmfile - Add x402Enabled flag to inference network template (values + helmfile + gateway) - Add go-ethereum v1.17.0 dependency
Add comprehensive unit tests for the x402 payment verification and ERC-8004 on-chain registration subsystems: - x402 config loading, chain resolution, and facilitator URL validation - x402 verifier ForwardAuth handler and route matching - x402 config file watcher polling logic - ERC-8004 ABI encoding/decoding roundtrips - ERC-8004 client type serialization and agent registration structs - x402 test plan document covering all verification scenarios
Address 4 vulnerabilities found during security review: HIGH — YAML/JSON injection in setup.go: Replace fmt.Sprintf string interpolation with json.Marshal/yaml.Marshal for all user-supplied values (wallet, chain, route configs). MEDIUM — ForwardAuth fail-open: Change empty X-Forwarded-Uri from 200 (allow) to 403 (deny). Missing header signals misconfiguration or tampering; fail-closed is the safer default. MEDIUM — Private key in process args: Add --private-key-file flag and deprecate --private-key. Key is no longer visible in ps output or shell history when using file or env var. MEDIUM — No wallet address validation: Add ValidateWallet() using go-ethereum/common.IsHexAddress with explicit 0x prefix check. Applied at all entry points (CLI, setup, verifier).
Add full in-pod ERC-8004 registration to the monetize skill, enabling agents to register themselves on the Identity Registry (Base Sepolia) using their auto-provisioned remote-signer wallet. Phase 1a: Add Base Sepolia to eRPC with two public RPC upstreams (sepolia.base.org, publicnode.com) and network alias routing. Phase 1b-1c: Implement register(string) calldata encoding in pure Python stdlib (hardcoded selector, manual ABI encoding), with full sign→broadcast→receipt→parse flow via remote-signer + eRPC. Phase 1d: Update CLI to read ERC-8004 registration from CRD status (single source of truth) instead of disk-based store. Remove RegistrationRecord disk writes from `monetize register` command.
Adds a new `obol rpc` CLI command group for managing eRPC upstreams: - `rpc list` — reads eRPC ConfigMap and displays configured networks with their upstream endpoints - `rpc add <chain>` — fetches free public RPCs from ChainList API (chainlist.org/rpcs.json), filters for HTTPS-only and low-tracking endpoints, sorts by quality, and adds top N to eRPC ConfigMap - `rpc remove <chain>` — removes ChainList-sourced RPCs for a chain - `rpc status` — shows eRPC pod health and upstream counts per chain Supports both chain names (base, arbitrum, optimism) and numeric chain IDs (8453, 42161). ChainList fetcher is injectable for testing. New files: - cmd/obol/rpc.go — CLI wiring - cmd/obol/rpc_test.go — command structure tests - internal/network/chainlist.go — ChainList API client and filtering - internal/network/chainlist_test.go — unit tests with fixture data - internal/network/rpc.go — eRPC ConfigMap read/patch operations
Add a new `discovery` skill that enables OpenClaw agents to discover other AI agents registered on the ERC-8004 Identity Registry. This completes the buy-side of the agent marketplace — agents can now search for, inspect, and evaluate other agents' services on-chain. Skill contents: - SKILL.md: usage docs, supported chains, environment variables - scripts/discovery.py: pure Python stdlib CLI with four commands: - search: list recently registered agents via Registered events - agent: get agent details (tokenURI, owner, wallet) - uri: fetch and display the agent's registration JSON - count: total registered agents (totalSupply or event count) - references/erc8004-registry.md: contract addresses, function selectors, event signatures, agentURI JSON schema Supports 20+ chains via CREATE2 addresses (mainnet + testnet sets). All queries are read-only, routed through the in-cluster eRPC gateway.
…on publishing Closes the gaps found during E2E testing of the full monetize flow (fresh cluster → ServiceOffer → 402 → paid inference → lifecycle). Changes: - Add --facilitator-url flag to `obol monetize pricing` (+ X402_FACILITATOR_URL env) so self-hosted facilitators are first-class, not a kubectl-patch afterthought - Add --endpoint flag to `obol rpc add` with AddCustomRPC() for injecting local Anvil forks or custom RPCs into eRPC without ChainList - Expand monetize RBAC: agent can now create/delete ConfigMaps, Services, Deployments (needed for agent-managed registration httpd) - Agent reconciler publishes ERC-8004 registration JSON: creates ConfigMap + busybox httpd Deployment + Service + HTTPRoute at /.well-known/ path, all with ownerReferences for automatic GC on ServiceOffer deletion - `monetize delete` now removes pricing routes and deactivates registration (sets active=false in ConfigMap) before deleting the CR - Extract removePricingRoute() helper (DRY: used by both stop and delete) - Add --register-image flag for ERC-8004 required `image` field - Add docs/guides/monetize-inference.md walkthrough guide
CLAUDE.md had drifted significantly (1385 lines) with stale content and missing documentation for the monetize/x402/ERC-8004 subsystem. Changes: - 1385 → 505 lines (64% reduction) - Fixed stale paths: internal/embed/defaults/ → internal/embed/infrastructure/ - Fixed stale function signature: Setup() now takes facilitatorURL param - Added full Monetize Subsystem section (data flow, CLI, CRD, ForwardAuth, agent reconciler, ERC-8004 registration, RBAC) - Added RPC Gateway Management section (obol rpc add/list/remove/status) - Updated CLI command tree to match actual main.go (monetize, rpc, service, agent) - Updated Embedded Infrastructure section with all 7 templates - Updated skill count: 21 → 23 (added monetize, discovery) - Trimmed verbose sections: obolup.sh internals, network install parser details, full directory trees, redundant examples - Kept testnet/facilitator operational details in guides/skills (not CLAUDE.md)
|
This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation. |
…ctl extraction (#235) * fix: harden monetize subsystem — RBAC split, URL validation, kubectl extraction Address 11 review findings from plan-exit-review: 1. **RBAC refactor**: Split monolithic `openclaw-monetize` ClusterRole into `openclaw-monetize-read` (cluster-wide read-only) and `openclaw-monetize-workload` (cluster-wide mutate). Add scoped `openclaw-x402-pricing` Role in x402 namespace for pricing ConfigMap. Update `patchMonetizeBinding()` to patch all 3 bindings. 2. **Extract internal/kubectl**: Eliminate ~250 lines of duplicated kubectl path construction and cluster-presence checks across 8 consumer files into a single `internal/kubectl` package. 3. **Fix ValidateFacilitatorURL bypass**: Replace `strings.HasPrefix` with `url.Parse()` + exact hostname matching to prevent http://localhost-hacker.com bypass. 4. **Pre-compute per-route chains**: Resolve all chain configs at Verifier load time instead of per-request, catching invalid chains early and eliminating hot-path allocations. 5. **x402-verifier HA**: Bump replicas to 2, add PodDisruptionBudget (minAvailable: 1) to prevent fail-open during rolling updates. 6. **Agent init errors fatal**: Make patchMonetizeBinding and injectHeartbeatFile failures return errors instead of warnings. 7. **Input validation in monetize.py**: Add strict regex validation for route patterns, prices, addresses, and network names to prevent YAML injection. 8. **Health check retries**: Add 3-attempt retry with 2s backoff to `stage_upstream_healthy` for transient pod startup failures. 9. **Test coverage**: Add 16-case ValidateFacilitatorURL test (including bypass regression), kubectl package tests, RBAC document structure tests, and load-time chain rejection test. * fix: use kubectl.Output in x402 e2e test after kubectl extraction The hardening commit extracted duplicated kubectl helpers into internal/kubectl but missed updating the x402 e2e integration test, causing a build failure. Use kubectl.Output instead of the removed local kubectlOutput function.
cmd/obol/main.go
Outdated
| RPC Gateway: | ||
| rpc list List configured chains and their upstreams | ||
| rpc add Add public RPCs for a chain from ChainList | ||
| rpc remove Remove public RPCs for a chain | ||
| rpc status Show eRPC health and upstream counts | ||
|
|
There was a problem hiding this comment.
I wonder could we fold this into the obol network behaviour? e.g. we have like a type --remote and you give it the public rpc (supporting auth /headers etc maybe), and it gets injected into erpc? so people have to differentiate less with obol network | obol rpc
(don't need you to action; will probably just take over and make opinionated updates on my end and then we merge both to main and confirm things are stable)
cmd/obol/main.go
Outdated
| Service Management: | ||
| service create Register a new service deployment | ||
| service deploy Create (or update) and start the service gateway | ||
| service serve Start the service gateway directly (no stored config) | ||
| service list List all service deployments | ||
| service info Show deployment details and encryption public key | ||
| service delete Remove a service deployment | ||
| service pubkey Print the encryption public key | ||
|
|
||
| Monetize: | ||
| monetize offer Create a ServiceOffer CR | ||
| monetize list List all ServiceOffer CRs | ||
| monetize status Show conditions for a ServiceOffer | ||
| monetize delete Delete a ServiceOffer CR | ||
| monetize pricing Configure x402 pricing in the cluster | ||
| monetize register Register service on ERC-8004 Identity Registry (Base Sepolia) |
There was a problem hiding this comment.
Yeah i don't find these very understandable, will have a think in a PR
…-patch Synced llmspy fork with upstream v3.0.38. All Obol-specific fixes (SSE tool_call passthrough, per-provider tool_call config, process_chat tools preservation) are now in the published image. This removes the runtime stream_options monkey-patch from the init container and the PYTHONPATH override that were needed for the old image. Also adds tool_call: false to the Ollama provider config so llmspy passes tool calls through to the client (OpenClaw) instead of attempting server-side execution.
…add payment flow tests
Key changes:
- x402 Setup() now reads existing pricing config and preserves routes
added by the ServiceOffer reconciler (was overwriting with empty array)
- EIP-712 signer uses correct USDC domain name ("USDC" not "USD Coin")
for Base Sepolia TransferWithAuthorization signatures
- Add full payment flow integration tests (402 → EIP-712 sign → 200)
- Add test utilities: Anvil fork helpers, real facilitator launcher,
EIP-712 payment header signer
- Remove standalone inference-gateway (replaced by obol service serve)
- Tunnel agent discovery, openclaw monetize integration tests
…esh install verification getting-started.md: Full rewrite covering the complete journey from install to monetized inference. Verified every command against a fresh cluster (vast-flounder). Adds agent deployment, LLM inference testing with tool calls, and links to monetize guide. monetize-inference.md: Multiple fixes from end-to-end verification: - Fix node count (1 not 4), pod counts (2 x402 replicas) - Fix model pulling (host Ollama, not in-cluster kubectl exec) - Add concrete 402 response JSON example - Fix EIP-712 domain name info (USDC not USD Coin) - Fix payment header name (X-PAYMENT not PAYMENT-SIGNATURE) - Fix facilitator config JSON format - Add USDC settlement verification section (cast balance checks) - Add Cloudflare tunnel payment verification section - Update troubleshooting for signature errors and pricing route issues
Use %q instead of %v to escape control characters in the decrypt error, preventing log injection via crafted ciphertext (CodeQL go/log-injection #2658).
Merge origin/oisin/clicleanup into feat/secure-enclave-inference. Resolves 14 conflict files by keeping cli/v3 signatures and adapting *ui.UI parameter threading. Keeps internal/kubectl package for RBAC patching, development mode image building, and OLLAMA_HOST comments.
Update all CLI command references from the old names to the new: - obol monetize offer → obol sell http - obol monetize offer-status → obol sell status - obol monetize list/stop/delete/pricing/register → obol sell ... - obol service → obol sell inference
The strategicMergePatches block added a second port named "http" (port 80) which conflicted with the chart's existing "http" port (4000), causing `spec.ports[1].name: Duplicate value: "http"` on stack up. Remove the patches and update HTTPRoute backendRef to use port 4000 directly.
Summary
Full sell-side monetization stack: from local inference to paid API endpoints with on-chain agent identity.
Validation Checklist
ABI & Function Selectors
register(string)selector is0xf2c298be— run:cast sig "register(string)"(Foundry)setAgentURI(uint256,string)selector is0x0af28bd3— run:cast sig "setAgentURI(uint256,string)"Registered(uint256,string,address)event topic is0xca52e62c367d81bb2e328eb795f7c7ba24afb478408a26c0e201d155c449bc4a— run:cast sig-event "Registered(uint256,string,address)"internal/erc8004/identity_registry.abi.json) matches the deployed contract ABI on Base Sepolia_abi_encode_string()inmonetize.pyproduces correct ABI encoding (offset=0x20, length, padded data) — cross-check withcast abi-encode "register(string)" "https://example.com/agent.json"Contract Addresses
0x8004A818BFB912233c491871b3d84c89A494BD9e— check contract is deployed and verifiedregister()calls (check recent txs on explorer)erc-8004-contracts/andlucid-agentschain configs84532is correct for Base Sepolia (not Base mainnet8453)eRPC Base Sepolia Configuration
https://sepolia.base.orgis live and responds toeth_blockNumberhttps://base-sepolia-rpc.publicnode.comis live and responds toeth_blockNumbererpc.gochain ID map includes"base-sepolia": 84532signer.pyCHAIN_IDS includes"base-sepolia": 84532base-sepoliain supported networksRemote-Signer Integration (monetize.py)
_get_signing_address()correctly parses/api/v1/keysresponse_register_on_chain()signs via/api/v1/sign/{address}/transactionendpointchain_id,to,nonce,gas_limit,max_fee_per_gas,max_priority_fee_per_gas,value,data* 1.3) for contract calls_parse_registered_event()correctly extractsagentIdfrom indexed topic[1]CRD Status (Single Source of Truth)
monetize registerCLI no longer writes to disk store (store.Save()removed)monetize statusreads from CRDcustom-columns(notstore.Load())monetize deletereadsstatus.agentIdfrom CRD via kubectl jsonpathstage_registered()patches CRD status fields:agentId,registrationTxHashTest Plan
go build ./...compiles cleanpython3 -m py_compile monetize.pypassesgo test ./internal/erc8004/...— 15 tests (ABI, types, client)go test ./internal/embed/...— CRD parsing, RBAC, skill syntaxgo test ./cmd/obol/ -run TestMonetize— 9 CLI structure testsgo test ./internal/x402/...— verifier, matcher, config, watchergo test ./internal/inference/...— gateway, store, enclave middlewarego test ./internal/schemas/...— payment, serviceoffer schemasgo test ./...— full unit test suite passesIntegration Tests (requires cluster + agent)
TestIntegration_CRD_*— CRD lifecycle (create, get, list, status, delete)TestIntegration_RBAC_*— ClusterRole + binding verificationTestIntegration_Monetize_*— Process, heartbeat, idempotencyTestIntegration_Route_*— Anvil upstream routing through TraefikTestIntegration_PaymentGate_*— 402 without payment, 200 with mock paymentTestIntegration_E2E_*— Full CLI-driven lifecycleFuture Work (NOT in this PR)
obol rpccommand — Auto-populate eRPC with quality-sorted free RPCs from ChainListagent-registration.jsonat the agentURIsetAgentURIwithactive=falseonmonetize deletestore.go— Disk-basedRegistrationRecordis no longer written from CLI; full removal is follow-upeth_sendRawTransactionblocking for Base Sepolia local upstreams in eRPC (currently only mainnet has this)Key Files
internal/erc8004/{abi,client,types,store}.go+ testsinternal/embed/skills/monetize/scripts/monetize.pycmd/obol/monetize.go+monetize_test.gointernal/embed/infrastructure/base/templates/serviceoffer-crd.yamlinternal/x402/verifier.go+cmd/x402-verifier/main.gointernal/enclave/enclave_darwin.go+ stubinternal/inference/gateway.go+ store + containerinternal/embed/infrastructure/values/erpc.yaml.gotmplinternal/testutil/{anvil,facilitator,verifier}.gointernal/openclaw/monetize_integration_test.go(1900 lines)