diff options
author | Jake Petroules <jake.petroules@qt.io> | 2016-04-22 01:20:24 -0700 |
---|---|---|
committer | Ivan Komissarov <ABBAPOH@gmail.com> | 2021-02-18 00:10:00 +0000 |
commit | 2bc823ec00cec8a1d58981710eb50ba85b4f58d7 (patch) | |
tree | 4397fc51e963e00f8ab6dbf7686d5e28cda40c01 /tests/auto/blackbox | |
parent | 05b74ff728e8c6bc975e8c55160e1feb137895a1 (diff) | |
download | qbs-2bc823ec00cec8a1d58981710eb50ba85b4f58d7.tar.gz |
Implement codesign module
This moves code signing functionality into a dedicated module, and also
implements automatic provisioning for Apple platforms, which
automatically selects appropriate signing identities and provisioning
profiles based on the product being built.
This also results in a significant performance improvement since all
code signing setup information is retrieved in process instead of
forking off the openssl and security command line tools.
Task-number: QBS-899
Change-Id: I60d0aeaeb2d1004929505bcb1e0bc77512fe77bc
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Diffstat (limited to 'tests/auto/blackbox')
-rw-r--r-- | tests/auto/blackbox/testdata-apple/codesign/app.cpp | 1 | ||||
-rw-r--r-- | tests/auto/blackbox/testdata-apple/codesign/codesign.qbs | 38 | ||||
-rw-r--r-- | tests/auto/blackbox/tst_blackbox.cpp | 4 | ||||
-rw-r--r-- | tests/auto/blackbox/tst_blackboxapple.cpp | 99 | ||||
-rw-r--r-- | tests/auto/blackbox/tst_blackboxapple.h | 2 | ||||
-rw-r--r-- | tests/auto/blackbox/tst_blackboxbase.h | 9 |
6 files changed, 150 insertions, 3 deletions
diff --git a/tests/auto/blackbox/testdata-apple/codesign/app.cpp b/tests/auto/blackbox/testdata-apple/codesign/app.cpp new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/codesign/app.cpp @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata-apple/codesign/codesign.qbs b/tests/auto/blackbox/testdata-apple/codesign/codesign.qbs new file mode 100644 index 000000000..312e9f001 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/codesign/codesign.qbs @@ -0,0 +1,38 @@ +Project { + name: "p" + + property bool isBundle: true + property bool enableSigning: true + + CppApplication { + name: "A" + bundle.isBundle: project.isBundle + files: "app.cpp" + codesign.enableCodeSigning: project.enableSigning + codesign.signingType: "ad-hoc" + install: true + installDir: "" + } + + DynamicLibrary { + Depends { name: "cpp" } + name: "B" + bundle.isBundle: project.isBundle + files: "app.cpp" + codesign.enableCodeSigning: project.enableSigning + codesign.signingType: "ad-hoc" + install: true + installDir: "" + } + + LoadableModule { + Depends { name: "cpp" } + name: "C" + bundle.isBundle: project.isBundle + files: "app.cpp" + codesign.enableCodeSigning: project.enableSigning + codesign.signingType: "ad-hoc" + install: true + installDir: "" + } +} diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index 20116ff56..2a3c40124 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -2173,7 +2173,7 @@ void TestBlackbox::trackExternalProductChanges() const QStringList toolchainTypes = profileToolchain(profile); if (!toolchainTypes.contains("gcc")) QSKIP("Need GCC-like compiler to run this test"); - params.environment = QProcessEnvironment::systemEnvironment(); + params.environment = QbsRunParameters::defaultEnvironment(); params.environment.insert("INCLUDE_PATH_TEST", "1"); params.expectFailure = true; QVERIFY(runQbs(params) != 0); @@ -6054,7 +6054,7 @@ void TestBlackbox::qbsSession() QJsonObject overriddenValues; overriddenValues.insert("products.theLib.cpp.cxxLanguageVersion", "c++17"); resolveMessage.insert("overridden-properties", overriddenValues); - resolveMessage.insert("environment", envToJson(QProcessEnvironment::systemEnvironment())); + resolveMessage.insert("environment", envToJson(QbsRunParameters::defaultEnvironment())); resolveMessage.insert("data-mode", "only-if-changed"); resolveMessage.insert("log-time", true); resolveMessage.insert("module-properties", diff --git a/tests/auto/blackbox/tst_blackboxapple.cpp b/tests/auto/blackbox/tst_blackboxapple.cpp index adde389ec..8915ac8b2 100644 --- a/tests/auto/blackbox/tst_blackboxapple.cpp +++ b/tests/auto/blackbox/tst_blackboxapple.cpp @@ -140,6 +140,39 @@ static QString findFatLibrary(const QString &dir, const QString &libraryName) return {}; } +enum class CodeSignResult { Failed = 0, Signed, Unsigned }; +using CodeSignData = QMap<QByteArray, QByteArray>; +static std::pair<CodeSignResult, CodeSignData> parseCodeSignOutput(const QByteArray &output) +{ + CodeSignData data; + if (output.contains("code object is not signed at all")) + return {CodeSignResult::Unsigned, data}; + const auto lines = output.split('\n'); + for (const auto &line: lines) { + if (line.isEmpty() + || line.startsWith("CodeDirectory") + || line.startsWith("Sealed Resources") + || line.startsWith("Internal requirements")) { + continue; + } + const int index = line.indexOf('='); + if (index == -1) + return {CodeSignResult::Failed, {}}; + data[line.mid(0, index)] = line.mid(index + 1); + } + return {CodeSignResult::Signed, data}; +} + +static std::pair<CodeSignResult, CodeSignData> getCodeSignInfo(const QString &path) +{ + QProcess codesign; + codesign.start("codesign", { QStringLiteral("-dv"), path }); + if (!codesign.waitForStarted() || !codesign.waitForFinished()) + return {CodeSignResult::Failed, {}}; + const auto output = codesign.readAllStandardError(); + return parseCodeSignOutput(output); +} + TestBlackboxApple::TestBlackboxApple() : TestBlackboxBase (SRCDIR "/testdata-apple", "blackbox-apple") { @@ -680,6 +713,72 @@ void TestBlackboxApple::bundleStructure_data() QTest::newRow("G") << "G" << "com.apple.product-type.in-app-purchase-content"; } +void TestBlackboxApple::codesign() +{ + QFETCH(bool, isBundle); + QFETCH(bool, enableSigning); + + QDir::setCurrent(testDataDir + "/codesign"); + QbsRunParameters params(QStringList{"qbs.installPrefix:''"}); + params.arguments + << QStringLiteral("project.isBundle:%1").arg(isBundle ? "true" : "false"); + params.arguments + << QStringLiteral("project.enableSigning:%1").arg(enableSigning ? "true" : "false"); + + rmDirR(relativeBuildDir()); + QCOMPARE(runQbs(params), 0); + + const auto appName = isBundle ? QStringLiteral("A.app") : QStringLiteral("A"); + const auto appPath = defaultInstallRoot + "/" + appName; + QVERIFY(QFileInfo(appPath).exists()); + auto codeSignInfo = getCodeSignInfo(appPath); + QVERIFY(codeSignInfo.first != CodeSignResult::Failed); + QCOMPARE(codeSignInfo.first == CodeSignResult::Signed, enableSigning); + QCOMPARE(codeSignInfo.second.isEmpty(), !enableSigning); + if (!codeSignInfo.second.isEmpty()) { + QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Executable"))); + QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Identifier"))); + QCOMPARE(codeSignInfo.second.value(QByteArrayLiteral("Signature")), "adhoc"); + } + + const auto libName = isBundle ? QStringLiteral("B.framework") : QStringLiteral("libB.dylib"); + const auto libPath = defaultInstallRoot + "/" + libName; + QVERIFY(QFileInfo(libPath).exists()); + codeSignInfo = getCodeSignInfo(libPath); + QVERIFY(codeSignInfo.first != CodeSignResult::Failed); + QCOMPARE(codeSignInfo.first == CodeSignResult::Signed, enableSigning); + QCOMPARE(codeSignInfo.second.isEmpty(), !enableSigning); + if (!codeSignInfo.second.isEmpty()) { + QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Executable"))); + QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Identifier"))); + QCOMPARE(codeSignInfo.second.value(QByteArrayLiteral("Signature")), "adhoc"); + } + + const auto pluginPath = defaultInstallRoot + "/" + QStringLiteral("C.bundle"); + QVERIFY(QFileInfo(pluginPath).exists()); + QVERIFY(QFileInfo(pluginPath).isDir() == isBundle); + codeSignInfo = getCodeSignInfo(pluginPath); + QVERIFY(codeSignInfo.first != CodeSignResult::Failed); + QCOMPARE(codeSignInfo.first == CodeSignResult::Signed, enableSigning); + QCOMPARE(codeSignInfo.second.isEmpty(), !enableSigning); + if (!codeSignInfo.second.isEmpty()) { + QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Executable"))); + QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Identifier"))); + QCOMPARE(codeSignInfo.second.value(QByteArrayLiteral("Signature")), "adhoc"); + } +} + +void TestBlackboxApple::codesign_data() +{ + QTest::addColumn<bool>("isBundle"); + QTest::addColumn<bool>("enableSigning"); + + QTest::newRow("bundle, unsigned") << true << false; + QTest::newRow("standalone, unsigned") << false << false; + QTest::newRow("bundle, signed") << true << true; + QTest::newRow("standalone, signed") << false << true; +} + void TestBlackboxApple::deploymentTarget() { QFETCH(QString, sdk); diff --git a/tests/auto/blackbox/tst_blackboxapple.h b/tests/auto/blackbox/tst_blackboxapple.h index eeaa28d2f..32eee2432 100644 --- a/tests/auto/blackbox/tst_blackboxapple.h +++ b/tests/auto/blackbox/tst_blackboxapple.h @@ -55,6 +55,8 @@ private slots: void assetCatalogsMultiple(); void bundleStructure(); void bundleStructure_data(); + void codesign(); + void codesign_data(); void deploymentTarget(); void deploymentTarget_data(); void dmg(); diff --git a/tests/auto/blackbox/tst_blackboxbase.h b/tests/auto/blackbox/tst_blackboxbase.h index ed9a233de..d020b7cd9 100644 --- a/tests/auto/blackbox/tst_blackboxbase.h +++ b/tests/auto/blackbox/tst_blackboxbase.h @@ -60,7 +60,14 @@ public: expectCrash = false; profile = profileName(); settingsDir = settings()->baseDirectory(); - environment = QProcessEnvironment::systemEnvironment(); + environment = defaultEnvironment(); + } + + static QProcessEnvironment defaultEnvironment() + { + auto result = QProcessEnvironment::systemEnvironment(); + result.insert(QStringLiteral("QBS_AUTOTEST_CODE_SIGNING_REQUIRED"), QStringLiteral("0")); + return result; } QString command; |