{"record":{"id":"441794687b127613","repo":"BigPizzaV3/CodexPlusPlus","slug":"backup-source-database-is-not-an-allowed-local-sto","errorCode":null,"errorMessage":"Backup source database is not an allowed local storage path","messagePattern":"Backup source database is not an allowed local storage path","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codex-plus-data/src/storage.rs","lineNumber":929,"sourceCode":") -> anyhow::Result<PathBuf> {\n    let source_db = backup[\"source_db\"]\n        .as_str()\n        .filter(|path| !path.trim().is_empty())\n        .map(PathBuf::from)\n        .unwrap_or_else(|| fallback_db_path.to_path_buf());\n    if !source_db.is_file() {\n        anyhow::bail!(\n            \"Backup source database not found: {}\",\n            source_db.to_string_lossy()\n        );\n    }\n    let source_db = fs::canonicalize(source_db)?;\n    let allowed = allowed_db_paths\n        .iter()\n        .filter_map(|path| fs::canonicalize(path).ok())\n        .any(|path| path == source_db);\n    if !allowed {\n        anyhow::bail!(\"Backup source database is not an allowed local storage path\");\n    }\n    Ok(source_db)\n}\n\nfn schema_kind(db: &Connection) -> anyhow::Result<Option<SchemaKind>> {\n    if has_table(db, \"sessions\")? && has_columns(db, \"sessions\", &[\"id\", \"title\"])? {\n        if has_table(db, \"messages\")? && !has_columns(db, \"messages\", &[\"session_id\"])? {\n            return Ok(None);\n        }\n        return Ok(Some(SchemaKind::GenericSessions));\n    }\n    if has_table(db, \"threads\")? && has_columns(db, \"threads\", &[\"id\", \"title\", \"rollout_path\"])? {\n        return Ok(Some(SchemaKind::CodexThreads));\n    }\n    if has_table(db, \"automation_runs\")? && has_columns(db, \"automation_runs\", &[\"thread_id\"])? {\n        return Ok(Some(SchemaKind::CodexAutomationRuns));\n    }\n    Ok(None)","sourceCodeStart":911,"sourceCodeEnd":947,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/f2074595a281bc057525c748175c8eb9805b0673/crates/codex-plus-data/src/storage.rs#L911-L947","documentation":"Thrown by backup_source_db when the canonicalized source database path is not in the caller-provided allowed_db_paths set. This is a path-confinement guard for restores: a backup record cannot pull rows from databases outside the sanctioned local-storage locations; the offending input is the source_db path embedded in the (untrusted) backup record.","triggerScenarios":"Thrown at crates/codex-plus-data/src/storage.rs:929 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["确认备份是在当前机器、当前数据库路径下创建的","若数据库位置合法迁移，更新 allowed_db_paths 候选列表","不要手工导入来源不明的备份 token","在生成备份的机器上执行 undo"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"f2074595a281bc057525c748175c8eb9805b0673","analyzedAt":"2026-08-23T12:52:24.489Z","contentChangedAt":"2026-08-23T12:52:24.489Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}