Documentation
¶
Overview ¶
Package app holds the dependency-injection builders and config predicates that assemble the RunLore agent. They live here (instead of in cmd/lore behind main()) so the wiring that decides what ships is unit-testable.
Index ¶
- func BuildApprovals(cfg *config.Config, exec action.Executor, aud audit.Auditor, log *slog.Logger) *action.Approvals
- func BuildAuditor(cfg *config.Config) (audit.Auditor, func(), error)
- func BuildAuto(cfg *config.Config, exec action.Executor, aud audit.Auditor, log *slog.Logger) *action.Auto
- func BuildCatalog(ctx context.Context, cfg *config.Config, forgeTok ForgeToken, ...) *catalog.Catalog
- func BuildCurator(cfg *config.Config, token ForgeToken, cat *catalog.Catalog, ...) *curator.Curator
- func BuildFailureDebouncer(cfg *config.Config, gp providers.GitOpsProvider, metrics *telemetry.Metrics, ...) *investigate.Debouncer
- func BuildGitOps(cfg *config.Config, dc dynamic.Interface, log *slog.Logger) providers.GitOpsProvider
- func BuildInvestigator(ctx context.Context, cfg *config.Config, gp providers.GitOpsProvider, ...) (investigate.Investigator, *catalog.Catalog, error)
- func BuildJudgeModel(cfg *config.Config, provider, baseURL, model, apiKeyEnv string) providers.ModelProvider
- func BuildModel(cfg *config.Config, apiKey string) providers.ModelProvider
- func BuildModelAndTools(ctx context.Context, cfg *config.Config, gp providers.GitOpsProvider, ...) (providers.ModelProvider, []investigate.Tool, *investigate.Recall, ...)
- func BuildNotifier(cfg *config.Config, log *slog.Logger) (*notify.Multi, error)
- func BuildReinvestigator(ctx context.Context, cfg *config.Config, gp providers.GitOpsProvider, ...) *investigate.Reinvestigator
- func BuildVerifyModel(cfg *config.Config) providers.ModelProvider
- func CatalogConfigured(cfg *config.Config) bool
- func GitOpsFromKube(cfg *config.Config, log *slog.Logger) providers.GitOpsProvider
- func GitopsEngine(cfg *config.Config) string
- func KubeClientset(log *slog.Logger) *kubernetes.Clientset
- func LogLedgerStartup(log *slog.Logger, s outcome.Status)
- func ModelConfigured(cfg *config.Config) bool
- func ModelProvider(cfg *config.Config) string
- func NewHTTPServer(addr string, h http.Handler) *http.Server
- func NewModelClient(provider, baseURL, model, apiKey string) providers.ModelProvider
- func OutcomeKind(recalled bool) string
- func PodName() string
- func PodNamespace() string
- func ReadyFunc(leader func() bool, cat *catalog.Catalog, configured bool) func() bool
- func RequireWebhookAuth(cfg *config.Config, webhookToken string) error
- func RestConfig() (*rest.Config, error)
- func RunCatalog(args []string) error
- func RunCatalogSync(args []string) error
- func RunCurate(args []string) error
- func RunEval(args []string) error
- func RunEvalLive(cfg *config.Config, scnDir, recordDir, reportDir, prevReport, stamp string, ...) error
- func RunInvestigate(args []string) error
- func RunLeaderElection(ctx context.Context, cfg *config.Config, cs *kubernetes.Clientset, ...)
- func RunMCP(version string, args []string) error
- func RunServe(version string, args []string) error
- func SetMemoryLimitFromCgroup(log *slog.Logger)
- type ForgeToken
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BuildApprovals ¶
func BuildApprovals(cfg *config.Config, exec action.Executor, aud audit.Auditor, log *slog.Logger) *action.Approvals
BuildApprovals enables rung-2 approval-gated execution for action mode "approve" (requires a reachable cluster).
func BuildAuditor ¶
BuildAuditor opens the append-only action audit log when configured, else a no-op. Validate already requires AuditLogPath when actions.mode=auto.
func BuildAuto ¶
func BuildAuto(cfg *config.Config, exec action.Executor, aud audit.Auditor, log *slog.Logger) *action.Auto
BuildAuto enables rung-3 unattended execution for action mode "auto" (requires a reachable cluster). Heavily gated: reversible-only, confidence-floored, rate- limited, kill-switchable, and audited. The rung is EXPERIMENTAL and FROZEN (FEAT-1): unattended execution contradicts the read-only-first posture and is the only path that turns a prompt-injected finding into a cluster mutation, so it gets no further investment and may be removed — prefer "approve", which captures nearly all the value. Recommend dry_run if you evaluate it.
func BuildCatalog ¶
func BuildCatalog(ctx context.Context, cfg *config.Config, forgeTok ForgeToken, metrics *telemetry.Metrics, log *slog.Logger) *catalog.Catalog
BuildCatalog returns the kb_search backing store, or nil when no catalog is configured. With a Git URL it starts a background syncer (running on every replica, so a failover standby is already warm) that re-indexes after each pull; otherwise it loads a static mounted directory once.
func BuildCurator ¶
func BuildCurator(cfg *config.Config, token ForgeToken, cat *catalog.Catalog, metrics *telemetry.Metrics, log *slog.Logger) *curator.Curator
BuildCurator returns a Curator when the GitHub App token + KB repo are configured, else nil.
func BuildFailureDebouncer ¶
func BuildFailureDebouncer(cfg *config.Config, gp providers.GitOpsProvider, metrics *telemetry.Metrics, log *slog.Logger) *investigate.Debouncer
BuildFailureDebouncer wires a Debouncer whose "still failing?" re-check reads the workload's CURRENT Ready condition via GitOpsInspector.ResourceStatus. When the engine offers no inspector, the predicate is nil and the debouncer just waits out the window before enqueuing (still filtering instantly-clearing flaps). A zero window makes Debounce enqueue immediately.
func BuildGitOps ¶
func BuildGitOps(cfg *config.Config, dc dynamic.Interface, log *slog.Logger) providers.GitOpsProvider
BuildGitOps builds the GitOps provider for the configured engine (flux default). The differ clones the GitOps source repo over HTTPS; it authenticates private repos with the shared GitHub App installation token (the App needs contents:read on the source repo). A nil token source (no App configured) means public/local repos only.
func BuildInvestigator ¶
func BuildInvestigator(ctx context.Context, cfg *config.Config, gp providers.GitOpsProvider, approvals *action.Approvals, auto *action.Auto, metrics *telemetry.Metrics, ledger *outcome.Ledger, log *slog.Logger) (investigate.Investigator, *catalog.Catalog, error)
BuildInvestigator returns the LLM ReAct investigator when a model is configured, otherwise the read-only LogInvestigator. It also returns the catalog (nil when no model is configured or no catalog is wired).
func BuildJudgeModel ¶
func BuildJudgeModel(cfg *config.Config, provider, baseURL, model, apiKeyEnv string) providers.ModelProvider
BuildJudgeModel builds the (stronger) grader model from --judge-* flags, falling back to the configured investigation model when unset.
func BuildModel ¶
func BuildModel(cfg *config.Config, apiKey string) providers.ModelProvider
BuildModel builds the ModelProvider for the configured provider.
func BuildModelAndTools ¶
func BuildModelAndTools(ctx context.Context, cfg *config.Config, gp providers.GitOpsProvider, metrics *telemetry.Metrics, log *slog.Logger) (providers.ModelProvider, []investigate.Tool, *investigate.Recall, *catalog.Catalog)
BuildModelAndTools assembles the model, investigation tools, and the instant-recall short-circuit from config + the GitOps provider. Shared by serve and investigate.
func BuildNotifier ¶
BuildNotifier assembles the configured chat notifiers (best-effort fan-out) via the notifier registry. Slack/Matrix (and any registered sink, e.g. the generic webhook) self-register; each Build reads its own config.
func BuildReinvestigator ¶
func BuildReinvestigator(ctx context.Context, cfg *config.Config, gp providers.GitOpsProvider, metrics *telemetry.Metrics, log *slog.Logger) *investigate.Reinvestigator
BuildReinvestigator returns a poller that re-runs KB issues labelled "reinvestigate" and posts the fresh findings back, or nil when the forge isn't configured. RunLore polls the forge (outbound) — it has no inbound webhooks.
func BuildVerifyModel ¶
func BuildVerifyModel(cfg *config.Config) providers.ModelProvider
BuildVerifyModel builds the optional cheaper model for the adversarial verify pass, inheriting any unset field from the main model. Returns nil when no model.verify override is configured (verify then runs on the main model).
func CatalogConfigured ¶
CatalogConfigured reports whether the operator asked for a knowledge catalog (a mounted dir or a git-sync repo). It is independent of whether the load succeeded: ReadyFunc uses it to keep a configured-but-failed catalog (which BuildCatalog returns as nil) from collapsing readiness to pure leadership and serving incident traffic with no knowledge base.
func GitOpsFromKube ¶
GitOpsFromKube builds the GitOps provider from the ambient kubeconfig (best-effort).
func GitopsEngine ¶
GitopsEngine returns the configured GitOps engine, defaulting to flux.
func KubeClientset ¶
func KubeClientset(log *slog.Logger) *kubernetes.Clientset
KubeClientset builds a read-only clientset for pod-log access, or nil when no cluster is reachable (e.g. local runs without a kubeconfig).
func LogLedgerStartup ¶
LogLedgerStartup reports, at the right level, what the outcome ledger looks like to this `lore curate` process — turning the previously-silent no-op into a visible warning. The Queue + Recurrence passes read the ledger, but outcome.New succeeds even when the file is absent, so a misconfigured mount (the ledger lives on a volume the CronJob doesn't see — e.g. persistence not enabled, the path not under catalog.mountPath, or a fresh per-Job emptyDir) would silently produce zero work. We still run the passes; we just make the likely misconfiguration loud.
func ModelConfigured ¶
ModelConfigured reports whether a usable model is configured: a provider with a built-in default endpoint (anthropic, gemini), or any provider with a base_url.
func ModelProvider ¶
ModelProvider returns the configured model provider name (default "openai").
func NewHTTPServer ¶
NewHTTPServer builds the serving http.Server with every inbound bound set. Go's zero defaults leave each of these unlimited, exposing the long-lived server to Slowloris (slow header/body), unbounded idle keep-alives, and oversized headers. Payloads (Alertmanager/Slack) are small and synchronous, so 30s read/write is generous while still cutting off slow attackers; the body itself is capped per handler (1 MiB).
func NewModelClient ¶
func NewModelClient(provider, baseURL, model, apiKey string) providers.ModelProvider
NewModelClient builds a ModelProvider for a wire protocol + endpoint.
func OutcomeKind ¶
OutcomeKind labels an outcome-ledger open as a recall (cache hit) or a fresh finding.
func PodNamespace ¶
func PodNamespace() string
PodNamespace resolves the namespace from the downward API or the service-account mount.
func ReadyFunc ¶
ReadyFunc gates readiness on leadership AND a warm catalog. When a catalog is configured, the leader must NOT advertise ready until its knowledge base is loaded and warm — otherwise it would serve incident traffic blind. This distinguishes the two ways BuildCatalog returns a nil catalog:
- configured but the load failed (configured=true, cat=nil): stay 503. A static catalog has no syncer to recover, so the pod stays not-ready and the misconfiguration surfaces loudly instead of silently serving with no KB.
- not configured at all (configured=false, cat=nil): no catalog gate; readiness is pure leadership.
A configured-but-not-yet-warm catalog (git-sync NewEmpty, cat!=nil && !Ready()) is also held at 503 until its first successful sync.
func RequireWebhookAuth ¶
RequireWebhookAuth fails closed on the serve path when the LLM investigator is wired but the alert webhook is anonymous. The webhook's labels/annotations flow verbatim into the LLM prompt (and bill the model), so an unauthenticated caller must not reach it once a model is configured — regardless of actions.mode. This lives on the serve path, NOT in config.Validate: Validate is shared by every subcommand (e.g. `lore investigate` legitimately needs a model and has no webhook), so the requirement is scoped to where the webhook is actually served. It mirrors the approval-token fail-closed guard.
func RestConfig ¶
RestConfig builds a Kubernetes REST config from in-cluster config, falling back to the local kubeconfig (respecting $KUBECONFIG, then ~/.kube/config).
func RunCatalogSync ¶
RunCatalogSync clones/pulls the catalog Git repo into the mirror and reports the indexed entry count — a one-shot of the background sync that serve runs.
func RunCurate ¶
RunCurate grooms the KB backlog (Phase-2 curation agent). It runs the backlog-dedup pass (collapses duplicate open PRs across history) and the lifecycle sweep (closes stale, unprotected PRs by forge age). When outcome.ledger_path is configured, it also runs the Queue pass (promotes solved→ready-to-merge when the incident resolves) and the Recurrence pass (opens a knowledge-gap issue for repeatedly-unresolved patterns).
func RunEval ¶
RunEval replays recorded incident cases through the investigation loop and reports the RCA-identification rate. Requires a configured model.
func RunEvalLive ¶
func RunEvalLive(cfg *config.Config, scnDir, recordDir, reportDir, prevReport, stamp string, n int, jProvider, jBaseURL, jModel, jKeyEnv string) error
RunEvalLive runs the live-fire campaign and writes a dated report.
func RunInvestigate ¶
RunInvestigate runs a single on-demand investigation and prints the findings.
func RunLeaderElection ¶
func RunLeaderElection(ctx context.Context, cfg *config.Config, cs *kubernetes.Clientset, leader *atomic.Bool, log *slog.Logger, startWork func(context.Context))
RunLeaderElection blocks running Lease-based leader election; the leader runs startWork and reports ready. Lost leadership cancels the work context.
func RunMCP ¶
RunMCP serves RunLore's GitOps what-changed capability over the Model Context Protocol (stdio JSON-RPC), so an MCP client (e.g. HolmesGPT) can call it as a toolset. stdout is the protocol channel; logs go to stderr. Read-only. version is injected at build time and stays in package main; it is passed through to the MCP server's advertised server info.
func RunServe ¶
RunServe runs the in-cluster agent: it loads config, builds the investigation pipeline (kube/GitOps/model/catalog/actions), runs leader election, and serves the webhook + readiness endpoints until SIGTERM, then drains gracefully. version is injected at build time and stays in package main; it is passed through for the build-info gauge.
func SetMemoryLimitFromCgroup ¶
SetMemoryLimitFromCgroup sets GOMEMLIMIT to ~90% of the cgroup v2 memory limit so the Go GC respects the container's memory cap — keeping the heap under a soft ceiling and returning memory to the OS under pressure — instead of letting RSS grow across investigations until the cgroup OOM-kills the process. No-op when GOMEMLIMIT is set explicitly, or there is no cgroup memory limit.
Types ¶
type ForgeToken ¶
ForgeToken mints GitHub App installation tokens.
func BuildForgeTokenSource ¶
func BuildForgeTokenSource(cfg *config.Config, log *slog.Logger) ForgeToken
BuildForgeTokenSource builds the GitHub App installation-token source shared by the curator (issues/PRs) and catalog git-sync (clone auth) — one identity for both forge writes and reads. Returns nil when no App is configured.