{"record":{"id":"ed8523addf54e1ed","repo":"getsops/sops","slug":"gnupghome-must-be-an-absolute-path","errorCode":null,"errorMessage":"GNUPGHOME must be an absolute path","messagePattern":"GNUPGHOME must be an absolute path","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pgp/keysource.go","lineNumber":196,"sourceCode":"\n// Cleanup deletes the GnuPGHome if it passes Validate.\n// It returns an error if the GnuPGHome does not pass Validate, or if the\n// removal failed.\nfunc (d GnuPGHome) Cleanup() error {\n\tif err := d.Validate(); err != nil {\n\t\treturn err\n\t}\n\treturn os.RemoveAll(d.String())\n}\n\n// Validate ensures the GnuPGHome is a valid GnuPG home directory path.\n// When validation fails, it returns a descriptive reason as error.\nfunc (d GnuPGHome) Validate() error {\n\tif d == \"\" {\n\t\treturn fmt.Errorf(\"empty GNUPGHOME path\")\n\t}\n\tif !filepath.IsAbs(d.String()) {\n\t\treturn fmt.Errorf(\"GNUPGHOME must be an absolute path\")\n\t}\n\tfi, err := os.Lstat(d.String())\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn fmt.Errorf(\"GNUPGHOME does not exist\")\n\t\t}\n\t\treturn fmt.Errorf(\"cannot stat GNUPGHOME: %w\", err)\n\t}\n\tif !fi.IsDir() {\n\t\treturn fmt.Errorf(\"GNUGPHOME is not a directory\")\n\t}\n\tif perm := fi.Mode().Perm(); perm != 0o700 {\n\t\treturn fmt.Errorf(\"GNUPGHOME has invalid permissions: got %#o wanted %#o\", perm, 0o700)\n\t}\n\treturn nil\n}\n\n// String returns the GnuPGHome as a string. It does not Validate.","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/pgp/keysource.go#L178-L214","documentation":"GnuPGHome.Validate requires an absolute path because gpg's GNUPGHOME must be absolute to be unambiguous. If the value is non-empty but relative (e.g. \"tmp/gnupg\"), validation fails with this message. The home is never used for gpg operations in this state.","triggerScenarios":"Setting GnuPGHome from a user-supplied relative path or a config value without filepath.Abs, then calling Import, ImportContext, Cleanup, or ApplyToMasterKey.","commonSituations":"Passing a CLI/config argument like './gnupg-home' or 'gnupg' directly into GnuPGHome; composing paths without filepath.Abs in scripts or tests.","solutions":["Convert to an absolute path with filepath.Abs before assigning to GnuPGHome.","Or use pgp.NewGnuPGHome() which always creates an absolute temp directory.","If the path comes from configuration, validate/normalize it at config-load time."],"exampleFix":"// before\nhome := pgp.GnuPGHome(\"gnupg-home\")\n// after\nabs, err := filepath.Abs(\"gnupg-home\")\nif err != nil { return err }\nhome := pgp.GnuPGHome(abs)","handlingStrategy":"validation","validationCode":"// Go\nfunc absHome(p string) (pgp.GnuPGHome, error) {\n  abs, err := filepath.Abs(p)\n  if err != nil { return \"\", err }\n  return pgp.GnuPGHome(abs), nil\n}","typeGuard":"func absoluteHome(home pgp.GnuPGHome) bool { return filepath.IsAbs(home.String()) }","tryCatchPattern":"// Go\nif err := home.Validate(); err != nil && strings.Contains(err.Error(), \"must be an absolute path\") {\n  return fmt.Errorf(\"normalize GNUPGHOME with filepath.Abs before use: %w\", err)\n}","preventionTips":["Normalize any user/config-supplied path with filepath.Abs at load time","Prefer NewGnuPGHome() which always yields an absolute temp path","Add a config validator that rejects relative GNUPGHOME values"],"tags":["gnupg","pgp","validation","path"],"backgroundTag":"relative-path-not-allowed","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}