1- from fastapi import FastAPI , Depends , HTTPException , Request
2- from fastapi .security import OAuth2PasswordBearer
31import os
2+
43import aiohttp
4+ from fastapi import Depends , FastAPI , HTTPException , Request
5+ from fastapi .security import OAuth2PasswordBearer
6+
57from netengine .core .state import RuntimeState
68from netengine .core .supabase_client import get_supabase
79from netengine .handlers .app_handler import AppHandler
1618KEYCLOAK_ISSUER = "https://auth.platform.internal/realms/platform"
1719oauth2_scheme = OAuth2PasswordBearer (tokenUrl = f"{ KEYCLOAK_ISSUER } /protocol/openid-connect/token" )
1820
21+
1922# ─────────────────────────────────────────────
2023# Auth dependency – switches after Phase 4
2124# ─────────────────────────────────────────────
@@ -34,7 +37,7 @@ async def get_current_user(request: Request, token: str = Depends(oauth2_scheme)
3437 async with session .post (
3538 f"{ KEYCLOAK_ISSUER } /protocol/openid-connect/token/introspect" ,
3639 data = {"token" : token },
37- auth = aiohttp .BasicAuth ("admin-cli" , "" ) # or use client credentials
40+ auth = aiohttp .BasicAuth ("admin-cli" , "" ), # or use client credentials
3841 ) as resp :
3942 if resp .status != 200 :
4043 raise HTTPException (status_code = 401 , detail = "Invalid token" )
@@ -43,87 +46,103 @@ async def get_current_user(request: Request, token: str = Depends(oauth2_scheme)
4346 raise HTTPException (status_code = 401 , detail = "Token expired" )
4447 return data
4548
49+
4650# ─────────────────────────────────────────────
4751# Routes
4852# ─────────────────────────────────────────────
4953@app .get ("/api/v1/health" )
5054async def health ():
5155 return {"status" : "ok" }
5256
57+
5358@app .get ("/api/v1/world" )
5459async def get_world (user = Depends (get_current_user )):
5560 state = RuntimeState .load ()
5661 # Return spec and runtime state (filter sensitive data)
5762 return {"spec" : state .world_spec , "state" : state .__dict__ }
5863
64+
5965@app .get ("/api/v1/services" )
6066async def get_services (user = Depends (get_current_user )):
6167 # Query running containers via Docker
6268 from netengine .handlers .docker_handler import DockerHandler
69+
6370 docker = DockerHandler ()
6471 containers = docker .client .containers .list ()
6572 return {"containers" : [{"name" : c .name , "status" : c .status } for c in containers ]}
6673
74+
6775# Add these routes to netengine/api/app.py
6876
77+
6978@app .get ("/api/v1/registry/domains" )
7079async def list_domains (user = Depends (get_current_user )):
7180 supabase = get_supabase ()
7281 result = await supabase .table ("domain_records" ).select ("*" ).execute ()
7382 return result .data
7483
84+
7585@app .get ("/api/v1/registry/addresses" )
7686async def list_addresses (user = Depends (get_current_user )):
7787 supabase = get_supabase ()
7888 result = await supabase .table ("address_leases" ).select ("*" ).execute ()
7989 return result .data
8090
91+
8192@app .get ("/api/v1/queues" )
8293async def get_queue_state (user = Depends (get_current_user )):
8394 # Query pgmq queue counts
8495 # This requires a custom Supabase function to get queue stats.
8596 # For MVP, we'll return a stub.
8697 return {"queues" : {"dns_updates" : 0 , "oidc_provisioning" : 0 , "and_provisioning" : 0 }}
8798
99+
88100@app .get ("/api/v1/events/{correlation_id}" )
89101async def get_event_chain (correlation_id : str , user = Depends (get_current_user )):
90102 # Query all events with this correlation_id from pgmq history
91103 # This requires a pgmq_archive table; stub for now.
92104 return {"correlation_id" : correlation_id , "events" : []}
93105
106+
94107@app .post ("/api/v1/orgs" )
95108async def admit_org (org : dict , user = Depends (get_current_user )):
96109 from ..handlers .world_registry_handler import WorldRegistryHandler
110+
97111 handler = WorldRegistryHandler ()
98112 await handler .admit_org (
99113 name = org ["name" ],
100114 capabilities = org .get ("capabilities" , []),
101- and_profile = org .get ("and_profile" , "business" )
115+ and_profile = org .get ("and_profile" , "business" ),
102116 )
103117 return {"status" : "admitted" }
104118
105119
106120# ANDs
107121
122+
108123@app .post ("/api/v1/ands/{and_name}/profile" )
109124async def change_and_profile (and_name : str , profile : str , user = Depends (get_current_user )):
110125 from netengine .handlers .and_handler import ANDHandler
111126 from netengine .handlers .docker_handler import DockerHandler
127+
112128 handler = ANDHandler (DockerHandler (), RuntimeState .load ())
113129 await handler .update_and_profile (and_name , profile )
114130 return {"status" : "updated" }
115131
132+
116133@app .delete ("/api/v1/ands/{and_name}" )
117134async def delete_and (and_name : str , user = Depends (get_current_user )):
118135 from netengine .handlers .and_handler import ANDHandler
119136 from netengine .handlers .docker_handler import DockerHandler
137+
120138 handler = ANDHandler (DockerHandler (), RuntimeState .load ())
121139 await handler .deprovision_and (and_name )
122140 return {"status" : "deleted" }
123141
124142
125143# App Deploymen
126144
145+
127146@app .post ("/api/v1/orgs/{org}/apps" )
128147async def deploy_app (org : str , payload : dict , user = Depends (get_current_user )):
129148
@@ -141,8 +160,8 @@ async def deploy_app(org: str, payload: dict, user=Depends(get_current_user)):
141160 oidc = OIDCHandler (
142161 keycloak_url = "https://auth.internal" ,
143162 admin_username = "admin" ,
144- admin_password = RuntimeState .load ().inworld_admin_password
163+ admin_password = RuntimeState .load ().inworld_admin_password ,
145164 )
146165 handler = AppHandler (docker , dns , pki , oidc , RuntimeState .load ())
147166 deployment = await handler .deploy_app (org , app_name , subdomain , config )
148- return deployment
167+ return deployment
0 commit comments