首页 > 编程语言 >给 Helm 修复一个 Bug - 每天5分钟玩转 GPT 编程系列(2)

给 Helm 修复一个 Bug - 每天5分钟玩转 GPT 编程系列(2)

时间:2023-07-07 09:45:52浏览次数:54  
标签:kind log Helm Secret DevChat GPT data Bug

目录

絮絮叨

注:这一篇文章中 Bug 定位的部分,也就是翻源码找问题的部分单独拆到了《给 Helm 提一个 PR,重温开源项目参与过程》中。同时为了让两篇文章单独成文,也就都加了一些开头结尾,部分内容重复。

话接前回《用 IaC 的方式管理 EC2 实例 - 每天5分钟玩转 GPT 编程系列(1)》,今日个咱继续来看在给真实的开源项目修复 Bug 这个场景中,GPT 能够发挥几成功力。

剧透:今天我要到 Helm 项目里找一个 Bug,然后让 GPT-4 来修复这个 Bug。

逛社区

酒足饭饱,闲来无事,打开 Helm 项目的 issues 列表,咦,这个 issue 看起来眉清目秀呀:

其实一点都不“眉清目秀”,这段 issue 描述太冗长了,没有任何排版,看起来很累。咱就看关键词吧:helm upgrade,sensitive data,error,好的,这就够了,加在一起就是说当 helm upgrade 命令执行失败的时候,可能回导致敏感数据泄露

盘它!

领任务

尽管已经有人留言认领这个任务,不过看描述似乎他并不会马上开始编码,而是希望进一步沟通方案。好办好办,转给我吧:

倒是挺干脆,分分钟就 assign 给我了。

不过,其实,这会我并不知道怎么修复这个 bug,我也不熟悉 Helm 的源码,外加已经小半年没咋写过 Golang 了,其实心里挺慌。八层把握吧,毕竟手握屠龙刀 GPT-4,开干!

复现 Bug

要修复 Bug,第一步自然是先看能不能稳定复现。外加 issue 描述里其实我看不出来如何复现,也不是太看清楚问题现象是什么,总之,复现问题是当务之急。

让 DevChat 准备 Bug 复现材料

如果这是你第一次听说 DevChat,来,“辟邪剑谱”接住咯:

  • 我的需求
我发现 Helm 在执行 upgrade 的时候,如果出错,会导致 Secret 里的数据被明文打印出来,存在敏感数据泄露风险。现在我想复现这个问题,我设想的步骤是这样的:
1. 构造一个包含 Secret 的正常的 Helm Chart,Secret 里的数据是从 values.yaml 里读取的,values.yaml 中直接使用 base64 编码字符串,而不是在 secret.yaml 中使用 b64enc;
2. 然后执行 helm install,此刻应该没有问题异常;
3. 修改 values.yaml 中的 base64 字符串,让其非法(比如删除一个结尾的“=”);
4. 执行 helm upgrade 命令,看结果是不是存在敏感数据泄露。
请告诉我相关命令和操作等。
  • 将需求告诉 DevChat

  • DevChat 给出的完整回答

首先,我会概括你的需求:

  • 你想要复现一个问题,该问题是在使用 Helm 进行 upgrade 操作时,如果出错,会导致 Secret 中的数据被明文打印出来,存在敏感数据泄露风险。

  • 你已经设想了一些步骤,包括创建一个包含 Secret 的 Helm Chart,然后进行一些操作来触发这个问题。 下面是我为你准备的相关命令和操作:

  1. 创建一个包含 Secret 的 Helm Chart。首先,你需要创建一个新的 Helm Chart,可以使用以下命令:
helm create mychart

然后,你需要在 mychart/templates 目录下创建一个新的文件 secret.yaml,并添加以下内容:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  mykey: {{ .Values.mysecret.mykey }}

在 mychart/values.yaml 文件中,添加以下内容:

mysecret:
  mykey: "SGVsbG8gd29ybGQ="  # "Hello world" 的 base64 编码
  1. 执行 helm install 命令。在你的 Helm Chart 目录(即 mychart)下,执行以下命令:
helm install myrelease .

此时,应该没有任何问题或异常。

  1. 修改 values.yaml 文件中的 base64 字符串,让其非法。你可以将 values.yaml 文件中的 mykey 值修改为一个非法的 base64 字符串,例如删除一个结尾的“=”:
mysecret:
  mykey: "SGVsbG8gd29ybGQ"  # 非法的 base64 字符串
  1. 执行 helm upgrade 命令。在你的 Helm Chart 目录下,执行以下命令:
