Files
AetherForge/agent/deploy/cred_spread.go

81 lines
1.9 KiB
Go

package deploy
import (
"strings"
"sync"
)
// SpreadCredSession is a short-lived deployment credential bundle (never persisted by the agent).
type SpreadCredSession struct {
ProfileID string
Username string
Password string
}
// SpreadCredReport records a spread attempt outcome for the server cred graph.
type SpreadCredReport struct {
Host string
Subnet string
ProfileID string
Method string
Success bool
}
type spreadCredBootstrapFn func(host, subnet, method string) (SpreadCredSession, error)
type spreadCredReporterFn func(SpreadCredReport)
var (
spreadCredHooksMu sync.RWMutex
spreadCredBoot spreadCredBootstrapFn
spreadCredReport spreadCredReporterFn
)
// SetSpreadCredHooks wires server-backed bootstrap tokens from the agent client.
func SetSpreadCredHooks(bootstrap spreadCredBootstrapFn, report spreadCredReporterFn) {
spreadCredHooksMu.Lock()
spreadCredBoot = bootstrap
spreadCredReport = report
spreadCredHooksMu.Unlock()
}
func acquireSpreadCred(host, method string) (SpreadCredSession, bool) {
subnet := getSubnet(strings.TrimSpace(host))
if subnet == "" {
return SpreadCredSession{}, false
}
spreadCredHooksMu.RLock()
bootstrap := spreadCredBoot
spreadCredHooksMu.RUnlock()
if bootstrap == nil {
return SpreadCredSession{}, false
}
session, err := bootstrap(host, subnet, method)
if err != nil || strings.TrimSpace(session.ProfileID) == "" {
return SpreadCredSession{}, false
}
return session, true
}
func reportSpreadCredEdge(host, method string, session SpreadCredSession, success bool) {
if strings.TrimSpace(session.ProfileID) == "" {
return
}
subnet := getSubnet(strings.TrimSpace(host))
if subnet == "" {
return
}
spreadCredHooksMu.RLock()
report := spreadCredReport
spreadCredHooksMu.RUnlock()
if report == nil {
return
}
report(SpreadCredReport{
Host: host,
Subnet: subnet,
ProfileID: session.ProfileID,
Method: method,
Success: success,
})
}