diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index f329996b91a25789e77a6cb2f3da06cad4f1b2ef..0000000000000000000000000000000000000000 --- a/.editorconfig +++ /dev/null @@ -1,29 +0,0 @@ -# https://EditorConfig.org - -root = true - -[*] -indent_style = space -# Reduce tab size on GitHub -indent_size = 4 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true -block_comment_start = /* -block_comment = * -block_comment_end = */ - -[{*.yml,*.yaml}] -indent_size = 2 - -[*.md] -trim_trailing_whitespace = false - -[Makefile] -indent_style = tab - -# Generated file -[infection.txt] -indent_size = unset -trim_trailing_whitespace = unset diff --git a/.gitattributes b/.gitattributes index de25e8fd72dbd0716f9370206a6b4b83c075e456..cea09fccdf7c684b0c3a5135ae68018a3f159d0d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,14 +3,14 @@ /.github export-ignore /doc export-ignore /tests export-ignore -/.editorconfig export-ignore /.gitattributes export-ignore /.gitignore export-ignore /CODE_OF_CONDUCT.md export-ignore -/deptrac.yaml export-ignore /ecs.php export-ignore /infection.json.dist export-ignore /Makefile export-ignore /phpstan.neon export-ignore /phpunit.xml.dist export-ignore +/README.md export-ignore /rector.php export-ignore +/SECURITY.md export-ignore diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 7cc67ce37ec5684052f27eb1b416515a419804d7..2b7c6aaa23db70c557a54a3c50e7ad45d8b1f7fd 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -11,14 +11,9 @@ Few rules to ease code reviews and merges: - You MUST write (or update) unit tests when bugs are fixed or features are added. - You SHOULD write documentation. -We use [Git-Flow](http://jeffkreeftmeijer.com/2010/why-arent-you-using-git-flow/) to automate our git branching -workflow. +To contribute use [Pull Requests](https://help.github.com/articles/using-pull-requests), please, write commit messages that make sense, and rebase your branch before submitting your PR. -To contribute use [Pull Requests](https://help.github.com/articles/using-pull-requests), please, write commit messages -that make sense, and rebase your branch before submitting your PR. - -May be asked to squash your commits too. This is used to "clean" your Pull Request before merging it, avoiding commits -such as fix tests, fix 2, fix 3, etc. +May be asked to squash your commits too. This is used to "clean" your Pull Request before merging it, avoiding commits such as fix tests, fix 2, fix 3, etc. Run test suite ------------ @@ -26,3 +21,7 @@ Run test suite * install composer: `curl -s http://getcomposer.org/installer | php` * install dependencies: `php composer.phar install` * run tests: `vendor/bin/phpunit` +* check and fix coding standards: + * `vendor/bin/phpstan analyse` + * `vendor/bin/rector process` + * `vendor/bin/ecs check --fix` diff --git a/.github/ISSUE_TEMPLATE/1_Bug_report.yaml b/.github/ISSUE_TEMPLATE/1_Bug_report.yaml index d3f26cf6bd326766d4222d2889b286c5de38be15..841cfdc01291a0ce2c7febbf5d53745c5ccb6ec7 100644 --- a/.github/ISSUE_TEMPLATE/1_Bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/1_Bug_report.yaml @@ -1,42 +1,43 @@ name: 🛠Bug Report description: âš ï¸ NEVER report security issues, email security AT spomky-labs.com instead labels: Bug + body: - - type: input - id: affected-versions - attributes: - label: Version(s) affected - placeholder: x.y.z - validations: - required: true - - type: textarea - id: description - attributes: - label: Description - description: A clear and concise description of the problem - validations: - required: true - - type: textarea - id: how-to-reproduce - attributes: - label: How to reproduce - description: | - âš ï¸ This is the most important part of the report âš ï¸ - Without a way to easily reproduce your issue, there is little chance we will be able to help you and work on a fix. - Please, take the time to show us some code and/or config that is needed for others to reproduce the problem easily. - Most of the time, creating a "bug reproducer" is the best way to help us and increases the chances someone - will have a look at it. - validations: - required: true - - type: textarea - id: possible-solution - attributes: - label: Possible Solution - description: | - Optional: only if you have suggestions on a fix/reason for the bug - Don't hesitate to create a pull request with your solution, it helps get faster feedback. - - type: textarea - id: additional-context - attributes: - label: Additional Context - description: "Optional: any other context about the problem: log messages, screenshots, etc." + - type: input + id: affected-versions + attributes: + label: Version(s) affected + placeholder: x.y.z + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + description: A clear and concise description of the problem + validations: + required: true + - type: textarea + id: how-to-reproduce + attributes: + label: How to reproduce + description: | + âš ï¸ This is the most important part of the report âš ï¸ + Without a way to easily reproduce your issue, there is little chance we will be able to help you and work on a fix. + Please, take the time to show us some code and/or config that is needed for others to reproduce the problem easily. + Most of the time, creating a "bug reproducer" is the best way to help us and increases the chances someone + will have a look at it. + validations: + required: true + - type: textarea + id: possible-solution + attributes: + label: Possible Solution + description: | + Optional: only if you have suggestions on a fix/reason for the bug + Don't hesitate to create a pull request with your solution, it helps get faster feedback. + - type: textarea + id: additional-context + attributes: + label: Additional Context + description: "Optional: any other context about the problem: log messages, screenshots, etc." diff --git a/.github/ISSUE_TEMPLATE/2_Feature_request.yaml b/.github/ISSUE_TEMPLATE/2_Feature_request.yaml index 52b3de7906c281f6e7026a0fb807ea171013ab2f..bd300eb1e82b265ed3b47052863d05504e029a75 100644 --- a/.github/ISSUE_TEMPLATE/2_Feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/2_Feature_request.yaml @@ -1,17 +1,17 @@ name: 🚀 Feature Request description: RFC and ideas for new features and improvements body: - - type: textarea - id: description - attributes: - label: Description - description: A clear and concise description of the new feature - validations: - required: true - - type: textarea - id: example - attributes: - label: Example - description: | - A simple example of the new feature in action (include PHP code, YAML config, etc.) - If the new feature changes an existing feature, include a simple before/after comparison. + - type: textarea + id: description + attributes: + label: Description + description: A clear and concise description of the new feature + validations: + required: true + - type: textarea + id: example + attributes: + label: Example + description: | + A simple example of the new feature in action (include PHP code, YAML config, etc.) + If the new feature changes an existing feature, include a simple before/after comparison. diff --git a/.github/ISSUE_TEMPLATE/3_Documentation.yaml b/.github/ISSUE_TEMPLATE/3_Documentation.yaml index 1c5ac8989090261cb0150b400740dfe255226e0a..7a3dc1785d3ccbfe76cb1f3dc596ce18fb39e8d1 100644 --- a/.github/ISSUE_TEMPLATE/3_Documentation.yaml +++ b/.github/ISSUE_TEMPLATE/3_Documentation.yaml @@ -1,10 +1,10 @@ name: 📖 Documentation Issue description: To report typo or obsolete section in the documentation body: - - type: textarea - id: description - attributes: - label: Description - description: A clear and concise description of the error you found in the documentation - validations: - required: true + - type: textarea + id: description + attributes: + label: Description + description: A clear and concise description of the error you found in the documentation + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 6d11ce273e77fdb97b79626a96f290ee5e4efea7..11812417c42426de5865c54614713516f84fadfb 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,5 @@ blank_issues_enabled: false contact_links: - - name: Support Question - url: https://spomky-labs.com/contact/ - about:| - We use GitHub issues only to discuss about bugs and new features. - For this kind of questions about using the framework or third-party bundles, - please email us contact AT spomky-labs.com for quoting + - name: Support Question + url: https://spomky-labs.com/contact/ + about: We use GitHub issues only to discuss about bugs and new features. For this kind of questions about using the library, please use Stackoverflow (or similar) or send a quote request at https://spomky-labs.com/contact/ diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 029817b6263c90e8cae54c264ed9b581dc7695be..1beb0a38bf47c49a64411a94f142854476051755 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,17 +1,19 @@ -Target branch: -Resolves issue # <!-- #-prefixed issue number(s), if any --> - -<!-- replace space with "x" in square brackets: [x] --> -- [ ] It is a Bug fix -- [ ] It is a New feature -- [ ] Breaks BC -- [ ] Includes Deprecations - +| Q | A +| ------------- | --- +| Branch? | <!-- see below --> +| Bug fix? | yes/no +| New feature? | yes/no <!-- please update src/**/CHANGELOG.md files --> +| Deprecations? | yes/no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> +| Tickets | Fix #... <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead --> +| License | MIT <!-- -Fill in this template according to the PR you're about to submit. -Replace this comment by a description of what your PR is solving. +Replace this notice by a short README for your feature/bugfix. This will help people +understand your PR and can be used as a start for the documentation. -Please consider the following requirement: -* Modification of existing tests should be avoided unless deemed necessary. -* You MUST never open a PR related to a security issue. Contact Spomky in private at https://gitter.im/Spomky/ ---> +Additionally: + - Always add tests and ensure they pass. + - Never break backward compatibility (unless you are working on the next major release branch). + - Bug fixes must be submitted against the lowest maintained branch where they apply + (lowest branches are regularly merged to upper ones so they get the fixes too.) + - Features and deprecations must be submitted against the last major branch (e.g. 1.x). +--> \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ae2faa417ae57237adbb29eb1eb53cb8ef000336..75436e42b0ab812b010b6dd6900713672891f104 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,19 +1,8 @@ version: 2 updates: - - package-ecosystem: "composer" - directory: "/" - schedule: - interval: "weekly" - day: "friday" - versioning-strategy: "widen" - open-pull-requests-limit: 20 - allow: - - dependency-type: all - labels: [ "Dependencies" ] - - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "monthly" - open-pull-requests-limit: 20 - labels: [ "Dependencies" ] +- package-ecosystem: composer + directory: "/" + schedule: + interval: daily + time: "11:00" + open-pull-requests-limit: 10 diff --git a/.github/stale.yml b/.github/stale.yml index 19367a6a66f45bdb6ab276746ba86ad6c24b1c70..98284be67bc99e9f9ca7af7ac4fc2de3790f88dd 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,8 +1,8 @@ -daysUntilStale: 30 +daysUntilStale: 60 daysUntilClose: 7 staleLabel: wontfix markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. + Ce problème a été automatiquement marqué comme périmé car il n'a pas eu + d’activité récente. Il sera fermé dans 7 jours si aucune autre activité ne se produit. Merci + pour votre contribution. closeComment: false diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml new file mode 100644 index 0000000000000000000000000000000000000000..584b524ce46cc9e56a98ab466981028fd1b56fa4 --- /dev/null +++ b/.github/workflows/coding-standards.yml @@ -0,0 +1,32 @@ +name: Coding Standards + +on: [push] + +jobs: + tests: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + operating-system: [ubuntu-latest] + php-versions: ['8.1'] + name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring + coverage: xdebug + + - name: Install the application + run: | + composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Coding Standards Checks + run: make ci-cs diff --git a/.github/workflows/gitsplit.yml b/.github/workflows/gitsplit.yml deleted file mode 100644 index 0677186146e18ffb9945395f32bef380013f184f..0000000000000000000000000000000000000000 --- a/.github/workflows/gitsplit.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: gitsplit -on: - push: - tags: - - '*' - release: - types: [ published ] - -jobs: - gitsplit: - runs-on: ubuntu-latest - steps: - - name: checkout - run: git clone https://github.com/web-auth/webauthn-framework /home/runner/work/web-auth/webauthn-framework && cd /home/runner/work/web-auth/webauthn-framework - - name: Split repositories - run: docker run --rm -t -e GH_TOKEN -v /cache/gitsplit:/cache/gitsplit -v /home/runner/work/web-auth/webauthn-framework:/srv jderusse/gitsplit gitsplit - env: - GH_TOKEN: ${{ secrets.GITSPLIT_TOKEN }} diff --git a/.github/workflows/integrate.yml b/.github/workflows/integrate.yml deleted file mode 100644 index 5578d067d87b6f454244bb516fde95d3eaf7137c..0000000000000000000000000000000000000000 --- a/.github/workflows/integrate.yml +++ /dev/null @@ -1,230 +0,0 @@ -# yaml-language-server: $schema=https://json.schemastore.org/github-workflow - -name: "Integrate" - -on: - push: - branches: - - "*.x" - pull_request: null - -jobs: - byte_level: - name: "0ï¸âƒ£ Byte-level" - runs-on: "ubuntu-latest" - steps: - - name: "Checkout code" - uses: "actions/checkout@v3" - - - name: "Check file permissions" - run: | - test "$(find . -type f -not -path './.git/*' -executable)" == "" - - - name: "Find non-printable ASCII characters" - run: | - ! LC_ALL=C.UTF-8 find . -type f -name "*.php" -print0 | xargs -0 -- grep -PHn "[^ -~]" - - syntax_errors: - name: "1ï¸âƒ£ Syntax errors" - runs-on: "ubuntu-latest" - steps: - - name: "Set up PHP" - uses: "shivammathur/setup-php@v2" - with: - php-version: "8.1" - coverage: "none" - - - name: "Checkout code" - uses: "actions/checkout@v3" - - - name: "Install dependencies" - uses: "ramsey/composer-install@v2" - with: - dependency-versions: "highest" - - - name: "Check source code for syntax errors" - run: "composer exec -- parallel-lint src/ tests/" - - unit_tests: - name: "2ï¸âƒ£ Unit and functional tests" - needs: - - "byte_level" - - "syntax_errors" - strategy: - matrix: - operating-system: - - "ubuntu-latest" - php-version: - - "8.1" - dependencies: - - "lowest" - - "highest" - runs-on: ${{ matrix.operating-system }} - steps: - - name: "Set up PHP" - uses: "shivammathur/setup-php@v2" - with: - php-version: "${{ matrix.php-version }}" - extensions: "mbstring" - coverage: "xdebug" - - - name: "Checkout code" - uses: "actions/checkout@v3" - - - name: "Install dependencies" - uses: "ramsey/composer-install@v2" - with: - dependency-versions: "${{ matrix.dependencies }}" - composer-options: "--optimize-autoloader" - - - name: "Execute tests (PHP)" - run: "make ci-cc" - - # - name: Send coverage to Coveralls - # if: "matrix.php-version == '8.1' && matrix.dependencies == 'highest'" - # env: - # COVERALLS_REPO_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - # run: | - # wget "https://github.com/php-coveralls/php-coveralls/releases/download/v2.5.2/php-coveralls.phar" - # php ./php-coveralls.phar -v - - static_analysis: - name: "3ï¸âƒ£ Static Analysis" - needs: - - "byte_level" - - "syntax_errors" - runs-on: "ubuntu-latest" - steps: - - name: "Set up PHP" - uses: "shivammathur/setup-php@v2" - with: - php-version: "8.1" - extensions: "mbstring" - coverage: "none" - - - name: "Checkout code" - uses: "actions/checkout@v3" - - - name: "Validate Composer configuration" - run: "composer validate --strict" - - - name: "Install dependencies" - uses: "ramsey/composer-install@v2" - with: - dependency-versions: "highest" - composer-options: "--optimize-autoloader" - - - name: "Check PSR-4 mapping" - run: "composer dump-autoload --optimize --strict-psr" - - - name: "Execute static analysis" - run: "make st" - - coding_standards: - name: "4ï¸âƒ£ Coding Standards" - needs: - - "byte_level" - - "syntax_errors" - runs-on: "ubuntu-latest" - steps: - - name: "Set up PHP" - uses: "shivammathur/setup-php@v2" - with: - php-version: "8.1" - extensions: "mbstring" - coverage: "none" - - - name: "Checkout code" - uses: "actions/checkout@v3" - - - name: "Check adherence to EditorConfig" - uses: "greut/eclint-action@v0" - - - name: "Install dependencies" - uses: "ramsey/composer-install@v2" - with: - dependency-versions: "highest" - composer-options: "--optimize-autoloader" - - - name: "Check coding style" - run: "make ci-cs" - - - name: "Deptrac" - run: | - vendor/bin/deptrac analyse --fail-on-uncovered --no-cache - - mutation_testing: - name: "5ï¸âƒ£ Mutation Testing" - needs: - - "byte_level" - - "syntax_errors" - runs-on: "ubuntu-latest" - steps: - - name: "Set up PHP" - uses: "shivammathur/setup-php@v2" - with: - php-version: "8.1" - extensions: "mbstring" - coverage: "xdebug" - - - name: "Checkout code" - uses: "actions/checkout@v3" - - - name: "Fetch Git base reference" - run: "git fetch --depth=1 origin ${GITHUB_BASE_REF}" - - - name: "Install dependencies" - uses: "ramsey/composer-install@v2" - with: - dependency-versions: "highest" - composer-options: "--optimize-autoloader" - - - name: "Execute Infection" - run: "make ci-mu" - - rector_checkstyle: - name: "6ï¸âƒ£ Rector Checkstyle" - needs: - - "byte_level" - - "syntax_errors" - runs-on: "ubuntu-latest" - steps: - - name: "Set up PHP" - uses: "shivammathur/setup-php@v2" - with: - php-version: "8.1" - extensions: "mbstring" - coverage: "xdebug" - - - name: "Checkout code" - uses: "actions/checkout@v3" - - - name: "Fetch Git base reference" - run: "git fetch --depth=1 origin ${GITHUB_BASE_REF}" - - - name: "Install dependencies" - uses: "ramsey/composer-install@v2" - with: - dependency-versions: "highest" - composer-options: "--optimize-autoloader" - - - name: "Execute Rector" - run: "make rector" - - exported_files: - name: "7ï¸âƒ£ Exported files" - needs: - - "byte_level" - - "syntax_errors" - runs-on: "ubuntu-20.04" - steps: - - name: "Checkout code" - uses: "actions/checkout@v3" - - - name: "Check exported files" - run: | - EXPECTED="LICENSE,README.md,SECURITY.md,composer.json" - CURRENT="$(git archive HEAD | tar --list --exclude="src" --exclude="src/*" | paste -s -d ",")" - echo "CURRENT =${CURRENT}" - echo "EXPECTED=${EXPECTED}" - test "${CURRENT}" == "${EXPECTED}" diff --git a/.github/workflows/merge-me.yml b/.github/workflows/merge-me.yml deleted file mode 100644 index 77e8f7d83cc29957995a5d829508963a61af19e7..0000000000000000000000000000000000000000 --- a/.github/workflows/merge-me.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Merge me! - -on: - check_suite: - types: - - completed - -jobs: - merge-me: - name: Merge me! - runs-on: ubuntu-latest - steps: - - name: Merge me! - uses: ridedott/merge-me-action@v2.10.19 - with: - # Depending on branch protection rules, a manually populated - # `GITHUB_TOKEN_WORKAROUND` environment variable with permissions to - # push to a protected branch must be used. This variable can have an - # arbitrary name, as an example, this repository uses - # `GITHUB_TOKEN_DOTTBOTT`. - # - # When using a custom token, it is recommended to leave the following - # comment for other developers to be aware of the reasoning behind it: - # - # This must be used as GitHub Actions token does not support - # pushing to protected branches. - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - MERGE_METHOD: MERGE diff --git a/.github/workflows/mutation-tests.yml b/.github/workflows/mutation-tests.yml new file mode 100644 index 0000000000000000000000000000000000000000..2277a9821695e58b1b6aee7a8c6316725d335bdd --- /dev/null +++ b/.github/workflows/mutation-tests.yml @@ -0,0 +1,35 @@ +name: Mutation Testing + +on: [push] + +jobs: + tests: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + operating-system: [ubuntu-latest] + php-versions: ['8.1'] + name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring + coverage: xdebug + + - name: Install the application + run: | + composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Fetch Git base reference + run: git fetch --depth=1 origin $GITHUB_BASE_REF + + - name: Infection + run: make ci-mu diff --git a/.github/workflows/rector_checkstyle.yaml b/.github/workflows/rector_checkstyle.yaml new file mode 100644 index 0000000000000000000000000000000000000000..53f8d36d08fb46b719bead12c8902ca0fd68b9d8 --- /dev/null +++ b/.github/workflows/rector_checkstyle.yaml @@ -0,0 +1,30 @@ +name: Rector Checkstyle + +on: [push] + +jobs: + tests: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + operating-system: [ ubuntu-latest ] + php-versions: ['8.1'] + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring + coverage: none + + - name: Install the application + run: | + composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Rector + run: make ci-rector diff --git a/.github/workflows/release-on-milestone-closed.yml b/.github/workflows/release-on-milestone-closed.yml deleted file mode 100644 index babdc0922c9f4fe1dfb6a8db7a34eaa2e2af3cb2..0000000000000000000000000000000000000000 --- a/.github/workflows/release-on-milestone-closed.yml +++ /dev/null @@ -1,72 +0,0 @@ -# https://help.github.com/en/categories/automating-your-workflow-with-github-actions - -name: "Automatic Releases" - -on: - milestone: - types: - - "closed" - -jobs: - release: - name: "GIT tag, release & create merge-up PR" - runs-on: ubuntu-latest - - steps: - - name: "Checkout" - uses: "actions/checkout@v3" - - - name: "Release" - uses: "laminas/automatic-releases@1.17.0" - with: - command-name: "laminas:automatic-releases:release" - env: - "SHELL_VERBOSITY": "3" - "GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }} - "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} - "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} - "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} - - - name: "Create Merge-Up Pull Request" - uses: "laminas/automatic-releases@1.17.0" - with: - command-name: "laminas:automatic-releases:create-merge-up-pull-request" - env: - "SHELL_VERBOSITY": "3" - "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} - "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} - "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} - "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} - - - name: "Create and/or Switch to new Release Branch" - uses: "laminas/automatic-releases@1.17.0" - with: - command-name: "laminas:automatic-releases:switch-default-branch-to-next-minor" - env: - "SHELL_VERBOSITY": "3" - "GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }} - "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} - "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} - "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} - - - name: "Bump Changelog Version On Originating Release Branch" - uses: "laminas/automatic-releases@1.17.0" - with: - command-name: "laminas:automatic-releases:bump-changelog" - env: - "SHELL_VERBOSITY": "3" - "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} - "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} - "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} - "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} - - - name: "Create new milestones" - uses: "laminas/automatic-releases@1.17.0" - with: - command-name: "laminas:automatic-releases:create-milestones" - env: - "SHELL_VERBOSITY": "3" - "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} - "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} - "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} - "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} diff --git a/.github/workflows/static-analyze.yml b/.github/workflows/static-analyze.yml new file mode 100644 index 0000000000000000000000000000000000000000..91154b0e13913726c515274becbcb619c61a1bf9 --- /dev/null +++ b/.github/workflows/static-analyze.yml @@ -0,0 +1,33 @@ +name: Static Analyze + +on: [push] + +jobs: + tests: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + operating-system: [ubuntu-latest] + php-versions: ['8.1'] + name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring + coverage: xdebug + tools: cs2pr + + - name: Install the application + run: | + composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Static Analyze Checks + run: make ci-st diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000000000000000000000000000000000000..71f18a43e684c2c355968d7db0fae5a3e93a3a72 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,32 @@ +name: Unit and Functional Tests + +on: [push] + +jobs: + tests: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + operating-system: [ ubuntu-latest ] + php-versions: ['8.1'] + name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring + coverage: xdebug + + - name: Install the application + run: | + composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Run tests + run: make all diff --git a/.github/workflows/tweet.yml b/.github/workflows/tweet.yml deleted file mode 100644 index 5f9acda82cd397e7de43686a03098f9aad8c1497..0000000000000000000000000000000000000000 --- a/.github/workflows/tweet.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: tweet -on: - push: - tags: - - '*' - release: - types: [ published ] - -jobs: - tweet: - runs-on: ubuntu-latest - steps: - - name: Tweet - uses: snow-actions/tweet@v1.3.0 - with: - status: | - We are proud to announce that ${{ github.repository }} · ${{ github.event.release.name }} - ${{ github.event.release.html_url }} is now released 🚀. #php #totp #hotp - env: - CONSUMER_API_KEY: ${{ secrets.TWITTER_CONSUMER_API_KEY }} - CONSUMER_API_SECRET_KEY: ${{ secrets.TWITTER_CONSUMER_API_SECRET }} - ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }} - ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} diff --git a/.gitignore b/.gitignore index 757b91777eaaac28819f56de5cef5409b02f04e0..9c4be60124746b4808e407cdd1c266e02c05bad0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ /vendor/ .phpunit.result.cache /phpunit.xml -/infection.log +/infection.log \ No newline at end of file diff --git a/Makefile b/Makefile index 159530a0bd3f58d94b32ef052b65be165a7d55fb..529b80e141bd5e11bca40138e60cab25f6600b9c 100644 --- a/Makefile +++ b/Makefile @@ -1,69 +1,63 @@ ######################## -# Everyday # +# CI/CD # ######################## -.PHONY: mu -mu: vendor ## Mutation tests - vendor/bin/infection -s --threads=$$(nproc) --min-msi=30 --min-covered-msi=50 +ci-cs: vendor ## Check all files using defined rules (CI/CD) + vendor/bin/ecs check -.PHONY: tests -tests: vendor ## Run all tests - vendor/bin/phpunit --color - yarn test +ci-st: vendor ## Run static analyse (CI/CD) + vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr -.PHONY: cc -cc: vendor ## Show test coverage rates (HTML) - vendor/bin/phpunit --coverage-html ./build +ci-rector: vendor ## Check all files using Rector (CI/CD) + vendor/bin/rector process --ansi --dry-run -.PHONY: cs -cs: vendor ## Fix all files using defined ECS rules - vendor/bin/ecs check --fix +ci-mu: vendor ## Mutation tests (CI/CD) + vendor/bin/infection --logger-github -s --threads=$$(nproc) --min-msi=70 --min-covered-msi=50 --test-framework-options="--exclude-group=Performance" -.PHONY: tu -tu: vendor ## Run only unit tests - vendor/bin/phpunit --color --group Unit +######################## +# Everyday # +######################## -.PHONY: ti -ti: vendor ## Run only integration tests - vendor/bin/phpunit --color --group Integration +all: vendor ## Run all tests + vendor/bin/phpunit --color -.PHONY: tf -tf: vendor ## Run only functional tests - vendor/bin/phpunit --color --group Functional +tu: vendor ## Run only unit tests + vendor/bin/phpunit --color tests -.PHONY: st st: vendor ## Run static analyse - XDEBUG_MODE=off vendor/bin/phpstan analyse + vendor/bin/phpstan analyse ######################## -# CI/CD # +# Every PR # ######################## -.PHONY: ci-mu -ci-mu: vendor ## Mutation tests (for CI/CD only) - vendor/bin/infection --logger-github -s --threads=$$(nproc) --min-msi=30 --min-covered-msi=50 +cs: vendor ## Fix all files using defined rules + vendor/bin/ecs check --fix -.PHONY: ci-cc -ci-cc: vendor ## Show test coverage rates (for CI/CD only) - vendor/bin/phpunit --coverage-text +rector: vendor ## Check all files using Rector + vendor/bin/rector process -.PHONY: ci-cs -ci-cs: vendor ## Check all files using defined ECS rules (for CI/CD only) - XDEBUG_MODE=off vendor/bin/ecs check ######################## # Others # ######################## -.PHONY: rector -rector: vendor ## Check all files using Rector - XDEBUG_MODE=off vendor/bin/rector process --ansi --dry-run --xdebug +mu: vendor ## Mutation tests + vendor/bin/infection -s --threads=$$(nproc) --min-msi=70 --min-covered-msi=50 --test-framework-options="--exclude-group=Performance" -vendor: composer.json +cc: vendor ## Show test coverage rates (HTML) + vendor/bin/phpunit --coverage-html ./build + +vendor: composer.json composer.lock composer validate composer install + +######################## +# Default # +######################## + .DEFAULT_GOAL := help help: @grep -E '(^[a-zA-Z_-]+:.*?##.*$$)|(^##)' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' | sed -e 's/\[32m##/[33m/' diff --git a/composer.json b/composer.json index 30db9729dd16b2088a07a8a31b632e64ea687f30..bff24fa1580d2ee1036c4afe2b257035724fd701 100644 --- a/composer.json +++ b/composer.json @@ -23,15 +23,13 @@ "require-dev": { "ekino/phpstan-banned-code": "^1.0", "infection/infection": "^0.26", - "php-parallel-lint/php-parallel-lint": "^1.3", "phpstan/phpstan": "^1.0", "phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5.26", - "qossmic/deptrac-shim": "^1.0", + "phpunit/phpunit": "^9.5", "rector/rector": "^0.14", - "symfony/phpunit-bridge": "^6.1", + "symfony/phpunit-bridge": "^6.0", "symplify/easy-coding-standard": "^11.0" }, "autoload": { diff --git a/deptrac.yaml b/deptrac.yaml deleted file mode 100644 index 1986e15e430b48e69667274a745acd43b1ed447f..0000000000000000000000000000000000000000 --- a/deptrac.yaml +++ /dev/null @@ -1,14 +0,0 @@ -parameters: - paths: - - './src' - layers: - - name: 'OTP' - collectors: - - type: 'directory' - regex: 'src/.*' - - name: 'Vendors' - collectors: - - { type: className, regex: '^ParagonIE\\' } - ruleset: - OTP: - - 'Vendors' diff --git a/infection.json.dist b/infection.json.dist index 00a3453d7b751e74f0ec0907420531174fd75874..f02cbf8717b764e2f6f7a8a46b034e03c49218e8 100644 --- a/infection.json.dist +++ b/infection.json.dist @@ -9,11 +9,8 @@ }, "mutators": { "@default": true, - "MBString": { - "settings": { - "mb_substr": false, - "mb_strlen": false - } - } + "global-ignoreSourceCodeByRegex": [ + "\\$this->logger.*" + ] } -} +} \ No newline at end of file diff --git a/phpstan.neon b/phpstan.neon index 2ce3a2c42ff3808e186faab575b7e97f7e418eef..e55b63567665aea4c8f07671e5507d964f764804 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,25 +4,10 @@ parameters: - src - tests ignoreErrors: - - - message: '#Variable property access on \$this\(OTPHP\\OTP\)\.#' - path: src/ParameterTrait.php - count: 1 - - - message: '#^Method OTPHP\\OTP::generateSecret\(\) should return non-empty-string but returns string\.$#' - path: src/OTP.php - count: 1 - - - message: '#^Cannot cast mixed to int\.$#' - path: src/HOTP.php - count: 1 - - - message: '#^Parameter \#\d .* of class OTPHP\\Url constructor expects .*\, .* given\.$#' - path: src/Url.php - count: 2 + - '#Variable property access on \$this\(OTPHP\\OTP\)\.#' + - '#^Method OTPHP\\OTP::generateSecret\(\) should return non-empty-string but returns string\.$#' includes: - - vendor/phpstan/phpstan/conf/bleedingEdge.neon - vendor/phpstan/phpstan-strict-rules/rules.neon - vendor/phpstan/phpstan-phpunit/extension.neon - vendor/phpstan/phpstan-deprecation-rules/rules.neon diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e52c02c0fbba2ff97270ecb0e5d37dae80dcd4b4..d4bd675ced25b45caddb42640b5d2e4ce31fae43 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,28 +1,24 @@ <?xml version="1.0" encoding="UTF-8"?> -<phpunit - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - bootstrap="vendor/autoload.php" - colors="true" - resolveDependencies="true" - xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" -> - <coverage> - <include> - <directory suffix=".php">./src</directory> - </include> - </coverage> - <testsuites> - <testsuite name="OTP Test Suite"> - <directory>./tests</directory> - </testsuite> - </testsuites> - <listeners> - <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener"> - <arguments> - <array> - <element key="time-sensitive"><string>OTPHP\TOTP</string></element> - </array> - </arguments> - </listener> - </listeners> +<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"> + <coverage> + <include> + <directory suffix=".php">./src</directory> + </include> + </coverage> + <testsuites> + <testsuite name="OTP Test Suite"> + <directory>./tests</directory> + </testsuite> + </testsuites> + <listeners> + <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener"> + <arguments> + <array> + <element key="time-sensitive"><string>OTPHP</string></element> + <element key="time-sensitive"><string>OTPHP\TOTP</string></element> + </array> + </arguments> + </listener> + <listener class="Symfony\Bridge\PhpUnit\CoverageListener" /> + </listeners> </phpunit> diff --git a/src/HOTP.php b/src/HOTP.php index aa5a2275417689e359cc53eeed449c274df72d9f..8dc18d3ef5421bb55af7f6c66e6988401220ffad 100644 --- a/src/HOTP.php +++ b/src/HOTP.php @@ -12,8 +12,6 @@ use function is_int; */ final class HOTP extends OTP implements HOTPInterface { - private const DEFAULT_WINDOW = 0; - public static function create( null|string $secret = null, int $counter = self::DEFAULT_COUNTER, @@ -88,11 +86,10 @@ final class HOTP extends OTP implements HOTPInterface protected function getParameterMap(): array { return [...parent::getParameterMap(), ...[ - 'counter' => static function (mixed $value): int { - $value = (int) $value; - $value >= 0 || throw new InvalidArgumentException('Counter must be at least 0.'); + 'counter' => static function ($value): int { + (int) $value >= 0 || throw new InvalidArgumentException('Counter must be at least 0.'); - return $value; + return (int) $value; }, ]]; } @@ -104,7 +101,7 @@ final class HOTP extends OTP implements HOTPInterface private function getWindow(null|int $window): int { - return abs($window ?? self::DEFAULT_WINDOW); + return abs($window ?? 0); } private function verifyOtpWithWindow(string $otp, int $counter, null|int $window): bool diff --git a/src/OTP.php b/src/OTP.php index 2cba067b3cd73f01b6c2d75e1b7d672dc0473aab..ba640a3d2ea3e66b7f5b698f2a871d2d500ceb71 100644 --- a/src/OTP.php +++ b/src/OTP.php @@ -17,8 +17,6 @@ abstract class OTP implements OTPInterface { use ParameterTrait; - private const DEFAULT_SECRET_SIZE = 64; - /** * @param non-empty-string $secret */ @@ -44,7 +42,7 @@ abstract class OTP implements OTPInterface */ final protected static function generateSecret(): string { - return Base32::encodeUpper(random_bytes(self::DEFAULT_SECRET_SIZE)); + return Base32::encodeUpper(random_bytes(64)); } /** diff --git a/src/ParameterTrait.php b/src/ParameterTrait.php index b05092351b02fc162e3045cc79b98d044ec598ed..80d38888325ff7f09c97cceacd28f6d0e6d93f13 100644 --- a/src/ParameterTrait.php +++ b/src/ParameterTrait.php @@ -149,7 +149,9 @@ trait ParameterTrait return $value; }, - 'secret' => static fn ($value): string => mb_strtoupper(trim((string) $value, '=')), + 'secret' => static function ($value): string { + return mb_strtoupper(trim($value, '=')); + }, 'algorithm' => static function ($value): string { $value = mb_strtolower($value); in_array($value, hash_algos(), true) || throw new InvalidArgumentException(sprintf( diff --git a/src/Url.php b/src/Url.php index 56ad979c5b6b48e7c496d4ef72d9de5caaaaa273..387d54fa5d5c3da89d0d827280ce5d554047d077 100644 --- a/src/Url.php +++ b/src/Url.php @@ -15,13 +15,13 @@ final class Url { /** * @param non-empty-string $secret - * @param array<string, mixed> $query */ public function __construct( private readonly string $scheme, private readonly string $host, private readonly string $path, private readonly string $secret, + /** @var array<string, mixed> $query */ private readonly array $query ) { } diff --git a/tests/TOTPTest.php b/tests/TOTPTest.php index 53d7284675d1fca5b66462eb41a40ad79393d772..03691da92b97e956bdec01bb42c0fbb5ca89e5e0 100644 --- a/tests/TOTPTest.php +++ b/tests/TOTPTest.php @@ -164,12 +164,9 @@ final class TOTPTest extends TestCase */ public function generateOtpNow(): void { - ClockMock::register(TOTP::class); - $time = time(); - ClockMock::withClockMock($time); $otp = $this->createTOTP(6, 'sha1', 30); - static::assertSame($otp->now(), $otp->at($time)); + static::assertSame($otp->now(), $otp->at(time())); } /** @@ -177,9 +174,7 @@ final class TOTPTest extends TestCase */ public function verifyOtpNow(): void { - ClockMock::register(TOTP::class); $time = time(); - ClockMock::withClockMock($time); $otp = $this->createTOTP(6, 'sha1', 30); $totp = $otp->at($time); @@ -313,12 +308,8 @@ final class TOTPTest extends TestCase * @test * @dataProvider dataLeewayWithEpoch */ - public function verifyOtpWithEpochInWindow( - int $timestamp, - string $input, - int $leeway, - bool $expectedResult - ): void { + public function verifyOtpWithEpochInWindow(int $timestamp, string $input, int $leeway, bool $expectedResult): void + { ClockMock::register(TOTP::class); ClockMock::withClockMock($timestamp); $otp = $this->createTOTP(6, 'sha1', 30, 'JDDK4U6G3BJLEZ7Y', 'alice@foo.bar', 'My Project', 100);