Merge remote-tracking branch 'origin/master' into 3855-immutable-http-apis-part-1

This commit is contained in:
Itamar Turner-Trauring 2022-01-25 10:42:04 -05:00
commit 609bd819bb
19 changed files with 261 additions and 89 deletions

View File

@ -49,8 +49,8 @@ workflows:
- "pypy27-buster":
{}
# Just one Python 3.6 configuration while the port is in-progress.
- "python36":
# Test against Python 3:
- "python37":
{}
# Other assorted tasks and configurations
@ -118,7 +118,7 @@ workflows:
<<: *DOCKERHUB_CONTEXT
- "build-image-pypy27-buster":
<<: *DOCKERHUB_CONTEXT
- "build-image-python36-ubuntu":
- "build-image-python37-ubuntu":
<<: *DOCKERHUB_CONTEXT
@ -379,11 +379,11 @@ jobs:
user: "nobody"
python36:
python37:
<<: *UBUNTU_18_04
docker:
- <<: *DOCKERHUB_AUTH
image: "tahoelafsci/ubuntu:18.04-py3"
image: "tahoelafsci/ubuntu:18.04-py3.7"
user: "nobody"
environment:
@ -392,7 +392,7 @@ jobs:
# this reporter on Python 3. So drop that and just specify the
# reporter.
TAHOE_LAFS_TRIAL_ARGS: "--reporter=subunitv2-file"
TAHOE_LAFS_TOX_ENVIRONMENT: "py36"
TAHOE_LAFS_TOX_ENVIRONMENT: "py37"
ubuntu-20-04:
@ -511,7 +511,9 @@ jobs:
# https://circleci.com/blog/how-to-build-a-docker-image-on-circleci-2-0/
docker:
- <<: *DOCKERHUB_AUTH
image: "docker:17.05.0-ce-git"
# CircleCI build images; https://github.com/CircleCI-Public/cimg-base
# for details.
image: "cimg/base:2022.01"
environment:
DISTRO: "tahoelafsci/<DISTRO>:foo-py2"
@ -577,13 +579,13 @@ jobs:
PYTHON_VERSION: "2.7"
build-image-python36-ubuntu:
build-image-python37-ubuntu:
<<: *BUILD_IMAGE
environment:
DISTRO: "ubuntu"
TAG: "18.04"
PYTHON_VERSION: "3"
PYTHON_VERSION: "3.7"
build-image-ubuntu-20-04:

View File

@ -39,12 +39,11 @@ jobs:
- ubuntu-latest
python-version:
- 2.7
- 3.6
- 3.7
- 3.8
- 3.9
include:
# On macOS don't bother with 3.6-3.8, just to get faster builds.
# On macOS don't bother with 3.7-3.8, just to get faster builds.
- os: macos-10.15
python-version: 2.7
- os: macos-latest
@ -181,10 +180,10 @@ jobs:
- ubuntu-latest
python-version:
- 2.7
- 3.6
- 3.7
- 3.9
include:
# On macOS don't bother with 3.6, just to get faster builds.
# On macOS don't bother with 3.7, just to get faster builds.
- os: macos-10.15
python-version: 2.7
- os: macos-latest

View File

@ -35,7 +35,7 @@ test: .tox/create-venvs.log
# Run codechecks first since it takes the least time to report issues early.
tox --develop -e codechecks
# Run all the test environments in parallel to reduce run-time
tox --develop -p auto -e 'py27,py36,pypy27'
tox --develop -p auto -e 'py27,py37,pypy27'
.PHONY: test-venv-coverage
## Run all tests with coverage collection and reporting.
test-venv-coverage:
@ -51,7 +51,7 @@ test-venv-coverage:
.PHONY: test-py3-all
## Run all tests under Python 3
test-py3-all: .tox/create-venvs.log
tox --develop -e py36 allmydata
tox --develop -e py37 allmydata
# This is necessary only if you want to automatically produce a new
# _version.py file from the current git history (without doing a build).

View File

