| 89 | } |
| 90 | |
| 91 | func (i *CSAFCrafter) Craft(ctx context.Context, filepath string) (*api.Attestation_Material, error) { |
| 92 | i.logger.Debug().Str("path", filepath).Msg("decoding CSAF file") |
| 93 | f, err := os.ReadFile(filepath) |
| 94 | if err != nil { |
| 95 | return nil, fmt.Errorf("can't open the file: %w - %w", err, ErrInvalidMaterialType) |
| 96 | } |
| 97 | |
| 98 | var v interface{} |
| 99 | if err := json.Unmarshal(f, &v); err != nil { |
| 100 | i.logger.Debug().Err(err).Msg("error decoding file") |
| 101 | return nil, fmt.Errorf("invalid CSAF file: %w", ErrInvalidMaterialType) |
| 102 | } |
| 103 | |
| 104 | // Validate the CSAF file against the specified category. |
| 105 | // First check that the content is a map with a `document` root |
| 106 | doc, ok := v.(map[string]interface{}) |
| 107 | if !ok { |
| 108 | return nil, fmt.Errorf("invalid CSAF file: %w", ErrInvalidMaterialType) |
| 109 | } |
| 110 | |
| 111 | // Map its content |
| 112 | documentMap, ok := doc["document"].(map[string]interface{}) |
| 113 | if !ok { |
| 114 | return nil, fmt.Errorf("invalid CSAF file: %w", ErrInvalidMaterialType) |
| 115 | } |
| 116 | |
| 117 | // extract category: not mandatory but if it comes we check it |
| 118 | category, categoryExists := documentMap["category"].(string) |
| 119 | if categoryExists && category != "" && category != i.category { |
| 120 | return nil, fmt.Errorf("invalid CSAF category field in file, expected: %v", i.category) |
| 121 | } |
| 122 | |
| 123 | // The validator will try in cascade the different schemas since CSAF specification |
| 124 | // is a strict schema. |
| 125 | err = schemavalidators.ValidateCSAF(v) |
| 126 | if err != nil { |
| 127 | i.logger.Debug().Err(err).Msgf("error decoding file: %#v", err) |
| 128 | |
| 129 | return nil, fmt.Errorf("invalid CSAF file: %w", ErrInvalidMaterialType) |
| 130 | } |
| 131 | |
| 132 | m, err := uploadAndCraft(ctx, i.input, i.backend, filepath, i.logger) |
| 133 | if err != nil { |
| 134 | return nil, err |
| 135 | } |
| 136 | |
| 137 | i.injectAnnotations(m, documentMap) |
| 138 | |
| 139 | return m, nil |
| 140 | } |
| 141 | |
| 142 | func (i *CSAFCrafter) injectAnnotations(m *api.Attestation_Material, documentMap map[string]any) { |
| 143 | m.Annotations = make(map[string]string) |