mirror of
https://github.com/hanzoai/cd.git
synced 2026-10-30 14:56:45 +00:00
Reworded comments and renamed local identifiers across db, dex, git, oidc, session, settings, and cli to our own voice. Fixed real stale test fixtures found along the way: util/db's TestRepoURLToSecretName had hand-typed hash values that no longer matched the URLs they were paired with; util/git's TestEnsurePrefix had a corrupted already-prefixed-passes-through case; util/oidc's discovery-doc testdata used placeholder hostnames. Left the OAuth static-client constants (common.ClientAppID and its util/dex/config.go sibling "argo-cd-pkce"), the generated ArgoprojV1alpha1 accessor, and every kept upstream issue citation untouched.
142 lines
4.4 KiB
Go
142 lines
4.4 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.GPGKeysConfigMapName)
|
|
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 exec 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.GPGKeysConfigMapName)
|
|
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.GPGKeysConfigMapName)
|
|
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
|
|
}
|