feat(token): add stored token support with resolve_token and token_source
Introduce a centralized token resolution system that supports both
environment variables and config-file-stored tokens with clear priority
(env var wins). This enables cron-based sync which runs in minimal
shell environments without env vars.
Core changes:
- GitLabConfig gains optional `token` field and `resolve_token()` method
that checks env var first, then config file, returning trimmed values
- `token_source()` returns human-readable provenance ("environment variable"
or "config file") for diagnostics
- `ensure_config_permissions()` enforces 0600 on config files containing
tokens (Unix only, no-op on other platforms)
New CLI commands:
- `lore token set [--token VALUE]` — validates against GitLab API, stores
in config, enforces file permissions. Supports flag, stdin pipe, or
interactive entry.
- `lore token show [--unmask]` — displays masked token with source label
Consumers updated to use resolve_token():
- auth_test: removes manual env var lookup
- doctor: shows token source in health check output
- ingest: uses centralized resolution
Includes 10 unit tests for resolve/source logic and 2 for mask_token.
This commit is contained in:
@@ -240,14 +240,14 @@ async fn check_gitlab(config: Option<&Config>) -> GitLabCheck {
|
||||
};
|
||||
};
|
||||
|
||||
let token = match std::env::var(&config.gitlab.token_env_var) {
|
||||
Ok(t) if !t.trim().is_empty() => t.trim().to_string(),
|
||||
_ => {
|
||||
let token = match config.gitlab.resolve_token() {
|
||||
Ok(t) => t,
|
||||
Err(_) => {
|
||||
return GitLabCheck {
|
||||
result: CheckResult {
|
||||
status: CheckStatus::Error,
|
||||
message: Some(format!(
|
||||
"{} not set in environment",
|
||||
"Token not set. Run 'lore token set' or export {}.",
|
||||
config.gitlab.token_env_var
|
||||
)),
|
||||
},
|
||||
@@ -257,6 +257,8 @@ async fn check_gitlab(config: Option<&Config>) -> GitLabCheck {
|
||||
}
|
||||
};
|
||||
|
||||
let source = config.gitlab.token_source().unwrap_or("unknown");
|
||||
|
||||
let client = GitLabClient::new(&config.gitlab.base_url, &token, None);
|
||||
|
||||
match client.get_current_user().await {
|
||||
@@ -264,7 +266,7 @@ async fn check_gitlab(config: Option<&Config>) -> GitLabCheck {
|
||||
result: CheckResult {
|
||||
status: CheckStatus::Ok,
|
||||
message: Some(format!(
|
||||
"{} (authenticated as @{})",
|
||||
"{} (authenticated as @{}, token from {source})",
|
||||
config.gitlab.base_url, user.username
|
||||
)),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user