Skip to content

Commit

Permalink
Add more rust data
Browse files Browse the repository at this point in the history
Signed-off-by: C0D3 M4513R <[email protected]>
  • Loading branch information
C0D3-M4513R committed Jun 11, 2024
1 parent 0956753 commit 18ed8a2
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 6 deletions.
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
github.com/go-git/go-git v1.0.0/go.mod h1:6+421e08gnZWn30y26Vchf7efgYLe4dl5OQbBSUXShE=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
Expand Down
5 changes: 5 additions & 0 deletions syft/format/common/spdxhelpers/to_format_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,11 @@ func toPackageChecksums(p pkg.Package) ([]spdx.Checksum, bool) {
Algorithm: spdx.ChecksumAlgorithm(algo),
Value: hexStr,
})
case pkg.RustCargoLockEntry:
checksums = append(checksums, spdx.Checksum{
Algorithm: meta.GetChecksumType(),
Value: meta.Checksum,
})
}
return checksums, filesAnalyzed
}
Expand Down
13 changes: 12 additions & 1 deletion syft/format/internal/spdxutil/helpers/download_location.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package helpers

import "github.com/anchore/syft/syft/pkg"
import (
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/pkg"
)

const NONE = "NONE"
const NOASSERTION = "NOASSERTION"
Expand All @@ -22,6 +25,14 @@ func DownloadLocation(p pkg.Package) string {
return NoneIfEmpty(metadata.URL)
case pkg.NpmPackageLockEntry:
return NoneIfEmpty(metadata.Resolved)
case pkg.RustCargoLockEntry:
var url, err = metadata.GetDownloadLink()
if err != nil {
log.Info(err)
return NONE
} else {
return NoneIfEmpty(url)
}
}
}
return NOASSERTION
Expand Down
2 changes: 2 additions & 0 deletions syft/pkg/cataloger/rust/parse_cargo_lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
var _ generic.Parser = parseCargoLock

type cargoLockFile struct {
Version int `toml:"version"`
Packages []pkg.RustCargoLockEntry `toml:"package"`
}

