Skip to content

Commit 9d75ca6

Browse files
committed
Fix config includes and CodeQL findings
1 parent b1a50d1 commit 9d75ca6

6 files changed

Lines changed: 106 additions & 45 deletions

File tree

docs/build-and-podman.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -332,10 +332,10 @@ root = "/srv/sites/example/public"
332332
For multi-site setups, prefer `/etc/fluxheim/conf.d/` with one vhost per file.
333333
`[[vhosts]]` starts a vhost, and each following `[vhosts.*]` table belongs to
334334
that vhost until the next `[[vhosts]]`.
335-
When Fluxheim starts from `/etc/fluxheim/fluxheim.toml`, it also loads visible
336-
`*.toml` files from `/etc/fluxheim/conf.d/` after the main file. When it starts
337-
from `/etc/fluxheim`, it loads top-level TOML files first and then
338-
`/etc/fluxheim/conf.d/*.toml`.
335+
The packaged `/etc/fluxheim/fluxheim.toml` sets `include_conf_d = true`, so it
336+
also loads visible `*.toml` files from `/etc/fluxheim/conf.d/` after the main
337+
file. When Fluxheim starts from `/etc/fluxheim`, it loads top-level TOML files
338+
first and then `/etc/fluxheim/conf.d/*.toml`.
339339

340340
Podman run example:
341341

