Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(oscal): link remapper method component defn #879

Merged
merged 23 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ac1e4ec
feat: added OSCALModel impl for compdef
meganwolf0 Jan 13, 2025
9005d78
fix: err handling
meganwolf0 Jan 13, 2025
d3ac877
Merge branch 'main' into 747-oscalmodel-interface-implementation-for-…
meganwolf0 Jan 13, 2025
98bbb25
test: updated component and ssp tests
meganwolf0 Jan 14, 2025
1dcd78f
fix: removed NewOscalComponentDefn
meganwolf0 Jan 14, 2025
5f6be3f
feat: added oscalmodel for assessment results
meganwolf0 Jan 14, 2025
296192f
fix: updated declaration syntax
meganwolf0 Jan 14, 2025
9c90ab0
Merge branch '748-oscalmodel-interface-implementation-for-assessment-…
meganwolf0 Jan 14, 2025
c3eb583
feat: added RewritePaths method on compdef
meganwolf0 Jan 15, 2025
91734a7
fix: err handling
meganwolf0 Jan 15, 2025
351701f
Merge remote-tracking branch 'origin/main' into 878-link-remapper-met…
meganwolf0 Jan 21, 2025
17254c9
fix: updated handling opaque files
meganwolf0 Jan 21, 2025
fc14483
feat: updated method to identify path rewrites
meganwolf0 Jan 23, 2025
ea09669
fix: removed copypasta
meganwolf0 Jan 23, 2025
458f73a
fix: removed test change
meganwolf0 Jan 23, 2025
32fcdd8
Merge branch 'main' into 878-link-remapper-method-component-defn
meganwolf0 Jan 23, 2025
f687f4e
Merge branch 'main' into 878-link-remapper-method-component-defn
meganwolf0 Jan 24, 2025
ff78d2a
feat: disaggregated rewrite fcns
meganwolf0 Jan 24, 2025
6d4a4ad
Merge branch '878-link-remapper-method-component-defn' of https://git…
meganwolf0 Jan 24, 2025
f49081e
fix: reverse files
meganwolf0 Jan 27, 2025
219e317
Merge branch 'main' into 878-link-remapper-method-component-defn
meganwolf0 Jan 27, 2025
06da95f
fix: fcn name
meganwolf0 Jan 27, 2025
62f637a
Merge branch 'main' into 878-link-remapper-method-component-defn
meganwolf0 Jan 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
goversion "github.com/hashicorp/go-version"
"k8s.io/apimachinery/pkg/util/yaml"

"github.com/defenseunicorns/lula/src/pkg/common/network"
"github.com/defenseunicorns/lula/src/pkg/domains/api"
"github.com/defenseunicorns/lula/src/pkg/domains/files"
kube "github.com/defenseunicorns/lula/src/pkg/domains/kubernetes"
Expand Down Expand Up @@ -211,3 +212,39 @@ func CleanMultilineString(str string) string {
formatted := re.ReplaceAllString(str, "\n")
return formatted
}

// RemapPath takes an input path, relative to the baseDir, and remaps it to be relative to the newDir
// Example: path = "folder/file.txt", baseDir = "/home/user/dir", newDir = "/home/user/newDir"
// output path = "../dir/folder/file.txt"
func RemapPath(path string, baseDir string, newDir string) (string, error) {
// Do nothing if the path is a UUID reference
if isUUIDReference(path) {
return path, nil
}

// Return if the path is a URL or absolute link
localDir := network.GetLocalFileDir(path, baseDir)
if localDir == "" {
return path, nil
}

// Trim file:// or file:, if present
path = strings.TrimPrefix(strings.TrimPrefix(path, "file://"), "file:")

// Find the relative path from newDir to baseDir
relativePath, err := filepath.Rel(newDir, baseDir)
if err != nil {
return "", err
}

// Append the original relative path to the computed relative path
remappedPath := filepath.Join(relativePath, path)
remappedPath = filepath.Clean(remappedPath)

return remappedPath, nil
}

func isUUIDReference(path string) bool {
path = strings.TrimPrefix(path, UUID_PREFIX)
return checkValidUuid(path)
}
115 changes: 115 additions & 0 deletions src/pkg/common/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,113 @@ func TestIsVersionValid(t *testing.T) {
}
}

func TestRemapPath(t *testing.T) {
tests := []struct {
name string
path string
baseDir string
newDir string
expectedPath string
expectedError bool
}{
{
name: "Absolute Path",
path: "/path/to/file.txt",
baseDir: "/path/to",
newDir: "/new/path",
expectedPath: "/path/to/file.txt",
expectedError: false,
},
{
name: "Relative Path",
path: "path/to/file.txt",
baseDir: "/app",
newDir: "/app2",
expectedPath: "../app/path/to/file.txt",
expectedError: false,
},
{
name: "Relative Path with ..",
path: "../path/to/file.txt",
baseDir: "/app/sub-path",
newDir: "/app",
expectedPath: "path/to/file.txt",
expectedError: false,
},
{
name: "Relative Path with deep nesting",
path: "../../file.txt",
baseDir: "/app/path/to/caller",
newDir: "/app",
expectedPath: "path/file.txt",
expectedError: false,
},
{
name: "Relative Path with file://",
path: "file://path/to/file.txt",
baseDir: "/app",
newDir: "/app2",
expectedPath: "../app/path/to/file.txt",
expectedError: false,
},
{
name: "Relative Path with file:",
path: "file:file.txt",
baseDir: "/app",
newDir: "/app2",
expectedPath: "../app/file.txt",
expectedError: false,
},
{
name: "Absolute Path with file://",
path: "file:///path/to/file.txt",
baseDir: "/path/to",
newDir: "/new/path",
expectedPath: "file:///path/to/file.txt",
expectedError: false,
},
{
name: "UUID",
path: "#0a2b9722-06ce-446f-85e5-cdfe2fe70975",
baseDir: "/path/to",
newDir: "/new/path",
expectedPath: "#0a2b9722-06ce-446f-85e5-cdfe2fe70975",
expectedError: false,
},
{
// This doesn't error because there's no check in the function to validate the path
// I think this is ok, because the old path wouldn't work anyway, so the new path not working doesn't matter(?)
name: "Invalid path remap",
path: "../../path/to/file.txt",
baseDir: "/app",
newDir: "/app2",
expectedPath: "../../path/to/file.txt",
expectedError: false,
},
{
// Similar logic to previous case: This doesn't error because there's no check in the function to validate the path
name: "Invalid path name",
path: "inv@1*d pa#h",
baseDir: "/app",
newDir: "/app2",
expectedPath: "../app/inv@1*d pa#h",
expectedError: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotPath, err := common.RemapPath(tt.path, tt.baseDir, tt.newDir)
if (err != nil) != tt.expectedError {
t.Errorf("RemapPath() error = %v, wantErr %v", err, tt.expectedError)
return
}
require.Equal(t, tt.expectedPath, gotPath)
})
}

}

