feat: enforce event authorization and readiness

This commit is contained in:
kami
2026-07-26 19:52:49 +04:00
parent 64abbe900e
commit 5d45351613
2 changed files with 37 additions and 5 deletions
+34 -4
View File
@@ -38,6 +38,13 @@ func main() {
rt = &router.Router{Store: s, Registry: rr, Reachability: registry.TCPReachability{}, Timeout: time.Second, Retry: router.RetryPolicy{MaxAttempts: 3, Backoff: time.Minute}}
}
mux := http.NewServeMux()
surface := func(r *http.Request) authz.Surface {
v := authz.ParseSurface(r.Header.Get("X-Orchestra-Surface"))
if v == "" {
return authz.Web
}
return v
}
mux.HandleFunc("/v1/tasks", func(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
json.NewEncoder(w).Encode(s.Tasks())
@@ -104,7 +111,19 @@ func main() {
}
taskID, action := parts[2], parts[3]
if action == "approval" {
if err := authz.AuthorizeEvent(surface(r), map[bool]string{true: "ApprovalRequested", false: "ApprovalGranted"}[len(parts) == 4]); err != nil && len(parts) == 4 {
http.Error(w, err.Error(), http.StatusForbidden)
return
}
if len(parts) == 5 {
typ := "ApprovalGranted"
if parts[4] == "deny" {
typ = "ApprovalDenied"
}
if err := authz.AuthorizeEvent(surface(r), typ); err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
}
if parts[4] != "grant" && parts[4] != "deny" {
http.Error(w, "unknown approval action", 404)
return
@@ -118,10 +137,6 @@ func main() {
if by == "" {
by = "surface"
}
typ := "ApprovalGranted"
if parts[4] == "deny" {
typ = "ApprovalDenied"
}
b, _ := json.Marshal(map[string]any{"subject_ref": taskID, "by": by})
e := domain.Event{ID: id(), Type: typ, TaskID: taskID, Version: t.Version + 1, Payload: b}
if err := s.Append(e); err != nil {
@@ -154,6 +169,13 @@ func main() {
}
var e domain.Event
var err error
actionTypes := map[string]string{"lease": "TaskLeased", "release": "TaskReleased", "complete": "TaskCompleted", "block": "TaskBlocked"}
if typ, known := actionTypes[action]; known {
if err := authz.AuthorizeEvent(surface(r), typ); err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
}
}
switch action {
case "lease":
var p struct {
@@ -230,6 +252,14 @@ func main() {
}()
}
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("ok\n")) })
mux.HandleFunc("/readyz", func(w http.ResponseWriter, r *http.Request) {
checks := map[string]any{"store": true, "router": rt != nil, "gitea": os.Getenv("ORCHESTRA_GITEA_URL") != "", "jsonl": os.Getenv("ORCHESTRA_JSONL") != ""}
ready := rt != nil || (os.Getenv("ORCHESTRA_CONFIG") == "")
if !ready {
w.WriteHeader(http.StatusServiceUnavailable)
}
json.NewEncoder(w).Encode(map[string]any{"ready": ready, "checks": checks})
})
if base := os.Getenv("ORCHESTRA_GITEA_URL"); base != "" {
g := provider.Gitea{BaseURL: base, Token: os.Getenv("ORCHESTRA_GITEA_TOKEN"), WebhookSecret: os.Getenv("ORCHESTRA_GITEA_WEBHOOK_SECRET"), Owner: os.Getenv("ORCHESTRA_GITEA_OWNER"), Repo: os.Getenv("ORCHESTRA_GITEA_REPO")}
mux.Handle("/v1/providers/gitea/webhook", g.WebhookHandler(s))