nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: PyFilesystem/pyfilesystem2
Pull request #117 (2017-12-12 11:49:41)

Fixed isbase method
Child and parent pathes were swapped by mistake. Documentation example for isbase didn't work because of that

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14616013/badge)](https://coveralls.io/builds/14616013)

Coverage decreased (-0.8%) to 99.115% when pulling **78ecd938446c8c4262c64b87441c362d8e45c8c2 on fresheed:isbase_fix** into **7e5d556b5c760a0d61ec679cf80081189053b4d7 on PyFilesystem:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14616013/badge)](https://coveralls.io/builds/14616013)

Coverage remained the same at 99.951% when pulling **78ecd938446c8c4262c64b87441c362d8e45c8c2 on fresheed:isbase_fix** into **7e5d556b5c760a0d61ec679cf80081189053b4d7 on PyFilesystem:master**.

willmcgugan: Thanks.

Patch:
diff --git a/fs/path.py b/fs/path.py
index 875e536..cf27203 100644
--- a/fs/path.py
+++ b/fs/path.py
@@ -437,7 +437,7 @@ def isbase(path1, path2):
     """
     _path1 = forcedir(abspath(path1))
     _path2 = forcedir(abspath(path2))
-    return _path1.startswith(_path2)
+    return _path2.startswith(_path1) # longer one is child
 
 
 def isparent(path1, path2):


Test patch:
diff --git a/tests/test_path.py b/tests/test_path.py
index af39541..6b67d2a 100644
--- a/tests/test_path.py
+++ b/tests/test_path.py
@@ -146,8 +146,8 @@ class TestPathFunctions(unittest.TestCase):
         self.assertEquals(recursepath("", reverse=True), ["/"])
 
     def test_isbase(self):
-        self.assertTrue(isbase('foo/bar', 'foo'))
-        self.assertFalse(isbase('foo/bar', 'baz'))
+        self.assertTrue(isbase('foo', 'foo/bar'))
+        self.assertFalse(isbase('baz', 'foo/bar'))        
 
     def test_isparent(self):
         self.assertTrue(isparent("foo/bar", "foo/bar/spam.txt"))
Repository: PyFilesystem/pyfilesystem2
Pull request #150 (2018-03-13 10:53:29)

fix multifs listdir bug


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9c614cd..237e479 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
+## [2.0.20] - 2018-03-13
+
+### Fixed
+
+- MultiFS.listdir now correctly filters out duplicates
+
 ## [2.0.19] - 2018-03-11
 
 ### Fixed
diff --git a/fs/_version.py b/fs/_version.py
index c016fb0..aff8a83 100644
--- a/fs/_version.py
+++ b/fs/_version.py
@@ -1,3 +1,3 @@
 """Version, used in module and setup.py.
 """
-__version__ = "2.0.19"
+__version__ = "2.0.20"
diff --git a/fs/multifs.py b/fs/multifs.py
index 3860520..8caf922 100644
--- a/fs/multifs.py
+++ b/fs/multifs.py
@@ -5,7 +5,7 @@ from __future__ import absolute_import
 from __future__ import unicode_literals
 from __future__ import print_function
 
-from collections import namedtuple
+from collections import namedtuple, OrderedDict
 from operator import itemgetter
 
 from six import text_type
@@ -203,6 +203,7 @@ class MultiFS(FS):
                 exists = True
         if not exists:
             raise errors.ResourceNotFound(path)
+        directory = list(OrderedDict.fromkeys(directory))
         return directory
 
     def makedir(self, path, permissions=None, recreate=False):


Test patch:
diff --git a/tests/test_multifs.py b/tests/test_multifs.py
index 974cdd2..c9dcc74 100644
--- a/tests/test_multifs.py
+++ b/tests/test_multifs.py
@@ -134,3 +134,13 @@ class TestMultiFS(FSTestCases, unittest.TestCase):
     def test_validate_path(self):
         self.fs.write_fs = None
         self.fs.validatepath('foo')
+
+    def test_listdir_duplicates(self):
+        m1 = MemoryFS()
+        m2 = MemoryFS()
+        m1.touch('foo')
+        m2.touch('foo')
+        multi_fs = MultiFS()
+        multi_fs.add_fs('m1', m1)
+        multi_fs.add_fs('m2', m2)
+        self.assertEqual(multi_fs.listdir(u'/'), ['foo'])
Repository: JonathonReinhart/scuba
Pull request #39 (2016-01-30 20:10:50)

Maintain version in only one location


Patch:
diff --git a/scuba/__init__.py b/scuba/__init__.py
index f856cca..58f3ace 100644
--- a/scuba/__init__.py
+++ b/scuba/__init__.py
@@ -1,3 +1,1 @@
-# Importing main ensures it is included in coverage,
-# even though we have no tests covering it yet.
-from . import __main__ as main
+from .version import __version__
diff --git a/scuba/__main__.py b/scuba/__main__.py
index bc53eb2..57f8671 100755
--- a/scuba/__main__.py
+++ b/scuba/__main__.py
@@ -21,8 +21,7 @@ from .config import find_config, load_config, ConfigError
 from .etcfiles import *
 from .filecleanup import FileCleanup
 from .utils import *
-
-__version__ = '1.4.0'
+from .version import __version__
 
 def appmsg(fmt, *args):
     print('scuba: ' + fmt.format(*args), file=sys.stderr)
diff --git a/scuba/version.py b/scuba/version.py
new file mode 100644
index 0000000..96e3ce8
--- /dev/null
+++ b/scuba/version.py
@@ -0,0 +1,1 @@
+__version__ = '1.4.0'
diff --git a/setup.py b/setup.py
index 74214a8..efbf336 100644
--- a/setup.py
+++ b/setup.py
@@ -1,10 +1,10 @@
 #!/usr/bin/env python
-
+import scuba.version
 from distutils.core import setup
 
 setup(
     name = 'SCUBA',
-    version = '1.4.0',
+    version = scuba.version.__version__,
     description = 'Simplify use of Docker containers for building software',
     author = 'Jonathon Reinhart',
     author_email = 'jonathon.reinhart@gmail.com',


Test patch:
diff --git a/tests/test_main.py b/tests/test_main.py
index 2574c40..b75f48b 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -16,6 +16,7 @@ from shutil import rmtree
 
 import scuba.__main__ as main
 import scuba.constants
+import scuba
 
 DOCKER_IMAGE = 'debian:8.2'
 
@@ -116,7 +117,7 @@ class TestMain(TestCase, BetterAssertRaisesMixin):
         assert_startswith(check, 'scuba')
 
         ver = check.split()[1]
-        assert_equal(ver, main.__version__)
+        assert_equal(ver, scuba.__version__)
 
 
     def test_no_docker(self):
Repository: Neoteroi/BlackSheep
Pull request #409 (2023-08-21 20:50:32)

Make .jinja the default extension for Jinja templates


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2af0e1f..e57c956 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,10 +5,15 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [2.0a10] - 2023-08-21 :broccoli:
+
+- Add support for `.jinja` extension by @thearchitector.
+- Makes the `.jinja` extension default for Jinja templates.
+
 ## [2.0a9] - 2023-07-14
 
-- Fixes bug #394, causing the `Content` max body size to be 2147483647
-  (C int max value). Reported and fixed by @thomafred
+- Fixes bug #394, causing the `Content` max body size to be 2147483647.
+  (C int max value). Reported and fixed by @thomafred.
 
 ## [2.0a8] - 2023-07-02
 
diff --git a/blacksheep/__init__.py b/blacksheep/__init__.py
index 2242c0c..58b6120 100644
--- a/blacksheep/__init__.py
+++ b/blacksheep/__init__.py
@@ -3,7 +3,7 @@ Root module of the framework. This module re-exports the most commonly
 used types to reduce the verbosity of the imports statements.
 """
 __author__ = "Roberto Prevato <roberto.prevato@gmail.com>"
-__version__ = "2.0a9"
+__version__ = "2.0a10"
 
 from .contents import Content as Content
 from .contents import FormContent as FormContent
diff --git a/blacksheep/server/rendering/jinja2.py b/blacksheep/server/rendering/jinja2.py
index e93084b..5e6851e 100644
--- a/blacksheep/server/rendering/jinja2.py
+++ b/blacksheep/server/rendering/jinja2.py
@@ -11,11 +11,13 @@ from blacksheep.server.csrf import AntiForgeryHandler, MissingRequestContextErro
 
 from .abc import Renderer
 
+_DEFAULT_TEMPLATES_EXTENSION = os.environ.get("APP_JINJA_EXTENSION", ".jinja")
+
 
 @lru_cache(1200)
 def get_template_name(name: str) -> str:
-    if not name.endswith(".html") and not name.endswith(".jinja"):
-        return name + ".html"
+    if not name.endswith(_DEFAULT_TEMPLATES_EXTENSION):
+        return name + _DEFAULT_TEMPLATES_EXTENSION
     return name
 
 


Test patch:
diff --git a/tests/test_templating.py b/tests/test_templating.py
index 7fc3d31..4426df2 100644
--- a/tests/test_templating.py
+++ b/tests/test_templating.py
@@ -322,11 +322,9 @@ async def test_controller_conventional_view_name_extraneous_function(home_model)
 @pytest.mark.parametrize(
     "value,expected_name",
     [
-        ("index", "index.html"),
-        ("index.html", "index.html"),
-        ("index.html.jinja", "index.html.jinja"),
+        ("index", "index.jinja"),
         ("index.jinja", "index.jinja"),
-        ("default", "default.html"),
+        ("default", "default.jinja"),
     ],
 )
 def test_template_name(value, expected_name):
Repository: libp2p/go-libp2p
Pull request #2849 (2024-06-25 16:52:01)

metricshelper: improve checks for ip and transport
minor quality of life improvements like nil checks and classifying dns4 as ipv4 addresses for purposes of tracking ip version. 


Patch:
diff --git a/p2p/metricshelper/conn.go b/p2p/metricshelper/conn.go
index b07016ce..5fd8a114 100644
--- a/p2p/metricshelper/conn.go
+++ b/p2p/metricshelper/conn.go
@@ -5,6 +5,9 @@ import ma "github.com/multiformats/go-multiaddr"
 var transports = [...]int{ma.P_CIRCUIT, ma.P_WEBRTC, ma.P_WEBRTC_DIRECT, ma.P_WEBTRANSPORT, ma.P_QUIC, ma.P_QUIC_V1, ma.P_WSS, ma.P_WS, ma.P_TCP}
 
 func GetTransport(a ma.Multiaddr) string {
+	if a == nil {
+		return "other"
+	}
 	for _, t := range transports {
 		if _, err := a.ValueForProtocol(t); err == nil {
 			return ma.ProtocolWithCode(t).Name
@@ -15,15 +18,17 @@ func GetTransport(a ma.Multiaddr) string {
 
 func GetIPVersion(addr ma.Multiaddr) string {
 	version := "unknown"
+	if addr == nil {
+		return version
+	}
 	ma.ForEach(addr, func(c ma.Component) bool {
-		if c.Protocol().Code == ma.P_IP4 {
+		switch c.Protocol().Code {
+		case ma.P_IP4, ma.P_DNS4:
 			version = "ip4"
-			return false
-		} else if c.Protocol().Code == ma.P_IP6 {
+		case ma.P_IP6, ma.P_DNS6:
 			version = "ip6"
-			return false
 		}
-		return true
+		return false
 	})
 	return version
 }


Test patch:
diff --git a/p2p/metricshelper/conn_test.go b/p2p/metricshelper/conn_test.go
new file mode 100644
index 00000000..0650bfec
--- /dev/null
+++ b/p2p/metricshelper/conn_test.go
@@ -0,0 +1,68 @@
+package metricshelper
+
+import (
+	"fmt"
+	"testing"
+
+	ma "github.com/multiformats/go-multiaddr"
+)
+
+func TestGetTransport(t *testing.T) {
+	cases := []struct {
+		addr   ma.Multiaddr
+		result string
+	}{
+		{
+			addr:   ma.StringCast("/ip4/1.1.1.1/tcp/1"),
+			result: "tcp",
+		},
+		{
+			addr:   ma.StringCast("/ip4/1.1.1.1/udp/10"),
+			result: "other",
+		},
+		{
+			addr:   nil,
+			result: "other",
+		},
+	}
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+			got := GetTransport(tc.addr)
+			if got != tc.result {
+				t.Fatalf("invalid transport for %s\ngot:%v\nwant:%v", tc.addr, got, tc.result)
+			}
+		})
+	}
+}
+
+func TestIPVersion(t *testing.T) {
+	cases := []struct {
+		addr   ma.Multiaddr
+		result string
+	}{
+		{
+			addr:   ma.StringCast("/ip4/1.1.1.1/tcp/1"),
+			result: "ip4",
+		},
+		{
+			addr:   ma.StringCast("/ip4/1.1.1.1/udp/10"),
+			result: "ip4",
+		},
+		{
+			addr:   nil,
+			result: "unknown",
+		},
+		{
+			addr:   ma.StringCast("/dns/hello.world/tcp/10"),
+			result: "unknown",
+		},
+	}
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+			got := GetIPVersion(tc.addr)
+			if got != tc.result {
+				t.Fatalf("invalid ip version for %s\ngot:%v\nwant:%v", tc.addr, got, tc.result)
+			}
+		})
+	}
+}
Repository: libp2p/go-libp2p
Pull request #3039 (2024-11-13 00:22:40)

