Strawberry GraphQL: 同期的な権限チェックにおいて、await可能な認証結果を真とみなすことができます。

### 概要

`PermissionExtension.resolve()`は、同期パスにおいて`has_permission()`の戻り値を真偽値として評価します。`supports_sync`は、`has_permission`が`async def`で宣言されている場合(`inspect.iscoroutinefunction`を使用)にのみ、権限を非同期として分類します。したがって、await可能な値を返す通常の`def`は、同期として扱われます。await可能な値は常に真とみなされるため、チェックは通過し、たとえそれが`False`に解決されたとしても、保護されたリゾルバーが実行されます。

リゾルブパスは、実行メソッドではなく、フィールドリゾルバーによって選択されるため、同期リゾルバーを持つすべてのフィールドは、`execute_sync()`と`execute()`の両方で影響を受けます。`async def has_permission()`で宣言された権限、またはブール値を返す通常の`def`で宣言された権限は、影響を受けません。

### 詳細

影響を受けるコードは、`strawberry/permission.py`の`PermissionExtension.resolve()`です。await可能な値を返す通常の`def`を持つ`has_permission`が設定されたフィールドにアタッチされた権限は、このパスに到達します。この場合、await可能な値は待機されず、その真偽値によってアクセスが許可されます。`resolve_async()`は影響を受けません。なぜなら、`await_maybe()`を使用しているからです。

### 実証コード

```python
import strawberry
from strawberry.permission import BasePermission

class DenyViaAwaitable(BasePermission):
message = "denied"

def has_permission(self, source, info, **kwargs):
async def result():
return False

return result()

@strawberry.type
class Query:
@strawberry.field(permission_classes=[DenyViaAwaitable])
def secret(self) -> str:
return "secret"

schema = strawberry.Schema(Query)
print(schema.execute_sync("{ secret }").data) # {'secret': 'secret'} (権限エラーではなく)
```

### 影響

カスタムパーミッションを使用するアプリケーションにおいて、`has_permission`が通常の`def`で定義され、awaitableを返す場合、意図せず保護されたフィールドへのアクセスを許可してしまう可能性があります。 標準的なパーミッション(booleanまたは`async def`を返すもの)には影響はなく、脆弱性の有無は、この特定のパーミッションの形状を使用しているアプリケーションに依存します。

### 修正

同期処理のパスにおいて、`has_permission()`がawaitableを返す場合、アクセスを許可する代わりにエラーが発生するように変更されました。

影響を受けるパッケージ:
- pip (Python) strawberry-graphql: 影響を受けるバージョンは0.217.0以上、0.326.0以下。0.326.1で修正済み。