Add a CSAR validator for model ETSI SOL001 2.5.1
[sdc.git] / openecomp-be / backend / openecomp-sdc-vendor-software-product-manager / src / main / java / org / openecomp / sdc / vendorsoftwareproduct / impl / orchestration / csar / validation / SOL004MetaDirectoryValidator.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019 Nordix Foundation.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  *  * Modifications copyright (c) 2020 Nokia
20  * ================================================================================
21  */
22 package org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation;
23
24 import static org.openecomp.sdc.be.config.NonManoArtifactType.ONAP_CNF_HELM;
25 import static org.openecomp.sdc.be.config.NonManoArtifactType.ONAP_PM_DICTIONARY;
26 import static org.openecomp.sdc.be.config.NonManoArtifactType.ONAP_SW_INFORMATION;
27 import static org.openecomp.sdc.be.config.NonManoArtifactType.ONAP_VES_EVENTS;
28 import static org.openecomp.sdc.tosca.csar.CSARConstants.CSAR_VERSION_1_0;
29 import static org.openecomp.sdc.tosca.csar.CSARConstants.CSAR_VERSION_1_1;
30 import static org.openecomp.sdc.tosca.csar.CSARConstants.MANIFEST_METADATA_LIMIT;
31 import static org.openecomp.sdc.tosca.csar.CSARConstants.MANIFEST_PNF_METADATA;
32 import static org.openecomp.sdc.tosca.csar.CSARConstants.MANIFEST_VNF_METADATA;
33 import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_MANIFEST_FILE_EXT;
34 import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_TYPE_PNF;
35 import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_TYPE_VNF;
36 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion261.CREATED_BY_ENTRY;
37 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion261.CSAR_VERSION_ENTRY;
38 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion261.ENTRY_DEFINITIONS;
39 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion261.ETSI_ENTRY_CERTIFICATE;
40 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion261.ETSI_ENTRY_MANIFEST;
41 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion261.TOSCA_META_FILE_VERSION_ENTRY;
42 import static org.openecomp.sdc.tosca.csar.ToscaMetadataFileInfo.TOSCA_META_FILE_VERSION_1_0;
43 import static org.openecomp.sdc.tosca.csar.ToscaMetadataFileInfo.TOSCA_META_PATH_FILE_NAME;
44
45 import com.google.common.collect.ImmutableSet;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.nio.file.Path;
49 import java.util.ArrayList;
50 import java.util.HashSet;
51 import java.util.List;
52 import java.util.Map;
53 import java.util.Optional;
54 import java.util.Set;
55 import java.util.concurrent.CopyOnWriteArrayList;
56 import java.util.stream.Collectors;
57 import java.util.stream.Stream;
58 import lombok.Getter;
59 import org.apache.commons.collections.CollectionUtils;
60 import org.apache.commons.io.FilenameUtils;
61 import org.openecomp.core.impl.ToscaDefinitionImportHandler;
62 import org.openecomp.core.utilities.file.FileContentHandler;
63 import org.openecomp.sdc.be.config.NonManoArtifactType;
64 import org.openecomp.sdc.be.csar.pnf.PnfSoftwareInformation;
65 import org.openecomp.sdc.be.csar.pnf.SoftwareInformationArtifactYamlParser;
66 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
67 import org.openecomp.sdc.common.errors.Messages;
68 import org.openecomp.sdc.datatypes.error.ErrorLevel;
69 import org.openecomp.sdc.datatypes.error.ErrorMessage;
70 import org.openecomp.sdc.logging.api.Logger;
71 import org.openecomp.sdc.logging.api.LoggerFactory;
72 import org.openecomp.sdc.tosca.csar.Manifest;
73 import org.openecomp.sdc.tosca.csar.OnboardingToscaMetadata;
74 import org.openecomp.sdc.tosca.csar.SOL004ManifestOnboarding;
75 import org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion261;
76 import org.openecomp.sdc.tosca.csar.ToscaMetadata;
77 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.OnboardingPackageContentHandler;
78 import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation.exception.MissingCertificateException;
79 import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation.utils.FileExtractor;
80 import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation.utils.InternalFilesFilter;
81 import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation.utils.ValidatorUtils;
82 import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.exceptions.InvalidManifestMetadataException;
83 import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManager;
84 import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManagerException;
85 import org.yaml.snakeyaml.Yaml;
86
87 /**
88  * Validates the contents of the package to ensure it complies with the "CSAR with TOSCA-Metadata directory" structure as defined in ETSI GS NFV-SOL
89  * 004 v2.6.1.
90  */
91 public class SOL004MetaDirectoryValidator implements Validator {
92
93     private static final Logger LOGGER = LoggerFactory.getLogger(SOL004MetaDirectoryValidator.class);
94     private static final String MANIFEST_SOURCE = "Source";
95     private static final String MANIFEST_NON_MANO_SOURCE = "Non-MANO Source";
96     protected final ValidatorUtils validatorUtils = new ValidatorUtils();
97     private final List<ErrorMessage> errorsByFile = new CopyOnWriteArrayList<>();
98     private final SecurityManager securityManager;
99     private final InternalFilesFilter internalFilesFilter = new InternalFilesFilter();
100     private OnboardingPackageContentHandler contentHandler;
101     private Set<String> folderList;
102     @Getter
103     private ToscaMetadata toscaMetadata;
104
105     public SOL004MetaDirectoryValidator() {
106         securityManager = SecurityManager.getInstance();
107     }
108
109     //for tests purpose
110     SOL004MetaDirectoryValidator(final SecurityManager securityManager) {
111         this.securityManager = securityManager;
112     }
113
114     @Override
115     public ValidationResult validate(final FileContentHandler csarContent) {
116         this.contentHandler = (OnboardingPackageContentHandler) csarContent;
117         this.folderList = contentHandler.getFolderList();
118         parseToscaMetadata();
119         verifyMetadataFile();
120         if (packageHasCertificate()) {
121             verifySignedFiles();
122         }
123         validatePmDictionaryContentsAgainstSchema();
124         final var csarValidationResult = new CsarValidationResult();
125         errorsByFile.forEach(csarValidationResult::addError);
126         return csarValidationResult;
127     }
128
129     @Override
130     public boolean appliesTo(final String model) {
131         return model == null;
132     }
133
134     @Override
135     public int getOrder() {
136         return 0;
137     }
138
139     protected boolean packageHasCertificate() {
140         final String certificatePath = getCertificatePath().orElse(null);
141         return contentHandler.containsFile(certificatePath);
142     }
143
144     protected Optional<String> getCertificatePath() {
145         return toscaMetadata.getEntry(ETSI_ENTRY_CERTIFICATE);
146     }
147
148     /**
149      * Parses the {@link org.openecomp.sdc.tosca.csar.ToscaMetadataFileInfo#TOSCA_META_PATH_FILE_NAME} file
150      */
151     protected void parseToscaMetadata() {
152         try {
153             toscaMetadata = OnboardingToscaMetadata.parseToscaMetadataFile(contentHandler.getFileContentAsStream(TOSCA_META_PATH_FILE_NAME));
154         } catch (final IOException e) {
155             reportError(ErrorLevel.ERROR, Messages.METADATA_PARSER_INTERNAL.getErrorMessage());
156             LOGGER.error(Messages.METADATA_PARSER_INTERNAL.getErrorMessage(), e.getMessage(), e);
157         }
158     }
159
160     protected void verifyMetadataFile() {
161         if (toscaMetadata.isValid() && hasETSIMetadata()) {
162             verifyManifestNameAndExtension();
163             handleMetadataEntries();
164         } else {
165             errorsByFile.addAll(toscaMetadata.getErrors());
166         }
167     }
168
169     protected void verifySignedFiles() {
170         final Map<String, String> signedFileMap = contentHandler.getFileAndSignaturePathMap(SecurityManager.ALLOWED_SIGNATURE_EXTENSIONS);
171         final String packageCertificatePath = getCertificatePath().orElse(null);
172         final byte[] packageCert = contentHandler.getFileContent(packageCertificatePath);
173         if (packageCert == null) {
174             throw new MissingCertificateException("Expected package certificate");
175         }
176         signedFileMap.entrySet().stream().filter(entry -> entry.getValue() != null).forEach(entry -> {
177             final String filePath = entry.getKey();
178             final String fileSignaturePath = entry.getValue();
179             final byte[] fileBytes = contentHandler.getFileContent(filePath);
180             final byte[] fileSignatureBytes = contentHandler.getFileContent(fileSignaturePath);
181             try {
182                 if (!securityManager.verifySignedData(fileSignatureBytes, packageCert, fileBytes)) {
183                     reportError(ErrorLevel.ERROR, Messages.ARTIFACT_INVALID_SIGNATURE.formatMessage(fileSignaturePath, filePath));
184                 }
185             } catch (final SecurityManagerException e) {
186                 final String errorMessage = Messages.ARTIFACT_SIGNATURE_VALIDATION_ERROR
187                     .formatMessage(fileSignaturePath, filePath, packageCertificatePath, e.getMessage());
188                 reportError(ErrorLevel.ERROR, errorMessage);
189                 LOGGER.error(errorMessage, e);
190             }
191         });
192     }
193
194     protected void verifyManifestNameAndExtension() {
195         final Map<String, String> entries = toscaMetadata.getMetaEntries();
196         final String manifestFileName = getFileName(entries.get(ETSI_ENTRY_MANIFEST.getName()));
197         final String manifestExtension = getFileExtension(entries.get(ETSI_ENTRY_MANIFEST.getName()));
198         final String mainDefinitionFileName = getFileName(entries.get(ENTRY_DEFINITIONS.getName()));
199         if (!(TOSCA_MANIFEST_FILE_EXT).equals(manifestExtension)) {
200             reportError(ErrorLevel.ERROR, Messages.MANIFEST_INVALID_EXT.getErrorMessage());
201         }
202         if (!mainDefinitionFileName.equals(manifestFileName)) {
203             reportError(ErrorLevel.ERROR, String.format(Messages.MANIFEST_INVALID_NAME.getErrorMessage(), manifestFileName, mainDefinitionFileName));
204         }
205     }
206
207     protected String getFileExtension(final String filePath) {
208         return FilenameUtils.getExtension(filePath);
209     }
210
211     protected String getFileName(final String filePath) {
212         return FilenameUtils.getBaseName(filePath);
213     }
214
215     private boolean hasETSIMetadata() {
216         final Map<String, String> entries = toscaMetadata.getMetaEntries();
217         return hasEntry(entries, TOSCA_META_FILE_VERSION_ENTRY.getName()) && hasEntry(entries, CSAR_VERSION_ENTRY.getName()) && hasEntry(entries,
218             CREATED_BY_ENTRY.getName());
219     }
220
221     private boolean hasEntry(final Map<String, String> entries, final String mandatoryEntry) {
222         if (!entries.containsKey(mandatoryEntry)) {
223             reportError(ErrorLevel.ERROR, String.format(Messages.METADATA_MISSING_ENTRY.getErrorMessage(), mandatoryEntry));
224             return false;
225         }
226         return true;
227     }
228
229     private void handleMetadataEntries() {
230         toscaMetadata.getMetaEntries().entrySet().parallelStream().forEach(this::handleEntry);
231     }
232
233     protected void handleEntry(final Map.Entry<String, String> entry) {
234         final String key = entry.getKey();
235         final var toscaMetaEntry = ToscaMetaEntryVersion261.parse(entry.getKey()).orElse(null);
236         // allows any other unknown entry
237         if (toscaMetaEntry == null) {
238             return;
239         }
240         final String value = entry.getValue();
241         switch (toscaMetaEntry) {
242             case TOSCA_META_FILE_VERSION_ENTRY:
243             case CSAR_VERSION_ENTRY:
244             case CREATED_BY_ENTRY:
245                 verifyMetadataEntryVersions(key, value);
246                 break;
247             case ENTRY_DEFINITIONS:
248                 validateDefinitionFile(value);
249                 break;
250             case ETSI_ENTRY_MANIFEST:
251                 validateManifestFile(value);
252                 break;
253             case ETSI_ENTRY_CHANGE_LOG:
254                 validateChangeLog(value);
255                 break;
256             case ETSI_ENTRY_TESTS:
257             case ETSI_ENTRY_LICENSES:
258                 validateOtherEntries(entry);
259                 break;
260             case ETSI_ENTRY_CERTIFICATE:
261                 validateCertificate(value);
262                 break;
263             default:
264                 handleOtherEntry(entry);
265                 break;
266         }
267     }
268
269     protected void validateOtherEntries(final Map.Entry<String, String> entry) {
270         final String manifestFile = getManifestFilePath();
271         if (verifyFileExists(contentHandler.getFileList(), manifestFile)) {
272             final Manifest onboardingManifest = new SOL004ManifestOnboarding();
273             onboardingManifest.parse(contentHandler.getFileContentAsStream(manifestFile));
274             final Optional<ResourceTypeEnum> resourceType = onboardingManifest.getType();
275             if (resourceType.isPresent() && resourceType.get() == ResourceTypeEnum.VF) {
276                 final String value = entry.getValue();
277                 validateOtherEntries(value);
278             } else {
279                 final String key = entry.getKey();
280                 reportError(ErrorLevel.ERROR, String.format(Messages.MANIFEST_INVALID_PNF_METADATA.getErrorMessage(), key));
281             }
282         }
283     }
284
285     protected String getManifestFilePath() {
286         return toscaMetadata.getMetaEntries().get(ETSI_ENTRY_MANIFEST.getName());
287     }
288
289     protected void verifyMetadataEntryVersions(final String key, final String version) {
290         if (!(isValidTOSCAVersion(key, version) || isValidCSARVersion(key, version) || CREATED_BY_ENTRY.getName().equals(key))) {
291             errorsByFile.add(new ErrorMessage(ErrorLevel.ERROR, String.format(Messages.METADATA_INVALID_VERSION.getErrorMessage(), key, version)));
292             LOGGER.error("{}: key {} - value {} ", Messages.METADATA_INVALID_VERSION.getErrorMessage(), key, version);
293         }
294     }
295
296     private boolean isValidTOSCAVersion(final String key, final String version) {
297         return TOSCA_META_FILE_VERSION_ENTRY.getName().equals(key) && TOSCA_META_FILE_VERSION_1_0.equals(version);
298     }
299
300     private boolean isValidCSARVersion(final String value, final String version) {
301         return CSAR_VERSION_ENTRY.getName().equals(value) && (CSAR_VERSION_1_1.equals(version) || CSAR_VERSION_1_0.equals(version));
302     }
303
304     protected void validateDefinitionFile(final String filePath) {
305         final Set<String> existingFiles = contentHandler.getFileList();
306         if (verifyFileExists(existingFiles, filePath)) {
307             final var toscaDefinitionImportHandler = new ToscaDefinitionImportHandler(contentHandler.getFiles(), filePath);
308             final List<ErrorMessage> validationErrorList = toscaDefinitionImportHandler.getErrors();
309             if (CollectionUtils.isNotEmpty(validationErrorList)) {
310                 errorsByFile.addAll(validationErrorList);
311             }
312         } else {
313             reportError(ErrorLevel.ERROR, String.format(Messages.MISSING_DEFINITION_FILE.getErrorMessage(), filePath));
314         }
315     }
316
317     private boolean verifyFileExists(final Set<String> existingFiles, final String filePath) {
318         return existingFiles.contains(filePath);
319     }
320
321     protected void validateManifestFile(final String filePath) {
322         final Set<String> existingFiles = contentHandler.getFileList();
323         if (verifyFileExists(existingFiles, filePath)) {
324             final Manifest onboardingManifest = new SOL004ManifestOnboarding();
325             onboardingManifest.parse(contentHandler.getFileContentAsStream(filePath));
326             if (onboardingManifest.isValid()) {
327                 try {
328                     verifyManifestMetadata(onboardingManifest.getMetadata());
329                 } catch (final InvalidManifestMetadataException e) {
330                     reportError(ErrorLevel.ERROR, e.getMessage());
331                     LOGGER.error(e.getMessage(), e);
332                 }
333                 verifyManifestSources(onboardingManifest);
334             } else {
335                 final List<String> manifestErrors = onboardingManifest.getErrors();
336                 manifestErrors.forEach(error -> reportError(ErrorLevel.ERROR, error));
337             }
338         } else {
339             reportError(ErrorLevel.ERROR, String.format(Messages.MANIFEST_NOT_FOUND.getErrorMessage(), filePath));
340         }
341     }
342
343     private void verifyManifestMetadata(final Map<String, String> metadata) {
344         if (!validMetaLimit(metadata)) {
345             reportError(ErrorLevel.ERROR, String.format(Messages.MANIFEST_METADATA_DOES_NOT_MATCH_LIMIT.getErrorMessage(), MANIFEST_METADATA_LIMIT));
346         }
347         handleMetadataEntries(metadata);
348     }
349
350     protected boolean isPnfMetadata(final Map<String, String> metadata) {
351         final String firstMetadataDefinition = metadata.keySet().iterator().next();
352         final String expectedMetadataType = firstMetadataDefinition.contains(TOSCA_TYPE_PNF) ? TOSCA_TYPE_PNF : TOSCA_TYPE_VNF;
353         if (metadata.keySet().stream().anyMatch((final String metadataEntry) -> !metadataEntry.contains(expectedMetadataType))) {
354             throw new InvalidManifestMetadataException(Messages.MANIFEST_METADATA_INVALID_ENTRY.getErrorMessage());
355         }
356         return TOSCA_TYPE_PNF.equals(expectedMetadataType);
357     }
358
359     private void handleMetadataEntries(final Map<String, String> metadata) {
360         getManifestMetadata(metadata).stream().filter(requiredEntry -> !metadata.containsKey(requiredEntry)).forEach(
361             requiredEntry -> reportError(ErrorLevel.ERROR, String.format(Messages.MANIFEST_METADATA_MISSING_ENTRY.getErrorMessage(), requiredEntry)));
362     }
363
364     /**
365      * Checks if all manifest sources exists within the package and if all package files are being referred.
366      *
367      * @param onboardingManifest The manifest
368      */
369     private void verifyManifestSources(final Manifest onboardingManifest) {
370         final Set<String> packageFiles = contentHandler.getFileList();
371         final List<String> sources = internalFilesFilter.filter(onboardingManifest.getSources());
372         verifyFilesExist(packageFiles, sources, MANIFEST_SOURCE);
373         final Map<String, List<String>> nonManoArtifacts = onboardingManifest.getNonManoSources();
374         final List<String> nonManoValidFilePaths = new ArrayList<>();
375         nonManoArtifacts.forEach((nonManoType, files) -> {
376             final List<String> internalNonManoFileList = internalFilesFilter.filter(files);
377             nonManoValidFilePaths.addAll(internalNonManoFileList);
378             final var nonManoArtifactType = NonManoArtifactType.parse(nonManoType).orElse(null);
379             if (nonManoArtifactType == ONAP_PM_DICTIONARY || nonManoArtifactType == ONAP_VES_EVENTS) {
380                 internalNonManoFileList.forEach(this::validateYaml);
381             } else if (nonManoArtifactType == ONAP_SW_INFORMATION) {
382                 validateSoftwareInformationNonManoArtifact(files);
383             } else if (nonManoArtifactType == ONAP_CNF_HELM) {
384                 validateOnapCnfHelmNonManoEntry(files);
385             }
386         });
387         verifyFilesExist(packageFiles, nonManoValidFilePaths, MANIFEST_NON_MANO_SOURCE);
388         final Set<String> allReferredFiles = new HashSet<>();
389         allReferredFiles.addAll(sources);
390         allReferredFiles.addAll(nonManoValidFilePaths);
391         verifyFilesBeingReferred(allReferredFiles, packageFiles);
392     }
393
394     private void validateSoftwareInformationNonManoArtifact(final List<String> files) {
395         if (CollectionUtils.isEmpty(files)) {
396             reportError(ErrorLevel.ERROR, Messages.EMPTY_SW_INFORMATION_NON_MANO_ERROR.getErrorMessage());
397             return;
398         }
399         if (files.size() != 1) {
400             final String formattedFileList = files.stream().map(filePath -> String.format("'%s'", filePath)).collect(Collectors.joining(", "));
401             reportError(ErrorLevel.ERROR, Messages.UNIQUE_SW_INFORMATION_NON_MANO_ERROR.formatMessage(formattedFileList));
402             return;
403         }
404         final String swInformationFilePath = files.get(0);
405         final byte[] swInformationYaml = contentHandler.getFileContent(swInformationFilePath);
406         final Optional<PnfSoftwareInformation> parsedYaml = SoftwareInformationArtifactYamlParser.parse(swInformationYaml);
407         if (parsedYaml.isEmpty()) {
408             reportError(ErrorLevel.ERROR, Messages.INVALID_SW_INFORMATION_NON_MANO_ERROR.formatMessage(swInformationFilePath));
409         } else {
410             final var pnfSoftwareInformation = parsedYaml.get();
411             if (!pnfSoftwareInformation.isValid()) {
412                 reportError(ErrorLevel.ERROR, Messages.INCORRECT_SW_INFORMATION_NON_MANO_ERROR.formatMessage(swInformationFilePath));
413             }
414         }
415     }
416
417     /**
418      * Validates if a YAML file has the correct extension, is not empty and the content is a valid YAML. Reports each error found.
419      *
420      * @param filePath the file path inside the package
421      */
422     private void validateYaml(final String filePath) {
423         if (!contentHandler.containsFile(filePath)) {
424             return;
425         }
426         final String fileExtension = getFileExtension(filePath);
427         if (!"yaml".equalsIgnoreCase(fileExtension) && !"yml".equalsIgnoreCase(fileExtension)) {
428             reportError(ErrorLevel.ERROR, Messages.INVALID_YAML_EXTENSION.formatMessage(filePath));
429             return;
430         }
431         try (final InputStream fileContent = contentHandler.getFileContentAsStream(filePath)) {
432             if (fileContent == null) {
433                 reportError(ErrorLevel.ERROR, Messages.EMPTY_YAML_FILE_1.formatMessage(filePath));
434                 return;
435             }
436             new Yaml().loadAll(fileContent).iterator().next();
437         } catch (final IOException e) {
438             final String errorMsg = Messages.FILE_LOAD_CONTENT_ERROR.formatMessage(filePath);
439             reportError(ErrorLevel.ERROR, errorMsg);
440             LOGGER.debug(errorMsg, e);
441         } catch (final Exception e) {
442             final String message = Messages.INVALID_YAML_FORMAT_1.formatMessage(filePath, e.getMessage());
443             LOGGER.debug(message, e);
444             reportError(ErrorLevel.ERROR, message);
445         }
446     }
447
448     /**
449      * Checks if all package files are referred in manifest. Reports missing references.
450      *
451      * @param referredFileSet the list of referred files path
452      * @param packageFileSet  the list of package file path
453      */
454     private void verifyFilesBeingReferred(final Set<String> referredFileSet, final Set<String> packageFileSet) {
455         packageFileSet.forEach(filePath -> {
456             if (!isManifestFile(filePath) && !referredFileSet.contains(filePath)) {
457                 reportError(ErrorLevel.ERROR, String.format(Messages.MISSING_MANIFEST_REFERENCE.getErrorMessage(), filePath));
458             }
459         });
460     }
461
462     private boolean isManifestFile(final String filePath) {
463         return filePath.equals(getManifestFilePath());
464     }
465
466     private void validateOtherEntries(final String folderPath) {
467         if (!verifyFoldersExist(folderList, folderPath)) {
468             reportError(ErrorLevel.ERROR, String.format(Messages.METADATA_MISSING_OPTIONAL_FOLDERS.getErrorMessage(), folderPath));
469         }
470     }
471
472     protected void validateCertificate(final String file) {
473         final Set<String> packageFiles = contentHandler.getFileList();
474         if (!verifyFileExist(packageFiles, file)) {
475             reportError(ErrorLevel.ERROR, String.format(Messages.MISSING_METADATA_FILES.getErrorMessage(), file, file));
476         }
477     }
478
479     private boolean verifyFoldersExist(final Set<String> folderList, final String folderPath) {
480         final var folderPath1 = Path.of(folderPath);
481         return folderList.stream().map(Path::of).anyMatch(path -> path.equals(folderPath1));
482     }
483
484     private void verifyFilesExist(final Set<String> existingFiles, final List<String> sources, final String type) {
485         sources.forEach(file -> {
486             if (!existingFiles.contains(file)) {
487                 reportError(ErrorLevel.ERROR, String.format(Messages.MISSING_MANIFEST_SOURCE.getErrorMessage(), type, file));
488             }
489         });
490     }
491
492     private boolean verifyFileExist(final Set<String> existingFiles, final String file) {
493         return existingFiles.contains(file);
494     }
495
496     protected void validateChangeLog(final String filePath) {
497         if (!verifyFileExists(contentHandler.getFileList(), filePath)) {
498             reportError(ErrorLevel.ERROR, String.format(Messages.MISSING_METADATA_FILES.getErrorMessage(), filePath));
499         }
500     }
501
502     protected void reportError(final ErrorLevel errorLevel, final String errorMessage) {
503         errorsByFile.add(new ErrorMessage(errorLevel, errorMessage));
504     }
505
506     protected boolean validMetaLimit(Map<String, String> metadata) {
507         return metadata.size() == MANIFEST_METADATA_LIMIT;
508     }
509
510     protected ImmutableSet<String> getManifestMetadata(final Map<String, String> metadata) {
511         return isPnfMetadata(metadata) ? MANIFEST_PNF_METADATA : MANIFEST_VNF_METADATA;
512     }
513
514     protected void handleOtherEntry(final Map.Entry<String, String> entry) {
515         reportError(ErrorLevel.ERROR, Messages.METADATA_UNSUPPORTED_ENTRY.formatMessage(entry.getKey()));
516         LOGGER.warn(Messages.METADATA_UNSUPPORTED_ENTRY.getErrorMessage(), entry.getKey());
517     }
518
519     private void validatePmDictionaryContentsAgainstSchema() {
520         final Stream<byte[]> pmDictionaryFiles = new FileExtractor(getEtsiEntryManifestPath(), contentHandler).findFiles(ONAP_PM_DICTIONARY);
521         new PMDictionaryValidator().validate(pmDictionaryFiles, (String message) -> reportError(ErrorLevel.ERROR, message));
522     }
523
524     private String getEtsiEntryManifestPath() {
525         return getManifestFilePath();
526     }
527
528     /**
529      * Validates if onap_cnf_helm non_mano type points to a file
530      *
531      * @param files
532      */
533     private void validateOnapCnfHelmNonManoEntry(final List<String> files) {
534         if (CollectionUtils.isEmpty(files)) {
535             reportError(ErrorLevel.ERROR, Messages.EMPTY_ONAP_CNF_HELM_NON_MANO_ERROR.getErrorMessage());
536             return;
537         }
538         if (files.size() != 1) {
539             final String formattedFileList = files.stream().map(filePath -> String.format("'%s'", filePath)).collect(Collectors.joining(", "));
540             reportError(ErrorLevel.ERROR, Messages.UNIQUE_ONAP_CNF_HELM_NON_MANO_ERROR.formatMessage(formattedFileList));
541         }
542     }
543
544 }