• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender / 1047260214

24 Oct 2023 08:50AM UTC coverage: 80.226% (-0.1%) from 80.34%
1047260214

push

gitlab-ci

oleorhagen
test(artifact): Add signature verification of the test artifact for RSA

Signed-off-by: Ole Petter <ole.orhagen@northern.tech>

6873 of 8567 relevant lines covered (80.23%)

9388.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.14
/common/conf/conf.cpp
1
// Copyright 2023 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
#include <common/conf.hpp>
16

17
#include <string>
18
#include <cstdlib>
19
#include <cerrno>
20

21
#include <mender-version.h>
22

23
#include <common/error.hpp>
24
#include <common/expected.hpp>
25
#include <common/log.hpp>
26
#include <common/json.hpp>
27

28
namespace mender {
29
namespace common {
30
namespace conf {
31

32
using namespace std;
33
namespace error = mender::common::error;
34
namespace expected = mender::common::expected;
35
namespace log = mender::common::log;
36
namespace json = mender::common::json;
37

38
const string kMenderVersion = MENDER_VERSION;
39

40
const ConfigErrorCategoryClass ConfigErrorCategory;
41

42
const char *ConfigErrorCategoryClass::name() const noexcept {
×
43
        return "ConfigErrorCategory";
×
44
}
45

46
string ConfigErrorCategoryClass::message(int code) const {
10✔
47
        switch (code) {
10✔
48
        case NoError:
49
                return "Success";
×
50
        case InvalidOptionsError:
51
                return "Invalid options given";
10✔
52
        }
53
        assert(false);
54
        return "Unknown";
×
55
}
56

57
error::Error MakeError(ConfigErrorCode code, const string &msg) {
5✔
58
        return error::Error(error_condition(code, ConfigErrorCategory), msg);
66✔
59
}
60

61

62
string GetEnv(const string &var_name, const string &default_value) {
1,873✔
63
        const char *value = getenv(var_name.c_str());
1,873✔
64
        if (value == nullptr) {
1,873✔
65
                return string(default_value);
1,872✔
66
        } else {
67
                return string(value);
1✔
68
        }
69
}
70

71
ExpectedOptionValue CmdlineOptionsIterator::Next() {
501✔
72
        string option = "";
501✔
73
        string value = "";
501✔
74

75
        if (start_ + pos_ >= end_) {
501✔
76
                return ExpectedOptionValue({"", ""});
160✔
77
        }
78

79
        if (past_double_dash_) {
341✔
80
                OptionValue opt_val {"", start_[pos_]};
6✔
81
                pos_++;
3✔
82
                return ExpectedOptionValue(opt_val);
3✔
83
        }
84

85
        if (start_[pos_] == "--") {
338✔
86
                past_double_dash_ = true;
1✔
87
                pos_++;
1✔
88
                return ExpectedOptionValue({"--", ""});
1✔
89
        }
90

91
        if (start_[pos_][0] == '-') {
337✔
92
                auto eq_idx = start_[pos_].find('=');
133✔
93
                if (eq_idx != string::npos) {
133✔
94
                        option = start_[pos_].substr(0, eq_idx);
3✔
95
                        value = start_[pos_].substr(eq_idx + 1, start_[pos_].size() - eq_idx - 1);
3✔
96
                        pos_++;
3✔
97
                } else {
98
                        option = start_[pos_];
130✔
99
                        pos_++;
130✔
100
                }
101

102
                if (opts_with_value_.count(option) != 0) {
133✔
103
                        // option with value
104
                        if ((value == "") && ((start_ + pos_ >= end_) || (start_[pos_][0] == '-'))) {
111✔
105
                                // the next item is not a value
106
                                error::Error err = MakeError(
107
                                        ConfigErrorCode::InvalidOptionsError, "Option " + option + " missing value");
4✔
108
                                return ExpectedOptionValue(expected::unexpected(err));
4✔
109
                        } else if (value == "") {
109✔
110
                                // only assign the next item as value if there was no value
111
                                // specified as '--opt=value' (parsed above)
112
                                value = start_[pos_];
107✔
113
                                pos_++;
107✔
114
                        }
115
                } else if (opts_wo_value_.count(option) == 0) {
22✔
116
                        // unknown option
117
                        error::Error err = MakeError(
118
                                ConfigErrorCode::InvalidOptionsError, "Unrecognized option '" + option + "'");
16✔
119
                        return ExpectedOptionValue(expected::unexpected(err));
16✔
120
                } else if (value != "") {
14✔
121
                        // option without a value, yet, there was a value specified as '--opt=value' (parsed
122
                        // above)
123
                        error::Error err = MakeError(
124
                                ConfigErrorCode::InvalidOptionsError,
125
                                "Option " + option + " doesn't expect a value");
2✔
126
                        return ExpectedOptionValue(expected::unexpected(err));
2✔
127
                }
128
        } else {
129
                switch (mode_) {
204✔
130
                case ArgumentsMode::AcceptBareArguments:
50✔
131
                        value = start_[pos_];
132
                        pos_++;
50✔
133
                        break;
50✔
134
                case ArgumentsMode::RejectBareArguments:
50✔
135
                        return expected::unexpected(MakeError(
50✔
136
                                ConfigErrorCode::InvalidOptionsError,
137
                                "Unexpected argument '" + start_[pos_] + "'"));
150✔
138
                case ArgumentsMode::StopAtBareArguments:
139
                        return ExpectedOptionValue({"", ""});
104✔
140
                }
141
        }
142

143
        return ExpectedOptionValue({std::move(option), std::move(value)});
172✔
144
}
145

146
expected::ExpectedSize MenderConfig::ProcessCmdlineArgs(
119✔
147
        vector<string>::const_iterator start, vector<string>::const_iterator end, const CliApp &app) {
148
        bool explicit_config_path = false;
149
        bool explicit_fallback_config_path = false;
150
        string log_file = "";
119✔
151
        string log_level;
152
        string trusted_cert;
153
        bool skip_verify_arg = false;
154
        bool version_arg = false;
155
        bool help_arg = false;
156

157
        CmdlineOptionsIterator opts_iter(
158
                start, end, GlobalOptsSetWithValue(), GlobalOptsSetWithoutValue());
357✔
159
        opts_iter.SetArgumentsMode(ArgumentsMode::StopAtBareArguments);
160
        auto ex_opt_val = opts_iter.Next();
119✔
161
        int arg_count = 0;
162
        while (ex_opt_val && ((ex_opt_val.value().option != "") || (ex_opt_val.value().value != ""))) {
225✔
163
                arg_count++;
110✔
164
                auto opt_val = ex_opt_val.value();
110✔
165
                if ((opt_val.option == "--config") || (opt_val.option == "-c")) {
110✔
166
                        paths.SetConfFile(opt_val.value);
167
                        explicit_config_path = true;
168
                } else if ((opt_val.option == "--fallback-config") || (opt_val.option == "-b")) {
107✔
169
                        paths.SetFallbackConfFile(opt_val.value);
170
                        explicit_fallback_config_path = true;
171
                } else if ((opt_val.option == "--data") || (opt_val.option == "-d")) {
107✔
172
                        paths.SetDataStore(opt_val.value);
97✔
173
                } else if ((opt_val.option == "--log-file") || (opt_val.option == "-L")) {
10✔
174
                        log_file = opt_val.value;
175
                } else if ((opt_val.option == "--log-level") || (opt_val.option == "-l")) {
10✔
176
                        log_level = opt_val.value;
177
                } else if ((opt_val.option == "--trusted-certs") || (opt_val.option == "-E")) {
8✔
178
                        trusted_cert = opt_val.value;
179
                } else if (opt_val.option == "--skipverify") {
8✔
180
                        skip_verify_arg = true;
181
                } else if ((opt_val.option == "--version") || (opt_val.option == "-v")) {
8✔
182
                        version_arg = true;
183
                } else if ((opt_val.option == "--help") || (opt_val.option == "-h")) {
4✔
184
                        help_arg = true;
185
                        break;
4✔
186
                } else {
187
                        assert(false);
188
                }
189
                ex_opt_val = opts_iter.Next();
212✔
190
        }
191
        if (!ex_opt_val) {
119✔
192
                return expected::unexpected(ex_opt_val.error());
×
193
        }
194

195
        if (version_arg) {
119✔
196
                if (arg_count > 1 || opts_iter.GetPos() < static_cast<size_t>(end - start)) {
4✔
197
                        return expected::unexpected(error::Error(
2✔
198
                                make_error_condition(errc::invalid_argument),
4✔
199
                                "--version can not be combined with other commands and arguments"));
6✔
200
                } else {
201
                        cout << kMenderVersion << endl;
2✔
202
                        return expected::unexpected(error::MakeError(error::ExitWithSuccessError, ""));
6✔
203
                }
204
        }
205

206
        if (help_arg) {
115✔
207
                PrintCliHelp(app);
4✔
208
                return expected::unexpected(error::MakeError(error::ExitWithSuccessError, ""));
12✔
209
        }
210

211
        if (log_file != "") {
111✔
212
                auto err = log::SetupFileLogging(log_file, true);
×
213
                if (error::NoError != err) {
×
214
                        return expected::unexpected(err);
×
215
                }
216
        }
217

218
        SetLevel(log::kDefaultLogLevel);
111✔
219

220
        if (log_level != "") {
111✔
221
                auto ex_log_level = log::StringToLogLevel(log_level);
2✔
222
                if (!ex_log_level) {
2✔
223
                        return expected::unexpected(ex_log_level.error());
×
224
                }
225
                SetLevel(ex_log_level.value());
2✔
226
        }
227

228
        auto err = LoadConfigFile_(paths.GetConfFile(), explicit_config_path);
111✔
229
        if (error::NoError != err) {
111✔
230
                this->Reset();
×
231
                return expected::unexpected(err);
×
232
        }
233

234
        err = LoadConfigFile_(paths.GetFallbackConfFile(), explicit_fallback_config_path);
222✔
235
        if (error::NoError != err) {
111✔
236
                this->Reset();
×
237
                return expected::unexpected(err);
×
238
        }
239

240
        if (this->update_log_path != "") {
111✔
241
                paths.SetUpdateLogPath(this->update_log_path);
242
        }
243

244
        if (log_level == "" && this->daemon_log_level != "") {
111✔
245
                auto ex_log_level = log::StringToLogLevel(this->daemon_log_level);
1✔
246
                if (!ex_log_level) {
1✔
247
                        return expected::unexpected(ex_log_level.error());
×
248
                }
249
                SetLevel(ex_log_level.value());
1✔
250
        }
251

252
        if (trusted_cert != "") {
111✔
253
                this->server_certificate = trusted_cert;
×
254
        }
255

256
        if (skip_verify_arg) {
111✔
257
                this->skip_verify = true;
×
258
        }
259

260
        http_client_config_.server_cert_path = server_certificate;
111✔
261
        http_client_config_.client_cert_path = https_client.certificate;
111✔
262
        http_client_config_.client_cert_key_path = https_client.key;
111✔
263
        http_client_config_.skip_verify = skip_verify;
111✔
264

265
        auto proxy = http::GetHttpProxyStringFromEnvironment();
111✔
266
        if (proxy) {
111✔
267
                http_client_config_.http_proxy = proxy.value();
110✔
268
        } else {
269
                return expected::unexpected(proxy.error());
2✔
270
        }
271

272
        proxy = http::GetHttpsProxyStringFromEnvironment();
220✔
273
        if (proxy) {
110✔
274
                http_client_config_.https_proxy = proxy.value();
109✔
275
        } else {
276
                return expected::unexpected(proxy.error());
2✔
277
        }
278

279
        proxy = http::GetNoProxyStringFromEnvironment();
218✔
280
        if (proxy) {
109✔
281
                http_client_config_.no_proxy = proxy.value();
108✔
282
        } else {
283
                return expected::unexpected(proxy.error());
2✔
284
        }
285

286
        return opts_iter.GetPos();
287
}
288

289
error::Error MenderConfig::LoadConfigFile_(const string &path, bool required) {
222✔
290
        auto ret = this->LoadFile(path);
222✔
291
        if (!ret) {
222✔
292
                if (required) {
219✔
293
                        // any failure when a file is required (e.g. path was given explicitly) means an error
294
                        log::Error("Failed to load config from '" + path + "': " + ret.error().message);
×
295
                        return ret.error();
×
296
                } else if (ret.error().IsErrno(ENOENT)) {
219✔
297
                        // File doesn't exist, OK for non-required
298
                        log::Debug("Failed to load config from '" + path + "': " + ret.error().message);
438✔
299
                        return error::NoError;
219✔
300
                } else {
301
                        // other errors (parsing errors,...) for default paths should produce warnings
302
                        log::Warning("Failed to load config from '" + path + "': " + ret.error().message);
×
303
                        return error::NoError;
×
304
                }
305
        }
306
        // else
307
        auto valid = this->ValidateConfig();
3✔
308
        if (!valid) {
3✔
309
                // validation error is always an error
310
                log::Error("Failed to validate config from '" + path + "': " + valid.error().message);
×
311
                return valid.error();
×
312
        }
313

314
        return error::NoError;
3✔
315
}
316

317
} // namespace conf
318
} // namespace common
319
} // namespace mender
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc