mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
537 lines
28 KiB
C++
537 lines
28 KiB
C++
/*
|
|
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=/../.."}));
|
|
BOOST_TEST(checkImport(import, {"--allow-paths=/../../a/../"}));
|
|
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
|