Initial commit: AetherForge Linux (forge-mesh) v0.1.0-dev
Some checks failed
Test / test (push) Has been cancelled

This commit is contained in:
drjones
2026-07-04 09:31:23 +00:00
commit 3678b199d0
154 changed files with 21714 additions and 0 deletions

View File

@@ -0,0 +1,253 @@
package handlers
import (
"encoding/json"
"io"
"net/http"
"strconv"
"forge-mesh/internal/auth"
"forge-mesh/internal/court"
"forge-mesh/internal/erasure"
"forge-mesh/internal/fleet"
)
// IntelligenceDeps bundles triple-onion fleet intelligence handlers.
type IntelligenceDeps struct {
Store *fleet.Store
Subnet *fleet.SubnetMapper
Earn *fleet.EarnGate
}
// RunLOTL handles POST /api/v1/fleet/{id}/lotl/run — execute tier chain with recon.
func RunLOTL(deps IntelligenceDeps) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
hostID := r.PathValue("id")
if hostID == "" {
http.Error(w, "host id required", http.StatusBadRequest)
return
}
strategy := fleet.AdaptiveStrategy{Store: deps.Store}
order, err := strategy.OrderForHost(r.Context(), hostID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
results, err := fleet.RunTierChain(r.Context(), deps.Store, hostID, order)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
auth.JSON(w, http.StatusOK, map[string]interface{}{
"host_id": hostID,
"order": order,
"results": results,
})
}
}
// ListLOTL handles GET /api/v1/fleet/{id}/lotl.
func ListLOTL(deps IntelligenceDeps) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
hostID := r.PathValue("id")
attempts, err := deps.Store.ListLOTL(r.Context(), hostID, 100)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
auth.JSON(w, http.StatusOK, map[string]interface{}{
"host_id": hostID,
"attempts": attempts,
})
}
}
// SpreadGate handles GET /api/v1/fleet/{id}/spread-gate (earn-before-burn).
func SpreadGate(deps IntelligenceDeps) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
hostID := r.PathValue("id")
dec, err := deps.Earn.CanSpreadToSiblings(r.Context(), hostID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
auth.JSON(w, http.StatusOK, dec)
}
}
// SubnetList handles GET /api/v1/fleet/subnets.
func SubnetList(deps IntelligenceDeps) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cidrs, err := deps.Subnet.ListCIDRs(r.Context())
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
auth.JSON(w, http.StatusOK, map[string]interface{}{"cidrs": cidrs})
}
}
// SubnetAdd handles POST /api/v1/fleet/subnets.
func SubnetAdd(deps IntelligenceDeps) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req struct {
CIDR string `json:"cidr"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.CIDR == "" {
http.Error(w, "cidr required", http.StatusBadRequest)
return
}
c, err := deps.Subnet.AddCIDR(r.Context(), req.CIDR)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
auth.JSON(w, http.StatusCreated, c)
}
}
// SubnetSweep handles POST /api/v1/fleet/subnets/sweep.
func SubnetSweep(deps IntelligenceDeps) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
results, err := deps.Subnet.SweepAll(r.Context())
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
auth.JSON(w, http.StatusOK, map[string]interface{}{"results": results})
}
}
// CourtDeps bundles court handler dependencies.
type CourtDeps struct {
Court *court.Court
Seer *court.SeerHub
}
// CourtOpen handles POST /api/v1/court/sessions.
func CourtOpen(deps CourtDeps) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req struct {
HostID string `json:"host_id"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.HostID == "" {
http.Error(w, "host_id required", http.StatusBadRequest)
return
}
s, err := deps.Court.OpenSession(r.Context(), req.HostID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
auth.JSON(w, http.StatusCreated, s)
}
}
// CourtDeliberate handles POST /api/v1/court/sessions/{id}/deliberate.
func CourtDeliberate(deps CourtDeps) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
s, err := deps.Court.Deliberate(r.Context(), id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
auth.JSON(w, http.StatusOK, s)
}
}
// CourtVerdict handles POST /api/v1/court/sessions/{id}/verdict (L4).
func CourtVerdict(deps CourtDeps) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
var req struct {
Verdict string `json:"verdict"`
Clearance int `json:"clearance"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.Verdict == "" {
http.Error(w, "verdict required", http.StatusBadRequest)
return
}
if req.Clearance == 0 {
req.Clearance = 4
}
if err := deps.Court.DispatchVerdict(r.Context(), id, req.Verdict, req.Clearance); err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
}
auth.JSON(w, http.StatusOK, map[string]string{"ok": "true", "verdict": req.Verdict})
}
}
// Timeline handles GET /api/v1/fleet/{id}/timeline (LOTL + court).
func Timeline(deps CourtDeps) http.HandlerFunc {
return court.TimelineHandler(deps.Court)
}
// ErasureDeps bundles public erasure routes.
type ErasureDeps struct {
Service *erasure.Service
}
// ErasureEncode handles POST /api/v1/public/erasure/encode (dev/admin via basic elsewhere).
func ErasureEncode(deps ErasureDeps) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
if name == "" {
name = "bundle"
}
data, err := io.ReadAll(io.LimitReader(r.Body, 16<<20))
if err != nil {
http.Error(w, "read error", http.StatusBadRequest)
return
}
b, err := deps.Service.Encode(r.Context(), name, data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
auth.JSON(w, http.StatusCreated, b)
}
}
// ErasureShard handles GET /api/v1/public/erasure/{bundle_id}/shard/{index}.
func ErasureShard(deps ErasureDeps) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
bundleID := r.PathValue("bundle_id")
idx, err := strconv.Atoi(r.PathValue("index"))
if err != nil {
http.Error(w, "invalid index", http.StatusBadRequest)
return
}
sh, err := deps.Service.GetShard(r.Context(), bundleID, idx)
if err != nil {
http.Error(w, "not found", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("X-Shard-Index", strconv.Itoa(sh.ShardIndex))
_, _ = w.Write(sh.Data)
}
}
// ErasureBundleMeta handles GET /api/v1/public/erasure/{bundle_id}.
func ErasureBundleMeta(deps ErasureDeps) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
bundleID := r.PathValue("bundle_id")
b, err := deps.Service.GetBundle(r.Context(), bundleID)
if err != nil {
http.Error(w, "not found", http.StatusNotFound)
return
}
indices, _ := deps.Service.ListShards(r.Context(), bundleID)
auth.JSON(w, http.StatusOK, map[string]interface{}{
"bundle": b,
"shards": indices,
"public": true,
"scheme": "RS_4_2",
})
}
}