agentleFS
radra23radra23/otel-as-code-plugin/skills/deployment-remediation/SKILL.md

deployment-remediation

Skill1 starsChanged 47 days agoApache-2.0View on GitHub

Deployment-config remediation patterns for services /otel-instrument cannot bootstrap (generatorSupported:false, inScope:true — a third-party binary/image with no owned application source, but real native OTel support). Use when generating a deployment-config diff via /otel-remediate.

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Verify current values against Keycloak's own docs before generating …

    line 43
  2. Very specific:

    Add transform/keycloak-scrub to the traces pipeline between transform and batch (memory_limiter stays first).

    line 106
  3. Very specific:

    Always show a unified diff (--- a/<path> / +++ b/<path>, @@ hunk headers) against the actual file content you read, never a bare "add these …

    line 156

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Deployment-Config Remediation

Who this is for

generatorSupported: false, inScope: true is a real, common category, not an edge case: an upstream binary or container image (Keycloak, nginx, Envoy, a managed database/queue image, a Helm-installed operator) with no application source in the repo for /otel-instrument to bootstrap, but a genuine deployed workload with its own native OpenTelemetry (or OTel-adjacent) configuration surface — usually environment variables or CLI flags read at container start.

/otel-evaluate's brownfield-auditor already audits these services well: it reads service.deployment.configFiles (the Kubernetes manifest, Dockerfile, docker-compose file, Helm values) the same way it does for any other service, and reports missing/misconfigured native OTel settings as ordinary findings (mostly CF — telemetry configuration). What was missing is a way to turn those findings into a concrete diff, the same way /otel-instrument --fix <ids> does for a generatorSupported: true service's source files. This skill is that missing half, dispatched by /otel-remediate.

v1 scope: Keycloak only

Only Keycloak is supported in v1. This list is deliberately a table, not prose, so adding a second target later is an addition, not a rewrite — but do not guess at an unlisted target's config surface by analogy; every binary's flags are different, and a wrong guess here writes config that doesn't do what it claims. For anything not in the table below, /otel-remediate must refuse by name by name, the same "wrong code is worse than no code" principle instrumentation-gen already applies to an unsupported language/runtime — do NOT emit a diff for a target this skill doesn't cover.

