Refine what a relative uri means in a git path (#3212)
diff --git a/lib/src/source/git.dart b/lib/src/source/git.dart index 1a792e3..0d26283 100644 --- a/lib/src/source/git.dart +++ b/lib/src/source/git.dart
@@ -145,9 +145,15 @@ return _ValidatedUrl(url, relative); } - /// Returns [path] normalized. + /// Normalizes [path]. /// - /// Throws a [FormatException] if [path] isn't a relative url or null. + /// Throws a [FormatException] if [path] isn't a [String] parsing as a + /// relative URL or `null`. + /// + /// A relative url here has: + /// - non-absolute path + /// - no scheme + /// - no authority String _validatedPath(dynamic path) { path ??= '.'; if (path is! String) { @@ -157,9 +163,13 @@ // Use Dart's URL parser to validate the URL. final parsed = Uri.parse(path); - if (parsed.isAbsolute) { + if (parsed.hasAbsolutePath || + parsed.hasScheme || + parsed.hasAuthority || + parsed.hasFragment || + parsed.hasQuery) { throw FormatException( - "The 'path' field of the description must be relative."); + "The 'path' field of the description must be a relative path URL."); } if (!p.url.isWithin('.', path) && !p.url.equals('.', path)) { throw FormatException(
diff --git a/test/get/git/path_test.dart b/test/get/git/path_test.dart index eab018f..d26d9cb 100644 --- a/test/get/git/path_test.dart +++ b/test/get/git/path_test.dart
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'package:path/path.dart' as p; +import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:pub/src/io.dart'; import 'package:pub/src/lock_file.dart'; import 'package:pub/src/source/git.dart'; @@ -86,6 +87,84 @@ reason: 'use uris to specify the path relative to the repo'); }); + group('requires path to be absolute', () { + test('absolute path', () async { + await d.appDir({ + 'sub': { + 'git': {'url': '../foo.git', 'path': '/subdir'} + } + }).create(); + + await pubGet( + error: contains( + 'Invalid description in the "myapp" pubspec on the "sub" dependency: The \'path\' field of the description must be a relative path URL.', + ), + exitCode: exit_codes.DATA, + ); + }); + test('scheme', () async { + await d.appDir({ + 'sub': { + 'git': {'url': '../foo.git', 'path': 'https://subdir'} + } + }).create(); + + await pubGet( + error: contains( + 'Invalid description in the "myapp" pubspec on the "sub" dependency: The \'path\' field of the description must be a relative path URL.', + ), + exitCode: exit_codes.DATA, + ); + }); + test('fragment', () async { + await d.appDir({ + 'sub': { + 'git': {'url': '../foo.git', 'path': 'subdir/dir#fragment'} + } + }).create(); + + await pubGet( + error: contains( + 'Invalid description in the "myapp" pubspec on the "sub" dependency: The \'path\' field of the description must be a relative path URL.', + ), + exitCode: exit_codes.DATA, + ); + }); + + test('query', () async { + await d.appDir({ + 'sub': { + 'git': {'url': '../foo.git', 'path': 'subdir/dir?query'} + } + }).create(); + + await pubGet( + error: contains( + 'Invalid description in the "myapp" pubspec on the "sub" dependency: The \'path\' field of the description must be a relative path URL.', + ), + exitCode: exit_codes.DATA, + ); + }); + + test('authority', () async { + await d.appDir({ + 'sub': { + 'git': { + 'url': '../foo.git', + 'path': 'bob:pwd@somewhere.example.com/subdir' + } + } + }).create(); + + await pubGet( + error: contains( + 'Invalid description in the "myapp" pubspec on the "sub" dependency: The \'path\' field of the description must be a relative path URL.', + ), + exitCode: exit_codes.DATA, + ); + }); + }); + test('depends on a package in a deep subdirectory, non-relative uri', () async { ensureGit();