fix(tcpreuse): remove windows specific code
Unclear why, but this causes a lot of CPU usage according to @aschmahmann

I wonder if we are spinning in the for loop. Is it possible the Windows api returns no bytes read and no error?

MarcoPolo: need to debug the failing test still
MarcoPolo: just an incomplete read in the test. Not a real issue.

Patch:
diff --git a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_other.go b/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_other.go
index 73861123..5197052f 100644
--- a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_other.go
+++ b/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_other.go
@@ -1,4 +1,4 @@
-//go:build !unix && !windows
+//go:build !unix
 
 package sampledconn
 
diff --git a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_windows.go b/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_windows.go
deleted file mode 100644
index 46b06179..00000000
--- a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_windows.go
+++ /dev/null
@@ -1,49 +0,0 @@
-//go:build windows
-
-package sampledconn
-
-import (
-	"errors"
-	"golang.org/x/sys/windows"
-	"syscall"
-)
-
-func OSPeekConn(conn syscall.Conn) (PeekedBytes, error) {
-	s := PeekedBytes{}
-
-	rawConn, err := conn.SyscallConn()
-	if err != nil {
-		return s, err
-	}
-
-	readBytes := 0
-	var readErr error
-	err = rawConn.Read(func(fd uintptr) bool {
-		for readBytes < peekSize {
-			var n uint32
-			flags := uint32(windows.MSG_PEEK)
-			wsabuf := windows.WSABuf{
-				Len: uint32(len(s) - readBytes),
-				Buf: &s[readBytes],
-			}
-
-			readErr = windows.WSARecv(windows.Handle(fd), &wsabuf, 1, &n, &flags, nil, nil)
-			if errors.Is(readErr, windows.WSAEWOULDBLOCK) {
-				return false
-			}
-			if readErr != nil {
-				return true
-			}
-			readBytes += int(n)
-		}
-		return true
-	})
-	if readErr != nil {
-		return s, readErr
-	}
-	if err != nil {
-		return s, err
-	}
-
-	return s, nil
-}