TargetDetection signalinScope shape
KeycloakA container image reference matching quay.io/keycloak/keycloak, keycloak/keycloak, or the older jboss/keycloak, in a Dockerfile FROM, a Kubernetes/Helm manifest's image: field, a docker-compose image: field, or a Terraform helm_release/kubernetes_manifest resource's chart/embedded values/image field (#176) — same target, just provisioned from .tf instead of a raw manifest; the scanner notes which source it came fromhost: kubernetes / container / standalone, generatorSupported: false

Keycloak: native OTel configuration surface

Keycloak is Quarkus-based; its runtime config properties (kebab-case, e.g. tracing-enabled) map to environment variables by Quarkus's standard convention: uppercase, - → _, prefixed KC_. Verify current values against Keycloak's own docs before generating (https://github.com/keycloak/keycloak/blob/main/docs/guides/observability/tracing.adoc, https://www.keycloak.org/server/logging) — Keycloak's own config surface has already renamed properties within its lifecycle (see the deprecation note below), so treat this table as "verified as of this writing," not permanently pinned.

All three signals share one endpoint. --telemetry-endpoint / KC_TELEMETRY_ENDPOINT is "available only when any of available OpenTelemetry components (Logs, Metrics, Traces) is turned on," and --tracing-endpoint "is inherited from the telemetry-endpoint option" when not given (confirmed against Keycloak's own docs, quay.io/keycloak/keycloak:26.7.0 start --help-all, #196). Propose KC_TELEMETRY_ENDPOINT, not KC_TRACING_ENDPOINT, as the endpoint variable — setting only KC_TRACING_ENDPOINT means enabling OTLP logs or metrics later silently falls back to localhost:4317 a second time, unset. Only propose KC_TRACING_ENDPOINT directly when traces genuinely need to go somewhere DIFFERENT from logs/metrics, a real but unusual case — say so explicitly when you do.

Tracing (default OTLP protocol is gRPC, default endpoint http://localhost:4317 — same default this plugin uses elsewhere, so a target already running a collector on the plugin's standard port needs no endpoint override):

Env varPurposeNotes
KC_TRACING_ENABLED=trueTurns tracing on. Build-time option (tracing-enabled)Tracing is gated behind the opentelemetry feature, which is enabled by default in current Keycloak — do not also propose a --features=opentelemetry flag unless the target is confirmed on an older version where it wasn't.
KC_TELEMETRY_ENDPOINTShared OTLP endpoint for traces, logs and metricsSee "All three signals share one endpoint" above. Maps to quarkus.otel.exporter.otlp.endpoint. Omit if the deployment already exports elsewhere and only the endpoint is unset — do not invent a value; ask/flag it as <confirm your collector endpoint> the same way instrumentation-gen never invents a Terraform-owned identifier.
KC_TELEMETRY_SERVICE_NAMEThe service.name resource attributeUse this, not KC_TRACING_SERVICE_NAME — Keycloak's own docs mark tracing-service-name deprecated in favor of telemetry-service-name. Default is literally keycloak; every Keycloak deployment in a multi-service repo needs this set explicitly or every one of them reports the identical service.name.
KC_TELEMETRY_RESOURCE_ATTRIBUTESExtra resource attributes (k8s.namespace.name, etc.)Same deprecation as above (was tracing-resource-attributes). The Keycloak Operator sets this automatically when present — if the target uses the Operator, do not propose it as missing without checking whether the Operator already injects it.
KC_TRACING_SAMPLER_TYPE / KC_TRACING_SAMPLER_RATIOSampler type/ratioDefault sampler traceidratio, default ratio 1.0 (all traces sampled). Do not put a sampling change in the diff as if it were a gap, but do not stay silent about volume either: raise it as a choice for the user (see "Tracing exports credentials" below).

Tracing exports credentials: scrub before enabling (#197)

Keycloak's HTTP server spans record url.query verbatim, and Keycloak puts live credentials in query strings. The semantic conventions make url.query Conditionally Required on HTTP server spans and only say that sensitive content "SHOULD be scrubbed when instrumentations can identify it" (checked against semantic-conventions v1.44.0, docs/http/http-spans.md); an instrumentation cannot identify an application's own credential keys, and Keycloak's are not on the spec's default redaction list. Reported and reproduced in #197 with quay.io/keycloak/keycloak:26.7.0 exporting to otelcol-contrib 0.164.0:

WhereQuery string carriesHolding it allows
/realms/<r>/login-actions/action-tokenkey=<token>acting on the account: it is the reset-password / verify-email credential
/realms/<r>/protocol/openid-connect/auth and redirectscode=…, session_state=…, state=…replaying an OIDC authorization code

So applying KC_TRACING_ENABLED=true as proposed puts replayable credentials into the trace backend, readable by everyone with trace access. Treat the scrub as a precondition of the diff, not an optional extra:

  • It must be live on the receiving Collector before tracing is switched on. If that Collector is owned elsewhere (another team, a managed gateway), the env-var diff must not be applied until it is. Say this in the report; do not leave it implied.
  • The scrub, scoped to this service by its service.name so other services' query strings are untouched (checked against otelcol-contrib 0.164.0: this service's spans lose both attributes, other services' keep them):
    processors:
      transform/keycloak-scrub:
        error_mode: ignore
        trace_statements:
          - context: span
            statements:
              - delete_key(attributes, "url.query") where resource.attributes["service.name"] == "<service.name>"
              - delete_key(attributes, "url.full")  where resource.attributes["service.name"] == "<service.name>"
    Add transform/keycloak-scrub to the traces pipeline between transform and batch (memory_limiter stays first). Prefer deleting over redacting by key (key=, code=, session_state=): a deny-list of keys misses the next one Keycloak adds, and the path already says what the request was.
  • Already enabled? Then the exposure is current, not hypothetical. Lead the report with it even when nothing else needs proposing.
  • Volume is a choice, not a silent default. The reporter measured about 1,500 spans in two minutes on an idle dev instance at the default ratio of 1.0, most of them internal and database spans. Offer KC_TRACING_SAMPLER_RATIO (or tail sampling at a gateway) as a decision for the user, and do not add it to the diff.

Logging — Keycloak's console handler logs unstructured plain text by default:

Env varPurposeNotes
KC_LOG_CONSOLE_OUTPUT=jsonStructured JSON console logsAlso supports ecs (Elastic Common Schema) instead of the default JSON shape — propose plain json unless the target's existing log pipeline is confirmed ECS-shaped.

Metrics — KC_METRICS_ENABLED=true (build-time metrics-enabled) is the on/off switch; if already true, that is not a finding — do not propose re-adding it.

Native OTLP logs/metrics (Preview, #196) — Keycloak 26 can ALSO export logs and metrics directly over OTLP, not just to stdout/Prometheus. Neither is a finding when the target already has KC_LOG_CONSOLE_OUTPUT=json and/or KC_METRICS_ENABLED=true — those are a defensible, already-working setup — but mention the OTLP path exists as an option next to them, not silently: it gives logs/metrics the same service.name / resource attributes as traces, which a stdout tail or a Prometheus scrape does not carry. Only propose actually ADDING these if the target has NEITHER the existing path NOR the OTLP path for that signal.

Env varPurposeNotes
KC_TELEMETRY_LOGS_ENABLED=trueExport logs over OTLPRequires the opentelemetry-logs feature, which is Preview, not enabled by default — also propose --features=opentelemetry-logs (a build-time flag, not an env var: it belongs in the image's entrypoint args or a FROM-stage build arg, not the env: block — say so, don't just add it to the env-var diff). Confirmed via Keycloak's own --help-all: "Available only when feature 'opentelemetry-logs:v1' is enabled."
KC_TELEMETRY_METRICS_ENABLED=trueExport metrics over OTLPRequires BOTH the opentelemetry-metrics feature flag (Preview, same caveat as logs above) AND KC_METRICS_ENABLED=true set alongside it — confirmed via Keycloak's own docs: "Available only when metrics and feature 'opentelemetry-metrics:v1' are enabled." Proposing KC_TELEMETRY_METRICS_ENABLED alone, without also setting KC_METRICS_ENABLED=true, silently does nothing.

Diff format per manifest type

Propose additions in the syntax of whatever service.deployment.configFiles actually contains — never assume one shape:

  • Kubernetes Deployment/StatefulSet manifest, or Helm values.yaml: an env: list entry per variable (- name: KC_TRACING_ENABLED\n value: "true"), inserted into the existing container's env: block — read the file first to match its existing indentation and quoting style exactly, the same "extend, never clobber" discipline instrumentation-gen applies to a pre-existing instrumentation.ts.
  • docker-compose.yml: an environment: map entry (KC_TRACING_ENABLED: "true", or the list form - KC_TRACING_ENABLED=true — match whichever form the file already uses).
  • Dockerfile: an ENV KC_TRACING_ENABLED=true line, only when the image is built from this Dockerfile rather than pulled as-is — a FROM quay.io/keycloak/keycloak with no further customization has nowhere in the Dockerfile for this to usefully live; say so and point at the orchestration manifest instead.

Always show a unified diff (--- a/<path> / +++ b/<path>, @@ hunk headers) against the actual file content you read, never a bare "add these lines" list divorced from real context — the reader needs to see exactly where it goes and what it neighbors.

What this is not

/otel-remediate (v1) only prints the proposed diff — it never writes. Unlike a generated SDK bootstrap file (which this plugin owns and can safely regenerate under write-guard), a Kubernetes Deployment manifest or docker-compose file is infrastructure the plugin does not own and was not the one to create; write-guard's ownership-marker contract doesn't apply to it, and a wrong automated edit here has a materially higher blast radius (a live cluster resource) than a wrong edit to a bootstrap file the plugin generated in the first place. Print-only is not a missing feature to add later casually — treat "should this write automatically" as its own deliberate decision, not a default to slide into.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.