├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── docker-build.yml │ └── pull_request.yml ├── .gitignore ├── .mdlrc ├── .phpcs.xml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── action.yaml ├── bin └── ghsec-jira ├── composer.json ├── composer.lock ├── docker-compose.override.example.yml ├── docker-compose.yml ├── phpstan.neon └── src ├── PullRequestIssue.php ├── SecurityAlertIssue.php └── SyncCommand.php /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @reload/developers -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: composer 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | timezone: Europe/Copenhagen 8 | - package-ecosystem: github-actions 9 | directory: "/" 10 | schedule: 11 | interval: daily 12 | timezone: Europe/Copenhagen 13 | - package-ecosystem: docker 14 | directory: "/" 15 | schedule: 16 | interval: daily 17 | timezone: Europe/Copenhagen 18 | -------------------------------------------------------------------------------- /.github/workflows/docker-build.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | name: Docker build and run 3 | jobs: 4 | build: 5 | name: Docker build and run 6 | if: '!github.event.deleted' 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v4 10 | - name: Docker build 11 | run: docker build --tag github-security-jira:latest . 12 | - name: Run in Docker 13 | run: docker run -t --rm github-security-jira:latest --version 14 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | on: pull_request 2 | name: Code style review 3 | jobs: 4 | review_codestyle: 5 | name: Codestyle 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | - name: Setup PHP, with composer and extensions 10 | uses: shivammathur/setup-php@master 11 | with: 12 | php-version: 8.2 13 | coverage: none 14 | - name: Install Reviewdog 15 | run: | 16 | wget -O - -q https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh| sh -s -- -b $PWD/ latest 17 | - name: Install Dependencies 18 | run: | 19 | composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist 20 | - name: Check codestyle 21 | run: | 22 | vendor/bin/phpcs bin/ src/ --report=checkstyle | ./reviewdog -f=checkstyle -name=PHPCS -reporter=github-pr-check 23 | env: 24 | REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | 26 | static_code_analysis: 27 | name: Static Code Analysis 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v4 31 | - name: Setup PHP, with composer and extensions 32 | uses: shivammathur/setup-php@master 33 | with: 34 | php-version: 8.2 35 | coverage: none 36 | - name: Install Reviewdog 37 | run: | 38 | wget -O - -q https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh| sh -s -- -b $PWD/ latest 39 | - name: Install Dependencies 40 | run: | 41 | composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist 42 | - name: Static code analysis 43 | run: | 44 | php -d memory_limit=1G vendor/bin/phpstan analyse . --error-format=checkstyle | ./reviewdog -f=checkstyle -name=PHPStan -reporter=github-pr-check 45 | env: 46 | REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | docker-compose.override.yml -------------------------------------------------------------------------------- /.mdlrc: -------------------------------------------------------------------------------- 1 | # Disable "MD013 Line length" and "MD029 Ordered list item prefix". 2 | rules "~MD013", "~MD029" 3 | -------------------------------------------------------------------------------- /.phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ./src 4 | 5 | 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # ----------------- 2 | FROM composer:2.8.9@sha256:623d15a4aae78c868a35c3942add4bb9b2f98e4a3ec26e1928c84df14695d4b0 AS build-env 3 | 4 | COPY . /opt/ghsec-jira/ 5 | 6 | WORKDIR /opt/ghsec-jira 7 | 8 | RUN composer install --prefer-dist --no-dev 9 | 10 | # ----------------- 11 | FROM php:8.3.7-alpine3.18@sha256:3da837b84db645187ae2f24ca664da3faee7c546f0e8d930950b12d24f0d8fa0 12 | 13 | COPY --from=build-env /opt/ghsec-jira/ /opt/ghsec-jira/ 14 | 15 | ENTRYPOINT ["/opt/ghsec-jira/bin/ghsec-jira", "sync", "-vvv"] 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019, 2020 Reload A/S 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: check phpstan phpcs markdownlint 2 | 3 | check: phpstan phpcs markdownlint 4 | 5 | phpstan: 6 | -vendor/bin/phpstan analyse . 7 | 8 | phpcs: 9 | -vendor/bin/phpcs -s bin/ src/ 10 | 11 | # gem install mdl 12 | markdownlint: 13 | -mdl *.md 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # github-security-jira 2 | 3 | GitHub Action for mapping Dependabot security alerts to Jira tickets. 4 | 5 | ## Setup 6 | 7 | You need the following pieces set up to sync alerts with Jira: 8 | 9 | 1. Two repo secrets containing a GitHub access token and a Jira API token, respectively. 10 | 2. A workflow file which runs the action on a schedule, continually creating new tickets when necessary. 11 | 12 | ### Repo secrets 13 | 14 | The `reload/github-security-jira` action requires you to [create two encrypted secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets#creating-encrypted-secrets) in the repo: 15 | 16 | 1. A secret called `GitHubSecurityToken` which should contain a [Personal Access Token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) for the GitHub user under which this action should be executed. The token must include the `public_repo` scope if checking only public repos, or the `repo` scope for use on private repos. Also, the user must have [access to security alerts in the repo](https://help.github.com/en/github/managing-security-vulnerabilities/managing-alerts-for-vulnerable-dependencies-in-your-organization). 17 | 2. A secret called `JiraApiToken` containing an [API Token](https://confluence.atlassian.com/cloud/api-tokens-938839638.html) for the Jira user that should be used to create tickets. 18 | 19 | ### Workflow file setup 20 | 21 | The [GitHub workflow file](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/configuring-a-workflow#creating-a-workflow-file) should reside in any repo where you want to sync security alerts with Jira. 22 | 23 | It has some required and some optional settings, which are passed to the action as environment variables: 24 | 25 | - `GH_SECURITY_TOKEN`: A reference to the repo secret `GitHubSecurityToken` (**REQUIRED**) 26 | - `JIRA_TOKEN`: A reference to the repo secret `JiraApiToken` (**REQUIRED**) 27 | - `JIRA_HOST`: The endpoint for your Jira instance, e.g. (**REQUIRED**) 28 | - `JIRA_USER`: The ID of the Jira user which is associated with the 'JiraApiToken' secret, eg 'someuser@reload.dk' (**REQUIRED**) 29 | - `JIRA_PROJECT`: The project key for the Jira project where issues should be created, eg `TEST` or `ABC`. (**REQUIRED**) 30 | - `JIRA_ISSUE_TYPE`: Type of issue to create, e.g. `Security`. Defaults to `Bug`. (*Optional*) 31 | - `JIRA_WATCHERS`: Jira users to add as watchers to tickets. Separate multiple watchers with comma (no spaces). 32 | - `JIRA_ISSUE_LABELS`: Jira labels to add to tickets. Separate multiple labels with comma (no spaces). 33 | - `JIRA_RESTRICTED_COMMENT_ROLE`: A comment with restricted visibility 34 | to this role is posted with info about who was added as watchers to 35 | the issue. Defaults to `Developers`. (*Optional*) 36 | 37 | Here is an example setup which runs this action every 6 hours. 38 | 39 | ```yaml 40 | name: GitHub Security Alerts for Jira 41 | 42 | on: 43 | schedule: 44 | - cron: '0 */6 * * *' 45 | 46 | jobs: 47 | syncSecurityAlerts: 48 | runs-on: ubuntu-latest 49 | steps: 50 | - name: "Sync security alerts to Jira issues" 51 | uses: reload/github-security-jira@v1.x 52 | env: 53 | GH_SECURITY_TOKEN: ${{ secrets.GitHubSecurityToken }} 54 | JIRA_TOKEN: ${{ secrets.JiraApiToken }} 55 | JIRA_HOST: https://foo.atlassian.net 56 | JIRA_USER: someuser@reload.dk 57 | JIRA_PROJECT: ABC 58 | JIRA_ISSUE_TYPE: Security 59 | JIRA_WATCHERS: someuser@reload.dk,someotheruser@reload.dk 60 | ``` 61 | 62 | ## Local development 63 | 64 | Copy `docker-composer.override.example.yml` to `docker-composer.override.yml` and edit according to your settings. 65 | 66 | After that, you can execute the Symfony console app like so: 67 | 68 | ``` 69 | docker-compose run --rm ghsec-jira --verbose --dry-run 70 | ``` 71 | 72 | Remove the `--dry-run` option to actually create issues in Jira. 73 | -------------------------------------------------------------------------------- /action.yaml: -------------------------------------------------------------------------------- 1 | name: 'Sync GitHub Security Alerts with Jira' 2 | description: 'Synchronize the current repo alert state with JIRA and creates tickets accordingly.' 3 | author: 'reload' 4 | outputs: 5 | result: 6 | description: 'A string summarizing actions performed' 7 | runs: 8 | using: 'docker' 9 | image: 'Dockerfile' 10 | branding: 11 | icon: 'rotate-cw' 12 | color: 'green' 13 | -------------------------------------------------------------------------------- /bin/ghsec-jira: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | add($command); 17 | $application->setDefaultCommand('sync'); 18 | $application->run(); 19 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reload/github-security-jira", 3 | "description": "Create Jira tickets for GitHub security alerts", 4 | "license": "MIT", 5 | "require": { 6 | "php": ">=8.1", 7 | "softonic/graphql-client": "^2.1", 8 | "symfony/console": "^5", 9 | "symfony/yaml": "^6.1", 10 | "reload/jira-security-issue": "^2.0.0" 11 | }, 12 | "repositories": [ 13 | { 14 | "type": "vcs", 15 | "url": "https://github.com/appocular/coding-standard" 16 | } 17 | ], 18 | "autoload": { 19 | "psr-4": { 20 | "GitHubSecurityJira\\": "src/" 21 | } 22 | }, 23 | "require-dev": { 24 | "phpstan/phpstan": "^1", 25 | "squizlabs/php_codesniffer": "^3.7", 26 | "phpstan/extension-installer": "^1.4", 27 | "phpstan/phpstan-deprecation-rules": "^1.2" 28 | }, 29 | "config": { 30 | "allow-plugins": { 31 | "dealerdirect/phpcodesniffer-composer-installer": true, 32 | "phpstan/extension-installer": true 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "58e97cb727dccec533f2cc5387e86ffa", 8 | "packages": [ 9 | { 10 | "name": "guzzlehttp/guzzle", 11 | "version": "7.8.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/guzzle/guzzle.git", 15 | "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/guzzle/guzzle/zipball/1110f66a6530a40fe7aea0378fe608ee2b2248f9", 20 | "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "ext-json": "*", 25 | "guzzlehttp/promises": "^1.5.3 || ^2.0.1", 26 | "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", 27 | "php": "^7.2.5 || ^8.0", 28 | "psr/http-client": "^1.0", 29 | "symfony/deprecation-contracts": "^2.2 || ^3.0" 30 | }, 31 | "provide": { 32 | "psr/http-client-implementation": "1.0" 33 | }, 34 | "require-dev": { 35 | "bamarni/composer-bin-plugin": "^1.8.1", 36 | "ext-curl": "*", 37 | "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", 38 | "php-http/message-factory": "^1.1", 39 | "phpunit/phpunit": "^8.5.29 || ^9.5.23", 40 | "psr/log": "^1.1 || ^2.0 || ^3.0" 41 | }, 42 | "suggest": { 43 | "ext-curl": "Required for CURL handler support", 44 | "ext-intl": "Required for Internationalized Domain Name (IDN) support", 45 | "psr/log": "Required for using the Log middleware" 46 | }, 47 | "type": "library", 48 | "extra": { 49 | "bamarni-bin": { 50 | "bin-links": true, 51 | "forward-command": false 52 | } 53 | }, 54 | "autoload": { 55 | "files": [ 56 | "src/functions_include.php" 57 | ], 58 | "psr-4": { 59 | "GuzzleHttp\\": "src/" 60 | } 61 | }, 62 | "notification-url": "https://packagist.org/downloads/", 63 | "license": [ 64 | "MIT" 65 | ], 66 | "authors": [ 67 | { 68 | "name": "Graham Campbell", 69 | "email": "hello@gjcampbell.co.uk", 70 | "homepage": "https://github.com/GrahamCampbell" 71 | }, 72 | { 73 | "name": "Michael Dowling", 74 | "email": "mtdowling@gmail.com", 75 | "homepage": "https://github.com/mtdowling" 76 | }, 77 | { 78 | "name": "Jeremy Lindblom", 79 | "email": "jeremeamia@gmail.com", 80 | "homepage": "https://github.com/jeremeamia" 81 | }, 82 | { 83 | "name": "George Mponos", 84 | "email": "gmponos@gmail.com", 85 | "homepage": "https://github.com/gmponos" 86 | }, 87 | { 88 | "name": "Tobias Nyholm", 89 | "email": "tobias.nyholm@gmail.com", 90 | "homepage": "https://github.com/Nyholm" 91 | }, 92 | { 93 | "name": "Márk Sági-Kazár", 94 | "email": "mark.sagikazar@gmail.com", 95 | "homepage": "https://github.com/sagikazarmark" 96 | }, 97 | { 98 | "name": "Tobias Schultze", 99 | "email": "webmaster@tubo-world.de", 100 | "homepage": "https://github.com/Tobion" 101 | } 102 | ], 103 | "description": "Guzzle is a PHP HTTP client library", 104 | "keywords": [ 105 | "client", 106 | "curl", 107 | "framework", 108 | "http", 109 | "http client", 110 | "psr-18", 111 | "psr-7", 112 | "rest", 113 | "web service" 114 | ], 115 | "support": { 116 | "issues": "https://github.com/guzzle/guzzle/issues", 117 | "source": "https://github.com/guzzle/guzzle/tree/7.8.0" 118 | }, 119 | "funding": [ 120 | { 121 | "url": "https://github.com/GrahamCampbell", 122 | "type": "github" 123 | }, 124 | { 125 | "url": "https://github.com/Nyholm", 126 | "type": "github" 127 | }, 128 | { 129 | "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", 130 | "type": "tidelift" 131 | } 132 | ], 133 | "time": "2023-08-27T10:20:53+00:00" 134 | }, 135 | { 136 | "name": "guzzlehttp/promises", 137 | "version": "2.0.1", 138 | "source": { 139 | "type": "git", 140 | "url": "https://github.com/guzzle/promises.git", 141 | "reference": "111166291a0f8130081195ac4556a5587d7f1b5d" 142 | }, 143 | "dist": { 144 | "type": "zip", 145 | "url": "https://api.github.com/repos/guzzle/promises/zipball/111166291a0f8130081195ac4556a5587d7f1b5d", 146 | "reference": "111166291a0f8130081195ac4556a5587d7f1b5d", 147 | "shasum": "" 148 | }, 149 | "require": { 150 | "php": "^7.2.5 || ^8.0" 151 | }, 152 | "require-dev": { 153 | "bamarni/composer-bin-plugin": "^1.8.1", 154 | "phpunit/phpunit": "^8.5.29 || ^9.5.23" 155 | }, 156 | "type": "library", 157 | "extra": { 158 | "bamarni-bin": { 159 | "bin-links": true, 160 | "forward-command": false 161 | } 162 | }, 163 | "autoload": { 164 | "psr-4": { 165 | "GuzzleHttp\\Promise\\": "src/" 166 | } 167 | }, 168 | "notification-url": "https://packagist.org/downloads/", 169 | "license": [ 170 | "MIT" 171 | ], 172 | "authors": [ 173 | { 174 | "name": "Graham Campbell", 175 | "email": "hello@gjcampbell.co.uk", 176 | "homepage": "https://github.com/GrahamCampbell" 177 | }, 178 | { 179 | "name": "Michael Dowling", 180 | "email": "mtdowling@gmail.com", 181 | "homepage": "https://github.com/mtdowling" 182 | }, 183 | { 184 | "name": "Tobias Nyholm", 185 | "email": "tobias.nyholm@gmail.com", 186 | "homepage": "https://github.com/Nyholm" 187 | }, 188 | { 189 | "name": "Tobias Schultze", 190 | "email": "webmaster@tubo-world.de", 191 | "homepage": "https://github.com/Tobion" 192 | } 193 | ], 194 | "description": "Guzzle promises library", 195 | "keywords": [ 196 | "promise" 197 | ], 198 | "support": { 199 | "issues": "https://github.com/guzzle/promises/issues", 200 | "source": "https://github.com/guzzle/promises/tree/2.0.1" 201 | }, 202 | "funding": [ 203 | { 204 | "url": "https://github.com/GrahamCampbell", 205 | "type": "github" 206 | }, 207 | { 208 | "url": "https://github.com/Nyholm", 209 | "type": "github" 210 | }, 211 | { 212 | "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", 213 | "type": "tidelift" 214 | } 215 | ], 216 | "time": "2023-08-03T15:11:55+00:00" 217 | }, 218 | { 219 | "name": "guzzlehttp/psr7", 220 | "version": "2.6.1", 221 | "source": { 222 | "type": "git", 223 | "url": "https://github.com/guzzle/psr7.git", 224 | "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727" 225 | }, 226 | "dist": { 227 | "type": "zip", 228 | "url": "https://api.github.com/repos/guzzle/psr7/zipball/be45764272e8873c72dbe3d2edcfdfcc3bc9f727", 229 | "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727", 230 | "shasum": "" 231 | }, 232 | "require": { 233 | "php": "^7.2.5 || ^8.0", 234 | "psr/http-factory": "^1.0", 235 | "psr/http-message": "^1.1 || ^2.0", 236 | "ralouphie/getallheaders": "^3.0" 237 | }, 238 | "provide": { 239 | "psr/http-factory-implementation": "1.0", 240 | "psr/http-message-implementation": "1.0" 241 | }, 242 | "require-dev": { 243 | "bamarni/composer-bin-plugin": "^1.8.1", 244 | "http-interop/http-factory-tests": "^0.9", 245 | "phpunit/phpunit": "^8.5.29 || ^9.5.23" 246 | }, 247 | "suggest": { 248 | "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" 249 | }, 250 | "type": "library", 251 | "extra": { 252 | "bamarni-bin": { 253 | "bin-links": true, 254 | "forward-command": false 255 | } 256 | }, 257 | "autoload": { 258 | "psr-4": { 259 | "GuzzleHttp\\Psr7\\": "src/" 260 | } 261 | }, 262 | "notification-url": "https://packagist.org/downloads/", 263 | "license": [ 264 | "MIT" 265 | ], 266 | "authors": [ 267 | { 268 | "name": "Graham Campbell", 269 | "email": "hello@gjcampbell.co.uk", 270 | "homepage": "https://github.com/GrahamCampbell" 271 | }, 272 | { 273 | "name": "Michael Dowling", 274 | "email": "mtdowling@gmail.com", 275 | "homepage": "https://github.com/mtdowling" 276 | }, 277 | { 278 | "name": "George Mponos", 279 | "email": "gmponos@gmail.com", 280 | "homepage": "https://github.com/gmponos" 281 | }, 282 | { 283 | "name": "Tobias Nyholm", 284 | "email": "tobias.nyholm@gmail.com", 285 | "homepage": "https://github.com/Nyholm" 286 | }, 287 | { 288 | "name": "Márk Sági-Kazár", 289 | "email": "mark.sagikazar@gmail.com", 290 | "homepage": "https://github.com/sagikazarmark" 291 | }, 292 | { 293 | "name": "Tobias Schultze", 294 | "email": "webmaster@tubo-world.de", 295 | "homepage": "https://github.com/Tobion" 296 | }, 297 | { 298 | "name": "Márk Sági-Kazár", 299 | "email": "mark.sagikazar@gmail.com", 300 | "homepage": "https://sagikazarmark.hu" 301 | } 302 | ], 303 | "description": "PSR-7 message implementation that also provides common utility methods", 304 | "keywords": [ 305 | "http", 306 | "message", 307 | "psr-7", 308 | "request", 309 | "response", 310 | "stream", 311 | "uri", 312 | "url" 313 | ], 314 | "support": { 315 | "issues": "https://github.com/guzzle/psr7/issues", 316 | "source": "https://github.com/guzzle/psr7/tree/2.6.1" 317 | }, 318 | "funding": [ 319 | { 320 | "url": "https://github.com/GrahamCampbell", 321 | "type": "github" 322 | }, 323 | { 324 | "url": "https://github.com/Nyholm", 325 | "type": "github" 326 | }, 327 | { 328 | "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", 329 | "type": "tidelift" 330 | } 331 | ], 332 | "time": "2023-08-27T10:13:57+00:00" 333 | }, 334 | { 335 | "name": "league/oauth2-client", 336 | "version": "2.7.0", 337 | "source": { 338 | "type": "git", 339 | "url": "https://github.com/thephpleague/oauth2-client.git", 340 | "reference": "160d6274b03562ebeb55ed18399281d8118b76c8" 341 | }, 342 | "dist": { 343 | "type": "zip", 344 | "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/160d6274b03562ebeb55ed18399281d8118b76c8", 345 | "reference": "160d6274b03562ebeb55ed18399281d8118b76c8", 346 | "shasum": "" 347 | }, 348 | "require": { 349 | "guzzlehttp/guzzle": "^6.0 || ^7.0", 350 | "paragonie/random_compat": "^1 || ^2 || ^9.99", 351 | "php": "^5.6 || ^7.0 || ^8.0" 352 | }, 353 | "require-dev": { 354 | "mockery/mockery": "^1.3.5", 355 | "php-parallel-lint/php-parallel-lint": "^1.3.1", 356 | "phpunit/phpunit": "^5.7 || ^6.0 || ^9.5", 357 | "squizlabs/php_codesniffer": "^2.3 || ^3.0" 358 | }, 359 | "type": "library", 360 | "extra": { 361 | "branch-alias": { 362 | "dev-2.x": "2.0.x-dev" 363 | } 364 | }, 365 | "autoload": { 366 | "psr-4": { 367 | "League\\OAuth2\\Client\\": "src/" 368 | } 369 | }, 370 | "notification-url": "https://packagist.org/downloads/", 371 | "license": [ 372 | "MIT" 373 | ], 374 | "authors": [ 375 | { 376 | "name": "Alex Bilbie", 377 | "email": "hello@alexbilbie.com", 378 | "homepage": "http://www.alexbilbie.com", 379 | "role": "Developer" 380 | }, 381 | { 382 | "name": "Woody Gilk", 383 | "homepage": "https://github.com/shadowhand", 384 | "role": "Contributor" 385 | } 386 | ], 387 | "description": "OAuth 2.0 Client Library", 388 | "keywords": [ 389 | "Authentication", 390 | "SSO", 391 | "authorization", 392 | "identity", 393 | "idp", 394 | "oauth", 395 | "oauth2", 396 | "single sign on" 397 | ], 398 | "support": { 399 | "issues": "https://github.com/thephpleague/oauth2-client/issues", 400 | "source": "https://github.com/thephpleague/oauth2-client/tree/2.7.0" 401 | }, 402 | "time": "2023-04-16T18:19:15+00:00" 403 | }, 404 | { 405 | "name": "lesstif/php-jira-rest-client", 406 | "version": "5.9.0", 407 | "source": { 408 | "type": "git", 409 | "url": "https://github.com/lesstif/php-jira-rest-client.git", 410 | "reference": "06c20a4b6ff263cbbeb90b270f49ac8e697e320f" 411 | }, 412 | "dist": { 413 | "type": "zip", 414 | "url": "https://api.github.com/repos/lesstif/php-jira-rest-client/zipball/06c20a4b6ff263cbbeb90b270f49ac8e697e320f", 415 | "reference": "06c20a4b6ff263cbbeb90b270f49ac8e697e320f", 416 | "shasum": "" 417 | }, 418 | "require": { 419 | "ext-curl": "*", 420 | "ext-json": "*", 421 | "monolog/monolog": "^2.0|^3.0", 422 | "netresearch/jsonmapper": "^4.2", 423 | "php": "^8.0" 424 | }, 425 | "require-dev": { 426 | "mockery/mockery": "^1.0|^2.0", 427 | "phpstan/phpstan": "^1.0|^2.0", 428 | "phpunit/phpunit": "^9.0|^10.0", 429 | "symfony/var-dumper": "^5.0|^6.0|^7.0" 430 | }, 431 | "suggest": { 432 | "vlucas/phpdotenv": "^5.0|^6.0" 433 | }, 434 | "type": "library", 435 | "extra": { 436 | "laravel": { 437 | "providers": [ 438 | "JiraRestApi\\JiraRestApiServiceProvider" 439 | ] 440 | } 441 | }, 442 | "autoload": { 443 | "psr-4": { 444 | "JiraRestApi\\": "src" 445 | } 446 | }, 447 | "notification-url": "https://packagist.org/downloads/", 448 | "license": [ 449 | "Apache-2.0" 450 | ], 451 | "authors": [ 452 | { 453 | "name": "KwangSeob Jeong", 454 | "email": "lesstif@gmail.com", 455 | "homepage": "https://lesstif.com/" 456 | } 457 | ], 458 | "description": "JIRA REST API Client for PHP Users.", 459 | "keywords": [ 460 | "jira", 461 | "jira-php", 462 | "jira-rest", 463 | "rest" 464 | ], 465 | "support": { 466 | "issues": "https://github.com/lesstif/php-jira-rest-client/issues", 467 | "source": "https://github.com/lesstif/php-jira-rest-client/tree/5.9.0" 468 | }, 469 | "time": "2024-09-16T11:00:42+00:00" 470 | }, 471 | { 472 | "name": "monolog/monolog", 473 | "version": "3.7.0", 474 | "source": { 475 | "type": "git", 476 | "url": "https://github.com/Seldaek/monolog.git", 477 | "reference": "f4393b648b78a5408747de94fca38beb5f7e9ef8" 478 | }, 479 | "dist": { 480 | "type": "zip", 481 | "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f4393b648b78a5408747de94fca38beb5f7e9ef8", 482 | "reference": "f4393b648b78a5408747de94fca38beb5f7e9ef8", 483 | "shasum": "" 484 | }, 485 | "require": { 486 | "php": ">=8.1", 487 | "psr/log": "^2.0 || ^3.0" 488 | }, 489 | "provide": { 490 | "psr/log-implementation": "3.0.0" 491 | }, 492 | "require-dev": { 493 | "aws/aws-sdk-php": "^3.0", 494 | "doctrine/couchdb": "~1.0@dev", 495 | "elasticsearch/elasticsearch": "^7 || ^8", 496 | "ext-json": "*", 497 | "graylog2/gelf-php": "^1.4.2 || ^2.0", 498 | "guzzlehttp/guzzle": "^7.4.5", 499 | "guzzlehttp/psr7": "^2.2", 500 | "mongodb/mongodb": "^1.8", 501 | "php-amqplib/php-amqplib": "~2.4 || ^3", 502 | "phpstan/phpstan": "^1.9", 503 | "phpstan/phpstan-deprecation-rules": "^1.0", 504 | "phpstan/phpstan-strict-rules": "^1.4", 505 | "phpunit/phpunit": "^10.5.17", 506 | "predis/predis": "^1.1 || ^2", 507 | "ruflin/elastica": "^7", 508 | "symfony/mailer": "^5.4 || ^6", 509 | "symfony/mime": "^5.4 || ^6" 510 | }, 511 | "suggest": { 512 | "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", 513 | "doctrine/couchdb": "Allow sending log messages to a CouchDB server", 514 | "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", 515 | "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", 516 | "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", 517 | "ext-mbstring": "Allow to work properly with unicode symbols", 518 | "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", 519 | "ext-openssl": "Required to send log messages using SSL", 520 | "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", 521 | "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", 522 | "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", 523 | "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", 524 | "rollbar/rollbar": "Allow sending log messages to Rollbar", 525 | "ruflin/elastica": "Allow sending log messages to an Elastic Search server" 526 | }, 527 | "type": "library", 528 | "extra": { 529 | "branch-alias": { 530 | "dev-main": "3.x-dev" 531 | } 532 | }, 533 | "autoload": { 534 | "psr-4": { 535 | "Monolog\\": "src/Monolog" 536 | } 537 | }, 538 | "notification-url": "https://packagist.org/downloads/", 539 | "license": [ 540 | "MIT" 541 | ], 542 | "authors": [ 543 | { 544 | "name": "Jordi Boggiano", 545 | "email": "j.boggiano@seld.be", 546 | "homepage": "https://seld.be" 547 | } 548 | ], 549 | "description": "Sends your logs to files, sockets, inboxes, databases and various web services", 550 | "homepage": "https://github.com/Seldaek/monolog", 551 | "keywords": [ 552 | "log", 553 | "logging", 554 | "psr-3" 555 | ], 556 | "support": { 557 | "issues": "https://github.com/Seldaek/monolog/issues", 558 | "source": "https://github.com/Seldaek/monolog/tree/3.7.0" 559 | }, 560 | "funding": [ 561 | { 562 | "url": "https://github.com/Seldaek", 563 | "type": "github" 564 | }, 565 | { 566 | "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", 567 | "type": "tidelift" 568 | } 569 | ], 570 | "time": "2024-06-28T09:40:51+00:00" 571 | }, 572 | { 573 | "name": "netresearch/jsonmapper", 574 | "version": "v4.5.0", 575 | "source": { 576 | "type": "git", 577 | "url": "https://github.com/cweiske/jsonmapper.git", 578 | "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5" 579 | }, 580 | "dist": { 581 | "type": "zip", 582 | "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8e76efb98ee8b6afc54687045e1b8dba55ac76e5", 583 | "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5", 584 | "shasum": "" 585 | }, 586 | "require": { 587 | "ext-json": "*", 588 | "ext-pcre": "*", 589 | "ext-reflection": "*", 590 | "ext-spl": "*", 591 | "php": ">=7.1" 592 | }, 593 | "require-dev": { 594 | "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0", 595 | "squizlabs/php_codesniffer": "~3.5" 596 | }, 597 | "type": "library", 598 | "autoload": { 599 | "psr-0": { 600 | "JsonMapper": "src/" 601 | } 602 | }, 603 | "notification-url": "https://packagist.org/downloads/", 604 | "license": [ 605 | "OSL-3.0" 606 | ], 607 | "authors": [ 608 | { 609 | "name": "Christian Weiske", 610 | "email": "cweiske@cweiske.de", 611 | "homepage": "http://github.com/cweiske/jsonmapper/", 612 | "role": "Developer" 613 | } 614 | ], 615 | "description": "Map nested JSON structures onto PHP classes", 616 | "support": { 617 | "email": "cweiske@cweiske.de", 618 | "issues": "https://github.com/cweiske/jsonmapper/issues", 619 | "source": "https://github.com/cweiske/jsonmapper/tree/v4.5.0" 620 | }, 621 | "time": "2024-09-08T10:13:13+00:00" 622 | }, 623 | { 624 | "name": "paragonie/random_compat", 625 | "version": "v9.99.100", 626 | "source": { 627 | "type": "git", 628 | "url": "https://github.com/paragonie/random_compat.git", 629 | "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" 630 | }, 631 | "dist": { 632 | "type": "zip", 633 | "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", 634 | "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", 635 | "shasum": "" 636 | }, 637 | "require": { 638 | "php": ">= 7" 639 | }, 640 | "require-dev": { 641 | "phpunit/phpunit": "4.*|5.*", 642 | "vimeo/psalm": "^1" 643 | }, 644 | "suggest": { 645 | "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." 646 | }, 647 | "type": "library", 648 | "notification-url": "https://packagist.org/downloads/", 649 | "license": [ 650 | "MIT" 651 | ], 652 | "authors": [ 653 | { 654 | "name": "Paragon Initiative Enterprises", 655 | "email": "security@paragonie.com", 656 | "homepage": "https://paragonie.com" 657 | } 658 | ], 659 | "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", 660 | "keywords": [ 661 | "csprng", 662 | "polyfill", 663 | "pseudorandom", 664 | "random" 665 | ], 666 | "support": { 667 | "email": "info@paragonie.com", 668 | "issues": "https://github.com/paragonie/random_compat/issues", 669 | "source": "https://github.com/paragonie/random_compat" 670 | }, 671 | "time": "2020-10-15T08:29:30+00:00" 672 | }, 673 | { 674 | "name": "psr/cache", 675 | "version": "3.0.0", 676 | "source": { 677 | "type": "git", 678 | "url": "https://github.com/php-fig/cache.git", 679 | "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" 680 | }, 681 | "dist": { 682 | "type": "zip", 683 | "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", 684 | "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", 685 | "shasum": "" 686 | }, 687 | "require": { 688 | "php": ">=8.0.0" 689 | }, 690 | "type": "library", 691 | "extra": { 692 | "branch-alias": { 693 | "dev-master": "1.0.x-dev" 694 | } 695 | }, 696 | "autoload": { 697 | "psr-4": { 698 | "Psr\\Cache\\": "src/" 699 | } 700 | }, 701 | "notification-url": "https://packagist.org/downloads/", 702 | "license": [ 703 | "MIT" 704 | ], 705 | "authors": [ 706 | { 707 | "name": "PHP-FIG", 708 | "homepage": "https://www.php-fig.org/" 709 | } 710 | ], 711 | "description": "Common interface for caching libraries", 712 | "keywords": [ 713 | "cache", 714 | "psr", 715 | "psr-6" 716 | ], 717 | "support": { 718 | "source": "https://github.com/php-fig/cache/tree/3.0.0" 719 | }, 720 | "time": "2021-02-03T23:26:27+00:00" 721 | }, 722 | { 723 | "name": "psr/container", 724 | "version": "2.0.2", 725 | "source": { 726 | "type": "git", 727 | "url": "https://github.com/php-fig/container.git", 728 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" 729 | }, 730 | "dist": { 731 | "type": "zip", 732 | "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", 733 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", 734 | "shasum": "" 735 | }, 736 | "require": { 737 | "php": ">=7.4.0" 738 | }, 739 | "type": "library", 740 | "extra": { 741 | "branch-alias": { 742 | "dev-master": "2.0.x-dev" 743 | } 744 | }, 745 | "autoload": { 746 | "psr-4": { 747 | "Psr\\Container\\": "src/" 748 | } 749 | }, 750 | "notification-url": "https://packagist.org/downloads/", 751 | "license": [ 752 | "MIT" 753 | ], 754 | "authors": [ 755 | { 756 | "name": "PHP-FIG", 757 | "homepage": "https://www.php-fig.org/" 758 | } 759 | ], 760 | "description": "Common Container Interface (PHP FIG PSR-11)", 761 | "homepage": "https://github.com/php-fig/container", 762 | "keywords": [ 763 | "PSR-11", 764 | "container", 765 | "container-interface", 766 | "container-interop", 767 | "psr" 768 | ], 769 | "support": { 770 | "issues": "https://github.com/php-fig/container/issues", 771 | "source": "https://github.com/php-fig/container/tree/2.0.2" 772 | }, 773 | "time": "2021-11-05T16:47:00+00:00" 774 | }, 775 | { 776 | "name": "psr/http-client", 777 | "version": "1.0.2", 778 | "source": { 779 | "type": "git", 780 | "url": "https://github.com/php-fig/http-client.git", 781 | "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" 782 | }, 783 | "dist": { 784 | "type": "zip", 785 | "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", 786 | "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", 787 | "shasum": "" 788 | }, 789 | "require": { 790 | "php": "^7.0 || ^8.0", 791 | "psr/http-message": "^1.0 || ^2.0" 792 | }, 793 | "type": "library", 794 | "extra": { 795 | "branch-alias": { 796 | "dev-master": "1.0.x-dev" 797 | } 798 | }, 799 | "autoload": { 800 | "psr-4": { 801 | "Psr\\Http\\Client\\": "src/" 802 | } 803 | }, 804 | "notification-url": "https://packagist.org/downloads/", 805 | "license": [ 806 | "MIT" 807 | ], 808 | "authors": [ 809 | { 810 | "name": "PHP-FIG", 811 | "homepage": "https://www.php-fig.org/" 812 | } 813 | ], 814 | "description": "Common interface for HTTP clients", 815 | "homepage": "https://github.com/php-fig/http-client", 816 | "keywords": [ 817 | "http", 818 | "http-client", 819 | "psr", 820 | "psr-18" 821 | ], 822 | "support": { 823 | "source": "https://github.com/php-fig/http-client/tree/1.0.2" 824 | }, 825 | "time": "2023-04-10T20:12:12+00:00" 826 | }, 827 | { 828 | "name": "psr/http-factory", 829 | "version": "1.0.2", 830 | "source": { 831 | "type": "git", 832 | "url": "https://github.com/php-fig/http-factory.git", 833 | "reference": "e616d01114759c4c489f93b099585439f795fe35" 834 | }, 835 | "dist": { 836 | "type": "zip", 837 | "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", 838 | "reference": "e616d01114759c4c489f93b099585439f795fe35", 839 | "shasum": "" 840 | }, 841 | "require": { 842 | "php": ">=7.0.0", 843 | "psr/http-message": "^1.0 || ^2.0" 844 | }, 845 | "type": "library", 846 | "extra": { 847 | "branch-alias": { 848 | "dev-master": "1.0.x-dev" 849 | } 850 | }, 851 | "autoload": { 852 | "psr-4": { 853 | "Psr\\Http\\Message\\": "src/" 854 | } 855 | }, 856 | "notification-url": "https://packagist.org/downloads/", 857 | "license": [ 858 | "MIT" 859 | ], 860 | "authors": [ 861 | { 862 | "name": "PHP-FIG", 863 | "homepage": "https://www.php-fig.org/" 864 | } 865 | ], 866 | "description": "Common interfaces for PSR-7 HTTP message factories", 867 | "keywords": [ 868 | "factory", 869 | "http", 870 | "message", 871 | "psr", 872 | "psr-17", 873 | "psr-7", 874 | "request", 875 | "response" 876 | ], 877 | "support": { 878 | "source": "https://github.com/php-fig/http-factory/tree/1.0.2" 879 | }, 880 | "time": "2023-04-10T20:10:41+00:00" 881 | }, 882 | { 883 | "name": "psr/http-message", 884 | "version": "2.0", 885 | "source": { 886 | "type": "git", 887 | "url": "https://github.com/php-fig/http-message.git", 888 | "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" 889 | }, 890 | "dist": { 891 | "type": "zip", 892 | "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", 893 | "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", 894 | "shasum": "" 895 | }, 896 | "require": { 897 | "php": "^7.2 || ^8.0" 898 | }, 899 | "type": "library", 900 | "extra": { 901 | "branch-alias": { 902 | "dev-master": "2.0.x-dev" 903 | } 904 | }, 905 | "autoload": { 906 | "psr-4": { 907 | "Psr\\Http\\Message\\": "src/" 908 | } 909 | }, 910 | "notification-url": "https://packagist.org/downloads/", 911 | "license": [ 912 | "MIT" 913 | ], 914 | "authors": [ 915 | { 916 | "name": "PHP-FIG", 917 | "homepage": "https://www.php-fig.org/" 918 | } 919 | ], 920 | "description": "Common interface for HTTP messages", 921 | "homepage": "https://github.com/php-fig/http-message", 922 | "keywords": [ 923 | "http", 924 | "http-message", 925 | "psr", 926 | "psr-7", 927 | "request", 928 | "response" 929 | ], 930 | "support": { 931 | "source": "https://github.com/php-fig/http-message/tree/2.0" 932 | }, 933 | "time": "2023-04-04T09:54:51+00:00" 934 | }, 935 | { 936 | "name": "psr/log", 937 | "version": "2.0.0", 938 | "source": { 939 | "type": "git", 940 | "url": "https://github.com/php-fig/log.git", 941 | "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376" 942 | }, 943 | "dist": { 944 | "type": "zip", 945 | "url": "https://api.github.com/repos/php-fig/log/zipball/ef29f6d262798707a9edd554e2b82517ef3a9376", 946 | "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376", 947 | "shasum": "" 948 | }, 949 | "require": { 950 | "php": ">=8.0.0" 951 | }, 952 | "type": "library", 953 | "extra": { 954 | "branch-alias": { 955 | "dev-master": "2.0.x-dev" 956 | } 957 | }, 958 | "autoload": { 959 | "psr-4": { 960 | "Psr\\Log\\": "src" 961 | } 962 | }, 963 | "notification-url": "https://packagist.org/downloads/", 964 | "license": [ 965 | "MIT" 966 | ], 967 | "authors": [ 968 | { 969 | "name": "PHP-FIG", 970 | "homepage": "https://www.php-fig.org/" 971 | } 972 | ], 973 | "description": "Common interface for logging libraries", 974 | "homepage": "https://github.com/php-fig/log", 975 | "keywords": [ 976 | "log", 977 | "psr", 978 | "psr-3" 979 | ], 980 | "support": { 981 | "source": "https://github.com/php-fig/log/tree/2.0.0" 982 | }, 983 | "time": "2021-07-14T16:41:46+00:00" 984 | }, 985 | { 986 | "name": "ralouphie/getallheaders", 987 | "version": "3.0.3", 988 | "source": { 989 | "type": "git", 990 | "url": "https://github.com/ralouphie/getallheaders.git", 991 | "reference": "120b605dfeb996808c31b6477290a714d356e822" 992 | }, 993 | "dist": { 994 | "type": "zip", 995 | "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", 996 | "reference": "120b605dfeb996808c31b6477290a714d356e822", 997 | "shasum": "" 998 | }, 999 | "require": { 1000 | "php": ">=5.6" 1001 | }, 1002 | "require-dev": { 1003 | "php-coveralls/php-coveralls": "^2.1", 1004 | "phpunit/phpunit": "^5 || ^6.5" 1005 | }, 1006 | "type": "library", 1007 | "autoload": { 1008 | "files": [ 1009 | "src/getallheaders.php" 1010 | ] 1011 | }, 1012 | "notification-url": "https://packagist.org/downloads/", 1013 | "license": [ 1014 | "MIT" 1015 | ], 1016 | "authors": [ 1017 | { 1018 | "name": "Ralph Khattar", 1019 | "email": "ralph.khattar@gmail.com" 1020 | } 1021 | ], 1022 | "description": "A polyfill for getallheaders.", 1023 | "support": { 1024 | "issues": "https://github.com/ralouphie/getallheaders/issues", 1025 | "source": "https://github.com/ralouphie/getallheaders/tree/develop" 1026 | }, 1027 | "time": "2019-03-08T08:55:37+00:00" 1028 | }, 1029 | { 1030 | "name": "reload/jira-security-issue", 1031 | "version": "v2.0.2", 1032 | "source": { 1033 | "type": "git", 1034 | "url": "https://github.com/reload/jira-security-issue.git", 1035 | "reference": "dbc8433c10bf81ba576b58331c81814948ec5048" 1036 | }, 1037 | "dist": { 1038 | "type": "zip", 1039 | "url": "https://api.github.com/repos/reload/jira-security-issue/zipball/dbc8433c10bf81ba576b58331c81814948ec5048", 1040 | "reference": "dbc8433c10bf81ba576b58331c81814948ec5048", 1041 | "shasum": "" 1042 | }, 1043 | "require": { 1044 | "lesstif/php-jira-rest-client": "^5", 1045 | "php": ">=8.2.0", 1046 | "webignition/symfony-console-typed-input": "^0.6" 1047 | }, 1048 | "require-dev": { 1049 | "appocular/coding-standard": "^2.0", 1050 | "jangregor/phpstan-prophecy": "^1.0", 1051 | "phpspec/prophecy": "^1.15", 1052 | "phpspec/prophecy-phpunit": "^2.0", 1053 | "phpstan/extension-installer": "^1.3", 1054 | "phpstan/phpstan": "^1.10", 1055 | "phpunit/phpunit": "^11.0", 1056 | "sempro/phpunit-pretty-print": "^1.2", 1057 | "symfony/console": "^5.0" 1058 | }, 1059 | "type": "library", 1060 | "autoload": { 1061 | "psr-4": { 1062 | "Reload\\": "src/" 1063 | } 1064 | }, 1065 | "notification-url": "https://packagist.org/downloads/", 1066 | "license": [ 1067 | "MIT" 1068 | ], 1069 | "description": "Create Jira issues if it doesn't exist", 1070 | "support": { 1071 | "issues": "https://github.com/reload/jira-security-issue/issues", 1072 | "source": "https://github.com/reload/jira-security-issue/tree/v2.0.2" 1073 | }, 1074 | "time": "2024-09-24T06:10:54+00:00" 1075 | }, 1076 | { 1077 | "name": "softonic/graphql-client", 1078 | "version": "2.2.0", 1079 | "source": { 1080 | "type": "git", 1081 | "url": "https://github.com/softonic/graphql-client.git", 1082 | "reference": "462cfc5e301a417da3abbf237f6dee2e6d73b99e" 1083 | }, 1084 | "dist": { 1085 | "type": "zip", 1086 | "url": "https://api.github.com/repos/softonic/graphql-client/zipball/462cfc5e301a417da3abbf237f6dee2e6d73b99e", 1087 | "reference": "462cfc5e301a417da3abbf237f6dee2e6d73b99e", 1088 | "shasum": "" 1089 | }, 1090 | "require": { 1091 | "ext-json": "*", 1092 | "guzzlehttp/guzzle": "^6.3 || ^7.0", 1093 | "php": "^8.0", 1094 | "softonic/guzzle-oauth2-middleware": "^2.1", 1095 | "symfony/console": "^5.0 || ^6.0" 1096 | }, 1097 | "require-dev": { 1098 | "friendsofphp/php-cs-fixer": "^3.9", 1099 | "mockery/mockery": "^1.5", 1100 | "phpunit/phpunit": "^9.5", 1101 | "rector/rector": "^0.13.8", 1102 | "squizlabs/php_codesniffer": "^3.7" 1103 | }, 1104 | "bin": [ 1105 | "bin/graphql-client" 1106 | ], 1107 | "type": "library", 1108 | "autoload": { 1109 | "psr-4": { 1110 | "Softonic\\GraphQL\\": "src/" 1111 | } 1112 | }, 1113 | "notification-url": "https://packagist.org/downloads/", 1114 | "license": [ 1115 | "Apache-2.0" 1116 | ], 1117 | "description": "Softonic GraphQL client", 1118 | "homepage": "https://github.com/softonic/graphql-client", 1119 | "keywords": [ 1120 | "client", 1121 | "graphql", 1122 | "oauth2", 1123 | "softonic" 1124 | ], 1125 | "support": { 1126 | "issues": "https://github.com/softonic/graphql-client/issues", 1127 | "source": "https://github.com/softonic/graphql-client/tree/2.2.0" 1128 | }, 1129 | "time": "2022-10-04T15:56:13+00:00" 1130 | }, 1131 | { 1132 | "name": "softonic/guzzle-oauth2-middleware", 1133 | "version": "2.1.0", 1134 | "source": { 1135 | "type": "git", 1136 | "url": "https://github.com/softonic/guzzle-oauth2-middleware.git", 1137 | "reference": "2e4bea29c8331b6032acbf379e19c6bc5dc1be1e" 1138 | }, 1139 | "dist": { 1140 | "type": "zip", 1141 | "url": "https://api.github.com/repos/softonic/guzzle-oauth2-middleware/zipball/2e4bea29c8331b6032acbf379e19c6bc5dc1be1e", 1142 | "reference": "2e4bea29c8331b6032acbf379e19c6bc5dc1be1e", 1143 | "shasum": "" 1144 | }, 1145 | "require": { 1146 | "league/oauth2-client": "^2.2", 1147 | "php": ">=7.0", 1148 | "psr/cache": "^1.0|^2.0|^3.0" 1149 | }, 1150 | "require-dev": { 1151 | "friendsofphp/php-cs-fixer": "^2.4", 1152 | "phpunit/phpunit": "^6.0" 1153 | }, 1154 | "type": "library", 1155 | "autoload": { 1156 | "psr-4": { 1157 | "Softonic\\OAuth2\\Guzzle\\Middleware\\": "src/" 1158 | } 1159 | }, 1160 | "notification-url": "https://packagist.org/downloads/", 1161 | "license": [ 1162 | "Apache-2.0" 1163 | ], 1164 | "description": "Guzzle middleware with OAuth2 integration", 1165 | "homepage": "https://github.com/softonic/guzzle-oauth2-middleware", 1166 | "keywords": [ 1167 | "Guzzle", 1168 | "middleware", 1169 | "oauth2" 1170 | ], 1171 | "support": { 1172 | "issues": "https://github.com/softonic/guzzle-oauth2-middleware/issues", 1173 | "source": "https://github.com/softonic/guzzle-oauth2-middleware/tree/2.1.0" 1174 | }, 1175 | "time": "2022-07-11T08:44:18+00:00" 1176 | }, 1177 | { 1178 | "name": "symfony/console", 1179 | "version": "v5.4.44", 1180 | "source": { 1181 | "type": "git", 1182 | "url": "https://github.com/symfony/console.git", 1183 | "reference": "5b5a0aa66e3296e303e22490f90f521551835a83" 1184 | }, 1185 | "dist": { 1186 | "type": "zip", 1187 | "url": "https://api.github.com/repos/symfony/console/zipball/5b5a0aa66e3296e303e22490f90f521551835a83", 1188 | "reference": "5b5a0aa66e3296e303e22490f90f521551835a83", 1189 | "shasum": "" 1190 | }, 1191 | "require": { 1192 | "php": ">=7.2.5", 1193 | "symfony/deprecation-contracts": "^2.1|^3", 1194 | "symfony/polyfill-mbstring": "~1.0", 1195 | "symfony/polyfill-php73": "^1.9", 1196 | "symfony/polyfill-php80": "^1.16", 1197 | "symfony/service-contracts": "^1.1|^2|^3", 1198 | "symfony/string": "^5.1|^6.0" 1199 | }, 1200 | "conflict": { 1201 | "psr/log": ">=3", 1202 | "symfony/dependency-injection": "<4.4", 1203 | "symfony/dotenv": "<5.1", 1204 | "symfony/event-dispatcher": "<4.4", 1205 | "symfony/lock": "<4.4", 1206 | "symfony/process": "<4.4" 1207 | }, 1208 | "provide": { 1209 | "psr/log-implementation": "1.0|2.0" 1210 | }, 1211 | "require-dev": { 1212 | "psr/log": "^1|^2", 1213 | "symfony/config": "^4.4|^5.0|^6.0", 1214 | "symfony/dependency-injection": "^4.4|^5.0|^6.0", 1215 | "symfony/event-dispatcher": "^4.4|^5.0|^6.0", 1216 | "symfony/lock": "^4.4|^5.0|^6.0", 1217 | "symfony/process": "^4.4|^5.0|^6.0", 1218 | "symfony/var-dumper": "^4.4|^5.0|^6.0" 1219 | }, 1220 | "suggest": { 1221 | "psr/log": "For using the console logger", 1222 | "symfony/event-dispatcher": "", 1223 | "symfony/lock": "", 1224 | "symfony/process": "" 1225 | }, 1226 | "type": "library", 1227 | "autoload": { 1228 | "psr-4": { 1229 | "Symfony\\Component\\Console\\": "" 1230 | }, 1231 | "exclude-from-classmap": [ 1232 | "/Tests/" 1233 | ] 1234 | }, 1235 | "notification-url": "https://packagist.org/downloads/", 1236 | "license": [ 1237 | "MIT" 1238 | ], 1239 | "authors": [ 1240 | { 1241 | "name": "Fabien Potencier", 1242 | "email": "fabien@symfony.com" 1243 | }, 1244 | { 1245 | "name": "Symfony Community", 1246 | "homepage": "https://symfony.com/contributors" 1247 | } 1248 | ], 1249 | "description": "Eases the creation of beautiful and testable command line interfaces", 1250 | "homepage": "https://symfony.com", 1251 | "keywords": [ 1252 | "cli", 1253 | "command-line", 1254 | "console", 1255 | "terminal" 1256 | ], 1257 | "support": { 1258 | "source": "https://github.com/symfony/console/tree/v5.4.44" 1259 | }, 1260 | "funding": [ 1261 | { 1262 | "url": "https://symfony.com/sponsor", 1263 | "type": "custom" 1264 | }, 1265 | { 1266 | "url": "https://github.com/fabpot", 1267 | "type": "github" 1268 | }, 1269 | { 1270 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1271 | "type": "tidelift" 1272 | } 1273 | ], 1274 | "time": "2024-09-20T07:56:40+00:00" 1275 | }, 1276 | { 1277 | "name": "symfony/deprecation-contracts", 1278 | "version": "v3.5.0", 1279 | "source": { 1280 | "type": "git", 1281 | "url": "https://github.com/symfony/deprecation-contracts.git", 1282 | "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" 1283 | }, 1284 | "dist": { 1285 | "type": "zip", 1286 | "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", 1287 | "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", 1288 | "shasum": "" 1289 | }, 1290 | "require": { 1291 | "php": ">=8.1" 1292 | }, 1293 | "type": "library", 1294 | "extra": { 1295 | "branch-alias": { 1296 | "dev-main": "3.5-dev" 1297 | }, 1298 | "thanks": { 1299 | "name": "symfony/contracts", 1300 | "url": "https://github.com/symfony/contracts" 1301 | } 1302 | }, 1303 | "autoload": { 1304 | "files": [ 1305 | "function.php" 1306 | ] 1307 | }, 1308 | "notification-url": "https://packagist.org/downloads/", 1309 | "license": [ 1310 | "MIT" 1311 | ], 1312 | "authors": [ 1313 | { 1314 | "name": "Nicolas Grekas", 1315 | "email": "p@tchwork.com" 1316 | }, 1317 | { 1318 | "name": "Symfony Community", 1319 | "homepage": "https://symfony.com/contributors" 1320 | } 1321 | ], 1322 | "description": "A generic function and convention to trigger deprecation notices", 1323 | "homepage": "https://symfony.com", 1324 | "support": { 1325 | "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" 1326 | }, 1327 | "funding": [ 1328 | { 1329 | "url": "https://symfony.com/sponsor", 1330 | "type": "custom" 1331 | }, 1332 | { 1333 | "url": "https://github.com/fabpot", 1334 | "type": "github" 1335 | }, 1336 | { 1337 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1338 | "type": "tidelift" 1339 | } 1340 | ], 1341 | "time": "2024-04-18T09:32:20+00:00" 1342 | }, 1343 | { 1344 | "name": "symfony/polyfill-ctype", 1345 | "version": "v1.31.0", 1346 | "source": { 1347 | "type": "git", 1348 | "url": "https://github.com/symfony/polyfill-ctype.git", 1349 | "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" 1350 | }, 1351 | "dist": { 1352 | "type": "zip", 1353 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", 1354 | "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", 1355 | "shasum": "" 1356 | }, 1357 | "require": { 1358 | "php": ">=7.2" 1359 | }, 1360 | "provide": { 1361 | "ext-ctype": "*" 1362 | }, 1363 | "suggest": { 1364 | "ext-ctype": "For best performance" 1365 | }, 1366 | "type": "library", 1367 | "extra": { 1368 | "thanks": { 1369 | "name": "symfony/polyfill", 1370 | "url": "https://github.com/symfony/polyfill" 1371 | } 1372 | }, 1373 | "autoload": { 1374 | "files": [ 1375 | "bootstrap.php" 1376 | ], 1377 | "psr-4": { 1378 | "Symfony\\Polyfill\\Ctype\\": "" 1379 | } 1380 | }, 1381 | "notification-url": "https://packagist.org/downloads/", 1382 | "license": [ 1383 | "MIT" 1384 | ], 1385 | "authors": [ 1386 | { 1387 | "name": "Gert de Pagter", 1388 | "email": "BackEndTea@gmail.com" 1389 | }, 1390 | { 1391 | "name": "Symfony Community", 1392 | "homepage": "https://symfony.com/contributors" 1393 | } 1394 | ], 1395 | "description": "Symfony polyfill for ctype functions", 1396 | "homepage": "https://symfony.com", 1397 | "keywords": [ 1398 | "compatibility", 1399 | "ctype", 1400 | "polyfill", 1401 | "portable" 1402 | ], 1403 | "support": { 1404 | "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" 1405 | }, 1406 | "funding": [ 1407 | { 1408 | "url": "https://symfony.com/sponsor", 1409 | "type": "custom" 1410 | }, 1411 | { 1412 | "url": "https://github.com/fabpot", 1413 | "type": "github" 1414 | }, 1415 | { 1416 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1417 | "type": "tidelift" 1418 | } 1419 | ], 1420 | "time": "2024-09-09T11:45:10+00:00" 1421 | }, 1422 | { 1423 | "name": "symfony/polyfill-intl-grapheme", 1424 | "version": "v1.31.0", 1425 | "source": { 1426 | "type": "git", 1427 | "url": "https://github.com/symfony/polyfill-intl-grapheme.git", 1428 | "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" 1429 | }, 1430 | "dist": { 1431 | "type": "zip", 1432 | "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", 1433 | "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", 1434 | "shasum": "" 1435 | }, 1436 | "require": { 1437 | "php": ">=7.2" 1438 | }, 1439 | "suggest": { 1440 | "ext-intl": "For best performance" 1441 | }, 1442 | "type": "library", 1443 | "extra": { 1444 | "thanks": { 1445 | "name": "symfony/polyfill", 1446 | "url": "https://github.com/symfony/polyfill" 1447 | } 1448 | }, 1449 | "autoload": { 1450 | "files": [ 1451 | "bootstrap.php" 1452 | ], 1453 | "psr-4": { 1454 | "Symfony\\Polyfill\\Intl\\Grapheme\\": "" 1455 | } 1456 | }, 1457 | "notification-url": "https://packagist.org/downloads/", 1458 | "license": [ 1459 | "MIT" 1460 | ], 1461 | "authors": [ 1462 | { 1463 | "name": "Nicolas Grekas", 1464 | "email": "p@tchwork.com" 1465 | }, 1466 | { 1467 | "name": "Symfony Community", 1468 | "homepage": "https://symfony.com/contributors" 1469 | } 1470 | ], 1471 | "description": "Symfony polyfill for intl's grapheme_* functions", 1472 | "homepage": "https://symfony.com", 1473 | "keywords": [ 1474 | "compatibility", 1475 | "grapheme", 1476 | "intl", 1477 | "polyfill", 1478 | "portable", 1479 | "shim" 1480 | ], 1481 | "support": { 1482 | "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" 1483 | }, 1484 | "funding": [ 1485 | { 1486 | "url": "https://symfony.com/sponsor", 1487 | "type": "custom" 1488 | }, 1489 | { 1490 | "url": "https://github.com/fabpot", 1491 | "type": "github" 1492 | }, 1493 | { 1494 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1495 | "type": "tidelift" 1496 | } 1497 | ], 1498 | "time": "2024-09-09T11:45:10+00:00" 1499 | }, 1500 | { 1501 | "name": "symfony/polyfill-intl-normalizer", 1502 | "version": "v1.31.0", 1503 | "source": { 1504 | "type": "git", 1505 | "url": "https://github.com/symfony/polyfill-intl-normalizer.git", 1506 | "reference": "3833d7255cc303546435cb650316bff708a1c75c" 1507 | }, 1508 | "dist": { 1509 | "type": "zip", 1510 | "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", 1511 | "reference": "3833d7255cc303546435cb650316bff708a1c75c", 1512 | "shasum": "" 1513 | }, 1514 | "require": { 1515 | "php": ">=7.2" 1516 | }, 1517 | "suggest": { 1518 | "ext-intl": "For best performance" 1519 | }, 1520 | "type": "library", 1521 | "extra": { 1522 | "thanks": { 1523 | "name": "symfony/polyfill", 1524 | "url": "https://github.com/symfony/polyfill" 1525 | } 1526 | }, 1527 | "autoload": { 1528 | "files": [ 1529 | "bootstrap.php" 1530 | ], 1531 | "psr-4": { 1532 | "Symfony\\Polyfill\\Intl\\Normalizer\\": "" 1533 | }, 1534 | "classmap": [ 1535 | "Resources/stubs" 1536 | ] 1537 | }, 1538 | "notification-url": "https://packagist.org/downloads/", 1539 | "license": [ 1540 | "MIT" 1541 | ], 1542 | "authors": [ 1543 | { 1544 | "name": "Nicolas Grekas", 1545 | "email": "p@tchwork.com" 1546 | }, 1547 | { 1548 | "name": "Symfony Community", 1549 | "homepage": "https://symfony.com/contributors" 1550 | } 1551 | ], 1552 | "description": "Symfony polyfill for intl's Normalizer class and related functions", 1553 | "homepage": "https://symfony.com", 1554 | "keywords": [ 1555 | "compatibility", 1556 | "intl", 1557 | "normalizer", 1558 | "polyfill", 1559 | "portable", 1560 | "shim" 1561 | ], 1562 | "support": { 1563 | "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" 1564 | }, 1565 | "funding": [ 1566 | { 1567 | "url": "https://symfony.com/sponsor", 1568 | "type": "custom" 1569 | }, 1570 | { 1571 | "url": "https://github.com/fabpot", 1572 | "type": "github" 1573 | }, 1574 | { 1575 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1576 | "type": "tidelift" 1577 | } 1578 | ], 1579 | "time": "2024-09-09T11:45:10+00:00" 1580 | }, 1581 | { 1582 | "name": "symfony/polyfill-mbstring", 1583 | "version": "v1.31.0", 1584 | "source": { 1585 | "type": "git", 1586 | "url": "https://github.com/symfony/polyfill-mbstring.git", 1587 | "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" 1588 | }, 1589 | "dist": { 1590 | "type": "zip", 1591 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", 1592 | "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", 1593 | "shasum": "" 1594 | }, 1595 | "require": { 1596 | "php": ">=7.2" 1597 | }, 1598 | "provide": { 1599 | "ext-mbstring": "*" 1600 | }, 1601 | "suggest": { 1602 | "ext-mbstring": "For best performance" 1603 | }, 1604 | "type": "library", 1605 | "extra": { 1606 | "thanks": { 1607 | "name": "symfony/polyfill", 1608 | "url": "https://github.com/symfony/polyfill" 1609 | } 1610 | }, 1611 | "autoload": { 1612 | "files": [ 1613 | "bootstrap.php" 1614 | ], 1615 | "psr-4": { 1616 | "Symfony\\Polyfill\\Mbstring\\": "" 1617 | } 1618 | }, 1619 | "notification-url": "https://packagist.org/downloads/", 1620 | "license": [ 1621 | "MIT" 1622 | ], 1623 | "authors": [ 1624 | { 1625 | "name": "Nicolas Grekas", 1626 | "email": "p@tchwork.com" 1627 | }, 1628 | { 1629 | "name": "Symfony Community", 1630 | "homepage": "https://symfony.com/contributors" 1631 | } 1632 | ], 1633 | "description": "Symfony polyfill for the Mbstring extension", 1634 | "homepage": "https://symfony.com", 1635 | "keywords": [ 1636 | "compatibility", 1637 | "mbstring", 1638 | "polyfill", 1639 | "portable", 1640 | "shim" 1641 | ], 1642 | "support": { 1643 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" 1644 | }, 1645 | "funding": [ 1646 | { 1647 | "url": "https://symfony.com/sponsor", 1648 | "type": "custom" 1649 | }, 1650 | { 1651 | "url": "https://github.com/fabpot", 1652 | "type": "github" 1653 | }, 1654 | { 1655 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1656 | "type": "tidelift" 1657 | } 1658 | ], 1659 | "time": "2024-09-09T11:45:10+00:00" 1660 | }, 1661 | { 1662 | "name": "symfony/polyfill-php73", 1663 | "version": "v1.31.0", 1664 | "source": { 1665 | "type": "git", 1666 | "url": "https://github.com/symfony/polyfill-php73.git", 1667 | "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" 1668 | }, 1669 | "dist": { 1670 | "type": "zip", 1671 | "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", 1672 | "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", 1673 | "shasum": "" 1674 | }, 1675 | "require": { 1676 | "php": ">=7.2" 1677 | }, 1678 | "type": "library", 1679 | "extra": { 1680 | "thanks": { 1681 | "name": "symfony/polyfill", 1682 | "url": "https://github.com/symfony/polyfill" 1683 | } 1684 | }, 1685 | "autoload": { 1686 | "files": [ 1687 | "bootstrap.php" 1688 | ], 1689 | "psr-4": { 1690 | "Symfony\\Polyfill\\Php73\\": "" 1691 | }, 1692 | "classmap": [ 1693 | "Resources/stubs" 1694 | ] 1695 | }, 1696 | "notification-url": "https://packagist.org/downloads/", 1697 | "license": [ 1698 | "MIT" 1699 | ], 1700 | "authors": [ 1701 | { 1702 | "name": "Nicolas Grekas", 1703 | "email": "p@tchwork.com" 1704 | }, 1705 | { 1706 | "name": "Symfony Community", 1707 | "homepage": "https://symfony.com/contributors" 1708 | } 1709 | ], 1710 | "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", 1711 | "homepage": "https://symfony.com", 1712 | "keywords": [ 1713 | "compatibility", 1714 | "polyfill", 1715 | "portable", 1716 | "shim" 1717 | ], 1718 | "support": { 1719 | "source": "https://github.com/symfony/polyfill-php73/tree/v1.31.0" 1720 | }, 1721 | "funding": [ 1722 | { 1723 | "url": "https://symfony.com/sponsor", 1724 | "type": "custom" 1725 | }, 1726 | { 1727 | "url": "https://github.com/fabpot", 1728 | "type": "github" 1729 | }, 1730 | { 1731 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1732 | "type": "tidelift" 1733 | } 1734 | ], 1735 | "time": "2024-09-09T11:45:10+00:00" 1736 | }, 1737 | { 1738 | "name": "symfony/polyfill-php80", 1739 | "version": "v1.31.0", 1740 | "source": { 1741 | "type": "git", 1742 | "url": "https://github.com/symfony/polyfill-php80.git", 1743 | "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" 1744 | }, 1745 | "dist": { 1746 | "type": "zip", 1747 | "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", 1748 | "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", 1749 | "shasum": "" 1750 | }, 1751 | "require": { 1752 | "php": ">=7.2" 1753 | }, 1754 | "type": "library", 1755 | "extra": { 1756 | "thanks": { 1757 | "name": "symfony/polyfill", 1758 | "url": "https://github.com/symfony/polyfill" 1759 | } 1760 | }, 1761 | "autoload": { 1762 | "files": [ 1763 | "bootstrap.php" 1764 | ], 1765 | "psr-4": { 1766 | "Symfony\\Polyfill\\Php80\\": "" 1767 | }, 1768 | "classmap": [ 1769 | "Resources/stubs" 1770 | ] 1771 | }, 1772 | "notification-url": "https://packagist.org/downloads/", 1773 | "license": [ 1774 | "MIT" 1775 | ], 1776 | "authors": [ 1777 | { 1778 | "name": "Ion Bazan", 1779 | "email": "ion.bazan@gmail.com" 1780 | }, 1781 | { 1782 | "name": "Nicolas Grekas", 1783 | "email": "p@tchwork.com" 1784 | }, 1785 | { 1786 | "name": "Symfony Community", 1787 | "homepage": "https://symfony.com/contributors" 1788 | } 1789 | ], 1790 | "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", 1791 | "homepage": "https://symfony.com", 1792 | "keywords": [ 1793 | "compatibility", 1794 | "polyfill", 1795 | "portable", 1796 | "shim" 1797 | ], 1798 | "support": { 1799 | "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" 1800 | }, 1801 | "funding": [ 1802 | { 1803 | "url": "https://symfony.com/sponsor", 1804 | "type": "custom" 1805 | }, 1806 | { 1807 | "url": "https://github.com/fabpot", 1808 | "type": "github" 1809 | }, 1810 | { 1811 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1812 | "type": "tidelift" 1813 | } 1814 | ], 1815 | "time": "2024-09-09T11:45:10+00:00" 1816 | }, 1817 | { 1818 | "name": "symfony/service-contracts", 1819 | "version": "v3.5.0", 1820 | "source": { 1821 | "type": "git", 1822 | "url": "https://github.com/symfony/service-contracts.git", 1823 | "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" 1824 | }, 1825 | "dist": { 1826 | "type": "zip", 1827 | "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", 1828 | "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", 1829 | "shasum": "" 1830 | }, 1831 | "require": { 1832 | "php": ">=8.1", 1833 | "psr/container": "^1.1|^2.0", 1834 | "symfony/deprecation-contracts": "^2.5|^3" 1835 | }, 1836 | "conflict": { 1837 | "ext-psr": "<1.1|>=2" 1838 | }, 1839 | "type": "library", 1840 | "extra": { 1841 | "branch-alias": { 1842 | "dev-main": "3.5-dev" 1843 | }, 1844 | "thanks": { 1845 | "name": "symfony/contracts", 1846 | "url": "https://github.com/symfony/contracts" 1847 | } 1848 | }, 1849 | "autoload": { 1850 | "psr-4": { 1851 | "Symfony\\Contracts\\Service\\": "" 1852 | }, 1853 | "exclude-from-classmap": [ 1854 | "/Test/" 1855 | ] 1856 | }, 1857 | "notification-url": "https://packagist.org/downloads/", 1858 | "license": [ 1859 | "MIT" 1860 | ], 1861 | "authors": [ 1862 | { 1863 | "name": "Nicolas Grekas", 1864 | "email": "p@tchwork.com" 1865 | }, 1866 | { 1867 | "name": "Symfony Community", 1868 | "homepage": "https://symfony.com/contributors" 1869 | } 1870 | ], 1871 | "description": "Generic abstractions related to writing services", 1872 | "homepage": "https://symfony.com", 1873 | "keywords": [ 1874 | "abstractions", 1875 | "contracts", 1876 | "decoupling", 1877 | "interfaces", 1878 | "interoperability", 1879 | "standards" 1880 | ], 1881 | "support": { 1882 | "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" 1883 | }, 1884 | "funding": [ 1885 | { 1886 | "url": "https://symfony.com/sponsor", 1887 | "type": "custom" 1888 | }, 1889 | { 1890 | "url": "https://github.com/fabpot", 1891 | "type": "github" 1892 | }, 1893 | { 1894 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1895 | "type": "tidelift" 1896 | } 1897 | ], 1898 | "time": "2024-04-18T09:32:20+00:00" 1899 | }, 1900 | { 1901 | "name": "symfony/string", 1902 | "version": "v6.4.12", 1903 | "source": { 1904 | "type": "git", 1905 | "url": "https://github.com/symfony/string.git", 1906 | "reference": "f8a1ccebd0997e16112dfecfd74220b78e5b284b" 1907 | }, 1908 | "dist": { 1909 | "type": "zip", 1910 | "url": "https://api.github.com/repos/symfony/string/zipball/f8a1ccebd0997e16112dfecfd74220b78e5b284b", 1911 | "reference": "f8a1ccebd0997e16112dfecfd74220b78e5b284b", 1912 | "shasum": "" 1913 | }, 1914 | "require": { 1915 | "php": ">=8.1", 1916 | "symfony/polyfill-ctype": "~1.8", 1917 | "symfony/polyfill-intl-grapheme": "~1.0", 1918 | "symfony/polyfill-intl-normalizer": "~1.0", 1919 | "symfony/polyfill-mbstring": "~1.0" 1920 | }, 1921 | "conflict": { 1922 | "symfony/translation-contracts": "<2.5" 1923 | }, 1924 | "require-dev": { 1925 | "symfony/error-handler": "^5.4|^6.0|^7.0", 1926 | "symfony/http-client": "^5.4|^6.0|^7.0", 1927 | "symfony/intl": "^6.2|^7.0", 1928 | "symfony/translation-contracts": "^2.5|^3.0", 1929 | "symfony/var-exporter": "^5.4|^6.0|^7.0" 1930 | }, 1931 | "type": "library", 1932 | "autoload": { 1933 | "files": [ 1934 | "Resources/functions.php" 1935 | ], 1936 | "psr-4": { 1937 | "Symfony\\Component\\String\\": "" 1938 | }, 1939 | "exclude-from-classmap": [ 1940 | "/Tests/" 1941 | ] 1942 | }, 1943 | "notification-url": "https://packagist.org/downloads/", 1944 | "license": [ 1945 | "MIT" 1946 | ], 1947 | "authors": [ 1948 | { 1949 | "name": "Nicolas Grekas", 1950 | "email": "p@tchwork.com" 1951 | }, 1952 | { 1953 | "name": "Symfony Community", 1954 | "homepage": "https://symfony.com/contributors" 1955 | } 1956 | ], 1957 | "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", 1958 | "homepage": "https://symfony.com", 1959 | "keywords": [ 1960 | "grapheme", 1961 | "i18n", 1962 | "string", 1963 | "unicode", 1964 | "utf-8", 1965 | "utf8" 1966 | ], 1967 | "support": { 1968 | "source": "https://github.com/symfony/string/tree/v6.4.12" 1969 | }, 1970 | "funding": [ 1971 | { 1972 | "url": "https://symfony.com/sponsor", 1973 | "type": "custom" 1974 | }, 1975 | { 1976 | "url": "https://github.com/fabpot", 1977 | "type": "github" 1978 | }, 1979 | { 1980 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1981 | "type": "tidelift" 1982 | } 1983 | ], 1984 | "time": "2024-09-20T08:15:52+00:00" 1985 | }, 1986 | { 1987 | "name": "symfony/yaml", 1988 | "version": "v6.4.8", 1989 | "source": { 1990 | "type": "git", 1991 | "url": "https://github.com/symfony/yaml.git", 1992 | "reference": "52903de178d542850f6f341ba92995d3d63e60c9" 1993 | }, 1994 | "dist": { 1995 | "type": "zip", 1996 | "url": "https://api.github.com/repos/symfony/yaml/zipball/52903de178d542850f6f341ba92995d3d63e60c9", 1997 | "reference": "52903de178d542850f6f341ba92995d3d63e60c9", 1998 | "shasum": "" 1999 | }, 2000 | "require": { 2001 | "php": ">=8.1", 2002 | "symfony/deprecation-contracts": "^2.5|^3", 2003 | "symfony/polyfill-ctype": "^1.8" 2004 | }, 2005 | "conflict": { 2006 | "symfony/console": "<5.4" 2007 | }, 2008 | "require-dev": { 2009 | "symfony/console": "^5.4|^6.0|^7.0" 2010 | }, 2011 | "bin": [ 2012 | "Resources/bin/yaml-lint" 2013 | ], 2014 | "type": "library", 2015 | "autoload": { 2016 | "psr-4": { 2017 | "Symfony\\Component\\Yaml\\": "" 2018 | }, 2019 | "exclude-from-classmap": [ 2020 | "/Tests/" 2021 | ] 2022 | }, 2023 | "notification-url": "https://packagist.org/downloads/", 2024 | "license": [ 2025 | "MIT" 2026 | ], 2027 | "authors": [ 2028 | { 2029 | "name": "Fabien Potencier", 2030 | "email": "fabien@symfony.com" 2031 | }, 2032 | { 2033 | "name": "Symfony Community", 2034 | "homepage": "https://symfony.com/contributors" 2035 | } 2036 | ], 2037 | "description": "Loads and dumps YAML files", 2038 | "homepage": "https://symfony.com", 2039 | "support": { 2040 | "source": "https://github.com/symfony/yaml/tree/v6.4.8" 2041 | }, 2042 | "funding": [ 2043 | { 2044 | "url": "https://symfony.com/sponsor", 2045 | "type": "custom" 2046 | }, 2047 | { 2048 | "url": "https://github.com/fabpot", 2049 | "type": "github" 2050 | }, 2051 | { 2052 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2053 | "type": "tidelift" 2054 | } 2055 | ], 2056 | "time": "2024-05-31T14:49:08+00:00" 2057 | }, 2058 | { 2059 | "name": "webignition/symfony-console-typed-input", 2060 | "version": "0.6", 2061 | "source": { 2062 | "type": "git", 2063 | "url": "https://github.com/webignition/symfony-console-typed-input.git", 2064 | "reference": "ec4976828ef7647b00ae63ce47060cc035307fc1" 2065 | }, 2066 | "dist": { 2067 | "type": "zip", 2068 | "url": "https://api.github.com/repos/webignition/symfony-console-typed-input/zipball/ec4976828ef7647b00ae63ce47060cc035307fc1", 2069 | "reference": "ec4976828ef7647b00ae63ce47060cc035307fc1", 2070 | "shasum": "" 2071 | }, 2072 | "require": { 2073 | "php": ">=7.4|^8", 2074 | "symfony/console": "^4.4|^5.0" 2075 | }, 2076 | "require-dev": { 2077 | "mockery/mockery": "^1.4", 2078 | "phpstan/extension-installer": "^1.1", 2079 | "phpstan/phpstan": "^0.12.77", 2080 | "phpstan/phpstan-mockery": "^0.12.12", 2081 | "phpunit/phpunit": "^9.5", 2082 | "squizlabs/php_codesniffer": "^3.5", 2083 | "symplify/easy-coding-standard": "^9.1" 2084 | }, 2085 | "type": "library", 2086 | "autoload": { 2087 | "psr-4": { 2088 | "webignition\\SymfonyConsole\\TypedInput\\": "src/" 2089 | } 2090 | }, 2091 | "notification-url": "https://packagist.org/downloads/", 2092 | "license": [ 2093 | "MIT" 2094 | ], 2095 | "authors": [ 2096 | { 2097 | "name": "Jon Cram", 2098 | "email": "jon@webignition.net" 2099 | } 2100 | ], 2101 | "description": "Symfony InputInterface providing type-specific getters for options and arguments", 2102 | "homepage": "https://github.com/webignition/symfony-console-typed-input", 2103 | "keywords": [ 2104 | "console", 2105 | "input", 2106 | "inputinterface", 2107 | "symfony", 2108 | "type", 2109 | "typed" 2110 | ], 2111 | "support": { 2112 | "issues": "https://github.com/webignition/symfony-console-typed-input/issues", 2113 | "source": "https://github.com/webignition/symfony-console-typed-input/tree/0.6" 2114 | }, 2115 | "time": "2021-02-18T14:29:52+00:00" 2116 | } 2117 | ], 2118 | "packages-dev": [ 2119 | { 2120 | "name": "phpstan/extension-installer", 2121 | "version": "1.4.3", 2122 | "source": { 2123 | "type": "git", 2124 | "url": "https://github.com/phpstan/extension-installer.git", 2125 | "reference": "85e90b3942d06b2326fba0403ec24fe912372936" 2126 | }, 2127 | "dist": { 2128 | "type": "zip", 2129 | "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", 2130 | "reference": "85e90b3942d06b2326fba0403ec24fe912372936", 2131 | "shasum": "" 2132 | }, 2133 | "require": { 2134 | "composer-plugin-api": "^2.0", 2135 | "php": "^7.2 || ^8.0", 2136 | "phpstan/phpstan": "^1.9.0 || ^2.0" 2137 | }, 2138 | "require-dev": { 2139 | "composer/composer": "^2.0", 2140 | "php-parallel-lint/php-parallel-lint": "^1.2.0", 2141 | "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" 2142 | }, 2143 | "type": "composer-plugin", 2144 | "extra": { 2145 | "class": "PHPStan\\ExtensionInstaller\\Plugin" 2146 | }, 2147 | "autoload": { 2148 | "psr-4": { 2149 | "PHPStan\\ExtensionInstaller\\": "src/" 2150 | } 2151 | }, 2152 | "notification-url": "https://packagist.org/downloads/", 2153 | "license": [ 2154 | "MIT" 2155 | ], 2156 | "description": "Composer plugin for automatic installation of PHPStan extensions", 2157 | "keywords": [ 2158 | "dev", 2159 | "static analysis" 2160 | ], 2161 | "support": { 2162 | "issues": "https://github.com/phpstan/extension-installer/issues", 2163 | "source": "https://github.com/phpstan/extension-installer/tree/1.4.3" 2164 | }, 2165 | "time": "2024-09-04T20:21:43+00:00" 2166 | }, 2167 | { 2168 | "name": "phpstan/phpstan", 2169 | "version": "1.12.9", 2170 | "source": { 2171 | "type": "git", 2172 | "url": "https://github.com/phpstan/phpstan.git", 2173 | "reference": "ceb937fb39a92deabc02d20709cf14b2c452502c" 2174 | }, 2175 | "dist": { 2176 | "type": "zip", 2177 | "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ceb937fb39a92deabc02d20709cf14b2c452502c", 2178 | "reference": "ceb937fb39a92deabc02d20709cf14b2c452502c", 2179 | "shasum": "" 2180 | }, 2181 | "require": { 2182 | "php": "^7.2|^8.0" 2183 | }, 2184 | "conflict": { 2185 | "phpstan/phpstan-shim": "*" 2186 | }, 2187 | "bin": [ 2188 | "phpstan", 2189 | "phpstan.phar" 2190 | ], 2191 | "type": "library", 2192 | "autoload": { 2193 | "files": [ 2194 | "bootstrap.php" 2195 | ] 2196 | }, 2197 | "notification-url": "https://packagist.org/downloads/", 2198 | "license": [ 2199 | "MIT" 2200 | ], 2201 | "description": "PHPStan - PHP Static Analysis Tool", 2202 | "keywords": [ 2203 | "dev", 2204 | "static analysis" 2205 | ], 2206 | "support": { 2207 | "docs": "https://phpstan.org/user-guide/getting-started", 2208 | "forum": "https://github.com/phpstan/phpstan/discussions", 2209 | "issues": "https://github.com/phpstan/phpstan/issues", 2210 | "security": "https://github.com/phpstan/phpstan/security/policy", 2211 | "source": "https://github.com/phpstan/phpstan-src" 2212 | }, 2213 | "funding": [ 2214 | { 2215 | "url": "https://github.com/ondrejmirtes", 2216 | "type": "github" 2217 | }, 2218 | { 2219 | "url": "https://github.com/phpstan", 2220 | "type": "github" 2221 | } 2222 | ], 2223 | "time": "2024-11-10T17:10:04+00:00" 2224 | }, 2225 | { 2226 | "name": "phpstan/phpstan-deprecation-rules", 2227 | "version": "1.2.1", 2228 | "source": { 2229 | "type": "git", 2230 | "url": "https://github.com/phpstan/phpstan-deprecation-rules.git", 2231 | "reference": "f94d246cc143ec5a23da868f8f7e1393b50eaa82" 2232 | }, 2233 | "dist": { 2234 | "type": "zip", 2235 | "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/f94d246cc143ec5a23da868f8f7e1393b50eaa82", 2236 | "reference": "f94d246cc143ec5a23da868f8f7e1393b50eaa82", 2237 | "shasum": "" 2238 | }, 2239 | "require": { 2240 | "php": "^7.2 || ^8.0", 2241 | "phpstan/phpstan": "^1.12" 2242 | }, 2243 | "require-dev": { 2244 | "php-parallel-lint/php-parallel-lint": "^1.2", 2245 | "phpstan/phpstan-phpunit": "^1.0", 2246 | "phpunit/phpunit": "^9.5" 2247 | }, 2248 | "type": "phpstan-extension", 2249 | "extra": { 2250 | "phpstan": { 2251 | "includes": [ 2252 | "rules.neon" 2253 | ] 2254 | } 2255 | }, 2256 | "autoload": { 2257 | "psr-4": { 2258 | "PHPStan\\": "src/" 2259 | } 2260 | }, 2261 | "notification-url": "https://packagist.org/downloads/", 2262 | "license": [ 2263 | "MIT" 2264 | ], 2265 | "description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.", 2266 | "support": { 2267 | "issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues", 2268 | "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.2.1" 2269 | }, 2270 | "time": "2024-09-11T15:52:35+00:00" 2271 | }, 2272 | { 2273 | "name": "squizlabs/php_codesniffer", 2274 | "version": "3.11.2", 2275 | "source": { 2276 | "type": "git", 2277 | "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", 2278 | "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079" 2279 | }, 2280 | "dist": { 2281 | "type": "zip", 2282 | "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/1368f4a58c3c52114b86b1abe8f4098869cb0079", 2283 | "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079", 2284 | "shasum": "" 2285 | }, 2286 | "require": { 2287 | "ext-simplexml": "*", 2288 | "ext-tokenizer": "*", 2289 | "ext-xmlwriter": "*", 2290 | "php": ">=5.4.0" 2291 | }, 2292 | "require-dev": { 2293 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" 2294 | }, 2295 | "bin": [ 2296 | "bin/phpcbf", 2297 | "bin/phpcs" 2298 | ], 2299 | "type": "library", 2300 | "extra": { 2301 | "branch-alias": { 2302 | "dev-master": "3.x-dev" 2303 | } 2304 | }, 2305 | "notification-url": "https://packagist.org/downloads/", 2306 | "license": [ 2307 | "BSD-3-Clause" 2308 | ], 2309 | "authors": [ 2310 | { 2311 | "name": "Greg Sherwood", 2312 | "role": "Former lead" 2313 | }, 2314 | { 2315 | "name": "Juliette Reinders Folmer", 2316 | "role": "Current lead" 2317 | }, 2318 | { 2319 | "name": "Contributors", 2320 | "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" 2321 | } 2322 | ], 2323 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", 2324 | "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", 2325 | "keywords": [ 2326 | "phpcs", 2327 | "standards", 2328 | "static analysis" 2329 | ], 2330 | "support": { 2331 | "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", 2332 | "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", 2333 | "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", 2334 | "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" 2335 | }, 2336 | "funding": [ 2337 | { 2338 | "url": "https://github.com/PHPCSStandards", 2339 | "type": "github" 2340 | }, 2341 | { 2342 | "url": "https://github.com/jrfnl", 2343 | "type": "github" 2344 | }, 2345 | { 2346 | "url": "https://opencollective.com/php_codesniffer", 2347 | "type": "open_collective" 2348 | } 2349 | ], 2350 | "time": "2024-12-11T16:04:26+00:00" 2351 | } 2352 | ], 2353 | "aliases": [], 2354 | "minimum-stability": "stable", 2355 | "stability-flags": [], 2356 | "prefer-stable": false, 2357 | "prefer-lowest": false, 2358 | "platform": { 2359 | "php": ">=8.1" 2360 | }, 2361 | "platform-dev": [], 2362 | "plugin-api-version": "2.6.0" 2363 | } 2364 | -------------------------------------------------------------------------------- /docker-compose.override.example.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | services: 3 | 4 | ghsec-jira: 5 | environment: 6 | # Repo name (normally set automatically by the action) eg. 7 | # 'reload/github-security-jira'. 8 | GITHUB_REPOSITORY: reload/github-security-jira 9 | # GitHub URLs (normally set automatically by the action) 10 | GITHUB_GRAPHQL_URL: https://api.github.com/graphql 11 | GITHUB_SERVER_URL: https://github.com 12 | # In repos, this is the 'GitHubSecurityToken' secret. 13 | GH_SECURITY_TOKEN: github_pat 14 | # In repos, this is the 'JiraApiToken' secret. 15 | JIRA_TOKEN: jira_api_token 16 | JIRA_HOST: https://foo.atlassian.net 17 | JIRA_USER: someuser@reload.dk 18 | JIRA_PROJECT: TEST 19 | JIRA_ISSUE_TYPE: Bug 20 | JIRA_WATCHERS: |- 21 | someuser@reload.dk 22 | someotheruser@reload.dk 23 | JIRA_RESTRICTED_GROUP: Developers 24 | JIRA_RESTRICTED_COMMENT: |- 25 | Remember to evaluate severity here and set ticket priority. 26 | Check out the guide [in our wiki|https://foo.atlassian.net/wiki/]! 27 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | services: 3 | 4 | ghsec-jira: 5 | build: . 6 | volumes: 7 | - $PWD:/opt/ghsec-jira 8 | 9 | # For local development, use Composer via 'docker-compose run --rm composer 10 | # install'. 11 | composer: 12 | image: composer:1.9 13 | volumes: 14 | - $PWD:/app 15 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 8 3 | paths: 4 | - . 5 | excludePaths: 6 | - vendor 7 | -------------------------------------------------------------------------------- /src/PullRequestIssue.php: -------------------------------------------------------------------------------- 1 | $data 28 | */ 29 | public function __construct(array $data) 30 | { 31 | $this->package = \preg_filter('/.*Bump (.*) from.*/', '$1', $data['title']) ?? ''; 32 | $this->manifestPath = \preg_filter('/.* in \/(.*)/', '$1', $data['title']) ?? ''; 33 | $this->safeVersion = \preg_filter('/.*to ([^ ]+).*/', '$1', $data['title']) ?? ''; 34 | 35 | $githubRepo = \getenv('GITHUB_REPOSITORY') ?: ''; 36 | $githubUrl = \getenv('GITHUB_SERVER_URL') ?: 'https://github.com'; 37 | 38 | $body = <<package} 41 | - Secure version: {$this->safeVersion} 42 | - Pull request with more info: [#{$data['number']}|{$data['url']}] 43 | EOT; 44 | 45 | parent::__construct(); 46 | 47 | $this->setKeyLabel($githubRepo); 48 | $this->setKeyLabel($this->uniqueId()); 49 | $this->setKeyLabel("{$this->package}"); 50 | 51 | if ($this->manifestPath !== '') { 52 | $this->setKeyLabel("{$this->package}:{$this->manifestPath}"); 53 | } 54 | 55 | $this->setTitle("{$this->package} ({$this->safeVersion})"); 56 | $this->setBody($body); 57 | } 58 | 59 | /** 60 | * The unique ID of the severity. 61 | * 62 | * @return string 63 | */ 64 | public function uniqueId(): string 65 | { 66 | if ($this->manifestPath === '') { 67 | return "{$this->package}:{$this->safeVersion}"; 68 | } 69 | 70 | return "{$this->package}:{$this->manifestPath}:{$this->safeVersion}"; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/SecurityAlertIssue.php: -------------------------------------------------------------------------------- 1 | $data 55 | */ 56 | public function __construct(array $data) 57 | { 58 | // phpcs:enable SlevomatCodingStandard.TypeHints.DisallowMixedTypeHint.DisallowedMixedTypeHint 59 | $this->package = $data['securityVulnerability']['package']['name']; 60 | $this->safeVersion = $data['securityVulnerability']['firstPatchedVersion']['identifier'] ?? null; 61 | $this->vulnerableVersionRange = $data['securityVulnerability']['vulnerableVersionRange']; 62 | $this->manifestPath = \pathinfo($data['vulnerableManifestPath'], \PATHINFO_DIRNAME); 63 | $this->id = $data['securityVulnerability']['advisory']['ghsaId']; 64 | $this->severity = $data['securityVulnerability']['severity']; 65 | $this->alertNumber = $data['number']; 66 | $this->advisorySummary = $data['securityVulnerability']['advisory']['summary']; 67 | 68 | $references = []; 69 | 70 | foreach ($data['securityVulnerability']['advisory']['references'] as $ref) { 71 | if (!\array_key_exists('url', $ref) || !\is_string($ref['url'])) { 72 | continue; 73 | } 74 | 75 | $references[] = $ref['url']; 76 | } 77 | 78 | $advisory_description = \wordwrap($data['securityVulnerability']['advisory']['description'] ?? '', 100); 79 | $ecosystem = $data['securityVulnerability']['package']['ecosystem'] ?? ''; 80 | $githubRepo = \getenv('GITHUB_REPOSITORY') ?: ''; 81 | $githubUrl = \getenv('GITHUB_SERVER_URL') ?: 'https://github.com'; 82 | $safeVersion = $this->safeVersion ?? 'no fix'; 83 | 84 | $body = <<advisorySummary}|{$githubUrl}/{$githubRepo}/security/dependabot/{$this->alertNumber}] 87 | - Package: {$this->package} ($ecosystem) 88 | - Vulnerable version: {$this->vulnerableVersionRange} 89 | - Secure version: {$safeVersion} 90 | 91 | EOT; 92 | 93 | if (\is_array($references) && (\count($references) > 0)) { 94 | $body .= "- Links: \n-- " . \implode("\n-- ", $references); 95 | } 96 | 97 | $body .= <<setKeyLabel($githubRepo); 108 | $this->setKeyLabel($this->uniqueId()); 109 | $this->setTitle("{$this->package} ({$safeVersion}) - {$this->severity}"); 110 | $this->setBody($body); 111 | 112 | $labels = \getenv('JIRA_ISSUE_LABELS'); 113 | 114 | if (!$labels) { 115 | return; 116 | } 117 | 118 | foreach (\explode(',', $labels) as $label) { 119 | $this->setKeyLabel($label); 120 | } 121 | } 122 | 123 | /** 124 | * The unique ID of the severity. 125 | * 126 | * @return string 127 | */ 128 | public function uniqueId(): string 129 | { 130 | // If there is no safe version we use the GHSA ID as 131 | // identifier. If the security alert is later updated with a 132 | // known safe version a side effect of this is that a new Jira 133 | // issue will be created. We'll consider this a positive side 134 | // effect. 135 | $identifier = $this->safeVersion ?? $this->id; 136 | 137 | if ($this->manifestPath === '.') { 138 | return "{$this->package}:{$identifier}"; 139 | } 140 | 141 | return str_ireplace(" ", "_", "{$this->package}:{$this->manifestPath}:{$identifier}"); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/SyncCommand.php: -------------------------------------------------------------------------------- 1 | 31 | */ 32 | protected $requiredOptions = [ 33 | 'GITHUB_REPOSITORY', 34 | 'GH_SECURITY_TOKEN', 35 | 'JIRA_HOST', 36 | 'JIRA_USER', 37 | 'JIRA_TOKEN', 38 | 'JIRA_PROJECT', 39 | ]; 40 | 41 | /** 42 | * {@inheritDoc} 43 | */ 44 | public function __construct() 45 | { 46 | parent::__construct(); 47 | } 48 | 49 | /** 50 | * {@inheritDoc} 51 | */ 52 | protected function configure(): void 53 | { 54 | $this 55 | ->setDescription('Sync GitHub Alert status to Jira') 56 | ->setHelp('This command allows you to synchronize the security status from GitHub security alerts to Jira.') 57 | ->addOption( 58 | 'dry-run', 59 | null, 60 | InputOption::VALUE_NONE, 61 | 'Do dry run (dont change anything)', 62 | ); 63 | } 64 | 65 | /** 66 | * {@inheritDoc} 67 | * 68 | * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter 69 | */ 70 | protected function initialize(InputInterface $input, OutputInterface $output): void 71 | { 72 | // Validate config. 73 | $this->validateConfig(); 74 | } 75 | 76 | /** 77 | * {@inheritDoc} 78 | */ 79 | protected function execute(InputInterface $input, OutputInterface $output) 80 | { 81 | 82 | // Fetch alert data from GitHub. 83 | $alerts = $this->fetchAlertData(); 84 | 85 | if (!\is_array($alerts)) { 86 | $this->log($output, 'No alerts found.'); 87 | } 88 | 89 | $alertsFound = []; 90 | 91 | // Go through each alert and create a Jira issue if one does not exist. 92 | foreach ($alerts as $alert) { 93 | $issue = new SecurityAlertIssue($alert); 94 | 95 | $existingKey = $issue->exists(); 96 | 97 | if (!\is_null($existingKey)) { 98 | $this->log($output, "Existing issue {$existingKey} covers {$issue->uniqueId()}."); 99 | } elseif (!$input->getOption('dry-run')) { 100 | $key = $issue->ensure(); 101 | $this->log($output, "Created issue {$key} for {$issue->uniqueId()}."); 102 | } else { 103 | $this->log($output, "Would have created an issue for {$issue->uniqueId()} if not a dry run."); 104 | } 105 | 106 | $alertsFound[] = $issue->uniqueId(); 107 | } 108 | 109 | $pull_requests = $this->fetchPullRequestData(); 110 | 111 | foreach ($pull_requests as $pull_request) { 112 | $issue = new PullRequestIssue($pull_request['node']); 113 | 114 | if (\in_array($issue->uniqueId(), $alertsFound)) { 115 | continue; 116 | } 117 | 118 | $existingKey = $issue->exists(); 119 | 120 | if (!\is_null($existingKey)) { 121 | $this->log($output, "Existing issue {$existingKey} covers {$issue->uniqueId()}."); 122 | } elseif (!$input->getOption('dry-run')) { 123 | $key = $issue->ensure(); 124 | $this->log($output, "Created issue {$key} for {$issue->uniqueId()}."); 125 | } else { 126 | $this->log($output, "Would have created an issue for {$issue->uniqueId()} if not a dry run."); 127 | } 128 | } 129 | 130 | return 0; 131 | } 132 | 133 | /** 134 | * phpcs:disable SlevomatCodingStandard.TypeHints.DisallowMixedTypeHint.DisallowedMixedTypeHint 135 | * 136 | * Fetch alert data from GitHub. 137 | * 138 | * @return array 139 | */ 140 | protected function fetchAlertData(): array 141 | { 142 | // phpcs:enable SlevomatCodingStandard.TypeHints.DisallowMixedTypeHint.DisallowedMixedTypeHint 143 | $query = <<<'GQL' 144 | query alerts($owner: String!, $repo: String!) { 145 | repository(owner: $owner, name: $repo) { 146 | vulnerabilityAlerts(first: 100, states: OPEN) { 147 | nodes { 148 | securityVulnerability { 149 | advisory { 150 | ghsaId 151 | description 152 | identifiers { 153 | type 154 | value 155 | } 156 | references { 157 | url 158 | } 159 | severity 160 | summary 161 | } 162 | firstPatchedVersion { 163 | identifier 164 | } 165 | package { 166 | name 167 | ecosystem 168 | } 169 | severity 170 | updatedAt 171 | vulnerableVersionRange 172 | } 173 | repository { 174 | nameWithOwner 175 | } 176 | vulnerableManifestFilename 177 | vulnerableManifestPath 178 | vulnerableRequirements 179 | number 180 | } 181 | } 182 | } 183 | } 184 | GQL; 185 | 186 | $repo = \explode('/', \getenv('GITHUB_REPOSITORY') ?: ''); 187 | $variables = [ 188 | 'owner' => $repo[0], 189 | 'repo' => $repo[1], 190 | ]; 191 | 192 | $response = $this->getGHClient()->query($query, $variables); 193 | 194 | if ($response->hasErrors()) { 195 | $messages = \array_map(static function (array $error) { 196 | return $error['message']; 197 | }, $response->getErrors()); 198 | 199 | throw new RuntimeException( 200 | \sprintf('GraphQL client error: %s. Original query: %s', \implode(', ', $messages), $query), 201 | ); 202 | } 203 | 204 | // Drill down to the response data we want, if there. 205 | $alert_data = $response->getData(); 206 | 207 | return $alert_data['repository']['vulnerabilityAlerts']['nodes'] ?? []; 208 | } 209 | 210 | /** 211 | * Fetch Dependabot pull request data from GitHub. 212 | * 213 | * @return array>> 214 | */ 215 | protected function fetchPullRequestData(): array 216 | { 217 | $repo = \getenv('GITHUB_REPOSITORY'); 218 | $author = 'author:app/dependabot author:app/dependabot-preview'; 219 | 220 | $query = <<getGHClient()->query($query, $variables); 244 | 245 | if ($response->hasErrors()) { 246 | $messages = \array_map(static function (array $error) { 247 | return $error['message']; 248 | }, $response->getErrors()); 249 | 250 | throw new RuntimeException( 251 | \sprintf('GraphQL client error: %s. Original query: %s', \implode(', ', $messages), $query), 252 | ); 253 | } 254 | 255 | // Drill down to the response data we want, if there. 256 | $pr_data = $response->getData(); 257 | 258 | return $pr_data['search']['edges'] ?? []; 259 | } 260 | 261 | /** 262 | * Create the GraphQL client with supplied Bearer token. 263 | */ 264 | protected function getGHClient(): GraphQLClient 265 | { 266 | $access_token = \getenv('GH_SECURITY_TOKEN'); 267 | $graphql_url = \getenv('GITHUB_GRAPHQL_URL') ?: 'https://api.github.com/graphql'; 268 | return ClientBuilder::build($graphql_url, [ 269 | 'headers' => [ 270 | 'Accept' => 'application/json', 271 | 'Authorization' => "Bearer {$access_token}", 272 | ], 273 | ]); 274 | } 275 | 276 | /** 277 | * Validate the required options. 278 | */ 279 | protected function validateConfig(): void 280 | { 281 | foreach ($this->requiredOptions as $option) { 282 | $var = \getenv($option); 283 | 284 | if (!\is_string($var)) { 285 | throw new RuntimeException("Required env variable '{$option}' not set or empty."); 286 | } 287 | 288 | if (($option === 'GITHUB_REPOSITORY') && (\count(\explode('/', $var)) < 2)) { 289 | throw new RuntimeException('GitHub repository invalid: ' . \getenv('GITHUB_REPOSITORY')); 290 | } 291 | } 292 | } 293 | 294 | protected function log(OutputInterface $output, string $message): void 295 | { 296 | if ($output->getVerbosity() < OutputInterface::VERBOSITY_VERBOSE) { 297 | return; 298 | } 299 | 300 | $timestamp = \gmdate(\DATE_ATOM); 301 | $jira_project = \getenv('JIRA_PROJECT'); 302 | 303 | $output->writeln("{$timestamp} - {$jira_project} - {$message}"); 304 | } 305 | } 306 | --------------------------------------------------------------------------------