Il motore di rilevamento del StyloBot' è ASP.NET CoreM SK2 Questo post spiega come quel motore si connette ai portali Go , NodeM Sk4js applicationsM sk5 e ad ogni altro stack tramite un'autostrana gRPC M Sk6 un Go SDK tipolato M sk7 e un plugin Caddy , senza che nessuno di quegli utenti abbia bisogno di sapere nulla sulle interfacce M k9NET M k10
L'informazione figura nella parte dispositiva.
github.com/scottgal/stylobot-goSDK, lagithub.com/scottgal/caddy-stylobotplugin, e ilMostlylucid.BotDetection.SidecarIl contenitore sarà pubblicato tra poco. Tutto qui descrive la superficie che esponeranno.
StyloBot Release Series
- Comportamento, Non identità: perché StyloBot modella i clienti comportamentalmente
- Comportamento-Aware ASP.NET UI: il server- la superficie restituita per le applicazioni .NET
- Trovare e riparare la crescita senza limiti nei servizi NET Long-Running .: la disciplina di affidabilità che mantiene il motore noioso nella produzione.
- Comportamento-Conoscere l'interfaccia grafica del tipoScript: ExpressM SK1 Fastify, e componenti del browser
- L'architettura della Sidecar: questo articolo
- Imparare a diventare più veloce: il sistema di apprendimento adattativo, quattroM SK2 memoria a livello di livello+, e la cassa del verdetto
- Provare a fare ciò che non si ferma.: la disciplina di verificazioneM SK1 un file BDF guida la regressione , carico, e calibrazione
- StyloExtract - un convertitore locale di HTML per Markdown: l'HTML→Layere Markdown che si combina con il rilevatore , il walkeder bug lucidVIEW catturatoM SK3 e la catena di cibo per cani che lo rende onesto
Un proxy inversa è il posto ovvio per far funzionare la rilevazione dei bot: si siede davanti a tuttoM SK1 vede ogni richiesta, e può bloccare prima che ogni codice dell'applicazione funzioniMSC3 Questa logica si mantiene fino a quando non si chiede cosa dovrebbe fare l'applicazione. fare in modo diverso. basandosi su chi fa la richiesta. Una passerella che blocca completamente è una porta; quello di cui la maggior parte delle applicazioni ha veramente bisogno è un verdetto su cui poter agire in molti modi simultaniM SK2 far girare l'API , personalizzare l'interfaccia utenteMSC4 escludere il traffico dall'analisiMST5 aggiungere un passo di frizione al checkoutM ST6 Una porta non può fare niente di questoM st7 Un tubo di verdetto puòMst8
Il modello della carrozza laterale separa le due preoccupazioni. La passerella rimane veloce e senza stato. La carrozza posteriore mantiene lo stato di sessioneM SK2 gli ancrami archetipi , lo stato d'immozioneMSC4 e il cache del verdetto che rende la rilevazione accurata MST5 l'archetipo MST6 il modello dell'ancrameMst7 il per-MST8 il cache di verdetto delle impronte digitaliM ST9 e i quattro sistemi di apprendimento a quattro livelliM st10 sono ricoperti Imparare a diventare più veloce). Le due comunicano attraverso la rete locale ( lo stesso host o lo stesso Pod) così il percorso rotondatoM SK3 è di microsecondi a un singoloMSC4 millisecondi di cifreMST5 non è il mSSK6ms di una chiamata API remotaMst7 Il budget della latenza è ciò che rende la rilevazione di una richiesta per ogni -pragenza pratica
Questo non è un modello nuovo. Proxy dell'ambasciatore Lo fa esattamente per il servizio-problemi di mesh M SK1mTLS, ripetizioniMSC3 rompere circuitiMNK4 Dapr Lo fa per lo stato e la pub/sub;. OpenTelemetry Collector Lo fa per la telemetria. Linkerd , Consul Connect, e AWS App Mesh tutti segueno lo stesso modelloM SK3 Il modello continua a comparire perché risolve un vero problemaMSC4 volete un comportamento di stato complesso che attraversa i confini linguistici senza riimplementarlo in ogni linguaMST5
L'alternativa è compilare la rilevazione direttamente nel gateway. Per Go significa una pura reimplementazione di -Go o un collegamento CGo a una biblioteca C. Per Node significa l'esecuzione della rilevazione nel processo in parallelo all'applicazioneM SK4
né è realistico per un motore di questa complessità. StyloBot ha 49 rilevatori organizzati in quattro esposizioni. le onde. (Le onde più tardi sparano solo quando i segnali precedenti lo garantisconoM SK1 un credenzale-il tentativo di sopravvivere attiva dei rilevatori diversi da quelli di una ricerca su Googlebot ). Mantiene ogni sessione I vettori della catena di Markov in uno spazio dimensionale. Una catena Markov è solo un modello di probabilità su ", dato l'ultima cosa che questa sessione ha fatto. Detezione della comunità di Leiden su quei vettori: un grafico-l'algoritmo che crea gruppi di sessioni che si comportano allo stesso modoM SK2 questo è il modo in cui StyloBot individua una rete di bot anche quando le sessioni individuali sembrano tranquille . E persiste tutto ciò a SQLite tra le richiesteMSC4 Quello stato ha bisogno di un ciclo di vita indipendenteMNK5 Non può ricominciare con il processo dei nodi o essere strappato quando la passerella ri scarica la propria configurazioneMسک6
Una carrozza laterale permette a ogni componente di fare quello che è buono.
graph TD
classDef input fill:none,stroke:#3b82f6,stroke-width:2px
classDef async fill:none,stroke:#a855f7,stroke-width:2px
classDef good fill:none,stroke:#22c55e,stroke-width:2px
classDef store fill:none,stroke:#f59e0b,stroke-width:2px
GW["Gateway<br/>Caddy / YARP / nginx"]:::input
SD["StyloBot Sidecar · ASP.NET Core<br/>gRPC :5090 · REST :5091<br/>≤50ms per Detect RPC"]:::async
APP["Upstream Application<br/>Node / Go / ASP.NET<br/>reads req.stylobot.verdict"]:::good
DB[("SQLite<br/>sessions · signatures · reputation")]:::store
GW --> SD
SD <--> DB
GW --> APP
Il gateway chiama la sidecar, inietta il risultato come header HTTP, e opzionalmente bloccaM SK2 L'applicazione in arrivo legge i headers e agisce sul verdetto . La sidecar persists state between requestsMSC4 La filiera di rilevamento va all'interno del singolo call gRPC e il suo risultato si propaga come nove headerHTTPMNK5
Mostlylucid.BotDetection.Sidecar è un processo minimo ASP.NET Core . Non ha UIM SK2 nessun servizio di file statici , e nessun routing al di là del gRPC e dei punti finali RESTMNK4 Inizia il motore di rilevamento completo e espone due portiMSC5
/api/v1/* i punti finali.gRPC è un sistema di call procedure remoto ad alta performance sviluppato da Google. Bufferi del protocollo (protobufM SK1 come formato di cavo: un encodamento binario compacto che è più veloce da serializzare e più piccolo sul cavo rispetto a JSON . gRPC funziona su HTTPMSC4 il che significa che ottiene moltiplicazioni SSK5multiple requests over one TCP connectionMNK6 gratisMMK7
L'interfaccia è definita in un .proto file. Da quel file, i generatori di codici, producono battute di cliente e server in qualsiasi lingua supportata. .proto file in modo che qualsiasi lingua con una implementazione gRPC possa chiamare la sidecar: Go, NodeM SK2 Python , RustMSC4 JavaMST5 e molti altriMSV6
Il servizio ha tre RPC:
service DetectionService {
rpc Detect(DetectRequest) returns (DetectResponse);
rpc DetectBatch(DetectBatchRequest) returns (DetectBatchResponse);
rpc RenderWidget(RenderWidgetRequest) returns (RenderWidgetResponse);
}
Detect è il per-il percorso caldo della richiesta. il metodo di passazioneM SK2 il percorsoMNK3 i headerMK4 l'IP remotoMRK5 e i dati opzionali delle impronte digitali TLSMMK6 Funziona la conduttura delle onde MEK7 solo i rilevatori che la richiesta MEK8 i segnali garantisconoMKK9 aggiorna il vettore di sessioneMZK10 fa dei punteggi contro il repertorio di reputazione MGK11 e restituisce un verdettoMDK12
DetectBatch conduce diverse richieste sequenzialmente. Usata per la riproduzione del log e l'analisi offline, non perM SK2uso della passerella per la richiesta .
RenderWidget accetta una sequenza di schemi liquidi, un verdetto opzionale, e una chiave - mappa di valori delle variabili aggiuntiveM SK3 poi riproduce il server di schemettiMSC4 sul lato e restituisce HTMLMST5 Ecco come i caller non--.NET producono botMSP7aware HTML senza creare un processo di rendering separatoMSV8 i dettagli nella sezione RenderWidget sotto
Un breve glossario prima del diagramma, visto che questi nomi appariranno:
request.ip.is_datacenter, detection.useragent.confidence). I rilevatori gli scriveno dei segnali ; i rilevatori più tardi nella stessa onda li leggonoM SK2 Live solo per la durata di una richiesta. Raw PII PSK4IPMSC5 String UAMNK6 rimane nel contesto della richiesta e non atterra mai sulla lavagnaHttpContext il servizio gRPC viene costruito dai campi di richiesta proto. Il motore di rilevamento è stato progettato per ASP.NET middleware e si aspetta di leggere da HttpContext; se ne sintetizza uno, lo stesso motore può funzionare inalterato all'interno di un call gRPC.sequenceDiagram
participant GW as Gateway (Caddy)
participant SD as gRPC Service
participant ORC as BlackboardOrchestrator
participant DET as Detectors (up to 49, 4 waves)
participant DB as SQLite
GW->>SD: Detect RPC { method, path, headers, remoteIp }
SD->>ORC: DetectAsync(syntheticHttpContext)
ORC->>DET: Wave 0 - Identity + ContentSequence
ORC->>DET: Wave 1 - Fast path <1ms: UA, Header, IP, Heuristic ...
ORC->>DET: Wave 2 - Session vectors, Behavioural waveform
ORC->>DET: Wave 3 - Slow path: DNS, advanced fingerprinting
DET-->>ORC: DetectionContributions (signals, confidence deltas)
ORC->>DB: update session vector and reputation score
DB-->>ORC: ok
ORC-->>SD: AggregatedEvidence { botProbability, riskBand, ... }
SD-->>GW: DetectResponse { isBot, riskBand, recommendedAction, ... }
L'intera catena si muove all'interno del singolo call gRPC. Non c'è lavoro asynco dopo il ritorno della risposta.
Il codice di Gateway in Go non può importare l' ASP.NET sidecar. Quello che può fare è chiamarlo via gRPCM SK2 Il Go SDK (github.com/scottgal/stylobot-go) fornisce un'interfaccia tipificata che nasconde completamente i tipi di protobuf generati dai chiamatori.
Protobuf-il codice generato è verboso e ha un API insolito. I enumi sono rappresentati come integeriM SK2 Le stringhe vengono come nomi di enumi proto.RISK_BAND_HIGH, non "High"). I nomi dei campi sono cammelCase in alcuni generatori e serpente_case in altriM SK2 Esibire i tipi di proto nella vostra API pubblica significa che i vostri chiamatori devono capire tutto questo .
Il SDK traduce una volta al confine (enumi proto alle stringhe canoniche,struzioni proto alle semplici Structure GoM SK2 e i chiamatori non la vedono mai
// the only interface you depend on: no proto imports required
type Client interface {
Detect(ctx context.Context, req DetectRequest) (*Verdict, error)
DetectBatch(ctx context.Context, reqs []DetectRequest) ([]*Verdict, error)
RenderWidget(ctx context.Context, req RenderRequest) (*RenderResponse, error)
Close() error
}
DetectRequest e Verdict sono semplici strutture Go:
type DetectRequest struct {
Method string
Path string
Headers map[string]string
RemoteIP string
Protocol string // "http" or "https"; defaults to "https" if empty
TLS *TLSInfo
}
type Verdict struct {
IsBot bool
BotProbability float32
Confidence float32
BotType string // "AiBot", "Scraper", "GoodBot", ...
BotName string
RiskBand string // "VeryLow", "Low", "Elevated", "Medium", "High", "VeryHigh"
RecommendedAction string // "Allow", "Throttle", "Challenge", "Block"
ThreatScore float32
ThreatBand string
ProcessingTimeMs float32
DetectorsRun int32
Reasons []Reason
}
Creare un cliente e attivare la rilevazione:
import (
stylobot "github.com/scottgal/stylobot-go"
"context"
"time"
)
client, err := stylobot.NewClient(
"localhost:5090",
stylobot.WithTimeout(50 * time.Millisecond),
stylobot.WithAPIKey(os.Getenv("SB_API_KEY")),
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
verdict, err := client.Detect(ctx, stylobot.DetectRequest{
Method: r.Method,
Path: r.URL.RequestURI(),
RemoteIP: r.RemoteAddr,
Headers: extractHeaders(r),
Protocol: "https",
})
if err != nil {
// fail open: log and continue
log.Printf("stylobot detect failed: %v", err)
return next(w, r)
}
if verdict.RecommendedAction == "Block" {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
grpc.NewClient crea un canale cliente ma non crea immediatamente una connessione TCP. La connessione avviene durante la prima chiamata RPC. Questo significa che il vostro processo di gateway inizia con successo anche se l'autostrana non è ancora iniziata . La prima richiesta dopo startup può fallire M SK3e dovrebbe essere gestita con fallimentoMSC4openMNK5 ma ogni richiesta successiva funziona normalmente una volta che l' autostrana è in funzioneMST6
Questo è diverso dai clienti HTTP, dove di solito si connette durante la creazione. gRPC Si va alla documentation copre il ciclo di vita in dettaglio.
WithTimeout su NewClient stabilisce un termine di chiamata predefinito per ogni -messa applicata all'interno di ognuno. Detect chiamare. Se il vostro codice di chiamata M SK1o il middleware come il plugin Caddy) deriva già un termine di termineMSC3 un contesto limitato dalla richiesta incomingente , il SDK applichiamo qualunque termine finisca primaMST5 Quando il plugin caddy è in usoMst6 il plugin possiede il termine mst7msM st8 potete omitare WithTimeout a partire da NewClient e lasciate che il plugin lo controlli. Per l'uso stand-alone (un handler che chiama direttamente il SDK NewClient come mostrato prima.
Caddy è un server web basato su Go- e proxy inverso con HTTPS automatico. Il suo sistema di plugin è compilatoM SK2time : che usate xcaddy per costruire un binario Caddy personalizzato che includa i vostri plugin, producendo un singolo auto-contenante il binario senza dipendenza del tempo di runtime dalle biblioteche condiviseM SK2 Questo è diverso da nginx 's dynamic module system MSC4.so file loaded at runtime). Il plugin StyloBot (github.com/scottgal/caddy-stylobot) registra un middleware handler che chiama il Go SDK su ogni richiesta.
La configurazione del Caddyfile:
{
order stylobot before respond
}
:80 {
stylobot {
endpoint localhost:5090 # gRPC host:port of the sidecar
timeout 50ms # per-request deadline; fails open on expiry
# on_block 503 # optional: change the block status code (default: 403)
}
reverse_proxy upstream:3000
}
Il plugin inserisce nove titoli di verdetto su ogni richiesta inviata:
| Insieme | campo di sorgente SSK2 |
|---|---|
X-StyloBot-IsBot |
isBot (boolM SK1 |
X-StyloBot-Probability |
botProbability (0.0-1.0) |
X-StyloBot-Confidence |
confidence (0.0-1.0) |
X-StyloBot-BotType |
eM SK1g. AiBot, Scraper, GoodBot |
X-StyloBot-BotName |
eM SK1g. GPTBot, Googlebot |
X-StyloBot-RiskBand |
VeryLow ... VeryHigh |
X-StyloBot-Action |
Allow / Throttle / Challenge / Block |
X-StyloBot-ThreatScore |
numerico |
X-StyloBot-ThreatBand |
None ... Critical |
Si chiede dove isBot=true e Action=Block Sono fermati alla porta con un 403 e non raggiungono mai l'altopiano . Tutto il resto (incluendo i robot con un Throttle o Challenge Ricommandazione) viene inviato con tutti i nove titoli intatti. Questa è la divisione previstaM SK2 il gateway gestisce i blocchi rigidi ; l'influente gestisce le nuanceMSC4
on_block cambia il codice di stato usato quando il gateway blocca (defaultM SK1 403). Set on_block 503 per sopprimere la logica di ritestazione nei scraper che trattano 403 come ritestabile.
flowchart TD
classDef input fill:none,stroke:#3b82f6,stroke-width:2px
classDef async fill:none,stroke:#a855f7,stroke-width:2px
classDef good fill:none,stroke:#22c55e,stroke-width:2px
A["1. Strip inbound X-StyloBot-* headers"]:::input
B["2. context.WithTimeout(r.Context(), 50ms)"]:::input
C["3. sbClient.Detect(ctx, DetectRequest)"]:::async
D{error?}
E["log warn - fail open<br/>forward unchanged"]:::good
F["4. injectHeaders<br/>X-StyloBot-IsBot, Probability, Confidence,<br/>BotType, BotName, RiskBand, Action,<br/>ThreatScore, ThreatBand"]:::input
I["next.ServeHTTP - forward to upstream<br/>with all verdict headers injected"]:::good
A --> B --> C --> D
D -->|yes| E --> I
D -->|no| F --> I
Step 1, strisciate i titoli entranti. Un cliente che conosce il X-StyloBot-* i nomi del titolo potrebbero auto-injectare un giudizio favorevole e farvi sopravvivere al fallimento-pace apertoM SK2Ne togliere prima significa che il giudizio che vedete in arrivo viene sempre dall'automobile laterale .
passo 2, termine di termine del contesto. L'intervallo di tempo è derivato da r.Context() usando context.WithTimeout (che richiede una durata relativaM SK1 context.WithDeadline prendono un tempo assoluto; sono equivalenti). derivano da r.Context() Invece di context.Background() è il punto chiave: se il cliente si disconnette prima che la chiamata del gRPC sia completata, l'annunciazione si propaga e la macchina laterale smette di processare prestoM SK2
Passi 3 e 4, rilevare e iniettareM SK2 I nove campi di giudizio diventano nove. X-StyloBot-* i titoli. I titoli sono stabiliti prima del blocco di controllo, così che l'alto flusso li legge attraverso styloBotMiddleware({ mode: 'headers' }) per tutte le richieste non bloccate-. Requests where isBot=true e recommendedAction=Block Vengono restituite come 403 all'entrata ; tutto il resto va avanti con i testi del verdetto completo attaccati.
Implementazione:
// from sdk/caddy/stylobot.go
func (s *StyloBot) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
for _, name := range stylobotHeaders {
r.Header.Del(name)
}
ctx, cancel := context.WithTimeout(r.Context(), s.timeout)
defer cancel()
verdict, err := s.sbClient.Detect(ctx, sb.DetectRequest{
Method: r.Method,
Path: r.URL.RequestURI(),
RemoteIP: ExtractIP(r),
Protocol: r.Proto,
Headers: ExtractHeaders(r),
})
if err != nil {
s.logger.Warn("stylobot detect failed, failing open", zap.Error(err))
return next.ServeHTTP(w, r)
}
injectHeaders(r, verdict)
if verdict.IsBot && s.OnBlock > 0 && verdict.RecommendedAction == "Block" {
http.Error(w, "Forbidden", s.OnBlock)
return nil
}
return next.ServeHTTP(w, r)
}
I plugin Caddy devono essere compilati nel binario usando xcaddy. Il Dockerfile nei test di integrazione mostra il modello:
# from tests/integration/caddy-sidecar/Dockerfile
FROM caddy:2-builder AS builder
WORKDIR /build
COPY sdk/caddy/ caddy-plugin/
COPY sdk/go/ go/
WORKDIR /build/caddy-plugin
RUN xcaddy build \
--with github.com/scottgal/caddy-stylobot=/build/caddy-plugin \
--with github.com/scottgal/stylobot-go=/build/go
FROM caddy:2
COPY --from=builder /build/caddy-plugin/caddy /usr/bin/caddy
COPY tests/integration/caddy-sidecar/Caddyfile /etc/caddy/Caddyfile
Il plugin's go.mod contiene:
replace github.com/scottgal/stylobot-go => ../go
Questo dice alla catena di strumenti Go " quando vedete. stylobot-go, usa il directorio locale invece di prelevare dal proxy del module." Funziona per go build e go test nel directorio di plugin.
xcaddy crea un nuovo modulo Go temporaneo per la sua costruzione. Quel modulo non eredita. replace istruzioni dal plugin's go.mod. Senza il secondo --with argument, xcaddy proverebbe a scaricare stylobot-go a partire da pkg.go.dev ( dove non è ancora stato pubblicato) e fallisceM SK2
L'informazione figura nella parte dispositiva. --with module=path l'argomentazione è il equivalente nativo di xcaddy' replace directiva: mappe un percorso di moduli verso un directorio locale al momento della costruzione. Entrambi i moduli locali devono essere chiamati esplicitamenteM SK2
RenderWidget è un gRPC RPC sul sidecar che accetta una sequenza di schemi liquidi, la riproduce con il contesto di rilevamento, e restituisce HTMLM SK2 Questo permette ad ogni chiamatore ( andare in proxyMSC4 Node Layer SSRMST5 Pipeline di lottoMSP6 produrre botMSSK7 essere consapevoli del HTML senza fare un processo di rendering separatoMSL8
Liquido è una lingua di templaggio creata da Shopify, usata dai temi di shopify , Jekyll, Pages of GitHubM SK3 e molti altri sistemi+. Le sue proprietà chiaveMSC5 sicure da usare con l'utenteMST6Template fornete MSSK7 nessun'esecuzione arbitraria del codice+MST8 abbastanza semplice da essere scritta dagli sviluppatori non-MST9+Mst10+Mt11+ StyloBot usa Fluid.Core, una alta -performance .implementazione NET di Liquid, per rendere server templatesMSC4sideM SK5
L'implementazione della carrozza laterale:
// from src/Mostlylucid.BotDetection.Sidecar/Services/DetectionGrpcService.cs
private static readonly FluidParser Parser = new(); // static, shared, compiled templates cached
public override async Task<Proto.RenderWidgetResponse> RenderWidget(
Proto.RenderWidgetRequest request, ServerCallContext context)
{
if (!Parser.TryParse(request.Template, out var template, out var error))
return new Proto.RenderWidgetResponse { Success = false, Error = error };
var ctx = new TemplateContext();
if (request.Verdict is { } v)
{
ctx.SetValue("isBot", v.IsBot);
ctx.SetValue("botProbability", (double)v.BotProbability);
ctx.SetValue("botType", v.BotType);
ctx.SetValue("botName", v.BotName);
ctx.SetValue("riskBand", v.RiskBand.ToString());
ctx.SetValue("recommendedAction", v.RecommendedAction.ToString());
ctx.SetValue("threatScore", (double)v.ThreatScore);
ctx.SetValue("threatBand", v.ThreatBand.ToString());
}
foreach (var kv in request.Vars)
ctx.SetValue(kv.Key, kv.Value);
var html = await template.RenderAsync(ctx);
return new Proto.RenderWidgetResponse { Html = html, Success = true };
}
Fluid.Core mantiene un archivio interno di schemi compilati. Rendimenti ripetuti della stessa sequenza di scheme skip reM SK2parsing FluidParser è statico e condiviso su tutte le chiamate del gRPC.
Il Nodo StyloBotGrpcClient.renderWidget() l'esempio e la completa riferimento alla variabile template sono nella Article di TypeScript SDK.
Lo chiamo da Go:
rendered, err := client.RenderWidget(ctx, stylobot.RenderRequest{
Template: `{% if isBot %}<p class="warning">Bot: {{ botType }}</p>{% endif %}`,
Verdict: verdict,
Vars: map[string]string{"locale": "en-GB"},
})
if err == nil && rendered.Success {
fmt.Fprint(w, rendered.HTML)
}
La sintax del template è identica anche se chiamate. RenderWidget da Go, Node, o usa <sb-widget> nel browser: lo stesso motore liquido, gli stessi nomi di variabiliM SK2 la stessa strada di renderingMSC3
graph LR
classDef input fill:none,stroke:#3b82f6,stroke-width:2px
classDef async fill:none,stroke:#a855f7,stroke-width:2px
classDef good fill:none,stroke:#22c55e,stroke-width:2px
classDef store fill:none,stroke:#f59e0b,stroke-width:2px
INT([Internet])
CF["Cloudflare<br/>Tunnel / CDN"]
CA["Caddy<br/>+ caddy-stylobot"]:::input
SD["StyloBot Sidecar<br/>:5090 gRPC · :5091 REST"]:::async
WEB["Upstream App<br/>Node / Go / ASP.NET"]:::good
DB[("SQLite<br/>sessions · reputation")]:::store
INT --> CF --> CA
CA -->|"gRPC Detect<br/>≤50ms"| SD
SD <-->|"persist"| DB
CA -->|"X-StyloBot-* headers"| WEB
WEB -->|"/_stylobot/partials/render<br/>(widget rendering)"| SD
L'applicazione in arrivo chiama il sidecar direttamente per rendere gli widget, bypassing the gateway. Il rendere degli widget ha bisogno del contesto del verdicto completo e succede dopo che la richiesta ha già passato la detezione delle porteM SK2 quindi non ci sono duplicazioni di rilevamentoMSC3
Caddy plugin, Node middleware, and Go SDK all'error openM SK2 a sidecar timeout or error becomes an warning log and a permissive empty verdictMNK3 not a MRK4xxMMK5 The 50ms Caddy deadline is a coldMSC7start safety marginMST8 the steadyMSSK9state cost on a warm connection is \1–5msMSL11
Il modo in cui il traffico è bloccato, perché la rilevazione non è disponibile, è peggio dell'assenza di traffic bot durante un'interruzione della macchina laterale.
La serie di esibizioni continua. Più post su interni di rilevamento, schemi di deploiamentoM SK2 osservabilità , e la topologia commerciale sono ancora in arrivoMSC4 L'arco finoraMST5
Source per la implementazione: github.comM SK1scottgal/stylobot. Motore viventeM SK1 Armatura dashboard, e controlli commerciali a stylobot.net.
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.