mirror of
https://github.com/helmfile/helmfile.git
synced 2026-10-04 09:51:45 +02:00
* feat: add `helmfile doctor` command for AI-assisted diff analysis `helmfile doctor` runs `helmfile diff` and asks an OpenAI-compatible LLM to summarize the changes and flag risks (data loss, security exposure, breaking changes, downtime, performance, best-practice issues). Key design decisions: - When no LLM is configured, doctor is equivalent to `helmfile diff` with one exception: --show-secrets is always forced off (secrets never reach stdout, even without an LLM). - Secrets are ALWAYS redacted via two layers: (1) ShowSecrets() forced to false so helm-diff emits <REDACTED> placeholders; (2) a defense-in-depth text redactor strips residual secret-looking content (Secret YAML blocks, sensitive key/value lines, base64 blobs, JWT tokens) before LLM transmission. - LLM configuration precedence: env (HELMFILE_LLM_*) < helmfile.yaml (llm:) < CLI flags (--llm-*). - Supports any OpenAI-compatible backend (OpenAI, Azure, One-API, LiteLLM, Ollama, etc.) with automatic response_format fallback for backends that don't support JSON mode. - Prompt injection defense: release names and environment values are JSON-encoded before insertion into the LLM prompt. - Exit codes: 0 (success/low-risk), 2 (high-risk gate, bypass with --force), 1 (other errors). Helm-diff's 'detected changes' exit-2 is swallowed. New packages: - pkg/agent/llm: OpenAI-compatible client with JSON response parsing, mock client for testing, prompt builder with injection defense. - pkg/agent/doctor: secret redactor (state machine + regex), report renderer (markdown + JSON), config resolver (env < yaml < flag merge). Testing: 70+ unit tests covering redaction patterns, prompt injection, response_format fallback, JSON parsing, yaml roundtrip, concurrency safety, panic recovery, and error propagation. go test -race passes. Documentation: full doctor section in docs/cli.md, llm: block reference in docs/configuration.md, updated skills/helmfile for AI agents. Signed-off-by: yxxhero <aiopsclub@163.com> * docs: fix doctor equivalence wording per PR review Per review feedback (PR #2660): the docs claimed doctor is 'equivalent to helmfile diff — same flags, same output, same exit codes' in the unconfigured path, but this over-promises because: 1. doctor --output is the report format (not helm-diff's output format) 2. helm-diff's --output is exposed as --diff-output in doctor 3. --show-secrets is silently ignored Updated all three locations (cli.md, cmd/doctor.go Long + godoc, pkg/app/doctor.go godoc) to say 'falls back to helmfile diff with --show-secrets forced off' and explicitly note the --output / --diff-output flag difference. Signed-off-by: yxxhero <aiopsclub@163.com> --------- Signed-off-by: yxxhero <aiopsclub@163.com>
386 lines
6.6 KiB
Go
386 lines
6.6 KiB
Go
package app
|
|
|
|
import (
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/helmfile/helmfile/pkg/agent/llm"
|
|
)
|
|
|
|
type ConfigProvider interface {
|
|
Args() string
|
|
HelmBinary() string
|
|
KustomizeBinary() string
|
|
EnableLiveOutput() bool
|
|
StripArgsValuesOnExitError() bool
|
|
DisableForceUpdate() bool
|
|
EnforcePluginVerification() bool
|
|
HelmOCIPlainHTTP() bool
|
|
SkipDeps() bool
|
|
SkipRefresh() bool
|
|
SequentialHelmfiles() bool
|
|
|
|
FileOrDir() string
|
|
KubeContext() string
|
|
Namespace() string
|
|
Chart() string
|
|
Selectors() []string
|
|
StateValuesSet() map[string]any
|
|
StateValuesFiles() []string
|
|
Kubeconfig() string
|
|
Env() string
|
|
|
|
loggingConfig
|
|
}
|
|
|
|
type DepsConfigProvider interface {
|
|
Args() string
|
|
SkipRepos() bool
|
|
IncludeTransitiveNeeds() bool
|
|
|
|
concurrencyConfig
|
|
}
|
|
|
|
type ReposConfigProvider interface {
|
|
Args() string
|
|
IncludeTransitiveNeeds() bool
|
|
}
|
|
|
|
type ApplyConfigProvider interface {
|
|
Args() string
|
|
PostRenderer() string
|
|
PostRendererArgs() []string
|
|
SkipSchemaValidation() bool
|
|
Cascade() string
|
|
HideNotes() bool
|
|
TakeOwnership() bool
|
|
ServerSide() string
|
|
SuppressOutputLineRegex() []string
|
|
|
|
Values() []string
|
|
Set() []string
|
|
SkipCRDs() bool
|
|
SkipDeps() bool
|
|
SkipRefresh() bool
|
|
Wait() bool
|
|
WaitRetries() int
|
|
WaitForJobs() bool
|
|
Timeout() int
|
|
|
|
IncludeTests() bool
|
|
|
|
Suppress() []string
|
|
SuppressSecrets() bool
|
|
ShowSecrets() bool
|
|
NoHooks() bool
|
|
SuppressDiff() bool
|
|
|
|
DetailedExitcode() bool
|
|
StripTrailingCR() bool
|
|
|
|
Color() bool
|
|
NoColor() bool
|
|
Context() int
|
|
DiffOutput() string
|
|
|
|
Validate() bool
|
|
SkipCleanup() bool
|
|
SkipDiffOnInstall() bool
|
|
|
|
DiffArgs() string
|
|
SyncArgs() string
|
|
|
|
SyncReleaseLabels() bool
|
|
|
|
DAGConfig
|
|
|
|
TrackMode() string
|
|
TrackTimeout() int
|
|
TrackLogs() bool
|
|
TrackFailedLogs() bool
|
|
HelmStuckGrace() int
|
|
TrackFailOnError() bool
|
|
|
|
Description() string
|
|
|
|
concurrencyConfig
|
|
interactive
|
|
loggingConfig
|
|
valuesControlMode
|
|
}
|
|
|
|
type SyncConfigProvider interface {
|
|
Args() string
|
|
PostRenderer() string
|
|
SkipSchemaValidation() bool
|
|
PostRendererArgs() []string
|
|
HideNotes() bool
|
|
TakeOwnership() bool
|
|
ServerSide() string
|
|
Cascade() string
|
|
|
|
Values() []string
|
|
Set() []string
|
|
SkipCRDs() bool
|
|
SkipDeps() bool
|
|
SkipRefresh() bool
|
|
Wait() bool
|
|
WaitRetries() int
|
|
WaitForJobs() bool
|
|
Timeout() int
|
|
SyncArgs() string
|
|
|
|
Validate() bool
|
|
|
|
SkipNeeds() bool
|
|
IncludeNeeds() bool
|
|
IncludeTransitiveNeeds() bool
|
|
|
|
SyncReleaseLabels() bool
|
|
TrackMode() string
|
|
TrackTimeout() int
|
|
TrackLogs() bool
|
|
TrackFailedLogs() bool
|
|
HelmStuckGrace() int
|
|
TrackFailOnError() bool
|
|
|
|
Color() bool
|
|
NoColor() bool
|
|
|
|
Description() string
|
|
|
|
DAGConfig
|
|
|
|
concurrencyConfig
|
|
interactive
|
|
loggingConfig
|
|
valuesControlMode
|
|
}
|
|
|
|
type DiffConfigProvider interface {
|
|
Args() string
|
|
PostRenderer() string
|
|
PostRendererArgs() []string
|
|
SkipSchemaValidation() bool
|
|
SuppressOutputLineRegex() []string
|
|
|
|
Values() []string
|
|
Set() []string
|
|
Validate() bool
|
|
SkipCRDs() bool
|
|
SkipDeps() bool
|
|
SkipRefresh() bool
|
|
|
|
IncludeTests() bool
|
|
|
|
Suppress() []string
|
|
SuppressSecrets() bool
|
|
ShowSecrets() bool
|
|
NoHooks() bool
|
|
SuppressDiff() bool
|
|
SkipDiffOnInstall() bool
|
|
DiffArgs() string
|
|
|
|
DAGConfig
|
|
|
|
DetailedExitcode() bool
|
|
StripTrailingCR() bool
|
|
Color() bool
|
|
NoColor() bool
|
|
Context() int
|
|
DiffOutput() string
|
|
TakeOwnership() bool
|
|
ServerSide() string
|
|
|
|
concurrencyConfig
|
|
valuesControlMode
|
|
}
|
|
|
|
// DoctorConfigProvider is the configuration surface required by App.Doctor.
|
|
// It embeds DiffConfigProvider because doctor is a strict superset of diff:
|
|
// the same helm-diff flags plus a handful of AI-specific knobs.
|
|
//
|
|
// The LLM-related accessors return the flag-sourced config only; env and
|
|
// helmfile.yaml sources are resolved by the doctor package itself
|
|
// (see pkg/agent/doctor/config.go).
|
|
type DoctorConfigProvider interface {
|
|
DiffConfigProvider
|
|
|
|
// FlagLLMConfig returns the LLM configuration sourced from --llm-* flags.
|
|
// Empty fields mean "flag not set" and do not override env/yaml.
|
|
FlagLLMConfig() llm.Config
|
|
|
|
// Force skips the high-risk exit-code-2 gate.
|
|
Force() bool
|
|
|
|
// DoctorOutput returns the report format ("text" or "json"). Named
|
|
// DoctorOutput to avoid colliding with DiffConfigProvider.DiffOutput
|
|
// which is the helm-diff plugin output format.
|
|
DoctorOutput() string
|
|
}
|
|
|
|
type DestroyConfigProvider interface {
|
|
Args() string
|
|
Cascade() string
|
|
|
|
SkipDeps() bool
|
|
SkipRefresh() bool
|
|
SkipCharts() bool
|
|
DeleteWait() bool
|
|
DeleteTimeout() int
|
|
NoColor() bool
|
|
|
|
interactive
|
|
loggingConfig
|
|
concurrencyConfig
|
|
}
|
|
|
|
type TestConfigProvider interface {
|
|
Args() string
|
|
|
|
SkipDeps() bool
|
|
SkipRefresh() bool
|
|
Timeout() int
|
|
Cleanup() bool
|
|
Logs() bool
|
|
|
|
concurrencyConfig
|
|
}
|
|
|
|
type LintConfigProvider interface {
|
|
Args() string
|
|
|
|
Values() []string
|
|
Set() []string
|
|
SkipDeps() bool
|
|
SkipRefresh() bool
|
|
SkipCleanup() bool
|
|
|
|
DAGConfig
|
|
|
|
concurrencyConfig
|
|
}
|
|
|
|
type UnittestConfigProvider interface {
|
|
Args() string
|
|
|
|
Values() []string
|
|
Set() []string
|
|
FailFast() bool
|
|
Color() bool
|
|
DebugPlugin() bool
|
|
SkipDeps() bool
|
|
SkipRefresh() bool
|
|
SkipCleanup() bool
|
|
|
|
DAGConfig
|
|
|
|
concurrencyConfig
|
|
}
|
|
|
|
type FetchConfigProvider interface {
|
|
SkipDeps() bool
|
|
SkipRefresh() bool
|
|
OutputDir() string
|
|
OutputDirTemplate() string
|
|
WriteOutput() bool
|
|
|
|
concurrencyConfig
|
|
}
|
|
|
|
type TemplateConfigProvider interface {
|
|
Args() string
|
|
PostRenderer() string
|
|
PostRendererArgs() []string
|
|
SkipSchemaValidation() bool
|
|
|
|
Values() []string
|
|
Set() []string
|
|
OutputDirTemplate() string
|
|
Validate() bool
|
|
SkipDeps() bool
|
|
SkipRefresh() bool
|
|
SkipCleanup() bool
|
|
SkipTests() bool
|
|
OutputDir() string
|
|
IncludeCRDs() bool
|
|
NoHooks() bool
|
|
KubeVersion() string
|
|
ShowOnly() []string
|
|
|
|
DAGConfig
|
|
|
|
concurrencyConfig
|
|
}
|
|
|
|
type DAGConfig interface {
|
|
SkipNeeds() bool
|
|
IncludeNeeds() bool
|
|
IncludeTransitiveNeeds() bool
|
|
EnforceNeedsAreInstalled() bool
|
|
}
|
|
|
|
type WriteValuesConfigProvider interface {
|
|
Values() []string
|
|
Set() []string
|
|
OutputFileTemplate() string
|
|
SkipDeps() bool
|
|
SkipRefresh() bool
|
|
SkipCleanup() bool
|
|
IncludeTransitiveNeeds() bool
|
|
|
|
concurrencyConfig
|
|
}
|
|
|
|
type StatusesConfigProvider interface {
|
|
Args() string
|
|
|
|
concurrencyConfig
|
|
}
|
|
|
|
type StateConfigProvider interface {
|
|
EmbedValues() bool
|
|
}
|
|
|
|
type DAGConfigProvider any
|
|
|
|
type concurrencyConfig interface {
|
|
Concurrency() int
|
|
}
|
|
|
|
type loggingConfig interface {
|
|
Logger() *zap.SugaredLogger
|
|
}
|
|
|
|
type interactive interface {
|
|
Interactive() bool
|
|
}
|
|
|
|
type ListConfigProvider interface {
|
|
Output() string
|
|
SkipCharts() bool
|
|
}
|
|
|
|
type CacheConfigProvider any
|
|
|
|
type InitConfigProvider interface {
|
|
Force() bool
|
|
}
|
|
|
|
type CreateConfigProvider interface {
|
|
Name() string
|
|
OutputDir() string
|
|
Force() bool
|
|
|
|
loggingConfig
|
|
}
|
|
|
|
type PrintEnvConfigProvider interface {
|
|
Output() string
|
|
}
|
|
|
|
// reset/reuse values helm cli flags handling for apply/sync/diff
|
|
type valuesControlMode interface {
|
|
ReuseValues() bool
|
|
ResetValues() bool
|
|
}
|