summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt7
-rw-r--r--hscript/meta.cc34
-rw-r--r--hscript/meta.hh5
-rw-r--r--hscript/script.cc50
-rw-r--r--tests/fixtures/0111-firmware-true.installfile6
-rw-r--r--tests/fixtures/0112-firmware-false.installfile6
-rw-r--r--tests/fixtures/0113-firmware-invalid.installfile7
-rw-r--r--tests/fixtures/0114-firmware-duplicate.installfile7
-rw-r--r--tests/spec/validator.rb33
-rw-r--r--tools/hscript-validate/validator.cc4
10 files changed, 159 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 16f9f58..faf04d2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,6 +15,13 @@ option(BUILD_TOOLS "Enable building of tools (Validator, Simulator, etc)" ON)
option(COVERAGE "Build for code coverage tests (slow)" OFF)
option(VALGRIND "Run Valgrind during test phase" OFF)
+option(FIRMWARE "Support loading and installation of non-libre firmware (DANGEROUS)" OFF)
+mark_as_advanced(FORCE FIRMWARE)
+
+IF(FIRMWARE)
+ add_definitions(-DNON_LIBRE_FIRMWARE)
+ENDIF(FIRMWARE)
+
IF(COVERAGE)
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} --coverage")
SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} --coverage")
diff --git a/hscript/meta.cc b/hscript/meta.cc
index 0248af9..b7da9d2 100644
--- a/hscript/meta.cc
+++ b/hscript/meta.cc
@@ -167,6 +167,40 @@ Key *PkgInstall::parseFromData(const std::string &data, int lineno, int *errors,
}
+Key *Firmware::parseFromData(const std::string &data, int lineno, int *errors,
+ int *warnings) {
+ bool value;
+ if(!BooleanKey::parse(data, "installfile:" + std::to_string(lineno),
+ "firmware", &value)) {
+ if(errors) *errors += 1;
+ return nullptr;
+ }
+
+ if(value) {
+#ifdef NON_LIBRE_FIRMWARE
+ output_warning("installfile:" + std::to_string(lineno),
+ "firmware: You have requested non-libre firmware. "
+ "This may cause security issues, system instability, "
+ "and many other issues. You should not enable this "
+ "option unless your system absolutely requires it.");
+#else
+ if(errors) *errors += 1;
+ output_error("installfile:" + std::to_string(lineno),
+ "firmware: You have requested non-libre firmware, "
+ "but this version of Horizon does not support "
+ "non-libre firmware.", "Installation cannot proceed.");
+ return nullptr;
+#endif
+ }
+ return new Firmware(lineno, value);
+}
+
+bool Firmware::execute(ScriptOptions) const {
+ /* By itself, this does nothing. */
+ return true;
+}
+
+
/* LCOV_EXCL_START */
bool PkgInstall::validate(ScriptOptions) const {
/* Any validation errors would have occurred above. */
diff --git a/hscript/meta.hh b/hscript/meta.hh
index 035bb8a..8a50576 100644
--- a/hscript/meta.hh
+++ b/hscript/meta.hh
@@ -51,6 +51,11 @@ class Keymap : public StringKey {
};
class Firmware : public BooleanKey {
+private:
+ Firmware(int _line, bool _value) : BooleanKey(_line, _value) {}
+public:
+ static Key *parseFromData(const std::string &, int, int*, int*);
+ bool execute(ScriptOptions) const override;
};
class Timezone : public StringKey {
diff --git a/hscript/script.cc b/hscript/script.cc
index 0d1c10a..f9f16f5 100644
--- a/hscript/script.cc
+++ b/hscript/script.cc
@@ -11,6 +11,7 @@
*/
#include <algorithm>
+#include <assert.h>
#include <fstream>
#include <iostream>
#include <map>
@@ -103,6 +104,10 @@ struct Script::ScriptPrivate {
/*! Disk identification keys */
std::vector< std::unique_ptr<DiskId> > diskids;
+#ifdef NON_LIBRE_FIRMWARE
+ std::unique_ptr<Firmware> firmware;
+#endif
+
/*! Store +key_obj+ representing the key +key_name+.
* @param key_name The name of the key that is being stored.
* @param obj The Key object associated with the key.
@@ -120,6 +125,8 @@ struct Script::ScriptPrivate {
return store_pkginstall(obj, lineno, errors, warnings, opts);
} else if(key_name == "rootpw") {
return store_rootpw(obj, lineno, errors, warnings, opts);
+ } else if(key_name == "firmware") {
+ return store_firmware(obj, lineno, errors, warnings, opts);
} else if(key_name == "mount") {
std::unique_ptr<Mount> mount(dynamic_cast<Mount *>(obj));
this->mounts.push_back(std::move(mount));
@@ -217,6 +224,23 @@ struct Script::ScriptPrivate {
return true;
}
+ bool store_firmware(Keys::Key *obj, int lineno, int *errors, int *warnings,
+ ScriptOptions opts) {
+ std::unique_ptr<Firmware> f(dynamic_cast<Firmware *>(obj));
+#ifdef NON_LIBRE_FIRMWARE
+ if(this->firmware) {
+ DUPLICATE_ERROR(this->firmware, std::string("firmware"),
+ (this->firmware->test()) ? "true" : "false")
+ return false;
+ }
+ this->firmware = std::move(f);
+ return true;
+#else
+ assert(!f->test());
+ return true;
+#endif
+ }
+
bool store_username(Keys::Key *obj, int lineno, int *errors, int *warnings,
ScriptOptions opts) {
if(accounts.size() >= 255) {
@@ -532,6 +556,25 @@ bool Script::validate() const {
}
std::unique_ptr<Keys::Repository> user_repo(user_key);
this->internal->repos.push_back(std::move(user_repo));
+
+#ifdef NON_LIBRE_FIRMWARE
+ /* REQ: Runner.Execute.firmware.Repository */
+ if(this->internal->firmware && this->internal->firmware->test()) {
+ Keys::Repository *fw_key = dynamic_cast<Keys::Repository *>(
+ Horizon::Keys::Repository::parseFromData(
+ "https://distfiles.apkfission.net/adelie-stable/nonfree",
+ 0, nullptr, nullptr
+ )
+ );
+ if(!fw_key) {
+ output_error("internal",
+ "failed to create firmware repository");
+ return false;
+ }
+ std::unique_ptr<Keys::Repository> fw_repo(fw_key);
+ this->internal->repos.push_back(std::move(fw_repo));
+ }
+#endif
}
/* REQ: Runner.Validate.repository */
@@ -711,6 +754,13 @@ bool Script::execute() const {
return false;
}
}
+
+#ifdef NON_LIBRE_FIRMWARE
+ /* REQ: Runner.Execute.firmware */
+ if(this->internal->firmware && this->internal->firmware->test()) {
+ this->internal->packages.insert("linux-firmware");
+ }
+#endif
output_step_end("pre-metadata");
/**************** NETWORK ****************/
diff --git a/tests/fixtures/0111-firmware-true.installfile b/tests/fixtures/0111-firmware-true.installfile
new file mode 100644
index 0000000..a2d5ead
--- /dev/null
+++ b/tests/fixtures/0111-firmware-true.installfile
@@ -0,0 +1,6 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+firmware true
diff --git a/tests/fixtures/0112-firmware-false.installfile b/tests/fixtures/0112-firmware-false.installfile
new file mode 100644
index 0000000..9abc556
--- /dev/null
+++ b/tests/fixtures/0112-firmware-false.installfile
@@ -0,0 +1,6 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+firmware false
diff --git a/tests/fixtures/0113-firmware-invalid.installfile b/tests/fixtures/0113-firmware-invalid.installfile
new file mode 100644
index 0000000..b823be1
--- /dev/null
+++ b/tests/fixtures/0113-firmware-invalid.installfile
@@ -0,0 +1,7 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+# Intentional misspelling
+firmware fasle
diff --git a/tests/fixtures/0114-firmware-duplicate.installfile b/tests/fixtures/0114-firmware-duplicate.installfile
new file mode 100644
index 0000000..372c645
--- /dev/null
+++ b/tests/fixtures/0114-firmware-duplicate.installfile
@@ -0,0 +1,7 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+firmware false
+firmware false
diff --git a/tests/spec/validator.rb b/tests/spec/validator.rb
index 023d49e..0a94dbf 100644
--- a/tests/spec/validator.rb
+++ b/tests/spec/validator.rb
@@ -166,6 +166,32 @@ RSpec.describe 'HorizonScript validation', :type => :aruba do
run_validate
expect(last_command_started).to have_output(/error: .*rootpw.*/)
end
+ context "for 'firmware' key" do
+ it "always supports 'false' value" do
+ use_fixture '0112-firmware-false.installfile'
+ run_validate
+ expect(last_command_started).to have_output(PARSER_SUCCESS)
+ expect(last_command_started).to have_output(VALIDATOR_SUCCESS)
+ end
+ it "requires 'false' if built without support" do
+ use_fixture '0111-firmware-true.installfile'
+ run_validate
+ skip "This build supports firmware" if last_command_started.stdout =~ /supports non-free/
+ expect(last_command_started).to have_output(/error: .*firmware/)
+ end
+ it "supports 'true' if built with support" do
+ use_fixture '0111-firmware-true.installfile'
+ run_validate
+ skip "This build does not support firmware" if last_command_started.stdout !~ /supports non-free/
+ expect(last_command_started).to have_output(PARSER_SUCCESS)
+ expect(last_command_started).to have_output(VALIDATOR_SUCCESS)
+ end
+ it "requires a boolean value" do
+ use_fixture '0113-firmware-invalid.installfile'
+ run_validate
+ expect(last_command_started).to have_output(/error: .*firmware.*value/)
+ end
+ end
context "for 'mount' key" do
# Runner.Validate.mount.
it "fails with an invalid value" do
@@ -507,6 +533,13 @@ RSpec.describe 'HorizonScript validation', :type => :aruba do
run_validate
expect(last_command_started).to have_output(/error: .*duplicate.*rootpw/)
end
+ # Runner.Validate.firmware.
+ it "fails with a duplicate 'firmware' key" do
+ use_fixture '0114-firmware-duplicate.installfile'
+ run_validate
+ skip "This build does not support firmware" if last_command_started.stdout !~ /supports non-free/
+ expect(last_command_started).to have_output(/error: .*duplicate.*firmware/)
+ end
end
context "user account keys:" do
context "'username'" do
diff --git a/tools/hscript-validate/validator.cc b/tools/hscript-validate/validator.cc
index 84c3be3..0d9a066 100644
--- a/tools/hscript-validate/validator.cc
+++ b/tools/hscript-validate/validator.cc
@@ -51,6 +51,10 @@ int main(int argc, char *argv[]) {
bold_if_pretty(std::cout);
std::cout << "HorizonScript Validation Utility version 0.1.0";
+#ifdef NON_LIBRE_FIRMWARE
+ colour_if_pretty(std::cout, "31");
+ std::cout << " (supports non-free firmware)";
+#endif
reset_if_pretty(std::cout);
std::cout << std::endl;
std::cout << "Copyright (c) 2019 Adélie Linux and contributors. AGPL-3.0 license." << std::endl;