launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #23740
[Merge] lp:~cjwatson/launchpad/snapcraft-yaml-remote-symlink into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/snapcraft-yaml-remote-symlink into lp:launchpad.
Commit message:
Try to manually resolve symlinks in remote Git repositories when fetching snapcraft.yaml.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1797366 in Launchpad itself: "Fetching snapcraft.yaml from GitHub doesn't honour symlinks"
https://bugs.launchpad.net/launchpad/+bug/1797366
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/snapcraft-yaml-remote-symlink/+merge/368899
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/snapcraft-yaml-remote-symlink into lp:launchpad.
=== modified file 'lib/lp/snappy/model/snap.py'
--- lib/lp/snappy/model/snap.py 2019-05-16 10:21:14 +0000
+++ lib/lp/snappy/model/snap.py 2019-06-17 08:07:25 +0000
@@ -14,9 +14,12 @@
from operator import attrgetter
from urlparse import urlsplit
+from bzrlib import urlutils
+from bzrlib.errors import InvalidURLJoin
from lazr.lifecycle.event import ObjectCreatedEvent
from pymacaroons import Macaroon
import pytz
+import six
from storm.expr import (
And,
Desc,
@@ -1298,6 +1301,21 @@
for path in paths:
try:
blob = context.getBlob(path)
+ if (IGitRef.providedBy(context) and
+ context.repository_url is not None and
+ isinstance(blob, bytes) and
+ b":" not in blob and b"\n" not in blob):
+ # Heuristic. It seems somewhat common for Git
+ # hosting sites to return the symlink target path
+ # when fetching a blob corresponding to a symlink
+ # committed to a repository: GitHub and GitLab both
+ # have this property. If it looks like this is what
+ # has happened here, try resolving the symlink (only
+ # to one level).
+ resolved_path = urlutils.join(
+ urlutils.dirname(path),
+ six.ensure_str(blob)).lstrip("/")
+ blob = context.getBlob(resolved_path)
break
except (BranchFileNotFound, GitRepositoryBlobNotFound):
pass
@@ -1309,6 +1327,8 @@
raise MissingSnapcraftYaml(context.unique_name)
except GitRepositoryBlobUnsupportedRemote as e:
raise CannotFetchSnapcraftYaml(str(e), unsupported_remote=True)
+ except InvalidURLJoin as e:
+ raise CannotFetchSnapcraftYaml(str(e))
except (BranchHostingFault, GitRepositoryScanFault) as e:
msg = "Failed to get snap manifest from %s"
if logger is not None:
=== modified file 'lib/lp/snappy/tests/test_snap.py'
--- lib/lp/snappy/tests/test_snap.py 2019-05-16 10:21:14 +0000
+++ lib/lp/snappy/tests/test_snap.py 2019-06-17 08:07:25 +0000
@@ -1764,6 +1764,64 @@
self.assertEqual(0, unsafe_load.mock.call_count)
self.assertEqual(1, safe_load.mock.call_count)
+ @responses.activate
+ def test_getSnapcraftYaml_symlink(self):
+ for path in ("snap/snapcraft.yaml", "build-aux/snap/snapcraft.yaml"):
+ responses.add(
+ "GET",
+ "https://raw.githubusercontent.com/owner/name/HEAD/%s" % path,
+ status=404)
+ responses.add(
+ "GET",
+ "https://raw.githubusercontent.com/owner/name/HEAD/snapcraft.yaml",
+ body=b"pkg/snap/snapcraft.yaml")
+ responses.add(
+ "GET",
+ "https://raw.githubusercontent.com/owner/name/HEAD/"
+ "pkg/snap/snapcraft.yaml",
+ body=b"name: test-snap")
+ git_ref = self.factory.makeGitRefRemote(
+ repository_url="https://github.com/owner/name", path="HEAD")
+ snap = self.factory.makeSnap(git_ref=git_ref)
+ with default_timeout(1.0):
+ self.assertEqual(
+ {"name": "test-snap"},
+ getUtility(ISnapSet).getSnapcraftYaml(snap))
+
+ @responses.activate
+ def test_getSnapcraftYaml_symlink_via_parent(self):
+ responses.add(
+ "GET",
+ "https://raw.githubusercontent.com/owner/name/HEAD/"
+ "snap/snapcraft.yaml",
+ body=b"../pkg/snap/snapcraft.yaml")
+ responses.add(
+ "GET",
+ "https://raw.githubusercontent.com/owner/name/HEAD/"
+ "pkg/snap/snapcraft.yaml",
+ body=b"name: test-snap")
+ git_ref = self.factory.makeGitRefRemote(
+ repository_url="https://github.com/owner/name", path="HEAD")
+ snap = self.factory.makeSnap(git_ref=git_ref)
+ with default_timeout(1.0):
+ self.assertEqual(
+ {"name": "test-snap"},
+ getUtility(ISnapSet).getSnapcraftYaml(snap))
+
+ @responses.activate
+ def test_getSnapcraftYaml_symlink_above_root(self):
+ responses.add(
+ "GET",
+ "https://raw.githubusercontent.com/owner/name/HEAD/snapcraft.yaml",
+ body=b"../pkg/snap/snapcraft.yaml")
+ git_ref = self.factory.makeGitRefRemote(
+ repository_url="https://github.com/owner/name", path="HEAD")
+ snap = self.factory.makeSnap(git_ref=git_ref)
+ with default_timeout(1.0):
+ self.assertRaises(
+ CannotFetchSnapcraftYaml,
+ getUtility(ISnapSet).getSnapcraftYaml, snap)
+
def test__findStaleSnaps(self):
# Stale; not built automatically.
self.factory.makeSnap(is_stale=True)
Follow ups