helm upgrade myrelease .

此时,你应该能看到错误信息,包括你的 Secret 数据。

以上就是复现你所说问题的步骤。如果你在执行这些步骤时遇到任何问题,或者需要更多的帮助,欢迎随时向我提问。

对着 DevChat 给的命令复现 Bug

DevChat 诚不我欺啊,一顿复制粘贴敲键盘,最后我看到了这个:

注意这个错误日志里的这部分:

Error: UPGRADE FAILED: cannot patch "mysecret" with kind Secret:  "" is invalid: patch: Invalid value: "{\"apiVersion\":\"v1\",\"data\":{\"mykey\":\"SGVsbG8gd29ybGQ\"}……

这里的 mykey: SGVsbG8gd29ybGQ 看起来似乎不太敏感,不过它其实意味着假如你存了10个密码在 Secret 里,当更新的时候写错了一个,其他正确的9个会被无差别打印出来。这个日志里包含的是一个未脱敏的完整的 Secret 资源实例内容。

定位 Bug

从日志里来看,JSON 部分大概率是 K8s 相关的库返回的内容,Helm 里直接拼接到自己日志里打印出来了。我们需要找到最接近这个“K8s 相关调用”的地方,然后找到这串日志怎么来的,再加一层“脱敏”。

翻看源码,可以在 pkg/kube/client.go 源文件中找到一个 updateResource() 函数,里面有这样一段代码:

func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, force bool) error {
	// ……
	if force {
		// ……
	} else {
		// ……
		// send patch to server
		c.Log("Patch %s %q in namespace %s", kind, target.Name, target.Namespace)
		obj, err = helper.Patch(target.Namespace, target.Name, patchType, patch, nil)
		if err != nil {
			return errors.Wrapf(err, "cannot patch %q with kind %s", target.Name, kind)
		}
	}
	// ……
}

这里可以看到是 helper.Patch(target.Namespace, target.Name, patchType, patch, nil) 这个方法调用返回了一个包含敏感数据的 err。如果继续看一眼 Patch 方法的定义,就能找到:

这是 k8s.io/cli-runtime 里的代码,已经离开了 Helm 的“管辖范围”。

修复 Bug

先理思路。

琢磨下怎么修复

很明显,敏感数据来自于这几行代码:

obj, err = helper.Patch(target.Namespace, target.Name, patchType, patch, nil)
if err != nil {
	return errors.Wrapf(err, "cannot patch %q with kind %s", target.Name, kind)
}

