HTML report¶
kubeagent scan --output html writes one self-contained HTML document to
stdout: the artifact you attach to an incident ticket, paste into a pull
request, or mail to a colleague who has no cluster access.
--output accepts text, json, or html. Anything else is rejected before
kubeagent touches the network:
What the document contains¶
- A header — kubeagent version, the namespace scope (or "all namespaces"), the generation timestamp, and the finding counts by severity.
- Blind spots — whatever kubeagent could not read, whenever there is any.
- Findings — every finding, highest severity first, with a severity filter.
- Detail — cluster health, the workload inventory, and the
--explainnarrative when you ran with--explain, each in a collapsed section so the findings stay at the top.
The opt-in advisory sections (--capacity, --drift, --operators,
--certs, and the rest) are not in the document yet. Their findings are —
--output html renders the same finding set the text report ranks — but their
detailed views only appear in --output text and --output json.
--investigate is in the same position. Its findings reach the document, but
its narrative — and the list of sources it consulted — do not; those still need
--output text or --output json.
What the document deliberately does not contain¶
No cluster identity. No context name, no API server URL, no kubeconfig
path. A context name is not safe by default — in the wild they carry
arn:aws:eks:eu-west-1:<account>:cluster/prod or
admin@prod-db.internal.corp — and this file is meant to be forwarded.
Whoever shares it names the cluster in the ticket. This is the same rule
kubeagent gate follows for its verdict, so both shareable
artifacts behave identically.
That guarantee reaches into the blind-spots block. An error the cluster produced is not
safe to quote: a denial names the user, and on a real cluster that is an IAM ARN, a
node's internal DNS name, or an email address — and under webhook authorization the
message carries a policy backend's own words as well. So the document never quotes it.
It names the resource kubeagent could not read and classifies the failure in kubeagent's
words — permission denied, resource type not served, or read failed. --output text and
--output json still carry the exact message.
Finding reasons are the exception, and they are the cluster's own words.
A finding quotes what the cluster said, because that quote is the diagnosis.
An ErrImagePull reason names the registry and the URL the kubelet could not
reach, and a DNS failure nested inside it names the resolver it asked,
address and all — dial tcp: lookup registry.example on <cluster-dns-ip>:53:
no such host. That text describes the workload's own network, not how you
reach the cluster, and stripping it would leave a report that says a pull
failed without saying why. Blind-spot reasons can be classified because
nothing diagnostic is lost; finding reasons cannot. So read the findings
before forwarding a report from a sensitive cluster: they carry whatever the
cluster put in them.
No JavaScript. The severity filter is pure CSS. There is no external stylesheet, font, or image either, so the file opens offline and renders under a strict Content-Security-Policy — which is what artifact previews, sandboxed mail clients, and corporate proxies enforce.
Blind spots are not optional¶
If kubeagent could not list a resource — RBAC denied it, a CRD is absent, the API timed out — the document says so in its own block, above the findings:
kubeagent could not read the following, so the findings below are incomplete.
A shared report that silently omits what it could not see is the same green-when-blind failure CI gate mode exists to prevent, and a rendered document is easier to over-trust than an exit code.
Escaping¶
Container termination messages, event reasons, and image-pull errors are
free-form strings the cluster controls, and they land verbatim in this
document. kubeagent renders it with Go's html/template, whose contextual
auto-escaping neutralizes them. A pod whose crash message contains markup
produces a report that displays that message as text.
Notes¶
scan's exit code is unchanged: still0on an unhealthy cluster. Gating on health iskubeagent gate.gatehas no--output html. Its job is a verdict, not a document; its machine-readable surface is JSON and SARIF.- Two runs against an unchanged cluster differ only in the header timestamp, so reports from the same incident diff cleanly.
--output html --fixinterleaves the remediation transcript after the document, exactly as--output json --fixdoes. Redirect the document to a file first, or run--fixseparately.