Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
parser.go 1.56 KiB
package sbom

import (
	"context"
	"fmt"
	"os"
	"path"
	"path/filepath"

	"dmd.tanna.dev/internal/domain"
	"dmd.tanna.dev/internal/tracing"
	"go.opentelemetry.io/otel"
	semconv "go.opentelemetry.io/otel/semconv/v1.25.0"
	"go.opentelemetry.io/otel/trace"
)

var tracer = otel.Tracer("dmd.tanna.dev/internal/datasources/sbom")

type Parser struct{}

func NewParser() Parser {
	return Parser{}
}

func (Parser) ParseFile(ctx context.Context, filename string, componentNameOverride *string, repoKey *domain.RepoKey) ([]domain.SBOMDependency, []domain.License, string, error) {
	attr := semconv.FileName(filepath.Base(filename))

	if path, err := filepath.Abs(filename); err == nil {
		attr = semconv.FilePath(path)
	}

	ctx, span := tracer.Start(ctx, "Parsing an SBOM", trace.WithAttributes(
		tracing.AttributeKeyDMDDatasource.String("sbom"),
		attr,
	))
	defer span.End()

	body, err := os.ReadFile(filename)
	if err != nil {
		return nil, nil, "", fmt.Errorf("failed to open %s: %w", filename, err)
	}

	format, found := Identify(body)
	if !found {
		return nil, nil, "", fmt.Errorf("the SBOM format provided isn't supported at this time, please raise an issue!")
	}

	span.SetAttributes(tracing.AttributeKeyDMDSBOMFormat.String(format.Name()))

	var componentName string
	if componentNameOverride != nil {
		componentName = *componentNameOverride
	} else {
		componentName = format.ComponentName(body)
		if componentName == "" {
			// TODO log
			componentName = path.Base(filename)
		}
	}

	deps, licenses := format.Parse(body, componentName, repoKey)
	return deps, licenses, componentName, nil
}