-
Notifications
You must be signed in to change notification settings - Fork 105
helm 从SDK 升级为二进制命令方式 #235
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
helm 从SDK 升级为二进制命令方式 #235
Conversation
- 新增 HelmCmd 实现,通过调用 helm 二进制命令完成 Helm 接口功能 - 修改控制器逻辑,默认使用 HelmCmd 替代原有 SDK 实现 - 移除不必要的 pq 依赖并添加 yaml.v2 依赖 - 添加 Helm 接口文档说明支持多实现方式
feat(models): 添加 HelmChart 的 BatchSave 方法以支持批量保存
- 将 Helm 相关接口和实现从使用 helm.sh/Release 改为自定义的 models.Release - 修改 runAndLog 方法支持标准输入参数 - 优化安装和升级逻辑,统一处理标准输入 - 修复 helm 命令执行时的错误处理
删除不再使用的图表图标和应用信息链接,统一使用更简洁的字段名显示状态信息
Warning Rate limit exceeded@weibaohui has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 13 minutes and 0 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (7)
📝 WalkthroughSummary by CodeRabbit
Summary by CodeRabbit
Walkthrough本次变更重构 Helm 功能,移除原 Helm SDK 实现,新增基于 Helm CLI 的 HelmCmd 实现,支持仓库管理、Release 操作及历史查询。新增 HelmRelease 数据模型及数据库操作。前端新增 Release 参数查看组件,UI 字段简化,新增获取指定修订版本参数和备注的接口及路由。依赖声明调整,新增 YAML 解析库。 Changes
Sequence Diagram(s)sequenceDiagram
participant 用户
participant Controller
participant Helm接口
participant HelmCmd
participant 数据库
用户->>Controller: 请求 Release 列表/安装/卸载/升级/获取备注/获取参数
Controller->>Helm接口: 调用 Release/Repo/Chart 方法
Helm接口->>HelmCmd: 通过 CLI 执行命令
HelmCmd->>数据库: 同步仓库/Chart 元数据(如需)
HelmCmd->>HelmCmd: 解析 CLI 输出(JSON/YAML)
HelmCmd-->>Helm接口: 返回 Release/Chart 数据或操作结果
Helm接口-->>Controller: 返回处理结果
Controller-->>用户: 返回响应
Poem
✨ Finishing Touches
🧪 Generate Unit Tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
修改UninstallRelease方法签名,增加namespace参数 更新所有调用处传递namespace参数 修复helm client实现中的参数顺序错误
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🔭 Outside diff range comments (1)
ui/public/pages/helm/release.json (1)
352-371
: 历史视图中的字段引用不一致。历史视图仍在使用旧的嵌套字段引用如
chart.metadata.version
和info.status
,这些可能与新的简化 Release 模型不兼容,可能导致显示问题。需要将这些字段更新为与新模型一致:
{ - "name": "chart.metadata.version", + "name": "chart", "label": "应用版本", "type": "text" }, { - "name": "info.status", + "name": "status", "label": "状态",
🧹 Nitpick comments (3)
pkg/models/helm_chart.go (1)
33-33
: 修正注释中的错误实体类型。注释中提到的 "InspectionCheckEvent" 应该是 "HelmChart"。
-// BatchSave 批量保存 InspectionCheckEvent 实例 +// BatchSave 批量保存 HelmChart 实例pkg/controller/helm/helm.go (1)
19-28
: 清理注释代码并确认架构变更。从基于集群 REST 配置的方法切换到直接的 CLI 命令包装器是一个重大的架构变更。建议删除注释的代码而不是保留,以保持代码库的整洁。
- // if namespace == "" { - // namespace = "default" - // } - // selectedCluster, err := amis.GetSelectedCluster(c) - // if err != nil { - // amis.WriteJsonError(c, err) - // return nil, err - // } - // restConfig := service.ClusterService().GetClusterByID(selectedCluster).GetRestConfig() - // h, err := helm.New(restConfig, namespace) - // return h, err cmd := helm.NewHelmCmd("helm") return cmd, nil新的 CLI 方法简化了 Helm 客户端的创建过程。
pkg/helm/helm_cmd.go (1)
43-43
: 使用结构化日志而非 fmt.Printf建议使用
klog
进行日志记录,以保持与项目其他部分的一致性。- fmt.Printf("[helm-cmd] exec: %s\n", cmdStr) + klog.V(6).Infof("[helm-cmd] exec: %s", cmdStr) - fmt.Printf("[helm-cmd] stdout: %s\n", stdout.String()) + klog.V(6).Infof("[helm-cmd] stdout: %s", stdout.String()) - fmt.Printf("[helm-cmd] stderr: %s\n", stderr.String()) + klog.V(6).Infof("[helm-cmd] stderr: %s", stderr.String())Also applies to: 53-58
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
go.mod
(2 hunks)pkg/controller/helm/helm.go
(1 hunks)pkg/controller/helm/helm_release.go
(3 hunks)pkg/helm/helm.go
(3 hunks)pkg/helm/helm_cmd.go
(1 hunks)pkg/models/helm_chart.go
(2 hunks)ui/public/pages/helm/release.json
(4 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
pkg/controller/helm/helm_release.go (1)
pkg/models/helm_chart.go (1)
Release
(49-57)
pkg/controller/helm/helm.go (1)
pkg/helm/helm_cmd.go (1)
NewHelmCmd
(30-38)
pkg/helm/helm.go (1)
pkg/models/helm_chart.go (1)
Release
(49-57)
pkg/helm/helm_cmd.go (5)
pkg/controller/helm/helm_repo.go (2)
AddOrUpdateRepo
(28-55)UpdateReposIndex
(100-125)pkg/models/helm_repository.go (1)
HelmRepository
(11-31)internal/dao/conn.go (1)
DB
(176-182)pkg/models/helm_chart.go (2)
HelmChart
(11-27)Release
(49-57)pkg/controller/helm/helm_release.go (3)
InstallRelease
(62-103)UninstallRelease
(106-127)UpgradeRelease
(164-198)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (go)
🔇 Additional comments (7)
go.mod (1)
35-35
: 依赖变更支持新的 Helm CLI 实现。添加
gopkg.in/yaml.v2
作为直接依赖合理,用于解析 Helm CLI 的 YAML 输出。将github.com/lib/pq
移至间接依赖表明新的 CLI 方法不再直接使用它。这些变更与从 SDK 到 CLI 的架构转换一致。Also applies to: 130-130
pkg/models/helm_chart.go (1)
49-57
: 新的 Release 数据模型简化了 Helm 发布表示。引入自定义 Release 结构体将复杂的 Helm SDK 类型简化为基本字符串字段,这与新的 CLI 方法很好地对齐。Chart 字段改为字符串类型的设计合理,便于处理 CLI 输出。
ui/public/pages/helm/release.json (1)
139-139
: UI 字段引用已更新以匹配新的 Release 模型。主要的 release 列表视图正确更新为使用简化的字段(
status
、chart
、app_version
、updated
),与新的数据模型保持一致。Also applies to: 148-148, 276-276, 281-281, 435-435, 452-452
pkg/controller/helm/helm_release.go (2)
43-54
: 验证排序方向的变更是否有意为之。排序逻辑从降序改为升序(
it.Before(jt)
),这会影响用户看到的 release 顺序。请确认这个变更是有意的,因为用户通常期望看到最新的 release 在前面。另外,时间解析格式非常具体且脆弱。建议增加错误处理的健壮性:
slice.SortBy(list, func(i, j *models.Release) bool { - it, err := time.Parse("2006-01-02 15:04:05.000000 -0700 MST", i.Updated) + it, err := time.Parse(time.RFC3339, i.Updated) if err != nil { + klog.Warningf("Failed to parse time %s: %v", i.Updated, err) return false } - jt, err := time.Parse("2006-01-02 15:04:05.000000 -0700 MST", j.Updated) + jt, err := time.Parse(time.RFC3339, j.Updated) if err != nil { + klog.Warningf("Failed to parse time %s: %v", j.Updated, err) return false } - return it.Before(jt) + return it.After(jt) // 如果需要保持降序 })
95-100
: 同步安装提供了更好的错误处理。从异步 goroutine 改为同步调用可以立即处理和返回错误,提供更好的用户反馈。这是一个积极的改进,尽管可能会稍微影响响应时间。
pkg/helm/helm.go (2)
28-31
: 文档注释清晰明了注释清楚地说明了 Helm 接口支持多种实现方式,有助于代码维护者理解设计意图。
41-41
: 验证通过:GetReleaseList 调用已全部更新已检查所有
GetReleaseList()
的调用点(pkg/helm/helm_cmd.go、pkg/helm/helm.go、pkg/controller/helm/helm_release.go),均已使用[]*models.Release
,未发现仍在引用release.Release
。接口变更已正确适配,无需进一步修改。
扩展Release结构体字段,新增ReleaseHistory类型 添加获取release notes和values的接口 优化helm release历史记录展示字段
将HELM_CACHE_HOME环境变量的设置从全局os.Setenv改为在命令执行时设置,避免影响其他命令的执行环境
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (8)
pkg/helm/helm_cmd.go (8)
39-60
: 改进命令执行的安全性当前实现使用
sh -c
执行命令,这可能导致命令注入漏洞。建议直接使用exec.Command
而不是通过 shell。此外,错误处理逻辑有问题:即使命令成功,如果有 stderr 输出也会返回错误。
func (h *HelmCmd) runAndLog(args []string, stdin string) ([]byte, error) { cmdStr := h.HelmBin + " " + strings.Join(args, " ") fmt.Printf("[helm-cmd] exec: %s\n", cmdStr) - // cmd := exec.Command(h.HelmBin, args...) - cmd := exec.Command("sh", "-c", cmdStr) + cmd := exec.Command(h.HelmBin, args...) if stdin != "" { cmd.Stdin = strings.NewReader(stdin) } var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() if stdout.Len() > 0 { fmt.Printf("[helm-cmd] stdout: %s\n", stdout.String()) } if stderr.Len() > 0 { fmt.Printf("[helm-cmd] stderr: %s\n", stderr.String()) - err = fmt.Errorf(stderr.String()) + // 只有在命令执行失败时才将 stderr 作为错误 + if err != nil { + err = fmt.Errorf("command failed: %v, stderr: %s", err, stderr.String()) + } } return stdout.Bytes(), err }
42-42
: 避免记录敏感信息当前代码会将包含密码的完整命令记录到日志中,这是一个安全风险。
func (h *HelmCmd) runAndLog(args []string, stdin string) ([]byte, error) { - cmdStr := h.HelmBin + " " + strings.Join(args, " ") - fmt.Printf("[helm-cmd] exec: %s\n", cmdStr) + // 构建安全的日志字符串,隐藏敏感参数 + safeArgs := make([]string, len(args)) + copy(safeArgs, args) + for i := 0; i < len(safeArgs)-1; i++ { + if safeArgs[i] == "--password" { + safeArgs[i+1] = "***" + } + } + cmdStr := h.HelmBin + " " + strings.Join(safeArgs, " ") + fmt.Printf("[helm-cmd] exec: %s\n", cmdStr)
87-87
: 避免直接使用 os.Setenv在并发环境中,
os.Setenv
会影响整个进程的环境变量,可能导致竞态条件。建议为每个命令设置独立的环境变量。建议修改
runAndLog
方法以支持环境变量:func (h *HelmCmd) runAndLogWithEnv(args []string, stdin string, env map[string]string) ([]byte, error) { cmd := exec.Command(h.HelmBin, args...) cmd.Env = os.Environ() for k, v := range env { cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v)) } // ... 其余代码 }
106-111
: 返回值顺序不符合 Go 惯例Go 的惯例是将 error 作为最后一个返回值。当前实现返回
(error, bool)
,应该改为(bool, error)
。-func (h *HelmCmd) updateRepoByName(repoEntry *repo.Entry, helmRepo *models.HelmRepository) (error, bool) { +func (h *HelmCmd) updateRepoByName(repoEntry *repo.Entry, helmRepo *models.HelmRepository) (bool, error) { // 4. helm repo update out, err := h.runAndLog([]string{"repo", "update", repoEntry.Name}, "") if err != nil { - return fmt.Errorf("helm repo update failed: %v, output: %s", err, string(out)), true + return true, fmt.Errorf("helm repo update failed: %v, output: %s", err, string(out)) }相应地更新调用处:
- err2, done := h.updateRepoByName(repoEntry, helmRepo) + done, err2 := h.updateRepoByName(repoEntry, helmRepo)
127-127
: 使用 repository_id 而非 repository_name 删除记录当前使用
repository_name
删除记录可能不够精确,特别是当存在同名但不同 URL 的仓库时。建议使用repository_id
以确保准确性。- dao.DB().Where("repository_name = ?", repoEntry.Name).Delete(models.HelmChart{}) + dao.DB().Where("repository_id = ?", helmRepo.ID).Delete(&models.HelmChart{})
217-217
: UpgradeRelease 方法中的 chartRef 构造错误使用
releaseName
作为 chart 名称是错误的。应该先获取 release 的历史记录,从中提取正确的 chart 名称。func (h *HelmCmd) UpgradeRelease(releaseName, repoName, targetVersion string, values ...string) error { - chartRef := fmt.Sprintf("%s/%s", repoName, releaseName) + // 需要先获取 release 信息以确定 chart 名称 + // 注意:当前方法签名缺少 namespace 参数 + // 建议修改方法签名以包含 namespace args := []string{"upgrade", releaseName, chartRef, "--version", targetVersion}注意:此方法签名与接口定义不一致,接口中没有 namespace 参数,但实际执行 helm 命令时需要指定 namespace。
243-243
: 移除硬编码的 stderr 重定向在命令参数中硬编码
2>/dev/null
依赖于 shell 特性,这与之前建议的直接使用exec.Command
不兼容。- args := []string{"search", "repo", chartRef, "-o", "json", "--versions", "2>/dev/null"} + args := []string{"search", "repo", chartRef, "-o", "json", "--versions"}
289-289
: 处理 updateRepoByName 的返回值调用
updateRepoByName
但忽略了其返回值,应该处理可能的错误。- h.updateRepoByName(repoEntry, item) + done, err := h.updateRepoByName(repoEntry, item) + if err != nil { + klog.Errorf("Failed to update repo %s: %v", item.Name, err) + }
🧹 Nitpick comments (2)
pkg/helm/helm.go (1)
8-539
: 建议删除注释代码而非保留整个 SDK 实现已被注释,既然已经切换到二进制命令方式,建议完全删除这些注释代码,以保持代码库的整洁。如果需要保留历史记录,Git 版本控制已经提供了这个功能。
-// import ( -// -// "errors" -// "fmt" -... -// func debug(format string, v ...interface{}) { -// klog.V(6).Infof(format, v...) -// }pkg/helm/helm_cmd.go (1)
128-172
: 优化批量保存逻辑当前实现逐个保存 chart,对于包含大量 chart 的仓库可能效率较低。建议使用批量保存来提高性能。
+ var charts []models.HelmChart for chartName, versionList := range index.Entries { if len(versionList) == 0 { continue } slice.SortBy(versionList, func(a *repo.ChartVersion, b *repo.ChartVersion) bool { return a.Created.After(b.Created) }) ct := versionList[0] if ct.Metadata != nil { m := models.HelmChart{ RepositoryID: helmRepo.ID, RepositoryName: helmRepo.Name, Name: chartName, // ... 其他字段 } - err = m.Save(nil) - if err != nil { - fmt.Printf("[helm-cmd] warn: save helm chart to database error: %v\n", err) - } + charts = append(charts, m) } } + // 批量保存 + if len(charts) > 0 { + if err := dao.DB().CreateInBatches(charts, 100).Error; err != nil { + return fmt.Errorf("batch save helm charts error: %v", err) + } + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
pkg/controller/helm/helm_release.go
(6 hunks)pkg/helm/helm.go
(1 hunks)pkg/helm/helm_cmd.go
(1 hunks)pkg/models/helm_chart.go
(2 hunks)ui/public/pages/helm/release.json
(6 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- ui/public/pages/helm/release.json
- pkg/models/helm_chart.go
- pkg/controller/helm/helm_release.go
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (go)
将updateRepoByName函数的返回值顺序从(error, bool)改为(bool, error)以符合Go语言惯例 简化AddOrUpdateRepo函数中的错误处理逻辑
将helm命令的环境变量设置改为追加模式,避免覆盖系统原有环境变量
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (7)
pkg/helm/helm_cmd.go (7)
42-42
: 避免在日志中记录敏感信息当前代码会将完整的命令字符串打印到日志中,这可能包含密码等敏感信息。
45-45
: 严重安全问题:命令注入风险使用
sh -c
执行拼接的命令字符串存在命令注入漏洞。攻击者可能通过特殊构造的输入执行任意命令。
114-115
: 潜在的路径遍历安全风险直接使用用户输入的
repoEntry.Name
构造文件路径可能导致路径遍历攻击。
217-217
: 错误:使用 releaseName 构造 chartRef使用
releaseName
作为 chart 名称是错误的。Release 名称和 Chart 名称可能不同。
243-243
: 移除硬编码的 stderr 重定向在命令参数中硬编码
2>/dev/null
不会生效,因为这是 shell 特性。
289-289
: 处理 updateRepoByName 的错误返回值当前代码忽略了
updateRepoByName
的错误返回值,可能导致更新失败时没有任何提示。建议修改:
- _, _ = h.updateRepoByName(repoEntry, item) + _, err := h.updateRepoByName(repoEntry, item) + if err != nil { + klog.Errorf("Failed to update repo %s: %v", item.Name, err) + }
40-63
: 改进命令执行的安全性和错误处理当前实现存在多个问题需要修复:
- 使用
sh -c
执行命令存在命令注入风险- 错误处理逻辑不正确:stderr 有输出不一定表示错误
建议修改如下:
func (h *HelmCmd) runAndLog(args []string, stdin string) ([]byte, error) { cmdStr := h.HelmBin + " " + strings.Join(args, " ") - fmt.Printf("[helm-cmd] exec: %s\n", cmdStr) - // cmd := exec.Command(h.HelmBin, args...) - - cmd := exec.Command("sh", "-c", cmdStr) + // 移除敏感信息的日志记录 + klog.V(6).Infof("[helm-cmd] exec: %s %s", h.HelmBin, maskSensitiveArgs(args)) + cmd := exec.Command(h.HelmBin, args...) cmd.Env = append(os.Environ(), fmt.Sprintf("%s=%s", "HELM_CACHE_HOME", h.repoCacheDir)) if stdin != "" { cmd.Stdin = strings.NewReader(stdin) } var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() if stdout.Len() > 0 { - fmt.Printf("[helm-cmd] stdout: %s\n", stdout.String()) + klog.V(6).Infof("[helm-cmd] stdout: %s", stdout.String()) } if stderr.Len() > 0 { - fmt.Printf("[helm-cmd] stderr: %s\n", stderr.String()) - err = fmt.Errorf(stderr.String()) + klog.V(6).Infof("[helm-cmd] stderr: %s", stderr.String()) + // 只有在命令执行失败时才将 stderr 作为错误 + if err != nil { + err = fmt.Errorf("command failed: %v, stderr: %s", err, stderr.String()) + } } return stdout.Bytes(), err } + +// maskSensitiveArgs 隐藏命令参数中的敏感信息 +func maskSensitiveArgs(args []string) []string { + masked := make([]string, len(args)) + copy(masked, args) + for i := 0; i < len(masked); i++ { + if i > 0 && (masked[i-1] == "--password" || masked[i-1] == "--username") { + masked[i] = "***" + } + } + return masked +}
🧹 Nitpick comments (2)
pkg/helm/helm_cmd.go (2)
88-94
: 建议使用更安全的方式传递凭据当前通过命令行参数传递用户名和密码,这些信息可能被系统进程列表(如
ps
命令)暴露。考虑使用环境变量或配置文件传递敏感信息:
args := []string{"repo", "add", repoEntry.Name, repoEntry.URL} -if repoEntry.Username != "" { - args = append(args, "--username", repoEntry.Username) -} -if repoEntry.Password != "" { - args = append(args, "--password", repoEntry.Password) -} +// 使用配置文件传递凭据 +if repoEntry.Username != "" || repoEntry.Password != "" { + configFile, err := h.createTempRepoConfig(repoEntry) + if err != nil { + return fmt.Errorf("create temp config failed: %v", err) + } + defer os.Remove(configFile) + args = append(args, "--repo-config", configFile) +}
295-326
: 代码重复:考虑提取通用的 JSON 命令执行方法多个方法(GetReleaseList、GetReleaseNote、GetReleaseValues 等)都遵循相同的模式:执行命令、获取 JSON 输出、解析结果。
建议提取一个通用方法减少代码重复:
// runJSONCommand 执行 helm 命令并返回 JSON 输出 func (h *HelmCmd) runJSONCommand(args []string) ([]byte, error) { args = append(args, "-o", "json") out, err := h.runAndLog(args, "") if err != nil { return nil, fmt.Errorf("helm %s failed: %v, output: %s", args[0], err, string(out)) } return out, nil } // 使用示例 func (h *HelmCmd) GetReleaseList() ([]*models.Release, error) { out, err := h.runJSONCommand([]string{"list", "-A"}) if err != nil { return nil, err } var releases []*models.Release if err := json.Unmarshal(out, &releases); err != nil { return nil, fmt.Errorf("unmarshal helm list output failed: %v", err) } return releases, nil }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
pkg/helm/helm_cmd.go
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (go)
添加新的API接口用于获取指定版本的release值 将GetReleaseValues和GetReleaseValuesWithRevision的输出格式从json改为yaml 简化UpgradeRelease接口参数,移除repo和version字段 优化前端HelmUpdateRelease组件,移除版本选择逻辑
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (6)
pkg/helm/helm.go (1)
8-539
: 建议删除注释代码而非保留整个 SDK 实现已被注释掉。根据 PR 描述,这是从 SDK 迁移到二进制命令方式的一部分。建议完全删除这些注释代码,以保持代码库整洁。
如果确认不再需要 SDK 实现,建议:
- 删除所有注释代码(第8-539行)
- 在文件顶部添加说明,指出现在使用
HelmCmd
实现- 或者将这些代码移到单独的废弃文件中以备参考
pkg/helm/helm_cmd.go (5)
288-288
: 处理 updateRepoByName 的错误虽然使用
_, _
显式忽略了返回值,但建议至少记录错误信息以便调试。
40-63
: 严重安全问题:命令注入风险使用
sh -c
执行命令存在命令注入漏洞。攻击者可能通过特殊构造的参数执行任意命令。必须修改为直接使用
exec.Command
:func (h *HelmCmd) runAndLog(args []string, stdin string) ([]byte, error) { cmdStr := h.HelmBin + " " + strings.Join(args, " ") - fmt.Printf("[helm-cmd] exec: %s\n", cmdStr) - // cmd := exec.Command(h.HelmBin, args...) - - cmd := exec.Command("sh", "-c", cmdStr) + // 只记录命令用于调试,但要注意不记录敏感信息 + safeArgs := make([]string, len(args)) + copy(safeArgs, args) + for i, arg := range safeArgs { + if i > 0 && (args[i-1] == "--password" || args[i-1] == "--username") { + safeArgs[i] = "***" + } + } + fmt.Printf("[helm-cmd] exec: %s %s\n", h.HelmBin, strings.Join(safeArgs, " ")) + + cmd := exec.Command(h.HelmBin, args...) cmd.Env = append(os.Environ(), fmt.Sprintf("%s=%s", "HELM_CACHE_HOME", h.repoCacheDir)) if stdin != "" { cmd.Stdin = strings.NewReader(stdin) } var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() if stdout.Len() > 0 { fmt.Printf("[helm-cmd] stdout: %s\n", stdout.String()) } if stderr.Len() > 0 { fmt.Printf("[helm-cmd] stderr: %s\n", stderr.String()) - err = fmt.Errorf(stderr.String()) + // 只在命令失败时将 stderr 作为错误信息 + if err != nil { + err = fmt.Errorf("command failed: %v, stderr: %s", err, stderr.String()) + } } return stdout.Bytes(), err }
88-94
: 避免在日志中暴露敏感信息当前实现会在日志中记录密码等敏感信息。
参见第40-63行的修复建议,其中包含了对敏感参数的处理。
114-115
: 验证仓库名称以防止路径遍历虽然路径是在缓存目录内构建的,但仍应验证仓库名称以防止路径遍历攻击。
添加仓库名称验证:
+ // 验证仓库名称,防止路径遍历 + if strings.Contains(repoEntry.Name, "..") || strings.Contains(repoEntry.Name, "/") { + return false, fmt.Errorf("invalid repository name: %s", repoEntry.Name) + } + cachePath := fmt.Sprintf("%s/repository/%s-index.yaml", h.repoCacheDir, repoEntry.Name)
242-242
: 移除硬编码的 stderr 重定向在命令参数中包含
2>/dev/null
依赖于 shell 特性,与建议的直接使用exec.Command
不兼容。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
main.go
(1 hunks)pkg/controller/helm/helm_release.go
(9 hunks)pkg/helm/helm.go
(1 hunks)pkg/helm/helm_cmd.go
(1 hunks)ui/src/components/Amis/custom/Helm/HelmUpdateRealease.tsx
(4 hunks)
✅ Files skipped from review due to trivial changes (1)
- main.go
🧰 Additional context used
🧬 Code Graph Analysis (2)
pkg/helm/helm.go (4)
pkg/controller/helm/helm_repo.go (2)
AddOrUpdateRepo
(28-55)UpdateReposIndex
(100-125)pkg/models/helm_chart.go (2)
ReleaseHistory
(59-65)Release
(49-58)pkg/controller/helm/helm_release.go (5)
InstallRelease
(62-103)UninstallRelease
(106-127)UpgradeRelease
(213-245)GetReleaseNote
(130-146)GetReleaseValues
(149-176)pkg/controller/helm/helm_chart.go (1)
GetChartValue
(26-46)
pkg/controller/helm/helm_release.go (1)
pkg/models/helm_chart.go (1)
Release
(49-58)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (go)
🔇 Additional comments (3)
ui/src/components/Amis/custom/Helm/HelmUpdateRealease.tsx (1)
57-63
: 升级请求参数简化合理移除了
version
和repoName
参数,只保留必要的values
、name
和namespace
,这与后端从 SDK 迁移到 CLI 的实现方式相匹配。pkg/helm/helm.go (1)
39-52
: 接口更新符合 CLI 实现需求接口变更包括:
- 为多个方法添加了明确的
namespace
参数- 简化了
UpgradeRelease
的参数- 新增了获取 release 详细信息的方法
这些变更与从 SDK 迁移到 CLI 的实现方式一致。
pkg/controller/helm/helm_release.go (1)
129-176
: 新增的获取 Release 详情功能实现合理新增的
GetReleaseNote
和GetReleaseValues
处理器正确实现了:
- 获取 Release 说明信息
- 支持按版本获取 Release 配置值
- 合理的错误处理
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (4)
pkg/helm/helm_cmd.go (4)
114-115
: 验证文件路径以防止路径遍历攻击。直接使用用户提供的仓库名称构建文件路径可能存在路径遍历风险。
建议添加路径验证:
+import "path/filepath" + +// 验证仓库名称 +if strings.Contains(repoEntry.Name, "..") || strings.Contains(repoEntry.Name, "/") { + return false, fmt.Errorf("invalid repository name: %s", repoEntry.Name) +} cachePath := fmt.Sprintf("%s/repository/%s-index.yaml", h.repoCacheDir, repoEntry.Name) +cachePath = filepath.Clean(cachePath)
42-42
: 避免记录敏感信息。命令字符串可能包含密码等敏感信息,不应该直接打印到日志中。
45-45
: 避免使用 shell 执行命令,存在命令注入风险。使用
sh -c
执行命令可能导致命令注入漏洞。建议直接使用exec.Command(h.HelmBin, args...)
。建议修改:
-cmd := exec.Command("sh", "-c", cmdStr) +cmd := exec.Command(h.HelmBin, args...)
269-269
: 移除硬编码的 stderr 重定向。在命令参数中硬编码
2>/dev/null
依赖于 shell 特性,与直接使用exec.Command
不兼容。-args := []string{"search", "repo", chartRef, "-o", "json", "--versions", "2>/dev/null"} +args := []string{"search", "repo", chartRef, "-o", "json", "--versions"}
🧹 Nitpick comments (1)
pkg/helm/helm_cmd.go (1)
315-315
: 处理 updateRepoByName 的错误返回值。虽然使用了
_, _
明确忽略返回值,但建议至少记录错误以便调试。-_, _ = h.updateRepoByName(repoEntry, item) +_, err := h.updateRepoByName(repoEntry, item) +if err != nil { + klog.Errorf("Failed to update repo %s: %v", item.Name, err) +}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
pkg/helm/helm_cmd.go
(1 hunks)pkg/models/helm_release.go
(1 hunks)pkg/models/migrate.go
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
pkg/models/migrate.go (2)
internal/dao/conn.go (1)
DB
(176-182)pkg/models/helm_release.go (1)
HelmRelease
(11-23)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (go)
🔇 Additional comments (5)
pkg/helm/helm_cmd.go (1)
46-46
: 环境变量设置方式正确。使用
cmd.Env
为每个命令单独设置环境变量,避免了并发环境中的竞态条件。pkg/models/migrate.go (1)
67-69
: 自动迁移添加正确新增 HelmRelease 模型的数据库迁移遵循了现有的迁移模式,错误处理方式与其他模型保持一致。
pkg/models/helm_release.go (3)
11-23
: HelmRelease 模型设计合理结构体定义包含了 Helm 发布管理所需的关键字段,GORM 注解使用恰当:
- 主键和索引设置合理
- 命名空间和 Chart 名称设置了必填约束
- JSON 标签支持 API 序列化
- 时间戳字段便于跟踪记录变更
25-39
: CRUD 方法实现标准使用通用 DAO 函数实现标准的增删改查操作,与项目中其他模型保持一致的实现模式,代码复用性良好。
41-55
: 专用查询函数设计恰当两个专用函数针对 Helm 发布的业务场景:
GetHelmReleaseByNsAndReleaseName
: 通过命名空间和发布名称查询,这是 Helm 管理中的常见需求DeleteHelmReleaseByNsAndReleaseName
: 对应的删除操作- 错误处理得当,使用了 GORM 的安全查询构建器
新增HelmViewRelease组件用于查看Helm发布的参数配置,替换原有的diffEditor实现 优化HelmUpdateRelease组件的代码格式
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (4)
ui/src/components/Amis/custom/Helm/HelmViewRelease.tsx (4)
18-18
: 未使用的 ref 参数组件使用了
React.forwardRef
但没有实际使用 ref,建议移除 forwardRef 包装或明确使用 ref。-const HelmViewRelease = React.forwardRef<HTMLSpanElement, HelmViewReleaseProps>(({ data }, _) => { +const HelmViewRelease: React.FC<HelmViewReleaseProps> = ({ data }) => {
21-24
: 变量命名不一致变量命名存在不一致问题,建议统一命名风格以提高代码可读性。
- let chartName = data.chart - let releaseName = data.name - let namespace = data.namespace - let revision = data.revision + const chartName = data.chart; + const releaseName = data.name; + const namespace = data.namespace; + const revision = data.revision;
61-61
: 建议将内联样式提取为 CSS 类内联样式不利于维护和重用,建议提取为 CSS 类或使用 styled-components。
可以在组件文件同目录创建对应的 CSS 文件:
.editor-container { border: 1px solid #d9d9d9; border-radius: 4px; }然后在组件中使用:
- <div style={{ border: '1px solid #d9d9d9', borderRadius: '4px' }}> + <div className="editor-container">
63-63
: 编辑器高度计算可能不够灵活硬编码的高度计算
calc(100vh - 200px)
可能在不同布局下不够灵活,建议考虑更动态的高度计算方式。可以考虑使用
useRef
和ResizeObserver
来动态调整编辑器高度,或者将高度作为 props 传入以增加组件的灵活性。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
ui/public/pages/helm/release.json
(8 hunks)ui/src/components/Amis/custom/Helm/HelmUpdateRealease.tsx
(3 hunks)ui/src/components/Amis/custom/Helm/HelmViewRelease.tsx
(1 hunks)ui/src/components/Amis/index.tsx
(3 hunks)
✅ Files skipped from review due to trivial changes (1)
- ui/src/components/Amis/index.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- ui/src/components/Amis/custom/Helm/HelmUpdateRealease.tsx
- ui/public/pages/helm/release.json
🧰 Additional context used
🧬 Code Graph Analysis (1)
ui/src/components/Amis/custom/Helm/HelmViewRelease.tsx (1)
ui/src/components/Amis/fetcher.ts (1)
fetcher
(8-60)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (go)
将cluster名称中的/替换为|以避免路径问题,并确保缓存目录存在
使用klog替代fmt.Printf进行日志输出,可以更好地控制日志级别和格式
在Helm接口和控制器中添加GetReleaseNoteWithRevision方法,支持通过指定版本号获取release notes。同时更新前端页面以适配新功能。
移除helm get notes命令中的json输出参数,并调整API返回格式为包含note字段的对象 更新前端页面以正确显示notes内容
在Dockerfile中增加helm工具的安装,同时添加tar和gzip工具包 优化apk包管理命令,删除无用缓存
升级基础镜像软件包并清理缓存,同时添加helm工具支持。优化构建步骤顺序以提高效率。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (9)
pkg/helm/helm_cmd.go (9)
48-48
: kubeconfig 文件权限过于宽松kubeconfig 包含敏感认证信息,但使用 0644 权限允许其他用户读取。
修改文件权限为仅所有者可读写:
-if err := os.WriteFile(kubeconfigPath, []byte(config), 0644); err != nil { +if err := os.WriteFile(kubeconfigPath, []byte(config), 0600); err != nil {
68-68
: 命令注入安全漏洞使用
sh -c
执行命令存在命令注入风险。应直接使用exec.Command
执行。修改为直接执行:
-cmd := exec.Command("sh", "-c", cmdStr) +cmd := exec.Command(h.HelmBin, args...)
84-87
: 错误处理逻辑有误即使命令成功执行,如果有 stderr 输出也会返回错误。某些命令正常运行时也会输出到 stderr。
修正错误处理:
if stderr.Len() > 0 { klog.V(6).Infof("[helm-cmd] stderr: %s\n", stderr.String()) - err = fmt.Errorf("%s", stderr.String()) + // 只有在命令执行失败时才将 stderr 作为错误 + if err != nil { + err = fmt.Errorf("command failed: %v, stderr: %s", err, stderr.String()) + } }
116-120
: 避免记录敏感信息密码通过命令行参数传递并在日志中以明文形式记录,存在安全风险。
建议使用环境变量或标准输入传递密码:
if repoEntry.Username != "" { args = append(args, "--username", repoEntry.Username) } if repoEntry.Password != "" { - args = append(args, "--password", repoEntry.Password) + // 通过标准输入传递密码,避免在命令行中暴露 + args = append(args, "--password-stdin") } -out, err := h.runAndLog(args, "") +out, err := h.runAndLog(args, repoEntry.Password)
132-132
: 返回值顺序不符合 Go 惯例Go 惯例是将 error 作为最后一个返回值。当前返回
(bool, error)
。修改返回值顺序并更新所有调用处:
-func (h *HelmCmd) updateRepoByName(repoEntry *repo.Entry, helmRepo *models.HelmRepository) (bool, error) { +func (h *HelmCmd) updateRepoByName(repoEntry *repo.Entry, helmRepo *models.HelmRepository) (bool, error) {
250-250
: Values 可能包含敏感信息将完整的 values 内容存储到数据库可能暴露密码、密钥等敏感信息。
建议实施以下安全措施之一:
- 对敏感字段进行脱敏处理
- 加密存储 values 内容
- 仅存储 values 的哈希值用于变更检测
- 使用专门的凭据管理服务
296-296
: 移除硬编码的 stderr 重定向在命令参数中硬编码
2>/dev/null
依赖于 shell 特性,与直接使用exec.Command
不兼容。-args := []string{"search", "repo", chartRef, "-o", "json", "--versions", "2>/dev/null"} +args := []string{"search", "repo", chartRef, "-o", "json", "--versions"}
342-342
: 处理 updateRepoByName 的返回值调用
updateRepoByName
但忽略了其返回值,应该处理可能的错误。-_, _ = h.updateRepoByName(repoEntry, item) +if _, err := h.updateRepoByName(repoEntry, item); err != nil { + klog.Errorf("Failed to update repo %s: %v", item.Name, err) +}
43-43
: 存在路径遍历安全漏洞
cluster
参数未经验证直接用于构建文件路径。如果包含../
等路径遍历序列,可能导致文件被写入任意位置。建议添加输入验证:
+import "path/filepath" kubeconfigPath := fmt.Sprintf("%s/%s-kubeconfig.yaml", repoCacheDir, strings.ReplaceAll(cluster, "/", "|")) +// 验证路径安全性 +kubeconfigPath = filepath.Clean(kubeconfigPath) +if !strings.HasPrefix(kubeconfigPath, repoCacheDir) { + return nil, fmt.Errorf("invalid cluster name") +}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
main.go
(1 hunks)pkg/controller/helm/helm.go
(1 hunks)pkg/controller/helm/helm_release.go
(9 hunks)pkg/helm/helm.go
(1 hunks)pkg/helm/helm_cmd.go
(1 hunks)pkg/models/helm_release.go
(1 hunks)ui/public/pages/helm/release.json
(9 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- main.go
- pkg/controller/helm/helm.go
- ui/public/pages/helm/release.json
- pkg/models/helm_release.go
- pkg/controller/helm/helm_release.go
🧰 Additional context used
🧬 Code Graph Analysis (1)
pkg/helm/helm_cmd.go (6)
pkg/controller/helm/helm_repo.go (2)
AddOrUpdateRepo
(28-55)UpdateReposIndex
(100-125)pkg/models/helm_repository.go (1)
HelmRepository
(11-31)internal/dao/conn.go (1)
DB
(176-182)pkg/models/helm_chart.go (3)
HelmChart
(11-27)ReleaseHistory
(59-65)Release
(49-58)pkg/controller/helm/helm_release.go (4)
UninstallRelease
(106-127)InstallRelease
(62-103)GetReleaseNote
(130-149)GetReleaseValues
(152-179)pkg/models/helm_release.go (3)
DeleteHelmReleaseByNsAndReleaseName
(54-56)HelmRelease
(11-24)GetHelmReleaseByNsAndReleaseName
(43-51)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (go)
🔇 Additional comments (4)
pkg/helm/helm_cmd.go (2)
153-199
: Chart 索引处理实现良好代码正确处理了仓库索引文件的解析和 Chart 信息的数据库存储:
- 使用 repository_id 精确删除旧数据
- 按创建时间排序获取最新版本
- 对非关键错误进行了适当的日志记录而不中断流程
348-386
: Get 方法实现正确所有获取方法的实现都正确:
GetReleaseList
使用-A
获取所有命名空间- 各方法都正确传递了命名空间参数
- 支持带修订版本的查询
pkg/helm/helm.go (2)
10-10
: 接口方法签名更新合理添加 namespace 参数并更新返回类型为自定义模型是很好的改进,提高了接口的明确性和类型安全性。
17-17
: GetReleaseList 返回类型更新符合重构目标返回类型更新为自定义的
*models.Release
类型,与从 SDK 迁移到二进制命令方式的目标一致。这解决了之前评论中提到的实现不完整问题。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🔭 Outside diff range comments (1)
Dockerfile (1)
2-7
:ARG
参数未一一声明,可能导致构建警告
-ldflags
中引用了$GIT_TAG
,$GIT_REPOSITORY
,$BUILD_DATE
但前面只声明了少部分ARG
。未声明的变量在构建时为空并触发unused build-arg
警告,亦降低可读性。请补充声明或移除未使用的变量。
🧹 Nitpick comments (4)
Dockerfile.action (2)
30-31
: 避免在运行镜像里执行apk upgrade
apk upgrade
会把基础镜像的全部包都升级到 edge 仓库最新版本,可能导致:
- 镜像尺寸暴涨;
- 与基础镜像安全扫描基线不一致;
- 难以重现的“雪花”环境。
除非确有必要安装特定补丁,建议仅使用
apk add --no-cache <pkg>
精确安装所需包。
32-33
: 使用 COPY 替代 ADD 以符合最佳实践此处只是把本地脚本放进镜像,
ADD
的额外功能(自动解压 / 远程 URL)并未用到,容易误导阅读者,也触发 Hadolint DL3020。-ADD reload.sh /app/reload.sh +COPY reload.sh /app/reload.shDockerfile (2)
16-19
:apk upgrade
同样应避免和
Dockerfile.action
中的情况一致,完整升级会引入不可控风险。仅安装所需的软件包即可,建议拆分为:-RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \ - && apk upgrade && apk add --no-cache curl bash inotify-tools alpine-conf busybox-extras tzdata tar gzip\ +RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \ + && apk add --no-cache curl bash inotify-tools busybox-extras tzdata tar gzip \
20-20
: 将ADD reload.sh
改为COPY
功能一致但
COPY
更语义化,亦可消除 Hadolint 警告。-ADD reload.sh /app/reload.sh +COPY reload.sh /app/reload.sh
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
Dockerfile
(1 hunks)Dockerfile.action
(1 hunks)
🧰 Additional context used
🪛 Hadolint (2.12.0)
Dockerfile.action
[error] 32-32: Use COPY instead of ADD for files and folders
(DL3020)
Dockerfile
[error] 20-20: Use COPY instead of ADD for files and folders
(DL3020)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (go)
重构 HelmCmd 结构,新增集群内运行模式支持,包括 token、caFile 和 apiServer 配置 将 cluster 参数改为 ClusterConfig 类型以获取更多集群信息 优化 kubeconfig 处理逻辑,区分集群内外不同运行环境
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (8)
pkg/helm/helm_cmd.go (8)
73-130
: 改进命令执行的安全性和错误处理
103-103
: 避免记录敏感信息
173-173
: 返回值顺序不符合 Go 惯例
182-182
: 路径遍历安全风险
194-194
: 使用 repository_id 而非 repository_name 删除记录
273-299
: 存储敏感数据的安全考虑
337-337
: 移除硬编码的 stderr 重定向
383-383
: 处理 updateRepoByName 的返回值
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
pkg/controller/helm/helm.go
(1 hunks)pkg/helm/helm_cmd.go
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- pkg/controller/helm/helm.go
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (go)
🔇 Additional comments (1)
pkg/helm/helm_cmd.go (1)
430-454
: InCluster 认证实现正确该方法正确读取了 Kubernetes ServiceAccount 的 token 和 CA 证书,实现符合 Kubernetes 的标准做法。
- 在helm_cmd.go中添加索引生成时间的更新逻辑 - 移除helm_repository.go中未使用的content字段 - 调整helm_release.go中字段顺序并添加集群字段
将clusterID从路径替换改为base64编码,避免特殊字符问题 统一接口方法参数命名,将namespace简化为ns 移除调试日志输出
清理 Helm 组件中未使用的 releaseName、repoName 和 chart 属性,简化接口定义
修改了前端和后端代码,统一将获取helm release值和notes的API请求方法从POST改为GET,遵循RESTful规范 同时移除了不必要的类型忽略注释,使用类型断言替代
添加对 chart、name、namespace 和 revision 的默认值处理 当缺少必要信息时显示错误提示并返回 null
helm 从SDK 升级为二进制命令方式