fix: read secrets from legacy data dir

This commit is contained in:
Keisuke Hirata 2026-07-28 04:12:26 +09:00
parent 5d1950647e
commit 6114cc9018
No known key found for this signature in database
4 changed files with 71 additions and 6 deletions

View File

@ -5,6 +5,9 @@
//! - **`config_dir`** — 人が手で書く / 編集する設定。`profiles.toml`,
//! `providers.toml`, `models.toml`, `prompts/`, `prompts.toml` 等
//! - **`data_dir`** — プログラムが書く永続データ。`sessions/` 等
//! - **`secret_data_dir`** — local secret store の読み書き base。既存
//! secret store は path-derived key を使うため、通常 data とは別に
//! legacy `$HOME/.yoi` を既定にする
//! - **`runtime_dir`** — 再起動で消えてよいランタイム状態。socket,
//! `workers.json`, `pid` ファイル等
//!
@ -14,6 +17,7 @@
//! |---|---|---|---|---|
//! | config | `YOI_CONFIG_DIR` | `$YOI_HOME/config` | `$XDG_CONFIG_HOME/yoi` | `$HOME/.config/yoi` |
//! | data | `YOI_DATA_DIR` | `$YOI_HOME` | `$XDG_DATA_HOME/yoi` | `$HOME/.local/share/yoi` |
//! | secrets | `YOI_DATA_DIR` | `$YOI_HOME` | — | `$HOME/.yoi` |
//! | runtime | `YOI_RUNTIME_DIR` | `$YOI_HOME/run` | `$XDG_RUNTIME_DIR/yoi` | `$HOME/.yoi/run` |
//!
//! `YOI_HOME=$X` のとき config は `$X/config`、data は `$X` 直下、
@ -47,6 +51,19 @@ pub fn data_dir() -> Option<PathBuf> {
)
}
/// Secret store 用の data directory。
///
/// SecretStore は base path から復号 key を導出するため、通常 data dir の
/// XDG fallback には追従させず、明示 override が無い場合は legacy
/// `$HOME/.yoi` を読み書きする。
pub fn secret_data_dir() -> Option<PathBuf> {
resolve_secret_data_dir_from_parts(
env_path("YOI_DATA_DIR"),
env_path("YOI_HOME"),
env_path("HOME"),
)
}
/// ランタイムディレクトリ。socket, `workers.json`, Worker ごとの `pid` /
/// `status.json` 等が置かれる。再起動で消えて構わない。
pub fn runtime_dir() -> Option<PathBuf> {
@ -147,6 +164,20 @@ fn resolve_data_dir_from_parts(
Some(home?.join(".local").join("share").join("yoi"))
}
fn resolve_secret_data_dir_from_parts(
yoi_data_dir: Option<PathBuf>,
yoi_home: Option<PathBuf>,
home: Option<PathBuf>,
) -> Option<PathBuf> {
if let Some(p) = yoi_data_dir {
return Some(p);
}
if let Some(p) = yoi_home {
return Some(p);
}
Some(home?.join(".yoi"))
}
fn resolve_runtime_dir_from_parts(
yoi_runtime_dir: Option<PathBuf>,
yoi_home: Option<PathBuf>,
@ -322,6 +353,40 @@ mod tests {
);
}
#[test]
fn secret_data_dir_falls_back_to_home_dot_yoi() {
assert_eq!(
resolve_secret_data_dir_from_parts(None, None, Some(PathBuf::from("/h"))).unwrap(),
PathBuf::from("/h/.yoi")
);
}
#[test]
fn secret_data_dir_yoi_home_wins() {
assert_eq!(
resolve_secret_data_dir_from_parts(
None,
Some(PathBuf::from("/sand")),
Some(PathBuf::from("/h"))
)
.unwrap(),
PathBuf::from("/sand")
);
}
#[test]
fn secret_data_dir_explicit_wins_over_yoi_home() {
assert_eq!(
resolve_secret_data_dir_from_parts(
Some(PathBuf::from("/explicit-data")),
Some(PathBuf::from("/sand")),
Some(PathBuf::from("/h")),
)
.unwrap(),
PathBuf::from("/explicit-data")
);
}
#[test]
fn runtime_dir_prefers_xdg_runtime_dir() {
assert_eq!(

View File

@ -47,7 +47,7 @@ impl WebTools {
.user_agent("yoi-web-tools/0.1")
.build()
.expect("static reqwest client configuration is valid");
let secret_store = manifest::paths::data_dir().map(SecretStore::new);
let secret_store = manifest::paths::secret_data_dir().map(SecretStore::new);
Self {
config,
client,

View File

@ -218,10 +218,10 @@ impl std::fmt::Debug for Action {
}
pub async fn launch() -> ExitCode {
let data_dir = match manifest::paths::data_dir() {
let data_dir = match manifest::paths::secret_data_dir() {
Some(path) => path,
None => {
eprintln!("yoi keys: could not determine yoi data directory");
eprintln!("yoi keys: could not determine yoi secret data directory");
return ExitCode::FAILURE;
}
};

View File

@ -70,11 +70,11 @@ struct DefaultSecretResolver;
impl SecretResolver for DefaultSecretResolver {
fn get_secret(&self, id: &str) -> Result<SecretValue, secrets::Error> {
let data_dir = manifest::paths::data_dir().ok_or_else(|| secrets::Error::Read {
path: std::path::PathBuf::from("<data_dir>"),
let data_dir = manifest::paths::secret_data_dir().ok_or_else(|| secrets::Error::Read {
path: std::path::PathBuf::from("<secret_data_dir>"),
source: std::io::Error::new(
std::io::ErrorKind::NotFound,
"could not determine yoi data directory",
"could not determine yoi secret data directory",
),
})?;
SecretStore::new(data_dir).get(id)