@ -5,6 +5,20 @@ User-Visible Changes in Tahoe-LAFS
==================================
.. towncrier start line
Release 1.17.1 (2022-01-07)
'''''''''''''''''''''''''''
Bug Fixes
---------
- Fixed regression on Python 3 causing the JSON version of the Welcome page to sometimes produce a 500 error (`#3852 <https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3852>`_)
- Fixed regression on Python 3 where JSON HTTP POSTs failed to be processed. (`#3854 <https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3854>`_)
Misc/Other
----------
- `#3848 <https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3848>`_, `#3849 <https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3849>`_, `#3850 <https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3850>`_, `#3856 <https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3856>`_
Release 1.17.0 (2021-12-06)

View File

@ -28,15 +28,15 @@ To install Tahoe-LAFS on Windows:
3. Open the installer by double-clicking it. Select the **Add Python to PATH** check-box, then click **Install Now**.
4. Start PowerShell and enter the following command to verify python installation::
python --version
5. Enter the following command to install Tahoe-LAFS::
pip install tahoe-lafs
6. Verify installation by checking for the version::
tahoe --version
If you want to hack on Tahoe's source code, you can install Tahoe in a ``virtualenv`` on your Windows Machine. To learn more, see :doc:`install-on-windows`.
@ -56,13 +56,13 @@ If you are working on MacOS or a Linux distribution which does not have Tahoe-LA
* **pip**: Most python installations already include `pip`. However, if your installation does not, see `pip installation <https://pip.pypa.io/en/stable/installing/>`_.
2. Install Tahoe-LAFS using pip::
pip install tahoe-lafs
3. Verify installation by checking for the version::
tahoe --version
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`.
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 <https://lists.tahoe-lafs.org/mailman/listinfo/tahoe-dev>`_ or chat on the `Libera.chat IRC <irc://irc.libera.chat/%23tahoe-lafs>`_ if you are not able to get Tahoe-LAFS up and running on your deployment.

View File

@ -70,7 +70,6 @@ Create Branch and Apply Updates
- commit it
- update "docs/known_issues.rst" if appropriate
- update "docs/Installation/install-tahoe.rst" references to the new release
- Push the branch to github
- Create a (draft) PR; this should trigger CI (note that github
doesn't let you create a PR without some changes on the branch so
@ -107,6 +106,11 @@ they will need to evaluate which contributors' signatures they trust.
- tox -e deprecations,upcoming-deprecations
- clone to a clean, local checkout (to avoid extra files being included in the release)
- cd /tmp
- git clone /home/meejah/src/tahoe-lafs
- build tarballs
- tox -e tarballs
@ -153,14 +157,20 @@ need to be uploaded to https://tahoe-lafs.org in `~source/downloads`
- secure-copy all release artifacts to the download area on the
tahoe-lafs.org host machine. `~source/downloads` on there maps to
https://tahoe-lafs.org/downloads/ on the Web.
- scp dist/*1.15.0* username@tahoe-lafs.org:/home/source/downloads
https://tahoe-lafs.org/downloads/ on the Web:
- scp dist/*1.15.0* username@tahoe-lafs.org:/home/source/downloads
- the following developers have access to do this:
- exarkun
- meejah
- warner
Push the signed tag to the main repository:
- git push origin tahoe-lafs-1.17.1
For the actual release, the tarball and signature files need to be
uploaded to PyPI as well.

View File

@ -0,0 +1 @@
Python 3.6 is no longer supported, as it has reached end-of-life and is no longer receiving security updates.

View File

@ -7,7 +7,7 @@
, html5lib, pyutil, distro, configparser, klein, werkzeug, cbor2
}:
python.pkgs.buildPythonPackage rec {
# Most of the time this is not exactly the release version (eg 1.17.0).
# Most of the time this is not exactly the release version (eg 1.17.1).
# Give it a `post` component to make it look newer than the release version
# and we'll bump this up at the time of each release.
#
@ -20,7 +20,7 @@ python.pkgs.buildPythonPackage rec {
# is not a reproducable artifact (in the sense of "reproducable builds") so
# it is excluded from the source tree by default. When it is included, the
# package tends to be frequently spuriously rebuilt.
version = "1.17.0.post1";
version = "1.17.1.post1";
name = "tahoe-lafs-${version}";
src = lib.cleanSourceWith {
src = ../.;

View File

@ -1,6 +1,6 @@
ANNOUNCING Tahoe, the Least-Authority File Store, v1.17.0
ANNOUNCING Tahoe, the Least-Authority File Store, v1.17.1
The Tahoe-LAFS team is pleased to announce version 1.17.0 of
The Tahoe-LAFS team is pleased to announce version 1.17.1 of
Tahoe-LAFS, an extremely reliable decentralized storage
system. Get it with "pip install tahoe-lafs", or download a
tarball here:
@ -15,19 +15,12 @@ unique security and fault-tolerance properties:
https://tahoe-lafs.readthedocs.org/en/latest/about.html
The previous stable release of Tahoe-LAFS was v1.16.0, released on
October 19, 2021.
The previous stable release of Tahoe-LAFS was v1.17.0, released on
December 6, 2021.
This release fixes several security issues raised as part of an audit
by Cure53. We developed fixes for these issues in a private
repository. Shortly after this release, public tickets will be updated
with further information (along with, of course, all the code).
This release fixes two Python3-releated regressions and 4 minor bugs.
There is also OpenMetrics support now and several bug fixes.
In all, 46 issues have been fixed since the last release.
Please see ``NEWS.rst`` for a more complete list of changes.
Please see ``NEWS.rst`` [1] for a complete list of changes.
WHAT IS IT GOOD FOR?
@ -66,12 +59,12 @@ to v1.0 (which was released March 25, 2008). Clients from this
release can read files and directories produced by clients of
all versions since v1.0.
Network connections are limited by the Introducer protocol in
use. If the Introducer is running v1.10 or v1.11, then servers
from this release (v1.12) can serve clients of all versions
back to v1.0 . If it is running v1.12, then they can only
serve clients back to v1.10. Clients from this release can use
servers back to v1.10, but not older servers.
Network connections are limited by the Introducer protocol in use. If
the Introducer is running v1.10 or v1.11, then servers from this
release can serve clients of all versions back to v1.0 . If it is
running v1.12 or higher, then they can only serve clients back to
v1.10. Clients from this release can use servers back to v1.10, but
not older servers.
Except for the new optional MDMF format, we have not made any
intentional compatibility changes. However we do not yet have
@ -79,7 +72,7 @@ the test infrastructure to continuously verify that all new
versions are interoperable with previous versions. We intend
to build such an infrastructure in the future.
This is the twenty-first release in the version 1 series. This
This is the twenty-second release in the version 1 series. This
series of Tahoe-LAFS will be actively supported and maintained
for the foreseeable future, and future versions of Tahoe-LAFS
will retain the ability to read and write files compatible
@ -139,7 +132,7 @@ Of Fame" [13].
ACKNOWLEDGEMENTS
This is the eighteenth release of Tahoe-LAFS to be created
This is the nineteenth release of Tahoe-LAFS to be created
solely as a labor of love by volunteers. Thank you very much
to the team of "hackers in the public interest" who make
Tahoe-LAFS possible.
@ -147,16 +140,16 @@ Tahoe-LAFS possible.
meejah
on behalf of the Tahoe-LAFS team
December 6, 2021
January 7, 2022
Planet Earth
[1] https://github.com/tahoe-lafs/tahoe-lafs/blob/tahoe-lafs-1.17.0/NEWS.rst
[1] https://github.com/tahoe-lafs/tahoe-lafs/blob/tahoe-lafs-1.17.1/NEWS.rst
[2] https://github.com/tahoe-lafs/tahoe-lafs/blob/master/docs/known_issues.rst
[3] https://tahoe-lafs.org/trac/tahoe-lafs/wiki/RelatedProjects
[4] https://github.com/tahoe-lafs/tahoe-lafs/blob/tahoe-lafs-1.17.0/COPYING.GPL
[5] https://github.com/tahoe-lafs/tahoe-lafs/blob/tahoe-lafs-1.17.0/COPYING.TGPPL.rst
[6] https://tahoe-lafs.readthedocs.org/en/tahoe-lafs-1.17.0/INSTALL.html
[4] https://github.com/tahoe-lafs/tahoe-lafs/blob/tahoe-lafs-1.17.1/COPYING.GPL
[5] https://github.com/tahoe-lafs/tahoe-lafs/blob/tahoe-lafs-1.17.1/COPYING.TGPPL.rst
[6] https://tahoe-lafs.readthedocs.org/en/tahoe-lafs-1.17.1/INSTALL.html
[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

View File

@ -380,9 +380,8 @@ setup(name="tahoe-lafs", # also set in __init__.py
package_dir = {'':'src'},
packages=find_packages('src') + ['allmydata.test.plugins'],
classifiers=trove_classifiers,
# We support Python 2.7, and we're working on support for 3.6 (the
# highest version that PyPy currently supports).
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*",
# We support Python 2.7, and Python 3.7 or later.
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*",
install_requires=install_requires,
extras_require={
# Duplicate the Twisted pywin32 dependency here. See
@ -413,7 +412,9 @@ setup(name="tahoe-lafs", # also set in __init__.py
"html5lib",
"junitxml",
"tenacity",
"paramiko",
# Pin old version until
# https://github.com/paramiko/paramiko/issues/1961 is fixed.
"paramiko < 2.9",
"pytest-timeout",
# Does our OpenMetrics endpoint adhere to the spec:
"prometheus-client == 0.11.0",

View File

@ -11,6 +11,7 @@ if PY2:
from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401
import time
import json
from urllib.parse import (
quote,
@ -24,14 +25,23 @@ from twisted.web.template import Tag
from twisted.web.test.requesthelper import DummyRequest
from twisted.application import service
from testtools.twistedsupport import succeeded
from twisted.internet.defer import inlineCallbacks
from twisted.internet.defer import (
inlineCallbacks,
succeed,
)
from ...storage_client import (
NativeStorageServer,
StorageFarmBroker,
)
from ...web.root import RootElement
from ...web.root import (
RootElement,
Root,
)
from ...util.connection_status import ConnectionStatus
from ...crypto.ed25519 import (
create_signing_keypair,
)
from allmydata.web.root import URIHandler
from allmydata.client import _Client
@ -47,6 +57,7 @@ from ..common import (
from ..common import (
SyncTestCase,
AsyncTestCase,
)
from testtools.matchers import (
@ -138,3 +149,94 @@ class RenderServiceRow(SyncTestCase):
self.assertThat(item.slotData.get("version"), Equals(""))
self.assertThat(item.slotData.get("nickname"), Equals(""))
class RenderRoot(AsyncTestCase):
@inlineCallbacks
def test_root_json(self):
"""
The 'welcome' / root page renders properly with ?t=json when some
servers show None for available_space while others show a
valid int
See also https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3852
"""
ann = {
"anonymous-storage-FURL": "pb://w2hqnbaa25yw4qgcvghl5psa3srpfgw3@tcp:127.0.0.1:51309/vucto2z4fxment3vfxbqecblbf6zyp6x",
"permutation-seed-base32": "w2hqnbaa25yw4qgcvghl5psa3srpfgw3",
}
srv0 = NativeStorageServer(b"server_id0", ann, None, {}, EMPTY_CLIENT_CONFIG)
srv0.get_connection_status = lambda: ConnectionStatus(False, "summary0", {}, 0, 0)
srv1 = NativeStorageServer(b"server_id1", ann, None, {}, EMPTY_CLIENT_CONFIG)
srv1.get_connection_status = lambda: ConnectionStatus(False, "summary1", {}, 0, 0)
# arrange for this server to have some valid available space
srv1.get_available_space = lambda: 12345
class FakeClient(_Client):
history = []
stats_provider = object()
nickname = ""
nodeid = b"asdf"
_node_public_key = create_signing_keypair()[1]
introducer_clients = []
helper = None
def __init__(self):
service.MultiService.__init__(self)
self.storage_broker = StorageFarmBroker(
permute_peers=True,
tub_maker=None,
node_config=EMPTY_CLIENT_CONFIG,
)
self.storage_broker.test_add_server(b"test-srv0", srv0)
self.storage_broker.test_add_server(b"test-srv1", srv1)
root = Root(FakeClient(), now_fn=time.time)
lines = []
req = DummyRequest(b"")
req.fields = {}
req.args = {
b"t": [b"json"],
}
# for some reason, DummyRequest is already finished when we
# try to add a notifyFinish handler, so override that
# behavior.
def nop():
return succeed(None)
req.notifyFinish = nop
req.write = lines.append
yield root.render(req)
raw_js = b"".join(lines).decode("utf8")
js = json.loads(raw_js)
servers = js["servers"]
self.assertEquals(len(servers), 2)
self.assertIn(
{
"connection_status": "summary0",
"nodeid": "server_id0",
"last_received_data": 0,
"version": None,
"available_space": None,
"nickname": ""
},
servers
)
self.assertIn(
{
"connection_status": "summary1",
"nodeid": "server_id1",
"last_received_data": 0,
"version": None,
"available_space": 12345,
"nickname": ""
},
servers
)

View File

@ -820,29 +820,37 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
"""
d = self.GET("/?t=json")
def _check(res):
"""
Check that the results are correct.
We can't depend on the order of servers in the output
"""
decoded = json.loads(res)
expected = {
u'introducers': {
u'statuses': [],
self.assertEqual(decoded['introducers'], {u'statuses': []})
actual_servers = decoded[u"servers"]
self.assertEquals(len(actual_servers), 2)
self.assertIn(
{
u"nodeid": u'other_nodeid',
u'available_space': 123456,
u'connection_status': u'summary',
u'last_received_data': 30,
u'nickname': u'other_nickname \u263b',
u'version': u'1.0',
},
u'servers': sorted([
{u"nodeid": u'other_nodeid',
u'available_space': 123456,
u'connection_status': u'summary',
u'last_received_data': 30,
u'nickname': u'other_nickname \u263b',
u'version': u'1.0',
},
{u"nodeid": u'disconnected_nodeid',
u'available_space': 123456,
u'connection_status': u'summary',
u'last_received_data': 35,
u'nickname': u'disconnected_nickname \u263b',
u'version': u'1.0',
},
], key=lambda o: sorted(o.items())),
}
self.assertEqual(expected, decoded)
actual_servers
)
self.assertIn(
{
u"nodeid": u'disconnected_nodeid',
u'available_space': 123456,
u'connection_status': u'summary',
u'last_received_data': 35,
u'nickname': u'disconnected_nickname \u263b',
u'version': u'1.0',
},
actual_servers
)
d.addCallback(_check)
return d

View File

@ -90,10 +90,11 @@ class TahoeLAFSRequestTests(SyncTestCase):
"""
self._fields_test(b"GET", {}, b"", Equals(None))
def test_form_fields(self):
def test_form_fields_if_filename_set(self):
"""
When a ``POST`` request is received, form fields are parsed into
``TahoeLAFSRequest.fields``.
``TahoeLAFSRequest.fields`` and the body is bytes (presuming ``filename``
is set).
"""
form_data, boundary = multipart_formdata([
[param(u"name", u"foo"),
@ -121,6 +122,49 @@ class TahoeLAFSRequestTests(SyncTestCase):
),
)
def test_form_fields_if_name_is_file(self):
"""
When a ``POST`` request is received, form fields are parsed into
``TahoeLAFSRequest.fields`` and the body is bytes when ``name``
is set to ``"file"``.
"""
form_data, boundary = multipart_formdata([
[param(u"name", u"foo"),
body(u"bar"),
],
[param(u"name", u"file"),
body(u"some file contents"),
],
])
self._fields_test(
b"POST",
{b"content-type": b"multipart/form-data; boundary=" + bytes(boundary, 'ascii')},
form_data.encode("ascii"),
AfterPreprocessing(
lambda fs: {
k: fs.getvalue(k)
for k
in fs.keys()
},
Equals({
"foo": "bar",
"file": b"some file contents",
}),
),
)
def test_form_fields_require_correct_mime_type(self):
"""
The body of a ``POST`` is not parsed into fields if its mime type is
not ``multipart/form-data``.
Reproducer for https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3854
"""
data = u'{"lalala": "lolo"}'
data = data.encode("utf-8")
self._fields_test(b"POST", {"content-type": "application/json"},
data, Equals(None))
class TahoeLAFSSiteTests(SyncTestCase):
"""

View File

@ -297,14 +297,12 @@ class Root(MultiFormatResource):
}
return json.dumps(result, indent=1) + "\n"
def _describe_known_servers(self, broker):
return sorted(list(
return list(
self._describe_server(server)
for server
in broker.get_known_servers()
), key=lambda o: sorted(o.items()))
)
def _describe_server(self, server):
status = server.get_connection_status()

View File

@ -114,7 +114,8 @@ class TahoeLAFSRequest(Request, object):
self.path, argstring = x
self.args = parse_qs(argstring, 1)
if self.method == b'POST':
content_type = (self.requestHeaders.getRawHeaders("content-type") or [""])[0]
if self.method == b'POST' and content_type.split(";")[0] in ("multipart/form-data", "application/x-www-form-urlencoded"):
# We use FieldStorage here because it performs better than
# cgi.parse_multipart(self.content, pdict) which is what
# twisted.web.http.Request uses.

View File

@ -8,7 +8,6 @@
[gh-actions]
python =
2.7: py27-coverage,codechecks
3.6: py36-coverage
3.7: py37-coverage,typechecks,codechecks3
3.8: py38-coverage
3.9: py39-coverage
@ -18,7 +17,7 @@ python =
twisted = 1
[tox]
envlist = typechecks,codechecks,codechecks3,py{27,36,37,38,39}-{coverage},pypy27,pypy3,integration,integration3
envlist = typechecks,codechecks,codechecks3,py{27,37,38,39}-{coverage},pypy27,pypy3,integration,integration3
minversion = 2.4
[testenv]
@ -51,7 +50,7 @@ deps =
# suffering we're trying to avoid with the above pins.
certifi
# VCS hooks support
py36,!coverage: pre-commit
py37,!coverage: pre-commit
# We add usedevelop=False because testing against a true installation gives
# more useful results.