Go Library Guide¶
The pkg/engine package provides the ORES engine as an embeddable Go library. Use it when you want to evaluate risk signals in-process — no subprocess, no network call, no IPC overhead.
Installation¶
Go version
Requires Go 1.25 or later.
Quick Start¶
package main
import (
"context"
"fmt"
"log"
"github.com/rigsecurity/ores/pkg/engine"
"github.com/rigsecurity/ores/pkg/score"
)
func main() {
eng := engine.New()
req := &score.EvaluationRequest{
APIVersion: "ores.dev/v1",
Kind: "EvaluationRequest",
Signals: map[string]any{
"cvss": map[string]any{
"base_score": 9.8,
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
},
"epss": map[string]any{
"probability": 0.91,
"percentile": 0.98,
},
"threat_intel": map[string]any{
"actively_exploited": true,
"ransomware_associated": false,
},
"asset": map[string]any{
"criticality": "high",
"network_exposure": true,
"data_classification": "pii",
},
},
}
result, err := eng.Evaluate(context.Background(), req)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Score: %d (%s)\n", result.Score, result.Label)
fmt.Printf("Confidence: %.2f\n", result.Explanation.Confidence)
for _, f := range result.Explanation.Factors {
fmt.Printf(" %-25s +%d\n", f.Name, f.Contribution)
}
}
API Reference¶
engine.New¶
Creates a new Engine with all built-in signal parsers registered. This is the standard constructor. Creating an Engine is inexpensive and the returned instance is safe for concurrent use.
(*Engine).Evaluate¶
func (e *Engine) Evaluate(ctx context.Context, req *score.EvaluationRequest) (*score.EvaluationResult, error)
Runs the full evaluation pipeline:
- Validates the request envelope (
apiVersion,kind, at least one signal) - Looks up each signal name in the registry
- Validates and normalizes each recognized signal
- Computes the weighted composite score
- Calculates confidence
- Builds the explanation with contributing factors
Returns an error if the request envelope is invalid, or if no valid signals were found after parsing.
Partial failures produce warnings, not errors
Invalid individual signals (bad field values, out-of-range numbers) produce warnings rather than errors. The evaluation continues with the remaining valid signals. Always check result.Explanation.Warnings.
(*Engine).Signals¶
Returns descriptors for all registered signal types, sorted alphabetically by name. Useful for dynamic documentation, validation UIs, or schema generation.
(*Engine).Version¶
Returns the model version string (e.g., "0.2.0").
Type Reference¶
score.EvaluationRequest¶
type EvaluationRequest struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Signals map[string]any `json:"signals"`
}
APIVersion- Must be
"ores.dev/v1". Kind- Must be
"EvaluationRequest". Signals- A map of signal type names to their payloads. Each value is a
map[string]anywith signal-specific fields. See Signals for the full catalog.
score.EvaluationResult¶
type EvaluationResult struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Score int `json:"score"`
Label Label `json:"label"`
Version string `json:"version"`
Explanation Explanation `json:"explanation"`
}
Score- Composite risk score from 0 (no risk) to 100 (critical risk).
Label- Human-readable risk category:
none,low,medium,high, orcritical. Version- The model version that produced this result.
Explanation- Detailed breakdown of how the score was computed.
score.Explanation¶
type Explanation struct {
SignalsProvided int `json:"signals_provided"`
SignalsUsed int `json:"signals_used"`
SignalsUnknown int `json:"signals_unknown"`
UnknownSignals []string `json:"unknown_signals"`
Warnings []string `json:"warnings"`
Confidence float64 `json:"confidence"`
Factors []Factor `json:"factors"`
}
SignalsProvided- Total number of signals in the request.
SignalsUsed- Number of signals that were valid and contributed to the score.
Confidence- A value between 0.0 and 1.0 reflecting signal coverage. See Confidence.
Factors- Ordered list of scoring factors, from highest contribution to lowest.
score.Factor¶
type Factor struct {
Name string `json:"factor"`
Contribution int `json:"contribution"`
DerivedFrom []string `json:"derived_from"`
Reasoning string `json:"reasoning"`
}
Contribution- Points this factor added to the composite score.
DerivedFrom- The signal types that fed into this factor. When a signal was not provided,
"defaults"appears here. Reasoning- Human-readable explanation of the factor's impact.
Embedding in an HTTP Handler¶
A complete example of wrapping the ORES engine in a custom HTTP service:
package main
import (
"context"
"encoding/json"
"log/slog"
"net/http"
"os"
"github.com/rigsecurity/ores/pkg/engine"
"github.com/rigsecurity/ores/pkg/score"
)
type ScoringServer struct {
engine *engine.Engine
logger *slog.Logger
}
func NewScoringServer() *ScoringServer {
return &ScoringServer{
engine: engine.New(),
logger: slog.New(slog.NewJSONHandler(os.Stdout, nil)),
}
}
func (s *ScoringServer) HandleScore(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
var req score.EvaluationRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "invalid JSON: "+err.Error(), http.StatusBadRequest)
return
}
result, err := s.engine.Evaluate(context.Background(), &req)
if err != nil {
s.logger.Error("evaluation failed", "err", err)
http.Error(w, "evaluation failed: "+err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
if err := enc.Encode(result); err != nil {
s.logger.Error("failed to write response", "err", err)
}
}
func main() {
srv := NewScoringServer()
mux := http.NewServeMux()
mux.HandleFunc("/score", srv.HandleScore)
slog.Info("starting scoring server", "addr", ":8080")
if err := http.ListenAndServe(":8080", mux); err != nil {
slog.Error("server failed", "err", err)
os.Exit(1)
}
}
Test it:
curl -X POST http://localhost:8080/score \
-H "Content-Type: application/json" \
-d '{
"apiVersion": "ores.dev/v1",
"kind": "EvaluationRequest",
"signals": {
"cvss": { "base_score": 9.8 },
"epss": { "probability": 0.91 },
"threat_intel": { "actively_exploited": true }
}
}'
Use the daemon for production
This example shows how to embed the engine in your own service. If you just need a standalone scoring API, use oresd instead — it includes health checks, audit logging, graceful shutdown, and ConnectRPC/gRPC support out of the box.
Concurrency & Thread Safety¶
The Engine is fully goroutine-safe
You can share a single engine.New() instance across all goroutines. The engine holds no mutable state after construction; every Evaluate call creates its own isolated working state.
// Create once at startup
eng := engine.New()
// Use from many goroutines concurrently
for i := 0; i < 100; i++ {
go func() {
result, err := eng.Evaluate(ctx, req)
// ...
}()
}
There is no need for mutexes, sync pools, or per-goroutine engine instances. A single Engine handles unlimited concurrent evaluations.
Error Handling¶
Evaluate returns a non-nil error in exactly two cases:
- Invalid request envelope — missing
apiVersion, wrongkind, or no signals provided - No valid signals — all provided signals were either unknown or had invalid field values
When some signals are invalid but others succeed, the engine uses the valid ones and records warnings. Always check both the error return and the warnings slice:
result, err := eng.Evaluate(ctx, req)
if err != nil {
// Fatal: request could not be scored at all
return fmt.Errorf("scoring failed: %w", err)
}
// Non-fatal: some signals were skipped
if len(result.Explanation.Warnings) > 0 {
for _, w := range result.Explanation.Warnings {
slog.Warn("signal skipped", "detail", w)
}
}
// Non-fatal: unrecognized signal names
if len(result.Explanation.UnknownSignals) > 0 {
slog.Warn("unknown signals in request",
"signals", result.Explanation.UnknownSignals)
}
Do not ignore warnings in production
A successful evaluation with warnings means the score was computed from fewer signals than intended. This can result in lower confidence and less accurate risk assessment. Log warnings and alert on persistent patterns.