feat: dependency DAG and YAML-defined compute jobs #92

Merged
forbes merged 13 commits from feat-dag-workers into main 2026-02-14 19:27:19 +00:00
2 changed files with 59 additions and 0 deletions
Showing only changes of commit 0eb891667b - Show all commits

View File

@@ -2,6 +2,8 @@
package api
import (
"crypto/sha256"
"encoding/hex"
"net/http"
"strings"
"time"
@@ -148,6 +150,39 @@ func (s *Server) RequireWritable(next http.Handler) http.Handler {
})
}
// RequireRunnerAuth extracts and validates a runner token from the
// Authorization header. On success, injects RunnerIdentity into context
// and updates the runner's heartbeat.
func (s *Server) RequireRunnerAuth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := extractBearerToken(r)
if token == "" || !strings.HasPrefix(token, "silo_runner_") {
writeError(w, http.StatusUnauthorized, "unauthorized", "Runner token required")
return
}
hash := sha256.Sum256([]byte(token))
tokenHash := hex.EncodeToString(hash[:])
runner, err := s.jobs.GetRunnerByToken(r.Context(), tokenHash)
if err != nil || runner == nil {
writeError(w, http.StatusUnauthorized, "unauthorized", "Invalid runner token")
return
}
// Update heartbeat on every authenticated request
_ = s.jobs.Heartbeat(r.Context(), runner.ID)
identity := &auth.RunnerIdentity{
ID: runner.ID,
Name: runner.Name,
Tags: runner.Tags,
}
ctx := auth.ContextWithRunner(r.Context(), identity)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func extractBearerToken(r *http.Request) string {
h := r.Header.Get("Authorization")
if strings.HasPrefix(h, "Bearer ") {

24
internal/auth/runner.go Normal file
View File

@@ -0,0 +1,24 @@
package auth
import "context"
const runnerContextKey contextKey = iota + 1
// RunnerIdentity represents an authenticated runner in the request context.
type RunnerIdentity struct {
ID string
Name string
Tags []string
}
// RunnerFromContext extracts the authenticated runner from the request context.
// Returns nil if no runner is present.
func RunnerFromContext(ctx context.Context) *RunnerIdentity {
r, _ := ctx.Value(runnerContextKey).(*RunnerIdentity)
return r
}
// ContextWithRunner returns a new context carrying the given runner identity.
func ContextWithRunner(ctx context.Context, r *RunnerIdentity) context.Context {
return context.WithValue(ctx, runnerContextKey, r)
}