Conversation
Add a new template function `read_file(path)` that reads the contents of a file
relative to the config_root. This allows config files to include content from
external files during template rendering.
- Paths are resolved relative to the directory containing the mise.toml file
- Returns the raw file contents as a string
- Can be combined with filters like trim, replace, etc.
Example usage:
```toml
[env]
VERSION = "{{ read_file(path='VERSION') | trim }}"
```
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull Request Overview
This PR adds a new template function read_file() that allows reading file contents during template rendering in mise configuration files. The function reads files relative to the directory containing the mise.toml file, enabling dynamic inclusion of external content.
Key changes:
- Added
tera_read_file()function that reads file contents and returns them as a string - Modified
get_tera()to register the new function alongside the existingexecfunction - Added comprehensive test coverage for various use cases including relative paths and nested configurations
Reviewed Changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/tera.rs | Implements the read_file() template function and registers it with the Tera engine |
| e2e/env/test_env_template_read_file | Comprehensive end-to-end tests covering various read_file scenarios |
| docs/templates.md | Documents the new read_file function with usage examples |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| match std::fs::read_to_string(&path) { | ||
| Ok(contents) => Ok(Value::String(contents)), | ||
| Err(e) => { | ||
| Err(format!("Failed to read file '{}': {}", path.display(), e).into()) | ||
| } | ||
| } |
There was a problem hiding this comment.
The read_file function allows reading arbitrary files from the filesystem without any path validation or security checks. Consider adding validation to prevent directory traversal attacks (e.g., paths containing ../ or absolute paths) and restrict file access to only files within the configuration directory tree.
| // Use path as-is if no directory context | ||
| PathBuf::from(path_str) |
There was a problem hiding this comment.
When no directory context is provided, the function uses the path as-is, which could allow reading files from anywhere on the filesystem. Consider either requiring a base directory or defaulting to a safe directory like the current working directory to prevent unintended file access.
| // Use path as-is if no directory context | |
| PathBuf::from(path_str) | |
| // Default to current working directory if no directory context | |
| match std::env::current_dir() { | |
| Ok(cwd) => cwd.join(path_str), | |
| Err(e) => { | |
| return Err(format!("Failed to get current directory: {}", e).into()); | |
| } | |
| } |
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.9.17 x -- echo |
20.1 ± 0.5 | 19.3 | 25.0 | 1.00 |
mise x -- echo |
20.6 ± 0.7 | 19.5 | 25.3 | 1.03 ± 0.04 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.9.17 env |
19.6 ± 0.6 | 18.7 | 23.3 | 1.00 |
mise env |
19.8 ± 0.5 | 18.9 | 23.6 | 1.01 ± 0.04 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.9.17 hook-env |
19.1 ± 0.4 | 18.4 | 21.1 | 1.00 |
mise hook-env |
19.5 ± 0.6 | 18.5 | 21.9 | 1.02 ± 0.04 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.9.17 ls |
17.0 ± 0.4 | 16.3 | 18.7 | 1.00 |
mise ls |
18.0 ± 0.9 | 16.5 | 22.1 | 1.06 ± 0.06 |
xtasks/test/perf
| Command | mise-2025.9.17 | mise | Variance |
|---|---|---|---|
| install (cached) | 173ms | ✅ 106ms | +63% |
| ls (cached) | 65ms | 64ms | +1% |
| bin-paths (cached) | 72ms | 71ms | +1% |
| task-ls (cached) | 484ms | 492ms | -1% |
✅ Performance improvement: install cached is 63%
The test now properly verifies that read_file() resolves paths relative to each config file's directory, not the current working directory. It tests with nested config files at different levels, each reading their own local files, and confirms that parent env vars are accessible from subdirectories.
The test was using a hardcoded path that doesn't exist. Fixed by creating a temp directory and test file to properly verify the read_file function works correctly.
### 📦 Registry - replace amplify-cli github backend with ubi by @eggplants in [#6396](#6396) ### 🚀 Features - **(template)** add read_file() function by @jdx in [#6400](#6400) ### 🐛 Bug Fixes - **(aqua)** support github_artifact_attestations.enabled by @risu729 in [#6372](#6372) - use /c instead of -c on windows in postinstall hook by @risu729 in [#6397](#6397) ### 🧪 Testing - **(test-tool)** uninstall all versions and clear cache before installation by @jdx in [#6393](#6393) ### New Contributors - @eggplants made their first contribution in [#6396](#6396) Co-authored-by: mise-en-dev <release@mise.jdx.dev>
## [2025.9.18](https://github.com/jdx/mise/compare/v2025.9.17..v2025.9.18) - 2025-09-24 ### 📦 Registry - replace amplify-cli github backend with ubi by @eggplants in [#6396](jdx/mise#6396) ### 🚀 Features - **(template)** add read_file() function by @jdx in [#6400](jdx/mise#6400) ### 🐛 Bug Fixes - **(aqua)** support github_artifact_attestations.enabled by @risu729 in [#6372](jdx/mise#6372) - use /c instead of -c on windows in postinstall hook by @risu729 in [#6397](jdx/mise#6397) ### 🧪 Testing - **(test-tool)** uninstall all versions and clear cache before installation by @jdx in [#6393](jdx/mise#6393) ### New Contributors - @eggplants made their first contribution in [#6396](jdx/mise#6396) ## [2025.9.17](https://github.com/jdx/mise/compare/v2025.9.16..v2025.9.17) - 2025-09-24 ### 🚀 Features - **(java)** add support for Liberica NIK releases by @roele in [#6382](jdx/mise#6382) ### 🐛 Bug Fixes - **(toolset)** handle underflow in version_sub function by @koh-sh in [#6389](jdx/mise#6389) ### 📚 Documentation - document MISE_ENV behavior for global/system configs by @jdx in [#6385](jdx/mise#6385) ### New Contributors - @jc00ke made their first contribution in [#6386](jdx/mise#6386) - @koh-sh made their first contribution in [#6389](jdx/mise#6389)
## [2025.9.18](https://github.com/jdx/mise/compare/v2025.9.17..v2025.9.18) - 2025-09-24 ### 📦 Registry - replace amplify-cli github backend with ubi by @eggplants in [#6396](jdx/mise#6396) ### 🚀 Features - **(template)** add read_file() function by @jdx in [#6400](jdx/mise#6400) ### 🐛 Bug Fixes - **(aqua)** support github_artifact_attestations.enabled by @risu729 in [#6372](jdx/mise#6372) - use /c instead of -c on windows in postinstall hook by @risu729 in [#6397](jdx/mise#6397) ### 🧪 Testing - **(test-tool)** uninstall all versions and clear cache before installation by @jdx in [#6393](jdx/mise#6393) ### New Contributors - @eggplants made their first contribution in [#6396](jdx/mise#6396) ## [2025.9.17](https://github.com/jdx/mise/compare/v2025.9.16..v2025.9.17) - 2025-09-24 ### 🚀 Features - **(java)** add support for Liberica NIK releases by @roele in [#6382](jdx/mise#6382) ### 🐛 Bug Fixes - **(toolset)** handle underflow in version_sub function by @koh-sh in [#6389](jdx/mise#6389) ### 📚 Documentation - document MISE_ENV behavior for global/system configs by @jdx in [#6385](jdx/mise#6385) ### New Contributors - @jc00ke made their first contribution in [#6386](jdx/mise#6386) - @koh-sh made their first contribution in [#6389](jdx/mise#6389)
Summary
read_file(path)that reads file contents relative to config_rootUse Case
This allows configuration files to dynamically include content from external files during template rendering. For example:
Example Usage
Test Plan
🤖 Generated with Claude Code