From 6d9cd6783927c8b3bd235123c5f07a2127c525b9 Mon Sep 17 00:00:00 2001 From: Saumya Dudeja Date: Fri, 9 Jan 2026 19:22:21 +0100 Subject: [PATCH 1/2] fix symlink resolution for noble --- src/bpm/runc/adapter/mount.go | 9 ++- src/bpm/runc/adapter/mount_symlink_test.go | 94 ++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 src/bpm/runc/adapter/mount_symlink_test.go diff --git a/src/bpm/runc/adapter/mount.go b/src/bpm/runc/adapter/mount.go index dda98083..29c9128e 100644 --- a/src/bpm/runc/adapter/mount.go +++ b/src/bpm/runc/adapter/mount.go @@ -16,6 +16,7 @@ package adapter import ( + "path/filepath" "sort" "strings" @@ -34,9 +35,15 @@ func Mount(from, to string, opts ...MountOption) specs.Mount { opt(mountOpts) } + // Resolve symlinks in source path for Noble stemcell compatibility + resolvedFrom := from + if resolved, err := filepath.EvalSymlinks(from); err == nil { + resolvedFrom = resolved + } + return specs.Mount{ Destination: to, - Source: from, + Source: resolvedFrom, Type: "bind", Options: mountOpts.opts(), } diff --git a/src/bpm/runc/adapter/mount_symlink_test.go b/src/bpm/runc/adapter/mount_symlink_test.go new file mode 100644 index 00000000..4b65ebed --- /dev/null +++ b/src/bpm/runc/adapter/mount_symlink_test.go @@ -0,0 +1,94 @@ +// Copyright (C) 2026-Present CloudFoundry.org Foundation, Inc. All rights reserved. +// +// This program and the accompanying materials are made available under +// the terms of the 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. + +package adapter_test + +import ( + "os" + "path/filepath" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + . "bpm/runc/adapter" +) + +var _ = Describe("Mount with Symlink Resolution", func() { + var ( + tempDir string + realDir string + symlinkPath string + ) + + BeforeEach(func() { + var err error + tempDir, err = os.MkdirTemp("", "bpm-mount-test") + Expect(err).NotTo(HaveOccurred()) + + realDir = filepath.Join(tempDir, "real-directory") + err = os.Mkdir(realDir, 0755) + Expect(err).NotTo(HaveOccurred()) + + symlinkPath = filepath.Join(tempDir, "symlink") + err = os.Symlink(realDir, symlinkPath) + Expect(err).NotTo(HaveOccurred()) + }) + + AfterEach(func() { + os.RemoveAll(tempDir) + }) + + Context("when mounting a symlinked path", func() { + It("resolves the symlink to the real path", func() { + mount := Mount(symlinkPath, "/container/path") + + Expect(mount.Source).To(Equal(realDir)) + Expect(mount.Destination).To(Equal("/container/path")) + Expect(mount.Type).To(Equal("bind")) + }) + }) + + Context("when mounting a non-symlinked path", func() { + It("uses the path as-is", func() { + mount := Mount(realDir, "/container/path") + + Expect(mount.Source).To(Equal(realDir)) + Expect(mount.Destination).To(Equal("/container/path")) + Expect(mount.Type).To(Equal("bind")) + }) + }) + + Context("when the symlink path does not exist", func() { + It("uses the original path", func() { + nonExistentPath := filepath.Join(tempDir, "does-not-exist") + mount := Mount(nonExistentPath, "/container/path") + + Expect(mount.Source).To(Equal(nonExistentPath)) + Expect(mount.Destination).To(Equal("/container/path")) + }) + }) + + Context("with IdentityMount", func() { + It("resolves symlinks in both source and destination", func() { + mount := IdentityMount(symlinkPath) + + // Source should be resolved, but destination stays as-is + // because IdentityMount(path) calls Mount(path, path) + // and the destination is not resolved + Expect(mount.Source).To(Equal(realDir)) + Expect(mount.Destination).To(Equal(symlinkPath)) + }) + }) +}) From 36a3297412cd2eea9ed4ba09338f5551d7464651 Mon Sep 17 00:00:00 2001 From: Saumya Dudeja Date: Mon, 12 Jan 2026 11:57:33 +0100 Subject: [PATCH 2/2] fix lint error --- src/bpm/runc/adapter/mount_symlink_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bpm/runc/adapter/mount_symlink_test.go b/src/bpm/runc/adapter/mount_symlink_test.go index 4b65ebed..9c8f5c98 100644 --- a/src/bpm/runc/adapter/mount_symlink_test.go +++ b/src/bpm/runc/adapter/mount_symlink_test.go @@ -47,7 +47,8 @@ var _ = Describe("Mount with Symlink Resolution", func() { }) AfterEach(func() { - os.RemoveAll(tempDir) + err := os.RemoveAll(tempDir) + Expect(err).NotTo(HaveOccurred()) }) Context("when mounting a symlinked path", func() {