func FuzzPrefix(f *testing.F) {
f.Add("uuid")
f.Add("149f0049-7a3c-4e4d-8431-bec3a55f31d9")
Expand All @@ -549,3 +656,11 @@ func FuzzReadValidationsFromYaml(f *testing.F) {
common.ReadValidationsFromYaml(a)
})
}

func FuzzRemapPath(f *testing.F) {
mildwonkey marked this conversation as resolved.
Show resolved Hide resolved
f.Add("foo", "bar", "baz")

f.Fuzz(func(t *testing.T, a string, b string, c string) {
common.RemapPath(a, b, c)
})
}
42 changes: 31 additions & 11 deletions src/pkg/common/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,25 +156,45 @@ func FetchLocalFile(url *url.URL, config *fetchOpts) ([]byte, error) {
return bytes, err
}

// GetLocalFileDir returns the directory of a local file
// See URL for reference: https://pkg.go.dev/net/url#URL
// Intent of check is to handle different specifications of file paths:
// - file:///path/to/file
// - file:my-file.txt
// - ./path/to/file
// - /path/to/file
// - https://example.com/path/to/file
// ** This will not work for Windows file paths, but Lula doesn't run on Windows for now
func GetLocalFileDir(inputURL, baseDir string) string {
url, err := url.Parse(inputURL)
if err != nil {
return ""
}
requestUri := url.RequestURI()

// Intent of check is to handle different specifications of file paths:
// - file:///path/to/file
// - ./path/to/file
// - /path/to/file
// - https://example.com/path/to/file
if url.Scheme == "file" || !url.IsAbs() {
fullPath := filepath.Join(baseDir, url.Host, requestUri)
if _, err := os.Stat(fullPath); err == nil {
return filepath.Dir(fullPath)
if url.Scheme == "file" {
// If the scheme is file, check if the path is absolute
// To check absolute path, check both the host and the opaque fields
if url.Opaque != "" {
return handlePath(url.Opaque, baseDir)
}
if url.Host == "" {
return ""
}
} else if url.Scheme != "" {
return ""
}
return ""

return handlePath(filepath.Join(url.Host, url.RequestURI()), baseDir)
}

func handlePath(path, baseDir string) string {
mildwonkey marked this conversation as resolved.
Show resolved Hide resolved
if filepath.IsAbs(path) {
return ""
}

fullPath := filepath.Join(baseDir, path)

return filepath.Dir(fullPath)
}

// ValidateChecksum validates a given checksum against a given []bytes.
Expand Down
73 changes: 73 additions & 0 deletions src/pkg/common/network/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,76 @@ func TestParseChecksum(t *testing.T) {
})
}
}

func TestGetLocalFileDir(t *testing.T) {
tests := []struct {
name string
inputFile string
baseDir string
expectedDir string
}{
{
name: "Absolute Path",
inputFile: "/root/path/to/file.txt",
baseDir: "/root",
expectedDir: "",
},
{
name: "Relative Path",
inputFile: "path/to/file.txt",
baseDir: "/root",
expectedDir: "/root/path/to",
},
{
name: "http URL",
inputFile: "https://example.com/path/to/file.txt",
baseDir: "/path/to",
expectedDir: "",
},
{
name: "Relative Path with ..",
inputFile: "../path/to/file.txt",
baseDir: "/root/path",
expectedDir: "/root/path/to",
},
{
name: "Relative Path with file://",
inputFile: "file://path/to/file.txt",
baseDir: "/root",
expectedDir: "/root/path/to",
},
{
name: "Relative Path with file://..",
inputFile: "file://../path/to/file.txt",
baseDir: "/root/path",
expectedDir: "/root/path/to",
},
{
name: "Absolute Path with file://",
inputFile: "file:///root/path/to/file.txt",
baseDir: "/root",
expectedDir: "",
},
{
name: "Opaque absolute Path",
inputFile: "file:/root/path/to/file.txt",
baseDir: "/root",
expectedDir: "",
},
{
name: "Opaque relative Path",
inputFile: "file:to/file.txt",
baseDir: "/root/path",
expectedDir: "/root/path/to",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotDir := network.GetLocalFileDir(tt.inputFile, tt.baseDir)
if tt.expectedDir != gotDir {
t.Errorf("GetLocalFileDir() gotDir = %v, want %v", gotDir, tt.expectedDir)
}
})
}
}
Loading
Loading