{"record":{"id":"f5c6d752cc1ec64f","repo":"JuliusBrussee/caveman","slug":"githubapp-private-key-pem-is-required","errorCode":null,"errorMessage":"githubapp: private key PEM is required","messagePattern":"githubapp: private key PEM is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/githubapp/githubapp.go","lineNumber":72,"sourceCode":"type App struct {\n\tappID         string\n\tslug          string\n\tprivateKey    *rsa.PrivateKey\n\twebhookSecret string\n\tbaseURL       string\n\thttpClient    *http.Client\n}\n\n// New parses the private key, validates the base URL, and builds the App. It\n// returns an error (not a half-built App) on any misconfiguration, so callers\n// fail closed — an unconfigured deployment leaves the App nil and the connect\n// endpoints answer a clean \"disabled\" rather than a fabricated success.\nfunc New(cfg Config) (*App, error) {\n\tif strings.TrimSpace(cfg.AppID) == \"\" {\n\t\treturn nil, fmt.Errorf(\"githubapp: app id is required\")\n\t}\n\tif len(cfg.PrivateKeyPEM) == 0 {\n\t\treturn nil, fmt.Errorf(\"githubapp: private key PEM is required\")\n\t}\n\tkey, err := parseRSAPrivateKey(cfg.PrivateKeyPEM)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbase := strings.TrimRight(strings.TrimSpace(cfg.BaseURL), \"/\")\n\tif base == \"\" {\n\t\tbase = defaultBaseURL\n\t}\n\tclient := cfg.HTTPClient\n\tif client == nil {\n\t\t// Production path: SSRF-guarded client + pre-flight host check on a custom\n\t\t// (GHE) base. When a caller injects a client (tests), it owns the host policy,\n\t\t// so we skip the pre-flight — but production never injects one.\n\t\tif base != defaultBaseURL {\n\t\t\tif err := ssrf.ValidateURL(context.Background(), base, ssrf.ManagedConfig()); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"githubapp: base_url rejected by SSRF guard: %w\", err)\n\t\t\t}","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/shared/platform/githubapp/githubapp.go#L54-L90","documentation":"Configuration guard in githubapp.New: the app's private key PEM is empty, so installation tokens cannot be signed and the App fails closed as unconfigured. The GITHUB_APP private key configuration is at fault.","triggerScenarios":"Thrown at shared/platform/githubapp/githubapp.go:72 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Supply the GitHub App private key PEM in Config (downloaded from the App settings page)","Verify the secret mount/env injection actually delivered the key contents, not an empty value"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"766dce6b1394ebb56a3090748d5a0240a5aefb36","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}