fix: authenticate cognitive readiness probe #138

Merged
m merged 1 commits from codex/authorized-cpu-health-probe into main 2026-08-22 17:47:26 +00:00
5 changed files with 60 additions and 8 deletions
+8 -6
View File
@@ -86,18 +86,20 @@ func main() {
mux.Handle("/healthz", health.Handler{Runtime: "cognitive-worker", SemanticGeneration: 1, ArchitectureGeneration: 1})
readinessClient := &http.Client{Timeout: 2 * time.Second}
lifeboatURL := strings.TrimSuffix(strings.TrimRight(envOr("LOCAL_LIFEBOAT_PROVIDER_URL", "http://cognitive-lifeboat:8086/v1"), "/"), "/v1") + "/health"
mux.Handle("/readyz", health.ReadinessHandler{Runtime: "cognitive-worker", Probes: []health.Probe{
health.HTTPProbe(readinessClient, strings.TrimRight(envOr("CORE_RUNTIME_URL", "http://core-runtime:8080"), "/")+"/healthz"),
health.OptionalHTTPProbe(readinessClient, strings.TrimRight(envOr("LOCAL_CPU_PROVIDER_URL", "http://docker.cin.su:18082/v1"), "/")+"/models"),
health.HTTPProbe(readinessClient, lifeboatURL),
health.OptionalHTTPProbe(readinessClient, strings.TrimRight(envOr("LOCAL_GPU_PROVIDER_URL", "http://192.168.220.91:11434"), "/")+"/api/tags"),
}})
fleetClient := &http.Client{Timeout: 2 * time.Second}
preferredFleet := capability.FleetTier(envOr("COGNITIVE_PREFERRED_FLEET_TIER", string(capability.FleetTierHeavy)))
cpuFleetHeaders := map[string]string{}
if cpuAPIKey != "" {
cpuFleetHeaders["Authorization"] = "Bearer " + cpuAPIKey
}
cpuHealthProbe := health.OptionalHTTPProbeWithHeaders(readinessClient, strings.TrimRight(envOr("LOCAL_CPU_PROVIDER_URL", "http://docker.cin.su:18082/v1"), "/")+"/models", cpuFleetHeaders)
readinessProbes := []health.Probe{
health.HTTPProbe(readinessClient, strings.TrimRight(envOr("CORE_RUNTIME_URL", "http://core-runtime:8080"), "/")+"/healthz"),
cpuHealthProbe,
health.HTTPProbe(readinessClient, lifeboatURL),
health.OptionalHTTPProbe(readinessClient, strings.TrimRight(envOr("LOCAL_GPU_PROVIDER_URL", "http://192.168.220.91:11434"), "/")+"/api/tags"),
}
mux.Handle("/readyz", health.ReadinessHandler{Runtime: "cognitive-worker", Probes: readinessProbes})
mux.Handle("/v1/fleet/readiness", fleetReadinessHandler(fleetClient, preferredFleet, []fleetEndpoint{
{ProviderID: "local-cpu-primary", ModelID: "local-cpu-model", Tier: capability.FleetTierFast, URL: strings.TrimRight(envOr("LOCAL_CPU_PROVIDER_URL", "http://docker.cin.su:18082/v1"), "/") + "/models", Headers: cpuFleetHeaders},
{ProviderID: "local-medium-unconfigured", ModelID: "medium-unconfigured", Tier: capability.FleetTierMedium},
+2 -2
View File
@@ -1,5 +1,5 @@
{
"task_file": "dev/tasks/DEV-000164-authorized-fleet-readiness.json",
"task_id": "DEV-000164",
"task_file": "dev/tasks/DEV-000165-authorized-cpu-health-probe.json",
"task_id": "DEV-000165",
"task_revision": 1
}
@@ -0,0 +1,23 @@
{
"task_id": "DEV-000165",
"task_revision": 1,
"architecture_revision": "ADR-0018",
"base_repo_revision": "5d5afc88883c7f79e3b051c790642e41386666ec",
"risk_tier": "E",
"intent": "Use the existing file-backed CPU provider API key in cognitive-worker readiness probes so /readyz and fleet readiness report consistent provider state.",
"requirement_ids": ["WP-601", "Model fleet/failover"],
"allowed_change_scope": {"modules": ["cognitive-worker", "platform-health"], "paths": ["runtime/health/server.go", "runtime/health/server_test.go", "cmd/cognitive-worker/main.go", "dev/ACTIVE_TASK.json", "dev/tasks/DEV-000165-authorized-cpu-health-probe.json"]},
"forbidden_change_scope": {"paths": ["architecture/**", "security/**", "database/**", "deploy/**", "contracts/**", "adapters/**", ".gitea/**"]},
"allowed_architecture_delta": {"new_cross_module_dependencies": 0, "new_canonical_owners": 0, "new_privileges": 0, "new_third_party_dependencies": 0, "new_database_owner_roles": 0},
"contracts": {"consume": ["existing health Probe contract", "existing provider API key resolver"], "may_change": ["health probe header support"]},
"semantic_owner": "cognitive-worker/platform health",
"canonical_state": [],
"state_transitions": ["authenticated CPU probe -> consistent readiness evidence"],
"side_effects_and_privileges": ["resolved key is used only in outbound probe header; never logged or persisted"],
"persistence_and_migrations": ["none"],
"failure_retry_restart": ["provider timeout or rejected key remains degraded; no fallback behavior changed"],
"assumptions": ["the local provider uses Bearer authentication"],
"acceptance_scenarios": ["health probe sends configured header", "cognitive /readyz uses authenticated CPU probe", "GPU remains optional", "no key is sent when absent"],
"required_tests": ["go test ./...", "go vet ./...", "preflight", "check-diff", "check-architecture", "independent", "git diff --check", "CI", "production /readyz and fleet readiness"],
"terminal_gap_states": ["BLOCKED_BY_MISSING_CAPABILITY", "BLOCKED_BY_CONFLICT"]
}
+13
View File
@@ -82,11 +82,18 @@ func (h ReadinessHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
func HTTPProbe(client *http.Client, endpoint string) Probe {
return HTTPProbeWithHeaders(client, endpoint, nil)
}
func HTTPProbeWithHeaders(client *http.Client, endpoint string, headers map[string]string) Probe {
return Probe{Name: endpoint, Check: func(ctx context.Context) error {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
if err != nil {
return err
}
for name, value := range headers {
req.Header.Set(name, value)
}
response, err := client.Do(req)
if err != nil {
return err
@@ -108,6 +115,12 @@ func OptionalHTTPProbe(client *http.Client, endpoint string) Probe {
return probe
}
func OptionalHTTPProbeWithHeaders(client *http.Client, endpoint string, headers map[string]string) Probe {
probe := HTTPProbeWithHeaders(client, endpoint, headers)
probe.Optional = true
return probe
}
func TCPProbe(name, host, port string) Probe {
return Probe{Name: name, Check: func(ctx context.Context) error {
connection, err := (&net.Dialer{}).DialContext(ctx, "tcp", net.JoinHostPort(host, port))
+14
View File
@@ -27,6 +27,20 @@ func TestReadinessReturns200WhenAllProbesPass(t *testing.T) {
}
}
func TestHTTPProbeWithHeadersSendsHeaders(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Authorization") != "Bearer health-key" {
t.Fatalf("authorization=%q", r.Header.Get("Authorization"))
}
w.WriteHeader(http.StatusOK)
}))
defer server.Close()
probe := HTTPProbeWithHeaders(server.Client(), server.URL, map[string]string{"Authorization": "Bearer health-key"})
if err := probe.Check(context.Background()); err != nil {
t.Fatal(err)
}
}
func TestReadinessStaysAvailableWithOptionalDependencyDegraded(t *testing.T) {
handler := ReadinessHandler{Runtime: "test", Probes: []Probe{
{Name: "lifeboat", Check: func(context.Context) error { return nil }},