launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #29721
[Merge] ~cjwatson/launchpad:archive-subscriber-view-files into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:archive-subscriber-view-files into launchpad:master.
Commit message:
Allow archive subscribers to use +sourcefiles and +files
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/438337
This will be needed by the `debuginfod` service, but it seems reasonable anyway. It has the effect that subscribers will be able to see historical files in archives as well as current ones; but they can build much of that information up over time anyway, so this was never a robust boundary, and the in-progress archive snapshot service will soon allow equivalent access.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:archive-subscriber-view-files into launchpad:master.
diff --git a/lib/lp/services/librarian/browser.py b/lib/lp/services/librarian/browser.py
index d364b68..334636f 100644
--- a/lib/lp/services/librarian/browser.py
+++ b/lib/lp/services/librarian/browser.py
@@ -78,10 +78,12 @@ class FileNavigationMixin:
with the same filename (product files or bug attachments).
"""
+ file_navigation_permission = "launchpad.View"
+
@stepthrough("+files")
def traverse_files(self, filename):
"""Traverse on filename in the archive domain."""
- if not check_permission("launchpad.View", self.context):
+ if not check_permission(self.file_navigation_permission, self.context):
raise Unauthorized()
library_file = self.context.getFileByName(filename)
diff --git a/lib/lp/soyuz/browser/archive.py b/lib/lp/soyuz/browser/archive.py
index 63b9171..f785294 100644
--- a/lib/lp/soyuz/browser/archive.py
+++ b/lib/lp/soyuz/browser/archive.py
@@ -222,6 +222,7 @@ class ArchiveNavigation(Navigation, FileNavigationMixin):
"""Navigation methods for IArchive."""
usedfor = IArchive
+ file_navigation_permission = "launchpad.SubscriberView"
@stepthrough("+build")
def traverse_build(self, name):
@@ -463,7 +464,7 @@ class ArchiveNavigation(Navigation, FileNavigationMixin):
version = self.request.stepstogo.consume()
filename = self.request.stepstogo.consume()
- if not check_permission("launchpad.View", self.context):
+ if not check_permission("launchpad.SubscriberView", self.context):
raise Unauthorized()
library_file = self.context.getSourceFileByName(
diff --git a/lib/lp/soyuz/interfaces/archive.py b/lib/lp/soyuz/interfaces/archive.py
index f1e2c3f..c59e03f 100644
--- a/lib/lp/soyuz/interfaces/archive.py
+++ b/lib/lp/soyuz/interfaces/archive.py
@@ -794,9 +794,48 @@ class IArchiveSubscriberView(Interface):
:return: A collection containing `BinaryPackagePublishingHistory`.
"""
+<<<<<<< lib/lp/soyuz/interfaces/archive.py
def getPoolFileByPath(
path: PurePath, live_at: typing.Optional[datetime] = None
):
+=======
+ def getFileByName(filename):
+ """Return the corresponding `ILibraryFileAlias` in this context.
+
+ The following file types (and extension) can be looked up in the
+ archive context:
+
+ * Source files: '.orig.tar.gz', 'tar.gz', '.diff.gz' and '.dsc';
+ * Binary files: '.deb' and '.udeb';
+ * Source changesfile: '_source.changes';
+ * Package diffs: '.diff.gz';
+
+ :param filename: exactly filename to be looked up.
+
+ :raises AssertionError if the given filename contains a unsupported
+ filename and/or extension, see the list above.
+ :raises NotFoundError if no file could not be found.
+
+ :return the corresponding `ILibraryFileAlias` is the file was found.
+ """
+
+ def getSourceFileByName(name, version, filename):
+ """Return the `ILibraryFileAlias` for a source name/version/filename.
+
+ This can be used to avoid ambiguities with `getFileByName` in
+ imported archives, where the upstream archive software may not
+ always have had robust historical filename uniqueness checks.
+
+ :param name: The name of the source package.
+ :param version: The version of the source package.
+ :param filename: The exact filename to look up.
+
+ :raises NotFoundError: if no matching file could be found.
+ :return: the corresponding `ILibraryFileAlias`.
+ """
+
+ def getPoolFileByPath(path):
+>>>>>>> lib/lp/soyuz/interfaces/archive.py
"""Return the `ILibraryFileAlias` for a path in this archive's pool.
:param path: A `PurePath` for where a source or binary package file
@@ -1283,41 +1322,6 @@ class IArchiveView(IHasBuildRecords):
queue admin permissions for this archive.
"""
- def getFileByName(filename):
- """Return the corresponding `ILibraryFileAlias` in this context.
-
- The following file types (and extension) can be looked up in the
- archive context:
-
- * Source files: '.orig.tar.gz', 'tar.gz', '.diff.gz' and '.dsc';
- * Binary files: '.deb' and '.udeb';
- * Source changesfile: '_source.changes';
- * Package diffs: '.diff.gz';
-
- :param filename: exactly filename to be looked up.
-
- :raises AssertionError if the given filename contains a unsupported
- filename and/or extension, see the list above.
- :raises NotFoundError if no file could not be found.
-
- :return the corresponding `ILibraryFileAlias` is the file was found.
- """
-
- def getSourceFileByName(name, version, filename):
- """Return the `ILibraryFileAlias` for a source name/version/filename.
-
- This can be used to avoid ambiguities with `getFileByName` in
- imported archives, where the upstream archive software may not
- always have had robust historical filename uniqueness checks.
-
- :param name: The name of the source package.
- :param version: The version of the source package.
- :param filename: The exact filename to look up.
-
- :raises NotFoundError: if no matching file could be found.
- :return: the corresponding `ILibraryFileAlias`.
- """
-
def getBinaryPackageRelease(name, version, archtag):
"""Find the specified `IBinaryPackageRelease` in the archive.
diff --git a/lib/lp/soyuz/stories/ppa/xx-ppa-files.rst b/lib/lp/soyuz/stories/ppa/xx-ppa-files.rst
index 7e0ce09..8eead97 100644
--- a/lib/lp/soyuz/stories/ppa/xx-ppa-files.rst
+++ b/lib/lp/soyuz/stories/ppa/xx-ppa-files.rst
@@ -27,8 +27,19 @@ Create a private PPA for no-priv.
... owner=no_priv, private=True, name="p3a", distribution=ubuntu
... )
+Add a subscriber to this private PPA.
+
+ >>> from zope.security.proxy import removeSecurityProxy
+ >>> _ = login_person(no_priv)
+ >>> subscriber = factory.makePerson()
+ >>> subscriber_email = removeSecurityProxy(
+ ... subscriber
+ ... ).preferredemail.email
+ >>> _ = no_priv_private_ppa.newSubscription(subscriber, no_priv)
+
Initialize SoyuzTestPublisher.
+ >>> login("foo.bar@xxxxxxxxxxxxx")
>>> test_publisher = SoyuzTestPublisher()
>>> test_publisher.prepareBreezyAutotest()
>>> test_publisher.addFakeChroots()
@@ -317,6 +328,25 @@ The 'No Privileges' user, the PPA owner, can download the DSC file.
Location: https://...restricted.../test-pkg_1.0.dsc?token=...
...
+A subscriber can download the DSC file.
+
+ >>> print(
+ ... http(
+ ... r"""
+ ... GET %s HTTP/1.1
+ ... Authorization: Basic %s:test
+ ... """
+ ... % (
+ ... dsc_file_lp_url.replace("http://launchpad.test", ""),
+ ... subscriber_email,
+ ... )
+ ... )
+ ... )
+ HTTP/1.1 303 See Other
+ ...
+ Location: https://...restricted.../test-pkg_1.0.dsc?token=...
+ ...
+
Binary files are served via '+files' rather than '+sourcefiles'.
>>> login("foo.bar@xxxxxxxxxxxxx")
@@ -342,6 +372,22 @@ Binary files are served via '+files' rather than '+sourcefiles'.
...
Location: https://...restricted.../test-bin_1.0_all.deb?token=...
...
+ >>> print(
+ ... http(
+ ... r"""
+ ... GET %s HTTP/1.1
+ ... Authorization: Basic %s:test
+ ... """
+ ... % (
+ ... deb_file_lp_url.replace("http://launchpad.test", ""),
+ ... subscriber_email,
+ ... )
+ ... )
+ ... )
+ HTTP/1.1 303 See Other
+ ...
+ Location: https://...restricted.../test-bin_1.0_all.deb?token=...
+ ...
If the associated PPA and the `LibraryFileAlias` are public, the +files/
proxy redirects to the public http url. We'll copy the test sources and
@@ -465,7 +511,6 @@ immediately deleted in case of reported ToS violation.
>>> from lp.services.database.interfaces import IPrimaryStore
>>> login("foo.bar@xxxxxxxxxxxxx")
>>> IPrimaryStore(Archive).commit()
- >>> from zope.security.proxy import removeSecurityProxy
>>> removeSecurityProxy(dsc_file).content = None
>>> transaction.commit()