pax_global_header00006660000000000000000000000064151544766470014535gustar00rootroot0000000000000052 comment=a6bdd0f7b6837f0fcbd1847c0f280a6d6c7ab39d golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/000077500000000000000000000000001515447664700225655ustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/.github/000077500000000000000000000000001515447664700241255ustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/.github/workflows/000077500000000000000000000000001515447664700261625ustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/.github/workflows/go.yml000066400000000000000000000010111515447664700273030ustar00rootroot00000000000000# This workflow will build a golang project # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go name: Go on: push: branches: [ "main" ] pull_request: branches: [ "main" ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Go uses: actions/setup-go@v3 with: go-version: 1.19 - name: Build run: go build -v ./... - name: Test run: go test -v ./... golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/.gitignore000066400000000000000000000004151515447664700245550ustar00rootroot00000000000000# Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/LICENSE000066400000000000000000000261351515447664700236010ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/README.md000066400000000000000000000031251515447664700240450ustar00rootroot00000000000000# omnitrail-go ## Overview Omnitrail-go is a Go library designed to manage and track file and directory metadata, including permissions, ownership, and cryptographic hashes. It supports various plugins to handle different types of metadata and hashing algorithms. ## Features - **File Plugin**: Computes SHA1, SHA256, and Gitoid hashes for files. - **Directory Plugin**: Manages directory structures and computes Gitoid hashes for directories. - **Posix Plugin**: Tracks POSIX file permissions, ownership, and size. ## Installation To install the library, use the following command: ```sh go get github.com/yourusername/omnitrail-go ``` ## Usage ### Creating a New Trail To create a new trail, use the `NewTrail` function: ```go import "github.com/yourusername/omnitrail-go" trail := omnitrail.NewTrail() ``` ### Adding Files and Directories To add files and directories to the trail, use the `Add` method: ```go err := trail.Add("/path/to/file_or_directory") if err != nil { log.Fatalf("Failed to add path: %v", err) } ``` ### Generating ADG Strings To generate ADG strings, use the `FormatADGString` function: ```go adgString := omnitrail.FormatADGString(trail) fmt.Println(adgString) ``` ## Testing To run the tests, use the following command: ```sh go test ./... ``` ## License This project is licensed under the ApacheV2 License. See the [LICENSE](LICENSE) file for details. ## Contributing Contributions are welcome! Please open an issue or submit a pull request for any changes. ## Acknowledgements Special thanks to all contributors and the open-source community for their support. golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/definitions.go000066400000000000000000000036141515447664700254330ustar00rootroot00000000000000package omnitrail type Envelope struct { Header Header `json:"header"` Mapping map[string]*Element `json:"mapping"` } type Header struct { Features map[string]Feature `json:"features"` } type Feature struct { Algorithms []string `json:"algorithms,omitempty"` } type Element struct { Type string `json:"type"` Sha1 string `json:"sha1,omitempty"` Sha256 string `json:"sha256,omitempty"` Sha1Gitoid string `json:"gitoid:sha1,omitempty"` Sha256Gitoid string `json:"gitoid:sha256,omitempty"` Posix *Posix `json:"posix,omitempty"` } type Posix struct { ATime string `json:"atime,omitempty"` CTime string `json:"ctime,omitempty"` CreationTime string `json:"creation_time,omitempty"` ExtendedAttributes string `json:"extended_attributes,omitempty"` FileDeviceID string `json:"file_device_id,omitempty"` FileFlags string `json:"file_flags,omitempty"` FileInode string `json:"file_inode,omitempty"` FileSystemID string `json:"file_system_id,omitempty"` FileType string `json:"file_type,omitempty"` HardLinkCount string `json:"hard_link_count,omitempty"` MTime string `json:"mtime,omitempty"` MetadataCTime string `json:"metadata_ctime,omitempty"` OwnerGID string `json:"owner_gid,omitempty"` OwnerUID string `json:"owner_uid,omitempty"` Permissions string `json:"permissions,omitempty"` Size string `json:"size,omitempty"` } type Factory interface { Add(originalPath string) error Sha1ADGs() map[string]string Sha256ADGs() map[string]string Envelope() *Envelope } type Option func(o *Options) type Options struct { Sha1Enabled bool Sha256Enabled bool } type Plugin interface { Add(path string) error Store(envelope *Envelope) error Sha1ADG(map[string]string) Sha256ADG(map[string]string) SetAllowList([]string) } golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/directory_plugin.go000066400000000000000000000110121515447664700264710ustar00rootroot00000000000000package omnitrail import ( "fmt" "os" "path/filepath" "sort" "strings" "github.com/omnibor/omnibor-go" ) type DirectoryPlugin struct { algorithms []string // algorithm -> path -> hash directories map[string]bool sha1adgs map[string]omnibor.ArtifactTree sha256adgs map[string]omnibor.ArtifactTree AllowList []string } func (plug *DirectoryPlugin) isAllowedDirectory(path string) bool { for _, allowedPath := range plug.AllowList { if strings.HasPrefix(path, allowedPath) { return true } } return false } func (plug *DirectoryPlugin) Sha1ADG(m map[string]string) { for _, v := range plug.sha1adgs { m[v.Identity()] = v.String() } } func (plug *DirectoryPlugin) Sha256ADG(m map[string]string) { for _, v := range plug.sha256adgs { m[v.Identity()] = v.String() } } func (plug *DirectoryPlugin) Add(path string) error { // if this is a broken symlink, ignore fileInfo, err := os.Lstat(path) if err != nil { // if it's a symlink and the symlink is bad, ignore and return if os.IsNotExist(err) { return nil } return err } if fileInfo.Mode()&os.ModeSymlink != 0 { // path is a symlink targetPath, err := os.Readlink(path) if err != nil { // if it's a symlink and the symlink is bad, ignore and return if os.IsNotExist(err) { return nil } return err } if !filepath.IsAbs(targetPath) { targetPath = filepath.Join(filepath.Dir(path), targetPath) } if !plug.isAllowedDirectory(targetPath) { return fmt.Errorf("path %s is not in the allow list", path) } if _, err := os.Stat(targetPath); err != nil { return nil } } stat, err := os.Stat(path) if err != nil { return err } if stat.IsDir() { plug.directories[path] = true } return nil } func (plug *DirectoryPlugin) Store(envelope *Envelope) error { envelope.Header.Features["directory"] = Feature{Algorithms: plug.algorithms} // get a list of all keys from plug.directories keys := make([]string, 0, len(plug.directories)) for path := range plug.directories { keys = append(keys, path) } var sha1tree map[string]omnibor.ArtifactTree var sha256tree map[string]omnibor.ArtifactTree for _, algorithm := range plug.algorithms { switch algorithm { case "gitoid:sha1": sha1tree = make(map[string]omnibor.ArtifactTree) case "gitoid:sha256": sha256tree = make(map[string]omnibor.ArtifactTree) default: continue } } for _, key := range keys { if sha1tree != nil { sha1tree[key] = omnibor.NewSha1OmniBOR() } if sha256tree != nil { sha256tree[key] = omnibor.NewSha256OmniBOR() } } for path, element := range envelope.Mapping { dir := filepath.Dir(path) if _, ok := sha1tree[dir]; ok { err := sha1tree[dir].AddExistingReference(element.Sha1Gitoid) if err != nil { return err } err = sha256tree[dir].AddExistingReference(element.Sha256Gitoid) if err != nil { return err } } } // sort the keys from the longest length to the shortest length sort.Slice(keys, func(i, j int) bool { return len(keys[i]) > len(keys[j]) }) if sha1tree != nil { err := plug.addKeysToTree(keys, sha1tree) if err != nil { return err } } if sha256tree != nil { err := plug.addKeysToTree(keys, sha256tree) if err != nil { return err } } for key, value := range sha1tree { if _, ok := envelope.Mapping[key]; !ok { envelope.Mapping[key] = &Element{ Type: "directory", } } e := envelope.Mapping[key] e.Sha1Gitoid = value.Identity() envelope.Mapping[key] = e } for key, value := range sha256tree { if _, ok := envelope.Mapping[key]; !ok { envelope.Mapping[key] = &Element{ Type: "directory", } } e := envelope.Mapping[key] e.Sha256Gitoid = value.Identity() envelope.Mapping[key] = e } for k, v := range sha1tree { plug.sha1adgs[k] = v } for k, v := range sha256tree { plug.sha256adgs[k] = v } return nil } func (plug *DirectoryPlugin) addKeysToTree(keys []string, tree map[string]omnibor.ArtifactTree) error { for _, key := range keys { dir := filepath.Dir(key) if _, ok := tree[dir]; ok { err := tree[dir].AddExistingReference(tree[key].Identity()) if err != nil { return err } } } return nil } func (plug *DirectoryPlugin) SetAllowList(allowList []string) { plug.AllowList = allowList } func NewDirectoryPlugin() Plugin { algorithms := []string{"gitoid:sha1", "gitoid:sha256"} sort.Strings(algorithms) return &DirectoryPlugin{ algorithms: algorithms, directories: make(map[string]bool), sha1adgs: make(map[string]omnibor.ArtifactTree), sha256adgs: make(map[string]omnibor.ArtifactTree), } } golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/factory.go000066400000000000000000000036621515447664700245720ustar00rootroot00000000000000package omnitrail import ( "io/fs" "path/filepath" "sort" ) type factoryImpl struct { Options *Options envelope *Envelope Plugins []Plugin AllowList []string } func (factory *factoryImpl) Add(originalPath string) error { // Convert the path to an absolute path absPath, err := filepath.Abs(originalPath) if err != nil { return err } // Add the absolute path to the allow list factory.AllowList = append(factory.AllowList, absPath) // For each plugin, add the allow list for _, plugin := range factory.Plugins { plugin.SetAllowList(factory.AllowList) } // check if path already exists in the envelope, if so, return if _, ok := factory.envelope.Mapping[originalPath]; ok { return nil } err = filepath.WalkDir(originalPath, func(path string, d fs.DirEntry, err error) error { path, err = filepath.Abs(path) if err != nil { return err } for _, plugin := range factory.Plugins { err := plugin.Add(path) if err != nil { return err } } return nil }) if err != nil { return err } // Generate ADGs for directories // collect all keys in the map var keys []string for k := range factory.envelope.Mapping { keys = append(keys, k) } // sort keys by lexical order sort.Strings(keys) // stable sort keys by length sort.SliceStable(keys, func(i, j int) bool { return len(keys[i]) > len(keys[j]) }) for _, plugin := range factory.Plugins { err := plugin.Store(factory.envelope) if err != nil { return err } } return nil } func (factory *factoryImpl) Sha1ADGs() map[string]string { m := make(map[string]string) for _, plugin := range factory.Plugins { plugin.Sha1ADG(m) } return m } // Sha256ADGs return sha256 omnibor objects func (factory *factoryImpl) Sha256ADGs() map[string]string { m := make(map[string]string) for _, plugin := range factory.Plugins { plugin.Sha256ADG(m) } return m } func (factory *factoryImpl) Envelope() *Envelope { return factory.envelope } golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/file_plugin.go000066400000000000000000000077401515447664700254210ustar00rootroot00000000000000package omnitrail import ( "crypto/sha1" "crypto/sha256" "fmt" "io" "os" "path/filepath" "sort" "strings" "github.com/edwarnicke/gitoid" ) type FilePlugin struct { algorithms []string files map[string]map[string]string AllowList []string } func (plug *FilePlugin) isAllowedDirectory(path string) bool { for _, allowedPath := range plug.AllowList { if strings.HasPrefix(path, allowedPath) { return true } } return false } func (plug *FilePlugin) Sha1ADG(m map[string]string) { for algo, files := range plug.files { if algo == "gitoid:sha1" { for _, adg := range files { m[adg] = "" } } } } func (plug *FilePlugin) Sha256ADG(m map[string]string) { for algo, files := range plug.files { if algo == "gitoid:sha256" { for _, adg := range files { m[adg] = "" } } } } func (plug *FilePlugin) SetAllowList(allowList []string) { plug.AllowList = allowList } func NewFilePlugin() Plugin { algorithms := []string{"sha1", "sha256", "gitoid:sha1", "gitoid:sha256"} sort.Strings(algorithms) files := make(map[string]map[string]string) for _, algorithms := range algorithms { files[algorithms] = make(map[string]string) } return &FilePlugin{ algorithms: algorithms, files: files, } } func (plug *FilePlugin) Add(filePath string) error { // ignore broken symlink localFileInfo, err := os.Lstat(filePath) if err != nil { // if it's a symlink and the symlink is bad, ignore and return if os.IsNotExist(err) { return nil } return err } if localFileInfo.Mode()&os.ModeSymlink != 0 { targetPath, err := os.Readlink(filePath) if err != nil { // if it's a symlink and the symlink is bad, ignore and return if os.IsNotExist(err) { return nil } fmt.Println("returning err: ", err) return err } if !filepath.IsAbs(targetPath) { targetPath = filepath.Join(filepath.Dir(filePath), targetPath) } if !plug.isAllowedDirectory(targetPath) { return fmt.Errorf("path %s is not in the allow list", filePath) } if _, err = os.Stat(targetPath); err != nil { return nil } } fileInfo, err := os.Stat(filePath) // if file is a symlink and the symlink points to a broken path, return nil if err != nil { return err } if fileInfo.IsDir() { return nil } file, err := os.Open(filePath) if err != nil { return err } // explicitly ignore error from closing file defer func(file *os.File) { _ = file.Close() }(file) for _, hashAlgo := range plug.algorithms { _, err := file.Seek(0, 0) if err != nil { return err } if strings.HasPrefix(hashAlgo, "gitoid:") { var hashResult *gitoid.GitOID switch hashAlgo { case "gitoid:sha1": hashResult, err = gitoid.New(file, gitoid.WithContentLength(fileInfo.Size())) case "gitoid:sha256": hashResult, err = gitoid.New(file, gitoid.WithContentLength(fileInfo.Size()), gitoid.WithSha256()) } if err != nil { return err } plug.files[hashAlgo][filePath] = hashResult.String() } else { switch hashAlgo { case "sha1": hasher := sha1.New() _, err = io.Copy(hasher, file) hashBytes := hasher.Sum([]byte{}) plug.files[hashAlgo][filePath] = fmt.Sprintf("%x", hashBytes) case "sha256": hasher := sha256.New() _, err = io.Copy(hasher, file) hashBytes := hasher.Sum([]byte{}) plug.files[hashAlgo][filePath] = fmt.Sprintf("%x", hashBytes) } } } return nil } func (plug *FilePlugin) Store(envelope *Envelope) error { envelope.Header.Features["file"] = Feature{Algorithms: plug.algorithms} for algorithm, paths := range plug.files { for path, hash := range paths { if _, ok := envelope.Mapping[path]; !ok { envelope.Mapping[path] = &Element{ Type: fmt.Sprintf("%s", "file"), } } { e := envelope.Mapping[path] switch algorithm { case "sha1": e.Sha1 = hash case "sha256": e.Sha256 = hash case "gitoid:sha1": e.Sha1Gitoid = hash case "gitoid:sha256": e.Sha256Gitoid = hash } envelope.Mapping[path] = e } } } return nil } golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/go.mod000066400000000000000000000010251515447664700236710ustar00rootroot00000000000000module github.com/fkautz/omnitrail-go go 1.20 require ( github.com/edwarnicke/gitoid v0.0.0-20220710194850-1be5bfda1f9d github.com/omnibor/omnibor-go v0.0.0-20230521145532-a77de61a16cd github.com/stretchr/testify v1.8.2 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.8.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/go.sum000066400000000000000000000042531515447664700237240ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/edwarnicke/gitoid v0.0.0-20220710194850-1be5bfda1f9d h1:4l+Uq5zFWSagXgGFaKRRVWJrnlzeathyagWgYUltCgY= github.com/edwarnicke/gitoid v0.0.0-20220710194850-1be5bfda1f9d/go.mod h1:WxWwA3EYuCQjlR5EBUX3uaTS8bh9BOa7BcqVREHQ0uQ= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/omnibor/omnibor-go v0.0.0-20230521145532-a77de61a16cd h1:25EpGVgctk6V3DUa1gqFHvjVbmdWqM+jBZAed7p/krQ= github.com/omnibor/omnibor-go v0.0.0-20230521145532-a77de61a16cd/go.mod h1:ArlQivzDQvZnFe8itjlA3ndPTXd9iWOgqzF31OyIEFQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/omnitrail.go000066400000000000000000000027031515447664700251140ustar00rootroot00000000000000package omnitrail import ( "fmt" "sort" ) func NewTrail(option ...Option) Factory { o := &Options{} for _, opt := range option { opt(o) } if o.Sha1Enabled == false && o.Sha256Enabled == false { o.Sha1Enabled = true } allowList := []string{} plugins := make([]Plugin, 0) plugins = append(plugins, NewFilePlugin()) plugins = append(plugins, NewDirectoryPlugin()) plugins = append(plugins, NewPosixPlugin()) factory := &factoryImpl{ Options: o, Plugins: plugins, envelope: &Envelope{ Header: Header{ Features: make(map[string]Feature), }, Mapping: make(map[string]*Element), }, AllowList: allowList, } return factory } func FormatADGString(mapping Factory) string { res := "" sha1adgs := mapping.Sha1ADGs() // create a list of all keys sorted in lexical order keys := make([]string, 0, len(sha1adgs)) for k := range sha1adgs { keys = append(keys, k) } // sort the keys sort.Strings(keys) for _, k := range keys { v := sha1adgs[k] if v != "" { res += fmt.Sprintln(k) res += fmt.Sprintln(v) res += fmt.Sprintln("--") } } res += fmt.Sprintln("----") keys = make([]string, 0, len(sha1adgs)) sha2adgs := mapping.Sha256ADGs() keys = make([]string, 0, len(sha2adgs)) for k := range sha2adgs { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { v := sha2adgs[k] if v != "" { res += fmt.Sprintln(k) res += fmt.Sprintln(v) res += fmt.Sprintln("--") } } return res } golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/omnitrail_test.go000066400000000000000000000073461515447664700261630ustar00rootroot00000000000000package omnitrail import ( "encoding/json" "fmt" "os" "os/user" "reflect" "sort" "strings" "testing" "github.com/stretchr/testify/assert" ) func TestEmpty(t *testing.T) { // TODO, use a tempdir instead of making one in ./test if _, err := os.Stat("./test/empty"); os.IsNotExist(err) { err := os.Mkdir("./test/empty", 0755) assert.NoError(t, err) } name := "empty" if err := testAdd(t, name); err != nil { t.Fatalf("TestEmpty failed: %v", err) } } func TestOneFiles(t *testing.T) { name := "one-file" if err := testAdd(t, name); err != nil { t.Fatalf("TestOneFiles failed: %v", err) } } func TestTwoFiles(t *testing.T) { name := "two-files" if err := testAdd(t, name); err != nil { t.Fatalf("TestTwoFiles failed: %v", err) } } func TestDeepStructure(t *testing.T) { name := "deep" if err := testAdd(t, name); err != nil { t.Fatalf("TestDeepStructure failed: %v", err) } } func TestSymlinkGood(t *testing.T) { name := "symlink-good" if err := testAdd(t, name); err != nil { t.Fatalf("TestSymlinkGood failed: %v", err) } } func TestSymlinkBroken(t *testing.T) { name := "symlink-broken" if err := testAdd(t, name); err != nil { t.Fatalf("should ignore a bad symlink: %v", err) } } func TestSymlinkOutOfBounds(t *testing.T) { name := "symlink-out-of-bounds" err := os.WriteFile("/tmp/omnitrail-well-known-file", []byte("hello"), 0644) if err != nil { t.Fatalf("unable to write temporary file: %v", err) } defer os.Remove("/tmp/omnitrail-well-known-file") err = testAdd(t, name) if !strings.Contains(err.Error(), "not in the allow list") { t.Fatalf("unexpected error: %v", err) } if err == nil { t.Fatalf("TestSymlinkOutOfBounds failed: should report a symlik out of bounds") } } func testAdd(t *testing.T, name string) error { mapping := NewTrail() err := mapping.Add("./test/" + name) if err != nil { return err } // WARNING: these are only for generating new test cases easily // file, err := json.MarshalIndent(mapping.Envelope(), "", " ") // os.WriteFile("./test/"+name+".json", file, 0644) // res := FormatADGString(mapping) // os.WriteFile("./test/"+name+".adg", []byte(res), 0644) // END WARNING expectedBytes, err := os.ReadFile("./test/" + name + ".json") if err != nil { return err } var expectedEnvelope Envelope err = json.Unmarshal(expectedBytes, &expectedEnvelope) if err != nil { return err } shortestExpectedKey := getShortestKey(&expectedEnvelope) shortestActualKey := getShortestKey(mapping.Envelope()) for oldKey, val := range expectedEnvelope.Mapping { newKey := strings.Replace(oldKey, shortestExpectedKey, shortestActualKey, 1) delete(expectedEnvelope.Mapping, oldKey) expectedEnvelope.Mapping[newKey] = val } // get current username currentUser, err := user.Current() if err != nil { return err } uid := currentUser.Uid gid := currentUser.Gid for _, v := range expectedEnvelope.Mapping { v.Posix.OwnerUID = uid v.Posix.OwnerGID = gid } assert.Equal(t, &expectedEnvelope, mapping.Envelope()) if !reflect.DeepEqual(&expectedEnvelope, mapping.Envelope()) { return fmt.Errorf("expected envelope does not match actual envelope") } res := FormatADGString(mapping) expectedBytes, err = os.ReadFile("./test/" + name + ".adg") if err != nil { return err } if string(expectedBytes) != res { return fmt.Errorf("expected ADG string does not match actual ADG string") } return nil } func getShortestKey(expectedEnvelope *Envelope) string { // get map keys keys := make([]string, 0, len(expectedEnvelope.Mapping)) for key := range expectedEnvelope.Mapping { keys = append(keys, key) } // sort keys from shortest to longest sort.Slice(keys, func(i, j int) bool { return len(keys[i]) < len(keys[j]) }) shortestKey := keys[0] return shortestKey } golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/posix_plugin_unix.go000066400000000000000000000046371515447664700267110ustar00rootroot00000000000000package omnitrail import ( "fmt" "os" "path/filepath" "strconv" "strings" "syscall" ) type PosixPlugin struct { params map[string]*posixInfo AllowList []string } func (p *PosixPlugin) isAllowedDirectory(path string) bool { for _, allowedPath := range p.AllowList { if strings.HasPrefix(path, allowedPath) { return true } } return false } type posixInfo struct { permMode os.FileMode uid uint32 gid uint32 size int64 } func (p *PosixPlugin) Add(path string) error { // check if symlink is broken localFileInfo, err := os.Lstat(path) if err != nil { // if it's a symlink and the symlink is bad, ignore and return if os.IsNotExist(err) { return nil } return err } if localFileInfo.Mode()&os.ModeSymlink != 0 { targetPath, err := os.Readlink(path) if err != nil { // if it's a symlink and the symlink is bad, ignore and return if os.IsNotExist(err) { return nil } return err } if !filepath.IsAbs(targetPath) { targetPath = filepath.Join(filepath.Dir(path), targetPath) } if !p.isAllowedDirectory(targetPath) { return fmt.Errorf("path %s is not in the allow list", path) } if _, err = os.Stat(targetPath); err != nil { return nil } } stat, err := os.Stat(path) if err != nil { return err } perms := stat.Mode() if _, ok := p.params[path]; !ok { p.params[path] = &posixInfo{} } p.params[path].permMode = perms statt := stat.Sys().(*syscall.Stat_t) p.params[path].uid = statt.Uid p.params[path].gid = statt.Gid // if path is a directory, set size to 0 if !perms.IsDir() { p.params[path].size = stat.Size() } return nil } func (p *PosixPlugin) Store(envelope *Envelope) error { envelope.Header.Features["posix"] = Feature{} for path, element := range envelope.Mapping { if element.Posix == nil { element.Posix = &Posix{} } element.Posix.Permissions = p.params[path].permMode.String() element.Posix.OwnerUID = strconv.Itoa(int(p.params[path].uid)) element.Posix.OwnerGID = strconv.Itoa(int(p.params[path].gid)) if p.params[path].size != 0 { element.Posix.Size = strconv.Itoa(int(p.params[path].size)) } } return nil } func (p *PosixPlugin) Sha1ADG(_ map[string]string) { } func (p *PosixPlugin) Sha256ADG(_ map[string]string) { } func (plug *PosixPlugin) SetAllowList(allowList []string) { plug.AllowList = allowList } func NewPosixPlugin() Plugin { return &PosixPlugin{ params: make(map[string]*posixInfo), } } golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/000077500000000000000000000000001515447664700235445ustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/deep.adg000066400000000000000000000016371515447664700251450ustar00rootroot00000000000000afc6c552cd2595009cf7847777ad5897d0abe46a blob 93ca1422a8da0a9effc465eccbcb17e23015542d blob f6c2e0f6ac10055527287a21db1ad39424bf3b99 -- b51452d06f9e8b948089762da313b43973cbd6a6 blob 30d67d4672d5c05833b7192cc77a79eaafb5c7ad -- f6c2e0f6ac10055527287a21db1ad39424bf3b99 blob 08219db9b0969fa29cf16fd04df4a63964da0b69 blob b51452d06f9e8b948089762da313b43973cbd6a6 -- ---- 188f8b3bc7cbce45e6bb5c2063c9733eb3a18ddcd3f593556b9a8626961b0f77 blob 2da00b9c51e5e7554c44a3929f9f8cee3c4e742d4f71bec0d4e1d37256d17207 blob 4dc2f9fa74bb7761434f4994c26b52d1b8c27661f19dba63d225749b5a5a60f3 -- 3f8d7b5b500f4db43c40c4586f754e4702c1a7a3d61509867f1af37fae04fa18 blob 188f8b3bc7cbce45e6bb5c2063c9733eb3a18ddcd3f593556b9a8626961b0f77 blob 520f6e3c5ab9d63a4b3acd9bb69d90aad62dd0362d35355d47fcda9f1b70be3e -- 4dc2f9fa74bb7761434f4994c26b52d1b8c27661f19dba63d225749b5a5a60f3 blob 73bae245b03a7c9d540831beca1987b2a34f8bec948d032132d09224b613d186 -- golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/deep.json000066400000000000000000000060101515447664700253510ustar00rootroot00000000000000{ "header": { "features": { "directory": { "algorithms": [ "gitoid:sha1", "gitoid:sha256" ] }, "file": { "algorithms": [ "gitoid:sha1", "gitoid:sha256", "sha1", "sha256" ] }, "posix": {} } }, "mapping": { "/Users/fkautz/src/testifysec/omnitrail-go/test/deep": { "type": "directory", "gitoid:sha1": "afc6c552cd2595009cf7847777ad5897d0abe46a", "gitoid:sha256": "3f8d7b5b500f4db43c40c4586f754e4702c1a7a3d61509867f1af37fae04fa18", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "drwxr-xr-x" } }, "/Users/fkautz/src/testifysec/omnitrail-go/test/deep/dir1": { "type": "directory", "gitoid:sha1": "f6c2e0f6ac10055527287a21db1ad39424bf3b99", "gitoid:sha256": "188f8b3bc7cbce45e6bb5c2063c9733eb3a18ddcd3f593556b9a8626961b0f77", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "drwxr-xr-x" } }, "/Users/fkautz/src/testifysec/omnitrail-go/test/deep/dir1/dir2": { "type": "directory", "gitoid:sha1": "b51452d06f9e8b948089762da313b43973cbd6a6", "gitoid:sha256": "4dc2f9fa74bb7761434f4994c26b52d1b8c27661f19dba63d225749b5a5a60f3", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "drwxr-xr-x" } }, "/Users/fkautz/src/testifysec/omnitrail-go/test/deep/dir1/dir2/file2.txt": { "type": "file", "sha1": "cb99b709a1978bd205ab9dfd4c5aaa1fc91c7523", "sha256": "3377870dfeaaa7adf79a374d2702a3fdb13e5e5ea0dd8aa95a802ad39044a92f", "gitoid:sha1": "30d67d4672d5c05833b7192cc77a79eaafb5c7ad", "gitoid:sha256": "73bae245b03a7c9d540831beca1987b2a34f8bec948d032132d09224b613d186", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "-rw-r--r--", "size": "5" } }, "/Users/fkautz/src/testifysec/omnitrail-go/test/deep/dir1/file1.txt": { "type": "file", "sha1": "60b27f004e454aca81b0480209cce5081ec52390", "sha256": "c147efcfc2d7ea666a9e4f5187b115c90903f0fc896a56df9a6ef5d8f3fc9f31", "gitoid:sha1": "08219db9b0969fa29cf16fd04df4a63964da0b69", "gitoid:sha256": "2da00b9c51e5e7554c44a3929f9f8cee3c4e742d4f71bec0d4e1d37256d17207", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "-rw-r--r--", "size": "5" } }, "/Users/fkautz/src/testifysec/omnitrail-go/test/deep/root.txt": { "type": "file", "sha1": "dc76e9f0c0006e8f919e0c515c66dbba3982f785", "sha256": "4813494d137e1631bba301d5acab6e7bb7aa74ce1185d456565ef51d737677b2", "gitoid:sha1": "93ca1422a8da0a9effc465eccbcb17e23015542d", "gitoid:sha256": "520f6e3c5ab9d63a4b3acd9bb69d90aad62dd0362d35355d47fcda9f1b70be3e", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "-rw-r--r--", "size": "4" } } } }golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/deep/000077500000000000000000000000001515447664700244615ustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/deep/dir1/000077500000000000000000000000001515447664700253205ustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/deep/dir1/dir2/000077500000000000000000000000001515447664700261605ustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/deep/dir1/dir2/file2.txt000066400000000000000000000000051515447664700277150ustar00rootroot00000000000000file2golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/deep/dir1/file1.txt000066400000000000000000000000051515447664700270540ustar00rootroot00000000000000file1golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/deep/root.txt000066400000000000000000000000041515447664700261770ustar00rootroot00000000000000rootgolang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/empty.adg000066400000000000000000000000051515447664700253520ustar00rootroot00000000000000---- golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/empty.json000066400000000000000000000013111515447664700255710ustar00rootroot00000000000000{ "header": { "features": { "directory": { "algorithms": [ "gitoid:sha1", "gitoid:sha256" ] }, "file": { "algorithms": [ "gitoid:sha1", "gitoid:sha256", "sha1", "sha256" ] }, "posix": {} } }, "mapping": { "/Users/fkautz/src/testifysec/omnitrail-go/test/empty": { "type": "directory", "gitoid:sha1": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "gitoid:sha256": "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "drwxr-xr-x" } } } }golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/one-file.adg000066400000000000000000000003531515447664700257200ustar00rootroot000000000000002a696b661094182bb79ac4c99d238d857879d6ad blob b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0 -- ---- 045ec8de70efb3ac502eafba875bcb21b6eddb5ab09025a9de7187948ffebb68 blob 8aec4e4876f854f688d0ebfc8f37598f38e5fd6903cccc850ca36591175aeb60 -- golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/one-file.json000066400000000000000000000023471515447664700261430ustar00rootroot00000000000000{ "header": { "features": { "directory": { "algorithms": [ "gitoid:sha1", "gitoid:sha256" ] }, "file": { "algorithms": [ "gitoid:sha1", "gitoid:sha256", "sha1", "sha256" ] }, "posix": {} } }, "mapping": { "/Users/fkautz/src/testifysec/omnitrail-go/test/one-file": { "type": "directory", "gitoid:sha1": "2a696b661094182bb79ac4c99d238d857879d6ad", "gitoid:sha256": "045ec8de70efb3ac502eafba875bcb21b6eddb5ab09025a9de7187948ffebb68", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "drwxr-xr-x" } }, "/Users/fkautz/src/testifysec/omnitrail-go/test/one-file/hello.txt": { "type": "file", "sha1": "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", "sha256": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", "gitoid:sha1": "b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0", "gitoid:sha256": "8aec4e4876f854f688d0ebfc8f37598f38e5fd6903cccc850ca36591175aeb60", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "-rw-r--r--", "size": "5" } } } }golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/one-file/000077500000000000000000000000001515447664700252425ustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/one-file/hello.txt000066400000000000000000000000051515447664700271010ustar00rootroot00000000000000hellogolang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-bad.adg000066400000000000000000000000051515447664700264260ustar00rootroot00000000000000---- golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-broken.adg000066400000000000000000000003531515447664700271660ustar00rootroot000000000000002a696b661094182bb79ac4c99d238d857879d6ad blob b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0 -- ---- 045ec8de70efb3ac502eafba875bcb21b6eddb5ab09025a9de7187948ffebb68 blob 8aec4e4876f854f688d0ebfc8f37598f38e5fd6903cccc850ca36591175aeb60 -- golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-broken.json000066400000000000000000000023551515447664700274100ustar00rootroot00000000000000{ "header": { "features": { "directory": { "algorithms": [ "gitoid:sha1", "gitoid:sha256" ] }, "file": { "algorithms": [ "gitoid:sha1", "gitoid:sha256", "sha1", "sha256" ] }, "posix": {} } }, "mapping": { "/Users/frederickkautz/src/omnitrail-go/test/symlink-broken": { "type": "directory", "gitoid:sha1": "2a696b661094182bb79ac4c99d238d857879d6ad", "gitoid:sha256": "045ec8de70efb3ac502eafba875bcb21b6eddb5ab09025a9de7187948ffebb68", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "drwxr-xr-x" } }, "/Users/frederickkautz/src/omnitrail-go/test/symlink-broken/hello.txt": { "type": "file", "sha1": "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", "sha256": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", "gitoid:sha1": "b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0", "gitoid:sha256": "8aec4e4876f854f688d0ebfc8f37598f38e5fd6903cccc850ca36591175aeb60", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "-rw-r--r--", "size": "5" } } } }golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-broken/000077500000000000000000000000001515447664700265105ustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-broken/hello.txt000066400000000000000000000000051515447664700303470ustar00rootroot00000000000000hellogolang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-broken/world.txt000077700000000000000000000000001515447664700311012fooustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-good.adg000066400000000000000000000003531515447664700266360ustar00rootroot000000000000002a696b661094182bb79ac4c99d238d857879d6ad blob b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0 -- ---- 045ec8de70efb3ac502eafba875bcb21b6eddb5ab09025a9de7187948ffebb68 blob 8aec4e4876f854f688d0ebfc8f37598f38e5fd6903cccc850ca36591175aeb60 -- golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-good.json000066400000000000000000000034051515447664700270550ustar00rootroot00000000000000{ "header": { "features": { "directory": { "algorithms": [ "gitoid:sha1", "gitoid:sha256" ] }, "file": { "algorithms": [ "gitoid:sha1", "gitoid:sha256", "sha1", "sha256" ] }, "posix": {} } }, "mapping": { "/Users/frederickkautz/src/omnitrail-go/test/symlink-good": { "type": "directory", "gitoid:sha1": "2a696b661094182bb79ac4c99d238d857879d6ad", "gitoid:sha256": "045ec8de70efb3ac502eafba875bcb21b6eddb5ab09025a9de7187948ffebb68", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "drwxr-xr-x" } }, "/Users/frederickkautz/src/omnitrail-go/test/symlink-good/hello.txt": { "type": "file", "sha1": "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", "sha256": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", "gitoid:sha1": "b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0", "gitoid:sha256": "8aec4e4876f854f688d0ebfc8f37598f38e5fd6903cccc850ca36591175aeb60", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "-rw-r--r--", "size": "5" } }, "/Users/frederickkautz/src/omnitrail-go/test/symlink-good/world.txt": { "type": "file", "sha1": "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", "sha256": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", "gitoid:sha1": "b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0", "gitoid:sha256": "8aec4e4876f854f688d0ebfc8f37598f38e5fd6903cccc850ca36591175aeb60", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "-rw-r--r--", "size": "5" } } } }golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-good/000077500000000000000000000000001515447664700261605ustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-good/hello.txt000066400000000000000000000000051515447664700300170ustar00rootroot00000000000000hellogolang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-good/world.txt000077700000000000000000000000001515447664700317072hello.txtustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-out-of-bounds.adg000066400000000000000000000003531515447664700304070ustar00rootroot000000000000002a696b661094182bb79ac4c99d238d857879d6ad blob b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0 -- ---- 045ec8de70efb3ac502eafba875bcb21b6eddb5ab09025a9de7187948ffebb68 blob 8aec4e4876f854f688d0ebfc8f37598f38e5fd6903cccc850ca36591175aeb60 -- golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-out-of-bounds.json000066400000000000000000000034331515447664700306270ustar00rootroot00000000000000{ "header": { "features": { "directory": { "algorithms": [ "gitoid:sha1", "gitoid:sha256" ] }, "file": { "algorithms": [ "gitoid:sha1", "gitoid:sha256", "sha1", "sha256" ] }, "posix": {} } }, "mapping": { "/Users/frederickkautz/src/omnitrail-go/test/symlink-out-of-bounds": { "type": "directory", "gitoid:sha1": "2a696b661094182bb79ac4c99d238d857879d6ad", "gitoid:sha256": "045ec8de70efb3ac502eafba875bcb21b6eddb5ab09025a9de7187948ffebb68", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "drwxr-xr-x" } }, "/Users/frederickkautz/src/omnitrail-go/test/symlink-out-of-bounds/hello.txt": { "type": "file", "sha1": "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", "sha256": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", "gitoid:sha1": "b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0", "gitoid:sha256": "8aec4e4876f854f688d0ebfc8f37598f38e5fd6903cccc850ca36591175aeb60", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "-rw-r--r--", "size": "5" } }, "/Users/frederickkautz/src/omnitrail-go/test/symlink-out-of-bounds/world": { "type": "file", "sha1": "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", "sha256": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", "gitoid:sha1": "b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0", "gitoid:sha256": "8aec4e4876f854f688d0ebfc8f37598f38e5fd6903cccc850ca36591175aeb60", "posix": { "owner_gid": "0", "owner_uid": "501", "permissions": "-rw-r--r--", "size": "5" } } } }golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-out-of-bounds/000077500000000000000000000000001515447664700277315ustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-out-of-bounds/hello.txt000066400000000000000000000000051515447664700315700ustar00rootroot00000000000000hellogolang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/symlink-out-of-bounds/world000077700000000000000000000000001515447664700366062/tmp/omnitrail-well-known-fileustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/two-files.adg000066400000000000000000000005371515447664700261370ustar00rootroot00000000000000dc0be356e8c2ba26e66448d97db76ad050206574 blob 04fea06420ca60892f73becee3614f6d023a4b7f blob b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0 -- ---- e32e7e7761709be17ef573556a82960d489ddf0092424f7db1c91d8363dde822 blob 8aec4e4876f854f688d0ebfc8f37598f38e5fd6903cccc850ca36591175aeb60 blob 8df3dab4ddfa6eb2a34065cda27d95af2709d4d2658e1b5fbd145822acf42b28 -- golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/two-files.json000066400000000000000000000033751515447664700263600ustar00rootroot00000000000000{ "header": { "features": { "directory": { "algorithms": [ "gitoid:sha1", "gitoid:sha256" ] }, "file": { "algorithms": [ "gitoid:sha1", "gitoid:sha256", "sha1", "sha256" ] }, "posix": {} } }, "mapping": { "/Users/fkautz/src/testifysec/omnitrail-go/test/two-files": { "type": "directory", "gitoid:sha1": "dc0be356e8c2ba26e66448d97db76ad050206574", "gitoid:sha256": "e32e7e7761709be17ef573556a82960d489ddf0092424f7db1c91d8363dde822", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "drwxr-xr-x" } }, "/Users/fkautz/src/testifysec/omnitrail-go/test/two-files/hello": { "type": "file", "sha1": "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", "sha256": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", "gitoid:sha1": "b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0", "gitoid:sha256": "8aec4e4876f854f688d0ebfc8f37598f38e5fd6903cccc850ca36591175aeb60", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "-rw-r--r--", "size": "5" } }, "/Users/fkautz/src/testifysec/omnitrail-go/test/two-files/world": { "type": "file", "sha1": "7c211433f02071597741e6ff5a8ea34789abbf43", "sha256": "486ea46224d1bb4fb680f34f7c9ad96a8f24ec88be73ea8e5a6c65260e9cb8a7", "gitoid:sha1": "04fea06420ca60892f73becee3614f6d023a4b7f", "gitoid:sha256": "8df3dab4ddfa6eb2a34065cda27d95af2709d4d2658e1b5fbd145822acf42b28", "posix": { "owner_gid": "20", "owner_uid": "501", "permissions": "-rw-r--r--", "size": "5" } } } }golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/two-files/000077500000000000000000000000001515447664700254555ustar00rootroot00000000000000golang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/two-files/hello000066400000000000000000000000051515447664700264760ustar00rootroot00000000000000hellogolang-github-fkautz-omnitrail-go-0.0~git20240613.999f2e7/test/two-files/world000066400000000000000000000000051515447664700265220ustar00rootroot00000000000000world