fix order of rust dependencies and support git sources in Cargo.lock dependencies (#3502)

* fix: un-reverse Cargo.lock dependencies

Previously, dependencyOf was pointing the wrong way. Use dependency
specification helpers to build the dependency graph.

Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com>

* feat: parse Cargo.lock git dependency relationships

Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com>

---------

Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com>
This commit is contained in:
William Murphy 2024-12-06 08:38:36 -05:00 committed by GitHub
parent d3c9ce532d
commit 4adb56d2fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 688 additions and 64 deletions

View File

@ -3,14 +3,17 @@ package rust
import ( import (
"context" "context"
"fmt" "fmt"
"strings"
"github.com/pelletier/go-toml" "github.com/pelletier/go-toml"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/unknown" "github.com/anchore/syft/internal/unknown"
"github.com/anchore/syft/syft/artifact" "github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file" "github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/generic" "github.com/anchore/syft/syft/pkg/cataloger/generic"
"github.com/anchore/syft/syft/pkg/cataloger/internal/dependency"
) )
var _ generic.Parser = parseCargoLock var _ generic.Parser = parseCargoLock
@ -33,7 +36,6 @@ func parseCargoLock(_ context.Context, _ file.Resolver, _ *generic.Environment,
} }
var pkgs []pkg.Package var pkgs []pkg.Package
pkgIndex := make(map[string]int)
for _, p := range m.Packages { for _, p := range m.Packages {
if p.Dependencies == nil { if p.Dependencies == nil {
@ -47,36 +49,42 @@ func parseCargoLock(_ context.Context, _ file.Resolver, _ *generic.Environment,
pkgs, pkgs,
newPkg, newPkg,
) )
newIx := len(pkgs) - 1
// Cargo.lock dependencies are strings that are the name of a package, if that
// is unambiguous, or a string like "name version" if the name alone is not
// ambiguous. Set both keys in the map, since we don't know which key is
// going to be used until we're trying to resolve dependencies. If the
// first key is overwritten, that means the package name was an ambiguous dependency
// and "name version" will be used as the key anyway.
keys := []string{
newPkg.Name,
fmt.Sprintf("%s %s", newPkg.Name, newPkg.Version),
}
for _, k := range keys {
pkgIndex[k] = newIx
}
}
var relationships []artifact.Relationship
for _, p := range pkgs {
meta := p.Metadata.(pkg.RustCargoLockEntry)
for _, d := range meta.Dependencies {
i, ok := pkgIndex[d]
if !ok {
continue
}
relationships = append(relationships, artifact.Relationship{
From: p,
To: pkgs[i],
Type: artifact.DependencyOfRelationship,
})
}
} }
return pkgs, relationships, unknown.IfEmptyf(pkgs, "unable to determine packages") return pkgs, dependency.Resolve(dependencySpecification, pkgs), unknown.IfEmptyf(pkgs, "unable to determine packages")
}
func dependencySpecification(p pkg.Package) dependency.Specification {
rustMeta, ok := p.Metadata.(pkg.RustCargoLockEntry)
if !ok {
log.Tracef("cataloger failed to extract rust Cargo.lock metadata for package %+v", p.Name)
return dependency.Specification{}
}
// Cargo.lock dependencies are strings that are the name of a package, if that
// is unambiguous, or a string like "name version" if the name alone is not
// ambiguous, or strings like "name version (source)" if "name version" is ambiguous.
// Provide all the strings, since we don't know which string will be used.
// In other words, each package "provides" 3 entries, one for each name format,
// and each package "requires" whatever it actually requires based on the Cargo.lock.
provides := []string{
p.Name,
fmt.Sprintf("%s %s", p.Name, p.Version),
}
if rustMeta.Source != "" {
src := rustMeta.Source
if strings.HasPrefix(src, "git") && strings.Contains(src, "#") {
src = strings.Split(src, "#")[0]
}
provides = append(provides, fmt.Sprintf("%s %s (%s)", p.Name, p.Version, src))
}
return dependency.Specification{
ProvidesRequires: dependency.ProvidesRequires{
Provides: provides,
Requires: rustMeta.Dependencies,
},
}
} }

