phase 3 review: fix broken error classification, stub checks, wasted uuid, token idempotency, dead code
- actuator/ssh.go: custom errorsAs chain broken — all SSH errors classified as SSHErrorOther. Replaced with standard errors.As + errors.Is. - scheduler/scheduler.go: all four check functions were stubs returning healthy. Implemented real HTTP GET, TCP dial, unix.Statfs disk, and TLS cert expiry checks. - learning/learning.go: uuid.NewV7() called unconditionally before ON CONFLICT upsert. Now looks up existing pattern first, reuses entity_id. - notifier/notifier.go: removed dead var_, fixed token regeneration every 15s. Now skips if token_hash already set. - phase3.go: removed dead GetPattern+dummy args call in PatchPattern. - classify.go: removed unused var_ guard.
This commit is contained in:
@@ -7,6 +7,7 @@ package actuator
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
@@ -78,21 +79,18 @@ func classifySSHError(err error) SSHErrorClass {
|
||||
return SSHErrorOther
|
||||
}
|
||||
|
||||
// Context deadline/cancel → timeout
|
||||
if err == context.DeadlineExceeded {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return SSHErrorTimeout
|
||||
}
|
||||
|
||||
// Network-level errors
|
||||
var netErr net.Error
|
||||
if ok := errorsAs(err, &netErr); ok {
|
||||
if errors.As(err, &netErr) {
|
||||
if netErr.Timeout() {
|
||||
return SSHErrorNetwork
|
||||
}
|
||||
return SSHErrorNetwork
|
||||
}
|
||||
|
||||
// SSH auth errors
|
||||
if strings.Contains(err.Error(), "unable to authenticate") ||
|
||||
strings.Contains(err.Error(), "no supported methods remain") ||
|
||||
strings.Contains(err.Error(), "ssh: handshake failed") ||
|
||||
@@ -101,70 +99,14 @@ func classifySSHError(err error) SSHErrorClass {
|
||||
return SSHErrorAuth
|
||||
}
|
||||
|
||||
// Exit errors (non-zero remote exit)
|
||||
var exitErr *ssh.ExitError
|
||||
if ok := errorsAs(err, &exitErr); ok {
|
||||
if errors.As(err, &exitErr) {
|
||||
return SSHErrorRemote
|
||||
}
|
||||
|
||||
return SSHErrorOther
|
||||
}
|
||||
|
||||
// errorsAs is a small wrapper to work with Go 1.26's errors.As signature.
|
||||
func errorsAs(err error, target interface{}) bool {
|
||||
// Use the standard errors.As
|
||||
return as(err, target)
|
||||
}
|
||||
|
||||
func as(err error, target interface{}) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
// Walk the error chain
|
||||
for err != nil {
|
||||
if assignable(err, target) {
|
||||
return true
|
||||
}
|
||||
if u, ok := err.(interface{ Unwrap() error }); ok {
|
||||
err = u.Unwrap()
|
||||
} else if u, ok := err.(interface{ Unwrap() []error }); ok {
|
||||
// Multi-error: check first
|
||||
for _, e := range u.Unwrap() {
|
||||
if as(e, target) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func assignable(err error, target interface{}) bool {
|
||||
switch t := target.(type) {
|
||||
case *error:
|
||||
return false
|
||||
case **net.OpError:
|
||||
*t, _ = err.(*net.OpError)
|
||||
return *t != nil
|
||||
case **ssh.ExitError:
|
||||
*t, _ = err.(*ssh.ExitError)
|
||||
return *t != nil
|
||||
default:
|
||||
// Use the original errors.As for typed interfaces
|
||||
return tryAssign(err, target)
|
||||
}
|
||||
}
|
||||
|
||||
func tryAssign(err error, target interface{}) bool {
|
||||
// Standard reflection-free check: if target is *E where E is an interface
|
||||
// and err implements E, it matches.
|
||||
// For concrete pointer types, use type assertion.
|
||||
return false
|
||||
}
|
||||
|
||||
// ─── SSH execution ────────────────────────────────────────────────────────
|
||||
|
||||
// SSHConfig holds connection parameters for SSH sessions.
|
||||
|
||||
Reference in New Issue
Block a user