Skip to content

Commit 42a6c8c

Browse files
committed
Permission controlled access to xdg config (#301)
1 parent 95577e2 commit 42a6c8c

File tree

8 files changed

+94
-9
lines changed

8 files changed

+94
-9
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

git-repository/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ git-ref = { version = "^0.12.1", path = "../git-ref" }
6060
git-tempfile = { version = "^2.0.0", path = "../git-tempfile" }
6161
git-lock = { version = "^2.0.0", path = "../git-lock" }
6262
git-validate = { version ="^0.5.3", path = "../git-validate" }
63-
git-sec = { version = "^0.1.0", path = "../git-sec" }
63+
git-sec = { version = "^0.1.0", path = "../git-sec", features = ["thiserror"] }
6464

6565
git-config = { version = "^0.2.1", path = "../git-config" }
6666
git-odb = { version = "^0.28.0", path = "../git-odb" }

git-repository/src/config.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::bstr::BString;
2+
use crate::permission::EnvVarResourcePermission;
23

34
#[derive(Debug, thiserror::Error)]
45
pub enum Error {
@@ -34,11 +35,16 @@ pub(crate) struct Cache {
3435
pub ignore_case: bool,
3536
/// The path to the user-level excludes file to ignore certain files in the worktree.
3637
pub excludes_file: Option<std::path::PathBuf>,
38+
/// Define how we can use values obtained with `xdg_config(…)` and its `XDG_CONFIG_HOME` variable.
39+
xdg_config_home_env: EnvVarResourcePermission,
40+
/// Define how we can use values obtained with `xdg_config(…)`. and its `HOME` variable.
41+
home_env: EnvVarResourcePermission,
3742
// TODO: make core.precomposeUnicode available as well.
3843
}
3944

4045
mod cache {
4146
use std::convert::TryFrom;
47+
use std::path::PathBuf;
4248

4349
use git_config::{
4450
file::GitConfig,
@@ -47,9 +53,15 @@ mod cache {
4753

4854
use super::{Cache, Error};
4955
use crate::bstr::ByteSlice;
56+
use crate::permission::EnvVarResourcePermission;
5057

5158
impl Cache {
52-
pub fn new(git_dir: &std::path::Path, git_install_dir: Option<&std::path::Path>) -> Result<Self, Error> {
59+
pub fn new(
60+
git_dir: &std::path::Path,
61+
xdg_config_home_env: EnvVarResourcePermission,
62+
home_env: EnvVarResourcePermission,
63+
git_install_dir: Option<&std::path::Path>,
64+
) -> Result<Self, Error> {
5365
let config = GitConfig::open(git_dir.join("config"))?;
5466

5567
let is_bare = config_bool(&config, "core.bare", false)?;
@@ -117,8 +129,26 @@ mod cache {
117129
ignore_case,
118130
hex_len,
119131
excludes_file,
132+
xdg_config_home_env,
133+
home_env,
120134
})
121135
}
136+
137+
/// Return a path by using the `$XDF_CONFIG_HOME` or `$HOME/.config/…` environment variables locations.
138+
pub fn xdg_config_path(
139+
&self,
140+
resource_file_name: &str,
141+
) -> Result<Option<PathBuf>, git_sec::permission::Error<PathBuf, git_sec::Permission>> {
142+
std::env::var_os("XDG_CONFIG_HOME")
143+
.map(|path| (path, &self.xdg_config_home_env))
144+
.or_else(|| std::env::var_os("HOME").map(|path| (path, &self.home_env)))
145+
.map(|(base, permission)| {
146+
let resource = std::path::PathBuf::from(base).join("git").join(resource_file_name);
147+
permission.check(resource).transpose()
148+
})
149+
.flatten()
150+
.transpose()
151+
}
122152
}
123153

124154
fn config_bool(config: &GitConfig<'_>, key: &str, default: bool) -> Result<bool, Error> {

git-repository/src/lib.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ pub mod id;
204204
pub mod object;
205205
pub mod reference;
206206
mod repository;
207-
pub use repository::{permissions, permissions::Permissions};
208207
pub mod tag;
209208

210209
/// The kind of `Repository`
@@ -243,6 +242,16 @@ pub fn open(directory: impl Into<std::path::PathBuf>) -> Result<crate::Repositor
243242
ThreadSafeRepository::open(directory).map(Into::into)
244243
}
245244

245+
///
246+
pub mod permission {
247+
use git_sec::permission::Resource;
248+
use git_sec::Access;
249+
250+
/// A permission to control access to the resource pointed to an environment variable.
251+
pub type EnvVarResourcePermission = Access<Resource, git_sec::Permission>;
252+
}
253+
pub use repository::permissions::Permissions;
254+
246255
///
247256
pub mod open;
248257

git-repository/src/open.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,18 +153,28 @@ impl crate::ThreadSafeRepository {
153153
Options {
154154
object_store_slots,
155155
replacement_objects,
156-
permissions,
156+
permissions:
157+
Permissions {
158+
git_dir: git_dir_perm,
159+
xdg_config_home,
160+
home,
161+
},
157162
}: Options,
158163
) -> Result<Self, Error> {
159-
if *permissions.git_dir != git_sec::ReadWrite::all() {
164+
if *git_dir_perm != git_sec::ReadWrite::all() {
160165
// TODO: respect `save.directory`, which needs more support from git-config to do properly.
161166
return Err(Error::UnsafeGitDir { path: git_dir });
162167
}
163168
// TODO: assure we handle the worktree-dir properly as we can have config per worktree with an extension.
164169
// This would be something read in later as have to first check for extensions. Also this means
165170
// that each worktree, even if accessible through this instance, has to come in its own Repository instance
166171
// as it may have its own configuration. That's fine actually.
167-
let config = crate::config::Cache::new(&git_dir, crate::path::install_dir().ok().as_deref())?;
172+
let config = crate::config::Cache::new(
173+
&git_dir,
174+
xdg_config_home,
175+
home,
176+
crate::path::install_dir().ok().as_deref(),
177+
)?;
168178
match worktree_dir {
169179
None if !config.is_bare => {
170180
worktree_dir = Some(git_dir.parent().expect("parent is always available").to_owned());

git-repository/src/repository/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl crate::Repository {
4242
mod worktree;
4343

4444
/// Various permissions for parts of git repositories.
45-
pub mod permissions;
45+
pub(crate) mod permissions;
4646

4747
mod init;
4848

git-repository/src/repository/permissions.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::permission::EnvVarResourcePermission;
12
use git_sec::permission::Resource;
23
use git_sec::{Access, Trust};
34

@@ -7,6 +8,12 @@ pub struct Permissions {
78
///
89
/// Note that a repository won't be usable at all unless read and write permissions are given.
910
pub git_dir: Access<Resource, git_sec::ReadWrite>,
11+
/// Control whether resources pointed to by `XDG_CONFIG_HOME` can be used when looking up common configuration values.
12+
///
13+
/// Note that [`git_sec::Permission::Forbid`] will cause the operation to abort if a resource is set via the XDG config environment.
14+
pub xdg_config_home: EnvVarResourcePermission,
15+
/// Control if resources pointed to by the
16+
pub home: EnvVarResourcePermission,
1017
}
1118

1219
impl Permissions {
@@ -15,6 +22,8 @@ impl Permissions {
1522
pub fn strict() -> Self {
1623
Permissions {
1724
git_dir: Access::resource(git_sec::ReadWrite::empty()),
25+
xdg_config_home: Access::resource(git_sec::Permission::Allow),
26+
home: Access::resource(git_sec::Permission::Allow),
1827
}
1928
}
2029

@@ -26,6 +35,8 @@ impl Permissions {
2635
pub fn secure() -> Self {
2736
Permissions {
2837
git_dir: Access::resource(git_sec::ReadWrite::all()),
38+
xdg_config_home: Access::resource(git_sec::Permission::Allow),
39+
home: Access::resource(git_sec::Permission::Allow),
2940
}
3041
}
3142

@@ -34,6 +45,8 @@ impl Permissions {
3445
pub fn all() -> Self {
3546
Permissions {
3647
git_dir: Access::resource(git_sec::ReadWrite::all()),
48+
xdg_config_home: Access::resource(git_sec::Permission::Allow),
49+
home: Access::resource(git_sec::Permission::Allow),
3750
}
3851
}
3952
}

git-repository/src/worktree.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,22 @@ pub mod open_index {
2222
}
2323
}
2424

25+
///
26+
#[cfg(feature = "git-index")]
27+
pub mod excludes {
28+
use std::path::PathBuf;
29+
30+
/// The error returned by [`Worktree::excludes()`][crate::Worktree::excludes()].
31+
#[derive(Debug, thiserror::Error)]
32+
#[allow(missing_docs)]
33+
pub enum Error {
34+
#[error("Could not read repository exclude.")]
35+
Io(#[from] std::io::Error),
36+
#[error(transparent)]
37+
EnvironmentPermission(#[from] git_sec::permission::Error<PathBuf, git_sec::Permission>),
38+
}
39+
}
40+
2541
/// A structure to make the API more stuctured.
2642
pub struct Platform<'repo> {
2743
pub(crate) parent: &'repo Repository,
@@ -45,7 +61,7 @@ impl<'repo> crate::Worktree<'repo> {
4561
&self,
4662
index: &'a git_index::State,
4763
overrides: Option<git_attributes::MatchGroup<git_attributes::Ignore>>,
48-
) -> std::io::Result<git_worktree::fs::Cache<'a>> {
64+
) -> Result<git_worktree::fs::Cache<'a>, excludes::Error> {
4965
let repo = self.parent;
5066
let case = repo
5167
.config
@@ -57,7 +73,13 @@ impl<'repo> crate::Worktree<'repo> {
5773
overrides.unwrap_or_default(),
5874
git_attributes::MatchGroup::<git_attributes::Ignore>::from_git_dir(
5975
repo.git_dir(),
60-
repo.config.excludes_file.clone(), // TODO: read from XDG home and make it controllable how env vars are used via git-sec
76+
repo.config
77+
.excludes_file
78+
.as_ref()
79+
.map(|p| Ok(Some(p.to_owned())))
80+
.or_else(|| repo.config.xdg_config_path("ignore").into())
81+
.transpose()?
82+
.flatten(),
6183
&mut buf,
6284
)?,
6385
None,

0 commit comments

Comments
 (0)