diff --git a/CHANGELOG.md b/CHANGELOG.md index 72acdbd..8293c38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,8 @@ ## 3.1.0 (unreleased) -- Add the scopes `products` and `products:read` (`Scope::PRODUCTS`, `Scope::PRODUCTS_READ`) for the - product APIs of the Anikeen Console. +- Add the scope `products:read` (`Scope::PRODUCTS_READ`) for read-only access to the product APIs + of the Anikeen Console. - Add the reseller scopes `reseller-customers:read`, `reseller-customers`, `reseller-grants` and `reseller-orders` (`Scope::RESELLER_CUSTOMERS_READ`, `Scope::RESELLER_CUSTOMERS`, `Scope::RESELLER_GRANTS`, `Scope::RESELLER_ORDERS`) for the reseller API of the Anikeen Console. diff --git a/README.md b/README.md index 70b55b5..1da3dae 100644 --- a/README.md +++ b/README.md @@ -172,14 +172,14 @@ these scopes for its product and reseller APIs: | Scope | Constant | Grants | |-------|----------|--------| | `products:read` | `Scope::PRODUCTS_READ` | view the products of your teams | -| `products` | `Scope::PRODUCTS` | full access to the products of your teams | | `reseller-customers:read` | `Scope::RESELLER_CUSTOMERS_READ` | view a reseller team's customers and invitations | | `reseller-customers` | `Scope::RESELLER_CUSTOMERS` | manage customers: invite, resend, remove logins (includes reading) | | `reseller-grants` | `Scope::RESELLER_GRANTS` | grant customers access to products and revoke it | | `reseller-orders` | `Scope::RESELLER_ORDERS` | order products for customers, charged right away | -A full scope includes reading. `user` and `*` do not open the reseller endpoints: the token has to -carry the reseller scope itself. +A full reseller scope includes reading. `user` and `*` do not open the reseller endpoints: the +token has to carry the reseller scope itself. For the product APIs there is only `products:read`; +changing products needs `user`. ### Change the default access token / refresh token field name diff --git a/README.stub b/README.stub index 3b8b76a..6fb0a71 100644 --- a/README.stub +++ b/README.stub @@ -172,14 +172,14 @@ these scopes for its product and reseller APIs: | Scope | Constant | Grants | |-------|----------|--------| | `products:read` | `Scope::PRODUCTS_READ` | view the products of your teams | -| `products` | `Scope::PRODUCTS` | full access to the products of your teams | | `reseller-customers:read` | `Scope::RESELLER_CUSTOMERS_READ` | view a reseller team's customers and invitations | | `reseller-customers` | `Scope::RESELLER_CUSTOMERS` | manage customers: invite, resend, remove logins (includes reading) | | `reseller-grants` | `Scope::RESELLER_GRANTS` | grant customers access to products and revoke it | | `reseller-orders` | `Scope::RESELLER_ORDERS` | order products for customers, charged right away | -A full scope includes reading. `user` and `*` do not open the reseller endpoints: the token has to -carry the reseller scope itself. +A full reseller scope includes reading. `user` and `*` do not open the reseller endpoints: the +token has to carry the reseller scope itself. For the product APIs there is only `products:read`; +changing products needs `user`. ### Change the default access token / refresh token field name diff --git a/src/Id/Enums/Scope.php b/src/Id/Enums/Scope.php index 3b77fac..0ce17a2 100644 --- a/src/Id/Enums/Scope.php +++ b/src/Id/Enums/Scope.php @@ -36,8 +36,8 @@ class Scope const SSH_KEYS = 'ssh-keys'; const SSH_KEYS_READ = 'ssh-keys:read'; - // Products of the Anikeen Console (servers, floating IPs, hosting, domains, zones, object storage). - const PRODUCTS = 'products'; + // Products of the Anikeen Console (servers, floating IPs, hosting, domains, zones, object storage), + // read-only. Changing products needs `user`; there is no full `products` scope. const PRODUCTS_READ = 'products:read'; // Reseller API of the Anikeen Console. A full scope includes reading; `user` and `*` do not diff --git a/tests/Id/ScopeTest.php b/tests/Id/ScopeTest.php index 59c41a9..08b3642 100644 --- a/tests/Id/ScopeTest.php +++ b/tests/Id/ScopeTest.php @@ -11,7 +11,6 @@ class ScopeTest extends TestCase public static function newScopes(): array { return [ - 'products' => [Scope::PRODUCTS, 'products'], 'products:read' => [Scope::PRODUCTS_READ, 'products:read'], 'reseller-customers' => [Scope::RESELLER_CUSTOMERS, 'reseller-customers'], 'reseller-customers:read' => [Scope::RESELLER_CUSTOMERS_READ, 'reseller-customers:read'], @@ -26,6 +25,12 @@ class ScopeTest extends TestCase $this->assertSame($expected, $constant); } + public function test_there_is_no_full_products_scope_the_console_would_not_accept(): void + { + // the Console's product APIs accept `user`, `user:read` and `products:read` only + $this->assertNotContains('products', (new ReflectionClass(Scope::class))->getConstants()); + } + public function test_every_scope_follows_the_resource_and_level_schema(): void { $scopes = array_values((new ReflectionClass(Scope::class))->getConstants());