Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
087b963
feat(bisect): implement git bisect command for binary search debugging
marshawcoco Mar 31, 2026
b88b3ac
fix(bisect): hydrate LFS objects during checkout and resolve clippy w…
marshawcoco Mar 31, 2026
23bb897
Merge branch 'web3infra-foundation:main' into main
marshawcoco Apr 1, 2026
37a9644
Merge branch 'main' of https://github.com/web3infra-foundation/libra
marshawcoco Apr 2, 2026
fd81680
Merge branch 'main' of https://github.com/marshawcoco/libra
marshawcoco Apr 2, 2026
51ba7bb
Merge branch 'web3infra-foundation:main' into main
marshawcoco Apr 5, 2026
c91e0c4
Merge branch 'web3infra-foundation:main' into main
marshawcoco Apr 6, 2026
55dc812
Merge branch 'web3infra-foundation:main' into main
marshawcoco Apr 7, 2026
cd70d00
feat(rev-parse): add revision parsing command
marshawcoco Apr 7, 2026
1e9da78
fix(ci): improve windows test portability
marshawcoco Apr 7, 2026
ec014ad
fix(rev-parse): restore command wiring and windows worktree fallback
marshawcoco Apr 8, 2026
13527e2
fix(review): address rev-parse and windows sandbox follow-ups
marshawcoco Apr 8, 2026
1bc0f34
fix(review): preserve rev-parse storage errors
marshawcoco Apr 8, 2026
27d6392
fix(cloud): resolve config without relying on cwd
marshawcoco Apr 8, 2026
54e729a
fix(ci): repair command test imports and formatting
marshawcoco Apr 8, 2026
06f0d7d
fix(test): accept config resolution error variants
marshawcoco Apr 8, 2026
4f33b38
fix(test): stabilize tag command setup
marshawcoco Apr 9, 2026
b74b699
fix(review): remove committed ci log file
marshawcoco Apr 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,6 @@ The following Git top-level commands are currently **not implemented** in Libra
- `maintenance` – periodic maintenance tasks
- `cat-file` – display raw object contents
- `hash-object` – compute object hash for raw data
- `rev-parse` – resolve revisions, refs, and object IDs
- `rev-list` – list reachable commits
- `describe` – human-readable description based on tags
- `show-ref` – list all refs
Expand Down
3 changes: 3 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ enum Commands {
Merge(command::merge::MergeArgs),
#[command(about = "Reset current HEAD to specified state")]
Reset(command::reset::ResetArgs),
#[command(about = "Parse and normalize revision names and repository paths")]
RevParse(command::rev_parse::RevParseArgs),
Comment thread
marshawcoco marked this conversation as resolved.
#[command(about = "Move or rename a file, a directory, or a symlink")]
Mv(command::mv::MvArgs),
#[command(
Expand Down Expand Up @@ -651,6 +653,7 @@ pub async fn parse_async(args: Option<&[&str]>) -> CliResult<()> {
Commands::Rebase(cmd_args) => command::rebase::execute_safe(cmd_args, &output).await?,
Commands::Merge(cmd_args) => command::merge::execute_safe(cmd_args, &output).await?,
Commands::Reset(cmd_args) => command::reset::execute_safe(cmd_args, &output).await?,
Commands::RevParse(cmd_args) => command::rev_parse::execute_safe(cmd_args, &output).await?,
Commands::Mv(cmd_args) => command::mv::execute_safe(cmd_args, &output).await?,
Commands::Describe(cmd_args) => command::describe::execute_safe(cmd_args, &output).await?,
Commands::CherryPick(cmd_args) => {
Expand Down
63 changes: 50 additions & 13 deletions src/command/cloud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
path::PathBuf,
sync::Arc,
};

Expand Down Expand Up @@ -591,26 +592,54 @@ async fn execute_status(args: StatusArgs) -> Result<(), String> {
Ok(())
}

async fn resolve_cloud_env(name: &str) -> Result<Option<String>, String> {
crate::internal::config::resolve_env(name)
fn cloud_local_db_path() -> Result<PathBuf, String> {
let storage = util::try_get_storage_path(None)
.map_err(|e| format!("failed to resolve current repository storage: {e}"))?;
Ok(storage.join(util::DATABASE))
}

async fn resolve_cloud_env(
name: &str,
local_db_path: Option<&std::path::Path>,
) -> Result<Option<String>, String> {
let local_target = match local_db_path {
Some(db_path) => crate::internal::config::LocalIdentityTarget::ExplicitDb(db_path),
None => crate::internal::config::LocalIdentityTarget::CurrentRepo,
};

crate::internal::config::resolve_env_for_target(name, local_target)
.await
.map_err(|e| format!("failed to resolve '{name}' from env or config: {e}"))
}

async fn resolve_required_cloud_env(name: &str) -> Result<String, String> {
match resolve_cloud_env(name).await? {
async fn resolve_required_cloud_env(
name: &str,
local_db_path: Option<&std::path::Path>,
) -> Result<String, String> {
match resolve_cloud_env(name, local_db_path).await? {
Some(value) if !value.is_empty() => Ok(value),
_ => Err(format!("{name} not set")),
}
}

/// Create R2 remote storage from environment variables and config.
async fn create_r2_storage(repo_id: &str) -> Result<RemoteStorage, String> {
let endpoint = resolve_required_cloud_env("LIBRA_STORAGE_ENDPOINT").await?;
let bucket = resolve_required_cloud_env("LIBRA_STORAGE_BUCKET").await?;
let access_key = resolve_required_cloud_env("LIBRA_STORAGE_ACCESS_KEY").await?;
let secret_key = resolve_required_cloud_env("LIBRA_STORAGE_SECRET_KEY").await?;
let region = resolve_cloud_env("LIBRA_STORAGE_REGION")
let local_db_path = cloud_local_db_path()?;
create_r2_storage_for_db_path(repo_id, &local_db_path).await
}

async fn create_r2_storage_for_db_path(
repo_id: &str,
local_db_path: &std::path::Path,
) -> Result<RemoteStorage, String> {
let endpoint =
resolve_required_cloud_env("LIBRA_STORAGE_ENDPOINT", Some(local_db_path)).await?;
let bucket = resolve_required_cloud_env("LIBRA_STORAGE_BUCKET", Some(local_db_path)).await?;
let access_key =
resolve_required_cloud_env("LIBRA_STORAGE_ACCESS_KEY", Some(local_db_path)).await?;
let secret_key =
resolve_required_cloud_env("LIBRA_STORAGE_SECRET_KEY", Some(local_db_path)).await?;
let region = resolve_cloud_env("LIBRA_STORAGE_REGION", Some(local_db_path))
.await?
.filter(|value| !value.is_empty())
.unwrap_or_else(|| "auto".to_string());
Expand Down Expand Up @@ -647,9 +676,10 @@ async fn validate_cloud_backup_env(skip_r2: bool) -> Result<(), String> {
]);
}

let local_db_path = cloud_local_db_path()?;
let mut missing = Vec::new();
for key in required {
match resolve_cloud_env(key).await? {
match resolve_cloud_env(key, Some(&local_db_path)).await? {
Some(value) if !value.is_empty() => {}
_ => missing.push(key),
}
Expand Down Expand Up @@ -910,8 +940,14 @@ mod tests {
.unwrap();
});

rt.block_on(create_r2_storage("repo-from-config"))
.expect("R2 storage should initialize from local config values");
let repo_db_path = repo.path().join(".libra").join(util::DATABASE);
let _manifest_dir = ChangeDirGuard::new(env!("CARGO_MANIFEST_DIR"));

rt.block_on(create_r2_storage_for_db_path(
"repo-from-config",
&repo_db_path,
))
.expect("R2 storage should initialize from local config values even after cwd drift");
}

#[test]
Expand All @@ -934,7 +970,8 @@ mod tests {
.block_on(validate_cloud_backup_env(true))
.expect_err("global config resolution failure should surface");
assert!(
err.contains("failed to connect to global config"),
err.contains("failed to open config database")
|| err.contains("failed to connect to global config"),
"unexpected error: {err}"
);
}
Expand Down
14 changes: 13 additions & 1 deletion src/command/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,20 @@ fn load_vault_unseal_key_sync() -> Result<Option<Vec<u8>>, String> {
}
}

fn resolve_home_directory() -> Result<PathBuf, String> {
for key in ["HOME", "USERPROFILE"] {
if let Some(value) = std::env::var_os(key)
&& !value.is_empty()
{
return Ok(PathBuf::from(value));
}
}

dirs::home_dir().ok_or_else(|| "cannot determine home directory".to_string())
}

fn ensure_vault_ssh_tmp_dir() -> Result<PathBuf, String> {
let home = dirs::home_dir().ok_or_else(|| "cannot determine home directory".to_string())?;
let home = resolve_home_directory()?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use consistent home path for SSH key GC

This change writes vault SSH temp files under resolve_home_directory() but the cleanup pass still scans dirs::home_dir(), so the two paths can diverge when HOME/USERPROFILE overrides are in effect (common in CI/sandboxed runs). In that case expired decrypted key files in the actual write location are never collected after abnormal exits, leaving sensitive material on disk longer than intended. Reuse the same home-resolution logic in cleanup_expired_vault_ssh_temp_files to keep write and GC directories aligned.

Useful? React with 👍 / 👎.

let tmp_dir = home.join(".libra").join("tmp");
std::fs::create_dir_all(&tmp_dir).map_err(|e| {
format!(
Expand Down
1 change: 1 addition & 0 deletions src/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub mod remote;
pub mod remove;
pub mod reset;
pub mod restore;
pub mod rev_parse;
pub mod revert;
pub mod shortlog;
pub mod show;
Expand Down
Loading
Loading