Expand All @@ -34,6 +35,7 @@ func parseCargoLock(_ context.Context, _ file.Resolver, _ *generic.Environment,
var pkgs []pkg.Package

for _, p := range m.Packages {
p.CargoLockVersion = m.Version
if p.Dependencies == nil {
p.Dependencies = make([]string, 0)
}
Expand Down
238 changes: 233 additions & 5 deletions syft/pkg/rust.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,243 @@
package pkg

import (
"encoding/json"
"fmt"
"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/storage/memory"
"github.com/spdx/tools-golang/spdx"
"strings"
)

type RustCargoLockEntry struct {
Name string `toml:"name" json:"name"`
Version string `toml:"version" json:"version"`
Source string `toml:"source" json:"source"`
Checksum string `toml:"checksum" json:"checksum"`
Dependencies []string `toml:"dependencies" json:"dependencies"`
CargoLockVersion int `toml:"-" json:"-"`
Name string `toml:"name" json:"name"`
Version string `toml:"version" json:"version"`
Source string `toml:"source" json:"source"`
Checksum string `toml:"checksum" json:"checksum"`
Dependencies []string `toml:"dependencies" json:"dependencies"`
}

type RustBinaryAuditEntry struct {
Name string `toml:"name" json:"name"`
Version string `toml:"version" json:"version"`
Source string `toml:"source" json:"source"`
}

type RustRepositoryConfig struct {
Download string `json:"dl"`
API string `json:"api"`
AuthRequired bool `json:"auth-required"`
}

type SourceId struct {
kind string
url string
}

type DependencyInformation struct {
}

// see https://github.com/rust-lang/cargo/blob/master/crates/cargo-util-schemas/src/core/source_kind.rs
const (
SourceKindPath = "path"
SourceKindGit = "git"
SourceKindRegistry = "registry"
SourceKindLocalRegistry = "local-registry"
SourceKindSparse = "sparse"
SourceKindLocalDirectory = "directory"
)

var RegistryRepos = make(map[string]*memory.Storage)
var RegistryConfig = make(map[string]RustRepositoryConfig)

// GetChecksumType This exists, to made adopting new potential cargo.lock versions easier
func (r *RustCargoLockEntry) GetChecksumType() spdx.ChecksumAlgorithm {
//Cargo currently always uses Sha256: https://github.com/rust-lang/cargo/blob/a9ee3e82b57df019dfc0385f844bc6928150ee63/src/cargo/sources/registry/download.rs#L125
return spdx.SHA256
}

func (r *RustCargoLockEntry) getSourceId() (*SourceId, error) {
var before, after, found = strings.Cut(r.Source, "+")
if !found {
return nil, fmt.Errorf("did not find \"+\" in source field of dependency: Name: %s, Version: %s, Source: %s", r.Name, r.Version, r.Source)
}

return &SourceId{
kind: before,
url: after,
}, nil
}

// GetPrefix get {path} for https://doc.rust-lang.org/cargo/reference/registry-index.html
func (r *RustCargoLockEntry) GetPrefix() string {
switch len(r.Name) {
case 0:
return ""
case 1:
return fmt.Sprintf("1/%s", r.Name[0:1])
case 2:
return fmt.Sprintf("2/%s", r.Name[0:2])
case 3:
return fmt.Sprintf("3/%s", r.Name[0:1])
default:
return fmt.Sprintf("%s/%s", r.Name[0:2], r.Name[2:4])
}
}

func (r *RustCargoLockEntry) GetDownloadLink() (string, error) {
var sourceId, err = r.getSourceId()
if err != nil {
return "", err
}
var repoConfig *RustRepositoryConfig = nil
repoConfig, err = sourceId.GetConfig()
if err != nil {
return "", err
}
return r.getDownloadLink(repoConfig.Download), err
}

func (r *RustCargoLockEntry) getDownloadLink(url string) string {
const Crate = "{crate}"
const Version = "{version}"
const Prefix = "{prefix}"
const LowerPrefix = "{lowerprefix}"
const Sha256Checksum = "{sha256-checksum}"
if !strings.Contains(url, Crate) &&
!strings.Contains(url, Version) &&
!strings.Contains(url, Prefix) &&
!strings.Contains(url, LowerPrefix) &&
!strings.Contains(url, Sha256Checksum) {
return url + fmt.Sprintf("/%s/%s/download", r.Name, r.Version)
}

var link = url
link = strings.ReplaceAll(link, Crate, r.Name)
link = strings.ReplaceAll(link, Version, r.Version)
link = strings.ReplaceAll(link, Prefix, r.GetPrefix())
link = strings.ReplaceAll(link, LowerPrefix, strings.ToLower(r.GetPrefix()))
link = strings.ReplaceAll(link, Sha256Checksum, r.Checksum)
return link
}
func (r *RustCargoLockEntry) getIndexPath() string {
return fmt.Sprintf("%s/%s", strings.ToLower(r.GetPrefix()), strings.ToLower(r.Name))
}

// RepositoryConfigName see https://github.com/rust-lang/cargo/blob/b134eff5cedcaa4879f60035d62630400e7fd543/src/cargo/sources/registry/mod.rs#L962
const RepositoryConfigName = "config.json"

func (i *SourceId) GetConfig() (*RustRepositoryConfig, error) {
if repoConfig, ok := RegistryConfig[i.url]; ok {
return &repoConfig, nil
}
content, err := i.GetPath(RepositoryConfigName)
if err != nil {
return nil, err
}
var repoConfig = RustRepositoryConfig{}
err = json.Unmarshal([]byte(content), &repoConfig)
RegistryConfig[i.url] = repoConfig
return &repoConfig, err
}

func (i *SourceId) GetPath(path string) (string, error) {
switch i.kind {
case SourceKindRegistry:
var content = ""
var tree, err = getTree(i.url)
if err != nil {
return content, err
}
var file *object.File = nil
file, err = tree.File(path)
if err != nil {
return content, err
}
content, err = file.Contents()
return content, err
}
return "", fmt.Errorf("unsupported Remote")
}

func getOrInitRepo(url string) (*memory.Storage, *git.Repository, error) {
var repo *git.Repository = nil
var err error = nil

var storage, ok = RegistryRepos[url]
//Todo: Should we use an on-disk storage?
if !ok {
storage = memory.NewStorage()
RegistryRepos[url] = storage
repo, err = git.Init(storage, memfs.New())
if err != nil {
return storage, nil, err
}
err = updateRepo(repo, url)
} else {
repo, err = git.Open(storage, memfs.New())
}
return storage, repo, err
}

func updateRepo(repo *git.Repository, url string) error {
//Todo: cargo re-initialises the repo, if the fetch fails. Do we need to copy that?
//see https://github.com/rust-lang/cargo/blob/b134eff5cedcaa4879f60035d62630400e7fd543/src/cargo/sources/git/utils.rs#L1150
var remote, err = repo.CreateRemoteAnonymous(&config.RemoteConfig{
Name: "anonymous",
URLs: []string{url},
Mirror: false,
//see https://github.com/rust-lang/cargo/blob/b134eff5cedcaa4879f60035d62630400e7fd543/src/cargo/sources/git/utils.rs#L979
Fetch: []config.RefSpec{"+HEAD:refs/remotes/origin/HEAD"},
})
if err != nil {
return err
}
err = remote.Fetch(&git.FetchOptions{
RemoteName: "origin",
Depth: 1,
//Todo: support private repos by allowing auth information to be specified
Auth: nil,
Progress: nil,
Tags: git.NoTags,
Force: false,
InsecureSkipTLS: false,
CABundle: nil,
ProxyOptions: transport.ProxyOptions{},
Prune: false,
})
return err
}

func getTree(url string) (*object.Tree, error) {
var _, repo, err = getOrInitRepo(url)
if err != nil {
return nil, err
}

var ref *plumbing.Reference = nil
ref, err = repo.Reference("refs/remotes/origin/HEAD", true)
if err != nil {
return nil, fmt.Errorf("failed to get reference to refs/remotes/origin/HEAD: %s", err)
}

var hash = ref.Hash()
var commit *object.Commit = nil
commit, err = repo.CommitObject(hash)
if err != nil {
return nil, fmt.Errorf("failed to get commit from repo head: %s", err)
}

var tree *object.Tree = nil
tree, err = commit.Tree()
if err != nil {
return nil, fmt.Errorf("failed to get Tree from Commit: %s", err)
}

return tree, err
}

0 comments on commit 18ed8a2

Please sign in to comment.