fix wsl lints

This commit is contained in:
Jörg Thalheim 2024-11-17 19:44:37 +01:00
parent 975c685308
commit 4d5d1b7559
4 changed files with 115 additions and 1 deletions

View file

@ -27,18 +27,23 @@ func SecureSymlinkChown(symlinkToCheck, expectedTarget string, owner, group int)
defer unix.Close(fd)
buf := make([]byte, len(expectedTarget)+1) // oversize by one to detect trunc
n, err := unix.Readlinkat(fd, "", buf)
if err != nil {
return fmt.Errorf("couldn't readlinkat %s", symlinkToCheck)
}
if n > len(expectedTarget) || string(buf[:n]) != expectedTarget {
return fmt.Errorf("symlink %s does not point to %s", symlinkToCheck, expectedTarget)
}
stat := unix.Stat_t{}
err = unix.Fstat(fd, &stat)
if err != nil {
return fmt.Errorf("cannot stat '%s': %w", symlinkToCheck, err)
}
if stat.Uid == uint32(owner) && stat.Gid == uint32(group) {
return nil // already correct
}
@ -62,6 +67,7 @@ func MountSecretFs(mountpoint string, keysGID int, useTmpfs bool, userMode bool)
fstype := "ramfs"
fsmagic := RamfsMagic
if useTmpfs {
fstype = "tmpfs"
fsmagic = TmpfsMagic

View file

@ -120,7 +120,9 @@ func (f *FormatType) UnmarshalJSON(b []byte) error {
if err := json.Unmarshal(b, &s); err != nil {
return err
}
t := FormatType(s)
switch t {
case "":
*f = Yaml
@ -165,12 +167,15 @@ func readManifest(path string) (*manifest, error) {
if err != nil {
return nil, fmt.Errorf("failed to open manifest: %w", err)
}
defer file.Close()
dec := json.NewDecoder(file)
var m manifest
if err := dec.Decode(&m); err != nil {
return nil, fmt.Errorf("failed to parse manifest: %w", err)
}
return &m, nil
}
@ -192,6 +197,7 @@ func createSymlink(targetFile string, path string, owner int, group int, userMod
if err = os.Symlink(targetFile, path); err != nil {
return fmt.Errorf("cannot create symlink '%s': %w", path, err)
}
if !userMode {
if err = SecureSymlinkChown(path, targetFile, owner, group); err != nil {
return fmt.Errorf("cannot chown symlink '%s': %w", path, err)
@ -201,6 +207,7 @@ func createSymlink(targetFile string, path string, owner int, group int, userMod
} else if err != nil {
return fmt.Errorf("cannot stat '%s': %w", path, err)
}
if stat.Mode()&os.ModeSymlink == os.ModeSymlink {
linkTarget, err := os.Readlink(path)
if os.IsNotExist(err) {
@ -211,6 +218,7 @@ func createSymlink(targetFile string, path string, owner int, group int, userMod
return nil
}
}
if err := os.Remove(path); err != nil {
return fmt.Errorf("cannot override %s: %w", path, err)
}
@ -223,10 +231,12 @@ func symlinkSecretsAndTemplates(targetDir string, secrets []secret, templates []
if targetFile == secret.Path {
continue
}
parent := filepath.Dir(secret.Path)
if err := os.MkdirAll(parent, os.ModePerm); err != nil {
return fmt.Errorf("cannot create parent directory of '%s': %w", secret.Path, err)
}
if err := createSymlink(targetFile, secret.Path, secret.owner, secret.group, userMode); err != nil {
return fmt.Errorf("failed to symlink secret '%s': %w", secret.Path, err)
}
@ -237,10 +247,12 @@ func symlinkSecretsAndTemplates(targetDir string, secrets []secret, templates []
if targetFile == template.Path {
continue
}
parent := filepath.Dir(template.Path)
if err := os.MkdirAll(parent, os.ModePerm); err != nil {
return fmt.Errorf("cannot create parent directory of '%s': %w", template.Path, err)
}
if err := createSymlink(targetFile, template.Path, template.owner, template.group, userMode); err != nil {
return fmt.Errorf("failed to symlink template '%s': %w", template.Path, err)
}
@ -256,7 +268,9 @@ type plainData struct {
func recurseSecretKey(keys map[string]interface{}, wantedKey string) (string, error) {
var val interface{}
var ok bool
currentKey := wantedKey
currentData := keys
keyUntilNow := ""
@ -274,23 +288,31 @@ func recurseSecretKey(keys map[string]interface{}, wantedKey string) (string, er
}
break
}
thisKey := currentKey[:slashIndex]
if keyUntilNow == "" {
keyUntilNow = thisKey
} else {
keyUntilNow += "/" + thisKey
}
currentKey = currentKey[(slashIndex + 1):]
val, ok = currentData[thisKey]
if !ok {
return "", fmt.Errorf("the key '%s' cannot be found", keyUntilNow)
}
var valWithWrongType map[interface{}]interface{}
valWithWrongType, ok = val.(map[interface{}]interface{})
if !ok {
return "", fmt.Errorf("key '%s' does not refer to a dictionary", keyUntilNow)
}
currentData = make(map[string]interface{})
for key, value := range valWithWrongType {
currentData[key.(string)] = value
}
@ -334,6 +356,7 @@ func decryptSecret(s *secret, sourceFiles map[string]plainData) error {
return fmt.Errorf("secret of type %s in %s is not supported", s.Format, s.SopsFile)
}
}
switch s.Format {
case Binary, Dotenv, Ini:
s.value = sourceFile.binary
@ -345,9 +368,11 @@ func decryptSecret(s *secret, sourceFiles map[string]plainData) error {
if err != nil {
return fmt.Errorf("secret %s in %s is not valid: %w", s.Name, s.SopsFile, err)
}
s.value = []byte(strVal)
}
}
sourceFiles[s.SopsFile] = sourceFile
return nil
}
@ -369,10 +394,12 @@ const (
func prepareSecretsDir(secretMountpoint string, linkName string, keysGID int, userMode bool) (*string, error) {
var generation uint64
linkTarget, err := os.Readlink(linkName)
if err == nil {
if strings.HasPrefix(linkTarget, secretMountpoint) {
targetBasename := filepath.Base(linkTarget)
generation, err = strconv.ParseUint(targetBasename, 10, 64)
if err != nil {
return nil, fmt.Errorf("cannot parse %s of %s as a number: %w", targetBasename, linkTarget, err)
@ -381,16 +408,20 @@ func prepareSecretsDir(secretMountpoint string, linkName string, keysGID int, us
} else if !os.IsNotExist(err) {
return nil, fmt.Errorf("cannot access %s: %w", linkName, err)
}
generation++
dir := filepath.Join(secretMountpoint, strconv.Itoa(int(generation)))
if _, err := os.Stat(dir); !os.IsNotExist(err) {
if err := os.RemoveAll(dir); err != nil {
return nil, fmt.Errorf("cannot remove existing %s: %w", dir, err)
}
}
if err := os.Mkdir(dir, os.FileMode(0o751)); err != nil {
return nil, fmt.Errorf("mkdir(): %w", err)
}
if !userMode {
if err := os.Chown(dir, 0, int(keysGID)); err != nil {
return nil, fmt.Errorf("cannot change owner/group of '%s' to 0/%d: %w", dir, keysGID, err)
@ -402,11 +433,13 @@ func prepareSecretsDir(secretMountpoint string, linkName string, keysGID int, us
func createParentDirs(parent string, target string, keysGID int, userMode bool) error {
dirs := strings.Split(filepath.Dir(target), "/")
pathSoFar := parent
for _, dir := range dirs {
pathSoFar = filepath.Join(pathSoFar, dir)
if err := os.MkdirAll(pathSoFar, 0o751); err != nil {
return fmt.Errorf("cannot create directory '%s' for %s: %w", pathSoFar, filepath.Join(parent, target), err)
}
if !userMode {
if err := os.Chown(pathSoFar, 0, int(keysGID)); err != nil {
return fmt.Errorf("cannot own directory '%s' for %s: %w", pathSoFar, filepath.Join(parent, target), err)
@ -423,9 +456,11 @@ func writeSecrets(secretDir string, secrets []secret, keysGID int, userMode bool
if err := createParentDirs(secretDir, secret.Name, keysGID, userMode); err != nil {
return err
}
if err := os.WriteFile(fp, []byte(secret.value), secret.mode); err != nil {
return fmt.Errorf("cannot write %s: %w", fp, err)
}
if !userMode {
if err := os.Chown(fp, secret.owner, secret.group); err != nil {
return fmt.Errorf("cannot change owner/group of '%s' to %d/%d: %w", fp, secret.owner, secret.group, err)
@ -440,6 +475,7 @@ func lookupGroup(groupname string) (int, error) {
if err != nil {
return 0, fmt.Errorf("failed to lookup 'keys' group: %w", err)
}
gid, err := strconv.ParseInt(group.Gid, 10, 64)
if err != nil {
return 0, fmt.Errorf("cannot parse keys gid %s: %w", group.Gid, err)
@ -452,6 +488,7 @@ func lookupKeysGroup() (int, error) {
if err1 == nil {
return gid, nil
}
gid, err2 := lookupGroup("nogroup")
if err2 == nil {
return gid, nil
@ -486,7 +523,9 @@ func (app *appContext) loadSopsFile(s *secret) (*secretFile, error) {
if err != nil {
return nil, fmt.Errorf("cannot parse dotenv of '%s': %w", s.SopsFile, err)
}
keys = map[string]interface{}{}
for k, v := range env {
keys[k] = v
}
@ -495,11 +534,11 @@ func (app *appContext) loadSopsFile(s *secret) (*secretFile, error) {
return nil, fmt.Errorf("cannot parse json of '%s': %w", s.SopsFile, err)
}
case Ini:
// TODO: we do not actually check the contents of the ini here...
_, err := ini.Load(bytes.NewReader(cipherText))
if err != nil {
return nil, fmt.Errorf("cannot parse ini of '%s': %w", s.SopsFile, err)
}
// TODO: we do not actually check the contents of the ini here...
}
return &secretFile{
@ -515,6 +554,7 @@ func (app *appContext) validateSopsFile(s *secret, file *secretFile) error {
s.Name, s.SopsFile, s.Format,
file.firstSecret.Format, file.firstSecret.Name)
}
if app.checkMode != Manifest && !(s.Format == Binary || s.Format == Dotenv || s.Format == Ini) && s.Key != "" {
_, err := recurseSecretKey(file.keys, s.Key)
if err != nil {
@ -537,6 +577,7 @@ func validateOwner(owner string) (int, error) {
if err != nil {
return 0, fmt.Errorf("failed to lookup user '%s': %w", owner, err)
}
ownerNr, err := strconv.ParseUint(lookedUp.Uid, 10, 64)
if err != nil {
return 0, fmt.Errorf("cannot parse uid %s: %w", lookedUp.Uid, err)
@ -549,6 +590,7 @@ func validateGroup(group string) (int, error) {
if err != nil {
return 0, fmt.Errorf("failed to lookup group '%s': %w", group, err)
}
groupNr, err := strconv.ParseUint(lookedUp.Gid, 10, 64)
if err != nil {
return 0, fmt.Errorf("cannot parse gid %s: %w", lookedUp.Gid, err)
@ -561,6 +603,7 @@ func (app *appContext) validateSecret(secret *secret) error {
if err != nil {
return err
}
secret.mode = mode
if app.ignorePasswd || os.Getenv("NIXOS_ACTION") == "dry-activate" {
@ -574,6 +617,7 @@ func (app *appContext) validateSecret(secret *secret) error {
if err != nil {
return err
}
secret.owner = owner
}
@ -584,6 +628,7 @@ func (app *appContext) validateSecret(secret *secret) error {
if err != nil {
return err
}
secret.group = group
}
}
@ -602,6 +647,7 @@ func (app *appContext) validateSecret(secret *secret) error {
if err != nil {
return err
}
app.secretFiles[secret.SopsFile] = *maybeFile
file = *maybeFile
@ -631,6 +677,7 @@ func (app *appContext) validateTemplate(template *template) error {
if err != nil {
return err
}
template.mode = mode
if app.ignorePasswd || os.Getenv("NIXOS_ACTION") == "dry-activate" {
@ -644,6 +691,7 @@ func (app *appContext) validateTemplate(template *template) error {
if err != nil {
return err
}
template.owner = owner
}
@ -654,11 +702,13 @@ func (app *appContext) validateTemplate(template *template) error {
if err != nil {
return err
}
template.group = group
}
}
var templateText string
if template.Content != "" {
templateText = template.Content
} else if template.File != "" {
@ -666,6 +716,7 @@ func (app *appContext) validateTemplate(template *template) error {
if err != nil {
return fmt.Errorf("cannot read %s: %w", template.File, err)
}
templateText = string(templateBytes)
} else {
return fmt.Errorf("neither content nor file was specified for template %s", template.Name)
@ -684,6 +735,7 @@ func (app *appContext) validateManifest() error {
if len(m.SSHKeyPaths) > 0 {
return fmt.Errorf(errorFmt, "sshKeyPaths")
}
if m.AgeKeyFile != "" {
return fmt.Errorf(errorFmt, "ageKeyFile")
}
@ -729,7 +781,9 @@ func atomicSymlink(oldname, newname string) error {
if err != nil {
return err
}
cleanup := true
defer func() {
if cleanup {
os.RemoveAll(d)
@ -771,6 +825,7 @@ func pruneGenerations(secretsMountPoint, secretsDir string, keepGenerations int)
if err != nil {
return fmt.Errorf("cannot read %s: %w", secretsMountPoint, err)
}
for _, generationName := range generations {
generationNum, err := strconv.Atoi(generationName)
// Not a number? Not relevant
@ -782,6 +837,7 @@ func pruneGenerations(secretsMountPoint, secretsDir string, keepGenerations int)
if generationNum == currentGeneration {
continue
}
if currentGeneration-keepGenerations >= generationNum {
os.RemoveAll(path.Join(secretsMountPoint, generationName))
}
@ -812,6 +868,7 @@ func importSSHKeys(logcfg loggingConfig, keyPaths []string, gpgHome string) erro
fmt.Fprintf(os.Stderr, "Cannot read ssh key '%s': %s\n", p, err)
continue
}
gpgKey, err := sshkeys.SSHPrivateKeyToPGP(sshKey)
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
@ -881,10 +938,12 @@ func symlinkWalk(filename string, linkDirname string, walkFn filepath.WalkFunc)
if err != nil {
return err
}
info, err := os.Lstat(finalPath)
if err != nil {
return walkFn(path, info, err)
}
if info.IsDir() {
return symlinkWalk(finalPath, path, walkFn)
}
@ -897,6 +956,7 @@ func symlinkWalk(filename string, linkDirname string, walkFn filepath.WalkFunc)
func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, secretDir string, secrets []secret, templates []template) error {
var restart []string
var reload []string
newSecrets := make(map[string]bool)
@ -989,7 +1049,9 @@ func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, s
if err != nil {
return err
}
defer f.Close()
for _, unit := range list {
if _, err = f.WriteString(unit + "\n"); err != nil {
return err
@ -998,15 +1060,18 @@ func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, s
}
return nil
}
var dryPrefix string
if isDry {
dryPrefix = "/run/nixos/dry-activation"
} else {
dryPrefix = "/run/nixos/activation"
}
if err := writeLines(restart, dryPrefix+"-restart-list"); err != nil {
return err
}
if err := writeLines(reload, dryPrefix+"-reload-list"); err != nil {
return err
}
@ -1018,10 +1083,12 @@ func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, s
// Find removed secrets/templates.
symlinkRenderedPath := filepath.Join(symlinkPath, RenderedSubdir)
err := symlinkWalk(symlinkPath, symlinkPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
@ -1032,6 +1099,7 @@ func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, s
if err != nil {
return err
}
isSecret := strings.HasPrefix(rel, "..")
if isSecret {
@ -1041,6 +1109,7 @@ func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, s
return nil
}
}
removedSecrets[path] = true
} else {
path = strings.TrimPrefix(path, symlinkRenderedPath+string(os.PathSeparator))
@ -1049,6 +1118,7 @@ func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, s
return nil
}
}
removedTemplates[path] = true
}
return nil
@ -1064,6 +1134,7 @@ func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, s
if len(changed) != 1 {
s = "s"
}
if isDry {
fmt.Printf("%s %s%s: ", dryPrefix, noun, s)
} else {
@ -1075,6 +1146,7 @@ func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, s
for key := range changed {
keys = append(keys, key)
}
sort.Strings(keys)
fmt.Println(strings.Join(keys, ", "))
@ -1104,12 +1176,14 @@ func setupGPGKeyring(logcfg loggingConfig, sshKeys []string, parentDir string) (
if err != nil {
return nil, fmt.Errorf("cannot create gpg home in '%s': %w", parentDir, err)
}
k := keyring{dir}
if err := importSSHKeys(logcfg, sshKeys, dir); err != nil {
os.RemoveAll(dir)
return nil, err
}
os.Setenv("GNUPGHOME", dir)
return &k, nil
@ -1117,14 +1191,17 @@ func setupGPGKeyring(logcfg loggingConfig, sshKeys []string, parentDir string) (
func parseFlags(args []string) (*options, error) {
var opts options
fs := flag.NewFlagSet(args[0], flag.ContinueOnError)
fs.Usage = func() {
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [OPTION] manifest.json\n", args[0])
fs.PrintDefaults()
}
var checkMode string
fs.StringVar(&checkMode, "check-mode", "off", `Validate configuration without installing it (possible values: "manifest","sopsfile","off")`)
fs.BoolVar(&opts.ignorePasswd, "ignore-passwd", false, `Don't look up anything in /etc/passwd. Causes everything to be owned by root:root or the user executing the tool in user mode`)
if err := fs.Parse(args[1:]); err != nil {
return nil, err
}
@ -1140,6 +1217,7 @@ func parseFlags(args []string) (*options, error) {
flag.Usage()
return nil, flag.ErrHelp
}
opts.manifest = fs.Arg(0)
return &opts, nil
}
@ -1147,10 +1225,12 @@ func parseFlags(args []string) (*options, error) {
func replaceRuntimeDir(path, rundir string) (ret string) {
parts := strings.Split(path, "%%")
first := true
for _, part := range parts {
if !first {
ret += "%"
}
first = false
ret += strings.ReplaceAll(part, "%r", rundir)
}
@ -1168,6 +1248,7 @@ func writeTemplates(targetDir string, templates []template, keysGID int, userMod
if err := os.WriteFile(fp, []byte(template.value), template.mode); err != nil {
return fmt.Errorf("cannot write %s: %w", fp, err)
}
if !userMode {
if err := os.Chown(fp, template.owner, template.group); err != nil {
return fmt.Errorf("cannot change owner/group of '%s' to %d/%d: %w", fp, template.owner, template.group, err)
@ -1191,16 +1272,21 @@ func installSecrets(args []string) error {
if manifest.UserMode {
var rundir string
rundir, err = RuntimeDir()
if opts.checkMode == Off && err != nil {
return fmt.Errorf("cannot figure out runtime directory: %w", err)
}
manifest.SecretsMountPoint = replaceRuntimeDir(manifest.SecretsMountPoint, rundir)
manifest.SymlinkPath = replaceRuntimeDir(manifest.SymlinkPath, rundir)
var newSecrets []secret
for _, secret := range manifest.Secrets {
secret.Path = replaceRuntimeDir(secret.Path, rundir)
newSecrets = append(newSecrets, secret)
}
manifest.Secrets = newSecrets
}
@ -1238,10 +1324,12 @@ func installSecrets(args []string) error {
if len(manifest.SSHKeyPaths) != 0 {
var keyring *keyring
keyring, err = setupGPGKeyring(manifest.Logging, manifest.SSHKeyPaths, manifest.SecretsMountPoint)
if err != nil {
return fmt.Errorf("error setting up gpg keyring: %w", err)
}
defer keyring.Remove()
} else if manifest.GnupgHome != "" {
os.Setenv("GNUPGHOME", manifest.GnupgHome)
@ -1253,11 +1341,14 @@ func installSecrets(args []string) error {
os.Setenv("SOPS_AGE_KEY_FILE", keyfile)
// Create the keyfile
var ageFile *os.File
ageFile, err = os.OpenFile(keyfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return fmt.Errorf("cannot create '%s': %w", keyfile, err)
}
defer ageFile.Close()
fmt.Fprintf(ageFile, "# generated by sops-nix at %s\n", time.Now().Format(time.RFC3339))
// Import SSH keys
@ -1271,10 +1362,12 @@ func installSecrets(args []string) error {
if manifest.AgeKeyFile != "" {
// Read the keyfile
var contents []byte
contents, err = os.ReadFile(manifest.AgeKeyFile)
if err != nil {
return fmt.Errorf("cannot read keyfile '%s': %w", manifest.AgeKeyFile, err)
}
// Append it to the file
_, err = ageFile.WriteString(string(contents) + "\n")
if err != nil {
@ -1294,6 +1387,7 @@ func installSecrets(args []string) error {
if err != nil {
return fmt.Errorf("failed to prepare new secrets directory: %w", err)
}
if err := writeSecrets(*secretDir, manifest.Secrets, keysGID, manifest.UserMode); err != nil {
return fmt.Errorf("cannot write secrets: %w", err)
}
@ -1314,9 +1408,11 @@ func installSecrets(args []string) error {
if err := symlinkSecretsAndTemplates(manifest.SymlinkPath, manifest.Secrets, manifest.Templates, manifest.UserMode); err != nil {
return fmt.Errorf("failed to prepare symlinks to secret store: %w", err)
}
if err := atomicSymlink(*secretDir, manifest.SymlinkPath); err != nil {
return fmt.Errorf("cannot update secrets symlink: %w", err)
}
if err := pruneGenerations(manifest.SecretsMountPoint, *secretDir, manifest.KeepGenerations); err != nil {
return fmt.Errorf("cannot prune old secrets generations: %w", err)
}
@ -1329,6 +1425,7 @@ func main() {
if errors.Is(err, flag.ErrHelp) {
return
}
fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], err)
os.Exit(1)
}

View file

@ -21,6 +21,7 @@ import (
// ok fails the test if an err is not nil.
func ok(tb testing.TB, err error) {
tb.Helper()
if err != nil {
fmt.Printf("\033[31munexpected error: %s\033[39m\n\n", err.Error())
tb.FailNow()
@ -29,6 +30,7 @@ func ok(tb testing.TB, err error) {
func equals(tb testing.TB, exp, act interface{}) {
tb.Helper()
if !reflect.DeepEqual(exp, act) {
fmt.Printf("\033[31m\texp: %#v\n\n\tgot: %#v\033[39m\n\n", exp, act)
tb.FailNow()
@ -41,6 +43,7 @@ func writeManifest(t *testing.T, dir string, m *manifest) string {
filename := path.Join(dir, "manifest.json")
f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0o755)
ok(t, err)
encoder := json.NewEncoder(f)
ok(t, encoder.Encode(m))
f.Close()
@ -66,6 +69,7 @@ func (dir testDir) Remove() {
func newTestDir(t *testing.T) testDir {
t.Helper()
tempdir, err := os.MkdirTemp("", "symlinkDir")
ok(t, err)
return testDir{tempdir, path.Join(tempdir, "secrets.d"), path.Join(tempdir, "secrets")}
@ -88,15 +92,18 @@ func TestGPG(t *testing.T) { //nolint:paralleltest
gpgEnv := append(os.Environ(), fmt.Sprintf("GNUPGHOME=%s", gpgHome))
ok(t, os.Mkdir(gpgHome, os.FileMode(0o700)))
cmd := exec.Command("gpg", "--import", path.Join(assets, "key.asc")) // nolint:gosec
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Env = gpgEnv
ok(t, cmd.Run())
stopGpgCmd := exec.Command("gpgconf", "--kill", "gpg-agent")
stopGpgCmd.Stdout = os.Stdout
stopGpgCmd.Stderr = os.Stderr
stopGpgCmd.Env = gpgEnv
defer func() {
if err := stopGpgCmd.Run(); err != nil {
fmt.Printf("failed to stop gpg-agent: %s\n", err)
@ -119,6 +126,7 @@ func TestGPG(t *testing.T) { //nolint:paralleltest
}
var jsonSecret, binarySecret, dotenvSecret, iniSecret secret
root := "root"
// should not create a symlink
jsonSecret = yamlSecret
@ -179,6 +187,7 @@ func TestGPG(t *testing.T) { //nolint:paralleltest
equals(t, 0o400, int(yamlStat.Mode().Perm()))
stat, success := yamlStat.Sys().(*syscall.Stat_t)
equals(t, true, success)
content, err := os.ReadFile(yamlSecret.Path)
ok(t, err)
equals(t, "test_value", string(content))
@ -195,6 +204,7 @@ func TestGPG(t *testing.T) { //nolint:paralleltest
ok(t, err)
equals(t, true, jsonStat.Mode().IsRegular())
equals(t, 0o700, int(jsonStat.Mode().Perm()))
if stat, ok := jsonStat.Sys().(*syscall.Stat_t); ok {
equals(t, 0, int(stat.Uid))
equals(t, 0, int(stat.Gid))

View file

@ -60,6 +60,7 @@ func SSHPrivateKeyToPGP(sshPrivateKey []byte) (*openpgp.Entity, error) {
IssuerKeyId: &gpgKey.PrimaryKey.KeyId,
},
}
err = gpgKey.Identities[uid.Id].SelfSignature.SignUserId(uid.Id, gpgKey.PrimaryKey, gpgKey.PrivateKey, nil)
if err != nil {
return nil, err