Test patch:
diff --git a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_test.go b/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_test.go
index a7c5a65f..d5b31009 100644
--- a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_test.go
+++ b/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_test.go
@@ -58,7 +58,7 @@ func TestSampledConn(t *testing.T) {
 				assert.Equal(t, "hel", string(peeked[:]))
 
 				buf := make([]byte, 5)
-				_, err = clientConn.Read(buf)
+				_, err = io.ReadFull(clientConn, buf)
 				assert.NoError(t, err)
 				assert.Equal(t, "hello", string(buf))
 			} else {
Repository: libp2p/go-libp2p
Pull request #3050 (2024-11-19 17:42:19)

fix(libp2phttp): Return ErrServerClosed on Close
This should match the semantics of the Go stdlib http server .Close which always returns an error


Patch:
diff --git a/p2p/http/libp2phttp.go b/p2p/http/libp2phttp.go
index d2a544d2..4dad47dd 100644
--- a/p2p/http/libp2phttp.go
+++ b/p2p/http/libp2phttp.go
@@ -359,6 +359,7 @@ func (h *Host) Serve() error {
 	expectedErrCount := len(h.httpTransport.listeners)
 	select {
 	case <-h.httpTransport.closeListeners:
+		err = http.ErrServerClosed
 	case err = <-errCh:
 		expectedErrCount--
 	}


Test patch:
diff --git a/p2p/http/libp2phttp_test.go b/p2p/http/libp2phttp_test.go
index fa8687e3..ae3285b9 100644
--- a/p2p/http/libp2phttp_test.go
+++ b/p2p/http/libp2phttp_test.go
@@ -30,6 +30,7 @@ import (
 	httpping "github.com/libp2p/go-libp2p/p2p/http/ping"
 	libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic"
 	ma "github.com/multiformats/go-multiaddr"
+	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
@@ -996,3 +997,20 @@ func TestImpliedHostIsSet(t *testing.T) {
 	}
 
 }
+
+func TestErrServerClosed(t *testing.T) {
+	server := libp2phttp.Host{
+		InsecureAllowHTTP: true,
+		ListenAddrs:       []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")},
+	}
+
+	done := make(chan struct{})
+	go func() {
+		err := server.Serve()
+		assert.Equal(t, http.ErrServerClosed, err)
+		close(done)
+	}()
+
+	server.Close()
+	<-done
+}
Repository: libp2p/go-libp2p
Pull request #3090 (2024-12-06 11:03:07)

peerstore: pass options to addrbook constructor
The constructor starts a goroutine, so we should pass these in the constructor.


Patch:
diff --git a/p2p/host/peerstore/pstoremem/peerstore.go b/p2p/host/peerstore/pstoremem/peerstore.go
index d5a41cc5..15383f06 100644
--- a/p2p/host/peerstore/pstoremem/peerstore.go
+++ b/p2p/host/peerstore/pstoremem/peerstore.go
@@ -26,28 +26,26 @@ type Option interface{}
 // It's the caller's responsibility to call RemovePeer to ensure
 // that memory consumption of the peerstore doesn't grow unboundedly.
 func NewPeerstore(opts ...Option) (ps *pstoremem, err error) {
-	ab := NewAddrBook()
-	defer func() {
-		if err != nil {
-			ab.Close()
-		}
-	}()
-
 	var protoBookOpts []ProtoBookOption
+	var addrBookOpts []AddrBookOption
 	for _, opt := range opts {
 		switch o := opt.(type) {
 		case ProtoBookOption:
 			protoBookOpts = append(protoBookOpts, o)
 		case AddrBookOption:
-			o(ab)
+			addrBookOpts = append(addrBookOpts, o)
 		default:
 			return nil, fmt.Errorf("unexpected peer store option: %v", o)
 		}
 	}
+	ab := NewAddrBook(addrBookOpts...)
+
 	pb, err := NewProtoBook(protoBookOpts...)
 	if err != nil {
+		ab.Close()
 		return nil, err
 	}
+
 	return &pstoremem{
 		Metrics:            pstore.NewMetrics(),
 		memoryKeyBook:      NewKeyBook(),
diff --git a/p2p/net/swarm/dial_worker.go b/p2p/net/swarm/dial_worker.go
index 9d097f3c..5bb9559e 100644
--- a/p2p/net/swarm/dial_worker.go
+++ b/p2p/net/swarm/dial_worker.go
@@ -2,6 +2,7 @@ package swarm
 
 import (
 	"context"
+	"fmt"
 	"math"
 	"sync"
 	"time"
@@ -295,6 +296,9 @@ loop:
 				}
 				ad.dialed = true
 				ad.dialRankingDelay = now.Sub(ad.createdAt)
+				if _, err := ad.addr.ValueForProtocol(ma.P_WEBRTC_DIRECT); err == nil {
+					fmt.Println("dial ranking delay", ad.addr, ad.dialRankingDelay)
+				}
 				err := w.s.dialNextAddr(ad.ctx, w.peer, ad.addr, w.resch)
 				if err != nil {
 					// Errored without attempting a dial. This happens in case of


Test patch:
diff --git a/p2p/host/peerstore/pstoremem/peerstore_test.go b/p2p/host/peerstore/pstoremem/peerstore_test.go
new file mode 100644
index 00000000..5a07e266
--- /dev/null
+++ b/p2p/host/peerstore/pstoremem/peerstore_test.go
@@ -0,0 +1,23 @@
+package pstoremem
+
+import (
+	"testing"
+
+	"github.com/libp2p/go-libp2p/core/peerstore"
+	ma "github.com/multiformats/go-multiaddr"
+	"github.com/stretchr/testify/require"
+)
+
+func TestPeerStoreAddrBookOpts(t *testing.T) {
+	ps, err := NewPeerstore(WithMaxAddresses(1))
+	require.NoError(t, err)
+	defer ps.Close()
+
+	ps.AddAddr("p1", ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1"), peerstore.TempAddrTTL)
+	res := ps.Addrs("p1")
+	require.NotEmpty(t, res)
+
+	ps.AddAddr("p2", ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1"), peerstore.TempAddrTTL)
+	res = ps.Addrs("p2")
+	require.Empty(t, res)
+}
Repository: libp2p/go-libp2p
Pull request #3094 (2024-12-08 10:57:24)

nat: ignore mapping if external port is 0
closes: https://github.com/libp2p/go-libp2p/issues/3057
rest of the work is in: https://github.com/libp2p/go-libp2p/pull/3075


Patch:
diff --git a/p2p/net/nat/nat.go b/p2p/net/nat/nat.go
index 28ffd4a5..23af5807 100644
--- a/p2p/net/nat/nat.go
+++ b/p2p/net/nat/nat.go
@@ -107,7 +107,8 @@ func (nat *NAT) GetMapping(protocol string, port int) (addr netip.AddrPort, foun
 		return netip.AddrPort{}, false
 	}
 	extPort, found := nat.mappings[entry{protocol: protocol, port: port}]
-	if !found {
+	// The mapping may have an invalid port.
+	if !found || extPort == 0 {
 		return netip.AddrPort{}, false
 	}
 	return netip.AddrPortFrom(nat.extAddr, uint16(extPort)), true
@@ -135,6 +136,9 @@ func (nat *NAT) AddMapping(ctx context.Context, protocol string, port int) error
 	// do it once synchronously, so first mapping is done right away, and before exiting,
 	// allowing users -- in the optimistic case -- to use results right after.
 	extPort := nat.establishMapping(ctx, protocol, port)
+	// Don't validate the mapping here, we refresh the mappings based on this map.
+	// We can try getting a port again in case it succeeds. In the worst case,
+	// this is one extra LAN request every few minutes.
 	nat.mappings[entry{protocol: protocol, port: port}] = extPort
 	return nil
 }


Test patch:
diff --git a/p2p/net/nat/nat_test.go b/p2p/net/nat/nat_test.go
index 772c876c..e370fc89 100644
--- a/p2p/net/nat/nat_test.go
+++ b/p2p/net/nat/nat_test.go
@@ -68,3 +68,18 @@ func TestRemoveMapping(t *testing.T) {
 	_, found = nat.GetMapping("tcp", 10000)
 	require.False(t, found, "didn't expect port mapping for deleted mapping")
 }
+
+func TestAddMappingInvalidPort(t *testing.T) {
+	mockNAT, reset := setupMockNAT(t)
+	defer reset()
+
+	mockNAT.EXPECT().GetExternalAddress().Return(net.IPv4(1, 2, 3, 4), nil)
+	nat, err := DiscoverNAT(context.Background())
+	require.NoError(t, err)
+
+	mockNAT.EXPECT().AddPortMapping(gomock.Any(), "tcp", 10000, gomock.Any(), MappingDuration).Return(0, nil)
+	require.NoError(t, nat.AddMapping(context.Background(), "tcp", 10000))
+
+	_, found := nat.GetMapping("tcp", 10000)
+	require.False(t, found, "didn't expect a port mapping for invalid nat-ed port")
+}
Repository: libp2p/go-libp2p
Pull request #3249 (2025-03-24 18:04:25)

autonatv2: explicitly handle dns addrs
We do allow dns addrs for autonatv2. This function handles them correcly, but the comment is wrong, and the handling is accidental.  Make it explicity.


Patch:
diff --git a/p2p/protocol/autonatv2/server.go b/p2p/protocol/autonatv2/server.go
index dafac4df..3c6d0d53 100644
--- a/p2p/protocol/autonatv2/server.go
+++ b/p2p/protocol/autonatv2/server.go
@@ -522,6 +522,9 @@ func amplificationAttackPrevention(observedAddr, dialAddr ma.Multiaddr) bool {
 	if err != nil {
 		return true
 	}
-	dialIP, _ := manet.ToIP(dialAddr) // must be an IP multiaddr
+	dialIP, err := manet.ToIP(dialAddr) // can be dns addr
+	if err != nil {
+		return true
+	}
 	return !observedIP.Equal(dialIP)
 }


Test patch:
diff --git a/p2p/protocol/autonatv2/server_test.go b/p2p/protocol/autonatv2/server_test.go
index f92396fb..65b1b131 100644
--- a/p2p/protocol/autonatv2/server_test.go
+++ b/p2p/protocol/autonatv2/server_test.go
@@ -588,6 +588,13 @@ func TestDefaultAmplificationAttackPrevention(t *testing.T) {
 
 	t2 := ma.StringCast("/ip4/1.1.1.1/tcp/1235") // different IP
 	require.True(t, amplificationAttackPrevention(q2, t2))
+
+	// always ask dial data for dns addrs
+	d1 := ma.StringCast("/dns/localhost/udp/1/quic-v1")
+	d2 := ma.StringCast("/dnsaddr/libp2p.io/tcp/1")
+	require.True(t, amplificationAttackPrevention(d1, t1))
+	require.True(t, amplificationAttackPrevention(d2, t1))
+
 }
 
 func FuzzServerDialRequest(f *testing.F) {