Files
knowledge-governance/internal/qaopsai/secrets.go
T
姚章浩 533db535f1
build / build (push) Successful in 1m12s
feat(qaops): 接入真实模型补缺任务与总表看板
按已确认需求提供独立安全模型配置、真实探测、正式字典字段评估与原问题译中,持久批次支持只补空白、暂停恢复、有限重试、幂等和逐字段依据。覆盖固定规则、本地语言、组织关联与主表有效看板共用治理侧读模型,保留源生产和冻结历史。

验证:完整 make verify 退出0,702项Go与329项前端通过;默认118项外部/隔离集成明确跳过,另跑完整镜像及组织隔离PG竞态。12并发、输入漂移、过期租约、暂停/恢复及有限重试通过。用户授权的百炼 deepseek-v4.1-flash 完成真实后台与浏览器评估/翻译;552行、16列、11块看板及完整PNG、独立配置页测试/保存、重开恢复和零JS异常通过。仅非业务样本外发,自动处理关闭,原payload不变。

上线前治理库已做导出快照原生备份并真实恢复,60表行数与17个QA表内容哈希一致;不修改DobotAI生产或隧道。本提交时尚未部署,线上验收须独立完成。
2026-10-19 14:29:49 +08:00

56 lines
1.5 KiB
Go

package qaopsai
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"os"
)
// The independently provisioned master key never lives in source, settings JSON or database backups.
func (s *Store) masterKey() ([]byte, error) {
info, err := os.Lstat(s.options.KeyFile)
if err != nil || !info.Mode().IsRegular() || info.Mode().Perm() != 0600 {
return nil, ErrUnavailable
}
raw, err := os.ReadFile(s.options.KeyFile)
if err != nil || len(raw) != 32 {
return nil, ErrUnavailable
}
return raw, nil
}
func (s *Store) aead() (cipher.AEAD, error) {
key, err := s.masterKey()
if err != nil {
return nil, err
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, ErrUnavailable
}
return cipher.NewGCM(block)
}
func (s *Store) seal(secret string, revision int64) ([]byte, error) {
aead, err := s.aead()
if err != nil {
return nil, err
}
nonce := make([]byte, aead.NonceSize())
if _, err = rand.Read(nonce); err != nil {
return nil, ErrUnavailable
}
return aead.Seal(nonce, nonce, []byte(secret), []byte(fmt.Sprintf("qa-ai:%s:%d", s.tenant, revision))), nil
}
func (s *Store) unseal(sealed []byte, revision int64) (string, error) {
aead, err := s.aead()
if err != nil || len(sealed) < aead.NonceSize() {
return "", ErrUnavailable
}
raw, err := aead.Open(nil, sealed[:aead.NonceSize()], sealed[aead.NonceSize():], []byte(fmt.Sprintf("qa-ai:%s:%d", s.tenant, revision)))
if err != nil {
return "", ErrUnavailable
}
return string(raw), nil
}