This is an automated email from the ASF dual-hosted git repository.

mchades pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 149b06250c [#11259] docs(open-api): Add OpenAPI spec for built-in IdP 
REST APIs (#11260)
149b06250c is described below

commit 149b06250ca6d43d983ab504addfd5b88f739717
Author: MaSai <[email protected]>
AuthorDate: Wed May 27 23:19:16 2026 +0800

    [#11259] docs(open-api): Add OpenAPI spec for built-in IdP REST APIs 
(#11260)
    
    ### What changes were proposed in this pull request?
    
    Add OpenAPI documentation for built-in IDP REST APIs exposed by the
    `idp-basic` plugin (when the `basic` authenticator is enabled):
    
    - **`docs/open-api/idp/openapi.yaml`** — standalone entry spec (info,
    servers, security, path refs)
    - **`docs/open-api/idp/idp.yaml`** — IdP paths, request/response
    schemas, and examples
    - **`docs/build.gradle.kts`** — add `lintIdpOpenAPI` and run it in
    `docs:build` alongside the existing main spec lint
    
    Documented endpoints:
    
    | Method | Path | Description |
    |--------|------|-------------|
    | POST | `/idp/users` | Add IDP user |
    | GET | `/idp/users/{user}` | Get IDP user |
    | PUT | `/idp/users/{user}` | Change password |
    | DELETE | `/idp/users/{user}` | Remove IDP user |
    | POST | `/idp/groups` | Add IDP group |
    | GET | `/idp/groups/{group}` | Get IDP group |
    | DELETE | `/idp/groups/{group}` | Remove IDP group (`force` query) |
    | PUT | `/idp/groups/{group}/users` | Change group membership
    (`usersToAdd` / `usersToRemove`) |
    
    Shared components (`ErrorModel`, common error responses, path
    parameters, `BasicAuth`) are referenced from
    `docs/open-api/openapi.yaml` where applicable. IdP-specific payloads
    live under `components/schemas` in `idp.yaml`.
    
    **Note:** IdP paths are **not** registered in the main
    `docs/open-api/openapi.yaml`; they are validated via the dedicated
    `idp/openapi.yaml` entry (see `lintIdpOpenAPI`).
    
    ### Why are the changes needed?
    
    IdP REST endpoints are implemented but were missing from published
    OpenAPI documentation, making discovery and review harder for clients
    and contributors.
    
    Fix: #11259
    
    ### Does this PR introduce _any_ user-facing change?
    
    No runtime behavior change. Documentation-only: adds OpenAPI
    descriptions for existing IdP REST APIs.
    
    ### How was this patch tested?
    
    ```bash
    ./gradlew :docs:build
    ```
    
    This runs Redocly lint (`recommended-strict`) for both:
    
    - `docs/open-api/openapi.yaml`
    - `docs/open-api/idp/openapi.yaml`
    
    ---------
    
    Co-authored-by: Cursor <[email protected]>
---
 docs/build.gradle.kts          |  12 +
 docs/open-api/idp/idp.yaml     | 505 +++++++++++++++++++++++++++++++++++++++++
 docs/open-api/idp/openapi.yaml |  69 ++++++
 3 files changed, 586 insertions(+)

diff --git a/docs/build.gradle.kts b/docs/build.gradle.kts
index 60b0be907a..39810c3dda 100644
--- a/docs/build.gradle.kts
+++ b/docs/build.gradle.kts
@@ -32,7 +32,19 @@ tasks {
     args.set(listOf("lint", "--extends=recommended-strict", 
"${project.projectDir}/open-api/openapi.yaml"))
   }
 
+  val lintIdpOpenAPI by registering(NpxTask::class) {
+    command.set("@redocly/[email protected]")
+    args.set(
+      listOf(
+        "lint",
+        "--extends=recommended-strict",
+        "${project.projectDir}/open-api/idp/openapi.yaml"
+      )
+    )
+  }
+
   build {
     dependsOn(lintOpenAPI)
+    dependsOn(lintIdpOpenAPI)
   }
 }
diff --git a/docs/open-api/idp/idp.yaml b/docs/open-api/idp/idp.yaml
new file mode 100644
index 0000000000..bc5e211ea9
--- /dev/null
+++ b/docs/open-api/idp/idp.yaml
@@ -0,0 +1,505 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+---
+
+paths:
+
+  /idp/users:
+    post:
+      tags:
+        - IDP
+      summary: Add built-in IDP user
+      description: >
+        Creates a built-in IDP user with the given username and password.
+        Requires the `basic` authenticator and the `idp-basic` plugin to be 
enabled.
+      operationId: addIdpUser
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/AddUserRequest"
+            examples:
+              AddUserRequest:
+                $ref: "#/components/examples/AddUserRequest"
+      responses:
+        "200":
+          description: Returns the added built-in IDP user
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "#/components/schemas/IdpUserResponse"
+              examples:
+                IdpUserResponse:
+                  $ref: "#/components/examples/IdpUserResponse"
+        "400":
+          $ref: "../openapi.yaml#/components/responses/BadRequestErrorResponse"
+        "403":
+          $ref: "#/components/responses/IdpForbiddenErrorResponse"
+        "409":
+          description: Conflict - The built-in IDP user already exists
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+              examples:
+                AlreadyExistsException:
+                  $ref: "#/components/examples/IdpAlreadyExistsException"
+        "5xx":
+          $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+  /idp/users/{user}:
+    parameters:
+      - $ref: "../openapi.yaml#/components/parameters/user"
+
+    get:
+      tags:
+        - IDP
+      summary: Get built-in IDP user
+      description: Returns the specified built-in IDP user, including group 
membership.
+      operationId: getIdpUser
+      responses:
+        "200":
+          description: Returns the built-in IDP user object
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "#/components/schemas/IdpUserResponse"
+              examples:
+                IdpUserResponse:
+                  $ref: "#/components/examples/IdpUserResponse"
+        "403":
+          $ref: "#/components/responses/IdpForbiddenErrorResponse"
+        "404":
+          description: Not Found - The specified built-in IDP user does not 
exist
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+              examples:
+                NotFoundException:
+                  $ref: "#/components/examples/IdpNotFoundException"
+        "5xx":
+          $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+    put:
+      tags:
+        - IDP
+      summary: Change built-in IDP user password
+      description: Updates the password of the specified built-in IDP user.
+      operationId: changeIdpUserPassword
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/ChangePasswordRequest"
+            examples:
+              ChangePasswordRequest:
+                $ref: "#/components/examples/ChangePasswordRequest"
+      responses:
+        "200":
+          description: Returns the built-in IDP user after the password change
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "#/components/schemas/IdpUserResponse"
+              examples:
+                IdpUserResponse:
+                  $ref: "#/components/examples/IdpUserResponse"
+        "400":
+          $ref: "../openapi.yaml#/components/responses/BadRequestErrorResponse"
+        "403":
+          $ref: "#/components/responses/IdpForbiddenErrorResponse"
+        "404":
+          description: Not Found - The specified built-in IDP user does not 
exist
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+              examples:
+                NotFoundException:
+                  $ref: "#/components/examples/IdpNotFoundException"
+        "5xx":
+          $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+    delete:
+      tags:
+        - IDP
+      summary: Remove built-in IDP user
+      operationId: removeIdpUser
+      responses:
+        "200":
+          $ref: "../openapi.yaml#/components/responses/RemoveResponse"
+        "400":
+          $ref: "../openapi.yaml#/components/responses/BadRequestErrorResponse"
+        "403":
+          $ref: "#/components/responses/IdpForbiddenErrorResponse"
+        "404":
+          description: Not Found - The specified built-in IDP user does not 
exist
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+              examples:
+                NotFoundException:
+                  $ref: "#/components/examples/IdpNotFoundException"
+        "5xx":
+          $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+  /idp/groups:
+    post:
+      tags:
+        - IDP
+      summary: Add built-in IDP group
+      description: Creates a built-in IDP group with the given name.
+      operationId: addIdpGroup
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/AddGroupRequest"
+            examples:
+              AddGroupRequest:
+                $ref: "#/components/examples/AddGroupRequest"
+      responses:
+        "200":
+          description: Returns the added built-in IDP group
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "#/components/schemas/IdpGroupResponse"
+              examples:
+                IdpGroupResponse:
+                  $ref: "#/components/examples/IdpGroupResponse"
+        "400":
+          $ref: "../openapi.yaml#/components/responses/BadRequestErrorResponse"
+        "403":
+          $ref: "#/components/responses/IdpForbiddenErrorResponse"
+        "409":
+          description: Conflict - The built-in IDP group already exists
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+              examples:
+                AlreadyExistsException:
+                  $ref: "#/components/examples/IdpAlreadyExistsException"
+        "5xx":
+          $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+  /idp/groups/{group}:
+    parameters:
+      - $ref: "../openapi.yaml#/components/parameters/group"
+
+    get:
+      tags:
+        - IDP
+      summary: Get built-in IDP group
+      description: Returns the specified built-in IDP group, including member 
usernames.
+      operationId: getIdpGroup
+      responses:
+        "200":
+          description: Returns the built-in IDP group object
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "#/components/schemas/IdpGroupResponse"
+              examples:
+                IdpGroupResponse:
+                  $ref: "#/components/examples/IdpGroupResponse"
+        "403":
+          $ref: "#/components/responses/IdpForbiddenErrorResponse"
+        "404":
+          description: Not Found - The specified built-in IDP group does not 
exist
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+              examples:
+                NotFoundException:
+                  $ref: "#/components/examples/IdpNotFoundException"
+        "5xx":
+          $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+    delete:
+      tags:
+        - IDP
+      summary: Remove built-in IDP group
+      operationId: removeIdpGroup
+      parameters:
+        - $ref: "../openapi.yaml#/components/parameters/force"
+      responses:
+        "200":
+          $ref: "../openapi.yaml#/components/responses/RemoveResponse"
+        "400":
+          $ref: "../openapi.yaml#/components/responses/BadRequestErrorResponse"
+        "403":
+          $ref: "#/components/responses/IdpForbiddenErrorResponse"
+        "404":
+          description: Not Found - The specified built-in IDP group does not 
exist
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+              examples:
+                NotFoundException:
+                  $ref: "#/components/examples/IdpNotFoundException"
+        "405":
+          description: Method Not Allowed - The group is not empty and force 
is false
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+              examples:
+                GroupNotEmptyException:
+                  $ref: "#/components/examples/IdpGroupNotEmptyException"
+        "5xx":
+          $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+  /idp/groups/{group}/users:
+    parameters:
+      - $ref: "../openapi.yaml#/components/parameters/group"
+
+    put:
+      tags:
+        - IDP
+      summary: Change built-in IDP group membership
+      description: >
+        Adds and/or removes users from the specified built-in IDP group in a 
single request,
+        similar to tag association. At least one of `usersToAdd` or 
`usersToRemove` must be set.
+      operationId: changeIdpGroupMembership
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/GroupMembershipChangeRequest"
+            examples:
+              GroupMembershipChangeRequest:
+                $ref: "#/components/examples/GroupMembershipChangeRequest"
+      responses:
+        "200":
+          description: Returns the built-in IDP group after membership changes
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "#/components/schemas/IdpGroupResponse"
+              examples:
+                IdpGroupResponse:
+                  $ref: "#/components/examples/IdpGroupResponse"
+        "400":
+          $ref: "../openapi.yaml#/components/responses/BadRequestErrorResponse"
+        "403":
+          $ref: "#/components/responses/IdpForbiddenErrorResponse"
+        "404":
+          description: Not Found - The specified built-in IDP group or user 
does not exist
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+              examples:
+                NotFoundException:
+                  $ref: "#/components/examples/IdpNotFoundException"
+        "5xx":
+          $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+components:
+  schemas:
+    IdpUser:
+      type: object
+      required:
+        - name
+      properties:
+        name:
+          type: string
+          description: The username of the built-in IDP user
+        groups:
+          type: array
+          items:
+            type: string
+          description: The built-in IDP groups the user belongs to
+
+    IdpGroup:
+      type: object
+      required:
+        - name
+      properties:
+        name:
+          type: string
+          description: The name of the built-in IDP group
+        users:
+          type: array
+          items:
+            type: string
+          description: The usernames of members in the built-in IDP group
+
+    AddUserRequest:
+      type: object
+      required:
+        - user
+        - password
+      properties:
+        user:
+          type: string
+          description: >
+            The username to add. Request payloads use `user`, while user 
objects in
+            responses use `name` (see IdpUser), matching the server JSON field 
names.
+        password:
+          type: string
+          format: password
+          description: The password of the built-in IDP user to add
+          writeOnly: true
+
+    ChangePasswordRequest:
+      type: object
+      required:
+        - password
+      properties:
+        password:
+          type: string
+          format: password
+          description: The new password of the built-in IDP user
+          writeOnly: true
+
+    AddGroupRequest:
+      type: object
+      required:
+        - group
+      properties:
+        group:
+          type: string
+          description: >
+            The group name to add. Request payloads use `group`, while group 
objects in
+            responses use `name` (see IdpGroup), matching the server JSON 
field names.
+
+    GroupMembershipChangeRequest:
+      type: object
+      anyOf:
+        - required:
+            - usersToAdd
+        - required:
+            - usersToRemove
+      properties:
+        usersToAdd:
+          type: array
+          items:
+            type: string
+          minItems: 1
+          description: The usernames to add to the built-in IDP group
+        usersToRemove:
+          type: array
+          items:
+            type: string
+          minItems: 1
+          description: The usernames to remove from the built-in IDP group
+
+    IdpUserResponse:
+      type: object
+      properties:
+        code:
+          type: integer
+          format: int32
+          description: Status code of the response
+          enum:
+            - 0
+        user:
+          $ref: "#/components/schemas/IdpUser"
+
+    IdpGroupResponse:
+      type: object
+      properties:
+        code:
+          type: integer
+          format: int32
+          description: Status code of the response
+          enum:
+            - 0
+        group:
+          $ref: "#/components/schemas/IdpGroup"
+
+  responses:
+    IdpForbiddenErrorResponse:
+      description: Forbidden - Built-in IDP REST APIs are disabled or the 
caller is not authorized
+      content:
+        application/vnd.gravitino.v1+json:
+          schema:
+            $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+
+  examples:
+    AddUserRequest:
+      value: {
+        "user": "alice",
+        "password": "secret"
+      }
+
+    ChangePasswordRequest:
+      value: {
+        "password": "new-secret"
+      }
+
+    AddGroupRequest:
+      value: {
+        "group": "engineers"
+      }
+
+    GroupMembershipChangeRequest:
+      value: {
+        "usersToAdd": ["alice", "bob"],
+        "usersToRemove": ["carol"]
+      }
+
+    IdpUserResponse:
+      value: {
+        "code": 0,
+        "user": {
+          "name": "alice",
+          "groups": ["engineers"]
+        }
+      }
+
+    IdpGroupResponse:
+      value: {
+        "code": 0,
+        "group": {
+          "name": "engineers",
+          "users": ["alice", "bob"]
+        }
+      }
+
+    IdpNotFoundException:
+      value: {
+        "code": 1003,
+        "type": "NotFoundException",
+        "message": "Failed to operate built-in IdP user [alice] operation 
[GET], reason [User does not exist]"
+      }
+
+    IdpAlreadyExistsException:
+      value: {
+        "code": 1004,
+        "type": "AlreadyExistsException",
+        "message": "Failed to operate built-in IdP user [] operation [ADD], 
reason [User already exists]"
+      }
+
+    IdpGroupNotEmptyException:
+      value: {
+        "code": 1003,
+        "type": "IllegalStateException",
+        "message": "Failed to operate built-in IdP group [engineers] operation 
[REMOVE], reason [Group is not empty]"
+      }
diff --git a/docs/open-api/idp/openapi.yaml b/docs/open-api/idp/openapi.yaml
new file mode 100644
index 0000000000..76e064083f
--- /dev/null
+++ b/docs/open-api/idp/openapi.yaml
@@ -0,0 +1,69 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+---
+openapi: 3.0.3
+info:
+  title: Gravitino Built-in IDP REST API
+  license:
+    name: Apache 2.0
+    url: https://www.apache.org/licenses/LICENSE-2.0.html
+  version: 1.3.0-SNAPSHOT
+  description: |
+    OpenAPI specification for built-in IDP user and group management APIs 
exposed
+    by the `idp-basic` plugin when the `basic` authenticator is enabled.
+
+servers:
+  - url: "{scheme}://{host}:{port}/{basePath}"
+    description: Generic base server URL, with all parts configurable.
+    variables:
+      scheme:
+        description: The scheme of the URI, either http or https.
+        default: http
+      host:
+        description: The host address for the specified server
+        default: localhost
+      port:
+        description: The port used when addressing the host
+        default: "8090"
+      basePath:
+        description: Optional prefix to be appended to all routes
+        default: "api"
+
+security:
+  - BasicAuth: []
+
+paths:
+  /idp/users:
+    $ref: "./idp.yaml#/paths/~1idp~1users"
+
+  /idp/users/{user}:
+    $ref: "./idp.yaml#/paths/~1idp~1users~1%7Buser%7D"
+
+  /idp/groups:
+    $ref: "./idp.yaml#/paths/~1idp~1groups"
+
+  /idp/groups/{group}:
+    $ref: "./idp.yaml#/paths/~1idp~1groups~1%7Bgroup%7D"
+
+  /idp/groups/{group}/users:
+    $ref: "./idp.yaml#/paths/~1idp~1groups~1%7Bgroup%7D~1users"
+
+components:
+  securitySchemes:
+    BasicAuth:
+      $ref: "../openapi.yaml#/components/securitySchemes/BasicAuth"

Reply via email to