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

mendersoftware / mender / 1073264463

15 Nov 2023 10:33AM UTC coverage: 80.186% (+0.1%) from 80.062%
1073264463

push

gitlab-ci

kacf
docs: Restore Update Control XML file for documentation purposes.

This is a partial restore of ee5dc24db79fc57, just to get the XML file
back. The feature is still removed, this is just to be able to keep it
in the documentation with a notice that says it's removed (already
merged to master in 426caf729c3191b).

Signed-off-by: Kristian Amlie <kristian.amlie@northern.tech>

6969 of 8691 relevant lines covered (80.19%)

9260.9 hits per line

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

70.33
/src/artifact/parser.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 <artifact/parser.hpp>
16

17
#include <cstdint>
18
#include <memory>
19
#include <system_error>
20
#include <unordered_map>
21

22
#include <common/json.hpp>
23
#include <common/log.hpp>
24
#include <artifact/tar/tar.hpp>
25
#include <common/common.hpp>
26

27
#include <artifact/lexer.hpp>
28
#include <artifact/tar/tar.hpp>
29
#include <artifact/sha/sha.hpp>
30

31
namespace mender {
32
namespace artifact {
33
namespace parser {
34

35
using namespace std;
36

37
namespace lexer = artifact::lexer;
38
namespace log = mender::common::log;
39
namespace io = mender::common::io;
40
namespace tar = mender::tar;
41
namespace expected = mender::common::expected;
42
namespace error = mender::common::error;
43

44
namespace version = mender::artifact::v3::version;
45
namespace manifest = mender::artifact::v3::manifest;
46
namespace manifest_sig = mender::artifact::v3::manifest_sig;
47
namespace payload = mender::artifact::v3::payload;
48

49
ExpectedArtifact VerifyEmptyPayloadArtifact(
4✔
50
        Artifact &artifact, lexer::Lexer<token::Token, token::Type> &lexer) {
51
        // No meta-data allowed
52
        if (artifact.header.subHeaders.at(0).metadata) {
4✔
53
                return expected::unexpected(parser_error::MakeError(
×
54
                        parser_error::Code::ParseError,
55
                        "Empty payload Artifacts cannot contain a meta-data section"));
×
56
        }
57
        // TODO - When augmented sections are added - check for these also
58
        log::Trace("Empty payload Artifact: Verifying empty payload");
8✔
59
        auto tok = lexer.Next();
4✔
60
        if (tok.type == token::Type::Payload) {
4✔
61
                // If a payload is present, verify that it is empty
62
                auto expected_payload = artifact.Next();
4✔
63
                if (!expected_payload) {
4✔
64
                        auto err = expected_payload.error();
×
65
                        if (err.code.value() != parser_error::Code::NoMorePayloadFilesError) {
×
66
                                return expected::unexpected(parser_error::MakeError(
×
67
                                        parser_error::Code::ParseError,
68
                                        "This should never happen, we have a payload token / programmer error"));
×
69
                        }
70
                        return artifact;
×
71
                }
72
                auto payload = expected_payload.value();
8✔
73
                auto expected_payload_file = payload.Next();
4✔
74
                if (expected_payload_file) {
4✔
75
                        return expected::unexpected(parser_error::MakeError(
×
76
                                parser_error::Code::ParseError, "Empty Payload Artifacts cannot have a payload"));
×
77
                }
78
        }
79
        return artifact;
4✔
80
}
81

82
ExpectedArtifact Parse(io::Reader &reader, config::ParserConfig config) {
137✔
83
        std::shared_ptr<tar::Reader> tar_reader {make_shared<tar::Reader>(reader)};
137✔
84

85
        auto lexer = lexer::Lexer<token::Token, token::Type> {tar_reader};
274✔
86

87
        token::Token tok = lexer.Next();
137✔
88

89
        log::Trace("Parsing Version");
274✔
90
        if (tok.type != token::Type::Version) {
137✔
91
                return expected::unexpected(parser_error::MakeError(
1✔
92
                        parser_error::Code::ParseError,
93
                        "Got unexpected token : '" + tok.TypeToString() + "' expected 'version'"));
3✔
94
        }
95

96
        auto expected_version = version::Parse(*tok.value);
136✔
97

98
        if (!expected_version) {
136✔
99
                return expected::unexpected(parser_error::MakeError(
×
100
                        parser_error::Code::ParseError,
101
                        "Failed to parse the version: " + expected_version.error().message));
×
102
        }
103

104
        auto version = expected_version.value();
136✔
105

106
        log::Trace("Parsing the Manifest");
272✔
107
        tok = lexer.Next();
136✔
108
        if (tok.type != token::Type::Manifest) {
136✔
109
                return expected::unexpected(parser_error::MakeError(
×
110
                        parser_error::Code::ParseError,
111
                        "Got unexpected token " + tok.TypeToString() + " expected 'manifest'"));
×
112
        }
113
        auto expected_manifest = manifest::Parse(*tok.value);
136✔
114
        if (!expected_manifest) {
136✔
115
                return expected::unexpected(parser_error::MakeError(
×
116
                        parser_error::Code::ParseError,
117
                        "Failed to parse the manifest: " + expected_manifest.error().message));
×
118
        }
119
        auto manifest = expected_manifest.value();
272✔
120

121
        tok = lexer.Next();
136✔
122
        optional<ManifestSignature> signature;
136✔
123

124
        // When configured for signed artifacts, refuse installing non signed ones
125
        if (config.artifact_verify_keys.size() > 0 and tok.type != token::Type::ManifestSignature) {
136✔
126
                return expected::unexpected(parser_error::MakeError(
×
127
                        parser_error::Code::SignatureVerificationError,
128
                        "expecting signed artifact, but no signature file found"));
×
129
        }
130

131
        if (tok.type == token::Type::ManifestSignature) {
136✔
132
                auto expected_signature = manifest_sig::Parse(*tok.value);
5✔
133
                if (!expected_signature) {
5✔
134
                        return expected::unexpected(parser_error::MakeError(
×
135
                                parser_error::Code::ParseError,
136
                                "Failed to parse the manifest signature: " + expected_signature.error().message));
×
137
                }
138
                signature = expected_signature.value();
5✔
139
                tok = lexer.Next();
5✔
140

141
                // Verify the signature
142
                if (config.artifact_verify_keys.size() > 0) {
5✔
143
                        auto expected_verified = manifest_sig::VerifySignature(
144
                                *signature, manifest.GetShaSum(), config.artifact_verify_keys);
8✔
145
                        if (!expected_verified) {
4✔
146
                                return expected::unexpected(parser_error::MakeError(
1✔
147
                                        parser_error::Code::SignatureVerificationError,
148
                                        "Failed to verify the manifest signature: "
149
                                                + expected_verified.error().message));
3✔
150
                        }
151
                        if (!expected_verified.value()) {
3✔
152
                                return expected::unexpected(parser_error::MakeError(
×
153
                                        parser_error::Code::SignatureVerificationError,
154
                                        "Wrong manifest signature or wrong key"));
×
155
                        }
156
                }
157
        }
158

159
        log::Trace("Parsing the Header");
270✔
160
        if (tok.type != token::Type::Header) {
135✔
161
                return expected::unexpected(parser_error::MakeError(
×
162
                        parser_error::Code::ParseError,
163
                        "Got unexpected token " + tok.TypeToString() + " expected 'Header'"));
×
164
        }
165
        sha::Reader shasum_reader {*tok.value, manifest.Get("header.tar")};
405✔
166
        auto expected_header = v3::header::Parse(shasum_reader, config);
270✔
167
        if (!expected_header) {
135✔
168
                return expected::unexpected(parser_error::MakeError(
×
169
                        parser_error::Code::ParseError,
170
                        "Failed to parse the header: " + expected_header.error().message));
×
171
        }
172
        auto header = expected_header.value();
270✔
173

174
        // Create the object
175
        auto artifact = Artifact {version, manifest, header, lexer};
405✔
176
        if (signature) {
135✔
177
                artifact.manifest_signature = signature;
178
        }
179

180
        // Check the empty payload structure
181
        if (header.info.payloads.at(0).type == v3::header::Payload::EmptyPayload) {
135✔
182
                auto expected_empty_payload_artifact = VerifyEmptyPayloadArtifact(artifact, lexer);
4✔
183
                if (!expected_empty_payload_artifact) {
4✔
184
                        return expected_empty_payload_artifact;
185
                }
186
                return artifact;
4✔
187
        }
188

189
        log::Trace("Parsing the payload");
262✔
190
        tok = lexer.Next();
131✔
191
        if (tok.type != token::Type::Payload) {
131✔
192
                return expected::unexpected(parser_error::MakeError(
×
193
                        parser_error::Code::ParseError,
194
                        "Got unexpected token " + tok.TypeToString() + " expected 'data/0000.tar"));
×
195
        }
196

197
        return artifact;
131✔
198
};
199

200

201
ExpectedPayload Artifact::Next() {
124✔
202
        // Currently only one payload supported
203
        if (payload_index_ != 0) {
124✔
204
                return expected::unexpected(parser_error::MakeError(
1✔
205
                        parser_error::Code::EOFError, "Reached the end of the Artifact"));
3✔
206
        }
207
        payload_index_++;
123✔
208
        return payload::Payload(*(this->lexer_.current.value), manifest);
123✔
209
}
210

211
} // namespace parser
212
} // namespace artifact
213
} // 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