docs/config-reference.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ For split config directories, Fluxheim reads `*.toml` files in sorted order:
1515
fluxheim --check-config --config examples/conf.d
1616
```
1717

18-
When the config path is a file, Fluxheim loads that file first and then loads
19-
visible `*.toml` files from a sibling `conf.d/` directory if it exists. When
20-
the config path is a directory, Fluxheim loads visible `*.toml` files in that
21-
directory first and then visible `*.toml` files in its `conf.d/` child. Files
22-
are loaded in lexical order within each directory.
18+
When the config path is a file, Fluxheim loads only that file unless the file
19+
sets `include_conf_d = true`. With that opt-in, visible `*.toml` files from a
20+
sibling `conf.d/` directory load after the main file. When the config path is a
21+
directory, Fluxheim loads visible `*.toml` files in that directory first and
22+
then visible `*.toml` files in its `conf.d/` child. Files are loaded in lexical
23+
order within each directory.
2324

2425
Relative filesystem paths are resolved from the config file directory.
2526
Config sources must be real TOML files or real directories. Fluxheim rejects a

packaging/default/fluxheim.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
include_conf_d = true
2+
13
[server]
24
listen = ["0.0.0.0:80"]
35
default_vhost = "default"

scripts/build_fluxheim_rpm.py

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import sys
1616
import tempfile
1717
from pathlib import Path
18-
from typing import Sequence
1918

2019

2120
OS_CONTAINERS = {
@@ -31,11 +30,6 @@
3130
SAFE_RPM_RELEASE = re.compile(r"^[0-9][0-9A-Za-z._+~]*$")
3231

3332

34-
def run_command(command: Sequence[str], cwd: Path | None = None) -> None:
35-
print(f"Executing: {shlex.join(command)}")
36-
subprocess.run(command, cwd=cwd, check=True)
37-
38-
3933
def get_container_tool(preferred: str | None) -> str:
4034
if preferred:
4135
if shutil.which(preferred):
@@ -92,6 +86,50 @@ def print_targets() -> None:
9286
print(f"{name}: {image}")
9387

9488

89+
def run_container_build(
90+
container_tool: str,
91+
work_dir: Path,
92+
container_image: str,
93+
version_tag: str,
94+
build_type: str,
95+
rpm_release: str,
96+
) -> None:
97+
print(
98+
"Executing: "
99+
+ shlex.join(
100+
[
101+
container_tool,
102+
"run",
103+
"--rm",
104+
"-v",
105+
f"{work_dir}:/workspace:Z",
106+
container_image,
107+
"bash",
108+
"/workspace/build_in_container.sh",
109+
version_tag,
110+
build_type,
111+
rpm_release,
112+
]
113+
)
114+
)
115+
subprocess.run(
116+
[
117+
container_tool,
118+
"run",
119+
"--rm",
120+
"-v",
121+
f"{work_dir}:/workspace:Z",
122+
container_image,
123+
"bash",
124+
"/workspace/build_in_container.sh",
125+
version_tag,
126+
build_type,
127+
rpm_release,
128+
],
129+
check=True,
130+
)
131+
132+
95133
def choose_target(target: str | None) -> tuple[str, str]:
96134
if target:
97135
return target, OS_CONTAINERS[target]
@@ -325,20 +363,13 @@ def main() -> int:
325363
generate_build_script(build_script_path)
326364
build_script_path.chmod(0o755)
327365

328-
run_command(
329-
[
330-
container_tool,
331-
"run",
332-
"--rm",
333-
"-v",
334-
f"{work_dir}:/workspace:Z",
335-
container_image,
336-
"bash",
337-
"/workspace/build_in_container.sh",
338-
args.version_tag,
339-
args.build_type,
340-
args.rpm_release,
341-
]
366+
run_container_build(
367+
container_tool,
368+
work_dir,
369+
container_image,
370+
args.version_tag,
371+
args.build_type,
372+
args.rpm_release,
342373
)
343374

344375
rpms = sorted(work_dir.glob("*.rpm"))

src/config.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,15 @@ impl Config {
7070

7171
fn load_file(path: &Path) -> Result<Self, ConfigLoadError> {
7272
let mut fragment = ConfigFragment::load(path)?;
73+
let include_conf_d = fragment.include_conf_d;
7374
let parent = path.parent();
7475
if let Some(parent) = parent {
7576
fragment.resolve_relative_paths(parent);
7677
}
7778

7879
let mut config = Self::default();
7980
config.merge(fragment);
80-
if let Some(parent) = parent {
81+
if include_conf_d && let Some(parent) = parent {
8182
config.merge_conf_d(parent)?;
8283
}
8384
Ok(config)
@@ -225,6 +226,8 @@ impl Config {
225226
#[derive(Debug, Clone, Default, Eq, PartialEq, Deserialize, Serialize)]
226227
#[serde(deny_unknown_fields)]
227228
struct ConfigFragment {
229+
#[serde(default)]
230+
include_conf_d: bool,
228231
#[serde(default)]
229232
server: Option<ServerConfigFragment>,
230233
#[serde(default)]
@@ -7065,6 +7068,8 @@ mod tests {
70657068
fs::write(
70667069
dir.child("fluxheim.toml"),
70677070
r#"
7071+
include_conf_d = true
7072+
70687073
[server]
70697074
listen = ["127.0.0.1:19090"]
70707075
default_vhost = "example"
@@ -7091,6 +7096,33 @@ mod tests {
70917096
assert_eq!(config.vhosts[0].web.root, Some(dir.child("conf.d/site")));
70927097
}
70937098

7099+
#[test]
7100+
fn loading_main_config_file_does_not_load_conf_d_without_opt_in() {
7101+
let dir = TestDir::new("config-file-with-conf-d-no-opt-in");
7102+
fs::create_dir_all(dir.child("conf.d")).unwrap();
7103+
fs::write(
7104+
dir.child("fluxheim.toml"),
7105+
r#"
7106+
[server]
7107+
listen = ["127.0.0.1:19090"]
7108+
"#,
7109+
)
7110+
.unwrap();
7111+
fs::write(
7112+
dir.child("conf.d/10-vhost.toml"),
7113+
r#"
7114+
[[vhosts]]
7115+
name = "example"
7116+
hosts = ["example.test"]
7117+
"#,
7118+
)
7119+
.unwrap();
7120+
7121+
let config = Config::load(Some(&dir.child("fluxheim.toml"))).unwrap();
7122+
7123+
assert!(config.vhosts.is_empty());
7124+
}
7125+
70947126
#[test]
70957127
fn loading_config_directory_also_loads_conf_d_after_top_level_files() {
70967128
let dir = TestDir::new("config-dir-with-conf-d");

src/web.rs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -301,24 +301,18 @@ fn normal_component(component: &std::ffi::OsStr) -> Option<&std::ffi::OsStr> {
301301
}
302302
}
303303

304-
fn symlink_walk_status(path: &Path) -> io::Result<Option<bool>> {
305-
if path.is_symlink() {
306-
return Ok(Some(true));
307-
}
308-
path.try_exists().map(|exists| exists.then_some(false))
309-
}
310-
311304
fn path_contains_symlink(root: &Path, relative: &SafeRelativePath) -> io::Result<bool> {
312305
let mut current = root.to_path_buf();
313306
for component in &relative.components {
314307
let Some(component) = normal_component(component) else {
315308
return Ok(true);
316309
};
317310
current.push(component);
318-
match symlink_walk_status(&current)? {
319-
Some(true) => return Ok(true),
320-
Some(false) => {}
321-
None => return Ok(false),
311+
match std::fs::read_link(&current) {
312+
Ok(_) => return Ok(true),
313+
Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(false),
314+
Err(error) if error.kind() == io::ErrorKind::InvalidInput => {}
315+
Err(error) => return Err(error),
322316
}
323317
}
324318

@@ -340,10 +334,11 @@ fn configured_web_path_contains_symlink(path: &Path) -> io::Result<bool> {
340334
}
341335
std::path::Component::CurDir | std::path::Component::ParentDir => return Ok(true),
342336
}
343-
match symlink_walk_status(&current)? {
344-
Some(true) => return Ok(true),
345-
Some(false) => {}
346-
None => return Ok(false),
337+
match std::fs::read_link(&current) {
338+
Ok(_) => return Ok(true),
339+
Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(false),
340+
Err(error) if error.kind() == io::ErrorKind::InvalidInput => {}
341+
Err(error) => return Err(error),
347342
}
348343
}
349344

0 commit comments

Comments
 (0)