From cad7604ba30a6338a8a6385db64bef8df9e93418 Mon Sep 17 00:00:00 2001 From: YashNRam13 Date: Wed, 18 Aug 2021 14:27:03 +0530 Subject: [PATCH 01/47] docs: Update README.rst --- README.rst | 9 +++------ newsfragments/3749.documentation | 1 + 2 files changed, 4 insertions(+), 6 deletions(-) create mode 100644 newsfragments/3749.documentation diff --git a/README.rst b/README.rst index 2cc6e38eb..99126c009 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ ====================================== -Free and Open decentralized data store +Free and Open Decentralized Data Store ====================================== |image0| @@ -48,13 +48,10 @@ Please read more about Tahoe-LAFS architecture `here `__. โœ… Installation --------------- -For more detailed instructions, read `docs/INSTALL.rst `__ . +For more detailed instructions, read `Installing Tahoe-LAFS `__. -- `Building Tahoe-LAFS on Windows `__ -- `OS-X Packaging `__ - -Once tahoe --version works, see `docs/running.rst `__ to learn how to set up your first Tahoe-LAFS node. +Once ``tahoe --version`` works, see `How to Run Tahoe-LAFS `__ to learn how to set up your first Tahoe-LAFS node. ๐Ÿค– Issues diff --git a/newsfragments/3749.documentation b/newsfragments/3749.documentation new file mode 100644 index 000000000..82e1e7856 --- /dev/null +++ b/newsfragments/3749.documentation @@ -0,0 +1 @@ +Fixes links to the installation and about Tahoe pages in the docs. From 3e0dc9449757054fb3a3fe3ffad8164c5fdb265d Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Wed, 25 Aug 2021 13:06:10 -0400 Subject: [PATCH 02/47] Annotate the two fakes that (at least partially) implement RIStorageServer, so they're easier to find. --- src/allmydata/test/mutable/util.py | 8 +++++++- src/allmydata/test/test_upload.py | 8 ++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/allmydata/test/mutable/util.py b/src/allmydata/test/mutable/util.py index 62e8d7295..7e3bd3ec7 100644 --- a/src/allmydata/test/mutable/util.py +++ b/src/allmydata/test/mutable/util.py @@ -96,8 +96,14 @@ class FakeStorage(object): shares[shnum] = f.getvalue() +# This doesn't actually implement the whole interface, but adding a commented +# interface implementation annotation for grepping purposes. +#@implementer(RIStorageServer) class FakeStorageServer(object): - + """ + A fake Foolscap remote object, implemented by overriding callRemote() to + call local methods. + """ def __init__(self, peerid, storage): self.peerid = peerid self.storage = storage diff --git a/src/allmydata/test/test_upload.py b/src/allmydata/test/test_upload.py index fc9bfd697..8d5435e88 100644 --- a/src/allmydata/test/test_upload.py +++ b/src/allmydata/test/test_upload.py @@ -122,7 +122,15 @@ class SetDEPMixin(object): } self.node.encoding_params = p + +# This doesn't actually implement the whole interface, but adding a commented +# interface implementation annotation for grepping purposes. +#@implementer(RIStorageServer) class FakeStorageServer(object): + """ + A fake Foolscap remote object, implemented by overriding callRemote() to + call local methods. + """ def __init__(self, mode, reactor=None): self.mode = mode self.allocated = [] From 342a1c2c31ead596cb705a30e69282ad28df9932 Mon Sep 17 00:00:00 2001 From: fenn-cs Date: Sun, 29 Aug 2021 16:10:30 +0100 Subject: [PATCH 03/47] Python 3 support complete, so removed warning Signed-off-by: fenn-cs --- newsfragments/3781.minor | 0 src/allmydata/scripts/runner.py | 5 ----- src/allmydata/test/test_system.py | 8 ++------ 3 files changed, 2 insertions(+), 11 deletions(-) create mode 100644 newsfragments/3781.minor diff --git a/newsfragments/3781.minor b/newsfragments/3781.minor new file mode 100644 index 000000000..e69de29bb diff --git a/src/allmydata/scripts/runner.py b/src/allmydata/scripts/runner.py index 7f7f88bf6..a42b30624 100644 --- a/src/allmydata/scripts/runner.py +++ b/src/allmydata/scripts/runner.py @@ -183,13 +183,8 @@ def _maybe_enable_eliot_logging(options, reactor): # Pass on the options so we can dispatch the subcommand. return options -PYTHON_3_WARNING = ("Support for Python 3 is an incomplete work-in-progress." - " Use at your own risk.") def run(): - if six.PY3: - print(PYTHON_3_WARNING, file=sys.stderr) - if sys.platform == "win32": from allmydata.windows.fixups import initialize initialize() diff --git a/src/allmydata/test/test_system.py b/src/allmydata/test/test_system.py index 627b6ef29..d61d6990b 100644 --- a/src/allmydata/test/test_system.py +++ b/src/allmydata/test/test_system.py @@ -43,7 +43,6 @@ from allmydata.monitor import Monitor from allmydata.mutable.common import NotWriteableError from allmydata.mutable import layout as mutable_layout from allmydata.mutable.publish import MutableData -from allmydata.scripts.runner import PYTHON_3_WARNING from foolscap.api import DeadReferenceError, fireEventually, flushEventualQueue from twisted.python.failure import Failure @@ -2632,18 +2631,16 @@ class SystemTest(SystemTestMixin, RunBinTahoeMixin, unittest.TestCase): newargs = ["--node-directory", self.getdir("client0"), verb] + list(args) return self.run_bintahoe(newargs, stdin=stdin, env=env) - def _check_succeeded(res, check_stderr=True): + def _check_succeeded(res): out, err, rc_or_sig = res self.failUnlessEqual(rc_or_sig, 0, str(res)) - if check_stderr: - self.assertIn(err.strip(), (b"", PYTHON_3_WARNING.encode("ascii"))) d.addCallback(_run_in_subprocess, "create-alias", "newalias") d.addCallback(_check_succeeded) STDIN_DATA = b"This is the file to upload from stdin." d.addCallback(_run_in_subprocess, "put", "-", "newalias:tahoe-file", stdin=STDIN_DATA) - d.addCallback(_check_succeeded, check_stderr=False) + d.addCallback(_check_succeeded) def _mv_with_http_proxy(ign): env = os.environ @@ -2656,7 +2653,6 @@ class SystemTest(SystemTestMixin, RunBinTahoeMixin, unittest.TestCase): def _check_ls(res): out, err, rc_or_sig = res self.failUnlessEqual(rc_or_sig, 0, str(res)) - self.assertIn(err.strip(), (b"", PYTHON_3_WARNING.encode("ascii"))) self.failUnlessIn(b"tahoe-moved", out) self.failIfIn(b"tahoe-file", out) d.addCallback(_check_ls) From 8202256fa2640b193022f58772b903ae7f730460 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Tue, 31 Aug 2021 09:58:03 -0400 Subject: [PATCH 04/47] Add newsfragment --- newsfragments/3782.documentation | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/3782.documentation diff --git a/newsfragments/3782.documentation b/newsfragments/3782.documentation new file mode 100644 index 000000000..5e5cecc13 --- /dev/null +++ b/newsfragments/3782.documentation @@ -0,0 +1 @@ +tahoe-dev mailing list is now at tahoe-dev@lists.tahoe-lafs.org. From 65a1040fe884aee4f075bc6ccc0ed2a9e2dc26cc Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Tue, 31 Aug 2021 09:58:43 -0400 Subject: [PATCH 05/47] Update references to the mailing list New list is tahoe-dev@lists.tahoe-lafs.org, list info page is at https://lists.tahoe-lafs.org/mailman/listinfo/tahoe-dev, and list archives are now at https://lists.tahoe-lafs.org/pipermail/tahoe-dev/. Sadly message numbers in list archive seem to have changed, so updating references to list archive is not as simple as prefixing `list.` --- NEWS.rst | 2 +- README.rst | 2 +- docs/Installation/install-tahoe.rst | 2 +- docs/historical/historical_known_issues.txt | 2 +- docs/man/man1/tahoe.1 | 2 +- docs/release-checklist.rst | 4 ++-- docs/running.rst | 2 +- misc/python3/depgraph.sh | 2 +- relnotes.txt | 2 +- setup.py | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 88d231826..d70fac6b5 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -1188,7 +1188,7 @@ Precautions when Upgrading .. _`#1915`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1915 .. _`#1926`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1926 .. _`message to the tahoe-dev mailing list`: - https://tahoe-lafs.org/pipermail/tahoe-dev/2013-March/008096.html + https://lists.tahoe-lafs.org/pipermail/tahoe-dev/2013-March/008096.html Release 1.9.2 (2012-07-03) diff --git a/README.rst b/README.rst index 2cc6e38eb..e58211601 100644 --- a/README.rst +++ b/README.rst @@ -76,7 +76,7 @@ Get involved with the Tahoe-LAFS community: - Join our `weekly conference calls `__ with core developers and interested community members. -- Subscribe to `the tahoe-dev mailing list `__, the community forum for discussion of Tahoe-LAFS design, implementation, and usage. +- Subscribe to `the tahoe-dev mailing list `__, the community forum for discussion of Tahoe-LAFS design, implementation, and usage. ๐Ÿค— Contributing --------------- diff --git a/docs/Installation/install-tahoe.rst b/docs/Installation/install-tahoe.rst index c8b0b521e..2fe47f4a8 100644 --- a/docs/Installation/install-tahoe.rst +++ b/docs/Installation/install-tahoe.rst @@ -65,4 +65,4 @@ If you are working on MacOS or a Linux distribution which does not have Tahoe-LA If you are looking to hack on the source code or run pre-release code, we recommend you install Tahoe-LAFS on a `virtualenv` instance. To learn more, see :doc:`install-on-linux`. -You can always write to the `tahoe-dev mailing list `_ or chat on the `Libera.chat IRC `_ if you are not able to get Tahoe-LAFS up and running on your deployment. +You can always write to the `tahoe-dev mailing list `_ or chat on the `Libera.chat IRC `_ if you are not able to get Tahoe-LAFS up and running on your deployment. diff --git a/docs/historical/historical_known_issues.txt b/docs/historical/historical_known_issues.txt index 9d4e1d427..8edab51a8 100644 --- a/docs/historical/historical_known_issues.txt +++ b/docs/historical/historical_known_issues.txt @@ -177,7 +177,7 @@ mutable files, you may be able to avoid the potential for "rollback" failure. A future version of Tahoe will include a fix for this issue. Here is -[https://tahoe-lafs.org/pipermail/tahoe-dev/2008-May/000630.html the +[https://lists.tahoe-lafs.org/pipermail/tahoe-dev/2008-May/000628.html the mailing list discussion] about how that future version will work. diff --git a/docs/man/man1/tahoe.1 b/docs/man/man1/tahoe.1 index 113f6a311..ab3d3c4c5 100644 --- a/docs/man/man1/tahoe.1 +++ b/docs/man/man1/tahoe.1 @@ -268,7 +268,7 @@ For known security issues see .PP Tahoe-LAFS home page: .PP -tahoe-dev mailing list: +tahoe-dev mailing list: .SH COPYRIGHT .PP Copyright \@ 2006\[en]2013 The Tahoe-LAFS Software Foundation diff --git a/docs/release-checklist.rst b/docs/release-checklist.rst index a5761c1c7..da1bbe16f 100644 --- a/docs/release-checklist.rst +++ b/docs/release-checklist.rst @@ -178,8 +178,8 @@ Announcing the Release Candidate ```````````````````````````````` The release-candidate should be announced by posting to the -mailing-list (tahoe-dev@tahoe-lafs.org). For example: -https://tahoe-lafs.org/pipermail/tahoe-dev/2020-October/009995.html +mailing-list (tahoe-dev@lists.tahoe-lafs.org). For example: +https://lists.tahoe-lafs.org/pipermail/tahoe-dev/2020-October/009978.html Is The Release Done Yet? diff --git a/docs/running.rst b/docs/running.rst index a53f5d9e2..406c8200b 100644 --- a/docs/running.rst +++ b/docs/running.rst @@ -238,7 +238,7 @@ You can chat with other users of and hackers of this software on the #tahoe-lafs IRC channel at ``irc.libera.chat``, or on the `tahoe-dev mailing list`_. -.. _tahoe-dev mailing list: https://tahoe-lafs.org/cgi-bin/mailman/listinfo/tahoe-dev +.. _tahoe-dev mailing list: https://lists.tahoe-lafs.org/mailman/listinfo/tahoe-dev Complain diff --git a/misc/python3/depgraph.sh b/misc/python3/depgraph.sh index d5ad33bf7..4fd98a717 100755 --- a/misc/python3/depgraph.sh +++ b/misc/python3/depgraph.sh @@ -16,7 +16,7 @@ if git diff-index --quiet HEAD; then fi git config user.name 'Build Automation' -git config user.email 'tahoe-dev@tahoe-lafs.org' +git config user.email 'tahoe-dev@lists.tahoe-lafs.org' git add tahoe-deps.json tahoe-ported.json git commit -m "\ diff --git a/relnotes.txt b/relnotes.txt index d5552e24b..4afbd6cc5 100644 --- a/relnotes.txt +++ b/relnotes.txt @@ -155,7 +155,7 @@ Planet Earth [4] https://github.com/tahoe-lafs/tahoe-lafs/blob/tahoe-lafs-1.15.1/COPYING.GPL [5] https://github.com/tahoe-lafs/tahoe-lafs/blob/tahoe-lafs-1.15.1/COPYING.TGPPL.rst [6] https://tahoe-lafs.readthedocs.org/en/tahoe-lafs-1.15.1/INSTALL.html -[7] https://tahoe-lafs.org/cgi-bin/mailman/listinfo/tahoe-dev +[7] https://lists.tahoe-lafs.org/mailman/listinfo/tahoe-dev [8] https://tahoe-lafs.org/trac/tahoe-lafs/roadmap [9] https://github.com/tahoe-lafs/tahoe-lafs/blob/master/CREDITS [10] https://tahoe-lafs.org/trac/tahoe-lafs/wiki/Dev diff --git a/setup.py b/setup.py index 3433e93f4..e1d711ccf 100644 --- a/setup.py +++ b/setup.py @@ -359,7 +359,7 @@ setup(name="tahoe-lafs", # also set in __init__.py description='secure, decentralized, fault-tolerant file store', long_description=open('README.rst', 'r', encoding='utf-8').read(), author='the Tahoe-LAFS project', - author_email='tahoe-dev@tahoe-lafs.org', + author_email='tahoe-dev@lists.tahoe-lafs.org', url='https://tahoe-lafs.org/', license='GNU GPL', # see README.rst -- there is an alternative licence cmdclass={"update_version": UpdateVersion, From 7537a3a06ffed66b63700d0dec759a4cb3c810a5 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Tue, 31 Aug 2021 10:22:50 -0400 Subject: [PATCH 06/47] Hat tip to OSUOSL for hosting tahoe-dev list --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index e58211601..7608e8829 100644 --- a/README.rst +++ b/README.rst @@ -98,6 +98,8 @@ Before authoring or reviewing a patch, please familiarize yourself with the `Cod We would like to thank `Fosshost `__ for supporting us with hosting services. If your open source project needs help, you can apply for their support. +We are grateful to `Oregon State University Open Source Lab `__ for hosting tahoe-dev mailing list. + โ“ FAQ ------ From d9561070ae6f7227dce4706f0ae02a77e963fb47 Mon Sep 17 00:00:00 2001 From: fenn-cs Date: Wed, 1 Sep 2021 23:07:19 +0100 Subject: [PATCH 07/47] Python3 support note in Readme Signed-off-by: fenn-cs --- README.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.rst b/README.rst index 2cc6e38eb..ca491b353 100644 --- a/README.rst +++ b/README.rst @@ -56,6 +56,11 @@ For more detailed instructions, read `docs/INSTALL.rst `__ . Once tahoe --version works, see `docs/running.rst `__ to learn how to set up your first Tahoe-LAFS node. +๐Ÿ `Python3` Support +-------------------- + +`Python 3` support has been introduced as from ` Tahoe-LAFS 1.16.x` alongside `Python 2`. System admnistrators are advised to start runing Tahoe on `Python 3` and should expect the drop of `Python 2` support any future version from now. Please, feel free to file issues if you run into bugs running Tahoe on `Python 3`. + ๐Ÿค– Issues --------- From 07ac248f3b462d4eb57ece4a536267db19f9820a Mon Sep 17 00:00:00 2001 From: fenn-cs Date: Wed, 1 Sep 2021 23:11:43 +0100 Subject: [PATCH 08/47] Python3 support note update Signed-off-by: fenn-cs --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index ca491b353..bb8c5c252 100644 --- a/README.rst +++ b/README.rst @@ -56,10 +56,10 @@ For more detailed instructions, read `docs/INSTALL.rst `__ . Once tahoe --version works, see `docs/running.rst `__ to learn how to set up your first Tahoe-LAFS node. -๐Ÿ `Python3` Support +๐Ÿ `Python 3` Support -------------------- -`Python 3` support has been introduced as from ` Tahoe-LAFS 1.16.x` alongside `Python 2`. System admnistrators are advised to start runing Tahoe on `Python 3` and should expect the drop of `Python 2` support any future version from now. Please, feel free to file issues if you run into bugs running Tahoe on `Python 3`. +`Python 3` support has been introduced as from `Tahoe-LAFS 1.16.x` alongside `Python 2`. System admnistrators are advised to start running Tahoe on `Python 3` and should expect the drop of `Python 2` support any future version from now. Please, feel free to file issues if you run into bugs while running Tahoe on `Python 3`. ๐Ÿค– Issues From 6c679bd4e0292af572026353d0e7a1c74e01184f Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Thu, 2 Sep 2021 11:35:39 -0400 Subject: [PATCH 09/47] Stop using callRemoteOnly. --- src/allmydata/immutable/layout.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/allmydata/immutable/layout.py b/src/allmydata/immutable/layout.py index 3db9f096e..886a5db73 100644 --- a/src/allmydata/immutable/layout.py +++ b/src/allmydata/immutable/layout.py @@ -15,7 +15,7 @@ from zope.interface import implementer from twisted.internet import defer from allmydata.interfaces import IStorageBucketWriter, IStorageBucketReader, \ FileTooLargeError, HASH_SIZE -from allmydata.util import mathutil, observer, pipeline +from allmydata.util import mathutil, observer, pipeline, log from allmydata.util.assertutil import precondition from allmydata.storage.server import si_b2a @@ -254,8 +254,7 @@ class WriteBucketProxy(object): return d def abort(self): - return self._rref.callRemoteOnly("abort") - + self._rref.callRemote("abort").addErrback(log.err) def get_servername(self): return self._server.get_name() From 63bfff19e9be9665461b4355e56ced50a227d2a8 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Thu, 2 Sep 2021 15:05:15 -0400 Subject: [PATCH 10/47] Don't rely on Foolscap's semantics. --- src/allmydata/mutable/servermap.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/allmydata/mutable/servermap.py b/src/allmydata/mutable/servermap.py index 4f3226649..211b1fc16 100644 --- a/src/allmydata/mutable/servermap.py +++ b/src/allmydata/mutable/servermap.py @@ -607,13 +607,14 @@ class ServermapUpdater(object): return d def _do_read(self, server, storage_index, shnums, readv): + """ + If self._add_lease is true, a lease is added, and the result only fires + once the least has also been added. + """ ss = server.get_storage_server() if self._add_lease: # send an add-lease message in parallel. The results are handled - # separately. This is sent before the slot_readv() so that we can - # be sure the add_lease is retired by the time slot_readv comes - # back (this relies upon our knowledge that the server code for - # add_lease is synchronous). + # separately. renew_secret = self._node.get_renewal_secret(server) cancel_secret = self._node.get_cancel_secret(server) d2 = ss.add_lease( @@ -623,7 +624,16 @@ class ServermapUpdater(object): ) # we ignore success d2.addErrback(self._add_lease_failed, server, storage_index) + else: + d2 = defer.succeed(None) d = ss.slot_readv(storage_index, shnums, readv) + + def passthrough(result): + # Wait for d2, but fire with result of slot_readv() regardless of + # result of d2. + return d2.addBoth(lambda _: result) + + d.addCallback(passthrough) return d From 789a7edb56501e5e7d95c93e7570bb4fc1197507 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Thu, 2 Sep 2021 15:21:42 -0400 Subject: [PATCH 11/47] Get rid of more callRemoteOnly usage. --- src/allmydata/immutable/downloader/share.py | 4 +++- src/allmydata/storage_client.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/allmydata/immutable/downloader/share.py b/src/allmydata/immutable/downloader/share.py index 86b99e99c..1e751500b 100644 --- a/src/allmydata/immutable/downloader/share.py +++ b/src/allmydata/immutable/downloader/share.py @@ -475,7 +475,9 @@ class Share(object): # there was corruption somewhere in the given range reason = "corruption in share[%d-%d): %s" % (start, start+offset, str(f.value)) - self._rref.callRemoteOnly("advise_corrupt_share", reason.encode("utf-8")) + self._rref.callRemote( + "advise_corrupt_share", reason.encode("utf-8") + ).addErrback(log.err) def _satisfy_block_hash_tree(self, needed_hashes): o_bh = self.actual_offsets["block_hashes"] diff --git a/src/allmydata/storage_client.py b/src/allmydata/storage_client.py index 22dd09bcb..c278abce3 100644 --- a/src/allmydata/storage_client.py +++ b/src/allmydata/storage_client.py @@ -1009,10 +1009,10 @@ class _StorageServer(object): shnum, reason, ): - return self._rref.callRemoteOnly( + self._rref.callRemote( "advise_corrupt_share", share_type, storage_index, shnum, reason, - ) + ).addErrback(log.err) From 04d2b27f46d9dee1122947e1f5bf50ac87a5b4aa Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Thu, 2 Sep 2021 15:24:19 -0400 Subject: [PATCH 12/47] News file. --- newsfragments/3779.minor | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 newsfragments/3779.minor diff --git a/newsfragments/3779.minor b/newsfragments/3779.minor new file mode 100644 index 000000000..e69de29bb From 78f70d6bdc1853537d7cc865f69368be541f746d Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Thu, 2 Sep 2021 15:53:14 -0400 Subject: [PATCH 13/47] write some words about lease renewal secrets --- docs/proposed/http-storage-node-protocol.rst | 5 +++ docs/specifications/index.rst | 1 + docs/specifications/lease.rst | 41 ++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 docs/specifications/lease.rst diff --git a/docs/proposed/http-storage-node-protocol.rst b/docs/proposed/http-storage-node-protocol.rst index d7a41e827..09c193c65 100644 --- a/docs/proposed/http-storage-node-protocol.rst +++ b/docs/proposed/http-storage-node-protocol.rst @@ -380,6 +380,11 @@ then the expiration time of that lease will be changed to 31 days after the time If it does not match an existing lease then a new lease will be created with this ``renew-secret`` which expires 31 days after the time of this operation. +The renew and cancel secrets must be 32 bytes long +(or in the case of JSON encoding they must UTF-8 encode to 32 bytes). +The server treats them as opaque values. +See `leases`_ for details about how the Tahoe-LAFS storage client constructs these values. + In these cases the response is ``NO CONTENT`` with an empty body. It is possible that the storage server will have no shares for the given ``storage_index`` because: diff --git a/docs/specifications/index.rst b/docs/specifications/index.rst index 2029c9e5a..e813acf07 100644 --- a/docs/specifications/index.rst +++ b/docs/specifications/index.rst @@ -14,5 +14,6 @@ the data formats used by Tahoe. URI-extension mutable dirnodes + lease servers-of-happiness backends/raic diff --git a/docs/specifications/lease.rst b/docs/specifications/lease.rst new file mode 100644 index 000000000..fd5535701 --- /dev/null +++ b/docs/specifications/lease.rst @@ -0,0 +1,41 @@ +.. -*- coding: utf-8 -*- + +Share Leases +============ + +A lease is a marker attached to a share indicating that some client has asked for that share to be retained for some amount of time. +The intent is to allow clients and servers to collaborate to determine which data should still be retained and which can be discarded to reclaim storage space. +Zero or more leases may be attached to any particular share. + +Renewal Secrets +--------------- + +Each lease is uniquely identified by its **renewal secret**. +This is a 32 byte string which can be used to extend the validity period of that lease. + +To a storage server a renewal secret is an opaque value which is only ever compared to other renewal secrets to determine equality. + +Storage clients will typically want to follow a scheme to deterministically derive the renewal secret for a particular share from information the client already holds about that share. +This allows a client to maintain and renew single long-lived lease without maintaining additional local state. + +The scheme in use in Tahoe-LAFS as of 1.16.0 is as follows. + +* The **netstring encoding** of a byte string is the concatenation of: + * the base 10 representation of the length of the string + * ":" + * the string + * "," +* The **sha256d digest** is the **sha256 digest** of the **sha256 digest** of a string. +* The **sha256d tagged digest** is the **sha256d digest** of the concatenation of the **netstring encoding** of one string with one other unmodified string. +* The **sha256d tagged pair digest** the **sha256d digest** of the concatenation of the **netstring encodings** of each of three strings. +* The **bucket renewal tag** is ``allmydata_bucket_renewal_secret_v1``. +* The **file renewal tag** is ``allmydata_file_renewal_secret_v1``. +* The **client renewal tag** is ``allmydata_client_renewal_secret_v1``. +* The **lease secret** is a 32 byte string, typically randomly generated once and then persisted for all future uses. +* The **client renewal secret** is the **sha256d tagged digest** of (**lease secret**, **client renewal tag**). +* The **storage index** is constructed using a capability-type-specific scheme. + See ``storage_index_hash`` and ``ssk_storage_index_hash`` calls in ``src/allmydata/uri.py``. +* The **file renewal secret** is the **sha256d tagged pair digest** of (**file renewal tag**, **client renewal secret**, **storage index**). +* The **base32 encoding** is ``base64.b32encode`` lowercased and with trailing ``=`` stripped. +* The **peer id** is the **base32 encoding** of the SHA1 digest of the server's x509 certificate. +* The **renewal secret** is the **sha256d tagged pair digest** of (**bucket renewal tag**, **file renewal secret**, **peer id**). From b6173eea839a21cdefedb6117cb5edf9b0fbee02 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Thu, 2 Sep 2021 16:42:27 -0400 Subject: [PATCH 14/47] news fragment --- docs/3774.documentation | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/3774.documentation diff --git a/docs/3774.documentation b/docs/3774.documentation new file mode 100644 index 000000000..d58105966 --- /dev/null +++ b/docs/3774.documentation @@ -0,0 +1 @@ +There is now a specification for the scheme which Tahoe-LAFS storage clients use to derive their lease renewal secrets. From 11a0b8d20979b1d0340819bd94b6b614496abde0 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Thu, 2 Sep 2021 16:44:42 -0400 Subject: [PATCH 15/47] attempt to appease rst --- docs/specifications/lease.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/specifications/lease.rst b/docs/specifications/lease.rst index fd5535701..bf8e8f181 100644 --- a/docs/specifications/lease.rst +++ b/docs/specifications/lease.rst @@ -21,10 +21,12 @@ This allows a client to maintain and renew single long-lived lease without maint The scheme in use in Tahoe-LAFS as of 1.16.0 is as follows. * The **netstring encoding** of a byte string is the concatenation of: + * the base 10 representation of the length of the string * ":" * the string * "," + * The **sha256d digest** is the **sha256 digest** of the **sha256 digest** of a string. * The **sha256d tagged digest** is the **sha256d digest** of the concatenation of the **netstring encoding** of one string with one other unmodified string. * The **sha256d tagged pair digest** the **sha256d digest** of the concatenation of the **netstring encodings** of each of three strings. From bb63331720f3e3d32fc6e2775e057064a1cc28b7 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 3 Sep 2021 09:04:08 -0400 Subject: [PATCH 16/47] put the newsfragment in the right place --- {docs => newsfragments}/3774.documentation | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {docs => newsfragments}/3774.documentation (100%) diff --git a/docs/3774.documentation b/newsfragments/3774.documentation similarity index 100% rename from docs/3774.documentation rename to newsfragments/3774.documentation From 3ba379ce7e90736adbc2b325f9965117bec09690 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 3 Sep 2021 09:06:27 -0400 Subject: [PATCH 17/47] some formatting improvements --- docs/specifications/lease.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/specifications/lease.rst b/docs/specifications/lease.rst index bf8e8f181..a8bee427e 100644 --- a/docs/specifications/lease.rst +++ b/docs/specifications/lease.rst @@ -22,17 +22,17 @@ The scheme in use in Tahoe-LAFS as of 1.16.0 is as follows. * The **netstring encoding** of a byte string is the concatenation of: - * the base 10 representation of the length of the string - * ":" - * the string - * "," + * the ascii encoding of the base 10 representation of the length of the string + * ``":"`` + * the string itself + * ``","`` * The **sha256d digest** is the **sha256 digest** of the **sha256 digest** of a string. * The **sha256d tagged digest** is the **sha256d digest** of the concatenation of the **netstring encoding** of one string with one other unmodified string. * The **sha256d tagged pair digest** the **sha256d digest** of the concatenation of the **netstring encodings** of each of three strings. -* The **bucket renewal tag** is ``allmydata_bucket_renewal_secret_v1``. -* The **file renewal tag** is ``allmydata_file_renewal_secret_v1``. -* The **client renewal tag** is ``allmydata_client_renewal_secret_v1``. +* The **bucket renewal tag** is ``"allmydata_bucket_renewal_secret_v1"``. +* The **file renewal tag** is ``"allmydata_file_renewal_secret_v1"``. +* The **client renewal tag** is ``"allmydata_client_renewal_secret_v1"``. * The **lease secret** is a 32 byte string, typically randomly generated once and then persisted for all future uses. * The **client renewal secret** is the **sha256d tagged digest** of (**lease secret**, **client renewal tag**). * The **storage index** is constructed using a capability-type-specific scheme. From 8fe9532faf64c9d65f46f0ecf92d38af2634568e Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 3 Sep 2021 09:17:34 -0400 Subject: [PATCH 18/47] get the cross-reference right --- docs/proposed/http-storage-node-protocol.rst | 2 +- docs/specifications/lease.rst | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/proposed/http-storage-node-protocol.rst b/docs/proposed/http-storage-node-protocol.rst index 09c193c65..47f94db49 100644 --- a/docs/proposed/http-storage-node-protocol.rst +++ b/docs/proposed/http-storage-node-protocol.rst @@ -383,7 +383,7 @@ then a new lease will be created with this ``renew-secret`` which expires 31 day The renew and cancel secrets must be 32 bytes long (or in the case of JSON encoding they must UTF-8 encode to 32 bytes). The server treats them as opaque values. -See `leases`_ for details about how the Tahoe-LAFS storage client constructs these values. +:ref:`Share Leases` gives details about how the Tahoe-LAFS storage client constructs these values. In these cases the response is ``NO CONTENT`` with an empty body. diff --git a/docs/specifications/lease.rst b/docs/specifications/lease.rst index a8bee427e..54ee5cd28 100644 --- a/docs/specifications/lease.rst +++ b/docs/specifications/lease.rst @@ -1,5 +1,7 @@ .. -*- coding: utf-8 -*- +.. _share leases: + Share Leases ============ From 78a1d65b784b50486c8c59f8cdc5bad706405797 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 3 Sep 2021 12:33:07 -0400 Subject: [PATCH 19/47] RFC 7049, section 4.1 describes correct JSON encoding for byte strings --- docs/proposed/http-storage-node-protocol.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/proposed/http-storage-node-protocol.rst b/docs/proposed/http-storage-node-protocol.rst index 47f94db49..bc44468a6 100644 --- a/docs/proposed/http-storage-node-protocol.rst +++ b/docs/proposed/http-storage-node-protocol.rst @@ -380,8 +380,7 @@ then the expiration time of that lease will be changed to 31 days after the time If it does not match an existing lease then a new lease will be created with this ``renew-secret`` which expires 31 days after the time of this operation. -The renew and cancel secrets must be 32 bytes long -(or in the case of JSON encoding they must UTF-8 encode to 32 bytes). +The renew and cancel secrets must be 32 bytes long. The server treats them as opaque values. :ref:`Share Leases` gives details about how the Tahoe-LAFS storage client constructs these values. From a864bd51323f4e1378ced63a50516bad645e559f Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 3 Sep 2021 12:44:23 -0400 Subject: [PATCH 20/47] more precision --- docs/proposed/http-storage-node-protocol.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/proposed/http-storage-node-protocol.rst b/docs/proposed/http-storage-node-protocol.rst index bc44468a6..ade0bc167 100644 --- a/docs/proposed/http-storage-node-protocol.rst +++ b/docs/proposed/http-storage-node-protocol.rst @@ -380,7 +380,7 @@ then the expiration time of that lease will be changed to 31 days after the time If it does not match an existing lease then a new lease will be created with this ``renew-secret`` which expires 31 days after the time of this operation. -The renew and cancel secrets must be 32 bytes long. +``renew-secret`` and ``cancel-secret`` values must be 32 bytes long. The server treats them as opaque values. :ref:`Share Leases` gives details about how the Tahoe-LAFS storage client constructs these values. From bb57fcfb50d4e01bbc4de2e23dbbf7a60c004031 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 3 Sep 2021 12:45:45 -0400 Subject: [PATCH 21/47] words about the cancel secret --- docs/specifications/lease.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/specifications/lease.rst b/docs/specifications/lease.rst index 54ee5cd28..8fc7c42eb 100644 --- a/docs/specifications/lease.rst +++ b/docs/specifications/lease.rst @@ -43,3 +43,21 @@ The scheme in use in Tahoe-LAFS as of 1.16.0 is as follows. * The **base32 encoding** is ``base64.b32encode`` lowercased and with trailing ``=`` stripped. * The **peer id** is the **base32 encoding** of the SHA1 digest of the server's x509 certificate. * The **renewal secret** is the **sha256d tagged pair digest** of (**bucket renewal tag**, **file renewal secret**, **peer id**). + +Cancel Secrets +-------------- + +Lease cancellation is unimplemented. +Nevertheless, +a cancel secret is sent by storage clients to storage servers and stored in lease records. + +The scheme for deriving **cancel secret** in use in Tahoe-LAFS as of 1.16.0 is similar to that used to derive the **renewal secret**. + +The differences are: + +* Use of **client renewal tag** is replaced by use of **client cancel tag**. +* Use of **file renewal secret** is replaced by use of **file cancel tag**. +* Use of **bucket renewal tag** is replaced by use of **bucket cancel tag**. +* **client cancel tag** is ``"allmydata_client_cancel_secret_v1"``. +* **file cancel tag** is ``"allmydata_file_cancel_secret_v1"``. +* **bucket cancel tag** is ``"allmydata_bucket_cancel_secret_v1"``. From 148a0573dea02d67e9b05e1156afe47807402a96 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Fri, 3 Sep 2021 13:11:02 -0400 Subject: [PATCH 22/47] Replace colon on filename only, not on whole path. This would break Windows logging of corruption reports, since colon would be removed from e.g. "C:". --- src/allmydata/storage/server.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/allmydata/storage/server.py b/src/allmydata/storage/server.py index 56b47ae89..f4996756e 100644 --- a/src/allmydata/storage/server.py +++ b/src/allmydata/storage/server.py @@ -708,8 +708,10 @@ class StorageServer(service.MultiService, Referenceable): now = time_format.iso_utc(sep="T") si_s = si_b2a(storage_index) # windows can't handle colons in the filename - fn = os.path.join(self.corruption_advisory_dir, - "%s--%s-%d" % (now, str(si_s, "utf-8"), shnum)).replace(":","") + fn = os.path.join( + self.corruption_advisory_dir, + ("%s--%s-%d" % (now, str(si_s, "utf-8"), shnum)).replace(":","") + ) with open(fn, "w") as f: f.write("report: Share Corruption\n") f.write("type: %s\n" % bytes_to_native_str(share_type)) From c7e82b1640238b9e8af65d3f05a7a21647cba183 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Fri, 3 Sep 2021 13:12:57 -0400 Subject: [PATCH 23/47] Guess it's a bugfix. --- newsfragments/3779.bugfix | 1 + newsfragments/3779.minor | 0 2 files changed, 1 insertion(+) create mode 100644 newsfragments/3779.bugfix delete mode 100644 newsfragments/3779.minor diff --git a/newsfragments/3779.bugfix b/newsfragments/3779.bugfix new file mode 100644 index 000000000..c6745f1af --- /dev/null +++ b/newsfragments/3779.bugfix @@ -0,0 +1 @@ +Fixed bug where share corruption events were not recorded on Windows. \ No newline at end of file diff --git a/newsfragments/3779.minor b/newsfragments/3779.minor deleted file mode 100644 index e69de29bb..000000000 From f0fe323fa1e32555aeb21d9332ad30ff319084b7 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 3 Sep 2021 15:14:09 -0400 Subject: [PATCH 24/47] Simplify the immutable share reading interface --- docs/proposed/http-storage-node-protocol.rst | 25 +++++++------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/docs/proposed/http-storage-node-protocol.rst b/docs/proposed/http-storage-node-protocol.rst index d7a41e827..fcf1e43fe 100644 --- a/docs/proposed/http-storage-node-protocol.rst +++ b/docs/proposed/http-storage-node-protocol.rst @@ -509,28 +509,21 @@ For example:: [1, 5] -``GET /v1/immutable/:storage_index?share=:s0&share=:sN&offset=o1&size=z0&offset=oN&size=zN`` -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +``GET /v1/immutable/:storage_index/:share_number?offset=:offset&length=:length +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -Read data from the indicated immutable shares. -If ``share`` query parameters are given, selecte only those shares for reading. -Otherwise, select all shares present. -If ``size`` and ``offset`` query parameters are given, -only the portions thus identified of the selected shares are returned. -Otherwise, all data is from the selected shares is returned. +Read a contiguous sequence of bytes from one share in one bucket. +If the ``offset`` query parameter is given then it is interpreted as a base 10 representation of an integer giving the position at which to begin reading. +If it is not given then begin reading at the beginning of the share. +If the ``length`` query parameter is given then it is interpreted as a base 10 representation of an integer giving the maximum number of bytes to read and return. +If it is not given then bytes will be read until the end of the share is reached. -The response body contains a mapping giving the read data. -For example:: - - { - 3: ["foo", "bar"], - 7: ["baz", "quux"] - } +The response body is the raw share data (i.e., ``application/octet-stream``). Discussion `````````` -Offset and size of the requested data are specified here as query arguments. +Offset and length of the requested data are specified here as query arguments. Instead, this information could be present in a ``Range`` header in the request. This is the more obvious choice and leverages an HTTP feature built for exactly this use-case. However, HTTP requires that the ``Content-Type`` of the response to "range requests" be ``multipart/...``. From 895c77fecf9559a31a7770ae98841846124e995e Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 3 Sep 2021 15:15:48 -0400 Subject: [PATCH 25/47] news fragment --- newsfragments/3777.documentation | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/3777.documentation diff --git a/newsfragments/3777.documentation b/newsfragments/3777.documentation new file mode 100644 index 000000000..7635cc1e6 --- /dev/null +++ b/newsfragments/3777.documentation @@ -0,0 +1 @@ +The Great Black Swamp proposed specification now has a simplified interface for reading data from immutable shares. From 18cbff1789c6f3525c3f8127b629f534bc5c9a9f Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 3 Sep 2021 15:22:29 -0400 Subject: [PATCH 26/47] minimal discussion about this change --- docs/proposed/http-storage-node-protocol.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/proposed/http-storage-node-protocol.rst b/docs/proposed/http-storage-node-protocol.rst index fcf1e43fe..fb327b0a8 100644 --- a/docs/proposed/http-storage-node-protocol.rst +++ b/docs/proposed/http-storage-node-protocol.rst @@ -534,6 +534,15 @@ There are many drawbacks to this framing technique: 2. It is resource-intensive to parse. 3. It is complex to parse safely [#]_ [#]_ [#]_ [#]_. +A previous revision of this specification allowed requesting one or more contiguous sequences from one or more shares. +This *superficially* mirrored the Foolscap based interface somewhat closely. +The interface was simplified to this version because this version is all that is required to let clients retrieve any desired information. +It only requires that the client issue multiple requests. +This can be done with pipelining or parallel requests to avoid an additional latency penalty. +In the future, +if there are performance goals, +benchmarks can demonstrate whether they are achieved by a more complicated interface or some other change. + Mutable ------- From 8d15a0d5ebcbf16979a984484807a0c54f6b4a24 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 3 Sep 2021 16:27:57 -0400 Subject: [PATCH 27/47] words about authorization --- docs/proposed/http-storage-node-protocol.rst | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/proposed/http-storage-node-protocol.rst b/docs/proposed/http-storage-node-protocol.rst index d7a41e827..0daa48cab 100644 --- a/docs/proposed/http-storage-node-protocol.rst +++ b/docs/proposed/http-storage-node-protocol.rst @@ -24,11 +24,21 @@ Glossary storage server a Tahoe-LAFS process configured to offer storage and reachable over the network for store and retrieve operations + storage service + a Python object held in memory in the storage server which provides the implementation of the storage protocol + introducer a Tahoe-LAFS process at a known location configured to re-publish announcements about the location of storage servers fURL a self-authenticating URL-like string which can be used to locate a remote object using the Foolscap protocol + (the storage service is an example of such an object) + + NURL + a self-authenticating URL-like string almost exactly like a fURL but without being tied to Foolscap + + swissnum + a short random string which is part of a fURL and which acts as a shared secret to authorize clients to use a storage service lease state associated with a share informing a storage server of the duration of storage desired by a client @@ -128,6 +138,8 @@ The Foolscap-based protocol offers: * A careful configuration of the TLS connection parameters *may* also offer **forward secrecy**. However, Tahoe-LAFS' use of Foolscap takes no steps to ensure this is the case. +* **Storage authorization** by way of a capability contained in the fURL addressing a storage service. + Discussion !!!!!!!!!! @@ -158,6 +170,10 @@ there is no way to write data which appears legitimate to a legitimate client). Therefore, **message confidentiality** is necessary when exchanging these secrets. **Forward secrecy** is preferred so that an attacker recording an exchange today cannot launch this attack at some future point after compromising the necessary keys. +A storage service offers service only to some clients. +A client proves their authorization to use the storage service by presenting a shared secret taken from the fURL. +In this way **storage authorization** is performed to prevent disallowed parties from consuming all available storage resources. + Functionality ------------- @@ -214,6 +230,10 @@ Additionally, by continuing to interact using TLS, Bob's client and Alice's storage node are assured of both **message authentication** and **message confidentiality**. +Bob's client further inspects the fURL for the *swissnum*. +When Bob's client issues HTTP requests to Alice's storage node it includes the *swissnum* in its requests. +**Storage authorization** has been achieved. + .. note:: Foolscap TubIDs are 20 bytes (SHA1 digest of the certificate). @@ -343,6 +363,12 @@ one branch contains all of the share data; another branch contains all of the lease data; etc. +Authorization is required for all endpoints. +The standard HTTP authorization protocol is used. +The authentication *type* used is ``Tahoe-LAFS``. +The swissnum from the NURL used to locate the storage service is used as the *credentials*. +If credentials are not presented or the swissnum is not associated with a storage service then no storage processing is performed and the request receives an ``UNAUTHORIZED`` response. + General ~~~~~~~ From a4334b35a0bb6f669429306187cc0fa93cef2518 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 3 Sep 2021 16:28:27 -0400 Subject: [PATCH 28/47] news fragment --- newsfragments/3785.documentation | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/3785.documentation diff --git a/newsfragments/3785.documentation b/newsfragments/3785.documentation new file mode 100644 index 000000000..4eb268f79 --- /dev/null +++ b/newsfragments/3785.documentation @@ -0,0 +1 @@ +The Great Black Swamp specification now describes the required authorization scheme. From e2b483e093b11cd31a513b2069755df7a0bf13ed Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Tue, 7 Sep 2021 08:13:03 -0400 Subject: [PATCH 29/47] an even stronger prevention is provided --- docs/proposed/http-storage-node-protocol.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/proposed/http-storage-node-protocol.rst b/docs/proposed/http-storage-node-protocol.rst index 0daa48cab..0c6186bc1 100644 --- a/docs/proposed/http-storage-node-protocol.rst +++ b/docs/proposed/http-storage-node-protocol.rst @@ -172,7 +172,7 @@ Therefore, **message confidentiality** is necessary when exchanging these secret A storage service offers service only to some clients. A client proves their authorization to use the storage service by presenting a shared secret taken from the fURL. -In this way **storage authorization** is performed to prevent disallowed parties from consuming all available storage resources. +In this way **storage authorization** is performed to prevent disallowed parties from consuming any storage resources. Functionality ------------- From 7219291343299263050ddaf7e39ac1f6af2c62b7 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Tue, 7 Sep 2021 13:30:21 -0400 Subject: [PATCH 30/47] add a reference implementation for lease renewal secret derivation --- docs/proposed/http-storage-node-protocol.rst | 2 +- docs/specifications/derive_renewal_secret.py | 87 ++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 docs/specifications/derive_renewal_secret.py diff --git a/docs/proposed/http-storage-node-protocol.rst b/docs/proposed/http-storage-node-protocol.rst index ade0bc167..3a09ccae0 100644 --- a/docs/proposed/http-storage-node-protocol.rst +++ b/docs/proposed/http-storage-node-protocol.rst @@ -45,7 +45,7 @@ Glossary (sometimes "slot" is considered a synonym for "storage index of a slot") storage index - a short string which can address a slot or a bucket + a 16 byte string which can address a slot or a bucket (in practice, derived by hashing the encryption key associated with contents of that slot or bucket) write enabler diff --git a/docs/specifications/derive_renewal_secret.py b/docs/specifications/derive_renewal_secret.py new file mode 100644 index 000000000..75009eda4 --- /dev/null +++ b/docs/specifications/derive_renewal_secret.py @@ -0,0 +1,87 @@ + +""" +This is a reference implementation of the lease renewal secret derivation +protocol in use by Tahoe-LAFS clients as of 1.16.0. +""" + +from allmydata.util.base32 import ( + a2b as b32decode, + b2a as b32encode, +) +from allmydata.util.hashutil import ( + tagged_hash, + tagged_pair_hash, +) + + +def derive_renewal_secret(lease_secret: bytes, storage_index: bytes, tubid: bytes) -> bytes: + assert len(lease_secret) == 32 + assert len(storage_index) == 16 + assert len(tubid) == 20 + + bucket_renewal_tag = b"allmydata_bucket_renewal_secret_v1" + file_renewal_tag = b"allmydata_file_renewal_secret_v1" + client_renewal_tag = b"allmydata_client_renewal_secret_v1" + + client_renewal_secret = tagged_hash(lease_secret, client_renewal_tag) + file_renewal_secret = tagged_pair_hash( + file_renewal_tag, + client_renewal_secret, + storage_index, + ) + peer_id = tubid + + return tagged_pair_hash(bucket_renewal_tag, file_renewal_secret, peer_id) + +def demo(): + secret = b32encode(derive_renewal_secret( + b"lease secretxxxxxxxxxxxxxxxxxxxx", + b"storage indexxxx", + b"tub idxxxxxxxxxxxxxx", + )).decode("ascii") + print("An example renewal secret: {}".format(secret)) + +def test(): + # These test vectors created by intrumenting Tahoe-LAFS + # bb57fcfb50d4e01bbc4de2e23dbbf7a60c004031 to emit `self.renew_secret` in + # allmydata.immutable.upload.ServerTracker.query and then uploading a + # couple files to a couple different storage servers. + test_vector = [ + dict(lease_secret=b"boity2cdh7jvl3ltaeebuiobbspjmbuopnwbde2yeh4k6x7jioga", + storage_index=b"vrttmwlicrzbt7gh5qsooogr7u", + tubid=b"v67jiisoty6ooyxlql5fuucitqiok2ic", + expected=b"osd6wmc5vz4g3ukg64sitmzlfiaaordutrez7oxdp5kkze7zp5zq", + ), + dict(lease_secret=b"boity2cdh7jvl3ltaeebuiobbspjmbuopnwbde2yeh4k6x7jioga", + storage_index=b"75gmmfts772ww4beiewc234o5e", + tubid=b"v67jiisoty6ooyxlql5fuucitqiok2ic", + expected=b"35itmusj7qm2pfimh62snbyxp3imreofhx4djr7i2fweta75szda", + ), + dict(lease_secret=b"boity2cdh7jvl3ltaeebuiobbspjmbuopnwbde2yeh4k6x7jioga", + storage_index=b"75gmmfts772ww4beiewc234o5e", + tubid=b"lh5fhobkjrmkqjmkxhy3yaonoociggpz", + expected=b"srrlruge47ws3lm53vgdxprgqb6bz7cdblnuovdgtfkqrygrjm4q", + ), + dict(lease_secret=b"vacviff4xfqxsbp64tdr3frg3xnkcsuwt5jpyat2qxcm44bwu75a", + storage_index=b"75gmmfts772ww4beiewc234o5e", + tubid=b"lh5fhobkjrmkqjmkxhy3yaonoociggpz", + expected=b"b4jledjiqjqekbm2erekzqumqzblegxi23i5ojva7g7xmqqnl5pq", + ), + ] + + for n, item in enumerate(test_vector): + derived = b32encode(derive_renewal_secret( + b32decode(item["lease_secret"]), + b32decode(item["storage_index"]), + b32decode(item["tubid"]), + )) + assert derived == item["expected"] , \ + "Test vector {} failed: {} (expected) != {} (derived)".format( + n, + item["expected"], + derived, + ) + print("{} test vectors validated".format(len(test_vector))) + +test() +demo() From ee224305b7a64f071103d387a7eb646f197710b7 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Tue, 7 Sep 2021 13:37:12 -0400 Subject: [PATCH 31/47] link to the reference implementation --- docs/specifications/lease.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/specifications/lease.rst b/docs/specifications/lease.rst index 8fc7c42eb..16adef0a7 100644 --- a/docs/specifications/lease.rst +++ b/docs/specifications/lease.rst @@ -44,6 +44,12 @@ The scheme in use in Tahoe-LAFS as of 1.16.0 is as follows. * The **peer id** is the **base32 encoding** of the SHA1 digest of the server's x509 certificate. * The **renewal secret** is the **sha256d tagged pair digest** of (**bucket renewal tag**, **file renewal secret**, **peer id**). +A reference implementation is available. + +.. literalinclude:: derive_renewal_secret.py + :language: python + :linenos: + Cancel Secrets -------------- From 82f94ae5af4791ff8d322f908432ae8c1fc7b2d0 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Tue, 7 Sep 2021 14:17:38 -0400 Subject: [PATCH 32/47] Yay use the Range request header --- docs/proposed/http-storage-node-protocol.rst | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docs/proposed/http-storage-node-protocol.rst b/docs/proposed/http-storage-node-protocol.rst index eb5154e45..5f67fcaa6 100644 --- a/docs/proposed/http-storage-node-protocol.rst +++ b/docs/proposed/http-storage-node-protocol.rst @@ -539,24 +539,20 @@ For example:: [1, 5] -``GET /v1/immutable/:storage_index/:share_number?offset=:offset&length=:length -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +``GET /v1/immutable/:storage_index/:share_number +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Read a contiguous sequence of bytes from one share in one bucket. -If the ``offset`` query parameter is given then it is interpreted as a base 10 representation of an integer giving the position at which to begin reading. -If it is not given then begin reading at the beginning of the share. -If the ``length`` query parameter is given then it is interpreted as a base 10 representation of an integer giving the maximum number of bytes to read and return. -If it is not given then bytes will be read until the end of the share is reached. - The response body is the raw share data (i.e., ``application/octet-stream``). +The ``Range`` header may be used to request exactly one ``bytes`` range. +Interpretation and response behavior is as specified in RFC 7233 ยง 4.1. +Multiple ranges in a single request are *not* supported. Discussion `````````` -Offset and length of the requested data are specified here as query arguments. -Instead, this information could be present in a ``Range`` header in the request. -This is the more obvious choice and leverages an HTTP feature built for exactly this use-case. -However, HTTP requires that the ``Content-Type`` of the response to "range requests" be ``multipart/...``. +Multiple ``bytes`` ranges are not supported. +HTTP requires that the ``Content-Type`` of the response in that case be ``multipart/...``. The ``multipart`` major type brings along string sentinel delimiting as a means to frame the different response parts. There are many drawbacks to this framing technique: From a988f126bee53252c0692dda40b3c0262000cba4 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Tue, 7 Sep 2021 16:12:01 -0400 Subject: [PATCH 33/47] fix markup error --- docs/proposed/http-storage-node-protocol.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/proposed/http-storage-node-protocol.rst b/docs/proposed/http-storage-node-protocol.rst index 5f67fcaa6..a84d62176 100644 --- a/docs/proposed/http-storage-node-protocol.rst +++ b/docs/proposed/http-storage-node-protocol.rst @@ -539,8 +539,8 @@ For example:: [1, 5] -``GET /v1/immutable/:storage_index/:share_number -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +``GET /v1/immutable/:storage_index/:share_number`` +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Read a contiguous sequence of bytes from one share in one bucket. The response body is the raw share data (i.e., ``application/octet-stream``). From e0414fd8af374ab8b4f04cbeb8d38be94d18b16a Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Wed, 8 Sep 2021 09:14:47 -0400 Subject: [PATCH 34/47] Upload eliot.log on CircleCI runs --- .circleci/config.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 28e4c8d58..62d1bd752 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -271,6 +271,11 @@ jobs: # in the project source checkout. path: "/tmp/project/_trial_temp/test.log" + - store_artifacts: &STORE_ELIOT_LOG + # Despite passing --workdir /tmp to tox above, it still runs trial + # in the project source checkout. + path: "/tmp/project/eliot.log" + - store_artifacts: &STORE_OTHER_ARTIFACTS # Store any other artifacts, too. This is handy to allow other jobs # sharing most of the definition of this one to be able to @@ -413,6 +418,7 @@ jobs: - run: *RUN_TESTS - store_test_results: *STORE_TEST_RESULTS - store_artifacts: *STORE_TEST_LOG + - store_artifacts: *STORE_ELIOT_LOG - store_artifacts: *STORE_OTHER_ARTIFACTS - run: *SUBMIT_COVERAGE From bcf1c7153676971d75be573f2cf9ad64c360f14a Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Wed, 8 Sep 2021 09:15:02 -0400 Subject: [PATCH 35/47] Upload trial's test.log on GitHub Actions --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e95d2ee88..f4e0b50ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,6 +83,12 @@ jobs: name: eliot.log path: eliot.log + - name: Upload trial log + uses: actions/upload-artifact@v1 + with: + name: _trial_temp/test.log + path: _trial_temp/test.log + # Upload this job's coverage data to Coveralls. While there is a GitHub # Action for this, as of Jan 2021 it does not support Python coverage # files - only lcov files. Therefore, we use coveralls-python, the From 1d4bc54b487e07d0c7316da77b834a2ddf2bc856 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Wed, 8 Sep 2021 09:15:13 -0400 Subject: [PATCH 36/47] Just upload the log all the time --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f4e0b50ce..9e6c246b6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,9 +76,8 @@ jobs: - name: Run tox for corresponding Python version run: python -m tox - - name: Upload eliot.log in case of failure + - name: Upload eliot.log uses: actions/upload-artifact@v1 - if: failure() with: name: eliot.log path: eliot.log From dd4e6c7741deb2545400b9c0bcb1337edccf483c Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Wed, 8 Sep 2021 09:15:28 -0400 Subject: [PATCH 37/47] whitespace --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9e6c246b6..cd6f872bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -141,7 +141,7 @@ jobs: # See notes about parallel builds on GitHub Actions at # https://coveralls-python.readthedocs.io/en/latest/usage/configuration.html finish-coverage-report: - needs: + needs: - "coverage" runs-on: "ubuntu-latest" container: "python:3-slim" @@ -178,7 +178,7 @@ jobs: - name: Install Tor [Ubuntu] if: matrix.os == 'ubuntu-latest' run: sudo apt install tor - + # TODO: See https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3744. # We have to use an older version of Tor for running integration # tests on macOS. From e3804e0354f30c4fc9a1371e5c4d9f5fc52b6a3a Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Wed, 8 Sep 2021 09:15:40 -0400 Subject: [PATCH 38/47] news fragment --- newsfragments/3792.minor | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 newsfragments/3792.minor diff --git a/newsfragments/3792.minor b/newsfragments/3792.minor new file mode 100644 index 000000000..e69de29bb From 93f2cf5ce1460192cae4c3ba9d42808c2caed107 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Wed, 8 Sep 2021 09:41:32 -0400 Subject: [PATCH 39/47] Minor edits --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index bb8c5c252..3686a58b8 100644 --- a/README.rst +++ b/README.rst @@ -56,10 +56,10 @@ For more detailed instructions, read `docs/INSTALL.rst `__ . Once tahoe --version works, see `docs/running.rst `__ to learn how to set up your first Tahoe-LAFS node. -๐Ÿ `Python 3` Support +๐Ÿ Python 3 Support -------------------- -`Python 3` support has been introduced as from `Tahoe-LAFS 1.16.x` alongside `Python 2`. System admnistrators are advised to start running Tahoe on `Python 3` and should expect the drop of `Python 2` support any future version from now. Please, feel free to file issues if you run into bugs while running Tahoe on `Python 3`. +Python 3 support has been introduced starting with Tahoe-LAFS 1.16.0, alongside Python 2. System admnistrators are advised to start running Tahoe on Python 3 and should expect Python 2 support to be dropped in a future version. Please, feel free to file issues if you run into bugs while running Tahoe on Python 3. ๐Ÿค– Issues From 2a6870d77253f0274b56cc9f9d725d7bd305b007 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Wed, 8 Sep 2021 09:42:23 -0400 Subject: [PATCH 40/47] The name must be pathless, it seems --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cd6f872bb..e161ec243 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,7 +85,7 @@ jobs: - name: Upload trial log uses: actions/upload-artifact@v1 with: - name: _trial_temp/test.log + name: test.log path: _trial_temp/test.log # Upload this job's coverage data to Coveralls. While there is a GitHub From edb380f80163f87428f5ba9cbaa1904d099228c4 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Wed, 8 Sep 2021 10:48:32 -0400 Subject: [PATCH 41/47] Bridge Foolscap logs to Twisted's so they appear in test.log --- src/allmydata/test/__init__.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/allmydata/test/__init__.py b/src/allmydata/test/__init__.py index 893aa15ce..8b11ffd17 100644 --- a/src/allmydata/test/__init__.py +++ b/src/allmydata/test/__init__.py @@ -55,9 +55,22 @@ def disable_foolscap_incidents(): iq = NonQualifier() theLogger.setIncidentQualifier(iq) -# we disable incident reporting for all unit tests. -disable_foolscap_incidents() +def bridge_foolscap_logs_to_twisted(): + # Dump all of the Foolscap logs into the Twisted logging system where they + # can get scooped up by any other log observers we configure. + from foolscap.logging import log + log.bridgeLogsToTwisted() +def configure_foolscap_logging(): + # we disable incident reporting for all unit tests. + disable_foolscap_incidents() + + # we want to collect Foolscap logs too, and it's easiest to do this by + # getting them into one of the log systems we already have collection set + # up for. + bridge_foolscap_logs_to_twisted() + +configure_foolscap_logging() def _configure_hypothesis(): from os import environ From 30b43a8ed6b543a5fe8e0dc01d8cbebb175cd7bd Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Wed, 8 Sep 2021 12:41:37 -0400 Subject: [PATCH 42/47] Revert "Bridge Foolscap logs to Twisted's so they appear in test.log" This reverts commit edb380f80163f87428f5ba9cbaa1904d099228c4. This breaks the test suite hard --- src/allmydata/test/__init__.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/allmydata/test/__init__.py b/src/allmydata/test/__init__.py index 8b11ffd17..893aa15ce 100644 --- a/src/allmydata/test/__init__.py +++ b/src/allmydata/test/__init__.py @@ -55,22 +55,9 @@ def disable_foolscap_incidents(): iq = NonQualifier() theLogger.setIncidentQualifier(iq) -def bridge_foolscap_logs_to_twisted(): - # Dump all of the Foolscap logs into the Twisted logging system where they - # can get scooped up by any other log observers we configure. - from foolscap.logging import log - log.bridgeLogsToTwisted() +# we disable incident reporting for all unit tests. +disable_foolscap_incidents() -def configure_foolscap_logging(): - # we disable incident reporting for all unit tests. - disable_foolscap_incidents() - - # we want to collect Foolscap logs too, and it's easiest to do this by - # getting them into one of the log systems we already have collection set - # up for. - bridge_foolscap_logs_to_twisted() - -configure_foolscap_logging() def _configure_hypothesis(): from os import environ From 02ad7b9709328319ef568b065de878d8bb9f6cc7 Mon Sep 17 00:00:00 2001 From: "F. E Noel Nfebe" Date: Fri, 10 Sep 2021 15:35:33 +0100 Subject: [PATCH 43/47] Improved python 3 support text format. Co-authored-by: Jean-Paul Calderone --- README.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 3686a58b8..df171b99f 100644 --- a/README.rst +++ b/README.rst @@ -59,7 +59,9 @@ Once tahoe --version works, see `docs/running.rst `__ to learn ๐Ÿ Python 3 Support -------------------- -Python 3 support has been introduced starting with Tahoe-LAFS 1.16.0, alongside Python 2. System admnistrators are advised to start running Tahoe on Python 3 and should expect Python 2 support to be dropped in a future version. Please, feel free to file issues if you run into bugs while running Tahoe on Python 3. +Python 3 support has been introduced starting with Tahoe-LAFS 1.16.0, alongside Python 2. +System administrators are advised to start running Tahoe on Python 3 and should expect Python 2 support to be dropped in a future version. +Please, feel free to file issues if you run into bugs while running Tahoe on Python 3. ๐Ÿค– Issues From 38fcbd56e0c1fffe3c4baf0789ce5e855d200dba Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 10 Sep 2021 10:46:17 -0400 Subject: [PATCH 44/47] Adjust the news fragment to match the writing style guide --- newsfragments/3749.documentation | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/newsfragments/3749.documentation b/newsfragments/3749.documentation index 82e1e7856..554564a0b 100644 --- a/newsfragments/3749.documentation +++ b/newsfragments/3749.documentation @@ -1 +1 @@ -Fixes links to the installation and about Tahoe pages in the docs. +Documentation and installation links in the README have been fixed. From ac9875da75c1dd42080f1d18a506a17846671df6 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Fri, 10 Sep 2021 11:39:48 -0400 Subject: [PATCH 45/47] Add explanation to new error logging. --- src/allmydata/immutable/downloader/share.py | 2 +- src/allmydata/immutable/layout.py | 2 +- src/allmydata/storage_client.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/allmydata/immutable/downloader/share.py b/src/allmydata/immutable/downloader/share.py index 1e751500b..41e11426f 100644 --- a/src/allmydata/immutable/downloader/share.py +++ b/src/allmydata/immutable/downloader/share.py @@ -477,7 +477,7 @@ class Share(object): str(f.value)) self._rref.callRemote( "advise_corrupt_share", reason.encode("utf-8") - ).addErrback(log.err) + ).addErrback(log.err, "Error from remote call to advise_corrupt_share") def _satisfy_block_hash_tree(self, needed_hashes): o_bh = self.actual_offsets["block_hashes"] diff --git a/src/allmydata/immutable/layout.py b/src/allmydata/immutable/layout.py index 886a5db73..6c7362b8a 100644 --- a/src/allmydata/immutable/layout.py +++ b/src/allmydata/immutable/layout.py @@ -254,7 +254,7 @@ class WriteBucketProxy(object): return d def abort(self): - self._rref.callRemote("abort").addErrback(log.err) + self._rref.callRemote("abort").addErrback(log.err, "Error from remote call to abort an immutable write bucket") def get_servername(self): return self._server.get_name() diff --git a/src/allmydata/storage_client.py b/src/allmydata/storage_client.py index c278abce3..e9dc8c84c 100644 --- a/src/allmydata/storage_client.py +++ b/src/allmydata/storage_client.py @@ -1015,4 +1015,4 @@ class _StorageServer(object): storage_index, shnum, reason, - ).addErrback(log.err) + ).addErrback(log.err, "Error from remote call to advise_corrupt_share") From fb61e29b5933fb9f84df4fc319e48a56f8e22659 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Fri, 10 Sep 2021 11:40:30 -0400 Subject: [PATCH 46/47] Better explanation. --- newsfragments/3779.bugfix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/newsfragments/3779.bugfix b/newsfragments/3779.bugfix index c6745f1af..073046474 100644 --- a/newsfragments/3779.bugfix +++ b/newsfragments/3779.bugfix @@ -1 +1 @@ -Fixed bug where share corruption events were not recorded on Windows. \ No newline at end of file +Fixed bug where share corruption events were not logged on storage servers running on Windows. \ No newline at end of file From 5264108182ddd7a3a199e1dfb7af6db9dca08d18 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Mon, 13 Sep 2021 13:24:35 -0400 Subject: [PATCH 47/47] account for the archive message renumbering in the list migration --- NEWS.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.rst b/NEWS.rst index d70fac6b5..1cfc726ae 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -1188,7 +1188,7 @@ Precautions when Upgrading .. _`#1915`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1915 .. _`#1926`: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1926 .. _`message to the tahoe-dev mailing list`: - https://lists.tahoe-lafs.org/pipermail/tahoe-dev/2013-March/008096.html + https://lists.tahoe-lafs.org/pipermail/tahoe-dev/2013-March/008079.html Release 1.9.2 (2012-07-03)