Allow glob literals in filenames (#44547)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #43598 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests - [X] QA'd all new/changed functionality manually - [X] added a script file `some-*-script[].sh` and referred to it in a gitops file using `path:`. Failed on main; on this branch it successfully uploaded the script - [X] still got expected error message when using `path: ` with a value that had glob characters that _didn't_ match an actual file - [X] `paths:` still worked and uploaded multiple files, including `some-*-script[].sh` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Fixed path validation in fleetctl gitops so path values containing glob metacharacters (e.g., brackets, asterisks, question marks) are accepted when a literal file with that name exists on disk; missing files still produce the appropriate error. * **Tests** * Added regression tests covering glob metacharacter handling in path validation. [](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/44547) <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1 @@
|
||||
- Fixed an issue where `fleetctl gitops` rejected `path:` values whose actual filenames contained glob metacharacters even when the file existed at that literal path.
|
||||
+14
-4
@@ -1297,11 +1297,21 @@ func expandBaseItems[T any, PT interface {
|
||||
result = append(result, entity)
|
||||
// Single path -- resolve to absolute path and add to result.
|
||||
case hasPath:
|
||||
if containsGlobMeta(*baseItem.Path) {
|
||||
errs = append(errs, fmt.Errorf(`%s "path" %q contains glob characters; use "paths" for glob patterns`, entityType, *baseItem.Path))
|
||||
continue
|
||||
}
|
||||
resolved := resolveApplyRelativePath(baseDir, *baseItem.Path)
|
||||
// Reject glob metacharacters in "path:" only when the literal path
|
||||
// does not resolve to an existing file. This allows filenames that
|
||||
// contain literal glob metacharacters (e.g. Windows CSP names like
|
||||
// "[AllowSpotlightCollection].xml") to be referenced via "path:".
|
||||
if containsGlobMeta(*baseItem.Path) {
|
||||
if _, err := os.Stat(resolved); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
errs = append(errs, fmt.Errorf(`%s "path" %q contains glob characters; use "paths" for glob patterns`, entityType, *baseItem.Path))
|
||||
} else {
|
||||
errs = append(errs, fmt.Errorf("failed to stat %s path %q: %w", entityType, resolved, err))
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Check for duplicate filenames if requested.
|
||||
if opts.RequireUniqueBasenames {
|
||||
base := filepath.Base(resolved)
|
||||
|
||||
@@ -2217,6 +2217,41 @@ func TestExpandBaseItems(t *testing.T) {
|
||||
requireErrorContains(t, errs, `contains glob characters`)
|
||||
})
|
||||
|
||||
// Filenames containing glob metacharacters should be accepted by "path:"
|
||||
// when the literal file exists on disk. Common with Windows MDM CSP
|
||||
// profile names like "[AllowSpotlightCollection].xml". Regression test for
|
||||
// fleetdm/fleet#43598.
|
||||
t.Run("path_with_literal_glob_meta_chars_existing_file", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
dir := t.TempDir()
|
||||
filenames := []string{
|
||||
"AllowRebootless -[Updates].xml",
|
||||
"profile{a,b}.xml",
|
||||
}
|
||||
for _, name := range filenames {
|
||||
require.NoError(t, os.WriteFile(filepath.Join(dir, name), []byte(""), 0o644))
|
||||
}
|
||||
|
||||
items := make([]fleet.BaseItem, 0, len(filenames))
|
||||
for _, name := range filenames {
|
||||
items = append(items, fleet.BaseItem{Path: ptr.String(name)}) //nolint:modernize
|
||||
}
|
||||
result, errs := expandBaseItems(items, dir, "test", GlobExpandOptions{})
|
||||
require.Empty(t, errs)
|
||||
require.Len(t, result, len(filenames))
|
||||
for i, name := range filenames {
|
||||
assert.Equal(t, filepath.Join(dir, name), *result[i].Path)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("path_with_glob_meta_chars_missing_file_error", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
dir := t.TempDir()
|
||||
items := []fleet.BaseItem{{Path: ptr.String("does-not-[exist].xml")}} //nolint:modernize
|
||||
_, errs := expandBaseItems(items, dir, "test", GlobExpandOptions{})
|
||||
requireErrorContains(t, errs, `contains glob characters`)
|
||||
})
|
||||
|
||||
t.Run("both_path_and_paths_error", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
items := []fleet.BaseItem{{Path: ptr.String("foo.yml"), Paths: ptr.String("*.yml")}} //nolint:modernize
|
||||
|
||||
Reference in New Issue
Block a user