From 25835ef58921fa3cf5d1ec13b3f087e04cb77b39 Mon Sep 17 00:00:00 2001 From: Nikita <33390074+Zilborg@users.noreply.github.com> Date: Wed, 10 Nov 2021 22:08:41 +0300 Subject: [PATCH] PHP parser composer.lock (#609) * PHP parse composer.lock Signed-off-by: Nikita <33390074+Zilborg@users.noreply.github.com> * rename PHP package type Signed-off-by: Alex Goodman * add PHP composer package support to source info SPDX helper Signed-off-by: Alex Goodman * update directory cataloger integration tests (make exception for images) Signed-off-by: Alex Goodman Co-authored-by: Alex Goodman --- .../formats/common/spdxhelpers/source_info.go | 2 + .../common/spdxhelpers/source_info_test.go | 8 + syft/pkg/cataloger/cataloger.go | 2 + syft/pkg/cataloger/php/index_cataloger.go | 17 + syft/pkg/cataloger/php/parse_composer_lock.go | 50 +++ .../cataloger/php/parse_composer_lock_test.go | 40 +++ .../cataloger/php/test-fixtures/composer.lock | 298 ++++++++++++++++++ syft/pkg/language.go | 2 + syft/pkg/type.go | 4 + .../catalog_packages_cases_test.go | 9 + test/integration/catalog_packages_test.go | 8 +- .../image-pkg-coverage/composer/composer.lock | 298 ++++++++++++++++++ 12 files changed, 736 insertions(+), 2 deletions(-) create mode 100644 syft/pkg/cataloger/php/index_cataloger.go create mode 100644 syft/pkg/cataloger/php/parse_composer_lock.go create mode 100644 syft/pkg/cataloger/php/parse_composer_lock_test.go create mode 100644 syft/pkg/cataloger/php/test-fixtures/composer.lock create mode 100644 test/integration/test-fixtures/image-pkg-coverage/composer/composer.lock diff --git a/internal/formats/common/spdxhelpers/source_info.go b/internal/formats/common/spdxhelpers/source_info.go index 9a09bf27b..793a86940 100644 --- a/internal/formats/common/spdxhelpers/source_info.go +++ b/internal/formats/common/spdxhelpers/source_info.go @@ -31,6 +31,8 @@ func SourceInfo(p *pkg.Package) string { answer = "acquired package info from go module information" case pkg.RustPkg: answer = "acquired package info from rust cargo manifest" + case pkg.PhpComposerPkg: + answer = "acquired package info from PHP composer manifest" default: answer = "acquired package info from the following paths" } diff --git a/internal/formats/common/spdxhelpers/source_info_test.go b/internal/formats/common/spdxhelpers/source_info_test.go index 0faec1548..2a668152e 100644 --- a/internal/formats/common/spdxhelpers/source_info_test.go +++ b/internal/formats/common/spdxhelpers/source_info_test.go @@ -124,6 +124,14 @@ func Test_SourceInfo(t *testing.T) { "from rust cargo manifest", }, }, + { + input: pkg.Package{ + Type: pkg.PhpComposerPkg, + }, + expected: []string{ + "from PHP composer manifest", + }, + }, } var pkgTypes []pkg.Type for _, test := range tests { diff --git a/syft/pkg/cataloger/cataloger.go b/syft/pkg/cataloger/cataloger.go index a92a2dfbe..d35e50ec7 100644 --- a/syft/pkg/cataloger/cataloger.go +++ b/syft/pkg/cataloger/cataloger.go @@ -12,6 +12,7 @@ import ( "github.com/anchore/syft/syft/pkg/cataloger/golang" "github.com/anchore/syft/syft/pkg/cataloger/java" "github.com/anchore/syft/syft/pkg/cataloger/javascript" + "github.com/anchore/syft/syft/pkg/cataloger/php" "github.com/anchore/syft/syft/pkg/cataloger/python" "github.com/anchore/syft/syft/pkg/cataloger/rpmdb" "github.com/anchore/syft/syft/pkg/cataloger/ruby" @@ -49,6 +50,7 @@ func DirectoryCatalogers() []Cataloger { ruby.NewGemFileLockCataloger(), python.NewPythonIndexCataloger(), python.NewPythonPackageCataloger(), + php.NewPHPIndexCataloger(), javascript.NewJavascriptLockCataloger(), deb.NewDpkgdbCataloger(), rpmdb.NewRpmdbCataloger(), diff --git a/syft/pkg/cataloger/php/index_cataloger.go b/syft/pkg/cataloger/php/index_cataloger.go new file mode 100644 index 000000000..e70374b7f --- /dev/null +++ b/syft/pkg/cataloger/php/index_cataloger.go @@ -0,0 +1,17 @@ +/* +Package python provides a concrete Cataloger implementation for Python ecosystem files (egg, wheel, requirements.txt). +*/ +package php + +import ( + "github.com/anchore/syft/syft/pkg/cataloger/common" +) + +// NewPythonIndexCataloger returns a new cataloger for python packages referenced from poetry lock files, requirements.txt files, and setup.py files. +func NewPHPIndexCataloger() *common.GenericCataloger { + globParsers := map[string]common.ParserFn{ + "**/composer.lock": parseComposerLock, + } + + return common.NewGenericCataloger(nil, globParsers, "php-index-cataloger") +} diff --git a/syft/pkg/cataloger/php/parse_composer_lock.go b/syft/pkg/cataloger/php/parse_composer_lock.go new file mode 100644 index 000000000..e3a0c41c1 --- /dev/null +++ b/syft/pkg/cataloger/php/parse_composer_lock.go @@ -0,0 +1,50 @@ +package php + +import ( + "encoding/json" + "fmt" + "io" + + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/common" +) + +type ComposerLock struct { + Packages []Dependency `json:"packages"` + PackageDev []Dependency `json:"packages-dev"` +} + +type Dependency struct { + Name string `json:"name"` + Version string `json:"version"` +} + +// integrity check +var _ common.ParserFn = parseComposerLock + +// parseComposerLock is a parser function for Composer.lock contents, returning "Default" php packages discovered. +func parseComposerLock(_ string, reader io.Reader) ([]pkg.Package, error) { + packages := make([]pkg.Package, 0) + dec := json.NewDecoder(reader) + + for { + var lock ComposerLock + if err := dec.Decode(&lock); err == io.EOF { + break + } else if err != nil { + return nil, fmt.Errorf("failed to parse composer.lock file: %w", err) + } + for _, pkgMeta := range lock.Packages { + version := pkgMeta.Version + name := pkgMeta.Name + packages = append(packages, pkg.Package{ + Name: name, + Version: version, + Language: pkg.PHP, + Type: pkg.PhpComposerPkg, + }) + } + } + + return packages, nil +} diff --git a/syft/pkg/cataloger/php/parse_composer_lock_test.go b/syft/pkg/cataloger/php/parse_composer_lock_test.go new file mode 100644 index 000000000..92ffbfaef --- /dev/null +++ b/syft/pkg/cataloger/php/parse_composer_lock_test.go @@ -0,0 +1,40 @@ +package php + +import ( + "os" + "testing" + + "github.com/anchore/syft/syft/pkg" + "github.com/go-test/deep" +) + +func TestParseComposerFileLock(t *testing.T) { + expected := []pkg.Package{ + { + Name: "adoy/fastcgi-client", + Version: "1.0.2", + Language: pkg.PHP, + Type: pkg.PhpComposerPkg, + }, + { + Name: "alcaeus/mongo-php-adapter", + Version: "1.1.11", + Language: pkg.PHP, + Type: pkg.PhpComposerPkg, + }, + } + fixture, err := os.Open("test-fixtures/composer.lock") + if err != nil { + t.Fatalf("failed to open fixture: %+v", err) + } + + actual, err := parseComposerLock(fixture.Name(), fixture) + if err != nil { + t.Fatalf("failed to parse requirements: %+v", err) + } + differences := deep.Equal(expected, actual) + if differences != nil { + t.Errorf("returned package list differed from expectation: %+v", differences) + } + +} diff --git a/syft/pkg/cataloger/php/test-fixtures/composer.lock b/syft/pkg/cataloger/php/test-fixtures/composer.lock new file mode 100644 index 000000000..b9388fd7b --- /dev/null +++ b/syft/pkg/cataloger/php/test-fixtures/composer.lock @@ -0,0 +1,298 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "746ba78c06aef0cf954135ea909f9eb9", + "packages": [ + { + "name": "adoy/fastcgi-client", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/adoy/PHP-FastCGI-Client.git", + "reference": "6d9a552f0206a1db7feb442824540aa6c55e5b27" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/adoy/PHP-FastCGI-Client/zipball/6d9a552f0206a1db7feb442824540aa6c55e5b27", + "reference": "6d9a552f0206a1db7feb442824540aa6c55e5b27", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Adoy\\FastCGI\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Pierrick Charron", + "email": "pierrick@adoy.net" + } + ], + "description": "Lightweight, single file FastCGI client for PHP.", + "keywords": [ + "fastcgi", + "fcgi" + ], + "time": "2019-12-11T13:49:21+00:00" + }, + { + "name": "alcaeus/mongo-php-adapter", + "version": "1.1.11", + "source": { + "type": "git", + "url": "https://github.com/alcaeus/mongo-php-adapter.git", + "reference": "43b6add94c8b4cb9890d662cba4c0defde733dcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alcaeus/mongo-php-adapter/zipball/43b6add94c8b4cb9890d662cba4c0defde733dcf", + "reference": "43b6add94c8b4cb9890d662cba4c0defde733dcf", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-hash": "*", + "ext-mongodb": "^1.2.0", + "mongodb/mongodb": "^1.0.1", + "php": "^5.6 || ^7.0" + }, + "provide": { + "ext-mongo": "1.6.14" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.27 || ^6.0 || ^7.0", + "squizlabs/php_codesniffer": "^3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Mongo": "lib/Mongo" + }, + "psr-4": { + "Alcaeus\\MongoDbAdapter\\": "lib/Alcaeus/MongoDbAdapter" + }, + "files": [ + "lib/Mongo/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "alcaeus", + "email": "alcaeus@alcaeus.org" + }, + { + "name": "Olivier Lechevalier", + "email": "olivier.lechevalier@gmail.com" + } + ], + "description": "Adapter to provide ext-mongo interface on top of mongo-php-libary", + "keywords": [ + "database", + "mongodb" + ], + "time": "2019-11-11T20:47:32+00:00" + } + ], + "packages-dev": [ + { + "name": "behat/gherkin", + "version": "v4.6.2", + "source": { + "type": "git", + "url": "https://github.com/Behat/Gherkin.git", + "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/51ac4500c4dc30cbaaabcd2f25694299df666a31", + "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.5|~5", + "symfony/phpunit-bridge": "~2.7|~3|~4", + "symfony/yaml": "~2.3|~3|~4" + }, + "suggest": { + "symfony/yaml": "If you want to parse features, represented in YAML files" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Gherkin": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Gherkin DSL parser for PHP 5.3", + "homepage": "http://behat.org/", + "keywords": [ + "BDD", + "Behat", + "Cucumber", + "DSL", + "gherkin", + "parser" + ], + "time": "2020-03-17T14:03:26+00:00" + }, + { + "name": "codeception/codeception", + "version": "4.1.6", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Codeception.git", + "reference": "5515b6a6c6f1e1c909aaff2e5f3a15c177dfd1a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/5515b6a6c6f1e1c909aaff2e5f3a15c177dfd1a9", + "reference": "5515b6a6c6f1e1c909aaff2e5f3a15c177dfd1a9", + "shasum": "" + }, + "require": { + "behat/gherkin": "^4.4.0", + "codeception/lib-asserts": "^1.0", + "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.1.1 | ^9.0", + "codeception/stub": "^2.0 | ^3.0", + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "guzzlehttp/psr7": "~1.4", + "php": ">=5.6.0 <8.0", + "symfony/console": ">=2.7 <6.0", + "symfony/css-selector": ">=2.7 <6.0", + "symfony/event-dispatcher": ">=2.7 <6.0", + "symfony/finder": ">=2.7 <6.0", + "symfony/yaml": ">=2.7 <6.0" + }, + "require-dev": { + "codeception/module-asserts": "*@dev", + "codeception/module-cli": "*@dev", + "codeception/module-db": "*@dev", + "codeception/module-filesystem": "*@dev", + "codeception/module-phpbrowser": "*@dev", + "codeception/specify": "~0.3", + "codeception/util-universalframework": "*@dev", + "monolog/monolog": "~1.8", + "squizlabs/php_codesniffer": "~2.0", + "symfony/process": ">=2.7 <6.0", + "vlucas/phpdotenv": "^2.0 | ^3.0 | ^4.0" + }, + "suggest": { + "codeception/specify": "BDD-style code blocks", + "codeception/verify": "BDD-style assertions", + "hoa/console": "For interactive console functionality", + "stecman/symfony-console-completion": "For BASH autocompletion", + "symfony/phpunit-bridge": "For phpunit-bridge support" + }, + "bin": [ + "codecept" + ], + "type": "library", + "extra": { + "branch-alias": [] + }, + "autoload": { + "psr-4": { + "Codeception\\": "src/Codeception", + "Codeception\\Extension\\": "ext" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert@mail.ua", + "homepage": "http://codegyre.com" + } + ], + "description": "BDD-style testing framework", + "homepage": "http://codeception.com/", + "keywords": [ + "BDD", + "TDD", + "acceptance testing", + "functional testing", + "unit testing" + ], + "time": "2020-06-07T16:31:51+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "intelligence/bt-base": 20, + "intelligence/bt-common": 20, + "intelligence/bt-lib-tools": 20, + "intelligence/ci-lib-cache": 20, + "intelligence/ci-lib-client": 20, + "intelligence/ci-lib-contributed": 20, + "intelligence/ci-lib-eav": 20, + "intelligence/ci-lib-report": 20, + "intelligence/git-leaks-elastic-client": 20, + "intelligence/phishing-elastic-client": 20, + "libs/gib-sso-client": 20, + "mozhin/phplib": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": "^7.4.0", + "ext-amqp": "^1.9", + "ext-ctype": "*", + "ext-curl": "^7.4", + "ext-date": "^7.4", + "ext-fileinfo": "*", + "ext-geoip": "^1.1", + "ext-gettext": "*", + "ext-iconv": "*", + "ext-imagick": "^3.4", + "ext-imap": "^7.4", + "ext-intl": "^7.4", + "ext-json": "*", + "ext-mbstring": "^7.4", + "ext-mongodb": "^1.4", + "ext-mysqli": "^7.4", + "ext-pdo_mysql": "^7.4", + "ext-redis": ">=3.1" + }, + "platform-dev": [] +} diff --git a/syft/pkg/language.go b/syft/pkg/language.go index 96aa4a6f9..582a0122a 100644 --- a/syft/pkg/language.go +++ b/syft/pkg/language.go @@ -9,6 +9,7 @@ const ( Java Language = "java" JavaScript Language = "javascript" Python Language = "python" + PHP Language = "php" Ruby Language = "ruby" Go Language = "go" Rust Language = "rust" @@ -19,6 +20,7 @@ var AllLanguages = []Language{ Java, JavaScript, Python, + PHP, Ruby, Go, Rust, diff --git a/syft/pkg/type.go b/syft/pkg/type.go index d61892b5f..572cead54 100644 --- a/syft/pkg/type.go +++ b/syft/pkg/type.go @@ -14,6 +14,7 @@ const ( RpmPkg Type = "rpm" NpmPkg Type = "npm" PythonPkg Type = "python" + PhpComposerPkg Type = "php-composer" JavaPkg Type = "java-archive" JenkinsPluginPkg Type = "jenkins-plugin" GoModulePkg Type = "go-module" @@ -29,6 +30,7 @@ var AllPkgs = []Type{ RpmPkg, NpmPkg, PythonPkg, + PhpComposerPkg, JavaPkg, JenkinsPluginPkg, GoModulePkg, @@ -47,6 +49,8 @@ func (t Type) PackageURLType() string { return "deb" case PythonPkg: return packageurl.TypePyPi + case PhpComposerPkg: + return packageurl.TypeComposer case NpmPkg: return packageurl.TypeNPM case JavaPkg, JenkinsPluginPkg: diff --git a/test/integration/catalog_packages_cases_test.go b/test/integration/catalog_packages_cases_test.go index 41b8ee2fe..18f15fac2 100644 --- a/test/integration/catalog_packages_cases_test.go +++ b/test/integration/catalog_packages_cases_test.go @@ -167,6 +167,15 @@ var dirOnlyTestCases = []testCase{ "libc-utils": "0.7.2-r0", }, }, + { + name: "find php composer package", + pkgType: pkg.PhpComposerPkg, + pkgLanguage: pkg.PHP, + pkgInfo: map[string]string{ + "adoy/fastcgi-client": "1.0.2", + "alcaeus/mongo-php-adapter": "1.1.11", + }, + }, } var commonTestCases = []testCase{ diff --git a/test/integration/catalog_packages_test.go b/test/integration/catalog_packages_test.go index ded7beb90..ecc2baa9b 100644 --- a/test/integration/catalog_packages_test.go +++ b/test/integration/catalog_packages_test.go @@ -57,9 +57,10 @@ func TestPkgCoverageImage(t *testing.T) { definedLanguages.Add(l.String()) } - // for image we remove the go mod and rust support by default + // for image scans we should not expect to see any of the following package types definedLanguages.Remove(pkg.Go.String()) definedLanguages.Remove(pkg.Rust.String()) + definedLanguages.Remove(pkg.PHP.String()) observedPkgs := internal.NewStringSet() definedPkgs := internal.NewStringSet() @@ -67,10 +68,11 @@ func TestPkgCoverageImage(t *testing.T) { definedPkgs.Add(string(p)) } - // for image we remove the go-module and rust-crate support by default + // for image scans we should not expect to see any of the following package types definedPkgs.Remove(string(pkg.KbPkg)) definedPkgs.Remove(string(pkg.GoModulePkg)) definedPkgs.Remove(string(pkg.RustPkg)) + definedPkgs.Remove(string(pkg.PhpComposerPkg)) var cases []testCase cases = append(cases, commonTestCases...) @@ -195,6 +197,8 @@ func TestPkgCoverageDirectory(t *testing.T) { definedLanguages.Remove(pkg.UnknownLanguage.String()) observedPkgs.Remove(string(pkg.UnknownPkg)) definedPkgs.Remove(string(pkg.UnknownPkg)) + + // for directory scans we should not expect to see any of the following package types definedPkgs.Remove(string(pkg.KbPkg)) // ensure that integration test commonTestCases stay in sync with the available catalogers diff --git a/test/integration/test-fixtures/image-pkg-coverage/composer/composer.lock b/test/integration/test-fixtures/image-pkg-coverage/composer/composer.lock new file mode 100644 index 000000000..b9388fd7b --- /dev/null +++ b/test/integration/test-fixtures/image-pkg-coverage/composer/composer.lock @@ -0,0 +1,298 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "746ba78c06aef0cf954135ea909f9eb9", + "packages": [ + { + "name": "adoy/fastcgi-client", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/adoy/PHP-FastCGI-Client.git", + "reference": "6d9a552f0206a1db7feb442824540aa6c55e5b27" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/adoy/PHP-FastCGI-Client/zipball/6d9a552f0206a1db7feb442824540aa6c55e5b27", + "reference": "6d9a552f0206a1db7feb442824540aa6c55e5b27", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Adoy\\FastCGI\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Pierrick Charron", + "email": "pierrick@adoy.net" + } + ], + "description": "Lightweight, single file FastCGI client for PHP.", + "keywords": [ + "fastcgi", + "fcgi" + ], + "time": "2019-12-11T13:49:21+00:00" + }, + { + "name": "alcaeus/mongo-php-adapter", + "version": "1.1.11", + "source": { + "type": "git", + "url": "https://github.com/alcaeus/mongo-php-adapter.git", + "reference": "43b6add94c8b4cb9890d662cba4c0defde733dcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alcaeus/mongo-php-adapter/zipball/43b6add94c8b4cb9890d662cba4c0defde733dcf", + "reference": "43b6add94c8b4cb9890d662cba4c0defde733dcf", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-hash": "*", + "ext-mongodb": "^1.2.0", + "mongodb/mongodb": "^1.0.1", + "php": "^5.6 || ^7.0" + }, + "provide": { + "ext-mongo": "1.6.14" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.27 || ^6.0 || ^7.0", + "squizlabs/php_codesniffer": "^3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Mongo": "lib/Mongo" + }, + "psr-4": { + "Alcaeus\\MongoDbAdapter\\": "lib/Alcaeus/MongoDbAdapter" + }, + "files": [ + "lib/Mongo/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "alcaeus", + "email": "alcaeus@alcaeus.org" + }, + { + "name": "Olivier Lechevalier", + "email": "olivier.lechevalier@gmail.com" + } + ], + "description": "Adapter to provide ext-mongo interface on top of mongo-php-libary", + "keywords": [ + "database", + "mongodb" + ], + "time": "2019-11-11T20:47:32+00:00" + } + ], + "packages-dev": [ + { + "name": "behat/gherkin", + "version": "v4.6.2", + "source": { + "type": "git", + "url": "https://github.com/Behat/Gherkin.git", + "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/51ac4500c4dc30cbaaabcd2f25694299df666a31", + "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.5|~5", + "symfony/phpunit-bridge": "~2.7|~3|~4", + "symfony/yaml": "~2.3|~3|~4" + }, + "suggest": { + "symfony/yaml": "If you want to parse features, represented in YAML files" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Gherkin": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Gherkin DSL parser for PHP 5.3", + "homepage": "http://behat.org/", + "keywords": [ + "BDD", + "Behat", + "Cucumber", + "DSL", + "gherkin", + "parser" + ], + "time": "2020-03-17T14:03:26+00:00" + }, + { + "name": "codeception/codeception", + "version": "4.1.6", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Codeception.git", + "reference": "5515b6a6c6f1e1c909aaff2e5f3a15c177dfd1a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/5515b6a6c6f1e1c909aaff2e5f3a15c177dfd1a9", + "reference": "5515b6a6c6f1e1c909aaff2e5f3a15c177dfd1a9", + "shasum": "" + }, + "require": { + "behat/gherkin": "^4.4.0", + "codeception/lib-asserts": "^1.0", + "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.1.1 | ^9.0", + "codeception/stub": "^2.0 | ^3.0", + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "guzzlehttp/psr7": "~1.4", + "php": ">=5.6.0 <8.0", + "symfony/console": ">=2.7 <6.0", + "symfony/css-selector": ">=2.7 <6.0", + "symfony/event-dispatcher": ">=2.7 <6.0", + "symfony/finder": ">=2.7 <6.0", + "symfony/yaml": ">=2.7 <6.0" + }, + "require-dev": { + "codeception/module-asserts": "*@dev", + "codeception/module-cli": "*@dev", + "codeception/module-db": "*@dev", + "codeception/module-filesystem": "*@dev", + "codeception/module-phpbrowser": "*@dev", + "codeception/specify": "~0.3", + "codeception/util-universalframework": "*@dev", + "monolog/monolog": "~1.8", + "squizlabs/php_codesniffer": "~2.0", + "symfony/process": ">=2.7 <6.0", + "vlucas/phpdotenv": "^2.0 | ^3.0 | ^4.0" + }, + "suggest": { + "codeception/specify": "BDD-style code blocks", + "codeception/verify": "BDD-style assertions", + "hoa/console": "For interactive console functionality", + "stecman/symfony-console-completion": "For BASH autocompletion", + "symfony/phpunit-bridge": "For phpunit-bridge support" + }, + "bin": [ + "codecept" + ], + "type": "library", + "extra": { + "branch-alias": [] + }, + "autoload": { + "psr-4": { + "Codeception\\": "src/Codeception", + "Codeception\\Extension\\": "ext" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert@mail.ua", + "homepage": "http://codegyre.com" + } + ], + "description": "BDD-style testing framework", + "homepage": "http://codeception.com/", + "keywords": [ + "BDD", + "TDD", + "acceptance testing", + "functional testing", + "unit testing" + ], + "time": "2020-06-07T16:31:51+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "intelligence/bt-base": 20, + "intelligence/bt-common": 20, + "intelligence/bt-lib-tools": 20, + "intelligence/ci-lib-cache": 20, + "intelligence/ci-lib-client": 20, + "intelligence/ci-lib-contributed": 20, + "intelligence/ci-lib-eav": 20, + "intelligence/ci-lib-report": 20, + "intelligence/git-leaks-elastic-client": 20, + "intelligence/phishing-elastic-client": 20, + "libs/gib-sso-client": 20, + "mozhin/phplib": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": "^7.4.0", + "ext-amqp": "^1.9", + "ext-ctype": "*", + "ext-curl": "^7.4", + "ext-date": "^7.4", + "ext-fileinfo": "*", + "ext-geoip": "^1.1", + "ext-gettext": "*", + "ext-iconv": "*", + "ext-imagick": "^3.4", + "ext-imap": "^7.4", + "ext-intl": "^7.4", + "ext-json": "*", + "ext-mbstring": "^7.4", + "ext-mongodb": "^1.4", + "ext-mysqli": "^7.4", + "ext-pdo_mysql": "^7.4", + "ext-redis": ">=3.1" + }, + "platform-dev": [] +}