View File

@ -3,6 +3,8 @@ package rust
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/anchore/syft/syft/artifact" "github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file" "github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/pkg"
@ -279,43 +281,43 @@ func TestParseCargoLock(t *testing.T) {
expectedRelationships := []artifact.Relationship{ expectedRelationships := []artifact.Relationship{
{ {
From: ansiTerm, To: ansiTerm,
From: winapi,
Type: artifact.DependencyOfRelationship,
},
{
To: errno,
From: windowsSys52,
Type: artifact.DependencyOfRelationship,
},
{
To: nom,
From: memchr,
Type: artifact.DependencyOfRelationship,
},
{
To: nom,
From: versionCheck,
Type: artifact.DependencyOfRelationship,
},
{
To: schannel,
From: windowsSys59,
Type: artifact.DependencyOfRelationship,
},
{
To: unicodeBidi,
From: matches,
Type: artifact.DependencyOfRelationship,
},
{
To: winapi, To: winapi,
From: winAPIi686PCWindowsGNU,
Type: artifact.DependencyOfRelationship, Type: artifact.DependencyOfRelationship,
}, },
{ {
From: errno, To: winapi,
To: windowsSys52, From: winAPIx8664PCWindowsGNU,
Type: artifact.DependencyOfRelationship,
},
{
From: nom,
To: memchr,
Type: artifact.DependencyOfRelationship,
},
{
From: nom,
To: versionCheck,
Type: artifact.DependencyOfRelationship,
},
{
From: schannel,
To: windowsSys59,
Type: artifact.DependencyOfRelationship,
},
{
From: unicodeBidi,
To: matches,
Type: artifact.DependencyOfRelationship,
},
{
From: winapi,
To: winAPIi686PCWindowsGNU,
Type: artifact.DependencyOfRelationship,
},
{
From: winapi,
To: winAPIx8664PCWindowsGNU,
Type: artifact.DependencyOfRelationship, Type: artifact.DependencyOfRelationship,
}, },
} }
@ -323,6 +325,513 @@ func TestParseCargoLock(t *testing.T) {
pkgtest.TestFileParser(t, fixture, parseCargoLock, expectedPkgs, expectedRelationships) pkgtest.TestFileParser(t, fixture, parseCargoLock, expectedPkgs, expectedRelationships)
} }
func TestCargoLockWithGitDependencies(t *testing.T) {
fixture := "test-fixtures/Cargo.lock-with-git-deps"
locations := file.NewLocationSet(file.NewLocation(fixture))
ahoCorasick := pkg.Package{
Name: "aho-corasick",
Version: "1.1.3",
PURL: "pkg:cargo/aho-corasick@1.1.3",
Locations: locations,
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "aho-corasick",
Version: "1.1.3",
Source: "registry+https://github.com/rust-lang/crates.io-index",
Checksum: "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916",
Dependencies: []string{
"memchr",
},
},
}
helloWorld := pkg.Package{
Name: "hello_world",
Version: "0.1.0",
PURL: "pkg:cargo/hello_world@0.1.0",
Locations: locations,
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "hello_world",
Version: "0.1.0",
Dependencies: []string{
"nom-regex",
"regex 1.11.1 (git+https://github.com/rust-lang/regex.git)",
},
},
}
memchr := pkg.Package{
Name: "memchr",
Version: "2.7.4",
PURL: "pkg:cargo/memchr@2.7.4",
Locations: locations,
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "memchr",
Version: "2.7.4",
Source: "registry+https://github.com/rust-lang/crates.io-index",
Checksum: "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3",
Dependencies: []string{},
},
}
minimalLexical := pkg.Package{
Name: "minimal-lexical",
Version: "0.2.1",
PURL: "pkg:cargo/minimal-lexical@0.2.1",
Locations: locations,
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "minimal-lexical",
Version: "0.2.1",
Source: "registry+https://github.com/rust-lang/crates.io-index",
Checksum: "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a",
Dependencies: []string{},
},
}
nom := pkg.Package{
Name: "nom",
Version: "7.1.3",
PURL: "pkg:cargo/nom@7.1.3",
Locations: locations,
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "nom",
Version: "7.1.3",
Source: "registry+https://github.com/rust-lang/crates.io-index",
Checksum: "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a",
Dependencies: []string{
"memchr",
"minimal-lexical",
},
},
}
nomRegex := pkg.Package{
Name: "nom-regex",
Version: "0.2.0",
PURL: "pkg:cargo/nom-regex@0.2.0",
Locations: locations,
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "nom-regex",
Version: "0.2.0",
Source: "registry+https://github.com/rust-lang/crates.io-index",
Checksum: "72e5c7731c4c1370b61604ed52a2475e861aac9e08dec9f23903d4ddfdc91c18",
Dependencies: []string{
"nom",
"regex 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
},
},
}
regexCrates := pkg.Package{
Name: "regex",
Version: "1.11.1",
PURL: "pkg:cargo/regex@1.11.1",
Locations: locations,
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "regex",
Version: "1.11.1",
Source: "registry+https://github.com/rust-lang/crates.io-index",
Checksum: "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191",
Dependencies: []string{
"aho-corasick",
"memchr",
"regex-automata 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
},
},
}
regexGit := pkg.Package{
Name: "regex",
Version: "1.11.1",
PURL: "pkg:cargo/regex@1.11.1",
Locations: locations,
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "regex",
Version: "1.11.1",
Source: "git+https://github.com/rust-lang/regex.git#1a069b9232c607b34c4937122361aa075ef573fa",
Dependencies: []string{
"aho-corasick",
"memchr",
"regex-automata 0.4.9 (git+https://github.com/rust-lang/regex.git)",
"regex-syntax 0.8.5 (git+https://github.com/rust-lang/regex.git)",
},
},
}
regexAutomataCrates := pkg.Package{
Name: "regex-automata",
Version: "0.4.9",
PURL: "pkg:cargo/regex-automata@0.4.9",
Locations: locations,
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "regex-automata",
Version: "0.4.9",
Source: "registry+https://github.com/rust-lang/crates.io-index",
Checksum: "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908",
Dependencies: []string{
"aho-corasick",
"memchr",
"regex-syntax 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
},
},
}
regexAutomataGit := pkg.Package{
Name: "regex-automata",
Version: "0.4.9",
PURL: "pkg:cargo/regex-automata@0.4.9",
Locations: locations,
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "regex-automata",
Version: "0.4.9",
Source: "git+https://github.com/rust-lang/regex.git#1a069b9232c607b34c4937122361aa075ef573fa",
Dependencies: []string{
"aho-corasick",
"memchr",
"regex-syntax 0.8.5 (git+https://github.com/rust-lang/regex.git)",
},
},
}
regexSyntaxCrates := pkg.Package{
Name: "regex-syntax",
Version: "0.8.5",
PURL: "pkg:cargo/regex-syntax@0.8.5",
Locations: locations,
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "regex-syntax",
Version: "0.8.5",
Source: "registry+https://github.com/rust-lang/crates.io-index",
Checksum: "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c",
Dependencies: []string{},
},
}
regexSyntaxGit := pkg.Package{
Name: "regex-syntax",
Version: "0.8.5",
PURL: "pkg:cargo/regex-syntax@0.8.5",
Locations: locations,
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "regex-syntax",
Version: "0.8.5",
Source: "git+https://github.com/rust-lang/regex.git#1a069b9232c607b34c4937122361aa075ef573fa",
Dependencies: []string{},
},
}
expectedPkgs := []pkg.Package{
ahoCorasick, helloWorld, memchr, minimalLexical, nom, nomRegex, regexCrates, regexGit,
regexAutomataCrates, regexAutomataGit, regexSyntaxCrates, regexSyntaxGit,
}
expectedRelationships := []artifact.Relationship{
{
From: memchr,
To: ahoCorasick,
Type: artifact.DependencyOfRelationship,
},
{
From: nomRegex,
To: helloWorld,
Type: artifact.DependencyOfRelationship,
},
{
From: regexGit,
To: helloWorld,
Type: artifact.DependencyOfRelationship,
},
{
From: memchr,
To: nom,
Type: artifact.DependencyOfRelationship,
},
{
From: minimalLexical,
To: nom,
Type: artifact.DependencyOfRelationship,
},
{
From: nom,
To: nomRegex,
Type: artifact.DependencyOfRelationship,
},
{
From: regexCrates,
To: nomRegex,
Type: artifact.DependencyOfRelationship,
},
{
From: ahoCorasick,
To: regexCrates,
Type: artifact.DependencyOfRelationship,
},
{
From: memchr,
To: regexCrates,
Type: artifact.DependencyOfRelationship,
},
{
From: regexAutomataCrates,
To: regexCrates,
Type: artifact.DependencyOfRelationship,
},
{
From: regexSyntaxCrates,
To: regexCrates,
Type: artifact.DependencyOfRelationship,
},
{
From: regexSyntaxCrates,
To: regexAutomataCrates,
Type: artifact.DependencyOfRelationship,
},
{
From: ahoCorasick,
To: regexGit,
Type: artifact.DependencyOfRelationship,
},
{
From: memchr,
To: regexGit,
Type: artifact.DependencyOfRelationship,
},
{
From: regexAutomataGit,
To: regexGit,
Type: artifact.DependencyOfRelationship,
},
{
From: regexSyntaxGit,
To: regexAutomataGit,
Type: artifact.DependencyOfRelationship,
},
{
From: regexSyntaxGit,
To: regexGit,
Type: artifact.DependencyOfRelationship,
},
{
From: ahoCorasick,
To: regexAutomataCrates,
Type: artifact.DependencyOfRelationship,
},
{
From: memchr,
To: regexAutomataCrates,
Type: artifact.DependencyOfRelationship,
},
{
From: ahoCorasick,
To: regexAutomataGit,
Type: artifact.DependencyOfRelationship,
},
{
From: memchr,
To: regexAutomataGit,
Type: artifact.DependencyOfRelationship,
},
}
// what I know so far - it's not sorting, it's not
pkgtest.TestFileParser(t, fixture, parseCargoLock, expectedPkgs, expectedRelationships)
}
func TestCargoLockDependencySpecification(t *testing.T) {
tests := []struct {
name string
p pkg.Package
provides []string
requires []string
}{
{
name: "requires git source",
p: pkg.Package{
Name: "hello_world",
Version: "0.1.0",
PURL: "pkg:cargo/hello_world@0.1.0",
Locations: file.NewLocationSet(),
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "hello_world",
Version: "0.1.0",
Dependencies: []string{
"nom-regex",
"regex 1.11.1 (git+https://github.com/rust-lang/regex.git)",
},
},
},
provides: []string{
"hello_world",
"hello_world 0.1.0",
},
requires: []string{
"nom-regex",
"regex 1.11.1 (git+https://github.com/rust-lang/regex.git)",
},
},
{
name: "provides git source",
p: pkg.Package{
Name: "regex-automata",
Version: "0.4.9",
PURL: "pkg:cargo/regex-automata@0.4.9",
Locations: file.NewLocationSet(),
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "regex-automata",
Version: "0.4.9",
Source: "git+https://github.com/rust-lang/regex.git#1a069b9232c607b34c4937122361aa075ef573fa",
Dependencies: []string{
"aho-corasick",
"memchr",
"regex-syntax 0.8.5 (git+https://github.com/rust-lang/regex.git)",
},
},
},
provides: []string{
"regex-automata",
"regex-automata 0.4.9",
"regex-automata 0.4.9 (git+https://github.com/rust-lang/regex.git)",
},
requires: []string{
"aho-corasick",
"memchr",
"regex-syntax 0.8.5 (git+https://github.com/rust-lang/regex.git)",
},
},
{
name: "regex-automata git",
p: pkg.Package{
Name: "regex-automata",
Version: "0.4.9",
PURL: "pkg:cargo/regex-automata@0.4.9",
Locations: file.NewLocationSet(),
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "regex-automata",
Version: "0.4.9",
Source: "git+https://github.com/rust-lang/regex.git#1a069b9232c607b34c4937122361aa075ef573fa",
Dependencies: []string{
"aho-corasick",
"memchr",
"regex-syntax 0.8.5 (git+https://github.com/rust-lang/regex.git)",
},
},
},
provides: []string{
"regex-automata",
"regex-automata 0.4.9",
"regex-automata 0.4.9 (git+https://github.com/rust-lang/regex.git)",
},
requires: []string{
"aho-corasick",
"memchr",
"regex-syntax 0.8.5 (git+https://github.com/rust-lang/regex.git)",
},
},
{
name: "regex-syntax git",
p: pkg.Package{
Name: "regex-syntax",
Version: "0.8.5",
PURL: "pkg:cargo/regex-syntax@0.8.5",
Locations: file.NewLocationSet(),
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "regex-syntax",
Version: "0.8.5",
Source: "git+https://github.com/rust-lang/regex.git#1a069b9232c607b34c4937122361aa075ef573fa",
Dependencies: []string{},
},
},
provides: []string{
"regex-syntax",
"regex-syntax 0.8.5",
"regex-syntax 0.8.5 (git+https://github.com/rust-lang/regex.git)",
},
requires: []string{},
},
{
name: "regex-syntax crates",
p: pkg.Package{
Name: "regex-syntax",
Version: "0.8.5",
PURL: "pkg:cargo/regex-syntax@0.8.5",
Locations: file.NewLocationSet(),
Language: pkg.Rust,
Type: pkg.RustPkg,
Licenses: pkg.NewLicenseSet(),
Metadata: pkg.RustCargoLockEntry{
Name: "regex-syntax",
Version: "0.8.5",
Source: "registry+https://github.com/rust-lang/crates.io-index",
Checksum: "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c",
Dependencies: []string{},
},
},
provides: []string{
"regex-syntax",
"regex-syntax 0.8.5",
"regex-syntax 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
},
requires: []string{},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
spec := dependencySpecification(test.p)
assert.Equal(t, test.provides, spec.Provides)
assert.Equal(t, test.requires, spec.Requires)
})
}
}
func Test_corruptCargoLock(t *testing.T) { func Test_corruptCargoLock(t *testing.T) {
pkgtest.NewCatalogTester(). pkgtest.NewCatalogTester().
FromFile(t, "test-fixtures/glob-paths/src/Cargo.lock"). FromFile(t, "test-fixtures/glob-paths/src/Cargo.lock").

View File

@ -0,0 +1,107 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "hello_world"
version = "0.1.0"
dependencies = [
"nom-regex",
"regex 1.11.1 (git+https://github.com/rust-lang/regex.git)",
]
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "nom-regex"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72e5c7731c4c1370b61604ed52a2475e861aac9e08dec9f23903d4ddfdc91c18"
dependencies = [
"nom",
"regex 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "git+https://github.com/rust-lang/regex.git#1a069b9232c607b34c4937122361aa075ef573fa"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata 0.4.9 (git+https://github.com/rust-lang/regex.git)",
"regex-syntax 0.8.5 (git+https://github.com/rust-lang/regex.git)",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "git+https://github.com/rust-lang/regex.git#1a069b9232c607b34c4937122361aa075ef573fa"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.8.5 (git+https://github.com/rust-lang/regex.git)",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "git+https://github.com/rust-lang/regex.git#1a069b9232c607b34c4937122361aa075ef573fa"