mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
Add apiProvider service kind, credential gateway, and cupfox routing
- TopologyNode.lean: apiProvider service kind with network-only requirement - server.py: OP_CREDENTIALS handler, RDS-backed wiki/fractal fold layers, /credentials HTTP endpoint via SurfaceHandler - cupfox-config.nix: Caddy routes for /api/credentials/ -> EC2 (100.69.1.43) and /git/ -> local Forgejo
This commit is contained in:
parent
d4603644d2
commit
04c2796cd3
3 changed files with 109 additions and 15 deletions
|
|
@ -68,6 +68,7 @@ inductive ServiceKind where
|
|||
| substrateIndex
|
||||
| rgflowFilter
|
||||
| tardyInterpreter
|
||||
| apiProvider
|
||||
deriving Repr, DecidableEq, Inhabited, BEq
|
||||
|
||||
/-- Hardware requirements per service. -/
|
||||
|
|
@ -79,6 +80,7 @@ def serviceRequirements : ServiceKind → List HardwareCapability
|
|||
| .substrateIndex => [.storage, .compute]
|
||||
| .rgflowFilter => [.compute, .network]
|
||||
| .tardyInterpreter => [.compute]
|
||||
| .apiProvider => [.network]
|
||||
|
||||
/-- Thermodynamic cost to run a service (Q16.16 per tick). -/
|
||||
def serviceCost : ServiceKind → Q16_16
|
||||
|
|
@ -89,6 +91,7 @@ def serviceCost : ServiceKind → Q16_16
|
|||
| .substrateIndex => ofNat 2
|
||||
| .rgflowFilter => ofNat 3
|
||||
| .tardyInterpreter => ofNat 1
|
||||
| .apiProvider => ofNat 1
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- §3 Node State Machine
|
||||
|
|
@ -236,5 +239,7 @@ def exampleFoxTopNode : TopologyNode :=
|
|||
#eval canRunService exampleCoreNode ServiceKind.architect
|
||||
#eval canRunService exampleEdgeNode ServiceKind.architect
|
||||
#eval canRunService exampleEdgeNode ServiceKind.warden
|
||||
#eval canRunService exampleEdgeNode ServiceKind.apiProvider
|
||||
#eval serviceCost ServiceKind.apiProvider
|
||||
|
||||
end Semantics.TopologyNode
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ OP_PLAN_ROUTE = 11
|
|||
OP_WIKI = 12
|
||||
OP_FRACTAL_FOLD = 13
|
||||
OP_META_AUTOTYPE = 14
|
||||
OP_CREDENTIALS = 15
|
||||
|
||||
CODEC_NONE = 0
|
||||
CODEC_ZLIB_TEST = 1
|
||||
|
|
@ -139,6 +140,7 @@ def primitive_payload() -> dict[str, Any]:
|
|||
"wiki",
|
||||
"fractal_fold",
|
||||
"meta_autotype",
|
||||
"credentials",
|
||||
]
|
||||
return {
|
||||
"node": PROFILE["node_id"],
|
||||
|
|
@ -267,15 +269,25 @@ def handle_surface_op(op: int, payload: bytes) -> dict[str, Any]:
|
|||
request = json.loads(payload.decode("utf-8")) if payload else {"op": "recent"}
|
||||
if not isinstance(request, dict):
|
||||
raise ValueError("wiki payload must be a JSON object")
|
||||
try:
|
||||
from infra.ene_wiki_layer import ENEWikiLayer
|
||||
except ModuleNotFoundError:
|
||||
import sys
|
||||
use_rds = os.environ.get("RS_USE_RDS", "").lower() in ("1", "true", "yes")
|
||||
if use_rds:
|
||||
try:
|
||||
from infra.ene_rds_wiki_layer import ENERDSWikiLayer
|
||||
except ModuleNotFoundError:
|
||||
import sys
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
from infra.ene_rds_wiki_layer import ENERDSWikiLayer
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
from infra.ene_wiki_layer import ENEWikiLayer
|
||||
wiki = ENERDSWikiLayer()
|
||||
else:
|
||||
try:
|
||||
from infra.ene_wiki_layer import ENEWikiLayer
|
||||
except ModuleNotFoundError:
|
||||
import sys
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
from infra.ene_wiki_layer import ENEWikiLayer
|
||||
|
||||
wiki = ENEWikiLayer(STATE_DIR / "ene-wiki.db")
|
||||
wiki = ENEWikiLayer(STATE_DIR / "ene-wiki.db")
|
||||
return wiki.handle_request(request)
|
||||
except Exception as exc:
|
||||
return {"ok": False, "op": "wiki", "error": str(exc)}
|
||||
|
|
@ -284,15 +296,25 @@ def handle_surface_op(op: int, payload: bytes) -> dict[str, Any]:
|
|||
request = json.loads(payload.decode("utf-8")) if payload else {"op": "manifest"}
|
||||
if not isinstance(request, dict):
|
||||
raise ValueError("fractal_fold payload must be a JSON object")
|
||||
try:
|
||||
from infra.ene_fractal_fold import ENEFractalFold
|
||||
except ModuleNotFoundError:
|
||||
import sys
|
||||
use_rds = os.environ.get("RS_USE_RDS", "").lower() in ("1", "true", "yes")
|
||||
if use_rds:
|
||||
try:
|
||||
from infra.ene_rds_fractal_fold import ENERDSFractalFold
|
||||
except ModuleNotFoundError:
|
||||
import sys
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
from infra.ene_rds_fractal_fold import ENERDSFractalFold
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
from infra.ene_fractal_fold import ENEFractalFold
|
||||
fold = ENERDSFractalFold()
|
||||
else:
|
||||
try:
|
||||
from infra.ene_fractal_fold import ENEFractalFold
|
||||
except ModuleNotFoundError:
|
||||
import sys
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
from infra.ene_fractal_fold import ENEFractalFold
|
||||
|
||||
fold = ENEFractalFold(STATE_DIR / "ene-fractal-fold.db")
|
||||
fold = ENEFractalFold(STATE_DIR / "ene-fractal-fold.db")
|
||||
return fold.handle_request(request)
|
||||
except Exception as exc:
|
||||
return {"ok": False, "op": "fractal_fold", "error": str(exc)}
|
||||
|
|
@ -312,6 +334,50 @@ def handle_surface_op(op: int, payload: bytes) -> dict[str, Any]:
|
|||
return handle_request(request)
|
||||
except Exception as exc:
|
||||
return {"ok": False, "op": "meta_autotype", "error": str(exc)}
|
||||
if op == OP_CREDENTIALS:
|
||||
try:
|
||||
request = json.loads(payload.decode("utf-8")) if payload else {}
|
||||
if not isinstance(request, dict):
|
||||
raise ValueError("credentials payload must be a JSON object")
|
||||
try:
|
||||
from credential_provider import (
|
||||
credential_status,
|
||||
provider_manifest,
|
||||
resolve_credential,
|
||||
)
|
||||
except ModuleNotFoundError:
|
||||
try:
|
||||
from infra.credential_provider import (
|
||||
credential_status,
|
||||
provider_manifest,
|
||||
resolve_credential,
|
||||
)
|
||||
except ModuleNotFoundError:
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
from credential_provider import (
|
||||
credential_status,
|
||||
provider_manifest,
|
||||
resolve_credential,
|
||||
)
|
||||
|
||||
action = request.get("action", "status")
|
||||
if action == "status":
|
||||
return credential_status()
|
||||
if action == "manifest":
|
||||
return provider_manifest()
|
||||
if action == "resolve":
|
||||
provider = request.get("provider", "")
|
||||
if not provider:
|
||||
return {"ok": False, "error": "missing provider name"}
|
||||
cred = resolve_credential(provider)
|
||||
if cred is None:
|
||||
return {"ok": False, "error": f"provider {provider!r} not available"}
|
||||
return {"ok": True, "provider": cred.provider, "value": cred.value}
|
||||
return {"ok": False, "error": f"unknown credentials action {action!r}"}
|
||||
except Exception as exc:
|
||||
return {"ok": False, "op": "credentials", "error": str(exc)}
|
||||
return {"error": "unknown-op", "op": op}
|
||||
|
||||
|
||||
|
|
@ -422,6 +488,20 @@ class SurfaceHandler(BaseHTTPRequestHandler):
|
|||
if self.path == "/ws":
|
||||
self.handle_ws()
|
||||
return
|
||||
if self.path == "/credentials":
|
||||
try:
|
||||
from credential_provider import credential_status
|
||||
except ModuleNotFoundError:
|
||||
try:
|
||||
from infra.credential_provider import credential_status
|
||||
except ModuleNotFoundError:
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
from credential_provider import credential_status
|
||||
|
||||
self.send_json(credential_status())
|
||||
return
|
||||
self.send_json({"error": "not-found"}, HTTPStatus.NOT_FOUND)
|
||||
|
||||
def handle_ws(self) -> None:
|
||||
|
|
|
|||
|
|
@ -52,13 +52,22 @@ in
|
|||
logFormat = "level INFO";
|
||||
package = caddyWithPorkbun;
|
||||
extraConfig = ''
|
||||
researchstack.info, cupfox.researchstack.info, http://100.126.151.57 {
|
||||
researchstack.info, cupfox.researchstack.info, git.researchstack.info, http://100.126.151.57 {
|
||||
tls {
|
||||
dns porkbun {
|
||||
api_key {$PORKBUN_API_KEY}
|
||||
api_secret_key {$PORKBUN_SECRET_KEY}
|
||||
}
|
||||
}
|
||||
|
||||
handle_path /api/credentials/* {
|
||||
reverse_proxy http://100.69.1.43:8444
|
||||
}
|
||||
|
||||
handle_path /git/* {
|
||||
reverse_proxy http://127.0.0.1:3000
|
||||
}
|
||||
|
||||
root * /var/www/researchstack
|
||||
file_server
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue