Skip to content

Don't skip symlinks during local source upload#355

Open
dollierp wants to merge 4 commits intoshipwright-io:mainfrom
dollierp:symlinks
Open

Don't skip symlinks during local source upload#355
dollierp wants to merge 4 commits intoshipwright-io:mainfrom
dollierp:symlinks

Conversation

@dollierp
Copy link
Copy Markdown

@dollierp dollierp commented Nov 6, 2025

Changes

Don't skip symlinks during local source upload

/kind bug

Submitter Checklist

  • Includes tests if functionality changed/was added
  • Includes docs if changes are user-facing
  • Set a kind label on this PR
  • Release notes block has been filled in, or marked NONE

See the contributor guide
for details on coding conventions, github and prow interactions, and the code review process.

Release Notes

Don't skip symlinks during local source upload

Signed-off-by: Denis Ollier <dollierp@redhat.com>
@pull-request-size pull-request-size bot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Nov 6, 2025
@openshift-ci openshift-ci bot added the kind/bug Categorizes issue or PR as related to a bug. label Nov 6, 2025
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Nov 6, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign heavywombat for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link
Copy Markdown
Member

@IrvingMg IrvingMg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

Overall, LGTM. I left a couple of comments. It would also be nice to have unit tests for at least basic cases, as the changes are related to the core functionality of the upload command.

// skipPath inspect each path and makes sure it skips files the tar helper can't handle.
func (t *Tar) skipPath(fpath string, stat fs.FileInfo) bool {
if !stat.Mode().IsRegular() {
if !stat.Mode().IsRegular() && !(stat.Mode()&fs.ModeSymlink != 0) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if !stat.Mode().IsRegular() && !(stat.Mode()&fs.ModeSymlink != 0) {
if !stat.Mode().IsRegular() && stat.Mode()&fs.ModeSymlink == 0 {

nit

Comment on lines +34 to +39
target, err := os.Readlink(fpath)
if err != nil {
return err
}

header.Linkname = target
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add validation or a warning if the symlink points outside the source directory?

dollierp added 2 commits April 6, 2026 10:23
Signed-off-by: Denis Ollier <dollierp@redhat.com>
Signed-off-by: Denis Ollier <dollierp@redhat.com>
Copilot AI review requested due to automatic review settings April 6, 2026 13:28
@dollierp
Copy link
Copy Markdown
Author

dollierp commented Apr 6, 2026

Hi @IrvingMg,

Thanks for your review.

I updated the PR with new changes trying to address your remarks.

Regards,

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a bug where symlinks were being skipped during local source uploads. Previously, the tar helper would skip any file that wasn't a regular file (including symlinks, directories, and other special file types). The changes now allow symlinks to be included in the tar archive while still skipping unsupported file types.

Changes:

  • Modified skipPath function to exclude symlinks from being skipped (allowing them to be processed)
  • Added symlink handling in writeFileToTar to read symlink targets, detect if they point outside the source directory, and properly set the tar header linkname
  • Added isSymlinkTargetOutsideOfDir function to check if symlink targets escape the source directory and warn appropriately
  • Updated test to verify that symlinks are captured in the tar archive
  • Fixed documentation from "buildrun" to "build" command references

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pkg/shp/streamer/tar.go Modified skipPath condition to allow symlinks through filtering
pkg/shp/streamer/util.go Added symlink handling logic with safety check for targets pointing outside source directory
pkg/shp/streamer/tar_test.go Enhanced test to verify symlinks are included in tar output
pkg/shp/cmd/build/upload.go Fixed documentation typo from "buildrun" to "build"
docs/shp_build_upload.md Updated documentation examples to match corrected command

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@dollierp dollierp requested a review from IrvingMg April 6, 2026 13:37
@IrvingMg
Copy link
Copy Markdown
Member

IrvingMg commented Apr 8, 2026

Hi @dollierp, thanks for the changes.

There’s one more Copilot comment, could you take a look?

@dollierp
Copy link
Copy Markdown
Author

dollierp commented Apr 8, 2026

Hi @IrvingMg,

I updated the PR to make Copilot happy.

Let me know if something else is missing.

Regards.

Copy link
Copy Markdown
Member

@IrvingMg IrvingMg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again for the changes. I left a couple more comments.


if outside, _ := isSymlinkTargetOutsideOfDir(absSrc, absTarget); outside {
relPath, _ := filepath.Rel(src, fpath)
fmt.Fprintf(os.Stderr, "WARNING: symlink %q points outside the source directory %q (target: %q)\n", relPath, absSrc, target)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we send the error through ioStreams.ErrOut?

@@ -0,0 +1 @@
../../test No newline at end of file
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to create and delete the symlink at runtime to avoid committing it?

Signed-off-by: Denis Ollier <dollierp@redhat.com>
@pull-request-size pull-request-size bot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Apr 9, 2026
@dollierp dollierp requested a review from Copilot April 9, 2026 18:06
@dollierp
Copy link
Copy Markdown
Author

dollierp commented Apr 9, 2026

Hi @IrvingMg,

I tried to address your latest remarks and updated the PR.

Regards,

@dollierp dollierp requested a review from IrvingMg April 9, 2026 19:03
Copy link
Copy Markdown
Member

@IrvingMg IrvingMg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update, looks good overall. Just a few final comments from my side.

return nil
}

func isSymlinkTargetOutsideOfDir(dir, target string) (bool, error) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Is it possible to replace this with https://pkg.go.dev/path/filepath#IsLocal?


stdErr := errOut.String()

t.Run("symlinks", func(_ *testing.T) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since *testing.T is unused, should we drop the t.Run wrapper?

os.Symlink("../test", baseDir+"/test/symlink_inside_tree")
os.Symlink("../../foobar/test", baseDir+"/test/symlink_outside_tree")

defer os.Remove(baseDir + "/test/symlink_inside_tree")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of deferring, I think we can use t.Cleanup.

ioStreams, _, _, errOut := genericclioptions.NewTestIOStreams()

baseDir := "../../.."
os.Symlink("../test", baseDir+"/test/symlink_inside_tree")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a good idea to check the error here and fail in case of an error. For example:

 if err := os.Symlink("../test", baseDir+"/test/symlink_inside_tree"); err != nil {                                                                                                                                          
      t.Fatalf("setup symlink: %v", err)                                                                                                                                                                                      
 }                                                                                                                                                                                                                           
 t.Cleanup(func() { 
      os.Remove(baseDir + "/test/symlink_inside_tree") 
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/bug Categorizes issue or PR as related to a bug. release-note size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

4 participants