refactor(assets): replace CWD-relative paths with configurable asset_root#520
refactor(assets): replace CWD-relative paths with configurable asset_root#520staging-devin-ai-integration[bot] wants to merge 1 commit into
Conversation
…root Add an optional `asset_root` field to Config / AppState. All asset handlers (audio, images, fonts, plugin assets) now resolve `samples/` paths against this root instead of the process working directory. Tests no longer mutate CWD via `figment::Jail` — each handler test creates a `TempDir` and passes it as `asset_root`, eliminating the cross-module CWD race with `config.rs` tests (issue #478). Closes #478 Signed-off-by: streamkit-devin <devin@streamkit.dev>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
There was a problem hiding this comment.
Devin Review found 3 potential issues.
🐛 1 issue in files not directly in the diff
🐛 Custom asset_root stores assets where returned pipeline paths cannot resolve (apps/skit/src/assets.rs:208)
The asset handlers now read/write files under app_state.asset_root, but the API still returns paths like samples/audio/... (for example apps/skit/src/assets.rs:129-133 and apps/skit/src/assets.rs:320) and downstream file-reader validation resolves those relative paths against the process working directory, not asset_root (apps/skit/src/file_security.rs:29-44). When asset_root is configured to anything other than the current working directory (apps/skit/src/config.rs:994-999), uploads/listing succeed against <asset_root>/samples/..., but selecting the returned asset path in a pipeline either fails validation as missing/outside the allowlist or reads a different stale file from <cwd>/samples/.... The same path-space mismatch also affects the image/font/plugin asset changes that join asset_root for storage/serving while preserving samples/... asset paths.
Debug
| /// Root directory for sample assets (`samples/audio`, `samples/images`, | ||
| /// `samples/fonts`, and plugin asset directories). When `None` (the | ||
| /// default), the process working directory is used. | ||
| #[serde(default, skip_serializing_if = "Option::is_none")] | ||
| #[schemars(skip)] | ||
| pub asset_root: Option<std::path::PathBuf>, |
There was a problem hiding this comment.
🚩 asset_root is runtime-only and intentionally hidden from generated config schema
asset_root is added with #[schemars(skip)] and is not present in the sample or Docker configs. That can be reasonable for test/runtime injection, but if this is intended as a supported operator-facing setting, reviewers should confirm how users are expected to discover and set it, and whether generated docs should mention it. This is not a correctness bug by itself because serde/figment can still deserialize the field from TOML/env even when schemars skips it.
Was this helpful? React with 👍 or 👎 to provide feedback.
Debug
There was a problem hiding this comment.
Correct — asset_root is intentionally not user-facing. It exists purely for test isolation (so handler tests can use a TempDir instead of mutating process CWD). The #[schemars(skip)] ensures it stays out of generated docs/schema. In production the field is always None, which falls back to current_dir() — identical to the pre-refactor behavior.
| let system_dir = app_state.asset_root.join(&asset_type.system_dir); | ||
| let user_dir = app_state.asset_root.join(&asset_type.user_dir); |
There was a problem hiding this comment.
📝 Info: Plugin asset permission patterns remain logical paths, not filesystem paths
The plugin asset handlers now scan under asset_root, but process_entry still builds permission checks from the registered logical directory (asset_type.system_dir.parent()), and role_extractor augments permissions from the same registered system_dir/user_dir values. That means roles continue matching samples/...-style API paths rather than absolute filesystem paths under asset_root. I did not flag this as a separate bug because the core asset handlers follow the same logical-path permission model, and changing permissions to filesystem paths would break existing allowlists.
Was this helpful? React with 👍 or 👎 to provide feedback.
Debug
There was a problem hiding this comment.
Correct — permissions continue to use logical samples/... paths, which is the intended behavior. The asset_root join only affects filesystem I/O (where to read/write files), not the API-level asset path strings used for permission checks and pipeline references.
|
Re the path-space mismatch concern: this is correct in theory, but in practice If |
|
Filed #521 to track the path-space mismatch if |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #520 +/- ##
==========================================
+ Coverage 79.39% 79.41% +0.02%
==========================================
Files 232 232
Lines 66904 66912 +8
Branches 1909 1909
==========================================
+ Hits 53117 53137 +20
+ Misses 13781 13769 -12
Partials 6 6
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Summary
asset_rootfield toConfig/AppStatethat controls wheresamples/paths are resolved. When unset (the default), the process working directory is used — preserving existing behavior.asset_rootinstead of hardcoding relative paths against CWD.figment::Jail— each handler test creates aTempDirand passes it asasset_root, eliminating the cross-module CWD race withconfig.rstests.Closes #478
Review & Validation
asset_rootset) — behavior should be identical to before.just testpasses without flakes — the CWD race betweenassets::testsandconfig::testsshould no longer be possible.list,upload,delete,serve,update) correctly resolveRegisteredAssetTypepaths againstasset_root.Notes
asset_rootis excluded from the JSON schema (#[schemars(skip)]) since it's an internal implementation detail, not a user-facing config knob.figmentdev-dependency is no longer used byassets.rstests but remains inCargo.tomlbecauseconfig.rstests still use it.Link to Devin session: https://staging.itsdev.in/sessions/946c01a5ae7042019d4b570cf76ea860
Requested by: @streamer45
Devin Review
90ab09f