fix: resolve workspace file browser to groves/ instead of projects/#302
fix: resolve workspace file browser to groves/ instead of projects/#302ptone wants to merge 3 commits into
Conversation
The Hub UI file browser was showing the wrong directory contents. The hubManagedProjectPath() function resolved workspace paths to ~/.scion/projects/<slug>/ (project metadata) instead of ~/.scion/groves/<slug>/ (the actual git checkout mounted as /workspace in agents). Reverse the lookup priority: check groves/ first, fall back to projects/, and default to groves/ when neither has content. Fixes #130
There was a problem hiding this comment.
Code Review
This pull request resolves a workspace file browser path resolution issue by reversing the lookup priority in hubManagedProjectPath() to prefer the actual git checkout directory (groves/<slug>) over the metadata directory (projects/<slug>). The changes also include updated and new unit tests to verify this behavior. The review feedback suggests adding a defensive check to prevent empty slugs from resolving to parent directories, which could lead to unintended operations, along with a corresponding unit test to verify this validation.
| func hubManagedProjectPath(slug string) (string, error) { | ||
| globalDir, err := config.GetGlobalDir() |
There was a problem hiding this comment.
An empty slug passed to hubManagedProjectPath could resolve to the parent directory (e.g., ~/.scion/groves or ~/.scion/projects). Since hasWorkspaceContent checks if the directory contains any files other than .scion or shared-dirs, a parent directory containing other projects would return true, causing the function to incorrectly return the parent directory. This could lead to catastrophic operations (like directory deletion or overwriting) on the entire parent directory. Adding a defensive check for an empty slug prevents this.
| func hubManagedProjectPath(slug string) (string, error) { | |
| globalDir, err := config.GetGlobalDir() | |
| func hubManagedProjectPath(slug string) (string, error) { | |
| if slug == "" { | |
| return "", errors.New("project slug cannot be empty") | |
| } | |
| globalDir, err := config.GetGlobalDir() |
| // When neither has content, should default to groves/ | ||
| path, err := hubManagedProjectPath(slug) | ||
| require.NoError(t, err) | ||
| assert.Equal(t, grovesDir, path, "should fall back to groves path when projects dir only contains infrastructure dirs") | ||
| assert.Equal(t, grovesDir, path, "should default to groves path when neither dir has workspace content") | ||
| } |
There was a problem hiding this comment.
Add a unit test to verify that hubManagedProjectPath returns an error when an empty slug is provided, ensuring the defensive check works as expected.
// When neither has content, should default to groves/
path, err := hubManagedProjectPath(slug)
require.NoError(t, err)
assert.Equal(t, grovesDir, path, "should default to groves path when neither dir has workspace content")
}
func TestHubManagedProjectPath_EmptySlug(t *testing.T) {
_, err := hubManagedProjectPath("")
assert.Error(t, err)
assert.Contains(t, err.Error(), "project slug cannot be empty")
}Prevent hubManagedProjectPath from resolving to the parent directory when called with an empty slug. Add unit test for this case.
Summary
hubManagedProjectPath()now resolves to~/.scion/groves/<slug>/(the actual git checkout mounted as/workspacein agents) instead of~/.scion/projects/<slug>/(which only contains project metadata and Telegram plugin downloads)groves/has no workspace content, falls back toprojects/for backward compatibilitygroves/path instead ofprojects/Fixes issue 130
Test plan
TestHubManagedProjectPath— default path now resolves togroves/TestHubManagedProjectPath_PrefersGrovesOverProjects— when both dirs have content,groves/winsTestHubManagedProjectPath_FallsBackToProjectsWhenGrovesEmpty— falls back toprojects/whengroves/has no real contentTestHubManagedProjectPath_DefaultsToGrovesWhenNeitherHasContent— defaults togroves/when neither has content