mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #11688 from ethereum/fix-and-document-allow-paths
Fix and document `--allow-paths`
This commit is contained in:
commit
39eb182ccc
@ -21,6 +21,7 @@ Bugfixes:
|
|||||||
* Code Generator: Fix ICE on assigning to calldata structs and statically-sized calldata arrays in inline assembly.
|
* Code Generator: Fix ICE on assigning to calldata structs and statically-sized calldata arrays in inline assembly.
|
||||||
* Code Generator: Use stable source order for ABI functions.
|
* Code Generator: Use stable source order for ABI functions.
|
||||||
* Commandline Interface: Disallow the ``--experimental-via-ir`` option in Standard JSON, Assembler and Linker modes.
|
* Commandline Interface: Disallow the ``--experimental-via-ir`` option in Standard JSON, Assembler and Linker modes.
|
||||||
|
* Commandline Interface: Fix resolution of paths whitelisted with ``--allowed-paths`` or implicitly due to base path, remappings and files being compiled. Correctly handle paths that do not match imports exactly due to being relative, non-normalized or empty.
|
||||||
* Commandline Interface: Report optimizer options as invalid in Standard JSON and linker modes instead of ignoring them.
|
* Commandline Interface: Report optimizer options as invalid in Standard JSON and linker modes instead of ignoring them.
|
||||||
* Name Resolver: Fix that when importing an aliased symbol using ``import {AliasedName} from "a.sol"`` it would use the original name of the symbol and not the aliased one.
|
* Name Resolver: Fix that when importing an aliased symbol using ``import {AliasedName} from "a.sol"`` it would use the original name of the symbol and not the aliased one.
|
||||||
* Opcode Optimizer: Prevent the optimizer from running multiple times to avoid potential bytecode differences for referenced code.
|
* Opcode Optimizer: Prevent the optimizer from running multiple times to avoid potential bytecode differences for referenced code.
|
||||||
|
@ -297,7 +297,7 @@ Here are some examples of what you can expect if they are not:
|
|||||||
The same effect can be achieved in a more reliable way by using direct imports with
|
The same effect can be achieved in a more reliable way by using direct imports with
|
||||||
:ref:`base path <base-path>` and :ref:`import remapping <import-remapping>`.
|
:ref:`base path <base-path>` and :ref:`import remapping <import-remapping>`.
|
||||||
|
|
||||||
.. index:: ! base path, --base-path
|
.. index:: ! base path, ! --base-path
|
||||||
.. _base-path:
|
.. _base-path:
|
||||||
|
|
||||||
Base Path
|
Base Path
|
||||||
@ -373,6 +373,72 @@ The resulting file path becomes the source unit name.
|
|||||||
When working with older versions of the compiler it is recommended to invoke the compiler from
|
When working with older versions of the compiler it is recommended to invoke the compiler from
|
||||||
the base path and to only use relative paths on the command line.
|
the base path and to only use relative paths on the command line.
|
||||||
|
|
||||||
|
.. index:: ! allowed paths, ! --allow-paths, remapping; target
|
||||||
|
.. _allowed-paths:
|
||||||
|
|
||||||
|
Allowed Paths
|
||||||
|
=============
|
||||||
|
|
||||||
|
As a security measure, the Host Filesystem Loader will refuse to load files from outside of a few
|
||||||
|
locations that are considered safe by default:
|
||||||
|
|
||||||
|
- Outside of Standard JSON mode:
|
||||||
|
|
||||||
|
- The directories containing input files listed on the command line.
|
||||||
|
- The directories used as :ref:`remapping <import-remapping>` targets.
|
||||||
|
If the target is not a directory (i.e does not end with ``/``, ``/.`` or ``/..``) the directory
|
||||||
|
containing the target is used instead.
|
||||||
|
- Base path.
|
||||||
|
|
||||||
|
- In Standard JSON mode:
|
||||||
|
|
||||||
|
- Base path.
|
||||||
|
|
||||||
|
Additional directories can be whitelisted using the ``--allow-paths`` option.
|
||||||
|
The option accepts a comma-separated list of paths:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
cd /home/user/project/
|
||||||
|
solc token/contract.sol \
|
||||||
|
lib/util.sol=libs/util.sol \
|
||||||
|
--base-path=token/ \
|
||||||
|
--allow-paths=../utils/,/tmp/libraries
|
||||||
|
|
||||||
|
When the compiler is invoked with the command shown above, the Host Filesystem Loader will allow
|
||||||
|
importing files from the following directories:
|
||||||
|
|
||||||
|
- ``/home/user/project/token/`` (because ``token/`` contains the input file and also because it is
|
||||||
|
the base path),
|
||||||
|
- ``/home/user/project/libs/`` (because ``libs/`` is a directory containing a remapping target),
|
||||||
|
- ``/home/user/utils/`` (because of ``../utils/`` passed to ``--allow-paths``),
|
||||||
|
- ``/tmp/libraries/`` (because of ``/tmp/libraries`` passed to ``--allow-paths``),
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The working directory of the compiler is one of the paths allowed by default only if it
|
||||||
|
happens to be the base path (or the base path is not specified or has an empty value).
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The compiler does not check if allowed paths actually exist and whether they are directories.
|
||||||
|
Non-existent or empty paths are simply ignored.
|
||||||
|
If an allowed path matches a file rather than a directory, the file is considered whitelisted, too.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Allowed paths are case-sensitive even if the filesystem is not.
|
||||||
|
The case must exactly match the one used in your imports.
|
||||||
|
For example ``--allow-paths tokens`` will not match ``import "Tokens/IERC20.sol"``.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Files and directories only reachable through symbolic links from allowed directories are not
|
||||||
|
automatically whitelisted.
|
||||||
|
For example if ``token/contract.sol`` in the example above was actually a symlink pointing at
|
||||||
|
``/etc/passwd`` the compiler would refuse to load it unless ``/etc/`` was one of the allowed
|
||||||
|
paths too.
|
||||||
|
|
||||||
.. index:: ! remapping; import, ! import; remapping, ! remapping; context, ! remapping; prefix, ! remapping; target
|
.. index:: ! remapping; import, ! import; remapping, ! remapping; context, ! remapping; prefix, ! remapping; target
|
||||||
.. _import-remapping:
|
.. _import-remapping:
|
||||||
|
|
||||||
|
@ -47,16 +47,13 @@ it is also possible to provide :ref:`path redirects <import-remapping>` using ``
|
|||||||
|
|
||||||
This essentially instructs the compiler to search for anything starting with
|
This essentially instructs the compiler to search for anything starting with
|
||||||
``github.com/ethereum/dapp-bin/`` under ``/usr/local/lib/dapp-bin``.
|
``github.com/ethereum/dapp-bin/`` under ``/usr/local/lib/dapp-bin``.
|
||||||
``solc`` will not read files from the filesystem that lie outside of
|
|
||||||
the remapping targets and outside of the directories where explicitly specified source
|
|
||||||
files reside, so things like ``import "/etc/passwd";`` only work if you add ``/=/`` as a remapping.
|
|
||||||
|
|
||||||
When accessing the filesystem to search for imports, :ref:`paths that do not start with ./
|
When accessing the filesystem to search for imports, :ref:`paths that do not start with ./
|
||||||
or ../ <relative-imports>` are treated as relative to the directory specified using
|
or ../ <direct-imports>` are treated as relative to the directory specified using
|
||||||
``--base-path`` option (or the current working directory if base path is not specified).
|
``--base-path`` option (or the current working directory if base path is not specified).
|
||||||
Furthermore, the part added via ``--base-path`` will not appear in the contract metadata.
|
Furthermore, the part added via ``--base-path`` will not appear in the contract metadata.
|
||||||
|
|
||||||
For security reasons the compiler has restrictions on what directories it can access.
|
For security reasons the compiler has :ref:`restrictions on what directories it can access <allowed-paths>`.
|
||||||
Directories of source files specified on the command line and target paths of
|
Directories of source files specified on the command line and target paths of
|
||||||
remappings are automatically allowed to be accessed by the file reader, but everything
|
remappings are automatically allowed to be accessed by the file reader, but everything
|
||||||
else is rejected by default.
|
else is rejected by default.
|
||||||
|
@ -33,11 +33,29 @@ using std::string;
|
|||||||
namespace solidity::frontend
|
namespace solidity::frontend
|
||||||
{
|
{
|
||||||
|
|
||||||
|
FileReader::FileReader(
|
||||||
|
boost::filesystem::path _basePath,
|
||||||
|
FileSystemPathSet _allowedDirectories
|
||||||
|
):
|
||||||
|
m_allowedDirectories(std::move(_allowedDirectories)),
|
||||||
|
m_sourceCodes()
|
||||||
|
{
|
||||||
|
setBasePath(_basePath);
|
||||||
|
for (boost::filesystem::path const& allowedDir: m_allowedDirectories)
|
||||||
|
solAssert(!allowedDir.empty(), "");
|
||||||
|
}
|
||||||
|
|
||||||
void FileReader::setBasePath(boost::filesystem::path const& _path)
|
void FileReader::setBasePath(boost::filesystem::path const& _path)
|
||||||
{
|
{
|
||||||
m_basePath = (_path.empty() ? "" : normalizeCLIPathForVFS(_path));
|
m_basePath = (_path.empty() ? "" : normalizeCLIPathForVFS(_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileReader::allowDirectory(boost::filesystem::path _path)
|
||||||
|
{
|
||||||
|
solAssert(!_path.empty(), "");
|
||||||
|
m_allowedDirectories.insert(std::move(_path));
|
||||||
|
}
|
||||||
|
|
||||||
void FileReader::setSource(boost::filesystem::path const& _path, SourceCode _source)
|
void FileReader::setSource(boost::filesystem::path const& _path, SourceCode _source)
|
||||||
{
|
{
|
||||||
boost::filesystem::path normalizedPath = normalizeCLIPathForVFS(_path);
|
boost::filesystem::path normalizedPath = normalizeCLIPathForVFS(_path);
|
||||||
@ -69,20 +87,17 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so
|
|||||||
if (strippedSourceUnitName.find("file://") == 0)
|
if (strippedSourceUnitName.find("file://") == 0)
|
||||||
strippedSourceUnitName.erase(0, 7);
|
strippedSourceUnitName.erase(0, 7);
|
||||||
|
|
||||||
auto canonicalPath = boost::filesystem::weakly_canonical(m_basePath / strippedSourceUnitName);
|
auto canonicalPath = normalizeCLIPathForVFS(m_basePath / strippedSourceUnitName, SymlinkResolution::Enabled);
|
||||||
|
FileSystemPathSet extraAllowedPaths = {m_basePath.empty() ? "." : m_basePath};
|
||||||
|
|
||||||
bool isAllowed = false;
|
bool isAllowed = false;
|
||||||
for (auto const& allowedDir: m_allowedDirectories)
|
for (boost::filesystem::path const& allowedDir: m_allowedDirectories + extraAllowedPaths)
|
||||||
{
|
if (isPathPrefix(normalizeCLIPathForVFS(allowedDir, SymlinkResolution::Enabled), canonicalPath))
|
||||||
// If dir is a prefix of boostPath, we are fine.
|
|
||||||
if (
|
|
||||||
std::distance(allowedDir.begin(), allowedDir.end()) <= std::distance(canonicalPath.begin(), canonicalPath.end()) &&
|
|
||||||
std::equal(allowedDir.begin(), allowedDir.end(), canonicalPath.begin())
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
isAllowed = true;
|
isAllowed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!isAllowed)
|
if (!isAllowed)
|
||||||
return ReadCallback::Result{false, "File outside of allowed directories."};
|
return ReadCallback::Result{false, "File outside of allowed directories."};
|
||||||
|
|
||||||
@ -101,13 +116,20 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so
|
|||||||
{
|
{
|
||||||
return ReadCallback::Result{false, "Exception in read callback: " + boost::diagnostic_information(_exception)};
|
return ReadCallback::Result{false, "Exception in read callback: " + boost::diagnostic_information(_exception)};
|
||||||
}
|
}
|
||||||
|
catch (std::exception const& _exception)
|
||||||
|
{
|
||||||
|
return ReadCallback::Result{false, "Exception in read callback: " + boost::diagnostic_information(_exception)};
|
||||||
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
return ReadCallback::Result{false, "Unknown exception in read callback."};
|
return ReadCallback::Result{false, "Unknown exception in read callback."};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::filesystem::path FileReader::normalizeCLIPathForVFS(boost::filesystem::path const& _path)
|
boost::filesystem::path FileReader::normalizeCLIPathForVFS(
|
||||||
|
boost::filesystem::path const& _path,
|
||||||
|
SymlinkResolution _symlinkResolution
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// Detailed normalization rules:
|
// Detailed normalization rules:
|
||||||
// - Makes the path either be absolute or have slash as root (note that on Windows paths with
|
// - Makes the path either be absolute or have slash as root (note that on Windows paths with
|
||||||
@ -121,7 +143,8 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS(boost::filesystem::pa
|
|||||||
// path to the current working directory.
|
// path to the current working directory.
|
||||||
//
|
//
|
||||||
// Also note that this function:
|
// Also note that this function:
|
||||||
// - Does NOT resolve symlinks (except for symlinks in the path to the current working directory).
|
// - Does NOT resolve symlinks (except for symlinks in the path to the current working directory)
|
||||||
|
// unless explicitly requested.
|
||||||
// - Does NOT check if the path refers to a file or a directory. If the path ends with a slash,
|
// - Does NOT check if the path refers to a file or a directory. If the path ends with a slash,
|
||||||
// the slash is preserved even if it's a file.
|
// the slash is preserved even if it's a file.
|
||||||
// - The only exception are paths where the file name is a dot (e.g. '.' or 'a/b/.'). These
|
// - The only exception are paths where the file name is a dot (e.g. '.' or 'a/b/.'). These
|
||||||
@ -135,9 +158,27 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS(boost::filesystem::pa
|
|||||||
// Windows it does not. To get consistent results we resolve them on all platforms.
|
// Windows it does not. To get consistent results we resolve them on all platforms.
|
||||||
boost::filesystem::path absolutePath = boost::filesystem::absolute(_path, canonicalWorkDir);
|
boost::filesystem::path absolutePath = boost::filesystem::absolute(_path, canonicalWorkDir);
|
||||||
|
|
||||||
|
boost::filesystem::path normalizedPath;
|
||||||
|
if (_symlinkResolution == SymlinkResolution::Enabled)
|
||||||
|
{
|
||||||
|
// NOTE: weakly_canonical() will not convert a relative path into an absolute one if no
|
||||||
|
// directory included in the path actually exists.
|
||||||
|
normalizedPath = boost::filesystem::weakly_canonical(absolutePath);
|
||||||
|
|
||||||
|
// The three corner cases in which lexically_normal() includes a trailing slash in the
|
||||||
|
// normalized path but weakly_canonical() does not. Note that the trailing slash is not
|
||||||
|
// ignored when comparing paths with ==.
|
||||||
|
if ((_path == "." || _path == "./" || _path == "../") && !boost::ends_with(normalizedPath.generic_string(), "/"))
|
||||||
|
normalizedPath = normalizedPath.parent_path() / (normalizedPath.filename().string() + "/");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solAssert(_symlinkResolution == SymlinkResolution::Disabled, "");
|
||||||
|
|
||||||
// NOTE: boost path preserves certain differences that are ignored by its operator ==.
|
// NOTE: boost path preserves certain differences that are ignored by its operator ==.
|
||||||
// E.g. "a//b" vs "a/b" or "a/b/" vs "a/b/.". lexically_normal() does remove these differences.
|
// E.g. "a//b" vs "a/b" or "a/b/" vs "a/b/.". lexically_normal() does remove these differences.
|
||||||
boost::filesystem::path normalizedPath = absolutePath.lexically_normal();
|
normalizedPath = absolutePath.lexically_normal();
|
||||||
|
}
|
||||||
solAssert(normalizedPath.is_absolute() || normalizedPath.root_path() == "/", "");
|
solAssert(normalizedPath.is_absolute() || normalizedPath.root_path() == "/", "");
|
||||||
|
|
||||||
// If the path is on the same drive as the working dir, for portability we prefer not to
|
// If the path is on the same drive as the working dir, for portability we prefer not to
|
||||||
|
@ -39,22 +39,19 @@ public:
|
|||||||
using PathMap = std::map<SourceUnitName, boost::filesystem::path>;
|
using PathMap = std::map<SourceUnitName, boost::filesystem::path>;
|
||||||
using FileSystemPathSet = std::set<boost::filesystem::path>;
|
using FileSystemPathSet = std::set<boost::filesystem::path>;
|
||||||
|
|
||||||
|
enum SymlinkResolution {
|
||||||
|
Disabled, ///< Do not resolve symbolic links in the path.
|
||||||
|
Enabled, ///< Follow symbolic links. The path should contain no symlinks.
|
||||||
|
};
|
||||||
|
|
||||||
/// Constructs a FileReader with a base path and a set of allowed directories that
|
/// Constructs a FileReader with a base path and a set of allowed directories that
|
||||||
/// will be used when requesting files from this file reader instance.
|
/// will be used when requesting files from this file reader instance.
|
||||||
explicit FileReader(
|
explicit FileReader(boost::filesystem::path _basePath = {}, FileSystemPathSet _allowedDirectories = {});
|
||||||
boost::filesystem::path _basePath = {},
|
|
||||||
FileSystemPathSet _allowedDirectories = {}
|
|
||||||
):
|
|
||||||
m_allowedDirectories(std::move(_allowedDirectories)),
|
|
||||||
m_sourceCodes()
|
|
||||||
{
|
|
||||||
setBasePath(_basePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setBasePath(boost::filesystem::path const& _path);
|
void setBasePath(boost::filesystem::path const& _path);
|
||||||
boost::filesystem::path const& basePath() const noexcept { return m_basePath; }
|
boost::filesystem::path const& basePath() const noexcept { return m_basePath; }
|
||||||
|
|
||||||
void allowDirectory(boost::filesystem::path _path) { m_allowedDirectories.insert(std::move(_path)); }
|
void allowDirectory(boost::filesystem::path _path);
|
||||||
FileSystemPathSet const& allowedDirectories() const noexcept { return m_allowedDirectories; }
|
FileSystemPathSet const& allowedDirectories() const noexcept { return m_allowedDirectories; }
|
||||||
|
|
||||||
StringMap const& sourceCodes() const noexcept { return m_sourceCodes; }
|
StringMap const& sourceCodes() const noexcept { return m_sourceCodes; }
|
||||||
@ -90,11 +87,16 @@ public:
|
|||||||
|
|
||||||
/// Normalizes a filesystem path to make it include all components up to the filesystem root,
|
/// Normalizes a filesystem path to make it include all components up to the filesystem root,
|
||||||
/// remove small, inconsequential differences that do not affect the meaning and make it look
|
/// remove small, inconsequential differences that do not affect the meaning and make it look
|
||||||
/// the same on all platforms (if possible). Symlinks in the path are not resolved.
|
/// the same on all platforms (if possible).
|
||||||
/// The resulting path uses forward slashes as path separators, has no redundant separators,
|
/// The resulting path uses forward slashes as path separators, has no redundant separators,
|
||||||
/// has no redundant . or .. segments and has no root name if removing it does not change the meaning.
|
/// has no redundant . or .. segments and has no root name if removing it does not change the meaning.
|
||||||
/// The path does not have to actually exist.
|
/// The path does not have to actually exist.
|
||||||
static boost::filesystem::path normalizeCLIPathForVFS(boost::filesystem::path const& _path);
|
/// @param _path Path to normalize.
|
||||||
|
/// @param _symlinkResolution If @a Disabled, any symlinks present in @a _path are preserved.
|
||||||
|
static boost::filesystem::path normalizeCLIPathForVFS(
|
||||||
|
boost::filesystem::path const& _path,
|
||||||
|
SymlinkResolution _symlinkResolution = SymlinkResolution::Disabled
|
||||||
|
);
|
||||||
|
|
||||||
/// @returns true if all the path components of @a _prefix are present at the beginning of @a _path.
|
/// @returns true if all the path components of @a _prefix are present at the beginning of @a _path.
|
||||||
/// Both paths must be absolute (or have slash as root) and normalized (no . or .. segments, no
|
/// Both paths must be absolute (or have slash as root) and normalized (no . or .. segments, no
|
||||||
|
@ -20,10 +20,12 @@
|
|||||||
#include <liblangutil/Exceptions.h>
|
#include <liblangutil/Exceptions.h>
|
||||||
|
|
||||||
using std::equal;
|
using std::equal;
|
||||||
|
using std::find;
|
||||||
using std::move;
|
using std::move;
|
||||||
|
using std::nullopt;
|
||||||
using std::optional;
|
using std::optional;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::string;
|
using std::string_view;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
namespace solidity::frontend
|
namespace solidity::frontend
|
||||||
@ -77,24 +79,29 @@ SourceUnitName ImportRemapper::apply(ImportPath const& _path, string const& _con
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<ImportRemapper::Remapping> ImportRemapper::parseRemapping(string const& _remapping)
|
bool ImportRemapper::isRemapping(string_view _input)
|
||||||
{
|
{
|
||||||
auto eq = find(_remapping.begin(), _remapping.end(), '=');
|
return _input.find("=") != string::npos;
|
||||||
if (eq == _remapping.end())
|
}
|
||||||
return {};
|
|
||||||
|
|
||||||
auto colon = find(_remapping.begin(), eq, ':');
|
optional<ImportRemapper::Remapping> ImportRemapper::parseRemapping(string_view _input)
|
||||||
|
{
|
||||||
|
auto equals = find(_input.cbegin(), _input.cend(), '=');
|
||||||
|
if (equals == _input.end())
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
Remapping r;
|
auto const colon = find(_input.cbegin(), equals, ':');
|
||||||
|
|
||||||
r.context = colon == eq ? string() : string(_remapping.begin(), colon);
|
Remapping remapping{
|
||||||
r.prefix = colon == eq ? string(_remapping.begin(), eq) : string(colon + 1, eq);
|
(colon == equals ? "" : string(_input.cbegin(), colon)),
|
||||||
r.target = string(eq + 1, _remapping.end());
|
(colon == equals ? string(_input.cbegin(), equals) : string(colon + 1, equals)),
|
||||||
|
string(equals + 1, _input.cend()),
|
||||||
|
};
|
||||||
|
|
||||||
if (r.prefix.empty())
|
if (remapping.prefix.empty())
|
||||||
return {};
|
return nullopt;
|
||||||
|
|
||||||
return r;
|
return remapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -56,8 +56,11 @@ public:
|
|||||||
|
|
||||||
SourceUnitName apply(ImportPath const& _path, std::string const& _context) const;
|
SourceUnitName apply(ImportPath const& _path, std::string const& _context) const;
|
||||||
|
|
||||||
// Parses a remapping of the format "context:prefix=target".
|
/// @returns true if the string can be parsed as a remapping
|
||||||
static std::optional<Remapping> parseRemapping(std::string const& _remapping);
|
static bool isRemapping(std::string_view _input);
|
||||||
|
|
||||||
|
/// Parses a remapping of the format "context:prefix=target".
|
||||||
|
static std::optional<Remapping> parseRemapping(std::string_view _input);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
|
/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
|
||||||
|
@ -338,11 +338,17 @@ bool CommandLineParser::parseInputPathsAndRemappings()
|
|||||||
m_options.input.ignoreMissingFiles = (m_args.count(g_strIgnoreMissingFiles) > 0);
|
m_options.input.ignoreMissingFiles = (m_args.count(g_strIgnoreMissingFiles) > 0);
|
||||||
|
|
||||||
if (m_args.count(g_strInputFile))
|
if (m_args.count(g_strInputFile))
|
||||||
for (string path: m_args[g_strInputFile].as<vector<string>>())
|
for (string const& positionalArg: m_args[g_strInputFile].as<vector<string>>())
|
||||||
{
|
{
|
||||||
auto eq = find(path.begin(), path.end(), '=');
|
if (ImportRemapper::isRemapping(positionalArg))
|
||||||
if (eq != path.end())
|
|
||||||
{
|
{
|
||||||
|
optional<ImportRemapper::Remapping> remapping = ImportRemapper::parseRemapping(positionalArg);
|
||||||
|
if (!remapping.has_value())
|
||||||
|
{
|
||||||
|
serr() << "Invalid remapping: \"" << positionalArg << "\"." << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_options.input.mode == InputMode::StandardJson)
|
if (m_options.input.mode == InputMode::StandardJson)
|
||||||
{
|
{
|
||||||
serr() << "Import remappings are not accepted on the command line in Standard JSON mode." << endl;
|
serr() << "Import remappings are not accepted on the command line in Standard JSON mode." << endl;
|
||||||
@ -350,21 +356,24 @@ bool CommandLineParser::parseInputPathsAndRemappings()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto r = ImportRemapper::parseRemapping(path))
|
if (!remapping->target.empty())
|
||||||
m_options.input.remappings.emplace_back(std::move(*r));
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
serr() << "Invalid remapping: \"" << path << "\"." << endl;
|
// If the target is a directory, whitelist it. Otherwise whitelist containing dir.
|
||||||
return false;
|
// NOTE: /a/b/c/ is a directory while /a/b/c is not.
|
||||||
|
boost::filesystem::path remappingDir = remapping->target;
|
||||||
|
if (remappingDir.filename() != "..")
|
||||||
|
// As an exception we'll treat /a/b/c/.. as a directory too. It would be
|
||||||
|
// unintuitive to whitelist /a/b/c when the target is equivalent to /a/b/.
|
||||||
|
remappingDir.remove_filename();
|
||||||
|
m_options.input.allowedDirectories.insert(remappingDir.empty() ? "." : remappingDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
string remappingTarget(eq + 1, path.end());
|
m_options.input.remappings.emplace_back(move(remapping.value()));
|
||||||
m_options.input.allowedDirectories.insert(boost::filesystem::path(remappingTarget).remove_filename());
|
|
||||||
}
|
}
|
||||||
else if (path == "-")
|
else if (positionalArg == "-")
|
||||||
m_options.input.addStdin = true;
|
m_options.input.addStdin = true;
|
||||||
else
|
else
|
||||||
m_options.input.paths.insert(path);
|
m_options.input.paths.insert(positionalArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_options.input.mode == InputMode::StandardJson)
|
if (m_options.input.mode == InputMode::StandardJson)
|
||||||
@ -977,17 +986,9 @@ bool CommandLineParser::processArgs()
|
|||||||
if (m_args.count(g_strAllowPaths))
|
if (m_args.count(g_strAllowPaths))
|
||||||
{
|
{
|
||||||
vector<string> paths;
|
vector<string> paths;
|
||||||
for (string const& path: boost::split(paths, m_args[g_strAllowPaths].as<string>(), boost::is_any_of(",")))
|
for (string const& allowedPath: boost::split(paths, m_args[g_strAllowPaths].as<string>(), boost::is_any_of(",")))
|
||||||
{
|
if (!allowedPath.empty())
|
||||||
auto filesystem_path = boost::filesystem::path(path);
|
m_options.input.allowedDirectories.insert(allowedPath);
|
||||||
// If the given path had a trailing slash, the Boost filesystem
|
|
||||||
// path will have it's last component set to '.'. This breaks
|
|
||||||
// path comparison in later parts of the code, so we need to strip
|
|
||||||
// it.
|
|
||||||
if (filesystem_path.filename() == ".")
|
|
||||||
filesystem_path.remove_filename();
|
|
||||||
m_options.input.allowedDirectories.insert(filesystem_path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_args.count(g_strStopAfter))
|
if (m_args.count(g_strStopAfter))
|
||||||
|
@ -160,6 +160,7 @@ set(solcli_sources
|
|||||||
solc/Common.cpp
|
solc/Common.cpp
|
||||||
solc/Common.h
|
solc/Common.h
|
||||||
solc/CommandLineInterface.cpp
|
solc/CommandLineInterface.cpp
|
||||||
|
solc/CommandLineInterfaceAllowPaths.cpp
|
||||||
solc/CommandLineParser.cpp
|
solc/CommandLineParser.cpp
|
||||||
)
|
)
|
||||||
detect_stray_source_files("${solcli_sources}" "solc/")
|
detect_stray_source_files("${solcli_sources}" "solc/")
|
||||||
|
@ -53,13 +53,17 @@ void solidity::test::createFileWithContent(boost::filesystem::path const& _path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool solidity::test::createSymlinkIfSupportedByFilesystem(
|
bool solidity::test::createSymlinkIfSupportedByFilesystem(
|
||||||
boost::filesystem::path const& _targetPath,
|
boost::filesystem::path _targetPath,
|
||||||
boost::filesystem::path const& _linkName,
|
boost::filesystem::path const& _linkName,
|
||||||
bool _directorySymlink
|
bool _directorySymlink
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
boost::system::error_code symlinkCreationError;
|
boost::system::error_code symlinkCreationError;
|
||||||
|
|
||||||
|
// NOTE: On Windows / works as a separator in a symlink target only if the target is absolute.
|
||||||
|
// Convert path separators to native ones to avoid this problem.
|
||||||
|
_targetPath.make_preferred();
|
||||||
|
|
||||||
if (_directorySymlink)
|
if (_directorySymlink)
|
||||||
boost::filesystem::create_directory_symlink(_targetPath, _linkName, symlinkCreationError);
|
boost::filesystem::create_directory_symlink(_targetPath, _linkName, symlinkCreationError);
|
||||||
else
|
else
|
||||||
|
@ -46,7 +46,7 @@ void createFileWithContent(boost::filesystem::path const& _path, std::string con
|
|||||||
/// support symlinks.
|
/// support symlinks.
|
||||||
/// Throws an exception of the operation fails for a different reason.
|
/// Throws an exception of the operation fails for a different reason.
|
||||||
bool createSymlinkIfSupportedByFilesystem(
|
bool createSymlinkIfSupportedByFilesystem(
|
||||||
boost::filesystem::path const& _targetPath,
|
boost::filesystem::path _targetPath,
|
||||||
boost::filesystem::path const& _linkName,
|
boost::filesystem::path const& _linkName,
|
||||||
bool _directorySymlink
|
bool _directorySymlink
|
||||||
);
|
);
|
||||||
|
@ -1 +0,0 @@
|
|||||||
-
|
|
@ -1,11 +0,0 @@
|
|||||||
Error: Source "too_long_line/input.sol" not found: File outside of allowed directories.
|
|
||||||
--> <stdin>:4:1:
|
|
||||||
|
|
|
||||||
4 | import "../too_long_line/input.sol";
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Error: Source "error_codes/input.sol" not found: File outside of allowed directories.
|
|
||||||
--> stdin_allowed_paths/input.sol:4:1:
|
|
||||||
|
|
|
||||||
4 | import "../error_codes/input.sol";
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
@ -1 +0,0 @@
|
|||||||
1
|
|
@ -1,4 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
pragma solidity >=0.0;
|
|
||||||
|
|
||||||
import "../error_codes/input.sol";
|
|
@ -1,4 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
pragma solidity >=0.0;
|
|
||||||
|
|
||||||
import "../too_long_line/input.sol";
|
|
@ -36,31 +36,39 @@ using namespace solidity::test;
|
|||||||
namespace solidity::frontend::test
|
namespace solidity::frontend::test
|
||||||
{
|
{
|
||||||
|
|
||||||
|
using SymlinkResolution = FileReader::SymlinkResolution;
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(FileReaderTest)
|
BOOST_AUTO_TEST_SUITE(FileReaderTest)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_absolute_path)
|
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_absolute_path)
|
||||||
{
|
{
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/"), "/");
|
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/."), "/");
|
{
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./"), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/.", resolveSymlinks), "/");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./", resolveSymlinks), "/");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./.", resolveSymlinks), "/");
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a"), "/a");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a", resolveSymlinks), "/a");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/"), "/a/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/", resolveSymlinks), "/a/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/."), "/a/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/.", resolveSymlinks), "/a/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a"), "/a");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a", resolveSymlinks), "/a");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/"), "/a/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/", resolveSymlinks), "/a/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/."), "/a/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/.", resolveSymlinks), "/a/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b"), "/a/b");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b", resolveSymlinks), "/a/b");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/"), "/a/b/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/", resolveSymlinks), "/a/b/");
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/./b/"), "/a/b/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/..", resolveSymlinks), "/a/b");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../a/b/"), "/a/b/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../", resolveSymlinks), "/a/b/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/.."), "/a/b");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/./b/", resolveSymlinks), "/a/b/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../"), "/a/b/");
|
#if !defined(_WIN32) || BOOST_VERSION > 107600
|
||||||
|
// This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../a/b/", resolveSymlinks), "/a/b/");
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../.."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../..", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../../"), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../../", resolveSymlinks), "/");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path)
|
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path)
|
||||||
@ -75,54 +83,64 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path)
|
|||||||
expectedPrefix = "/" / expectedPrefix.relative_path();
|
expectedPrefix = "/" / expectedPrefix.relative_path();
|
||||||
soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", "");
|
soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", "");
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("."), expectedPrefix / "x/y/z/");
|
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./"), expectedPrefix / "x/y/z/");
|
{
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".//"), expectedPrefix / "x/y/z/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".", resolveSymlinks), expectedPrefix / "x/y/z/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".."), expectedPrefix / "x/y");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./", resolveSymlinks), expectedPrefix / "x/y/z/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../"), expectedPrefix / "x/y/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".//", resolveSymlinks), expectedPrefix / "x/y/z/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..//"), expectedPrefix / "x/y/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..", resolveSymlinks), expectedPrefix / "x/y");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../", resolveSymlinks), expectedPrefix / "x/y/");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..//", resolveSymlinks), expectedPrefix / "x/y/");
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a"), expectedPrefix / "x/y/z/a");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a", resolveSymlinks), expectedPrefix / "x/y/z/a");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/"), expectedPrefix / "x/y/z/a/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/."), expectedPrefix / "x/y/z/a/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/.", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a"), expectedPrefix / "x/y/z/a");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a", resolveSymlinks), expectedPrefix / "x/y/z/a");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/"), expectedPrefix / "x/y/z/a/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/."), expectedPrefix / "x/y/z/a/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/.", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./"), expectedPrefix / "x/y/z/a/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/.//"), expectedPrefix / "x/y/z/a/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/.//", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./."), expectedPrefix / "x/y/z/a/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./.", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././"), expectedPrefix / "x/y/z/a/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././/"), expectedPrefix / "x/y/z/a/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././/", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b"), expectedPrefix / "x/y/z/a/b");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b", resolveSymlinks), expectedPrefix / "x/y/z/a/b");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/"), expectedPrefix / "x/y/z/a/b/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/");
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/b"), expectedPrefix / "x/y/a/b");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/b", resolveSymlinks), expectedPrefix / "x/y/a/b");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/b"), expectedPrefix / "x/a/b");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/b", resolveSymlinks), expectedPrefix / "x/a/b");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/b"), expectedPrefix / "x/y/z/a/b");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/b", resolveSymlinks), expectedPrefix / "x/y/z/a/b");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("././a/b"), expectedPrefix / "x/y/z/a/b");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("././a/b", resolveSymlinks), expectedPrefix / "x/y/z/a/b");
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/./b/"), expectedPrefix / "x/y/z/a/b/");
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../a/b/"), expectedPrefix / "x/y/z/a/b/");
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/.."), expectedPrefix / "x/y/z/a/b");
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../"), expectedPrefix / "x/y/z/a/b/");
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..//"), expectedPrefix / "x/y/z/a/b/");
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../.."), expectedPrefix / "x/y/z/a");
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../../"), expectedPrefix / "x/y/z/a/");
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..//"), expectedPrefix / "x/y/z/a/");
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b"), expectedPrefix / "a/b");
|
#if !defined(_WIN32) || BOOST_VERSION > 107600
|
||||||
|
// This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b", resolveSymlinks), expectedPrefix / "a/b");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../a/b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/");
|
||||||
|
#endif
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/./b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..", resolveSymlinks), expectedPrefix / "x/y/z/a/b");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../", resolveSymlinks), expectedPrefix / "x/y/z/a/b/");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..//", resolveSymlinks), expectedPrefix / "x/y/z/a/b/");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..", resolveSymlinks), expectedPrefix / "x/y/z/a");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../../", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..//", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_redundant_slashes)
|
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_redundant_slashes)
|
||||||
{
|
{
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("///"), "/");
|
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////"), "/");
|
{
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("///", resolveSymlinks), "/");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////", resolveSymlinks), "/");
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////a/b/"), "/a/b/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////a/b/", resolveSymlinks), "/a/b/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a//b/"), "/a/b/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a//b/", resolveSymlinks), "/a/b/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a////b/"), "/a/b/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a////b/", resolveSymlinks), "/a/b/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b//"), "/a/b/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b//", resolveSymlinks), "/a/b/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b////"), "/a/b/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b////", resolveSymlinks), "/a/b/");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_unc_path)
|
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_unc_path)
|
||||||
@ -134,23 +152,26 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_unc_path)
|
|||||||
boost::filesystem::path expectedWorkDir = "/" / boost::filesystem::current_path().relative_path();
|
boost::filesystem::path expectedWorkDir = "/" / boost::filesystem::current_path().relative_path();
|
||||||
soltestAssert(expectedWorkDir.is_absolute() || expectedWorkDir.root_path() == "/", "");
|
soltestAssert(expectedWorkDir.is_absolute() || expectedWorkDir.root_path() == "/", "");
|
||||||
|
|
||||||
|
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||||
|
{
|
||||||
// UNC paths start with // or \\ followed by a name. They are used for network shares on Windows.
|
// UNC paths start with // or \\ followed by a name. They are used for network shares on Windows.
|
||||||
// On UNIX systems they are not supported but still treated in a special way.
|
// On UNIX systems they are not supported but still treated in a special way.
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/"), "//host/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/", resolveSymlinks), "//host/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b"), "//host/a/b");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b", resolveSymlinks), "//host/a/b");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b/"), "//host/a/b/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b/", resolveSymlinks), "//host/a/b/");
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
// On Windows an UNC path can also start with \\ instead of //
|
// On Windows an UNC path can also start with \\ instead of //
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/"), "//host/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/", resolveSymlinks), "//host/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b"), "//host/a/b");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b", resolveSymlinks), "//host/a/b");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/"), "//host/a/b/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/", resolveSymlinks), "//host/a/b/");
|
||||||
#else
|
#else
|
||||||
// On UNIX systems it's just a fancy relative path instead
|
// On UNIX systems it's just a fancy relative path instead
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/"), expectedWorkDir / "\\\\host/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/", resolveSymlinks), expectedWorkDir / "\\\\host/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b"), expectedWorkDir / "\\\\host/a/b");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b", resolveSymlinks), expectedWorkDir / "\\\\host/a/b");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/"), expectedWorkDir / "\\\\host/a/b/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/", resolveSymlinks), expectedWorkDir / "\\\\host/a/b/");
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_root_name_only)
|
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_root_name_only)
|
||||||
@ -167,20 +188,23 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_root_name_only)
|
|||||||
// C:\ represents the root directory of drive C: but C: on its own refers to the current working
|
// C:\ represents the root directory of drive C: but C: on its own refers to the current working
|
||||||
// directory.
|
// directory.
|
||||||
|
|
||||||
|
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||||
|
{
|
||||||
// UNC paths
|
// UNC paths
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//"), "//" / expectedWorkDir);
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//", resolveSymlinks), "//" / expectedWorkDir);
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host"), "//host" / expectedWorkDir);
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host", resolveSymlinks), "//host" / expectedWorkDir);
|
||||||
|
|
||||||
// On UNIX systems root name is empty.
|
// On UNIX systems root name is empty.
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(""), expectedWorkDir);
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("", resolveSymlinks), expectedWorkDir);
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
boost::filesystem::path driveLetter = boost::filesystem::current_path().root_name();
|
boost::filesystem::path driveLetter = boost::filesystem::current_path().root_name();
|
||||||
solAssert(!driveLetter.empty(), "");
|
solAssert(!driveLetter.empty(), "");
|
||||||
solAssert(driveLetter.is_relative(), "");
|
solAssert(driveLetter.is_relative(), "");
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(driveLetter), expectedWorkDir);
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(driveLetter, resolveSymlinks), expectedWorkDir);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_stripping_root_name)
|
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_stripping_root_name)
|
||||||
@ -193,41 +217,55 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_stripping_root_name)
|
|||||||
soltestAssert(!boost::filesystem::current_path().root_name().empty(), "");
|
soltestAssert(!boost::filesystem::current_path().root_name().empty(), "");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
boost::filesystem::path normalizedPath = FileReader::normalizeCLIPathForVFS(boost::filesystem::current_path());
|
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||||
|
{
|
||||||
|
boost::filesystem::path normalizedPath = FileReader::normalizeCLIPathForVFS(
|
||||||
|
boost::filesystem::current_path(),
|
||||||
|
resolveSymlinks
|
||||||
|
);
|
||||||
BOOST_CHECK_EQUAL(normalizedPath, "/" / boost::filesystem::current_path().relative_path());
|
BOOST_CHECK_EQUAL(normalizedPath, "/" / boost::filesystem::current_path().relative_path());
|
||||||
BOOST_TEST(normalizedPath.root_name().empty());
|
BOOST_TEST(normalizedPath.root_name().empty());
|
||||||
BOOST_CHECK_EQUAL(normalizedPath.root_directory(), "/");
|
BOOST_CHECK_EQUAL(normalizedPath.root_directory(), "/");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_beyond_root)
|
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_beyond_root)
|
||||||
{
|
{
|
||||||
TemporaryWorkingDirectory tempWorkDir("/");
|
TemporaryWorkingDirectory tempWorkDir("/");
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/.."), "/");
|
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../"), "/");
|
{
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/..", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../.."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a"), "/a");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../.", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/.."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../..", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/../.."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a", resolveSymlinks), "/a");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a"), "/a");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a", resolveSymlinks), "/a");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/.."), "/");
|
#if !defined(_WIN32) || BOOST_VERSION > 107600
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/../.."), "/");
|
// This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../.."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/..", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../../b/../.."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/../..", resolveSymlinks), "/");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/..", resolveSymlinks), "/");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/../..", resolveSymlinks), "/");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../..", resolveSymlinks), "/");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../../b/../..", resolveSymlinks), "/");
|
||||||
|
#endif
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../"), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../.", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../.."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../..", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a"), "/a");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a", resolveSymlinks), "/a");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/.."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a", resolveSymlinks), "/a");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/../.."), "/");
|
#if !defined(_WIN32) || BOOST_VERSION > 107600
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a"), "/a");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/..", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/../..", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/../.."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/..", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../.."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/../..", resolveSymlinks), "/");
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../../b/../.."), "/");
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../..", resolveSymlinks), "/");
|
||||||
|
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../../b/../..", resolveSymlinks), "/");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_case_sensitivity)
|
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_case_sensitivity)
|
||||||
@ -235,22 +273,31 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_case_sensitivity)
|
|||||||
TemporaryDirectory tempDir(TEST_CASE_NAME);
|
TemporaryDirectory tempDir(TEST_CASE_NAME);
|
||||||
TemporaryWorkingDirectory tempWorkDir(tempDir);
|
TemporaryWorkingDirectory tempWorkDir(tempDir);
|
||||||
|
|
||||||
boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path();
|
boost::filesystem::path workDirNoSymlinks = boost::filesystem::weakly_canonical(tempDir);
|
||||||
soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", "");
|
boost::filesystem::path expectedPrefix = "/" / workDirNoSymlinks.relative_path();
|
||||||
|
|
||||||
BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc") == expectedPrefix / "abc");
|
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||||
BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc") != expectedPrefix / "ABC");
|
{
|
||||||
BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "ABC") != expectedPrefix / "abc");
|
BOOST_TEST(FileReader::normalizeCLIPathForVFS(workDirNoSymlinks / "abc", resolveSymlinks) == expectedPrefix / "abc");
|
||||||
BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "ABC") == expectedPrefix / "ABC");
|
BOOST_TEST(FileReader::normalizeCLIPathForVFS(workDirNoSymlinks / "abc", resolveSymlinks) != expectedPrefix / "ABC");
|
||||||
|
BOOST_TEST(FileReader::normalizeCLIPathForVFS(workDirNoSymlinks / "ABC", resolveSymlinks) != expectedPrefix / "abc");
|
||||||
|
BOOST_TEST(FileReader::normalizeCLIPathForVFS(workDirNoSymlinks / "ABC", resolveSymlinks) == expectedPrefix / "ABC");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_separators)
|
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_separators)
|
||||||
{
|
{
|
||||||
|
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||||
|
{
|
||||||
// Even on Windows we want / as a separator.
|
// Even on Windows we want / as a separator.
|
||||||
BOOST_TEST((FileReader::normalizeCLIPathForVFS("/a/b/c").native() == boost::filesystem::path("/a/b/c").native()));
|
BOOST_TEST((
|
||||||
|
FileReader::normalizeCLIPathForVFS("/a/b/c", resolveSymlinks).native() ==
|
||||||
|
boost::filesystem::path("/a/b/c").native()
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks)
|
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks_unless_requested)
|
||||||
{
|
{
|
||||||
TemporaryDirectory tempDir({"abc/"}, TEST_CASE_NAME);
|
TemporaryDirectory tempDir({"abc/"}, TEST_CASE_NAME);
|
||||||
soltestAssert(tempDir.path().is_absolute(), "");
|
soltestAssert(tempDir.path().is_absolute(), "");
|
||||||
@ -258,11 +305,26 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks)
|
|||||||
if (!createSymlinkIfSupportedByFilesystem(tempDir.path() / "abc", tempDir.path() / "sym", true))
|
if (!createSymlinkIfSupportedByFilesystem(tempDir.path() / "abc", tempDir.path() / "sym", true))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path();
|
boost::filesystem::path expectedPrefixWithSymlinks = "/" / tempDir.path().relative_path();
|
||||||
soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", "");
|
boost::filesystem::path expectedPrefixWithoutSymlinks = "/" / boost::filesystem::weakly_canonical(tempDir).relative_path();
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol"), expectedPrefix / "sym/contract.sol");
|
BOOST_CHECK_EQUAL(
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol"), expectedPrefix / "abc/contract.sol");
|
FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol", SymlinkResolution::Disabled),
|
||||||
|
expectedPrefixWithSymlinks / "sym/contract.sol"
|
||||||
|
);
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol", SymlinkResolution::Disabled),
|
||||||
|
expectedPrefixWithSymlinks / "abc/contract.sol"
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol", SymlinkResolution::Enabled),
|
||||||
|
expectedPrefixWithoutSymlinks / "abc/contract.sol"
|
||||||
|
);
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol", SymlinkResolution::Enabled),
|
||||||
|
expectedPrefixWithoutSymlinks / "abc/contract.sol"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_resolve_symlinks_in_workdir_when_path_is_relative)
|
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_resolve_symlinks_in_workdir_when_path_is_relative)
|
||||||
@ -280,9 +342,31 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_resolve_symlinks_in_workdir_w
|
|||||||
boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path();
|
boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path();
|
||||||
soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", "");
|
soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", "");
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("contract.sol"), expectedWorkDir / "contract.sol");
|
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol"), expectedPrefix / "sym/contract.sol");
|
{
|
||||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol"), expectedPrefix / "abc/contract.sol");
|
BOOST_CHECK_EQUAL(
|
||||||
|
FileReader::normalizeCLIPathForVFS("contract.sol", resolveSymlinks),
|
||||||
|
expectedWorkDir / "contract.sol"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol", SymlinkResolution::Disabled),
|
||||||
|
expectedPrefix / "sym/contract.sol"
|
||||||
|
);
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol", SymlinkResolution::Disabled),
|
||||||
|
expectedPrefix / "abc/contract.sol"
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol", SymlinkResolution::Enabled),
|
||||||
|
expectedWorkDir / "contract.sol"
|
||||||
|
);
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol", SymlinkResolution::Enabled),
|
||||||
|
expectedWorkDir / "contract.sol"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(isPathPrefix_file_prefix)
|
BOOST_AUTO_TEST_CASE(isPathPrefix_file_prefix)
|
||||||
|
@ -786,12 +786,7 @@ BOOST_AUTO_TEST_CASE(cli_paths_to_source_unit_names_symlinks)
|
|||||||
TemporaryWorkingDirectory tempWorkDir(tempDir.path() / "r");
|
TemporaryWorkingDirectory tempWorkDir(tempDir.path() / "r");
|
||||||
|
|
||||||
if (
|
if (
|
||||||
#if !defined(_WIN32)
|
|
||||||
!createSymlinkIfSupportedByFilesystem("../x/y", tempDir.path() / "r/sym", true) ||
|
!createSymlinkIfSupportedByFilesystem("../x/y", tempDir.path() / "r/sym", true) ||
|
||||||
#else
|
|
||||||
// NOTE: On Windows / works as a separator in a symlink target only if the target is absolute
|
|
||||||
!createSymlinkIfSupportedByFilesystem("..\\x\\y", tempDir.path() / "r/sym", true) ||
|
|
||||||
#endif
|
|
||||||
!createSymlinkIfSupportedByFilesystem("contract.sol", tempDir.path() / "x/y/z/contract_symlink.sol", false)
|
!createSymlinkIfSupportedByFilesystem("contract.sol", tempDir.path() / "x/y/z/contract_symlink.sol", false)
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
539
test/solc/CommandLineInterfaceAllowPaths.cpp
Normal file
539
test/solc/CommandLineInterfaceAllowPaths.cpp
Normal file
@ -0,0 +1,539 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
|
/// Unit tests for solc/CommandLineInterface.h
|
||||||
|
|
||||||
|
#include <solc/CommandLineInterface.h>
|
||||||
|
|
||||||
|
#include <test/solc/Common.h>
|
||||||
|
|
||||||
|
#include <test/Common.h>
|
||||||
|
#include <test/FilesystemUtils.h>
|
||||||
|
#include <test/TemporaryDirectory.h>
|
||||||
|
#include <test/libsolidity/util/SoltestErrors.h>
|
||||||
|
|
||||||
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <regex>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace solidity::frontend;
|
||||||
|
using namespace solidity::test;
|
||||||
|
|
||||||
|
#define TEST_CASE_NAME (boost::unit_test::framework::current_test_case().p_name)
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
struct ImportCheck
|
||||||
|
{
|
||||||
|
enum class Result
|
||||||
|
{
|
||||||
|
Unknown, ///< Status is unknown due to a failure of the status check.
|
||||||
|
OK, ///< Passed compilation without errors.
|
||||||
|
FileNotFound, ///< Error was reported: file not found.
|
||||||
|
PathDisallowed, ///< Error was reported: file not allowed paths.
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator==(ImportCheck const& _other) const { return result == _other.result && message == _other.message; }
|
||||||
|
bool operator!=(ImportCheck const& _other) const { return !(*this == _other); }
|
||||||
|
|
||||||
|
operator bool() const { return this->result == Result::OK; }
|
||||||
|
|
||||||
|
static ImportCheck const OK() { return {Result::OK, ""}; }
|
||||||
|
static ImportCheck const FileNotFound() { return {Result::FileNotFound, ""}; }
|
||||||
|
static ImportCheck const PathDisallowed() { return {Result::PathDisallowed, ""}; }
|
||||||
|
static ImportCheck const Unknown(const string& _message) { return {Result::Unknown, _message}; }
|
||||||
|
|
||||||
|
Result result;
|
||||||
|
std::string message;
|
||||||
|
};
|
||||||
|
|
||||||
|
ImportCheck checkImport(
|
||||||
|
string const& _import,
|
||||||
|
vector<string> const& _cliOptions
|
||||||
|
)
|
||||||
|
{
|
||||||
|
soltestAssert(regex_match(_import, regex{R"(import '[^']*')"}), "");
|
||||||
|
for (string const& option: _cliOptions)
|
||||||
|
soltestAssert(
|
||||||
|
boost::starts_with(option, "--base-path") ||
|
||||||
|
boost::starts_with(option, "--allow-paths") ||
|
||||||
|
!boost::starts_with(option, "--"),
|
||||||
|
""
|
||||||
|
);
|
||||||
|
|
||||||
|
vector<string> commandLine = {
|
||||||
|
"solc",
|
||||||
|
"-",
|
||||||
|
"--no-color",
|
||||||
|
"--error-codes",
|
||||||
|
};
|
||||||
|
commandLine += _cliOptions;
|
||||||
|
|
||||||
|
string standardInputContent =
|
||||||
|
"// SPDX-License-Identifier: GPL-3.0\n"
|
||||||
|
"pragma solidity >=0.0;\n" +
|
||||||
|
_import + ";";
|
||||||
|
|
||||||
|
test::OptionsReaderAndMessages cliResult = test::parseCommandLineAndReadInputFiles(
|
||||||
|
commandLine,
|
||||||
|
standardInputContent,
|
||||||
|
true /* processInput */
|
||||||
|
);
|
||||||
|
if (cliResult.success)
|
||||||
|
return ImportCheck::OK();
|
||||||
|
|
||||||
|
static regex const sourceNotFoundErrorRegex{
|
||||||
|
R"(^Error \(6275\): Source ".+" not found: (.*)\.\n)"
|
||||||
|
R"(\s*--> .*<stdin>:\d+:\d+:\n)"
|
||||||
|
R"(\s*\|\n)"
|
||||||
|
R"(\d+\s*\| import '.+';\n)"
|
||||||
|
R"(\s*\| \^+\n\s*$)"
|
||||||
|
};
|
||||||
|
|
||||||
|
smatch submatches;
|
||||||
|
if (!regex_match(cliResult.stderrContent, submatches, sourceNotFoundErrorRegex))
|
||||||
|
return ImportCheck::Unknown("Unexpected stderr content: '" + cliResult.stderrContent + "'");
|
||||||
|
if (submatches[1] != "File not found" && submatches[1] != "File outside of allowed directories")
|
||||||
|
return ImportCheck::Unknown("Unexpected error message: '" + cliResult.stderrContent + "'");
|
||||||
|
|
||||||
|
if (submatches[1] == "File not found")
|
||||||
|
return ImportCheck::FileNotFound();
|
||||||
|
else if (submatches[1] == "File outside of allowed directories")
|
||||||
|
return ImportCheck::PathDisallowed();
|
||||||
|
else
|
||||||
|
return ImportCheck::Unknown("Unexpected error message '" + submatches[1].str() + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
class AllowPathsFixture
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
AllowPathsFixture():
|
||||||
|
m_tempDir({"code/", "work/"}, TEST_CASE_NAME),
|
||||||
|
m_tempWorkDir(m_tempDir.path() / "work"),
|
||||||
|
m_codeDir(m_tempDir.path() / "code"),
|
||||||
|
m_workDir(m_tempDir.path() / "work"),
|
||||||
|
m_portablePrefix(("/" / boost::filesystem::canonical(m_codeDir).relative_path()).generic_string())
|
||||||
|
{
|
||||||
|
createFilesWithParentDirs(
|
||||||
|
{
|
||||||
|
m_codeDir / "a/b/c/d.sol",
|
||||||
|
m_codeDir / "a/b/c.sol",
|
||||||
|
m_codeDir / "a/b/X.sol",
|
||||||
|
m_codeDir / "a/X/c.sol",
|
||||||
|
m_codeDir / "X/b/c.sol",
|
||||||
|
|
||||||
|
m_codeDir / "a/bc/d.sol",
|
||||||
|
m_codeDir / "X/bc/d.sol",
|
||||||
|
|
||||||
|
m_codeDir / "x/y/z.sol",
|
||||||
|
m_codeDir / "contract.sol",
|
||||||
|
|
||||||
|
m_workDir / "a/b/c/d.sol",
|
||||||
|
m_workDir / "a/b/c.sol",
|
||||||
|
m_workDir / "a/b/X.sol",
|
||||||
|
m_workDir / "a/X/c.sol",
|
||||||
|
m_workDir / "X/b/c.sol",
|
||||||
|
|
||||||
|
m_workDir / "contract.sol",
|
||||||
|
},
|
||||||
|
"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!createSymlinkIfSupportedByFilesystem("b", m_codeDir / "a/b_sym", true) ||
|
||||||
|
!createSymlinkIfSupportedByFilesystem("../x/y", m_codeDir / "a/y_sym", true) ||
|
||||||
|
!createSymlinkIfSupportedByFilesystem("../../a/b/c.sol", m_codeDir / "a/b/c_sym.sol", false) ||
|
||||||
|
!createSymlinkIfSupportedByFilesystem("../../x/y/z.sol", m_codeDir / "a/b/z_sym.sol", false)
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_caseSensitiveFilesystem = boost::filesystem::create_directories(m_codeDir / "A/B/C");
|
||||||
|
soltestAssert(boost::filesystem::equivalent(m_codeDir / "a/b/c", m_codeDir / "A/B/C") != m_caseSensitiveFilesystem, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporaryDirectory m_tempDir;
|
||||||
|
TemporaryWorkingDirectory m_tempWorkDir;
|
||||||
|
boost::filesystem::path const m_codeDir;
|
||||||
|
boost::filesystem::path const m_workDir;
|
||||||
|
string m_portablePrefix;
|
||||||
|
bool m_caseSensitiveFilesystem = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
ostream& operator<<(ostream& _out, ImportCheck const& _value)
|
||||||
|
{
|
||||||
|
switch (_value.result)
|
||||||
|
{
|
||||||
|
case ImportCheck::Result::Unknown: _out << "Unknown"; break;
|
||||||
|
case ImportCheck::Result::OK: _out << "OK"; break;
|
||||||
|
case ImportCheck::Result::FileNotFound: _out << "FileNotFound"; break;
|
||||||
|
case ImportCheck::Result::PathDisallowed: _out << "PathDisallowed"; break;
|
||||||
|
}
|
||||||
|
if (_value.message != "")
|
||||||
|
_out << "(" << _value.message << ")";
|
||||||
|
return _out;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace boost::test_tools::tt_detail
|
||||||
|
{
|
||||||
|
|
||||||
|
// Boost won't find the << operator unless we put it in the std namespace which is illegal.
|
||||||
|
// The recommended solution is to overload print_log_value<> struct and make it use our operator.
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct print_log_value<ImportCheck>
|
||||||
|
{
|
||||||
|
void operator()(std::ostream& _out, ImportCheck const& _value) { ::operator<<(_out, _value); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace boost::test_tools::tt_detail
|
||||||
|
|
||||||
|
namespace solidity::frontend::test
|
||||||
|
{
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(CommandLineInterfaceAllowPathsTest)
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(allow_path_multiple_paths, AllowPathsFixture)
|
||||||
|
{
|
||||||
|
string allowedPaths =
|
||||||
|
m_codeDir.generic_string() + "/a/b/X.sol," +
|
||||||
|
m_codeDir.generic_string() + "/X/," +
|
||||||
|
m_codeDir.generic_string() + "/z," +
|
||||||
|
m_codeDir.generic_string() + "/a/b";
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", allowedPaths}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", allowedPaths}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", allowedPaths}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", allowedPaths}));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(allow_path_should_work_with_various_path_forms, AllowPathsFixture)
|
||||||
|
{
|
||||||
|
string import = "import '" + m_portablePrefix + "/a/b/c.sol'";
|
||||||
|
|
||||||
|
// Without --allow-path
|
||||||
|
BOOST_TEST(checkImport(import, {}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
// Absolute paths allowed
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string()}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/b"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/b/c.sol"}));
|
||||||
|
|
||||||
|
// Relative paths allowed
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths=../code/a"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/b"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/b/c.sol"}));
|
||||||
|
|
||||||
|
// Non-normalized paths allowed
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/."}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/./"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/.."}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/../"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/./b"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/../a/b"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a///b"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b//"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b///"}));
|
||||||
|
|
||||||
|
// Root path allowed
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths=/"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths=///"}));
|
||||||
|
|
||||||
|
// UNC paths should be treated differently from normal paths
|
||||||
|
soltestAssert(FileReader::isUNCPath("/" + m_portablePrefix), "");
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths=//"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths=/" + m_portablePrefix}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
// Paths going beyond root allowed
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths=/../../"}));
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths=/../.."}));
|
||||||
|
#if !defined(_WIN32) || BOOST_VERSION > 107600
|
||||||
|
// This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths=/../../a/../"}));
|
||||||
|
#endif
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths=/../../" + m_portablePrefix}));
|
||||||
|
|
||||||
|
// File named like a directory
|
||||||
|
BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/b/c.sol/"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(allow_path_should_handle_empty_paths, AllowPathsFixture)
|
||||||
|
{
|
||||||
|
// Work dir is base path
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", ""}));
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "x,,y"}));
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", ""}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y"}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
// Work dir is not base path
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"}));
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(allow_path_case_sensitive, AllowPathsFixture)
|
||||||
|
{
|
||||||
|
// Allowed paths are case-sensitive even on case-insensitive filesystems
|
||||||
|
BOOST_TEST(
|
||||||
|
checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", m_codeDir.string() + "/A/B/"}) ==
|
||||||
|
ImportCheck::PathDisallowed()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(allow_path_should_work_with_various_import_forms, AllowPathsFixture)
|
||||||
|
{
|
||||||
|
// Absolute import paths
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b/"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b/"}));
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b"}));
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a"}));
|
||||||
|
|
||||||
|
// Relative import paths
|
||||||
|
// NOTE: Base path is whitelisted by default so we need the 'a/../../code/' part to get
|
||||||
|
// outside of it. And it can't be just '../code/' because that would not be a direct import.
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "../code/a/b"}));
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../code/X/b/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../code/a/X/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../code/a/b/X.sol'", {"--allow-paths", "../code/a/b"}));
|
||||||
|
|
||||||
|
// Non-normalized relative import paths
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../code/a/./b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}));
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../code/a/../a/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}));
|
||||||
|
BOOST_TEST(checkImport("import 'a/../../code/a///b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}));
|
||||||
|
|
||||||
|
// UNC paths in imports
|
||||||
|
string uncImportPath = "/" + m_portablePrefix + "/a/b/c.sol";
|
||||||
|
soltestAssert(FileReader::isUNCPath(uncImportPath), "");
|
||||||
|
BOOST_TEST(checkImport("import '" + uncImportPath + "'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_input_files, AllowPathsFixture)
|
||||||
|
{
|
||||||
|
// By default none of the files is whitelisted
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
// Compiling a file whitelists its directory and subdirectories
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_codeDir.string() + "/a/b/c.sol"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {m_codeDir.string() + "/a/b/c.sol"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {m_codeDir.string() + "/a/b/c.sol"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {m_codeDir.string() + "/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {m_codeDir.string() + "/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {m_codeDir.string() + "/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
// If only file name is specified, its parent dir path is empty. This should be equivalent to
|
||||||
|
// whitelisting the work dir.
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/contract.sol'", {"contract.sol"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import 'contract.sol'", {"contract.sol"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_remappings, AllowPathsFixture)
|
||||||
|
{
|
||||||
|
// Adding a remapping whitelists target's parent directory and subdirectories
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/c.sol"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b/c.sol"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b/c.sol"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=/contract.sol"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=/contract.sol/"}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b=../code/X/b"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b/=../code/X/b/"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {m_portablePrefix + "/a/b=../code/X/b"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {m_portablePrefix + "/a/b/=../code/X/b/"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b:y/z=x/w"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b:y/z=x/w"}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
// Adding a remapping whitelists the target and subdirectories when the target is a directory
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b/"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b/"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/c/"}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
// Adding a remapping whitelists target's parent directory and subdirectories when the target
|
||||||
|
// is a directory but does not have a trailing slash
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/b"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/c"}));
|
||||||
|
|
||||||
|
// Adding a remapping to a relative target at VFS root whitelists the work dir
|
||||||
|
BOOST_TEST(checkImport("import '/../../x/y/z.sol'", {"x=contract.sol", "--base-path=../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '/../../../work/a/b/c.sol'", {"x=contract.sol", "--base-path=../code/a/b/"}));
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '/../../x/y/z.sol'", {"x=contract.sol/", "--base-path=../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '/../../../work/a/b/c.sol'", {"x=contract.sol/", "--base-path=../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
// Adding a remapping with an empty target does not whitelist anything
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "="}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"../code/="}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '/../work/a/b/c.sol'", {"../code/=", "--base-path", m_portablePrefix}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
// Adding a remapping that includes .. or . segments whitelists the parent dir and subdirectories
|
||||||
|
// of the resolved target
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=."}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=."}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=./"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=./"}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=.."}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=.."}));
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../"}));
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./.."}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./.."}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./.."}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./../"}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../b"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../b"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./../b"}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../b/"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../b/"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./../b/"}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
// If the target is just a file name, its parent dir path is empty. This should be equivalent to
|
||||||
|
// whitelisting the work dir.
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/contract.sol'", {"x=contract.sol"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import 'contract.sol'", {"x=contract.sol"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_base_path, AllowPathsFixture)
|
||||||
|
{
|
||||||
|
// Relative base path whitelists its content
|
||||||
|
BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=../code/a"}));
|
||||||
|
BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path=../code/a"}));
|
||||||
|
BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path=../code/a"}));
|
||||||
|
BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path=../code/a"}));
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=../code/a/"}));
|
||||||
|
BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path=../code/a/"}));
|
||||||
|
BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path=../code/a/"}));
|
||||||
|
BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path=../code/a/"}));
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path=../code/."}));
|
||||||
|
BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path=../code/./"}));
|
||||||
|
BOOST_TEST(checkImport("import 'code/a/b/c.sol'", {"--base-path=.."}));
|
||||||
|
BOOST_TEST(checkImport("import 'code/a/b/c.sol'", {"--base-path=../"}));
|
||||||
|
|
||||||
|
// Absolute base path whitelists its content
|
||||||
|
BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path", m_codeDir.string() + "/a"}));
|
||||||
|
BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path", m_codeDir.string() + "/a"}));
|
||||||
|
BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path", m_codeDir.string() + "/a"}));
|
||||||
|
BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path", m_codeDir.string() + "/a"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_work_dir, AllowPathsFixture)
|
||||||
|
{
|
||||||
|
// Work dir is only automatically whitelisted if it matches base path
|
||||||
|
BOOST_TEST(checkImport("import 'b/../../../work/a/b/c.sol'", {"--base-path=../code/a/"}) == ImportCheck::PathDisallowed());
|
||||||
|
|
||||||
|
// Compiling a file in the work dir whitelists it even if it's not in base path
|
||||||
|
BOOST_TEST(checkImport("import 'b/../../../work/a/b/c.sol'", {"--base-path", "../code/a/", "a/b/c.sol"}));
|
||||||
|
|
||||||
|
// Work dir can also be whitelisted manually
|
||||||
|
BOOST_TEST(checkImport("import 'b/../../../work/a/b/c.sol'", {"--base-path", "../code/a/", "--allow-paths=."}));
|
||||||
|
|
||||||
|
// Not setting base path whitelists the working directory
|
||||||
|
BOOST_TEST(checkImport("import 'a/b/c.sol'", {}));
|
||||||
|
BOOST_TEST(checkImport("import 'a/b/c/d.sol'", {}));
|
||||||
|
BOOST_TEST(checkImport("import 'a/b/X.sol'", {}));
|
||||||
|
BOOST_TEST(checkImport("import 'a/X/c.sol'", {}));
|
||||||
|
|
||||||
|
// Setting base path to an empty value whitelists the working directory
|
||||||
|
BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path", ""}));
|
||||||
|
BOOST_TEST(checkImport("import 'a/b/c/d.sol'", {"--base-path", ""}));
|
||||||
|
BOOST_TEST(checkImport("import 'a/b/X.sol'", {"--base-path", ""}));
|
||||||
|
BOOST_TEST(checkImport("import 'a/X/c.sol'", {"--base-path", ""}));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(allow_path_symlinks_within_whitelisted_dir, AllowPathsFixture)
|
||||||
|
{
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b/"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b_sym/"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b_sym/"}));
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b_sym"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b_sym"}));
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c_sym.sol'", {"--allow-paths=../code/a/b/c.sol"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b/c_sym.sol"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c_sym.sol'", {"--allow-paths=../code/a/b/c_sym.sol"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(allow_path_symlinks_outside_whitelisted_dir, AllowPathsFixture)
|
||||||
|
{
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/y_sym/z.sol'", {"--allow-paths=../code/a/"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/y_sym/z.sol'", {"--allow-paths=../code/x/"}));
|
||||||
|
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/a/"}) == ImportCheck::PathDisallowed());
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/x/"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/a/b/z_sym.sol"}));
|
||||||
|
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/x/y/z.sol"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
|
} // namespace solidity::frontend::test
|
@ -168,7 +168,7 @@ BOOST_AUTO_TEST_CASE(cli_mode_options)
|
|||||||
|
|
||||||
expectedOptions.input.addStdin = true;
|
expectedOptions.input.addStdin = true;
|
||||||
expectedOptions.input.basePath = "/home/user/";
|
expectedOptions.input.basePath = "/home/user/";
|
||||||
expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "", "c", "/usr/lib"};
|
expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "c", "/usr/lib"};
|
||||||
expectedOptions.input.ignoreMissingFiles = true;
|
expectedOptions.input.ignoreMissingFiles = true;
|
||||||
expectedOptions.input.errorRecovery = (inputMode == InputMode::Compiler);
|
expectedOptions.input.errorRecovery = (inputMode == InputMode::Compiler);
|
||||||
expectedOptions.output.dir = "/tmp/out";
|
expectedOptions.output.dir = "/tmp/out";
|
||||||
@ -307,7 +307,7 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options)
|
|||||||
};
|
};
|
||||||
expectedOptions.input.addStdin = true;
|
expectedOptions.input.addStdin = true;
|
||||||
expectedOptions.input.basePath = "/home/user/";
|
expectedOptions.input.basePath = "/home/user/";
|
||||||
expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "", "c", "/usr/lib"};
|
expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "c", "/usr/lib"};
|
||||||
expectedOptions.input.ignoreMissingFiles = true;
|
expectedOptions.input.ignoreMissingFiles = true;
|
||||||
expectedOptions.output.overwriteFiles = true;
|
expectedOptions.output.overwriteFiles = true;
|
||||||
expectedOptions.output.evmVersion = EVMVersion::spuriousDragon();
|
expectedOptions.output.evmVersion = EVMVersion::spuriousDragon();
|
||||||
|
@ -54,5 +54,22 @@ test::OptionsReaderAndMessages test::parseCommandLineAndReadInputFiles(
|
|||||||
if (success && _processInput)
|
if (success && _processInput)
|
||||||
success = cli.processInput();
|
success = cli.processInput();
|
||||||
|
|
||||||
return {success, cli.options(), cli.fileReader(), cli.standardJsonInput(), sout.str(), serr.str()};
|
return {
|
||||||
|
success,
|
||||||
|
cli.options(),
|
||||||
|
cli.fileReader(),
|
||||||
|
cli.standardJsonInput(),
|
||||||
|
sout.str(),
|
||||||
|
stripPreReleaseWarning(serr.str()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
string test::stripPreReleaseWarning(string const& _stderrContent)
|
||||||
|
{
|
||||||
|
static regex const preReleaseWarningRegex{
|
||||||
|
R"(Warning( \(3805\))?: This is a pre-release compiler version, please do not use it in production\.\n)"
|
||||||
|
R"((\n)?)"
|
||||||
|
};
|
||||||
|
|
||||||
|
return regex_replace(_stderrContent, preReleaseWarningRegex, "");
|
||||||
}
|
}
|
||||||
|
@ -50,4 +50,6 @@ OptionsReaderAndMessages parseCommandLineAndReadInputFiles(
|
|||||||
bool _processInput = false
|
bool _processInput = false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
std::string stripPreReleaseWarning(std::string const& _stderrContent);
|
||||||
|
|
||||||
} // namespace solidity::frontend::test
|
} // namespace solidity::frontend::test
|
||||||
|
Loading…
Reference in New Issue
Block a user