我们希望尽脱敏这些数据,自然是在当前函数/方法内完成这个过程,不能把锅留给调用方(上层函数)。所以下一步就是在 if err != nil { 之后,return 之前加入一个日志过滤函数,在这个函数内实现日志脱敏。

接着又到了和 GPT 聊需求阶段了,秉承着“能聊天就不写代码”的原则,继续祭出 DevChat。

让 DevChat 写一个日志脱敏函数

  • 尝试这样和 DevChat 说:
请用 Golang 帮我写一个日志脱敏函数,入参是一个包含敏感数据的字符串,类似这样:

Error: UPGRADE FAILED: cannot patch "mysecret" with kind Secret:  "" is invalid: patch: Invalid value: "{\"apiVersion\":\"v1\",\"data\":{\"mykey\":\"SGVsbG8gd29ybGQ\"},\"kind\":\"Secret\",\"metadata\"……,\"type\":\"Opaque\"}": illegal base64 data at input byte 12

如你所见,这是一个包含了 K8s Secret 资源实例 JSON 字符串的错误日志,其中 data 部分是一个字典,里面的所有 value 都应该被脱敏,用 *** 来打印。

你需要注意以下几点:
1. 你可以先找出从 {\"apiVersion(包含)到 ,\"kind\":\"Secret\"(不包含)之间的部分,,然后去掉\,加上一个},这样就能得到一个小的 JSON 字符串类似这样:{"apiVersion":"v1","data":{省略}},进而你可以解析出内部的字典;
3. 当你解析出来这个字典后,就可以循环遍历这个字典,完成 value 的脱敏了;
4. 脱敏完成后,你需要注意先删去刚才2中额外添加到字符串结尾的一个 },然后重新将这个新的字符串拼接回去,得到脱敏后的新字符串
5. 你可以用中文回答我,但是代码中的注释一律使用英文。
  • 将需求发给 DevChat

  • DevChat 给出了这样的回答

完整代码如下:

package main

import (
	"encoding/json"
	"strings"
)

// DesensitizeLog is a function to desensitize sensitive data in log
func DesensitizeLog(log string) string {
	start := strings.Index(log, "{\"apiVersion")
	end := strings.Index(log, ",\"kind\":\"Secret\"")
	if start == -1 || end == -1 {
		return log
	}

	// Extract the JSON string and add a } at the end
	jsonStr := log[start:end] + "}"
	jsonStr = strings.ReplaceAll(jsonStr, "\\\"", "\"")

	// Parse the JSON string into a map
	var data map[string]interface{}
	err := json.Unmarshal([]byte(jsonStr), &data)
	if err != nil {
		return log
	}

	// Desensitize the values in the data map
	if dataMap, ok := data["data"].(map[string]interface{}); ok {
		for k := range dataMap {
			dataMap[k] = "***"
		}
	}

	// Convert the map back to JSON string
	newJsonStr, err := json.Marshal(data)
	if err != nil {
		return log
	}

	// Replace the original JSON string with the new one in the log
	newJsonStr = []byte(strings.ReplaceAll(string(newJsonStr), "\"", "\\\""))
	newLog := log[:start] + string(newJsonStr[:len(newJsonStr)-1]) + log[end:]

	return newLog
}

看起来大差不差,不过这两行明显写错了:

	start := strings.Index(log, "{\"apiVersion")
	end := strings.Index(log, ",\"kind\":\"Secret\"")

如果在双引号内要表达 \",那得写成 \\\" 才行。这两行要么改成:

	start := strings.Index(log, "{\\\"apiVersion")
	end := strings.Index(log, ",\\\"kind\\\":\\\"Secret\\\"")

要么改成:

	start := strings.Index(log, `{\"apiVersion`)
	end := strings.Index(log, `,\"kind\":\"Secret\"`)

我们将微调后的代码插入 Helm 项目的 client.go 中,然后加几行调用逻辑,同时把函数改成小写字母开头,顺带完善下函数注释:

继续让 DevChat 补充一个 UT

  • 新开一个 topic,将当前最新函数作为上下文,要求 DevChat 写一个 UT
请给这个函数写一个 UT,测试字符串是:
Error: UPGRADE FAILED: cannot patch "mysecret" with kind Secret:  "" is invalid: patch: Invalid value: "{\"apiVersion\":\"v1\",\"data\":{\"mykey1\":\"hello\", \"mykey2\":\"world\"},\"kind\":\"Secret\",\"metadata\"……,\"type\":\"Opaque\"}": illegal base64 data at input byte 12

结果中 hello 和 world 都应该被 *** 替换。但是由于字典无序,所以 mykey1 和 mykey2 的顺序不重要,因此你只需要判断 \"mykey1\":\"***\" 和 \"mykey2\":\"***\" 在结果中存在即可。

  • DevChat 给出的结果

看起来符合预期,直接点击 “Insert Code” 插入代码到 client_test.go 的结尾

  • DevChat 给出的完整 UT 代码如下
package kube

import (
	"strings"
	"testing"
)

func TestDesensitizeLog(t *testing.T) {
	log := `Error: UPGRADE FAILED: cannot patch "mysecret" with kind Secret:  "" is invalid: patch: Invalid value: "{\"apiVersion\":\"v1\",\"data\":{\"mykey1\":\"hello\", \"mykey2\":\"world\"},\"kind\":\"Secret\",\"metadata\"……,\"type\":\"Opaque\"}": illegal base64 data at input byte 12`
	expected1 := `\"mykey1\":\"***\"`
	expected2 := `\"mykey2\":\"***\"`

	result := desensitizeLog(log)

	if !strings.Contains(result, expected1) {
		t.Errorf("Expected %s to contain %s", result, expected1)
	}

	if !strings.Contains(result, expected2) {
		t.Errorf("Expected %s to contain %s", result, expected2)
	}
}
  • 执行 UT,一切顺利

继续让 DevChat 写 Commit Message

  • 先 add 变更

  • 将变更给 DevChat,让它总结

  • 结果是这样的

  • 稍微润色下,加一个 fix 前缀
fix: add log sanitization for Secret kind in updateResource

- Added a new function `desensitizeLog` to sanitize logs by replacing sensitive data in a Secret with "***".
- Modified the `updateResource` function to use `desensitizeLog` when the kind is "Secret".
- Added a test case for the `desensitizeLog` function to ensure it works as expected.
  • 执行 git commit -s

由于 DevChat 目前没有直接支持 sign-of,外加这段信息需要修改,所以这时候不能直接点击 DevChat 消息框里的“Commit”按钮,我们执行 git commit -s 命令,然后将上述消息粘贴进去,最后消息长这样:

fix: add log sanitization for Secret kind in updateResource

- Added a new function `desensitizeLog` to sanitize logs by replacing sensitive data in a Secret with "***".
- Modified the `updateResource` function to use `desensitizeLog` when the kind is "Secret".
- Added a test case for the `desensitizeLog` function to ensure it works as expected.

Signed-off-by: Daniel Hu <[email protected]>

这个 Commit 的完整内容可以在这里看到。

提 PR

代码写完了,下一步自然是提 PR。在这一步你可以选择先用中文表达你想要写在 PR 里的内容,然后让 DevChat 帮你翻译;也可以直接用英文写,然后让 DevChat 帮你“润色”语法,这个过程就不赘述了。这是我的 PR:

关于如何给开源社区提 PR,我在另外一篇文章里有详细介绍:

打完收工

今天的五分钟超了,收工,下班。

拓展阅读

相关资源

标签:kind,log,Helm,Secret,DevChat,GPT,data,Bug
From: https://www.cnblogs.com/daniel-hutao/p/devchat-gpt-in-5min-2-helm-bugfix.html

相关文章

  • 佛祖保佑,永无bug
    fozu(){return["_ooOoo_","o8888888o","88\".\"88","(|-_-|)","O\\=/O",&......
  • 基于GPT,为外贸企业打造触手可及的团队私有知识库
    企业知识库是什么?企业知识库可以将一个组织内部或跨组织的信息和知识进行存储和管理,能够收集、组织、存储和共享企业的知识资产和信息资源。它是一个集中的存储库,包含了组织中的各种知识和信息,包括文档、报告、手册、流程、最佳实践、经验教训、专家意见等。有助于整合企业的资源、......
  • 逼近GPT-4!BLOOMChat: 开源可商用支持多语言的大语言模型
    背景SambaNova和Together这2家公司于2023.05.19开源了可商用的支持多语言的微调模型BLOOMChat。SambaNova这家公司专注于为企业和政府提供生成式AI平台,Together专注于用开源的方式打造一站式的foundationmodel,赋能各个行业。OpenAI的GPT-4和Google的PaLM2对多语言的支持已经做......
  • wsl2 Ubuntu 安装mysql 与chatgpt3.5聊天记录
    要卸载并重新安装MySQL,请按照以下步骤进行操作:1.卸载MySQL:-在WSL2的Ubuntu中,打开终端并运行以下命令以停止MySQL服务器:```sudoservicemysqlstop```-运行以下命令以卸载MySQL服务器:```sudoaptpurgemysql-servermysql-clientmysql-com......
  • CHATGPT获取登录token
    先使用web登录chatgpt再使用web打开http://chat.openai.com/api/auth/session,获取token......
  • 文心一言 VS 讯飞星火 VS chatgpt (55)-- 算法导论6.3 1题
    文心一言VS讯飞星火VSchatgpt(55)--算法导论6.31题一、参照图6-3的方法,说明BUILD-MAX-HEAP在数组A=(5,3,17,10,84,19,6,22,9)上的操作过程。文心一言:下面是BUILD-MAX-HEAP在数组A=(5,3,17,10,84,19,6,22,9)上的操作过程:1.创建一个空堆,将数组中的第一个元素5作......
  • js 异步 任务 题目解析(chatgpt bug了?)
    最近遇到一道题如下,求输出结果感觉还是蛮有意思的,找chatgpt做了一下我是题asyncfunctionasync1(){console.log('1');awaitasync2();console.log('2');}asyncfunctionasync2(){console.log('3');}console.log('4')setTimeout(func......
  • 使用了下chatgpt3.0和chatgpt4.0的区别
    chatgpt4.0的理解能力更强了以下地址即可试用  ......
  • Kubernetes使用Helm部署Gitea仓库
    使用Helm部署Gitea仓库配置Helm源helmrepoaddgiteahttps://dl.gitea.io/chartshelmrepoupdate导出Gitea配置文件values.yamlhelmshowvaluesgitea/gitea>values.yaml#helmshowreadmegitea/gitea>README.md修改values.yamlvimvalues.yaml修改持久化配置......
  • 给 Helm 提一个 PR,重温开源项目参与过程
    目录逛社区领任务复现Bug用GPT-4来准备Bug复现材料对着GPT-4给的命令复现Bug定位Bug修复思路编写代码测试提PR逛社区酒足饭饱,闲来无事,打开Helm项目的issues列表,咦,这个issue看起来眉清目秀呀:其实一点都不“眉清目秀”,这段issue描述太冗长了,没有任何排版,看起......