Files
deploy/util/db/gpgkeys.go
zeekayandHanzo Dev 1ab6e799c1 cd: the module is github.com/hanzoai/cd, where it is actually hosted
go.mod still declared `module github.com/hanzoai/deploy` after the repo was
renamed. A Go module path is not cosmetic — it is the resolvable location. So
`go get github.com/hanzoai/cd` could not work, and anything importing this
module had to spell a name that no longer exists at that address. The build log
of v3.6.0 is where it surfaced: the compiler was still emitting
github.com/hanzoai/deploy/cmd/cd/commands.

3541 import paths across 690 .go, 19 .proto, 4 .yaml, 3 .sh, 2 .mod, Procfile
and Makefile. Plus the 62 ghcr.io/hanzoai/deploy image references, moved to
ghcr.io/hanzoai/cd to match hanzo.yml's build target — a distinct string from
the module path, replaced separately so neither could clobber the other.

go mod tidy clean, CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./... clean.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-28 21:16:24 -07:00

142 lines
4.5 KiB
Go

package db
import (
"context"
"errors"
"fmt"
"os"
log "github.com/sirupsen/logrus"
"github.com/hanzoai/cd/common"
appsv1 "github.com/hanzoai/cd/pkg/apis/application/v1alpha1"
"github.com/hanzoai/cd/util/sourceintegrity"
)
// Validates a single GnuPG key and returns the key's ID
func validatePGPKey(keyData string) (*appsv1.GnuPGPublicKey, error) {
f, err := os.CreateTemp("", "gpg-public-key")
if err != nil {
return nil, fmt.Errorf("error creating temp file for GPG key: %w", err)
}
defer os.Remove(f.Name())
err = os.WriteFile(f.Name(), []byte(keyData), 0o600)
if err != nil {
return nil, fmt.Errorf("error writing GPG key to temp file: %w", err)
}
defer func() {
err = f.Close()
if err != nil {
log.Errorf("error closing file %q: %v", f.Name(), err)
}
}()
parsed, err := sourceintegrity.ValidatePGPKeys(f.Name())
if err != nil {
return nil, fmt.Errorf("error validating PGP key: %w", err)
}
// Each key/value pair in the config map must exactly contain one public key, with the (short) GPG key ID as key
if len(parsed) != 1 {
return nil, errors.New("more than one key found in input data")
}
var retKey *appsv1.GnuPGPublicKey
// Is there a better way to get the first element from a map without knowing its key?
for _, k := range parsed {
retKey = k
break
}
if retKey != nil {
retKey.KeyData = keyData
return retKey, nil
}
return nil, errors.New("could not find the GPG key")
}
// ListConfiguredGPGPublicKeys returns a list of all configured GPG public keys from the ConfigMap
func (db *db) ListConfiguredGPGPublicKeys(_ context.Context) (map[string]*appsv1.GnuPGPublicKey, error) {
log.Debugf("Loading PGP public keys from config map")
result := make(map[string]*appsv1.GnuPGPublicKey)
keysCM, err := db.settingsMgr.GetConfigMapByName(common.ArgoCDGPGKeysConfigMapName)
if err != nil {
return nil, fmt.Errorf("error getting GPG keys configmap: %w", err)
}
// We have to verify all PGP keys in the ConfigMap to be valid keys before. To do so,
// we write each single one out to a temporary file and validate them through gpg.
// This is not optimal, but the executil from argo-pkg does not support writing to
// stdin of the forked process. So for now, we must live with that.
for k, p := range keysCM.Data {
expectedKeyID, err := sourceintegrity.KeyID(k)
if err != nil {
return nil, fmt.Errorf("error validating key ID %q in GPG keys configmap: %w", k, err)
}
parsedKey, err := validatePGPKey(p)
if err != nil {
return nil, fmt.Errorf("error parsing GPG key for entry %q: %w", expectedKeyID, err)
}
if expectedKeyID != parsedKey.KeyID {
return nil, fmt.Errorf("key parsed for entry with key ID '%s' had different key ID '%s'", expectedKeyID, parsedKey.KeyID)
}
result[parsedKey.KeyID] = parsedKey
}
return result, nil
}
// AddGPGPublicKey adds one or more public keys to the configuration
func (db *db) AddGPGPublicKey(ctx context.Context, keyData string) (map[string]*appsv1.GnuPGPublicKey, []string, error) {
result := make(map[string]*appsv1.GnuPGPublicKey)
skipped := make([]string, 0)
keys, err := sourceintegrity.ValidatePGPKeysFromString(keyData)
if err != nil {
return nil, nil, fmt.Errorf("error validating PGP keys from input: %w", err)
}
keysCM, err := db.settingsMgr.GetConfigMapByName(common.ArgoCDGPGKeysConfigMapName)
if err != nil {
return nil, nil, fmt.Errorf("error getting GPG keys configmap: %w", err)
}
for kid, key := range keys {
if _, ok := keysCM.Data[kid]; ok {
skipped = append(skipped, kid)
log.Debugf("Not adding incoming key with kid=%s because it is configured already", kid)
} else {
result[kid] = key
keysCM.Data[kid] = key.KeyData
log.Debugf("Adding incoming key with kid=%s to database", kid)
}
}
err = db.settingsMgr.SaveGPGPublicKeyData(ctx, keysCM.Data)
if err != nil {
return nil, nil, fmt.Errorf("error saving GPG public key data: %w", err)
}
return result, skipped, nil
}
// DeleteGPGPublicKey deletes a GPG public key from the configuration
func (db *db) DeleteGPGPublicKey(ctx context.Context, keyID string) error {
keysCM, err := db.settingsMgr.GetConfigMapByName(common.ArgoCDGPGKeysConfigMapName)
if err != nil {
return fmt.Errorf("error getting GPG keys configmap: %w", err)
}
if _, ok := keysCM.Data[keyID]; !ok {
return fmt.Errorf("no such key configured: %s", keyID)
}
delete(keysCM.Data, keyID)
err = db.settingsMgr.SaveGPGPublicKeyData(ctx, keysCM.Data)
if err != nil {
return fmt.Errorf("error saving GPG public key data: %w", err)
}
return nil
}