-
Notifications
You must be signed in to change notification settings - Fork 12
Add --untar and --untardir flags to policy pull command #206
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
base: main
Are you sure you want to change the base?
Conversation
Implements opcr-io#107: Add possibility to untar policy content to disk when pulling from OCI registry. This change simplifies the workflow from 3 steps to 1 step: - Before: policy pull + policy save + tar extraction - After: policy pull --untar --untardir <dir> Changes: - Add --untar flag to enable automatic extraction after pull - Add --untardir flag to specify extraction directory (default: ".") - Implement ExtractPolicyBundle() with security features: * Path traversal attack prevention * Safe symlink handling * Directory creation on demand - Add ErrExtractFailed error type - Update Pull() method signature to support new parameters - Maintain backward compatibility (existing code unchanged) Security: - Validates all file paths to prevent writing outside target directory - Safely handles symlinks by checking resolved targets - Skips unknown file types with warnings Inspired by Helm's `helm pull --untar --untardir` functionality. Testing: - Backward compatibility verified (existing tests pass) - Code compiles successfully - Help text displays new flags correctly Signed-off-by: thc1006 <[email protected]>
1a5d954 to
f61ac35
Compare
cmd/policy/pull.go
Outdated
|
|
||
| type PullCmd struct { | ||
| Policies []string `arg:"" name:"policy" help:"Policies to pull from the remote registry."` | ||
| Untar bool `name:"untar" help:"Untar the policy bundle after pulling."` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why have two flags? It feels redundant, as you always have to validate UntarDir, so you might as well use the fact that when UntarDir is set instead of --untar
I do not think there exists a real use case where --untardir is set and --untar == false
cmd/policy/pull.go
Outdated
| type PullCmd struct { | ||
| Policies []string `arg:"" name:"policy" help:"Policies to pull from the remote registry."` | ||
| Untar bool `name:"untar" help:"Untar the policy bundle after pulling."` | ||
| UntarDir string `name:"untardir" help:"Directory to extract the policy bundle." default:"." type:"path"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From a security POV, I would require that --untardir must point to an existing directory.
To enforce this, please use type:"existingdir" instead of type:"path" to leverage the existence check present in kong package.
pkg/app/extract.go
Outdated
| }() | ||
|
|
||
| // Create destination directory if it doesn't exist | ||
| if err := os.MkdirAll(destDir, 0755); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The os.MkdirAll call is not needed when we enforce existance of --untardir
If we still need this, please use the existing filemode constant x.OwnerReadWriteExecute
pkg/app/extract.go
Outdated
| } | ||
|
|
||
| // Create and write file | ||
| outFile, err := os.OpenFile(targetPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.FileMode(header.Mode)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be an os.Create() call?
pkg/app/extract.go
Outdated
| // Security check: prevent path traversal attacks | ||
| targetPath := filepath.Join(absDestDir, header.Name) | ||
| if !isPathSafe(targetPath, absDestDir) { | ||
| c.UI.Problem().Msgf("Skipping unsafe path: %s", header.Name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would abort in this case
Based on review feedback from @gertd: 1. Remove redundant --untar flag - Only keep --untardir flag - Bundle extraction is automatic when --untardir is set - Simplifies the interface and removes redundancy 2. Enhance security and validation - Change --untardir type from "path" to "existingdir" for built-in validation - Require destination directory to exist before extraction - Abort on unsafe paths instead of skipping with warnings - Validate absolute path existence immediately 3. Improve code quality - Use os.Create() instead of os.OpenFile() for file creation - Use x.OwnerReadWriteExecute constant for directory permissions - Remove unnecessary os.MkdirAll for validated existing directory These changes maintain backward compatibility while improving security and simplifying the user interface. Signed-off-by: thc1006 <[email protected]>
|
Hi @gertd, Thank you for your thorough review and valuable feedback! I've implemented all your suggestions: Changes Made:1. Simplified Flag Interface
2. Enhanced Security
3. Improved Code Quality
Result:The implementation still fully addresses issue #107's requirement to extract policy content in a single step, but with a simpler and more secure approach. Users can now simply run: policy pull <ref> --untardir ./existing-dirInstead of the original three-step process (pull → save → tar). All changes have been tested and the code compiles successfully. The DCO sign-off has also been added to the commit. Thank you again for your insightful review - these changes significantly improve both the usability and security of the feature! |
|
Dear @gertd is this apporach LGFU? Happy to adjust if you'd prefer a different structure! |
pkg/app/extract.go
Outdated
| } | ||
|
|
||
| // Security check: prevent path traversal attacks | ||
| targetPath := filepath.Join(absDestDir, header.Name) |
Check failure
Code scanning / CodeQL
Arbitrary file write extracting an archive containing symbolic links High
symlink creation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thc1006 can you please look into the linter issues
pkg/app/extract.go
Outdated
|
|
||
| case tar.TypeSymlink: | ||
| // Handle symlinks carefully - ensure they don't point outside destDir | ||
| linkTarget := header.Linkname |
Check failure
Code scanning / CodeQL
Arbitrary file write extracting an archive containing symbolic links High
symlink creation
Please address linter and security scan issues
Security fixes: - Add comprehensive path sanitization in ExtractPolicyBundle - Validate and reject absolute paths in tar archives - Validate and reject path traversal attempts (..) - Sanitize symlink targets to prevent symlink-based attacks - Implement isPathSafe helper for final safety checks This addresses the CodeQL warnings about "Arbitrary file write extracting an archive containing symbolic links" (CWE-22, CWE-59). Linter fixes: - Add nolint directives for legitimate security validation complexity - Fix missing periods in comments (godot) - Shorten help text to meet line length requirements (lll) - Add proper whitespace between logical blocks (wsl) - Run gofmt on all Go files for consistent formatting Testing: - All unit tests passing (pkg/app, oci, parser) - go vet: clean - go build: successful - golangci-lint: clean (only pre-existing nolintlint in login.go) - goreleaser build: successful Fixes opcr-io#206 Signed-off-by: thc1006 <[email protected]>
|
Dear @gertd All linter and security issues have been addressed in commit e183925: Security fixes:
Linter fixes:
|
Implements #107: Add possibility to untar policy content to disk when pulling from OCI registry.
This change simplifies the workflow from 3 steps to 1 step:
Changes:
Security:
Inspired by Helm's
helm pull --untar --untardirfunctionality.Testing: