From d9a905cea51c6f709aa9e9d706c66b6bb0abe6b3 Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Fri, 4 Oct 2024 14:05:47 +0200 Subject: [PATCH] Code style fixes and actions --- .github/PULL_REQUEST_TEMPLATE.md | 25 +++++ .github/workflows/pr.yaml | 153 +++++++++++++++++++++++++++++++ .gitignore | 1 + .markdownlint.json | 11 +++ .php-cs-fixer.dist.php | 14 +++ CHANGELOG.md | 16 ++++ README.md | 19 ++++ composer.json | 19 +++- package.json | 14 +++ phpunit.xml | 26 ++++-- src/Vault/Model/Secret.php | 5 +- src/Vault/Model/Token.php | 8 +- src/Vault/Vault.php | 57 +++++++----- src/Vault/VaultInterface.php | 63 ++++++++++++- tests/VaultTest.php | 16 ++-- 15 files changed, 395 insertions(+), 52 deletions(-) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/pr.yaml create mode 100644 .markdownlint.json create mode 100644 .php-cs-fixer.dist.php create mode 100644 CHANGELOG.md create mode 100644 README.md create mode 100644 package.json diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..05ccf56 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,25 @@ +#### Link to ticket + +Please add a link to the ticket being addressed by this change. + +#### Description + +Please include a short description of the suggested change and the reasoning behind the approach you have chosen. + +#### Screenshot of the result + +If your change affects the user interface, you should include a screenshot of the result with the pull request. + +#### Checklist + +- [ ] My code is covered by test cases. +- [ ] My code passes our test (all our tests). +- [ ] My code passes our static analysis suite. +- [ ] My code passes our continuous integration process. + +If your code does not pass all the requirements on the checklist, you have to add a comment explaining why this change +should be exempt from the list. + +#### Additional comments or questions + +If you have any further comments or questions for the reviewer, please add them here. diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml new file mode 100644 index 0000000..0ba1cd2 --- /dev/null +++ b/.github/workflows/pr.yaml @@ -0,0 +1,153 @@ +on: pull_request +name: Review +jobs: + test-composer-install: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: [ '8.2', '8.3' ] + name: Validate composer (${{ matrix.php}}) + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php}} + extensions: http, ctype, iconv + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}-${{ matrix.dependency-version }}- + restore-keys: ${{ runner.os }}-composer-${{ matrix.dependency-version }}- + + - name: Validate composer files + run: composer validate composer.json --strict + + - name: Composer install with exported .env variables + run: | + set -a && source .env && set +a + APP_ENV=prod composer install --no-dev -o + + test-suite: + name: Test suite (${{ matrix.php }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: [ '8.2', '8.3' ] + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php}} + extensions: http, ctype, iconv + coverage: xdebug + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}-${{ matrix.dependency-version }}- + restore-keys: ${{ runner.os }}-composer-${{ matrix.dependency-version }}- + + - name: Install Dependencies + run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist + + - name: Test suite + run: ./vendor/bin/phpunit --coverage-clover=coverage/unit.xml + + - name: Upload coverage to Codecov test + uses: codecov/codecov-action@v2 + with: + files: ./coverage/unit.xml + flags: unittests, ${{ matrix.php }} + + php-cs-fixer: + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + php: ['8.2', '8.3'] + name: PHP Coding Standards Fixer (PHP ${{ matrix.php }}) + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php}} + extensions: http, ctype, iconv + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ matrix.php }}-composer- + + - name: Install Dependencies + run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist + + - name: php-cs-fixer + run: phpdbg -qrr ./vendor/bin/php-cs-fixer fix --dry-run + + markdownlint: + name: Markdown Lint + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + - name: Cache yarn packages + uses: actions/cache@v4 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + - name: Yarn install + uses: actions/setup-node@v2 + with: + node-version: '18' + - run: yarn install + - name: markdownlint + run: yarn run coding-standards-check + + changelog: + runs-on: ubuntu-latest + name: Changelog should be updated + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Git fetch + run: git fetch + + - name: Check that changelog has been updated. + run: git diff --exit-code origin/${{ github.base_ref }} -- CHANGELOG.md && exit 1 || exit 0 diff --git a/.gitignore b/.gitignore index 50b321e..15b94f7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ vendor composer.lock .phpunit.result.cache +.php-cs-fixer.cache diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..85d45c0 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,11 @@ +{ + "default": true, + "MD013": { + "line_length": 120, + "ignore_code_blocks": true, + "tables": false + }, + "no-duplicate-heading": { + "siblings_only": true + } +} diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..50e228b --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,14 @@ +in(__DIR__) + ->exclude('var') +; + +return (new PhpCsFixer\Config()) + ->setRules([ + '@Symfony' => true, + 'phpdoc_align' => false, + ]) + ->setFinder($finder) +; diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ae5682b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +![keep a changelog](https://img.shields.io/badge/Keep%20a%20Changelog-v1.1.0-brightgreen.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmMTVkMzAiIHZpZXdCb3g9IjAgMCAxODcgMTg1Ij48cGF0aCBkPSJNNjIgN2MtMTUgMy0yOCAxMC0zNyAyMmExMjIgMTIyIDAgMDAtMTggOTEgNzQgNzQgMCAwMDE2IDM4YzYgOSAxNCAxNSAyNCAxOGE4OSA4OSAwIDAwMjQgNCA0NSA0NSAwIDAwNiAwbDMtMSAxMy0xYTE1OCAxNTggMCAwMDU1LTE3IDYzIDYzIDAgMDAzNS01MiAzNCAzNCAwIDAwLTEtNWMtMy0xOC05LTMzLTE5LTQ3LTEyLTE3LTI0LTI4LTM4LTM3QTg1IDg1IDAgMDA2MiA3em0zMCA4YzIwIDQgMzggMTQgNTMgMzEgMTcgMTggMjYgMzcgMjkgNTh2MTJjLTMgMTctMTMgMzAtMjggMzhhMTU1IDE1NSAwIDAxLTUzIDE2bC0xMyAyaC0xYTUxIDUxIDAgMDEtMTItMWwtMTctMmMtMTMtNC0yMy0xMi0yOS0yNy01LTEyLTgtMjQtOC0zOWExMzMgMTMzIDAgMDE4LTUwYzUtMTMgMTEtMjYgMjYtMzMgMTQtNyAyOS05IDQ1LTV6TTQwIDQ1YTk0IDk0IDAgMDAtMTcgNTQgNzUgNzUgMCAwMDYgMzJjOCAxOSAyMiAzMSA0MiAzMiAyMSAyIDQxLTIgNjAtMTRhNjAgNjAgMCAwMDIxLTE5IDUzIDUzIDAgMDA5LTI5YzAtMTYtOC0zMy0yMy01MWE0NyA0NyAwIDAwLTUtNWMtMjMtMjAtNDUtMjYtNjctMTgtMTIgNC0yMCA5LTI2IDE4em0xMDggNzZhNTAgNTAgMCAwMS0yMSAyMmMtMTcgOS0zMiAxMy00OCAxMy0xMSAwLTIxLTMtMzAtOS01LTMtOS05LTEzLTE2YTgxIDgxIDAgMDEtNi0zMiA5NCA5NCAwIDAxOC0zNSA5MCA5MCAwIDAxNi0xMmwxLTJjNS05IDEzLTEzIDIzLTE2IDE2LTUgMzItMyA1MCA5IDEzIDggMjMgMjAgMzAgMzYgNyAxNSA3IDI5IDAgNDJ6bS00My03M2MtMTctOC0zMy02LTQ2IDUtMTAgOC0xNiAyMC0xOSAzN2E1NCA1NCAwIDAwNSAzNGM3IDE1IDIwIDIzIDM3IDIyIDIyLTEgMzgtOSA0OC0yNGE0MSA0MSAwIDAwOC0yNCA0MyA0MyAwIDAwLTEtMTJjLTYtMTgtMTYtMzEtMzItMzh6bS0yMyA5MWgtMWMtNyAwLTE0LTItMjEtN2EyNyAyNyAwIDAxLTEwLTEzIDU3IDU3IDAgMDEtNC0yMCA2MyA2MyAwIDAxNi0yNWM1LTEyIDEyLTE5IDI0LTIxIDktMyAxOC0yIDI3IDIgMTQgNiAyMyAxOCAyNyAzM3MtMiAzMS0xNiA0MGMtMTEgOC0yMSAxMS0zMiAxMXptMS0zNHYxNGgtOFY2OGg4djI4bDEwLTEwaDExbC0xNCAxNSAxNyAxOEg5NnoiLz48L3N2Zz4K) + +All notable changes to this project will be documented in this file. + +See [keep a changelog] for information about writing changes to this log. + +## [Unreleased] + +* Added cache of token and possibility to cache secrets. +* Added get secrets. +* Added login. + +[keep a changelog]: https://keepachangelog.com/en/1.1.0/ +[unreleased]: https://github.com/itk-dev/itkdev-vault-library/compare/main...develop diff --git a/README.md b/README.md new file mode 100644 index 0000000..055039d --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# Vault library + +A PHP library for authenticating with HashiCorp Vault using the `approle` +method. This library implements the PSR-18 and PSR-17 interfaces, so you will +need to provide your own HTTP client. + +## Install + +You can install this library by utilizing PHP Composer, which is the recommended +dependency management tool for PHP. + +```shell +composer require itkdev/vault +``` + +## Usage + +@TODO: Add links to the symfony bundel and drupal Keys provider module as +examples on how to use this library. diff --git a/composer.json b/composer.json index 986f8c8..fadd101 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,11 @@ "role": "Developer" } ], + "autoload": { + "psr-4": { + "ItkDev\\Vault\\": "src/Vault" + } + }, "require": { "php": ">=8.2", "psr/http-client": "^1.0", @@ -20,11 +25,15 @@ "psr/simple-cache": "^3.0" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^11.3", + "friendsofphp/php-cs-fixer": "^3.64" }, - "autoload": { - "psr-4": { - "ItkDev\\Vault\\": "src/Vault" - } + "scripts": { + "coding-standards-apply": [ + "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix" + ], + "coding-standards-check": [ + "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --dry-run" + ] } } diff --git a/package.json b/package.json new file mode 100644 index 0000000..2a82596 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "license": "UNLICENSED", + "private": true, + "description": "Tooling setup for linting", + "devDependencies": { + "markdownlint-cli": "^0.35.0" + }, + "scripts": { + "coding-standards-check/markdownlint": "markdownlint --ignore 'node_modules' --ignore 'vendor' README.md CHANGELOG.md 'docs/**/*.md'", + "coding-standards-check": "yarn coding-standards-check/markdownlint", + "coding-standards-apply/markdownlint": "markdownlint --fix README.md CHANGELOG.md docs/*.md docs/**/*.md", + "coding-standards-apply": "yarn coding-standards-apply/markdownlint" + } +} diff --git a/phpunit.xml b/phpunit.xml index ac32d5c..f6025b6 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,14 +1,26 @@ - + - - ./tests + + tests - + + - src + src - + diff --git a/src/Vault/Model/Secret.php b/src/Vault/Model/Secret.php index 2d6b74d..d76c976 100644 --- a/src/Vault/Model/Secret.php +++ b/src/Vault/Model/Secret.php @@ -9,9 +9,6 @@ public function __construct( public string $value, public string $version, public \DateTimeImmutable $createdAt, - ) - { - + ) { } - } diff --git a/src/Vault/Model/Token.php b/src/Vault/Model/Token.php index 705a8c4..3e48091 100644 --- a/src/Vault/Model/Token.php +++ b/src/Vault/Model/Token.php @@ -10,11 +10,12 @@ public function __construct( public readonly bool $renewable, public readonly string $roleName, private int $numUsesLeft, - ) {} + ) { + } public function used(): void { - $this->numUsesLeft--; + --$this->numUsesLeft; } public function usesLeft(): int @@ -24,7 +25,6 @@ public function usesLeft(): int public function isExpired(int $tokenGracePeriod = 60): bool { - return $this->expiresAt->sub(new \DateInterval('PT' . $tokenGracePeriod .'S')) < new \DateTimeImmutable(timezone: new \DateTimeZone('UTC')); + return $this->expiresAt->sub(new \DateInterval('PT'.$tokenGracePeriod.'S')) < new \DateTimeImmutable(timezone: new \DateTimeZone('UTC')); } - } diff --git a/src/Vault/Vault.php b/src/Vault/Vault.php index 842b557..1f256c0 100644 --- a/src/Vault/Vault.php +++ b/src/Vault/Vault.php @@ -2,15 +2,12 @@ namespace ItkDev\Vault; -use DateInterval; -use DateTimeImmutable; -use DateTimeZone; +use ItkDev\Vault\Model\Secret; +use ItkDev\Vault\Model\Token; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\StreamFactoryInterface; use Psr\SimpleCache\CacheInterface; -use \ItkDev\Vault\Model\Secret; -use \ItkDev\Vault\Model\Token; readonly class Vault implements VaultInterface { @@ -20,14 +17,22 @@ public function __construct( private StreamFactoryInterface $streamFactory, private CacheInterface $cache, private string $vaultUrl, - ) {} + ) { + } - public function login(string $roleId, string $secretId, string $enginePath = 'approle', bool $reset = false): Token + /** + * @throws \DateMalformedIntervalStringException + * @throws \DateMalformedStringException + * @throws \JsonException + * @throws \Psr\Http\Client\ClientExceptionInterface + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function login(string $roleId, string $secretId, string $enginePath = 'approle', bool $refreshCache = false): Token { $cacheKey = 'itkdev_vault_token'; $token = $this->cache->get($cacheKey); - if ($reset || is_null($token) || $token->isExpired()) { + if ($refreshCache || is_null($token) || $token->isExpired()) { $loginUrl = sprintf('%s/v1/auth/%s/login', $this->vaultUrl, $enginePath); $body = $this->streamFactory->createStream(json_encode([ @@ -40,13 +45,13 @@ public function login(string $roleId, string $secretId, string $enginePath = 'ap $response = $this->httpClient->sendRequest($request); - $data = json_decode($response->getBody(), associative: true, flags: JSON_THROW_ON_ERROR); + $data = json_decode($response->getBody(), associative: true, flags: JSON_THROW_ON_ERROR); $ttl = (int) $data['auth']['lease_duration']; - $now = new DateTimeImmutable(timezone: new DateTimeZone('UTC')); + $now = new \DateTimeImmutable(timezone: new \DateTimeZone('UTC')); $token = new Token( token: $data['auth']['client_token'], - expiresAt: $now->add(new DateInterval('PT' . $ttl . 'S')), + expiresAt: $now->add(new \DateInterval('PT'.$ttl.'S')), renewable: (bool) $data['auth']['renewable'], roleName: $data['auth']['metadata']['role_name'], numUsesLeft: (int) $data['auth']['num_uses'], @@ -58,7 +63,13 @@ public function login(string $roleId, string $secretId, string $enginePath = 'ap return $token; } - public function getSecret(Token $token, string $path, string $secret, array $id, bool $useCache = false, bool $reset = false, int $expire = 0): Secret + /** + * @throws \DateMalformedStringException + * @throws \JsonException + * @throws \Psr\Http\Client\ClientExceptionInterface + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function getSecret(Token $token, string $path, string $secret, string $id, bool $useCache = false, bool $refreshCache = false, int $expire = 0): Secret { $secret = $this->getSecrets( token: $token, @@ -66,30 +77,35 @@ public function getSecret(Token $token, string $path, string $secret, array $id, secret: $secret, ids: [$id], useCache: $useCache, - reset: $reset, + refreshCache: $refreshCache, expire: $expire ); return reset($secret); } - // @TODO: Add cache of secret (handle vault offline). - public function getSecrets(Token $token, string $path, string $secret, array $ids, bool $useCache = false, bool $reset = false, int $expire = 0): array + /** + * @throws \DateMalformedStringException + * @throws \JsonException + * @throws \Psr\Http\Client\ClientExceptionInterface + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function getSecrets(Token $token, string $path, string $secret, array $ids, bool $useCache = false, bool $refreshCache = false, int $expire = 0): array { - $cacheKey = 'itkdev_vault_secret_' . $secret; + $cacheKey = 'itkdev_vault_secret_'.$secret; $data = $this->cache->get($cacheKey); - if (!$useCache || is_null($data) || $reset) { + if (!$useCache || is_null($data) || $refreshCache) { $url = sprintf('%s/v1/%s/data/%s', $this->vaultUrl, $path, $secret); $request = $this->requestFactory->createRequest('GET', $url) ->withHeader('Content-Type', 'application/json') - ->withHeader('Authorization', 'Bearer ' . $token->token); + ->withHeader('Authorization', 'Bearer '.$token->token); $response = $this->httpClient->sendRequest($request); - $res = json_decode($response->getBody(), associative: true, flags: JSON_THROW_ON_ERROR); + $res = json_decode($response->getBody(), associative: true, flags: JSON_THROW_ON_ERROR); - $created = new DateTimeImmutable($res['data']['metadata']['created_time'], new DateTimeZone('UTC')); + $created = new \DateTimeImmutable($res['data']['metadata']['created_time'], new \DateTimeZone('UTC')); $version = $res['data']['metadata']['version']; $data = []; @@ -114,5 +130,4 @@ public function getSecrets(Token $token, string $path, string $secret, array $id return $data; } - } diff --git a/src/Vault/VaultInterface.php b/src/Vault/VaultInterface.php index bb73209..fa49ecc 100644 --- a/src/Vault/VaultInterface.php +++ b/src/Vault/VaultInterface.php @@ -7,13 +7,66 @@ interface VaultInterface { - public function login(string $roleId, string $secretId, string $enginePath = 'approle', bool $reset = false): Token; - + /** + * Get a token from the vault using the provided roleId and secretId. + * + * @param string $roleId + * Role ID for authentication + * @param string $secretId + * Secret ID for authentication + * @param string $enginePath + * The path to the authentication engine. Default is 'approle'. + * @param bool $refreshCache + * By-pass cache and refresh the cache content. Default is false. + * + * @return Token + * Token that can be used to communicate with the vault + */ + public function login(string $roleId, string $secretId, string $enginePath = 'approle', bool $refreshCache = false): Token; - public function getSecret(Token $token, string $path, string $secret, array $id, bool $useCache = false, bool $reset = false, int $expire = 0): Secret; + /** + * Retrieve a secret from the specified secret engine path. + * + * @param Token $token + * Authentication token required to access the secrets + * @param string $path + * The path from which to retrieve the secrets + * @param string $secret + * The type of secret being requested + * @param string $id + * An array of identifiers specifying which secrets to retrieve + * @param bool $useCache + * Optional parameter to indicate whether to use cached secrets. Defaults to false. + * @param bool $refreshCache + * Optional parameter to indicate whether to refresh the cache. Defaults to false. + * @param int $expire + * Optional parameter specifying cache expiration time in seconds. Defaults to 0. + * + * @return Secret + * The secret found + */ + public function getSecret(Token $token, string $path, string $secret, string $id, bool $useCache = false, bool $refreshCache = false, int $expire = 0): Secret; /** - * An array of retrieved secrets. + * Retrieves secrets from the specified secret engine path. + * + * @param Token $token + * Authentication token required to access the secrets + * @param string $path + * The path from which to retrieve the secrets + * @param string $secret + * The type of secret being requested + * @param array $ids + * An array of identifiers specifying which secrets to retrieve + * @param bool $useCache + * Optional parameter to indicate whether to use cached secrets. Defaults to false. + * @param bool $refreshCache + * Optional parameter to indicate whether to refresh the cache. Defaults to false. + * @param int $expire + * Optional parameter specifying cache expiration time in seconds. Defaults to 0. + * + * @return array + * An array containing the requested secrets */ - public function getSecrets(Token $token, string $path, string $secret, array $ids, bool $useCache = false, bool $reset = false, int $expire = 0): array; + public function getSecrets(Token $token, string $path, string $secret, array $ids, bool $useCache = false, bool $refreshCache = false, int $expire = 0): array; } diff --git a/tests/VaultTest.php b/tests/VaultTest.php index 6bdf5f2..e72b8ae 100644 --- a/tests/VaultTest.php +++ b/tests/VaultTest.php @@ -2,8 +2,10 @@ namespace ItkDev\Vault\Tests; -use ItkDev\Vault\Token; +use ItkDev\Vault\Model\Token; use ItkDev\Vault\Vault; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; @@ -13,6 +15,8 @@ use Psr\Http\Message\StreamInterface; use Psr\SimpleCache\CacheInterface; +#[CoversClass(Vault::class)] +#[UsesClass(Token::class)] class VaultTest extends TestCase { private string $vaultUrl = 'http://test-url.com'; @@ -28,7 +32,7 @@ public function testLogin() $now = new \DateTimeImmutable(timezone: new \DateTimeZone('UTC')); $token = new Token( token: 'hvs.CAESIO5SjAQ5ggMi7HxpZUm5TZeJWZQ5i9425SMFZ', - expiresAt: $now->add(new \DateInterval('PT' . $ttl . 'S')), + expiresAt: $now->add(new \DateInterval('PT'.$ttl.'S')), renewable: true, roleName: 'test-role-name', numUsesLeft: 2, @@ -44,11 +48,11 @@ public function testLogin() 'lease_duration' => $ttl, 'renewable' => $token->renewable, 'num_uses' => $token->usesLeft(), - ] + ], ]; $data = [ - "role_id" => "ffffffff-ffff-ffff-ffff-ffffffffffff", - "secret_id" => "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" + 'role_id' => 'ffffffff-ffff-ffff-ffff-ffffffffffff', + 'secret_id' => 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', ]; $mockCache = $this->createMock(CacheInterface::class); @@ -68,7 +72,7 @@ public function testLogin() $mockRequestFactory->expects($this->once()) ->method('createRequest') - ->with('POST', $this->vaultUrl . '/v1/auth/approle/login') + ->with('POST', $this->vaultUrl.'/v1/auth/approle/login') ->willReturn($mockRequest); $mockRequest->expects($this->once())