From b563b4721f5e840037436ea0d48ddafd969c67b1 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 9 Sep 2026 11:41:52 +0000 Subject: [PATCH 01/13] docs: migrate dvp specification to OpenAPI 3.2 --- content/reference/api/dvp/latest.yaml | 295 +++++------ hack/api-docs/adoption/dvp.json | 389 +++++++++++++++ hack/api-docs/adoption/dvp.patch | 692 ++++++++++++++++++++++++++ 3 files changed, 1235 insertions(+), 141 deletions(-) create mode 100644 hack/api-docs/adoption/dvp.json create mode 100644 hack/api-docs/adoption/dvp.patch diff --git a/content/reference/api/dvp/latest.yaml b/content/reference/api/dvp/latest.yaml index 01811d55bc7c..3d0c606a0c72 100644 --- a/content/reference/api/dvp/latest.yaml +++ b/content/reference/api/dvp/latest.yaml @@ -1,4 +1,4 @@ -openapi: 3.0.0 +openapi: 3.2.0 info: title: DVP Data API version: 1.0.0 @@ -6,75 +6,79 @@ info: url: https://docs.docker.com/assets/images/logo-docker-main.png href: /reference description: | - The Docker DVP Data API allows [Docker Verified Publishers](https://docs.docker.com/docker-hub/publish/) to view image pull analytics data for their namespaces. Analytics data can be retrieved in a CSV as raw data, or in a summary format. - - #### Summary data + The Docker DVP Data API allows [Docker Verified Publishers](https://docs.docker.com/docker-hub/publish/) to view image pull analytics data for their namespaces. Analytics data can be retrieved in a CSV as raw data, or in a summary format. + + #### Summary data - In your summary data CSV, you will have access to the data points listed below. You can request summary data for a complete week (Monday through Sunday) or for a complete month (available on the first day of the following month). + In your summary data CSV, you will have access to the data points listed below. You can request summary data for a complete week (Monday through Sunday) or for a complete month (available on the first day of the following month). - There are two levels of summary data: + There are two levels of summary data: - - Repository-level, a summary of every namespace and repository - - Tag- or digest-level, a summary of every namespace, repository, and reference - (tag or digest) + - Repository-level, a summary of every namespace and repository + - Tag- or digest-level, a summary of every namespace, repository, and reference + (tag or digest) - The summary data formats contain the following data points: + The summary data formats contain the following data points: - - Unique IP address count - - Pulls by tag count - - Pulls by digest count - - Version check count + - Unique IP address count + - Pulls by tag count + - Pulls by digest count + - Version check count - #### Raw data + #### Raw data - In your raw data CSV you will have access to the data points listed below. You can request raw data for a complete week (Monday through Sunday) or for a complete month (available on the first day of the following month). **Note:** each action is represented as a single row. - - - Type (industry) - - Host (cloud provider) - - Country (geolocation) - - Timestamp - - Namespace - - Repository - - Reference (digest is always included, tag is provided when available) - - HTTP request method - - Action, one of the following: - - Pull by tag - - Pull by digest - - Version check - - User-Agent + In your raw data CSV you will have access to the data points listed below. You can request raw data for a complete week (Monday through Sunday) or for a complete month (available on the first day of the following month). **Note:** each action is represented as a single row. + - Type (industry) + - Host (cloud provider) + - Country (geolocation) + - Timestamp + - Namespace + - Repository + - Reference (digest is always included, tag is provided when available) + - HTTP request method + - Action, one of the following: + - Pull by tag + - Pull by digest + - Version check + - User-Agent servers: - url: https://hub.docker.com/api/publisher/analytics/v1 security: - HubAuth: [] - -features.openapi: - schemaDefinitionsTagName: Schemas - tags: - name: authentication - x-displayName: Authentication Endpoints + summary: Authentication Endpoints + kind: nav + description: Authentication Endpoints reference. - name: namespaces - x-displayName: Namespace data + summary: Namespace data + kind: nav + description: Namespace data reference. - name: discovery - x-displayName: Discovery + summary: Discovery + kind: nav + description: Discovery reference. - name: responseDataFile - x-displayName: ResponseDataFile description: | - + [ResponseDataFile](#schema-ResponseDataFile) + summary: ResponseDataFile + kind: info - name: yearModel - x-displayName: Year Data Model description: | - + [YearModel](#schema-YearModel) + summary: Year Data Model + kind: info - name: monthModel - x-displayName: Month Data Model description: | - + [MonthModel](#schema-MonthModel) + summary: Month Data Model + kind: info - name: weekModel - x-displayName: Week Data Model description: | - - + [WeekModel](#schema-WeekModel) + summary: Week Data Model + kind: info x-tagGroups: - name: API tags: @@ -87,10 +91,8 @@ x-tagGroups: - yearModel - monthModel - weekModel - paths: /v2/users/login: - security: [] servers: - url: https://hub.docker.com post: @@ -114,20 +116,19 @@ paths: description: Login details. required: true responses: - 200: + "200": description: Authentication successful content: application/json: schema: $ref: "#/components/schemas/PostUsersLoginSuccessResponse" - 401: + "401": description: Authentication failed or second factor required content: application/json: schema: $ref: "#/components/schemas/PostUsersLoginErrorResponse" /v2/users/2fa-login: - security: [] servers: - url: https://hub.docker.com post: @@ -153,53 +154,54 @@ paths: description: Login details. required: true responses: - 200: + "200": description: Authentication successful content: application/json: schema: $ref: "#/components/schemas/PostUsersLoginSuccessResponse" - 401: + "401": description: Authentication failed or second factor required content: application/json: schema: $ref: "#/components/schemas/PostUsers2FALoginErrorResponse" - - /: get: - tags: [discovery] + tags: + - discovery summary: Get namespaces and repos description: Gets a list of your namespaces and repos which have data available. operationId: getNamespaces responses: - '200': + "200": description: Success content: application/json: schema: - $ref: '#/components/schemas/NamespaceData' + $ref: "#/components/schemas/NamespaceData" /namespaces: get: - tags: [discovery] + tags: + - discovery summary: Get user's namespaces description: Get metadata associated with the namespaces the user has access to, including extra repos associated with the namespaces. operationId: getUserNamespaces responses: - '200': + "200": description: Success content: application/json: schema: type: array items: - $ref: '#/components/schemas/NamespaceMetadata' - '401': + $ref: "#/components/schemas/NamespaceMetadata" + "401": description: Authentication failed or second factor required /namespaces/{namespace}: get: - tags: [discovery] + tags: + - discovery summary: Get namespace description: Gets metadata associated with specified namespace, including extra repos associated with the namespace. operationId: getNamespace @@ -211,15 +213,16 @@ paths: required: true description: Namespace to fetch data for responses: - '200': + "200": description: Success content: application/json: schema: - $ref: '#/components/schemas/NamespaceMetadata' + $ref: "#/components/schemas/NamespaceMetadata" /namespaces/{namespace}/pulls: get: - tags: [namespaces] + tags: + - namespaces summary: Get pull data description: Gets pulls for the given namespace. operationId: getNamespacePulls @@ -233,33 +236,34 @@ paths: - in: query name: timespan schema: - $ref: '#/components/schemas/TimespanType' + $ref: "#/components/schemas/TimespanType" required: false description: Timespan type for fetching data - in: query name: period schema: - $ref: '#/components/schemas/PeriodType' + $ref: "#/components/schemas/PeriodType" required: false description: Relative period of the period to fetch data - in: query name: group schema: - $ref: '#/components/schemas/GroupType' + $ref: "#/components/schemas/GroupType" required: false description: Field to group the data by responses: - '200': + "200": description: Success content: application/json: schema: - $ref: '#/components/schemas/PullData' - '404': + $ref: "#/components/schemas/PullData" + "404": description: Not found - namespace doesn't exist or user does not have permission to access it /namespaces/{namespace}/repos/{repo}/pulls: get: - tags: [namespaces] + tags: + - namespaces summary: Get pull data description: Gets pulls for the given repo. operationId: getRepoPulls @@ -279,33 +283,34 @@ paths: - in: query name: timespan schema: - $ref: '#/components/schemas/TimespanType' + $ref: "#/components/schemas/TimespanType" required: false description: Timespan type for fetching data - in: query name: period schema: - $ref: '#/components/schemas/PeriodType' + $ref: "#/components/schemas/PeriodType" required: false description: Relative period of the period to fetch data - in: query name: group schema: - $ref: '#/components/schemas/GroupType' + $ref: "#/components/schemas/GroupType" required: false description: Field to group the data by responses: - '200': + "200": description: Success content: application/json: schema: - $ref: '#/components/schemas/PullData' - '404': + $ref: "#/components/schemas/PullData" + "404": description: Not found - repo doesn't exist or user does not have permission to access it /namespaces/{namespace}/pulls/exports/years: get: - tags: [namespaces] + tags: + - namespaces summary: Get years with data description: Gets a list of years that have data for the given namespace. operationId: getNamespaceYears @@ -317,15 +322,16 @@ paths: required: true description: Namespace to fetch data for responses: - '200': + "200": description: Success content: application/json: schema: - $ref: '#/components/schemas/YearData' + $ref: "#/components/schemas/YearData" /namespaces/{namespace}/pulls/exports/years/{year}/{timespantype}: get: - tags: [namespaces] + tags: + - namespaces summary: Get timespans with data description: Gets a list of timespans of the given type that have data for the given namespace and year. operationId: getNamespaceTimespans @@ -345,19 +351,20 @@ paths: - in: path name: timespantype schema: - $ref: '#/components/schemas/TimespanType' + $ref: "#/components/schemas/TimespanType" required: true description: Type of timespan to fetch data for responses: - '200': + "200": description: Success content: application/json: schema: - $ref: '#/components/schemas/TimespanData' + $ref: "#/components/schemas/TimespanData" /namespaces/{namespace}/pulls/exports/years/{year}/{timespantype}/{timespan}: get: - tags: [namespaces] + tags: + - namespaces summary: Get namespace metadata for timespan description: Gets info about data for the given namespace and timespan. operationId: getNamespaceTimespanMetadata @@ -377,7 +384,7 @@ paths: - in: path name: timespantype schema: - $ref: '#/components/schemas/TimespanType' + $ref: "#/components/schemas/TimespanType" required: true description: Type of timespan to fetch data for - in: path @@ -387,17 +394,18 @@ paths: required: true description: Timespan to fetch data for responses: - '200': + "200": description: Success content: application/json: schema: - $ref: '#/components/schemas/TimespanModel' - '404': + $ref: "#/components/schemas/TimespanModel" + "404": description: Not Found /namespaces/{namespace}/pulls/exports/years/{year}/{timespantype}/{timespan}/{dataview}: get: - tags: [namespaces] + tags: + - namespaces summary: Get namespace data for timespan description: Gets a list of URLs that can be used to download the pull data for the given namespace and timespan. operationId: getNamespaceDataByTimespan @@ -417,7 +425,7 @@ paths: - in: path name: timespantype schema: - $ref: '#/components/schemas/TimespanType' + $ref: "#/components/schemas/TimespanType" required: true description: Type of timespan to fetch data for - in: path @@ -429,19 +437,20 @@ paths: - in: path name: dataview schema: - $ref: '#/components/schemas/DataviewType' + $ref: "#/components/schemas/DataviewType" required: true description: Type of data to fetch responses: - '200': + "200": description: Success content: application/json: schema: - $ref: '#/components/schemas/ResponseData' + $ref: "#/components/schemas/ResponseData" /repos/pulls: get: - tags: [namespaces] + tags: + - namespaces summary: Get pull data for multiple repos description: Gets pull for the given repos. operationId: getManyReposPulls @@ -457,29 +466,28 @@ paths: - in: query name: timespan schema: - $ref: '#/components/schemas/TimespanType' + $ref: "#/components/schemas/TimespanType" required: false description: Timespan type for fetching data - in: query name: period schema: - $ref: '#/components/schemas/PeriodType' + $ref: "#/components/schemas/PeriodType" required: false description: Relative period of the period to fetch data - in: query name: group schema: - $ref: '#/components/schemas/GroupType' + $ref: "#/components/schemas/GroupType" required: false description: Field to group the data by responses: - '200': + "200": description: Success content: application/json: schema: - $ref: '#/components/schemas/ReposPullData' - + $ref: "#/components/schemas/ReposPullData" components: schemas: UsersLoginRequest: @@ -494,9 +502,7 @@ components: type: string example: myusername password: - description: - The password or personal access token (PAT) of the Docker Hub - account to authenticate with. + description: The password or personal access token (PAT) of the Docker Hub account to authenticate with. type: string example: hunter2 PostUsersLoginSuccessResponse: @@ -510,7 +516,6 @@ components: This token can be used in the HTTP Authorization header as a JWT to authenticate with the Docker Hub APIs. type: string example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c - nullable: false PostUsersLoginErrorResponse: description: failed user login response or second factor required type: object @@ -521,15 +526,12 @@ components: description: Description of the error. type: string example: Incorrect authentication credentials - nullable: false login_2fa_token: - description: - Short-lived token to be used on `/v2/users/2fa-login` to - complete the authentication. This field is present only if 2FA is - enabled. - type: string + description: Short-lived token to be used on `/v2/users/2fa-login` to complete the authentication. This field is present only if 2FA is enabled. + type: + - string + - "null" example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c - nullable: true Users2FALoginRequest: description: Second factor user login details type: object @@ -542,9 +544,7 @@ components: type: string example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c code: - description: - The Time-based One-Time Password of the Docker Hub account to - authenticate with. + description: The Time-based One-Time Password of the Docker Hub account to authenticate with. type: string example: 123456 PostUsers2FALoginErrorResponse: @@ -555,16 +555,14 @@ components: description: Description of the error. type: string example: Incorrect authentication credentials - nullable: false - ResponseData: properties: data: type: array description: | List of urls to download the data. When the data is large, the data will be split into multiple files. - items: - $ref: '#/components/schemas/ResponseDataFile' + items: + $ref: "#/components/schemas/ResponseDataFile" ResponseDataFile: properties: url: @@ -589,31 +587,31 @@ components: datasets: type: array items: - $ref: '#/components/schemas/DatasetModel' + $ref: "#/components/schemas/DatasetModel" DatasetModel: properties: name: - $ref: '#/components/schemas/DatasetType' + $ref: "#/components/schemas/DatasetType" views: type: array items: - $ref: '#/components/schemas/DataviewType' + $ref: "#/components/schemas/DataviewType" timespans: type: array items: - $ref: '#/components/schemas/TimespanType' + $ref: "#/components/schemas/TimespanType" PullData: properties: pulls: type: array items: - $ref: '#/components/schemas/PullModel' + $ref: "#/components/schemas/PullModel" ReposPullData: properties: repos: type: object additionalProperties: - $ref: '#/components/schemas/PullData' + $ref: "#/components/schemas/PullData" PullModel: properties: start: @@ -630,13 +628,12 @@ components: type: integer country: type: string - YearData: properties: years: type: array items: - $ref: '#/components/schemas/YearModel' + $ref: "#/components/schemas/YearModel" YearModel: properties: year: @@ -646,7 +643,7 @@ components: months: type: array items: - $ref: '#/components/schemas/MonthModel' + $ref: "#/components/schemas/MonthModel" MonthModel: properties: month: @@ -656,37 +653,50 @@ components: weeks: type: array items: - $ref: '#/components/schemas/WeekModel' + $ref: "#/components/schemas/WeekModel" WeekModel: properties: week: type: integer TimespanType: type: string - enum: [months,weeks] + enum: + - months + - weeks PeriodType: type: string - enum: [last-2-months,last-3-months,last-6-months,last-12-months] + enum: + - last-2-months + - last-3-months + - last-6-months + - last-12-months DataviewType: type: string - enum: [raw,summary,repo-summary,namespace-summary] + enum: + - raw + - summary + - repo-summary + - namespace-summary DatasetType: type: string - enum: [pulls] + enum: + - pulls TimespanModel: oneOf: - - $ref: '#/components/schemas/MonthModel' - - $ref: '#/components/schemas/WeekModel' + - $ref: "#/components/schemas/MonthModel" + - $ref: "#/components/schemas/WeekModel" TimespanData: oneOf: - - $ref: '#/components/schemas/MonthData' - - $ref: '#/components/schemas/WeekData' + - $ref: "#/components/schemas/MonthData" + - $ref: "#/components/schemas/WeekData" GroupType: type: string - enum: [repo,namespace] + enum: + - repo + - namespace securitySchemes: HubAuth: - type: https + type: http scheme: bearer bearerFormat: JWT description: | @@ -694,3 +704,6 @@ components: This authentication documentation is duplicated from the [Hub API Authentication docs](https://docs.docker.com/reference/api/hub/latest/#tag/authentication) x-displayName: Docker Hub Authentication +jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base +x-features-openapi: + schemaDefinitionsTagName: Schemas diff --git a/hack/api-docs/adoption/dvp.json b/hack/api-docs/adoption/dvp.json new file mode 100644 index 000000000000..034699bd2ccd --- /dev/null +++ b/hack/api-docs/adoption/dvp.json @@ -0,0 +1,389 @@ +{ + "api": "dvp", + "source": { + "id": "dvp", + "product": "dvp", + "title": "Publisher analytics", + "source": "content/reference/api/dvp/latest.yaml", + "owner": "docker/docs (product authority to confirm)", + "manual": "/manuals/docker-hub/repos/manage/trusted-content/insights-analytics.md", + "connection": "hosted", + "auth": "Analytics calls use a bearer token. The copied source retains the legacy login flow pending product confirmation.", + "guides": [], + "sha256": "4aeacaaa1237609c3dd9cec43f9807a229ac98a0e9b837f291c02df3cf89172a" + }, + "convertedSha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "profile": "docker-docs-prototype-1", + "changes": [ + { + "pointer": "/jsonSchemaDialect", + "beforePresent": false, + "afterPresent": true, + "after": "https://spec.openapis.org/oas/3.1/dialect/base", + "id": "dvp-03ee85af235e", + "stage": "oas32-header", + "classification": "mechanical conversion", + "rationale": "Adopt the common OpenAPI version and its selected schema dialect.", + "evidence": "API-DOCUMENTATION-ARCHITECTURE.md S1", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/jsonSchemaDialect" + }, + { + "pointer": "/openapi", + "beforePresent": true, + "afterPresent": true, + "before": "3.0.0", + "after": "3.2.0", + "id": "dvp-71377657b6ae", + "stage": "oas32-header", + "classification": "mechanical conversion", + "rationale": "Adopt the common OpenAPI version and its selected schema dialect.", + "evidence": "API-DOCUMENTATION-ARCHITECTURE.md S1", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/openapi", + "destinationPointer": "/openapi" + }, + { + "pointer": "/components/schemas/PostUsers2FALoginErrorResponse/properties/detail/nullable", + "beforePresent": true, + "afterPresent": false, + "before": false, + "id": "dvp-4a84441cce53", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/PostUsers2FALoginErrorResponse/properties/detail/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/PostUsersLoginErrorResponse/properties/detail/nullable", + "beforePresent": true, + "afterPresent": false, + "before": false, + "id": "dvp-209f129099a9", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/PostUsersLoginErrorResponse/properties/detail/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "dvp-74ca1738d170", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "dvp-14920c5fdaca", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/type", + "destinationPointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/type" + }, + { + "pointer": "/components/schemas/PostUsersLoginSuccessResponse/properties/token/nullable", + "beforePresent": true, + "afterPresent": false, + "before": false, + "id": "dvp-f4382a2a3adb", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/PostUsersLoginSuccessResponse/properties/token/nullable", + "destinationPointer": null + }, + { + "pointer": "/tags", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "name": "authentication", + "x-displayName": "Authentication Endpoints" + }, + { + "name": "namespaces", + "x-displayName": "Namespace data" + }, + { + "name": "discovery", + "x-displayName": "Discovery" + }, + { + "name": "responseDataFile", + "x-displayName": "ResponseDataFile", + "description": "\n" + }, + { + "name": "yearModel", + "x-displayName": "Year Data Model", + "description": "\n" + }, + { + "name": "monthModel", + "x-displayName": "Month Data Model", + "description": "\n" + }, + { + "name": "weekModel", + "x-displayName": "Week Data Model", + "description": "\n" + } + ], + "after": [ + { + "name": "authentication", + "summary": "Authentication Endpoints", + "kind": "nav", + "description": "Authentication Endpoints reference." + }, + { + "name": "namespaces", + "summary": "Namespace data", + "kind": "nav", + "description": "Namespace data reference." + }, + { + "name": "discovery", + "summary": "Discovery", + "kind": "nav", + "description": "Discovery reference." + }, + { + "name": "responseDataFile", + "description": "[ResponseDataFile](#schema-ResponseDataFile)\n", + "summary": "ResponseDataFile", + "kind": "info" + }, + { + "name": "yearModel", + "description": "[YearModel](#schema-YearModel)\n", + "summary": "Year Data Model", + "kind": "info" + }, + { + "name": "monthModel", + "description": "[MonthModel](#schema-MonthModel)\n", + "summary": "Month Data Model", + "kind": "info" + }, + { + "name": "weekModel", + "description": "[WeekModel](#schema-WeekModel)\n", + "summary": "Week Data Model", + "kind": "info" + } + ], + "id": "dvp-8d93cf25f3e7", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/tags", + "destinationPointer": "/tags" + }, + { + "pointer": "/tags", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "name": "authentication", + "summary": "Authentication Endpoints", + "kind": "nav", + "description": "Authentication Endpoints reference." + }, + { + "name": "namespaces", + "summary": "Namespace data", + "kind": "nav", + "description": "Namespace data reference." + }, + { + "name": "discovery", + "summary": "Discovery", + "kind": "nav", + "description": "Discovery reference." + }, + { + "name": "responseDataFile", + "description": "\n", + "summary": "ResponseDataFile", + "kind": "info" + }, + { + "name": "yearModel", + "description": "\n", + "summary": "Year Data Model", + "kind": "info" + }, + { + "name": "monthModel", + "description": "\n", + "summary": "Month Data Model", + "kind": "info" + }, + { + "name": "weekModel", + "description": "\n", + "summary": "Week Data Model", + "kind": "info" + } + ], + "after": [ + { + "name": "authentication", + "summary": "Authentication Endpoints", + "kind": "nav", + "description": "Authentication Endpoints reference." + }, + { + "name": "namespaces", + "summary": "Namespace data", + "kind": "nav", + "description": "Namespace data reference." + }, + { + "name": "discovery", + "summary": "Discovery", + "kind": "nav", + "description": "Discovery reference." + }, + { + "name": "responseDataFile", + "description": "[ResponseDataFile](#schema-ResponseDataFile)\n", + "summary": "ResponseDataFile", + "kind": "info" + }, + { + "name": "yearModel", + "description": "[YearModel](#schema-YearModel)\n", + "summary": "Year Data Model", + "kind": "info" + }, + { + "name": "monthModel", + "description": "[MonthModel](#schema-MonthModel)\n", + "summary": "Month Data Model", + "kind": "info" + }, + { + "name": "weekModel", + "description": "[WeekModel](#schema-WeekModel)\n", + "summary": "Week Data Model", + "kind": "info" + } + ], + "id": "dvp-8c67a3d8bd5a", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/tags", + "destinationPointer": "/tags" + }, + { + "pointer": "/components/securitySchemes/HubAuth/type", + "beforePresent": true, + "afterPresent": true, + "before": "https", + "after": "http", + "id": "dvp-0825c9518516", + "stage": "dvp-structural-correction", + "classification": "evidence-backed correction", + "rationale": "Use the standard http bearer scheme and move invalid path security to each operation without changing the documented requirement.", + "evidence": "Existing HubAuth bearer definition and path-level security declarations", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/securitySchemes/HubAuth/type", + "destinationPointer": "/components/securitySchemes/HubAuth/type" + }, + { + "pointer": "/features.openapi", + "beforePresent": true, + "afterPresent": false, + "before": { + "schemaDefinitionsTagName": "Schemas" + }, + "id": "dvp-133a84bacaf5", + "stage": "dvp-structural-correction", + "classification": "evidence-backed correction", + "rationale": "Use the standard http bearer scheme and move invalid path security to each operation without changing the documented requirement.", + "evidence": "Existing HubAuth bearer definition and path-level security declarations", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/features.openapi", + "destinationPointer": null + }, + { + "pointer": "/paths/~1v2~1users~12fa-login/security", + "beforePresent": true, + "afterPresent": false, + "before": [], + "id": "dvp-bbb175aad84a", + "stage": "dvp-structural-correction", + "classification": "evidence-backed correction", + "rationale": "Use the standard http bearer scheme and move invalid path security to each operation without changing the documented requirement.", + "evidence": "Existing HubAuth bearer definition and path-level security declarations", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1users~12fa-login/security", + "destinationPointer": null + }, + { + "pointer": "/paths/~1v2~1users~1login/security", + "beforePresent": true, + "afterPresent": false, + "before": [], + "id": "dvp-a0ab3de3a681", + "stage": "dvp-structural-correction", + "classification": "evidence-backed correction", + "rationale": "Use the standard http bearer scheme and move invalid path security to each operation without changing the documented requirement.", + "evidence": "Existing HubAuth bearer definition and path-level security declarations", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1users~1login/security", + "destinationPointer": null + }, + { + "pointer": "/x-features-openapi", + "beforePresent": false, + "afterPresent": true, + "after": { + "schemaDefinitionsTagName": "Schemas" + }, + "id": "dvp-b66b5e3c3512", + "stage": "dvp-structural-correction", + "classification": "evidence-backed correction", + "rationale": "Use the standard http bearer scheme and move invalid path security to each operation without changing the documented requirement.", + "evidence": "Existing HubAuth bearer definition and path-level security declarations", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/x-features-openapi" + } + ] +} diff --git a/hack/api-docs/adoption/dvp.patch b/hack/api-docs/adoption/dvp.patch new file mode 100644 index 000000000000..b7aa184cbba6 --- /dev/null +++ b/hack/api-docs/adoption/dvp.patch @@ -0,0 +1,692 @@ +--- original/dvp.yaml ++++ converted/dvp.yaml +@@ -1,4 +1,4 @@ +-openapi: 3.0.0 ++openapi: 3.2.0 + info: + title: DVP Data API + version: 1.0.0 +@@ -6,75 +6,79 @@ + url: https://docs.docker.com/assets/images/logo-docker-main.png + href: /reference + description: | +- The Docker DVP Data API allows [Docker Verified Publishers](https://docs.docker.com/docker-hub/publish/) to view image pull analytics data for their namespaces. Analytics data can be retrieved in a CSV as raw data, or in a summary format. +- +- #### Summary data +- +- In your summary data CSV, you will have access to the data points listed below. You can request summary data for a complete week (Monday through Sunday) or for a complete month (available on the first day of the following month). +- +- There are two levels of summary data: +- +- - Repository-level, a summary of every namespace and repository +- - Tag- or digest-level, a summary of every namespace, repository, and reference +- (tag or digest) +- +- The summary data formats contain the following data points: +- +- - Unique IP address count +- - Pulls by tag count +- - Pulls by digest count +- - Version check count +- +- #### Raw data +- +- In your raw data CSV you will have access to the data points listed below. You can request raw data for a complete week (Monday through Sunday) or for a complete month (available on the first day of the following month). **Note:** each action is represented as a single row. +- +- - Type (industry) +- - Host (cloud provider) +- - Country (geolocation) +- - Timestamp +- - Namespace +- - Repository +- - Reference (digest is always included, tag is provided when available) +- - HTTP request method +- - Action, one of the following: +- - Pull by tag +- - Pull by digest +- - Version check +- - User-Agent +- ++ The Docker DVP Data API allows [Docker Verified Publishers](https://docs.docker.com/docker-hub/publish/) to view image pull analytics data for their namespaces. Analytics data can be retrieved in a CSV as raw data, or in a summary format. ++ ++ #### Summary data ++ ++ In your summary data CSV, you will have access to the data points listed below. You can request summary data for a complete week (Monday through Sunday) or for a complete month (available on the first day of the following month). ++ ++ There are two levels of summary data: ++ ++ - Repository-level, a summary of every namespace and repository ++ - Tag- or digest-level, a summary of every namespace, repository, and reference ++ (tag or digest) ++ ++ The summary data formats contain the following data points: ++ ++ - Unique IP address count ++ - Pulls by tag count ++ - Pulls by digest count ++ - Version check count ++ ++ #### Raw data ++ ++ In your raw data CSV you will have access to the data points listed below. You can request raw data for a complete week (Monday through Sunday) or for a complete month (available on the first day of the following month). **Note:** each action is represented as a single row. ++ ++ - Type (industry) ++ - Host (cloud provider) ++ - Country (geolocation) ++ - Timestamp ++ - Namespace ++ - Repository ++ - Reference (digest is always included, tag is provided when available) ++ - HTTP request method ++ - Action, one of the following: ++ - Pull by tag ++ - Pull by digest ++ - Version check ++ - User-Agent + servers: + - url: https://hub.docker.com/api/publisher/analytics/v1 + security: + - HubAuth: [] +- +-features.openapi: +- schemaDefinitionsTagName: Schemas +- + tags: + - name: authentication +- x-displayName: Authentication Endpoints ++ summary: Authentication Endpoints ++ kind: nav ++ description: Authentication Endpoints reference. + - name: namespaces +- x-displayName: Namespace data ++ summary: Namespace data ++ kind: nav ++ description: Namespace data reference. + - name: discovery +- x-displayName: Discovery ++ summary: Discovery ++ kind: nav ++ description: Discovery reference. + - name: responseDataFile +- x-displayName: ResponseDataFile + description: | +- ++ [ResponseDataFile](#schema-ResponseDataFile) ++ summary: ResponseDataFile ++ kind: info + - name: yearModel +- x-displayName: Year Data Model + description: | +- ++ [YearModel](#schema-YearModel) ++ summary: Year Data Model ++ kind: info + - name: monthModel +- x-displayName: Month Data Model + description: | +- ++ [MonthModel](#schema-MonthModel) ++ summary: Month Data Model ++ kind: info + - name: weekModel +- x-displayName: Week Data Model + description: | +- +- ++ [WeekModel](#schema-WeekModel) ++ summary: Week Data Model ++ kind: info + x-tagGroups: + - name: API + tags: +@@ -87,10 +91,8 @@ + - yearModel + - monthModel + - weekModel +- + paths: + /v2/users/login: +- security: [] + servers: + - url: https://hub.docker.com + post: +@@ -114,20 +116,19 @@ + description: Login details. + required: true + responses: +- 200: ++ "200": + description: Authentication successful + content: + application/json: + schema: + $ref: "#/components/schemas/PostUsersLoginSuccessResponse" +- 401: ++ "401": + description: Authentication failed or second factor required + content: + application/json: + schema: + $ref: "#/components/schemas/PostUsersLoginErrorResponse" + /v2/users/2fa-login: +- security: [] + servers: + - url: https://hub.docker.com + post: +@@ -153,53 +154,54 @@ + description: Login details. + required: true + responses: +- 200: ++ "200": + description: Authentication successful + content: + application/json: + schema: + $ref: "#/components/schemas/PostUsersLoginSuccessResponse" +- 401: ++ "401": + description: Authentication failed or second factor required + content: + application/json: + schema: + $ref: "#/components/schemas/PostUsers2FALoginErrorResponse" +- +- + /: + get: +- tags: [discovery] ++ tags: ++ - discovery + summary: Get namespaces and repos + description: Gets a list of your namespaces and repos which have data available. + operationId: getNamespaces + responses: +- '200': ++ "200": + description: Success + content: + application/json: + schema: +- $ref: '#/components/schemas/NamespaceData' ++ $ref: "#/components/schemas/NamespaceData" + /namespaces: + get: +- tags: [discovery] ++ tags: ++ - discovery + summary: Get user's namespaces + description: Get metadata associated with the namespaces the user has access to, including extra repos associated with the namespaces. + operationId: getUserNamespaces + responses: +- '200': ++ "200": + description: Success + content: + application/json: + schema: + type: array + items: +- $ref: '#/components/schemas/NamespaceMetadata' +- '401': ++ $ref: "#/components/schemas/NamespaceMetadata" ++ "401": + description: Authentication failed or second factor required + /namespaces/{namespace}: + get: +- tags: [discovery] ++ tags: ++ - discovery + summary: Get namespace + description: Gets metadata associated with specified namespace, including extra repos associated with the namespace. + operationId: getNamespace +@@ -211,15 +213,16 @@ + required: true + description: Namespace to fetch data for + responses: +- '200': ++ "200": + description: Success + content: + application/json: + schema: +- $ref: '#/components/schemas/NamespaceMetadata' ++ $ref: "#/components/schemas/NamespaceMetadata" + /namespaces/{namespace}/pulls: + get: +- tags: [namespaces] ++ tags: ++ - namespaces + summary: Get pull data + description: Gets pulls for the given namespace. + operationId: getNamespacePulls +@@ -233,33 +236,34 @@ + - in: query + name: timespan + schema: +- $ref: '#/components/schemas/TimespanType' ++ $ref: "#/components/schemas/TimespanType" + required: false + description: Timespan type for fetching data + - in: query + name: period + schema: +- $ref: '#/components/schemas/PeriodType' ++ $ref: "#/components/schemas/PeriodType" + required: false + description: Relative period of the period to fetch data + - in: query + name: group + schema: +- $ref: '#/components/schemas/GroupType' ++ $ref: "#/components/schemas/GroupType" + required: false + description: Field to group the data by + responses: +- '200': ++ "200": + description: Success + content: + application/json: + schema: +- $ref: '#/components/schemas/PullData' +- '404': ++ $ref: "#/components/schemas/PullData" ++ "404": + description: Not found - namespace doesn't exist or user does not have permission to access it + /namespaces/{namespace}/repos/{repo}/pulls: + get: +- tags: [namespaces] ++ tags: ++ - namespaces + summary: Get pull data + description: Gets pulls for the given repo. + operationId: getRepoPulls +@@ -279,33 +283,34 @@ + - in: query + name: timespan + schema: +- $ref: '#/components/schemas/TimespanType' ++ $ref: "#/components/schemas/TimespanType" + required: false + description: Timespan type for fetching data + - in: query + name: period + schema: +- $ref: '#/components/schemas/PeriodType' ++ $ref: "#/components/schemas/PeriodType" + required: false + description: Relative period of the period to fetch data + - in: query + name: group + schema: +- $ref: '#/components/schemas/GroupType' ++ $ref: "#/components/schemas/GroupType" + required: false + description: Field to group the data by + responses: +- '200': ++ "200": + description: Success + content: + application/json: + schema: +- $ref: '#/components/schemas/PullData' +- '404': ++ $ref: "#/components/schemas/PullData" ++ "404": + description: Not found - repo doesn't exist or user does not have permission to access it + /namespaces/{namespace}/pulls/exports/years: + get: +- tags: [namespaces] ++ tags: ++ - namespaces + summary: Get years with data + description: Gets a list of years that have data for the given namespace. + operationId: getNamespaceYears +@@ -317,15 +322,16 @@ + required: true + description: Namespace to fetch data for + responses: +- '200': ++ "200": + description: Success + content: + application/json: + schema: +- $ref: '#/components/schemas/YearData' ++ $ref: "#/components/schemas/YearData" + /namespaces/{namespace}/pulls/exports/years/{year}/{timespantype}: + get: +- tags: [namespaces] ++ tags: ++ - namespaces + summary: Get timespans with data + description: Gets a list of timespans of the given type that have data for the given namespace and year. + operationId: getNamespaceTimespans +@@ -345,19 +351,20 @@ + - in: path + name: timespantype + schema: +- $ref: '#/components/schemas/TimespanType' ++ $ref: "#/components/schemas/TimespanType" + required: true + description: Type of timespan to fetch data for + responses: +- '200': ++ "200": + description: Success + content: + application/json: + schema: +- $ref: '#/components/schemas/TimespanData' ++ $ref: "#/components/schemas/TimespanData" + /namespaces/{namespace}/pulls/exports/years/{year}/{timespantype}/{timespan}: + get: +- tags: [namespaces] ++ tags: ++ - namespaces + summary: Get namespace metadata for timespan + description: Gets info about data for the given namespace and timespan. + operationId: getNamespaceTimespanMetadata +@@ -377,7 +384,7 @@ + - in: path + name: timespantype + schema: +- $ref: '#/components/schemas/TimespanType' ++ $ref: "#/components/schemas/TimespanType" + required: true + description: Type of timespan to fetch data for + - in: path +@@ -387,17 +394,18 @@ + required: true + description: Timespan to fetch data for + responses: +- '200': ++ "200": + description: Success + content: + application/json: + schema: +- $ref: '#/components/schemas/TimespanModel' +- '404': ++ $ref: "#/components/schemas/TimespanModel" ++ "404": + description: Not Found + /namespaces/{namespace}/pulls/exports/years/{year}/{timespantype}/{timespan}/{dataview}: + get: +- tags: [namespaces] ++ tags: ++ - namespaces + summary: Get namespace data for timespan + description: Gets a list of URLs that can be used to download the pull data for the given namespace and timespan. + operationId: getNamespaceDataByTimespan +@@ -417,7 +425,7 @@ + - in: path + name: timespantype + schema: +- $ref: '#/components/schemas/TimespanType' ++ $ref: "#/components/schemas/TimespanType" + required: true + description: Type of timespan to fetch data for + - in: path +@@ -429,19 +437,20 @@ + - in: path + name: dataview + schema: +- $ref: '#/components/schemas/DataviewType' ++ $ref: "#/components/schemas/DataviewType" + required: true + description: Type of data to fetch + responses: +- '200': ++ "200": + description: Success + content: + application/json: + schema: +- $ref: '#/components/schemas/ResponseData' ++ $ref: "#/components/schemas/ResponseData" + /repos/pulls: + get: +- tags: [namespaces] ++ tags: ++ - namespaces + summary: Get pull data for multiple repos + description: Gets pull for the given repos. + operationId: getManyReposPulls +@@ -457,29 +466,28 @@ + - in: query + name: timespan + schema: +- $ref: '#/components/schemas/TimespanType' ++ $ref: "#/components/schemas/TimespanType" + required: false + description: Timespan type for fetching data + - in: query + name: period + schema: +- $ref: '#/components/schemas/PeriodType' ++ $ref: "#/components/schemas/PeriodType" + required: false + description: Relative period of the period to fetch data + - in: query + name: group + schema: +- $ref: '#/components/schemas/GroupType' ++ $ref: "#/components/schemas/GroupType" + required: false + description: Field to group the data by + responses: +- '200': ++ "200": + description: Success + content: + application/json: + schema: +- $ref: '#/components/schemas/ReposPullData' +- ++ $ref: "#/components/schemas/ReposPullData" + components: + schemas: + UsersLoginRequest: +@@ -494,9 +502,7 @@ + type: string + example: myusername + password: +- description: +- The password or personal access token (PAT) of the Docker Hub +- account to authenticate with. ++ description: The password or personal access token (PAT) of the Docker Hub account to authenticate with. + type: string + example: hunter2 + PostUsersLoginSuccessResponse: +@@ -510,7 +516,6 @@ + This token can be used in the HTTP Authorization header as a JWT to authenticate with the Docker Hub APIs. + type: string + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c +- nullable: false + PostUsersLoginErrorResponse: + description: failed user login response or second factor required + type: object +@@ -521,15 +526,12 @@ + description: Description of the error. + type: string + example: Incorrect authentication credentials +- nullable: false + login_2fa_token: +- description: +- Short-lived token to be used on `/v2/users/2fa-login` to +- complete the authentication. This field is present only if 2FA is +- enabled. +- type: string ++ description: Short-lived token to be used on `/v2/users/2fa-login` to complete the authentication. This field is present only if 2FA is enabled. ++ type: ++ - string ++ - "null" + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c +- nullable: true + Users2FALoginRequest: + description: Second factor user login details + type: object +@@ -542,9 +544,7 @@ + type: string + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + code: +- description: +- The Time-based One-Time Password of the Docker Hub account to +- authenticate with. ++ description: The Time-based One-Time Password of the Docker Hub account to authenticate with. + type: string + example: 123456 + PostUsers2FALoginErrorResponse: +@@ -555,16 +555,14 @@ + description: Description of the error. + type: string + example: Incorrect authentication credentials +- nullable: false +- + ResponseData: + properties: + data: + type: array + description: | + List of urls to download the data. When the data is large, the data will be split into multiple files. +- items: +- $ref: '#/components/schemas/ResponseDataFile' ++ items: ++ $ref: "#/components/schemas/ResponseDataFile" + ResponseDataFile: + properties: + url: +@@ -589,31 +587,31 @@ + datasets: + type: array + items: +- $ref: '#/components/schemas/DatasetModel' ++ $ref: "#/components/schemas/DatasetModel" + DatasetModel: + properties: + name: +- $ref: '#/components/schemas/DatasetType' ++ $ref: "#/components/schemas/DatasetType" + views: + type: array + items: +- $ref: '#/components/schemas/DataviewType' ++ $ref: "#/components/schemas/DataviewType" + timespans: + type: array + items: +- $ref: '#/components/schemas/TimespanType' ++ $ref: "#/components/schemas/TimespanType" + PullData: + properties: + pulls: + type: array + items: +- $ref: '#/components/schemas/PullModel' ++ $ref: "#/components/schemas/PullModel" + ReposPullData: + properties: + repos: + type: object + additionalProperties: +- $ref: '#/components/schemas/PullData' ++ $ref: "#/components/schemas/PullData" + PullModel: + properties: + start: +@@ -630,13 +628,12 @@ + type: integer + country: + type: string +- + YearData: + properties: + years: + type: array + items: +- $ref: '#/components/schemas/YearModel' ++ $ref: "#/components/schemas/YearModel" + YearModel: + properties: + year: +@@ -646,7 +643,7 @@ + months: + type: array + items: +- $ref: '#/components/schemas/MonthModel' ++ $ref: "#/components/schemas/MonthModel" + MonthModel: + properties: + month: +@@ -656,37 +653,50 @@ + weeks: + type: array + items: +- $ref: '#/components/schemas/WeekModel' ++ $ref: "#/components/schemas/WeekModel" + WeekModel: + properties: + week: + type: integer + TimespanType: + type: string +- enum: [months,weeks] ++ enum: ++ - months ++ - weeks + PeriodType: + type: string +- enum: [last-2-months,last-3-months,last-6-months,last-12-months] ++ enum: ++ - last-2-months ++ - last-3-months ++ - last-6-months ++ - last-12-months + DataviewType: + type: string +- enum: [raw,summary,repo-summary,namespace-summary] ++ enum: ++ - raw ++ - summary ++ - repo-summary ++ - namespace-summary + DatasetType: + type: string +- enum: [pulls] ++ enum: ++ - pulls + TimespanModel: + oneOf: +- - $ref: '#/components/schemas/MonthModel' +- - $ref: '#/components/schemas/WeekModel' ++ - $ref: "#/components/schemas/MonthModel" ++ - $ref: "#/components/schemas/WeekModel" + TimespanData: + oneOf: +- - $ref: '#/components/schemas/MonthData' +- - $ref: '#/components/schemas/WeekData' ++ - $ref: "#/components/schemas/MonthData" ++ - $ref: "#/components/schemas/WeekData" + GroupType: + type: string +- enum: [repo,namespace] ++ enum: ++ - repo ++ - namespace + securitySchemes: + HubAuth: +- type: https ++ type: http + scheme: bearer + bearerFormat: JWT + description: | +@@ -694,3 +704,6 @@ + + This authentication documentation is duplicated from the [Hub API Authentication docs](https://docs.docker.com/reference/api/hub/latest/#tag/authentication) + x-displayName: Docker Hub Authentication ++jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base ++x-features-openapi: ++ schemaDefinitionsTagName: Schemas From 88bb0faf0c9a01c69f10f54e23e2337e6cad101c Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 9 Sep 2026 11:41:56 +0000 Subject: [PATCH 02/13] docs: migrate registry specification to OpenAPI 3.2 --- content/reference/api/registry/latest.yaml | 228 +++----- hack/api-docs/adoption/registry.json | 247 +++++++++ hack/api-docs/adoption/registry.patch | 606 +++++++++++++++++++++ 3 files changed, 938 insertions(+), 143 deletions(-) create mode 100644 hack/api-docs/adoption/registry.json create mode 100644 hack/api-docs/adoption/registry.patch diff --git a/content/reference/api/registry/latest.yaml b/content/reference/api/registry/latest.yaml index 445cc7f98f95..809419006d80 100644 --- a/content/reference/api/registry/latest.yaml +++ b/content/reference/api/registry/latest.yaml @@ -1,4 +1,4 @@ -openapi: 3.0.3 +openapi: 3.2.0 info: title: Supported registry API for Docker Hub description: | @@ -11,14 +11,13 @@ info: It focuses on pulling, pushing, and deleting images. It does not cover the full OCI Distribution Specification. For the complete OCI specification, see [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec). + version: "2" servers: - description: Docker Hub registry API x-audience: public url: https://registry-1.docker.io - tags: - name: overview - x-displayName: Overview description: | All endpoints in this API are prefixed by the version and repository name, for example: @@ -38,29 +37,28 @@ tags: 1. Consist of path components matching `[a-z0-9]+(?:[._-][a-z0-9]+)*` 2. If more than one component, they must be separated by `/` 3. Full repository name must be fewer than 256 characters - - + summary: Overview + kind: info - name: authentication - x-displayName: Authentication description: | Specifies registry authentication. externalDocs: description: Detailed authentication workflow and token usage url: https://docs.docker.com/reference/api/registry/auth/ - + summary: Authentication + kind: info - name: Manifests - x-displayName: Manifests description: | Image manifests are JSON documents that describe an image: its configuration blob, the digests of each layer blob, and metadata such as media‑types and annotations. - + summary: Manifests + kind: nav - name: Blobs - x-displayName: Blobs description: | Blobs are the binary objects referenced from manifests: the config JSON and one or more compressed layer tarballs. - + summary: Blobs + kind: nav - name: pull - x-displayName: Pulling Images description: | Pulling an image involves retrieving the manifest and downloading each of the image's layer blobs. This section outlines the general steps followed by a working example. @@ -79,94 +77,93 @@ tags: # Step 1: Get a bearer token TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/ubuntu:pull" | jq -r .token) - + # Step 2: Get the image manifest. In this example, an image manifest list is returned. curl -s -H "Authorization: Bearer $TOKEN" \ -H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" \ https://registry-1.docker.io/v2/library/ubuntu/manifests/latest \ -o manifest-list.json - + # Step 3a: Parse the `manifests[]` array to locate the digest for your target platform (e.g., `linux/amd64`). IMAGE_MANIFEST_DIGEST=$(jq -r '.manifests[] | select(.platform.architecture == "amd64" and .platform.os == "linux") | .digest' manifest-list.json) - + # Step 3b: Get the platform-specific image manifest curl -s -H "Authorization: Bearer $TOKEN" \ -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ https://registry-1.docker.io/v2/library/ubuntu/manifests/$IMAGE_MANIFEST_DIGEST \ -o manifest.json - + # Step 4: Send a HEAD request to check if the layer blob exists DIGEST=$(jq -r '.layers[0].digest' manifest.json) curl -I -H "Authorization: Bearer $TOKEN" \ https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST - + # Step 5: Download the layer blob curl -L -H "Authorization: Bearer $TOKEN" \ https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST ``` - - This example pulls the manifest and the first layer for the `ubuntu:latest` image on the `linux/amd64` platform. Repeat steps 4 and 5 for each digest in the `.layers[]` array in the manifest. - + This example pulls the manifest and the first layer for the `ubuntu:latest` image on the `linux/amd64` platform. Repeat steps 4 and 5 for each digest in the `.layers[]` array in the manifest. + summary: Pulling Images + kind: info - name: push - x-displayName: Pushing Images description: | Pushing an image involves uploading any image blobs (such as the config or layers), and then uploading the manifest that references those blobs. - + This section outlines the basic steps to push an image using the registry API. - + 1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/) - + 2. [Check if the blob exists](#operation/CheckBlobExists) using a `HEAD` request for each blob digest. - + 3. If the blob does not exist, [upload the blob](#operation/CompleteBlobUpload) using a monolithic `PUT` request: - First, [initiate the upload](#operation/InitiateBlobUpload) with `POST`. - Then [upload and complete](#operation/CompleteBlobUpload) with `PUT`. **Note**: Alternatively, you can upload the blob in multiple chunks by using `PATCH` requests to send each chunk, followed by a final `PUT` request to complete the upload. This is known as a [chunked upload](#operation/UploadBlobChunk) and is useful for large blobs or when resuming interrupted uploads. - + 4. [Upload the image manifest](#operation/PutImageManifest) using a `PUT` request to associate the config and layers. - + The following bash script example pushes a dummy config blob and manifest to `yourusername/helloworld:latest` on Docker Hub. You can replace `yourusername` with your Docker Hub username and `dckr_pat` with your Docker Hub personal access token. - + ```bash #!/bin/bash - + USERNAME=yourusername PASSWORD=dckr_pat REPO=yourusername/helloworld TAG=latest CONFIG=config.json MIME_TYPE=application/vnd.docker.container.image.v1+json - + # Step 1: Get a bearer token TOKEN=$(curl -s -u "$USERNAME:$PASSWORD" \ "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:push,pull" \ | jq -r .token) - + # Create a dummy config blob and compute its digest echo '{"architecture":"amd64","os":"linux","config":{},"rootfs":{"type":"layers","diff_ids":[]}}' > $CONFIG DIGEST="sha256:$(sha256sum $CONFIG | awk '{print $1}')" - + # Step 2: Check if the blob exists STATUS=$(curl -s -o /dev/null -w "%{http_code}" -I \ -H "Authorization: Bearer $TOKEN" \ https://registry-1.docker.io/v2/$REPO/blobs/$DIGEST) - + if [ "$STATUS" != "200" ]; then # Step 3: Upload blob using monolithic upload LOCATION=$(curl -sI -X POST \ -H "Authorization: Bearer $TOKEN" \ https://registry-1.docker.io/v2/$REPO/blobs/uploads/ \ | grep -i Location | tr -d '\r' | awk '{print $2}') - + curl -s -X PUT "$LOCATION&digest=$DIGEST" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/octet-stream" \ --data-binary @$CONFIG fi - + # Step 4: Upload the manifest that references the config blob MANIFEST=$(cat <` header. - x-codeSamples: - lang: Bash label: cURL @@ -300,7 +296,7 @@ paths: required: false description: | Media type(s) the client supports for the manifest. - + The registry supports the following media types: - application/vnd.docker.distribution.manifest.v2+json - application/vnd.docker.distribution.manifest.list.v2+json @@ -308,7 +304,6 @@ paths: - application/vnd.oci.image.index.v1+json schema: type: string - responses: "200": description: Manifest fetched successfully. @@ -367,28 +362,19 @@ paths: docker-manifest: summary: Docker image manifest (schema v2) value: - { - "schemaVersion": 2, - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "config": { - "mediaType": "application/vnd.docker.container.image.v1+json", - "size": 7023, - "digest": "sha256:123456abcdef..." - }, - "layers": [ - { - "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "size": 32654, - "digest": "sha256:abcdef123456..." - }, - { - "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "size": 16724, - "digest": "sha256:7890abcdef12..." - } - ] - } - + schemaVersion: 2 + mediaType: application/vnd.docker.distribution.manifest.v2+json + config: + mediaType: application/vnd.docker.container.image.v1+json + size: 7023 + digest: sha256:123456abcdef... + layers: + - mediaType: application/vnd.docker.image.rootfs.diff.tar.gzip + size: 32654 + digest: sha256:abcdef123456... + - mediaType: application/vnd.docker.image.rootfs.diff.tar.gzip + size: 16724 + digest: sha256:7890abcdef12... "400": description: Invalid name or reference. "401": @@ -399,8 +385,6 @@ paths: description: Repository or manifest not found. "429": description: Too many requests. - - put: tags: - Manifests @@ -459,7 +443,6 @@ paths: schema: type: string example: application/vnd.docker.distribution.manifest.v2+json - requestBody: required: true content: @@ -512,28 +495,20 @@ paths: digest: type: string example: sha256:abcdef123456... - examples: sample-manifest: summary: Sample Docker image manifest (schema v2) value: - { - "schemaVersion": 2, - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "config": { - "mediaType": "application/vnd.docker.container.image.v1+json", - "size": 7023, - "digest": "sha256:123456abcdef..." - }, - "layers": [ - { - "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "size": 32654, - "digest": "sha256:abcdef123456..." - } - ] - } - + schemaVersion: 2 + mediaType: application/vnd.docker.distribution.manifest.v2+json + config: + mediaType: application/vnd.docker.container.image.v1+json + size: 7023 + digest: sha256:123456abcdef... + layers: + - mediaType: application/vnd.docker.image.rootfs.diff.tar.gzip + size: 32654 + digest: sha256:abcdef123456... responses: "201": description: Manifest created successfully. @@ -578,7 +553,6 @@ paths: - Determining the digest or size of a manifest before downloading or deleting This endpoint requires authentication with pull scope. - parameters: - name: name in: path @@ -642,12 +616,12 @@ paths: schema: type: string example: application/vnd.docker.distribution.manifest.v2+json - "404": - description: Manifest not found. "401": description: Authentication required. "403": description: Access denied. + "404": + description: Manifest not found. "429": description: Too many requests. delete: @@ -733,7 +707,6 @@ paths: curl -i -X POST \ -H "Authorization: Bearer $TOKEN" \ https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/ - - lang: Bash label: cURL (Cross-Repository Blob Mount) source: | @@ -741,7 +714,6 @@ paths: curl -i -X POST \ -H "Authorization: Bearer $TOKEN" \ "https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/?mount=sha256:abc123def456...&from=library/busybox" - parameters: - name: name in: path @@ -770,7 +742,6 @@ paths: schema: type: string description: Bearer token for authentication with `push` scope - responses: "201": description: Blob successfully mounted from another repository. @@ -865,7 +836,6 @@ paths: schema: type: string example: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6... - responses: "200": description: Blob exists @@ -885,32 +855,12 @@ paths: schema: type: string example: application/octet-stream - content: - application/json: - examples: - blob-check-request: - summary: Sample request - value: - method: HEAD - url: /v2/library/ubuntu/blobs/sha256:abc123def4567890... - headers: - Authorization: Bearer - Accept: '*/*' - blob-check-response: - summary: Sample 200 response headers - value: - status: 200 OK - headers: - Docker-Content-Digest: sha256:abc123def4567890... - Content-Length: 32654 - Content-Type: application/octet-stream - - "404": - description: Blob not found "401": description: Authentication required "403": description: Access denied + "404": + description: Blob not found "429": description: Too many requests get: @@ -957,7 +907,6 @@ paths: type: string description: Bearer token with pull scope example: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6... - responses: "200": description: Blob content returned directly @@ -985,8 +934,7 @@ paths: examples: small-layer: summary: Example binary blob (gzipped tar layer) - value: "" - + value: "307": description: Temporary redirect to blob location headers: @@ -1031,7 +979,7 @@ paths: in: path required: true description: Repository Name - example : library/ubuntu + example: library/ubuntu schema: type: string - name: uuid @@ -1047,7 +995,6 @@ paths: schema: type: string example: Bearer eyJhbGciOi... - responses: "204": description: Upload in progress. No body is returned. @@ -1075,7 +1022,6 @@ paths: description: Upload session not found "429": description: Too many requests - put: tags: - Blobs @@ -1089,7 +1035,6 @@ paths: This endpoint supports: - Monolithic uploads (upload entire blob in this request) - Finalizing chunked uploads (last chunk plus `digest`) - x-codeSamples: - lang: Bash label: cURL @@ -1100,8 +1045,6 @@ paths: -H "Content-Type: application/octet-stream" \ --data-binary @layer.tar.gz \ "https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123?digest=sha256:abcd1234..." - - parameters: - name: name in: path @@ -1130,7 +1073,6 @@ paths: schema: type: string example: Bearer eyJhbGciOi... - requestBody: required: false content: @@ -1141,8 +1083,7 @@ paths: examples: layer-upload: summary: Layer tarball blob - value: "" - + value: responses: "201": description: Upload completed successfully @@ -1174,7 +1115,6 @@ paths: description: Requested range not satisfiable (if used in chunked mode) "429": description: Too many requests - patch: tags: - Blobs @@ -1229,7 +1169,6 @@ paths: type: string example: bytes 0-65535 description: Optional. Byte range of the chunk being sent - requestBody: required: true content: @@ -1240,8 +1179,7 @@ paths: examples: chunk-0: summary: Upload chunk 0 of a blob - value: "" - + value: responses: "202": description: Chunk accepted and stored @@ -1288,7 +1226,6 @@ paths: - The client wants to clean up unused upload sessions After cancellation, the UUID is no longer valid and a new `POST` must be issued to restart the upload. - x-codeSamples: - lang: Bash label: cURL @@ -1297,7 +1234,6 @@ paths: curl -X DELETE \ -H "Authorization: Bearer $TOKEN" \ https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123` - parameters: - name: name in: path @@ -1319,7 +1255,6 @@ paths: schema: type: string example: Bearer eyJhbGciOi... - responses: "204": description: Upload session cancelled successfully. No body is returned. @@ -1337,8 +1272,6 @@ paths: description: Upload session not found "429": description: Too many requests - - x-tagGroups: - name: General tags: @@ -1351,3 +1284,12 @@ x-tagGroups: tags: - Manifests - Blobs +jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base +components: + securitySchemes: + registryToken: + type: http + scheme: bearer + description: Follow the WWW-Authenticate challenge and obtain a repository-scoped registry token. This is separate from the Hub API token exchange. +security: + - registryToken: [] diff --git a/hack/api-docs/adoption/registry.json b/hack/api-docs/adoption/registry.json new file mode 100644 index 000000000000..35d8f50dffa6 --- /dev/null +++ b/hack/api-docs/adoption/registry.json @@ -0,0 +1,247 @@ +{ + "api": "registry", + "source": { + "id": "registry", + "product": "registry", + "title": "Registry", + "source": "content/reference/api/registry/latest.yaml", + "owner": "docker/docs (product authority to confirm)", + "manual": "/manuals/docker-hub/repos/", + "connection": "hosted", + "auth": "Follow the WWW-Authenticate challenge and obtain a repository-scoped registry token. This is separate from the Hub API token exchange.", + "guides": [ + "/reference/api/registry/auth.md" + ], + "sha256": "229198e078ee30400c0359311f5baaf23a1f80563a1c2e82834f17f2db0d9fd1" + }, + "convertedSha256": "3257829998629249bd9bd27a79996f922169e0c98677b67fb1dc87f565391a01", + "profile": "docker-docs-prototype-1", + "changes": [ + { + "pointer": "/jsonSchemaDialect", + "beforePresent": false, + "afterPresent": true, + "after": "https://spec.openapis.org/oas/3.1/dialect/base", + "id": "registry-03ee85af235e", + "stage": "oas32-header", + "classification": "mechanical conversion", + "rationale": "Adopt the common OpenAPI version and its selected schema dialect.", + "evidence": "API-DOCUMENTATION-ARCHITECTURE.md S1", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/jsonSchemaDialect" + }, + { + "pointer": "/openapi", + "beforePresent": true, + "afterPresent": true, + "before": "3.0.3", + "after": "3.2.0", + "id": "registry-71377657b6ae", + "stage": "oas32-header", + "classification": "mechanical conversion", + "rationale": "Adopt the common OpenAPI version and its selected schema dialect.", + "evidence": "API-DOCUMENTATION-ARCHITECTURE.md S1", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/openapi", + "destinationPointer": "/openapi" + }, + { + "pointer": "/tags", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "name": "overview", + "x-displayName": "Overview", + "description": "All endpoints in this API are prefixed by the version and repository name, for example:\n\n```\n/v2//\n```\n\nThis format provides structured access control and URI-based scoping of image operations.\n\nFor example, to interact with the `library/ubuntu` repository, use:\n\n```\n/v2/library/ubuntu/\n```\n\nRepository names must meet these requirements:\n1. Consist of path components matching `[a-z0-9]+(?:[._-][a-z0-9]+)*`\n2. If more than one component, they must be separated by `/`\n3. Full repository name must be fewer than 256 characters\n" + }, + { + "name": "authentication", + "x-displayName": "Authentication", + "description": "Specifies registry authentication.\n", + "externalDocs": { + "description": "Detailed authentication workflow and token usage", + "url": "https://docs.docker.com/reference/api/registry/auth/" + } + }, + { + "name": "Manifests", + "x-displayName": "Manifests", + "description": "Image manifests are JSON documents that describe an image: its configuration blob, the digests of each layer blob, and metadata such as media‑types and annotations.\n" + }, + { + "name": "Blobs", + "x-displayName": "Blobs", + "description": "Blobs are the binary objects referenced from manifests:\nthe config JSON and one or more compressed layer tarballs.\n" + }, + { + "name": "pull", + "x-displayName": "Pulling Images", + "description": "Pulling an image involves retrieving the manifest and downloading each of the image's layer blobs. This section outlines the general steps followed by a working example.\n\n1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/).\n2. [Get the image manifest](#operation/GetImageManifest).\n3. If the response in the previous step is a multi-architecture manifest list, you must do the following:\n - Parse the `manifests[]` array to locate the digest for your target platform (e.g., `linux/amd64`).\n - [Get the image manifest](#operation/GetImageManifest) using the located digest.\n4. [Check if the blob exists](#operation/CheckBlobExists) before downloading. The client should send a `HEAD` request for each layer digest.\n5. [Download each layer blob](#operation/GetBlob) using the digest obtained from the manifest. The client should send a `GET` request for each layer digest.\n\nThe following bash script example pulls `library/ubuntu:latest` from Docker Hub.\n\n```bash\n#!/bin/bash\n\n# Step 1: Get a bearer token\nTOKEN=$(curl -s \"https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/ubuntu:pull\" | jq -r .token)\n\n# Step 2: Get the image manifest. In this example, an image manifest list is returned.\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Accept: application/vnd.docker.distribution.manifest.list.v2+json\" \\\n https://registry-1.docker.io/v2/library/ubuntu/manifests/latest \\\n -o manifest-list.json\n\n# Step 3a: Parse the `manifests[]` array to locate the digest for your target platform (e.g., `linux/amd64`).\nIMAGE_MANIFEST_DIGEST=$(jq -r '.manifests[] | select(.platform.architecture == \"amd64\" and .platform.os == \"linux\") | .digest' manifest-list.json)\n\n# Step 3b: Get the platform-specific image manifest\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Accept: application/vnd.docker.distribution.manifest.v2+json\" \\\n https://registry-1.docker.io/v2/library/ubuntu/manifests/$IMAGE_MANIFEST_DIGEST \\\n -o manifest.json\n\n# Step 4: Send a HEAD request to check if the layer blob exists\nDIGEST=$(jq -r '.layers[0].digest' manifest.json)\ncurl -I -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST\n\n# Step 5: Download the layer blob\ncurl -L -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST\n```\n\nThis example pulls the manifest and the first layer for the `ubuntu:latest` image on the `linux/amd64` platform. Repeat steps 4 and 5 for each digest in the `.layers[]` array in the manifest.\n" + }, + { + "name": "push", + "x-displayName": "Pushing Images", + "description": "Pushing an image involves uploading any image blobs (such as the config or layers), and then uploading the manifest that references those blobs.\n\nThis section outlines the basic steps to push an image using the registry API.\n\n1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/)\n\n2. [Check if the blob exists](#operation/CheckBlobExists) using a `HEAD` request for each blob digest.\n\n3. If the blob does not exist, [upload the blob](#operation/CompleteBlobUpload) using a monolithic `PUT` request:\n - First, [initiate the upload](#operation/InitiateBlobUpload) with `POST`.\n - Then [upload and complete](#operation/CompleteBlobUpload) with `PUT`.\n\n **Note**: Alternatively, you can upload the blob in multiple chunks by using `PATCH` requests to send each chunk, followed by a final `PUT` request to complete the upload. This is known as a [chunked upload](#operation/UploadBlobChunk) and is useful for large blobs or when resuming interrupted uploads.\n\n\n4. [Upload the image manifest](#operation/PutImageManifest) using a `PUT` request to associate the config and layers.\n\nThe following bash script example pushes a dummy config blob and manifest to `yourusername/helloworld:latest` on Docker Hub. You can replace `yourusername` with your Docker Hub username and `dckr_pat` with your Docker Hub personal access token.\n\n```bash\n#!/bin/bash\n\nUSERNAME=yourusername\nPASSWORD=dckr_pat\nREPO=yourusername/helloworld\nTAG=latest\nCONFIG=config.json\nMIME_TYPE=application/vnd.docker.container.image.v1+json\n\n# Step 1: Get a bearer token\nTOKEN=$(curl -s -u \"$USERNAME:$PASSWORD\" \\\n\"https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:push,pull\" \\\n| jq -r .token)\n\n# Create a dummy config blob and compute its digest\necho '{\"architecture\":\"amd64\",\"os\":\"linux\",\"config\":{},\"rootfs\":{\"type\":\"layers\",\"diff_ids\":[]}}' > $CONFIG\nDIGEST=\"sha256:$(sha256sum $CONFIG | awk '{print $1}')\"\n\n# Step 2: Check if the blob exists\nSTATUS=$(curl -s -o /dev/null -w \"%{http_code}\" -I \\\n -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/$REPO/blobs/$DIGEST)\n\nif [ \"$STATUS\" != \"200\" ]; then\n # Step 3: Upload blob using monolithic upload\n LOCATION=$(curl -sI -X POST \\\n -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/$REPO/blobs/uploads/ \\\n | grep -i Location | tr -d '\\r' | awk '{print $2}')\n\n curl -s -X PUT \"$LOCATION&digest=$DIGEST\" \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/octet-stream\" \\\n --data-binary @$CONFIG\nfi\n\n# Step 4: Upload the manifest that references the config blob\nMANIFEST=$(cat < **Note**\n>\n> Manifest deletion operations may experience latency and could return a `500 Internal Server Error` during deletion. The system automatically retries the deletion in the background, so the manifest will eventually be removed. You do not need to manually retry the request.\n\nThis section outlines the basic steps to delete an image using the registry API.\n\n1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/).\n2. [Get the manifest](#operation/GetImageManifest) using the image's tag.\n3. Retrieve the `Docker-Content-Digest` header from the manifest response. This digest uniquely identifies the manifest.\n4. [Delete the manifest](#operation/DeleteImageManifest) using a `DELETE` request and the digest.\n\nThe following bash script example deletes the `latest` tag from `yourusername/helloworld` on Docker Hub. Replace `yourusername` with your Docker Hub username and `dckr_pat` with your Docker Hub personal access token.\n\n```bash\n#!/bin/bash\n\nUSERNAME=yourusername\nPASSWORD=dckr_pat\nREPO=yourusername/helloworld\nTAG=latest\n\n# Step 1: Get a bearer token\nTOKEN=$(curl -s -u \"$USERNAME:$PASSWORD\" \\\n \"https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:pull,push,delete\" \\\n | jq -r .token)\n\n# Step 2 and 3: Get the manifest and extract the digest from response headers\nDIGEST=$(curl -sI -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Accept: application/vnd.docker.distribution.manifest.v2+json\" \\\n https://registry-1.docker.io/v2/$REPO/manifests/$TAG \\\n | grep -i Docker-Content-Digest | tr -d '\\r' | awk '{print $2}')\n\necho \"Deleting manifest with digest: $DIGEST\"\n\n# Step 4: Delete the manifest by digest\ncurl -s -X DELETE \\\n -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/$REPO/manifests/$DIGEST\n\necho \"Deleted image: $REPO@$DIGEST\"\n```\n\nThis example deletes the manifest for the `latest` tag. To fully delete all references to an image, ensure no other tags or referrers point to the same manifest digest.\n" + } + ], + "after": [ + { + "name": "overview", + "description": "All endpoints in this API are prefixed by the version and repository name, for example:\n\n```\n/v2//\n```\n\nThis format provides structured access control and URI-based scoping of image operations.\n\nFor example, to interact with the `library/ubuntu` repository, use:\n\n```\n/v2/library/ubuntu/\n```\n\nRepository names must meet these requirements:\n1. Consist of path components matching `[a-z0-9]+(?:[._-][a-z0-9]+)*`\n2. If more than one component, they must be separated by `/`\n3. Full repository name must be fewer than 256 characters\n", + "summary": "Overview", + "kind": "info" + }, + { + "name": "authentication", + "description": "Specifies registry authentication.\n", + "externalDocs": { + "description": "Detailed authentication workflow and token usage", + "url": "https://docs.docker.com/reference/api/registry/auth/" + }, + "summary": "Authentication", + "kind": "info" + }, + { + "name": "Manifests", + "description": "Image manifests are JSON documents that describe an image: its configuration blob, the digests of each layer blob, and metadata such as media‑types and annotations.\n", + "summary": "Manifests", + "kind": "nav" + }, + { + "name": "Blobs", + "description": "Blobs are the binary objects referenced from manifests:\nthe config JSON and one or more compressed layer tarballs.\n", + "summary": "Blobs", + "kind": "nav" + }, + { + "name": "pull", + "description": "Pulling an image involves retrieving the manifest and downloading each of the image's layer blobs. This section outlines the general steps followed by a working example.\n\n1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/).\n2. [Get the image manifest](#operation/GetImageManifest).\n3. If the response in the previous step is a multi-architecture manifest list, you must do the following:\n - Parse the `manifests[]` array to locate the digest for your target platform (e.g., `linux/amd64`).\n - [Get the image manifest](#operation/GetImageManifest) using the located digest.\n4. [Check if the blob exists](#operation/CheckBlobExists) before downloading. The client should send a `HEAD` request for each layer digest.\n5. [Download each layer blob](#operation/GetBlob) using the digest obtained from the manifest. The client should send a `GET` request for each layer digest.\n\nThe following bash script example pulls `library/ubuntu:latest` from Docker Hub.\n\n```bash\n#!/bin/bash\n\n# Step 1: Get a bearer token\nTOKEN=$(curl -s \"https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/ubuntu:pull\" | jq -r .token)\n\n# Step 2: Get the image manifest. In this example, an image manifest list is returned.\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Accept: application/vnd.docker.distribution.manifest.list.v2+json\" \\\n https://registry-1.docker.io/v2/library/ubuntu/manifests/latest \\\n -o manifest-list.json\n\n# Step 3a: Parse the `manifests[]` array to locate the digest for your target platform (e.g., `linux/amd64`).\nIMAGE_MANIFEST_DIGEST=$(jq -r '.manifests[] | select(.platform.architecture == \"amd64\" and .platform.os == \"linux\") | .digest' manifest-list.json)\n\n# Step 3b: Get the platform-specific image manifest\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Accept: application/vnd.docker.distribution.manifest.v2+json\" \\\n https://registry-1.docker.io/v2/library/ubuntu/manifests/$IMAGE_MANIFEST_DIGEST \\\n -o manifest.json\n\n# Step 4: Send a HEAD request to check if the layer blob exists\nDIGEST=$(jq -r '.layers[0].digest' manifest.json)\ncurl -I -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST\n\n# Step 5: Download the layer blob\ncurl -L -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST\n```\n\nThis example pulls the manifest and the first layer for the `ubuntu:latest` image on the `linux/amd64` platform. Repeat steps 4 and 5 for each digest in the `.layers[]` array in the manifest.\n", + "summary": "Pulling Images", + "kind": "info" + }, + { + "name": "push", + "description": "Pushing an image involves uploading any image blobs (such as the config or layers), and then uploading the manifest that references those blobs.\n\nThis section outlines the basic steps to push an image using the registry API.\n\n1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/)\n\n2. [Check if the blob exists](#operation/CheckBlobExists) using a `HEAD` request for each blob digest.\n\n3. If the blob does not exist, [upload the blob](#operation/CompleteBlobUpload) using a monolithic `PUT` request:\n - First, [initiate the upload](#operation/InitiateBlobUpload) with `POST`.\n - Then [upload and complete](#operation/CompleteBlobUpload) with `PUT`.\n\n **Note**: Alternatively, you can upload the blob in multiple chunks by using `PATCH` requests to send each chunk, followed by a final `PUT` request to complete the upload. This is known as a [chunked upload](#operation/UploadBlobChunk) and is useful for large blobs or when resuming interrupted uploads.\n\n\n4. [Upload the image manifest](#operation/PutImageManifest) using a `PUT` request to associate the config and layers.\n\nThe following bash script example pushes a dummy config blob and manifest to `yourusername/helloworld:latest` on Docker Hub. You can replace `yourusername` with your Docker Hub username and `dckr_pat` with your Docker Hub personal access token.\n\n```bash\n#!/bin/bash\n\nUSERNAME=yourusername\nPASSWORD=dckr_pat\nREPO=yourusername/helloworld\nTAG=latest\nCONFIG=config.json\nMIME_TYPE=application/vnd.docker.container.image.v1+json\n\n# Step 1: Get a bearer token\nTOKEN=$(curl -s -u \"$USERNAME:$PASSWORD\" \\\n\"https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:push,pull\" \\\n| jq -r .token)\n\n# Create a dummy config blob and compute its digest\necho '{\"architecture\":\"amd64\",\"os\":\"linux\",\"config\":{},\"rootfs\":{\"type\":\"layers\",\"diff_ids\":[]}}' > $CONFIG\nDIGEST=\"sha256:$(sha256sum $CONFIG | awk '{print $1}')\"\n\n# Step 2: Check if the blob exists\nSTATUS=$(curl -s -o /dev/null -w \"%{http_code}\" -I \\\n -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/$REPO/blobs/$DIGEST)\n\nif [ \"$STATUS\" != \"200\" ]; then\n # Step 3: Upload blob using monolithic upload\n LOCATION=$(curl -sI -X POST \\\n -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/$REPO/blobs/uploads/ \\\n | grep -i Location | tr -d '\\r' | awk '{print $2}')\n\n curl -s -X PUT \"$LOCATION&digest=$DIGEST\" \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/octet-stream\" \\\n --data-binary @$CONFIG\nfi\n\n# Step 4: Upload the manifest that references the config blob\nMANIFEST=$(cat < **Note**\n>\n> Manifest deletion operations may experience latency and could return a `500 Internal Server Error` during deletion. The system automatically retries the deletion in the background, so the manifest will eventually be removed. You do not need to manually retry the request.\n\nThis section outlines the basic steps to delete an image using the registry API.\n\n1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/).\n2. [Get the manifest](#operation/GetImageManifest) using the image's tag.\n3. Retrieve the `Docker-Content-Digest` header from the manifest response. This digest uniquely identifies the manifest.\n4. [Delete the manifest](#operation/DeleteImageManifest) using a `DELETE` request and the digest.\n\nThe following bash script example deletes the `latest` tag from `yourusername/helloworld` on Docker Hub. Replace `yourusername` with your Docker Hub username and `dckr_pat` with your Docker Hub personal access token.\n\n```bash\n#!/bin/bash\n\nUSERNAME=yourusername\nPASSWORD=dckr_pat\nREPO=yourusername/helloworld\nTAG=latest\n\n# Step 1: Get a bearer token\nTOKEN=$(curl -s -u \"$USERNAME:$PASSWORD\" \\\n \"https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:pull,push,delete\" \\\n | jq -r .token)\n\n# Step 2 and 3: Get the manifest and extract the digest from response headers\nDIGEST=$(curl -sI -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Accept: application/vnd.docker.distribution.manifest.v2+json\" \\\n https://registry-1.docker.io/v2/$REPO/manifests/$TAG \\\n | grep -i Docker-Content-Digest | tr -d '\\r' | awk '{print $2}')\n\necho \"Deleting manifest with digest: $DIGEST\"\n\n# Step 4: Delete the manifest by digest\ncurl -s -X DELETE \\\n -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/$REPO/manifests/$DIGEST\n\necho \"Deleted image: $REPO@$DIGEST\"\n```\n\nThis example deletes the manifest for the `latest` tag. To fully delete all references to an image, ensure no other tags or referrers point to the same manifest digest.\n", + "summary": "Deleting Images", + "kind": "info" + } + ], + "id": "registry-8d93cf25f3e7", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/tags", + "destinationPointer": "/tags" + }, + { + "pointer": "/components", + "beforePresent": false, + "afterPresent": true, + "after": { + "securitySchemes": { + "registryToken": { + "type": "http", + "scheme": "bearer", + "description": "Follow the WWW-Authenticate challenge and obtain a repository-scoped registry token. This is separate from the Hub API token exchange." + } + } + }, + "id": "registry-28462495ac89", + "stage": "registry-version-auth-assumption", + "classification": "provisional assumption", + "rationale": "Use protocol version 2 as provisional info.version and declare challenge-acquired bearer access. Confirm anonymous/public access alternatives and version identity with Hub owners.", + "evidence": "Registry description and content/reference/api/registry/auth.md", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/components" + }, + { + "pointer": "/info/version", + "beforePresent": false, + "afterPresent": true, + "after": "2", + "id": "registry-4d1e2c3e182a", + "stage": "registry-version-auth-assumption", + "classification": "provisional assumption", + "rationale": "Use protocol version 2 as provisional info.version and declare challenge-acquired bearer access. Confirm anonymous/public access alternatives and version identity with Hub owners.", + "evidence": "Registry description and content/reference/api/registry/auth.md", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/info/version" + }, + { + "pointer": "/security", + "beforePresent": false, + "afterPresent": true, + "after": [ + { + "registryToken": [] + } + ], + "id": "registry-ccc57ca992b3", + "stage": "registry-version-auth-assumption", + "classification": "provisional assumption", + "rationale": "Use protocol version 2 as provisional info.version and declare challenge-acquired bearer access. Confirm anonymous/public access alternatives and version identity with Hub owners.", + "evidence": "Registry description and content/reference/api/registry/auth.md", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/security" + }, + { + "pointer": "/paths/~1v2~1{name}~1blobs~1{digest}/head/responses/200/content", + "beforePresent": true, + "afterPresent": false, + "before": { + "application/json": { + "examples": { + "blob-check-request": { + "summary": "Sample request", + "value": { + "method": "HEAD", + "url": "/v2/library/ubuntu/blobs/sha256:abc123def4567890...", + "headers": { + "Authorization": "Bearer ", + "Accept": "*/*" + } + } + }, + "blob-check-response": { + "summary": "Sample 200 response headers", + "value": { + "status": "200 OK", + "headers": { + "Docker-Content-Digest": "sha256:abc123def4567890...", + "Content-Length": 32654, + "Content-Type": "application/octet-stream" + } + } + } + } + } + }, + "id": "registry-585e6c6be138", + "stage": "head-response-bodies", + "classification": "evidence-backed correction", + "rationale": "HEAD responses transfer headers without a response body. Preserve headers and status codes; remove declared content from HEAD responses.", + "evidence": "RFC 9110 section 9.3.2", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1{name}~1blobs~1{digest}/head/responses/200/content", + "destinationPointer": null + } + ] +} diff --git a/hack/api-docs/adoption/registry.patch b/hack/api-docs/adoption/registry.patch new file mode 100644 index 000000000000..6335a9c0a28a --- /dev/null +++ b/hack/api-docs/adoption/registry.patch @@ -0,0 +1,606 @@ +--- original/registry.yaml ++++ converted/registry.yaml +@@ -1,4 +1,4 @@ +-openapi: 3.0.3 ++openapi: 3.2.0 + info: + title: Supported registry API for Docker Hub + description: | +@@ -11,14 +11,13 @@ + It focuses on pulling, pushing, and deleting images. It does not cover the full OCI Distribution Specification. + + For the complete OCI specification, see [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec). ++ version: "2" + servers: + - description: Docker Hub registry API + x-audience: public + url: https://registry-1.docker.io +- + tags: + - name: overview +- x-displayName: Overview + description: | + All endpoints in this API are prefixed by the version and repository name, for example: + +@@ -38,29 +37,28 @@ + 1. Consist of path components matching `[a-z0-9]+(?:[._-][a-z0-9]+)*` + 2. If more than one component, they must be separated by `/` + 3. Full repository name must be fewer than 256 characters +- +- ++ summary: Overview ++ kind: info + - name: authentication +- x-displayName: Authentication + description: | + Specifies registry authentication. + externalDocs: + description: Detailed authentication workflow and token usage + url: https://docs.docker.com/reference/api/registry/auth/ +- ++ summary: Authentication ++ kind: info + - name: Manifests +- x-displayName: Manifests + description: | + Image manifests are JSON documents that describe an image: its configuration blob, the digests of each layer blob, and metadata such as media‑types and annotations. +- ++ summary: Manifests ++ kind: nav + - name: Blobs +- x-displayName: Blobs + description: | + Blobs are the binary objects referenced from manifests: + the config JSON and one or more compressed layer tarballs. +- ++ summary: Blobs ++ kind: nav + - name: pull +- x-displayName: Pulling Images + description: | + Pulling an image involves retrieving the manifest and downloading each of the image's layer blobs. This section outlines the general steps followed by a working example. + +@@ -79,94 +77,93 @@ + + # Step 1: Get a bearer token + TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/ubuntu:pull" | jq -r .token) +- ++ + # Step 2: Get the image manifest. In this example, an image manifest list is returned. + curl -s -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" \ + https://registry-1.docker.io/v2/library/ubuntu/manifests/latest \ + -o manifest-list.json +- ++ + # Step 3a: Parse the `manifests[]` array to locate the digest for your target platform (e.g., `linux/amd64`). + IMAGE_MANIFEST_DIGEST=$(jq -r '.manifests[] | select(.platform.architecture == "amd64" and .platform.os == "linux") | .digest' manifest-list.json) +- ++ + # Step 3b: Get the platform-specific image manifest + curl -s -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + https://registry-1.docker.io/v2/library/ubuntu/manifests/$IMAGE_MANIFEST_DIGEST \ + -o manifest.json +- ++ + # Step 4: Send a HEAD request to check if the layer blob exists + DIGEST=$(jq -r '.layers[0].digest' manifest.json) + curl -I -H "Authorization: Bearer $TOKEN" \ + https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST +- ++ + # Step 5: Download the layer blob + curl -L -H "Authorization: Bearer $TOKEN" \ + https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST + ``` +- +- This example pulls the manifest and the first layer for the `ubuntu:latest` image on the `linux/amd64` platform. Repeat steps 4 and 5 for each digest in the `.layers[]` array in the manifest. +- + ++ This example pulls the manifest and the first layer for the `ubuntu:latest` image on the `linux/amd64` platform. Repeat steps 4 and 5 for each digest in the `.layers[]` array in the manifest. ++ summary: Pulling Images ++ kind: info + - name: push +- x-displayName: Pushing Images + description: | + Pushing an image involves uploading any image blobs (such as the config or layers), and then uploading the manifest that references those blobs. +- ++ + This section outlines the basic steps to push an image using the registry API. +- ++ + 1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/) +- ++ + 2. [Check if the blob exists](#operation/CheckBlobExists) using a `HEAD` request for each blob digest. +- ++ + 3. If the blob does not exist, [upload the blob](#operation/CompleteBlobUpload) using a monolithic `PUT` request: + - First, [initiate the upload](#operation/InitiateBlobUpload) with `POST`. + - Then [upload and complete](#operation/CompleteBlobUpload) with `PUT`. + + **Note**: Alternatively, you can upload the blob in multiple chunks by using `PATCH` requests to send each chunk, followed by a final `PUT` request to complete the upload. This is known as a [chunked upload](#operation/UploadBlobChunk) and is useful for large blobs or when resuming interrupted uploads. + +- ++ + 4. [Upload the image manifest](#operation/PutImageManifest) using a `PUT` request to associate the config and layers. +- ++ + The following bash script example pushes a dummy config blob and manifest to `yourusername/helloworld:latest` on Docker Hub. You can replace `yourusername` with your Docker Hub username and `dckr_pat` with your Docker Hub personal access token. +- ++ + ```bash + #!/bin/bash +- ++ + USERNAME=yourusername + PASSWORD=dckr_pat + REPO=yourusername/helloworld + TAG=latest + CONFIG=config.json + MIME_TYPE=application/vnd.docker.container.image.v1+json +- ++ + # Step 1: Get a bearer token + TOKEN=$(curl -s -u "$USERNAME:$PASSWORD" \ + "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:push,pull" \ + | jq -r .token) +- ++ + # Create a dummy config blob and compute its digest + echo '{"architecture":"amd64","os":"linux","config":{},"rootfs":{"type":"layers","diff_ids":[]}}' > $CONFIG + DIGEST="sha256:$(sha256sum $CONFIG | awk '{print $1}')" +- ++ + # Step 2: Check if the blob exists + STATUS=$(curl -s -o /dev/null -w "%{http_code}" -I \ + -H "Authorization: Bearer $TOKEN" \ + https://registry-1.docker.io/v2/$REPO/blobs/$DIGEST) +- ++ + if [ "$STATUS" != "200" ]; then + # Step 3: Upload blob using monolithic upload + LOCATION=$(curl -sI -X POST \ + -H "Authorization: Bearer $TOKEN" \ + https://registry-1.docker.io/v2/$REPO/blobs/uploads/ \ + | grep -i Location | tr -d '\r' | awk '{print $2}') +- ++ + curl -s -X PUT "$LOCATION&digest=$DIGEST" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/octet-stream" \ + --data-binary @$CONFIG + fi +- ++ + # Step 4: Upload the manifest that references the config blob + MANIFEST=$(cat <` header. +- + x-codeSamples: + - lang: Bash + label: cURL +@@ -300,7 +296,7 @@ + required: false + description: | + Media type(s) the client supports for the manifest. +- ++ + The registry supports the following media types: + - application/vnd.docker.distribution.manifest.v2+json + - application/vnd.docker.distribution.manifest.list.v2+json +@@ -308,7 +304,6 @@ + - application/vnd.oci.image.index.v1+json + schema: + type: string +- + responses: + "200": + description: Manifest fetched successfully. +@@ -367,28 +362,19 @@ + docker-manifest: + summary: Docker image manifest (schema v2) + value: +- { +- "schemaVersion": 2, +- "mediaType": "application/vnd.docker.distribution.manifest.v2+json", +- "config": { +- "mediaType": "application/vnd.docker.container.image.v1+json", +- "size": 7023, +- "digest": "sha256:123456abcdef..." +- }, +- "layers": [ +- { +- "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", +- "size": 32654, +- "digest": "sha256:abcdef123456..." +- }, +- { +- "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", +- "size": 16724, +- "digest": "sha256:7890abcdef12..." +- } +- ] +- } +- ++ schemaVersion: 2 ++ mediaType: application/vnd.docker.distribution.manifest.v2+json ++ config: ++ mediaType: application/vnd.docker.container.image.v1+json ++ size: 7023 ++ digest: sha256:123456abcdef... ++ layers: ++ - mediaType: application/vnd.docker.image.rootfs.diff.tar.gzip ++ size: 32654 ++ digest: sha256:abcdef123456... ++ - mediaType: application/vnd.docker.image.rootfs.diff.tar.gzip ++ size: 16724 ++ digest: sha256:7890abcdef12... + "400": + description: Invalid name or reference. + "401": +@@ -399,8 +385,6 @@ + description: Repository or manifest not found. + "429": + description: Too many requests. +- +- + put: + tags: + - Manifests +@@ -459,7 +443,6 @@ + schema: + type: string + example: application/vnd.docker.distribution.manifest.v2+json +- + requestBody: + required: true + content: +@@ -512,28 +495,20 @@ + digest: + type: string + example: sha256:abcdef123456... +- + examples: + sample-manifest: + summary: Sample Docker image manifest (schema v2) + value: +- { +- "schemaVersion": 2, +- "mediaType": "application/vnd.docker.distribution.manifest.v2+json", +- "config": { +- "mediaType": "application/vnd.docker.container.image.v1+json", +- "size": 7023, +- "digest": "sha256:123456abcdef..." +- }, +- "layers": [ +- { +- "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", +- "size": 32654, +- "digest": "sha256:abcdef123456..." +- } +- ] +- } +- ++ schemaVersion: 2 ++ mediaType: application/vnd.docker.distribution.manifest.v2+json ++ config: ++ mediaType: application/vnd.docker.container.image.v1+json ++ size: 7023 ++ digest: sha256:123456abcdef... ++ layers: ++ - mediaType: application/vnd.docker.image.rootfs.diff.tar.gzip ++ size: 32654 ++ digest: sha256:abcdef123456... + responses: + "201": + description: Manifest created successfully. +@@ -578,7 +553,6 @@ + - Determining the digest or size of a manifest before downloading or deleting + + This endpoint requires authentication with pull scope. +- + parameters: + - name: name + in: path +@@ -642,12 +616,12 @@ + schema: + type: string + example: application/vnd.docker.distribution.manifest.v2+json +- "404": +- description: Manifest not found. + "401": + description: Authentication required. + "403": + description: Access denied. ++ "404": ++ description: Manifest not found. + "429": + description: Too many requests. + delete: +@@ -733,7 +707,6 @@ + curl -i -X POST \ + -H "Authorization: Bearer $TOKEN" \ + https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/ +- + - lang: Bash + label: cURL (Cross-Repository Blob Mount) + source: | +@@ -741,7 +714,6 @@ + curl -i -X POST \ + -H "Authorization: Bearer $TOKEN" \ + "https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/?mount=sha256:abc123def456...&from=library/busybox" +- + parameters: + - name: name + in: path +@@ -770,7 +742,6 @@ + schema: + type: string + description: Bearer token for authentication with `push` scope +- + responses: + "201": + description: Blob successfully mounted from another repository. +@@ -865,7 +836,6 @@ + schema: + type: string + example: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6... +- + responses: + "200": + description: Blob exists +@@ -885,32 +855,12 @@ + schema: + type: string + example: application/octet-stream +- content: +- application/json: +- examples: +- blob-check-request: +- summary: Sample request +- value: +- method: HEAD +- url: /v2/library/ubuntu/blobs/sha256:abc123def4567890... +- headers: +- Authorization: Bearer +- Accept: '*/*' +- blob-check-response: +- summary: Sample 200 response headers +- value: +- status: 200 OK +- headers: +- Docker-Content-Digest: sha256:abc123def4567890... +- Content-Length: 32654 +- Content-Type: application/octet-stream +- +- "404": +- description: Blob not found + "401": + description: Authentication required + "403": + description: Access denied ++ "404": ++ description: Blob not found + "429": + description: Too many requests + get: +@@ -957,7 +907,6 @@ + type: string + description: Bearer token with pull scope + example: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6... +- + responses: + "200": + description: Blob content returned directly +@@ -985,8 +934,7 @@ + examples: + small-layer: + summary: Example binary blob (gzipped tar layer) +- value: "" +- ++ value: + "307": + description: Temporary redirect to blob location + headers: +@@ -1031,7 +979,7 @@ + in: path + required: true + description: Repository Name +- example : library/ubuntu ++ example: library/ubuntu + schema: + type: string + - name: uuid +@@ -1047,7 +995,6 @@ + schema: + type: string + example: Bearer eyJhbGciOi... +- + responses: + "204": + description: Upload in progress. No body is returned. +@@ -1075,7 +1022,6 @@ + description: Upload session not found + "429": + description: Too many requests +- + put: + tags: + - Blobs +@@ -1089,7 +1035,6 @@ + This endpoint supports: + - Monolithic uploads (upload entire blob in this request) + - Finalizing chunked uploads (last chunk plus `digest`) +- + x-codeSamples: + - lang: Bash + label: cURL +@@ -1100,8 +1045,6 @@ + -H "Content-Type: application/octet-stream" \ + --data-binary @layer.tar.gz \ + "https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123?digest=sha256:abcd1234..." +- +- + parameters: + - name: name + in: path +@@ -1130,7 +1073,6 @@ + schema: + type: string + example: Bearer eyJhbGciOi... +- + requestBody: + required: false + content: +@@ -1141,8 +1083,7 @@ + examples: + layer-upload: + summary: Layer tarball blob +- value: "" +- ++ value: + responses: + "201": + description: Upload completed successfully +@@ -1174,7 +1115,6 @@ + description: Requested range not satisfiable (if used in chunked mode) + "429": + description: Too many requests +- + patch: + tags: + - Blobs +@@ -1229,7 +1169,6 @@ + type: string + example: bytes 0-65535 + description: Optional. Byte range of the chunk being sent +- + requestBody: + required: true + content: +@@ -1240,8 +1179,7 @@ + examples: + chunk-0: + summary: Upload chunk 0 of a blob +- value: "" +- ++ value: + responses: + "202": + description: Chunk accepted and stored +@@ -1288,7 +1226,6 @@ + - The client wants to clean up unused upload sessions + + After cancellation, the UUID is no longer valid and a new `POST` must be issued to restart the upload. +- + x-codeSamples: + - lang: Bash + label: cURL +@@ -1297,7 +1234,6 @@ + curl -X DELETE \ + -H "Authorization: Bearer $TOKEN" \ + https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123` +- + parameters: + - name: name + in: path +@@ -1319,7 +1255,6 @@ + schema: + type: string + example: Bearer eyJhbGciOi... +- + responses: + "204": + description: Upload session cancelled successfully. No body is returned. +@@ -1337,8 +1272,6 @@ + description: Upload session not found + "429": + description: Too many requests +- +- + x-tagGroups: + - name: General + tags: +@@ -1351,3 +1284,12 @@ + tags: + - Manifests + - Blobs ++jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base ++components: ++ securitySchemes: ++ registryToken: ++ type: http ++ scheme: bearer ++ description: Follow the WWW-Authenticate challenge and obtain a repository-scoped registry token. This is separate from the Hub API token exchange. ++security: ++ - registryToken: [] From afdabfa42f490ddb6eb07346a6f5a2a2f87ad001 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 9 Sep 2026 11:41:56 +0000 Subject: [PATCH 03/13] docs: migrate hub specification to OpenAPI 3.2 --- content/reference/api/hub/latest.yaml | 767 ++++--- hack/api-docs/adoption/hub.json | 2950 +++++++++++++++++++++++++ hack/api-docs/adoption/hub.patch | 2056 +++++++++++++++++ 3 files changed, 5415 insertions(+), 358 deletions(-) create mode 100644 hack/api-docs/adoption/hub.json create mode 100644 hack/api-docs/adoption/hub.patch diff --git a/content/reference/api/hub/latest.yaml b/content/reference/api/hub/latest.yaml index 3ed32a2c6302..e5eb668ef321 100644 --- a/content/reference/api/hub/latest.yaml +++ b/content/reference/api/hub/latest.yaml @@ -1,6 +1,4 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/OAI/OpenAPI-Specification/refs/heads/main/schemas/v3.0/schema.yaml - -openapi: 3.0.3 +openapi: 3.2.0 info: title: Docker HUB API version: 2-beta @@ -21,16 +19,17 @@ servers: url: https://hub.docker.com tags: - name: changelog - x-displayName: Changelog description: | See the [Changelog](/reference/api/hub/changelog) for a summary of changes across Docker Hub API versions. + summary: Changelog + kind: info - name: resources - x-displayName: Resources description: | The following resources are available to interact with the documented API: - [Docker Hub CLI tool](https://github.com/docker/hub-tool#readme) (currently experimental) + summary: Resources + kind: info - name: rate-limiting - x-displayName: Rate Limiting description: | The Docker Hub API is limited on the amount of requests you can perform per minute against it. @@ -46,9 +45,10 @@ tags: **Note**: These rate limits are separate from anti-abuse and Docker Hub download, or pull rate limiting. To learn more about Docker Hub pull rate limiting, see [Usage and limits](https://docs.docker.com/docker-hub/usage/). + summary: Rate Limiting + kind: info - name: authentication - x-displayName: Authentication - description: | + description: |+ Most Docker Hub API endpoints require you to authenticate using your Docker credentials before using them. Additionally, similar to the Docker Hub UI features, API endpoint responses may vary depending on your subscription (Personal, Pro, or Team) and your account's permissions. @@ -90,16 +90,18 @@ tags: These labels will show up on routes in this reference that allow for use of bearer tokens issued from them. - - + + + summary: Authentication + kind: info - name: authentication-api - x-displayName: Authentication description: | The authentication endpoints allow you to authenticate with Docker Hub APIs. For more information, see [Authentication](#tag/authentication). + summary: Authentication + kind: nav - name: access-tokens - x-displayName: Personal Access Tokens description: | The Personal Access Token endpoints lets you manage personal access tokens. For more information, see [Access Tokens](https://docs.docker.com/security/access-tokens/personal-access-tokens/). @@ -112,50 +114,58 @@ tags: If you were to define both `repo:write` *and* `repo:read`, then `repo:read` is assumed by `repo:write` and ignored. ***Treat your personal access token like your password and keep it secret. You cannot retrieve your token after it is generated.*** + summary: Personal Access Tokens + kind: nav - name: audit-logs - x-displayName: Audit Logs description: | The Audit Logs API endpoints allow you to query audit log events across a namespace. For more information, see [Audit Logs](https://docs.docker.com/admin/activity-logs/). + summary: Audit Logs + kind: nav - name: org-settings - x-displayName: Org Settings description: | The Org Settings API endpoints allow you to manage your organization's settings. + summary: Org Settings + kind: nav - name: repositories - x-displayName: Repositories description: | The repository endpoints allow you to access your repository's tags. + summary: Repositories + kind: nav - name: orgs - x-displayName: Organizations x-audience: public description: | The organization endpoints allow you to interact with and manage your organizations. For more information, see [Organization administration overview](https://docs.docker.com/admin/organization/). + summary: Organizations + kind: nav - name: groups - x-displayName: Groups (Teams) x-audience: public description: | The groups endpoints allow you to manage your organization's teams and their members. For more information, see [Create and manage a team](https://docs.docker.com/admin/organization/manage/manage-a-team/). + summary: Groups (Teams) + kind: nav - name: invites - x-displayName: Invites x-audience: public description: | The invites endpoints allow you to manage invites for users to join your Docker organization. For more information, see [Invite members](https://docs.docker.com/admin/organization/manage/members/#invite-members). + summary: Invites + kind: nav - name: scim - x-displayName: SCIM x-audience: public description: | SCIM is a provisioning system that lets you manage users within your identity provider (IdP). For more information, see [System for Cross-domain Identity management](https://docs.docker.com/security/for-admins/provisioning/scim/). + summary: SCIM + kind: nav - name: org-access-tokens - x-displayName: Organization Access Tokens x-audience: public description: | The organization access token endpoints allow you to manage organization access tokens (OATs). See [Organization access tokens](https://docs.docker.com/security/for-admins/access-tokens/) for more information. @@ -165,6 +175,8 @@ tags: - `GET /v2/repositories/{namespace}/{repository}` — use [Get repository](#tag/repositories/operation/GetRepository) instead. - `GET /v2/repositories/{namespace}` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead. - `GET /v2/users/{username}/repositories` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead. + summary: Organization Access Tokens + kind: nav paths: /v2/users/login: post: @@ -174,16 +186,16 @@ paths: operationId: PostUsersLogin security: [] deprecated: true - description: | + description: |+ Creates and returns a bearer token in JWT format that you can use to authenticate with Docker Hub APIs. The returned token is used in the HTTP Authorization header like `Authorization: Bearer {TOKEN}`. _**As of September 16, 2024, this route requires a personal access token (PAT) instead of a password if your organization has SSO enforced.**_ -
- Deprecated: Use [Create access token] instead. -
+ + Deprecated: Use [Create access token](#tag/authentication-api/operation/AuthCreateAccessToken) instead. + requestBody: content: application/json: @@ -310,6 +322,7 @@ paths: $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" + operationId: postV2AccessTokens get: summary: List personal access tokens description: Returns a paginated list of personal access tokens. @@ -339,6 +352,7 @@ paths: $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" + operationId: getV2AccessTokens /v2/access-tokens/{uuid}: parameters: - in: path @@ -371,6 +385,7 @@ paths: $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" + operationId: patchV2AccessTokensByUuid get: summary: Get personal access token description: Returns a personal access token by UUID. @@ -395,6 +410,7 @@ paths: $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" + operationId: getV2AccessTokensByUuid delete: summary: Delete personal access token description: | @@ -410,13 +426,14 @@ paths: $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" + operationId: deleteV2AccessTokensByUuid /v2/auditlogs/{account}/actions: get: summary: List audit log actions - description: | + description: |+ List audit log actions for a namespace to be used as a filter for querying audit log events. - + operationId: AuditLogs_ListAuditActions security: - bearerAuth: [] @@ -707,10 +724,10 @@ paths: /v2/auditlogs/{account}: get: summary: List audit log events - description: | + description: |+ List audit log events for a given namespace. - + operationId: AuditLogs_ListAuditLogs security: - bearerAuth: [] @@ -732,7 +749,7 @@ paths: data: digest: sha256:c1ae9c435032a276f80220c7d9b40f76266bbe79243d34f9cda30b76fe114dfa tag: latest - timestamp: "2021-02-19T01:34:35Z" + timestamp: 2021-02-19T01:34:35Z action_description: | pushed the tag latest with the digest sha256:c1ae9c435032a to the repository docker/example - account: docker @@ -742,12 +759,12 @@ paths: data: lease_id: l_3EgPuRCjtUqT279CFPOQWcO8zOf resource_type: run_4cpu_8mem - started_at: "2026-06-04T18:24:21Z" - updated_at: "2026-06-04T18:36:43Z" + started_at: 2026-06-04T18:24:21Z + updated_at: 2026-06-04T18:36:43Z org_id: b908ca6e-b9a9-4a53-a9a5-6bec96f72432 user_id: ecae6747-e42c-43cb-925d-cfce1ab32b02 - timestamp: "2026-06-04T18:36:43Z" - action_description: "offload lease 'l_3EgPuRCjtUqT279CFPOQWcO8zOf' ended, ran for '12m22s'" + timestamp: 2026-06-04T18:36:43Z + action_description: offload lease 'l_3EgPuRCjtUqT279CFPOQWcO8zOf' ended, ran for '12m22s' "429": description: "" content: @@ -858,6 +875,7 @@ paths: $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" + operationId: getV2OrgsByNameSettings put: summary: Update organization settings description: | @@ -900,6 +918,7 @@ paths: $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" + operationId: putV2OrgsByNameSettings /v2/orgs/{name}/access-tokens: post: summary: Create access token @@ -930,6 +949,7 @@ paths: $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" + operationId: postV2OrgsByNameAccessTokens get: summary: List access tokens description: | @@ -962,7 +982,7 @@ paths: $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" - + operationId: getV2OrgsByNameAccessTokens /v2/orgs/{org_name}/access-tokens/{access_token_id}: parameters: - $ref: "#/components/parameters/org_name" @@ -972,7 +992,7 @@ paths: schema: type: string description: The ID of the access token to retrieve - example: "a7a5ef25-8889-43a0-8cc7-f2a94268e861" + example: a7a5ef25-8889-43a0-8cc7-f2a94268e861 get: summary: Get access token description: | @@ -994,6 +1014,7 @@ paths: $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" + operationId: getV2OrgsByOrgNameAccessTokensByAccessTokenId patch: summary: Update access token description: | @@ -1021,6 +1042,7 @@ paths: $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" + operationId: patchV2OrgsByOrgNameAccessTokensByAccessTokenId delete: summary: Delete access token description: | @@ -1038,6 +1060,7 @@ paths: $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" + operationId: deleteV2OrgsByOrgNameAccessTokensByAccessTokenId /v2/namespaces/{namespace}/repositories/{repository}/tags: parameters: - $ref: "#/components/parameters/namespace" @@ -1045,10 +1068,10 @@ paths: get: operationId: ListRepositoryTags summary: List repository tags - description: | + description: |+ Returns the list of tags for the specified repository. - + tags: - repositories security: @@ -1075,10 +1098,10 @@ paths: $ref: "#/components/responses/NotFound" head: summary: Check repository tags - description: | + description: |+ Checks whether the repository has any tags. - + tags: - repositories security: @@ -1090,6 +1113,7 @@ paths: $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" + operationId: headV2NamespacesByNamespaceRepositoriesByRepositoryTags /v2/namespaces/{namespace}/repositories/{repository}/tags/{tag}: parameters: - $ref: "#/components/parameters/namespace" @@ -1098,10 +1122,10 @@ paths: get: operationId: GetRepositoryTag summary: Read repository tag - description: | + description: |+ Returns details for a specific tag in the specified repository. - + tags: - repositories security: @@ -1115,10 +1139,10 @@ paths: $ref: "#/components/responses/NotFound" head: summary: Check repository tag - description: | + description: |+ Checks whether the specified tag exists in the repository. - + tags: - repositories security: @@ -1130,19 +1154,20 @@ paths: $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" + operationId: headV2NamespacesByNamespaceRepositoriesByRepositoryTagsByTag /v2/namespaces/{namespace}/repositories/{repository}/immutabletags: parameters: - $ref: "#/components/parameters/namespace" - $ref: "#/components/parameters/repository" patch: operationId: UpdateRepositoryImmutableTags - summary: "Update repository immutable tags" - description: | + summary: Update repository immutable tags + description: |+ Updates the immutable tags configuration for this repository. **Only users with administrative privileges for the repository can modify these settings.** - + tags: - repositories security: @@ -1150,15 +1175,15 @@ paths: requestBody: $ref: "#/components/requestBodies/update_repository_immutable_tags_request" responses: - 200: + "200": $ref: "#/components/responses/update_repository_immutable_tags_response" - 400: + "400": $ref: "#/components/responses/bad_request" - 401: + "401": $ref: "#/components/responses/unauthorized" - 403: + "403": $ref: "#/components/responses/forbidden" - 404: + "404": $ref: "#/components/responses/not_found" /v2/namespaces/{namespace}/repositories/{repository}/immutabletags/verify: parameters: @@ -1166,13 +1191,13 @@ paths: - $ref: "#/components/parameters/repository" post: operationId: VerifyRepositoryImmutableTags - summary: "Verify repository immutable tags" - description: | + summary: Verify repository immutable tags + description: |+ Validates the immutable tags regex passed in the request body and returns a list of tags matching it in this repository. **Only users with administrative privileges for the repository can call this endpoint.** - + tags: - repositories security: @@ -1180,15 +1205,15 @@ paths: requestBody: $ref: "#/components/requestBodies/immutable_tags_verify_request" responses: - 200: + "200": $ref: "#/components/responses/immutable_tags_verify_response" - 400: + "400": $ref: "#/components/responses/bad_request" - 401: + "401": $ref: "#/components/responses/unauthorized" - 403: + "403": $ref: "#/components/responses/forbidden" - 404: + "404": $ref: "#/components/responses/not_found" /v2/repositories/{namespace}/{repository}/groups: parameters: @@ -1196,10 +1221,10 @@ paths: - $ref: "#/components/parameters/repository" post: summary: Assign a group (Team) to a repository for access - description: | + description: |+ Assigns an organization group (team) to a repository with a specified permission level. - + tags: - repositories operationId: CreateRepositoryGroup @@ -1213,7 +1238,7 @@ paths: $ref: "#/components/schemas/RepositoryGroupCreationRequest" example: group_id: 12345 - permission: "write" + permission: write responses: "200": description: Repository group permission created successfully @@ -1222,8 +1247,8 @@ paths: schema: $ref: "#/components/schemas/RepositoryGroup" example: - group_name: "developers" - permission: "write" + group_name: developers + permission: write group_id: 12345 "400": description: Bad Request - Invalid request parameters @@ -1248,14 +1273,14 @@ paths: Public repositories are accessible to everyone, while private repositories require appropriate authentication and permissions. - + **OAT listing behavior**: an OAT with the `scope-repository-list` scope sees all repositories including private ones. An OAT without that scope only sees public repositories. This filtering is silent: the response is a normal `200` with no indication that private repositories were withheld. tags: - repositories security: - bearerAuth: [] - - {} # Allow anonymous access for public repositories + - {} parameters: - in: query name: page @@ -1309,59 +1334,59 @@ paths: repositories_list: value: count: 287 - next: "https://hub.docker.com/v2/namespaces/docker/repositories?page=2&page_size=2" + next: https://hub.docker.com/v2/namespaces/docker/repositories?page=2&page_size=2 previous: null results: - - name: "highland_builder" - namespace: "docker" - repository_type: "image" + - name: highland_builder + namespace: docker + repository_type: image status: 1 - status_description: "active" - description: "Image for performing Docker build requests" + status_description: active + description: Image for performing Docker build requests is_private: false star_count: 7 pull_count: 15722123 - last_updated: "2023-06-20T10:44:45.459826Z" - last_modified: "2024-10-16T13:48:34.145251Z" - date_registered: "2015-05-19T21:13:35.937763Z" + last_updated: 2023-06-20T10:44:45.459826Z + last_modified: 2024-10-16T13:48:34.145251Z + date_registered: 2015-05-19T21:13:35.937763Z affiliation: "" media_types: - - "application/octet-stream" - - "application/vnd.docker.container.image.v1+json" - - "application/vnd.docker.distribution.manifest.v1+prettyjws" + - application/octet-stream + - application/vnd.docker.container.image.v1+json + - application/vnd.docker.distribution.manifest.v1+prettyjws content_types: - - "unrecognized" - - "image" + - unrecognized + - image categories: - - name: "Languages & frameworks" - slug: "languages-and-frameworks" - - name: "Integration & delivery" - slug: "integration-and-delivery" - - name: "Operating systems" - slug: "operating-systems" + - name: Languages & frameworks + slug: languages-and-frameworks + - name: Integration & delivery + slug: integration-and-delivery + - name: Operating systems + slug: operating-systems storage_size: 488723114800 - - name: "whalesay" - namespace: "docker" + - name: whalesay + namespace: docker repository_type: null status: 1 - status_description: "active" - description: "An image for use in the Docker demo tutorial" + status_description: active + description: An image for use in the Docker demo tutorial is_private: false star_count: 757 pull_count: 130737682 - last_updated: "2015-06-19T19:06:27.388123Z" - last_modified: "2024-10-16T13:48:34.145251Z" - date_registered: "2015-06-09T18:16:36.527329Z" + last_updated: 2015-06-19T19:06:27.388123Z + last_modified: 2024-10-16T13:48:34.145251Z + date_registered: 2015-06-09T18:16:36.527329Z affiliation: "" media_types: - - "application/vnd.docker.distribution.manifest.v1+prettyjws" + - application/vnd.docker.distribution.manifest.v1+prettyjws content_types: - - "image" + - image categories: - - name: "Languages & frameworks" - slug: "languages-and-frameworks" - - name: "Integration & delivery" - slug: "integration-and-delivery" + - name: Languages & frameworks + slug: languages-and-frameworks + - name: Integration & delivery + slug: integration-and-delivery storage_size: 103666708 "400": description: Bad Request - Invalid request parameters @@ -1375,10 +1400,8 @@ paths: value: fields: ordering: - [ - "Invalid ordering value. Must be one of: name, -name, last_updated, -last_updated, pull_count, -pull_count", - ] - text: "Invalid ordering value" + - "Invalid ordering value. Must be one of: name, -name, last_updated, -last_updated, pull_count, -pull_count" + text: Invalid ordering value "401": $ref: "#/components/responses/unauthorized" "403": @@ -1391,11 +1414,11 @@ paths: $ref: "#/components/schemas/error" post: summary: Create a new repository - description: | + description: |+ Creates a new repository within the specified namespace. The repository will be created with the provided metadata including name, description, and privacy settings. - + operationId: CreateRepository tags: - repositories @@ -1408,36 +1431,36 @@ paths: schema: $ref: "#/components/schemas/repo_creation_request" example: - name: "my-app" - namespace: "myorganization" - description: "A sample application repository" - full_description: "This is a comprehensive description of my application repository that contains additional details about the project." - registry: "docker.io" + name: my-app + namespace: myorganization + description: A sample application repository + full_description: This is a comprehensive description of my application repository that contains additional details about the project. + registry: docker.io is_private: false responses: - 201: + "201": description: Repository created successfully content: application/json: schema: $ref: "#/components/schemas/repository_info" example: - name: "my-app" - namespace: "myorganization" - repository_type: "image" + name: my-app + namespace: myorganization + repository_type: image status: 1 - status_description: "Active" - description: "A sample application repository" + status_description: Active + description: A sample application repository is_private: false is_automated: false star_count: 0 pull_count: 0 - last_updated: "2025-01-20T10:30:00Z" - date_registered: "2025-01-20T10:30:00Z" + last_updated: 2025-01-20T10:30:00Z + date_registered: 2025-01-20T10:30:00Z collaborator_count: 0 - hub_user: "myorganization" + hub_user: myorganization has_starred: false - full_description: "This is a comprehensive description of my application repository that contains additional details about the project." + full_description: This is a comprehensive description of my application repository that contains additional details about the project. media_types: [] content_types: [] categories: [] @@ -1446,15 +1469,15 @@ paths: rules: [] storage_size: null source: null - 400: + "400": $ref: "#/components/responses/bad_request" - 401: + "401": $ref: "#/components/responses/unauthorized" - 403: + "403": $ref: "#/components/responses/forbidden" - 404: + "404": $ref: "#/components/responses/not_found" - 500: + "500": $ref: "#/components/responses/internal_error" /v2/namespaces/{namespace}/repositories/{repository}: parameters: @@ -1463,40 +1486,40 @@ paths: get: operationId: GetRepository summary: Get repository in a namespace - description: | + description: |+ Returns a repository within the specified namespace (organization or user). Public repositories are accessible to everyone, while private repositories require appropriate authentication and permissions. - + tags: - repositories security: - bearerAuth: [] - - {} # Allow anonymous access for public repositories + - {} responses: - 200: + "200": content: application/json: schema: $ref: "#/components/schemas/repository_info" example: - name: "my-app" - namespace: "myorganization" - repository_type: "image" + name: my-app + namespace: myorganization + repository_type: image status: 1 - status_description: "Active" - description: "A sample application repository" + status_description: Active + description: A sample application repository is_private: false is_automated: false star_count: 0 pull_count: 0 - last_updated: "2025-01-20T10:30:00Z" - date_registered: "2025-01-20T10:30:00Z" + last_updated: 2025-01-20T10:30:00Z + date_registered: 2025-01-20T10:30:00Z collaborator_count: 0 - hub_user: "myorganization" + hub_user: myorganization has_starred: false - full_description: "This is a comprehensive description of my application repository that contains additional details about the project." + full_description: This is a comprehensive description of my application repository that contains additional details about the project. media_types: [] content_types: [] categories: [] @@ -1505,66 +1528,37 @@ paths: rules: [] storage_size: null source: null - 401: + "401": $ref: "#/components/responses/unauthorized" - 403: + "403": $ref: "#/components/responses/forbidden" - 404: + "404": $ref: "#/components/responses/not_found" - 500: + "500": $ref: "#/components/responses/internal_error" head: operationId: CheckRepository summary: Check repository in a namespace - description: | + description: |+ Check a repository within the specified namespace (organization or user). Public repositories are accessible to everyone, while private repositories require appropriate authentication and permissions. - + tags: - repositories security: - bearerAuth: [] - - {} # Allow anonymous access for public repositories + - {} responses: - 200: - content: - application/json: - schema: - $ref: "#/components/schemas/repository_info" - example: - name: "my-app" - namespace: "myorganization" - repository_type: "image" - status: 1 - status_description: "Active" - description: "A sample application repository" - is_private: false - is_automated: false - star_count: 0 - pull_count: 0 - last_updated: "2025-01-20T10:30:00Z" - date_registered: "2025-01-20T10:30:00Z" - collaborator_count: 0 - hub_user: "myorganization" - has_starred: false - full_description: "This is a comprehensive description of my application repository that contains additional details about the project." - media_types: [] - content_types: [] - categories: [] - immutable_tags_settings: - enabled: false - rules: [] - storage_size: null - source: null - 401: + "200": {} + "401": $ref: "#/components/responses/unauthorized" - 403: + "403": $ref: "#/components/responses/forbidden" - 404: + "404": $ref: "#/components/responses/not_found" - 500: + "500": $ref: "#/components/responses/internal_error" /v2/orgs/{org_name}/members: parameters: @@ -1577,7 +1571,7 @@ paths: - $ref: "#/components/parameters/role" get: summary: List org members - description: | + description: |+ Returns a list of members for an organization. _The following fields are only visible to orgs with insights enabled._ @@ -1588,7 +1582,7 @@ paths: To make visible, please see [View Insights for organization users](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). - + tags: - orgs security: @@ -1610,15 +1604,16 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: getV2OrgsByOrgNameMembers /v2/orgs/{org_name}/members/export: parameters: - $ref: "#/components/parameters/org_name" get: summary: Export org members CSV - description: | + description: |+ Export members of an organization as a CSV - + tags: - orgs security: @@ -1682,6 +1677,7 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: getV2OrgsByOrgNameMembersExport /v2/orgs/{org_name}/members/{username}: x-audience: public parameters: @@ -1689,11 +1685,11 @@ paths: - $ref: "#/components/parameters/username" put: summary: Update org member (role) - description: | + description: |+ Updates the role of a member in the organization. ***Only users in the "owners" group of the organization can use this endpoint.*** - + tags: - orgs security: @@ -1729,12 +1725,13 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: putV2OrgsByOrgNameMembersByUsername delete: summary: Remove member from org - description: | + description: |+ Removes the member from the org, ie. all groups in the org, unless they're the last owner - + tags: - orgs security: @@ -1750,16 +1747,17 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: deleteV2OrgsByOrgNameMembersByUsername /v2/orgs/{org_name}/invites: x-audience: public parameters: - $ref: "#/components/parameters/org_name" get: summary: List org invites - description: | + description: |+ Return all pending invites for a given org, only team owners can call this endpoint - + tags: - invites security: @@ -1782,14 +1780,14 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: getV2OrgsByOrgNameInvites /v2/orgs/{org_name}/groups: x-audience: public parameters: - $ref: "#/components/parameters/org_name" get: summary: Get groups of an organization - description: | - + description: Get groups of an organization. tags: - groups security: @@ -1833,12 +1831,13 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: getV2OrgsByOrgNameGroups post: summary: Create a new group - description: | + description: |+ Create a new group within an organization. - + tags: - groups security: @@ -1867,6 +1866,7 @@ paths: $ref: "#/components/responses/unauthorized" "403": $ref: "#/components/responses/forbidden" + operationId: postV2OrgsByOrgNameGroups /v2/orgs/{org_name}/groups/{group_name}: x-audience: public parameters: @@ -1874,8 +1874,7 @@ paths: - $ref: "#/components/parameters/group_name" get: summary: Get a group of an organization - description: | - + description: Get a group of an organization. tags: - groups security: @@ -1893,10 +1892,10 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: getV2OrgsByOrgNameGroupsByGroupName put: summary: Update the details for an organization group - description: | - + description: Update the details for an organization group. tags: - groups security: @@ -1925,10 +1924,10 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: putV2OrgsByOrgNameGroupsByGroupName patch: summary: Update some details for an organization group - description: | - + description: Update some details for an organization group. tags: - groups security: @@ -1962,10 +1961,10 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: patchV2OrgsByOrgNameGroupsByGroupName delete: summary: Delete an organization group - description: | - + description: Delete an organization group. tags: - groups security: @@ -1979,6 +1978,7 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: deleteV2OrgsByOrgNameGroupsByGroupName /v2/orgs/{org_name}/groups/{group_name}/members: x-audience: public get: @@ -1995,11 +1995,11 @@ paths: type: string description: Search members by username, full_name or email. summary: List members of a group - description: | + description: |+ List the members (users) that are in a group. If user is owner of the org or has otherwise elevated permissions, they can search by email and the result will also contain emails. - + tags: - groups responses: @@ -2028,13 +2028,13 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: getV2OrgsByOrgNameGroupsByGroupNameMembers post: parameters: - $ref: "#/components/parameters/org_name" - $ref: "#/components/parameters/group_name" summary: Add a member to a group - description: | - + description: Add a member to a group. tags: - groups security: @@ -2052,6 +2052,7 @@ paths: $ref: "#/components/responses/not_found" "500": $ref: "#/components/responses/internal_error" + operationId: postV2OrgsByOrgNameGroupsByGroupNameMembers /v2/orgs/{org_name}/groups/{group_name}/members/{username}: x-audience: public parameters: @@ -2060,8 +2061,7 @@ paths: - $ref: "#/components/parameters/username" delete: summary: Remove a user from a group - description: | - + description: Remove a user from a group. tags: - groups security: @@ -2075,6 +2075,7 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: deleteV2OrgsByOrgNameGroupsByGroupNameMembersByUsername /v2/invites/{id}: x-audience: public parameters: @@ -2085,10 +2086,10 @@ paths: type: string delete: summary: Cancel an invite - description: | + description: |+ Mark the invite as cancelled so it doesn't show up on the list of pending invites - + tags: - invites security: @@ -2102,6 +2103,7 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: deleteV2InvitesById /v2/invites/{id}/resend: x-audience: public parameters: @@ -2112,10 +2114,10 @@ paths: required: true patch: summary: Resend an invite - description: | + description: |+ Resend a pending invite to the user, any org owner can resend an invite - + tags: - invites security: @@ -2129,16 +2131,17 @@ paths: $ref: "#/components/responses/forbidden" "404": $ref: "#/components/responses/not_found" + operationId: patchV2InvitesByIdResend /v2/invites/bulk: x-audience: public parameters: - $ref: "#/components/parameters/bulk_invite" post: summary: Bulk create invites - description: | + description: |+ Create multiple invites by emails or DockerIDs. Only a team owner can create invites. - + tags: - invites requestBody: @@ -2159,6 +2162,7 @@ paths: $ref: "#/components/responses/bad_request" "409": $ref: "#/components/responses/conflict" + operationId: postV2InvitesBulk /v2/scim/2.0/ServiceProviderConfig: x-audience: public get: @@ -2168,7 +2172,7 @@ paths: tags: - scim security: - - bearerSCIMAuth: [] + - scimToken: [] responses: "200": $ref: "#/components/responses/scim_get_service_provider_config_resp" @@ -2176,6 +2180,7 @@ paths: $ref: "#/components/responses/scim_unauthorized" "500": $ref: "#/components/responses/scim_error" + operationId: getV2Scim20ServiceProviderConfig /v2/scim/2.0/ResourceTypes: x-audience: public get: @@ -2185,7 +2190,7 @@ paths: tags: - scim security: - - bearerSCIMAuth: [] + - scimToken: [] responses: "200": $ref: "#/components/responses/scim_get_resource_types_resp" @@ -2193,6 +2198,7 @@ paths: $ref: "#/components/responses/scim_unauthorized" "500": $ref: "#/components/responses/scim_error" + operationId: getV2Scim20ResourceTypes /v2/scim/2.0/ResourceTypes/{name}: x-audience: public get: @@ -2209,7 +2215,7 @@ paths: example: User required: true security: - - bearerSCIMAuth: [] + - scimToken: [] responses: "200": $ref: "#/components/responses/scim_get_resource_type_resp" @@ -2219,6 +2225,7 @@ paths: $ref: "#/components/responses/scim_not_found" "500": $ref: "#/components/responses/scim_error" + operationId: getV2Scim20ResourceTypesByName /v2/scim/2.0/Schemas: x-audience: public get: @@ -2228,7 +2235,7 @@ paths: tags: - scim security: - - bearerSCIMAuth: [] + - scimToken: [] responses: "200": $ref: "#/components/responses/scim_get_schemas_resp" @@ -2236,6 +2243,7 @@ paths: $ref: "#/components/responses/scim_unauthorized" "500": $ref: "#/components/responses/scim_error" + operationId: getV2Scim20Schemas /v2/scim/2.0/Schemas/{id}: x-audience: public get: @@ -2252,7 +2260,7 @@ paths: example: urn:ietf:params:scim:schemas:core:2.0:User required: true security: - - bearerSCIMAuth: [] + - scimToken: [] responses: "200": $ref: "#/components/responses/scim_get_schema_resp" @@ -2262,6 +2270,7 @@ paths: $ref: "#/components/responses/scim_not_found" "500": $ref: "#/components/responses/scim_error" + operationId: getV2Scim20SchemasById /v2/scim/2.0/Users: x-audience: public get: @@ -2292,7 +2301,7 @@ paths: tags: - scim security: - - bearerSCIMAuth: [] + - scimToken: [] parameters: - name: startIndex in: query @@ -2342,6 +2351,7 @@ paths: $ref: "#/components/responses/scim_not_found" "500": $ref: "#/components/responses/scim_error" + operationId: getV2Scim20Users post: summary: Create user description: | @@ -2349,7 +2359,7 @@ paths: tags: - scim security: - - bearerSCIMAuth: [] + - scimToken: [] requestBody: $ref: "#/components/requestBodies/scim_create_user_request" responses: @@ -2367,6 +2377,7 @@ paths: $ref: "#/components/responses/scim_conflict" "500": $ref: "#/components/responses/scim_error" + operationId: postV2Scim20Users /v2/scim/2.0/Users/{id}: x-audience: public parameters: @@ -2378,7 +2389,7 @@ paths: tags: - scim security: - - bearerSCIMAuth: [] + - scimToken: [] responses: "200": $ref: "#/components/responses/scim_get_user_resp" @@ -2392,6 +2403,7 @@ paths: $ref: "#/components/responses/scim_not_found" "500": $ref: "#/components/responses/scim_error" + operationId: getV2Scim20UsersById put: summary: Update a user description: | @@ -2399,7 +2411,7 @@ paths: tags: - scim security: - - bearerSCIMAuth: [] + - scimToken: [] requestBody: $ref: "#/components/requestBodies/scim_update_user_request" responses: @@ -2417,6 +2429,7 @@ paths: $ref: "#/components/responses/scim_conflict" "500": $ref: "#/components/responses/scim_error" + operationId: putV2Scim20UsersById components: responses: BadRequest: @@ -2679,8 +2692,8 @@ components: type: string description: List of immutable tag rules example: - - "v.*" - - ".*-RELEASE" + - v.* + - .*-RELEASE required: - immutable_tags - immutable_tags_rules @@ -2698,26 +2711,26 @@ components: Letters must be lowercase. minLength: 2 maxLength: 255 - pattern: "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" - example: "my-app" + pattern: ^[a-z0-9]+(?:[._-][a-z0-9]+)*$ + example: my-app namespace: type: string description: The namespace where the repository will be created - example: "myorganization" + example: myorganization description: type: string description: Short description of the repository maxLength: 100 - example: "A sample application repository" + example: A sample application repository full_description: type: string description: Detailed description of the repository maxLength: 25000 - example: "This is a comprehensive description of my application repository that contains additional details about the project, its purpose, usage instructions, and other relevant information." + example: This is a comprehensive description of my application repository that contains additional details about the project, its purpose, usage instructions, and other relevant information. registry: type: string description: The registry where the repository will be hosted - example: "docker.io" + example: docker.io is_private: type: boolean description: Whether the repository should be private @@ -2741,20 +2754,26 @@ components: - read: Can view and pull from the repository - write: Can view, pull, and push to the repository - admin: Can view, pull, push, and manage repository settings - enum: ["read", "write", "admin"] - example: "write" + enum: + - read + - write + - admin + example: write RepositoryGroup: type: object properties: group_name: type: string description: The name of the group - example: "developers" + example: developers permission: type: string description: The permission level granted to the group - enum: ["read", "write", "admin"] - example: "write" + enum: + - read + - write + - admin + example: write group_id: type: integer format: int64 @@ -2773,8 +2792,9 @@ components: type: string description: Repository namespace repository_type: - type: string - nullable: true + type: + - string + - "null" description: Type of the repository status: type: integer @@ -2802,45 +2822,50 @@ components: last_updated: type: string format: date-time - example: "2021-01-05T21:06:53.506400Z" + example: 2021-01-05T21:06:53.506400Z description: ISO 8601 timestamp of when repository was last updated last_modified: - type: string + type: + - string + - "null" format: date-time - example: "2021-01-05T21:06:53.506400Z" - nullable: true + example: 2021-01-05T21:06:53.506400Z description: ISO 8601 timestamp of when repository was last modified date_registered: type: string format: date-time - example: "2021-01-05T21:06:53.506400Z" + example: 2021-01-05T21:06:53.506400Z description: ISO 8601 timestamp of when repository was created collaborator_count: type: integer format: int64 description: Number of collaborators affiliation: - type: string - nullable: true + type: + - string + - "null" description: Repository affiliation hub_user: - type: string - nullable: true + type: + - string + - "null" description: Hub user information has_starred: type: boolean description: Whether the current user has starred this repository full_description: - type: string - nullable: true + type: + - string + - "null" description: Full description of the repository permissions: $ref: "#/components/schemas/repo_permissions" media_types: type: array items: - type: string - nullable: true + type: + - string + - "null" description: Supported media types content_types: type: array @@ -2855,13 +2880,15 @@ components: immutable_tags_settings: $ref: "#/components/schemas/immutable_tags_settings" storage_size: - type: integer + type: + - integer + - "null" format: int64 - nullable: true description: Storage size in bytes source: - type: string - nullable: true + type: + - string + - "null" description: Source of the repository, where it was created from required: - user @@ -2918,9 +2945,9 @@ components: properties: regex: type: string - pattern: '^[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*(\\/[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*)*$' - description: 'Immutable tags rule regex pattern. Must match format: [a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*(\\/[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*)*' - example: "v.*" + pattern: ^[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*(\\/[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*)*$ + description: "Immutable tags rule regex pattern. Must match format: [a-z0-9]+((\\\\.|_|__|-+)[a-z0-9]+)*(\\\\/[a-z0-9]+((\\\\.|_|__|-+)[a-z0-9]+)*)*" + example: v.* required: - regex immutable_tags_verify_response: @@ -2932,9 +2959,9 @@ components: type: string description: List of tags that match the provided regex pattern example: - - "v1.0.0" - - "v2.1.3" - - "latest" + - v1.0.0 + - v2.1.3 + - latest required: - tags repository_list_entry: @@ -2943,20 +2970,21 @@ components: name: type: string description: Name of the repository - example: "hello-world" + example: hello-world namespace: type: string description: Namespace (organization or username) that owns the repository - example: "docker" + example: docker repository_type: - type: string + type: + - string + - "null" description: Type of repository enum: - image - plugin - null - example: "image" - nullable: true + example: image status: type: integer description: Repository status code @@ -2967,12 +2995,13 @@ components: enum: - active - inactive - example: "active" + example: active description: - type: string + type: + - string + - "null" description: Repository description - nullable: true - example: "Hello World! (an example of minimal Dockerization)" + example: Hello World! (an example of minimal Dockerization) is_private: type: boolean description: Whether the repository is private @@ -2988,22 +3017,24 @@ components: minimum: 0 example: 50000000 last_updated: - type: string + type: + - string + - "null" format: date-time description: ISO 8601 timestamp of when the repository was last updated - example: "2023-12-01T10:30:00Z" - nullable: true + example: 2023-12-01T10:30:00Z last_modified: - type: string + type: + - string + - "null" format: date-time description: ISO 8601 timestamp of when the repository was last modified - example: "2023-12-01T10:30:00Z" - nullable: true + example: 2023-12-01T10:30:00Z date_registered: type: string format: date-time description: ISO 8601 timestamp of when the repository was created - example: "2013-06-19T19:07:54Z" + example: 2013-06-19T19:07:54Z affiliation: type: string description: User's affiliation with the repository (empty string if no affiliation) @@ -3014,14 +3045,14 @@ components: items: type: string example: - - "application/vnd.docker.plugin.v1+json" + - application/vnd.docker.plugin.v1+json content_types: type: array description: Content types supported by this repository items: type: string example: - - "plugin" + - plugin categories: type: array description: Categories associated with this repository @@ -3042,14 +3073,14 @@ components: name: type: string description: Human-readable name of the category - example: "Databases" + example: Databases minLength: 1 slug: type: string description: URL-friendly identifier for the category - example: "databases" + example: databases minLength: 1 - pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*$" + pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$ description: Repository category for classification and discovery list_repositories_response: allOf: @@ -3094,7 +3125,6 @@ components: This token can be used in the HTTP Authorization header as a JWT to authenticate with the Docker Hub APIs. type: string example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c - nullable: false PostUsersLoginErrorResponse: description: failed user login response or second factor required type: object @@ -3105,13 +3135,13 @@ components: description: Description of the error. type: string example: Incorrect authentication credentials - nullable: false login_2fa_token: description: | Short time lived token to be used on `/v2/users/2fa-login` to complete the authentication. This field is present only if 2FA is enabled. - type: string + type: + - string + - "null" example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c - nullable: true Users2FALoginRequest: description: Second factor user login details type: object @@ -3136,7 +3166,6 @@ components: description: Description of the error. type: string example: Incorrect authentication credentials - nullable: false protobufAny: type: object properties: @@ -3254,11 +3283,12 @@ components: example: some user agent created_at: type: string - example: "2021-07-20T12:00:00.000000Z" + example: 2021-07-20T12:00:00.000000Z last_used: - type: string + type: + - string + - "null" example: null - nullable: true generated_by: type: string example: manual @@ -3280,7 +3310,7 @@ components: expires_at: type: string format: date-time - example: "2021-10-28T18:30:19.520861Z" + example: 2021-10-28T18:30:19.520861Z createAccessTokenRequest: type: object required: @@ -3307,7 +3337,7 @@ components: Optional expiration date for the token. If omitted, the token will remain valid indefinitely. format: date-time - example: "2021-10-28T18:30:19.520861Z" + example: 2021-10-28T18:30:19.520861Z createAccessTokensResponse: $ref: "#/components/schemas/accessToken" getAccessTokensResponse: @@ -3372,9 +3402,10 @@ components: type: object properties: digest: - type: string + type: + - string + - "null" description: image layer digest - nullable: true size: type: integer description: size of the layer @@ -3394,9 +3425,10 @@ components: type: string description: CPU variant digest: - type: string + type: + - string + - "null" description: image digest - nullable: true layers: type: array items: @@ -3420,15 +3452,17 @@ components: - inactive description: Status of the image last_pulled: - type: string - example: "2021-01-05T21:06:53.506400Z" + type: + - string + - "null" + example: 2021-01-05T21:06:53.506400Z description: datetime of last pull - nullable: true last_pushed: - type: string - example: "2021-01-05T21:06:53.506400Z" + type: + - string + - "null" + example: 2021-01-05T21:06:53.506400Z description: datetime of last push - nullable: true tag: type: object properties: @@ -3442,10 +3476,11 @@ components: type: integer description: ID of the user that pushed the tag last_updated: - type: string - example: "2021-01-05T21:06:53.506400Z" + type: + - string + - "null" + example: 2021-01-05T21:06:53.506400Z description: datetime of last update - nullable: true last_updater: type: integer description: ID of the last user that updated the tag @@ -3471,15 +3506,17 @@ components: - inactive description: whether a tag has been pushed to or pulled in the past month tag_last_pulled: - type: string - example: "2021-01-05T21:06:53.506400Z" + type: + - string + - "null" + example: 2021-01-05T21:06:53.506400Z description: datetime of last pull - nullable: true tag_last_pushed: - type: string - example: "2021-01-05T21:06:53.506400Z" + type: + - string + - "null" + example: 2021-01-05T21:06:53.506400Z description: datetime of last push - nullable: true paginated_tags: allOf: - $ref: "#/components/schemas/page" @@ -3496,13 +3533,15 @@ components: type: integer description: total number of results available across all pages next: - type: string + type: + - string + - "null" description: link to next page of results if any - nullable: true previous: - type: string + type: + - string + - "null" description: link to previous page of results if any - nullable: true scim_schema_attribute: type: object properties: @@ -3570,7 +3609,7 @@ components: example: owners created_at: type: string - example: "2021-10-28T18:30:19.520861Z" + example: 2021-10-28T18:30:19.520861Z bulk_invite: type: object properties: @@ -3599,7 +3638,7 @@ components: invitee: invitee@docker.com org: docker team: owners - created_at: "2021-10-28T18:30:19.520861Z" + created_at: 2021-10-28T18:30:19.520861Z - invitee: invitee2@docker.com status: existing_org_member - invitee: invitee3@docker.com @@ -3641,7 +3680,7 @@ components: example: Docker Inc date_joined: type: string - example: "2021-01-05T21:06:53.506400Z" + example: 2021-01-05T21:06:53.506400Z full_name: type: string example: Jon Snow @@ -3704,21 +3743,20 @@ components: description: | Last time the user logged in. To access this field, you must have insights visible for your organization. See [Insights](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). - example: "2021-01-05T21:06:53.506400Z" + example: 2021-01-05T21:06:53.506400Z last_seen_at: type: string format: date-time description: | Last time the user was seen. To access this field, you must have insights visible for your organization. See [Insights](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). - example: "2021-01-05T21:06:53.506400Z" + example: 2021-01-05T21:06:53.506400Z last_desktop_version: type: string description: | Last desktop version the user used. To access this field, you must have insights visible for your organization. See [Insights](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). example: 4.29.0 - org_member_paginated: type: object properties: @@ -3779,7 +3817,7 @@ components: date_joined: type: string format: date-time - example: "2021-01-05T21:06:53.506400Z" + example: 2021-01-05T21:06:53.506400Z full_name: type: string example: John Snow @@ -4034,41 +4072,43 @@ components: type: string format: date-time description: The creation date for the user as a RFC3339 formatted string. - example: "2022-05-20T00:54:18Z" + example: 2022-05-20T00:54:18Z lastModified: type: string format: date-time description: The date the user was last modified as a RFC3339 formatted string. - example: "2022-05-20T00:54:18Z" + example: 2022-05-20T00:54:18Z orgAccessToken: type: object properties: id: type: string - example: "a7a5ef25-8889-43a0-8cc7-f2a94268e861" + example: a7a5ef25-8889-43a0-8cc7-f2a94268e861 label: type: string - example: "My organization token" + example: My organization token created_by: type: string - example: "johndoe" + example: johndoe is_active: type: boolean example: true created_at: type: string format: date-time - example: "2022-05-20T00:54:18Z" + example: 2022-05-20T00:54:18Z expires_at: - type: string + type: + - string + - "null" format: date-time - example: "2023-05-20T00:54:18Z" - nullable: true + example: 2023-05-20T00:54:18Z last_used_at: - type: string + type: + - string + - "null" format: date-time - example: "2022-06-15T12:30:45Z" - nullable: true + example: 2022-06-15T12:30:45Z orgAccessTokenResource: type: object properties: @@ -4077,12 +4117,11 @@ components: enum: - TYPE_REPO - TYPE_ORG - example: "TYPE_REPO" + example: TYPE_REPO description: The type of resource - required: true path: type: string - example: "myorg/myrepo" + example: myorg/myrepo description: | The path of the resource. The format of this will change depending on the type of resource. @@ -4090,14 +4129,16 @@ components: - Must be an existing repository name (e.g., "myorg/myrepo") - Can use glob patterns (e.g., "myorg/*" for all repositories in the organization) - Use "*/*/public" to reference all public repositories - required: true scopes: type: array description: The scopes this token has access to items: type: string - example: "scope-image-pull" - required: true + example: scope-image-pull + required: + - type + - path + - scopes getOrgAccessTokensResponse: type: object properties: @@ -4130,23 +4171,25 @@ components: label: type: string description: Label for the access token - example: "My organization token" - required: true + example: My organization token description: type: string description: Description of the access token - example: "Token for CI/CD pipeline" + example: Token for CI/CD pipeline resources: type: array description: Resources this token has access to items: $ref: "#/components/schemas/orgAccessTokenResource" expires_at: - type: string + type: + - string + - "null" format: date-time description: Expiration date for the token - example: "2023-05-20T00:54:18Z" - nullable: true + example: 2023-05-20T00:54:18Z + required: + - label createOrgAccessTokenResponse: type: object allOf: @@ -4154,33 +4197,35 @@ components: properties: id: type: string - example: "a7a5ef25-8889-43a0-8cc7-f2a94268e861" + example: a7a5ef25-8889-43a0-8cc7-f2a94268e861 label: type: string - example: "My organization token" + example: My organization token is_active: type: boolean example: true created_at: type: string format: date-time - example: "2022-05-20T00:54:18Z" + example: 2022-05-20T00:54:18Z expires_at: - type: string + type: + - string + - "null" format: date-time - example: "2023-05-20T00:54:18Z" - nullable: true + example: 2023-05-20T00:54:18Z last_used_at: - type: string + type: + - string + - "null" format: date-time - example: "2022-06-15T12:30:45Z" - nullable: true + example: 2022-06-15T12:30:45Z - type: object properties: token: type: string description: The actual token value that can be used for authentication - example: "dckr_oat_7awgM4jG5SQvxcvmNzhKj8PQjxo" + example: dckr_oat_7awgM4jG5SQvxcvmNzhKj8PQjxo resources: type: array items: @@ -4191,11 +4236,11 @@ components: label: type: string description: Label for the access token - example: "My organization token" + example: My organization token description: type: string description: Description of the access token - example: "Token for CI/CD pipeline" + example: Token for CI/CD pipeline resources: type: array description: Resources this token has access to @@ -4218,7 +4263,7 @@ components: $ref: "#/components/schemas/orgAccessTokenResource" team_repo: allOf: - - $ref: "#/components/responses/team_repo" + - $ref: "#/components/schemas/repository_info" properties: group_name: type: string @@ -4442,6 +4487,10 @@ components: bearerSCIMAuth: type: http scheme: bearer + scimToken: + type: http + scheme: bearer + description: Use the SCIM provisioning token configured for the organization. x-tagGroups: - name: General tags: @@ -4462,3 +4511,5 @@ x-tagGroups: - org-access-tokens - groups - invites +jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base +security: [] diff --git a/hack/api-docs/adoption/hub.json b/hack/api-docs/adoption/hub.json new file mode 100644 index 000000000000..49a9323bf289 --- /dev/null +++ b/hack/api-docs/adoption/hub.json @@ -0,0 +1,2950 @@ +{ + "api": "hub", + "source": { + "id": "hub", + "product": "hub", + "title": "Docker Hub", + "source": "content/reference/api/hub/latest.yaml", + "owner": "docker/docs (product authority to confirm)", + "manual": "/manuals/docker-hub/", + "connection": "hosted", + "auth": "Use the documented Hub token exchange. SCIM operations use a separate provisioning token.", + "guides": [ + "/manuals/security/provisioning/scim/provision-scim.md" + ], + "sha256": "aeefa9b62b10d70f9e28e9508d5a4c1361e0a541e209ff0af9ed2544b0cb415e" + }, + "convertedSha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "profile": "docker-docs-prototype-1", + "changes": [ + { + "pointer": "/jsonSchemaDialect", + "beforePresent": false, + "afterPresent": true, + "after": "https://spec.openapis.org/oas/3.1/dialect/base", + "id": "hub-03ee85af235e", + "stage": "oas32-header", + "classification": "mechanical conversion", + "rationale": "Adopt the common OpenAPI version and its selected schema dialect.", + "evidence": "API-DOCUMENTATION-ARCHITECTURE.md S1", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/jsonSchemaDialect" + }, + { + "pointer": "/openapi", + "beforePresent": true, + "afterPresent": true, + "before": "3.0.3", + "after": "3.2.0", + "id": "hub-71377657b6ae", + "stage": "oas32-header", + "classification": "mechanical conversion", + "rationale": "Adopt the common OpenAPI version and its selected schema dialect.", + "evidence": "API-DOCUMENTATION-ARCHITECTURE.md S1", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/openapi", + "destinationPointer": "/openapi" + }, + { + "pointer": "/components/schemas/PostUsers2FALoginErrorResponse/properties/detail/nullable", + "beforePresent": true, + "afterPresent": false, + "before": false, + "id": "hub-4a84441cce53", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/PostUsers2FALoginErrorResponse/properties/detail/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/PostUsersLoginErrorResponse/properties/detail/nullable", + "beforePresent": true, + "afterPresent": false, + "before": false, + "id": "hub-209f129099a9", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/PostUsersLoginErrorResponse/properties/detail/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-74ca1738d170", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-14920c5fdaca", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/type", + "destinationPointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/type" + }, + { + "pointer": "/components/schemas/PostUsersLoginSuccessResponse/properties/token/nullable", + "beforePresent": true, + "afterPresent": false, + "before": false, + "id": "hub-f4382a2a3adb", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/PostUsersLoginSuccessResponse/properties/token/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/accessToken/properties/last_used/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-419d1bfbeeec", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/accessToken/properties/last_used/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/accessToken/properties/last_used/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-03403114b7b9", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/accessToken/properties/last_used/type", + "destinationPointer": "/components/schemas/accessToken/properties/last_used/type" + }, + { + "pointer": "/components/schemas/createOrgAccessTokenRequest/properties/expires_at/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-25ea10e8d019", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/createOrgAccessTokenRequest/properties/expires_at/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/createOrgAccessTokenRequest/properties/expires_at/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-4251302b3c95", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/createOrgAccessTokenRequest/properties/expires_at/type", + "destinationPointer": "/components/schemas/createOrgAccessTokenRequest/properties/expires_at/type" + }, + { + "pointer": "/components/schemas/createOrgAccessTokenResponse/allOf", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "a7a5ef25-8889-43a0-8cc7-f2a94268e861" + }, + "label": { + "type": "string", + "example": "My organization token" + }, + "is_active": { + "type": "boolean", + "example": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2022-05-20T00:54:18Z" + }, + "expires_at": { + "type": "string", + "format": "date-time", + "example": "2023-05-20T00:54:18Z", + "nullable": true + }, + "last_used_at": { + "type": "string", + "format": "date-time", + "example": "2022-06-15T12:30:45Z", + "nullable": true + } + } + }, + { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "The actual token value that can be used for authentication", + "example": "dckr_oat_7awgM4jG5SQvxcvmNzhKj8PQjxo" + }, + "resources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/orgAccessTokenResource" + } + } + } + } + ], + "after": [ + { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "a7a5ef25-8889-43a0-8cc7-f2a94268e861" + }, + "label": { + "type": "string", + "example": "My organization token" + }, + "is_active": { + "type": "boolean", + "example": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2022-05-20T00:54:18Z" + }, + "expires_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2023-05-20T00:54:18Z" + }, + "last_used_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2022-06-15T12:30:45Z" + } + } + }, + { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "The actual token value that can be used for authentication", + "example": "dckr_oat_7awgM4jG5SQvxcvmNzhKj8PQjxo" + }, + "resources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/orgAccessTokenResource" + } + } + } + } + ], + "id": "hub-6c45e809bb08", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/createOrgAccessTokenResponse/allOf", + "destinationPointer": "/components/schemas/createOrgAccessTokenResponse/allOf" + }, + { + "pointer": "/components/schemas/image/properties/digest/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-7b78462e893b", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/image/properties/digest/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/image/properties/digest/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-549328d76dcd", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/image/properties/digest/type", + "destinationPointer": "/components/schemas/image/properties/digest/type" + }, + { + "pointer": "/components/schemas/image/properties/last_pulled/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-5499989516b9", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/image/properties/last_pulled/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/image/properties/last_pulled/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-443454d8717b", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/image/properties/last_pulled/type", + "destinationPointer": "/components/schemas/image/properties/last_pulled/type" + }, + { + "pointer": "/components/schemas/image/properties/last_pushed/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-d2b5e9cbe250", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/image/properties/last_pushed/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/image/properties/last_pushed/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-f68167523b21", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/image/properties/last_pushed/type", + "destinationPointer": "/components/schemas/image/properties/last_pushed/type" + }, + { + "pointer": "/components/schemas/layer/properties/digest/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-983b2bb794e8", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/layer/properties/digest/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/layer/properties/digest/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-3e1807d3a49e", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/layer/properties/digest/type", + "destinationPointer": "/components/schemas/layer/properties/digest/type" + }, + { + "pointer": "/components/schemas/orgAccessToken/properties/expires_at/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-1dd2703f9cc7", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/orgAccessToken/properties/expires_at/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/orgAccessToken/properties/expires_at/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-e97055a90965", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/orgAccessToken/properties/expires_at/type", + "destinationPointer": "/components/schemas/orgAccessToken/properties/expires_at/type" + }, + { + "pointer": "/components/schemas/orgAccessToken/properties/last_used_at/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-4770a0e1fc68", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/orgAccessToken/properties/last_used_at/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/orgAccessToken/properties/last_used_at/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-bcb75b8a4856", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/orgAccessToken/properties/last_used_at/type", + "destinationPointer": "/components/schemas/orgAccessToken/properties/last_used_at/type" + }, + { + "pointer": "/components/schemas/page/properties/next/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-5f51929ee3be", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/page/properties/next/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/page/properties/next/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-1c9303e797fd", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/page/properties/next/type", + "destinationPointer": "/components/schemas/page/properties/next/type" + }, + { + "pointer": "/components/schemas/page/properties/previous/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-f55371c00ee8", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/page/properties/previous/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/page/properties/previous/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-aaf9dcecb4e7", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/page/properties/previous/type", + "destinationPointer": "/components/schemas/page/properties/previous/type" + }, + { + "pointer": "/components/schemas/repository_info/properties/affiliation/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-db0ca8c6118b", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/affiliation/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/repository_info/properties/affiliation/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-53c12223e744", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/affiliation/type", + "destinationPointer": "/components/schemas/repository_info/properties/affiliation/type" + }, + { + "pointer": "/components/schemas/repository_info/properties/full_description/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-693d06466546", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/full_description/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/repository_info/properties/full_description/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-f2a62661a71f", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/full_description/type", + "destinationPointer": "/components/schemas/repository_info/properties/full_description/type" + }, + { + "pointer": "/components/schemas/repository_info/properties/hub_user/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-586430b24161", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/hub_user/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/repository_info/properties/hub_user/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-8b002c0c2379", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/hub_user/type", + "destinationPointer": "/components/schemas/repository_info/properties/hub_user/type" + }, + { + "pointer": "/components/schemas/repository_info/properties/last_modified/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-51ed4d2375e7", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/last_modified/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/repository_info/properties/last_modified/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-e3991fed6abd", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/last_modified/type", + "destinationPointer": "/components/schemas/repository_info/properties/last_modified/type" + }, + { + "pointer": "/components/schemas/repository_info/properties/media_types/items/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-e5cd63f7e46b", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/media_types/items/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/repository_info/properties/media_types/items/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-d4542159a0cb", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/media_types/items/type", + "destinationPointer": "/components/schemas/repository_info/properties/media_types/items/type" + }, + { + "pointer": "/components/schemas/repository_info/properties/repository_type/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-3ed558f36655", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/repository_type/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/repository_info/properties/repository_type/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-572974596a5e", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/repository_type/type", + "destinationPointer": "/components/schemas/repository_info/properties/repository_type/type" + }, + { + "pointer": "/components/schemas/repository_info/properties/source/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-e33e16e370d0", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/source/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/repository_info/properties/source/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-8e2a47ca4188", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/source/type", + "destinationPointer": "/components/schemas/repository_info/properties/source/type" + }, + { + "pointer": "/components/schemas/repository_info/properties/storage_size/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-a9dd6412fb55", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/storage_size/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/repository_info/properties/storage_size/type", + "beforePresent": true, + "afterPresent": true, + "before": "integer", + "after": [ + "integer", + "null" + ], + "id": "hub-3cb15ac31d13", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_info/properties/storage_size/type", + "destinationPointer": "/components/schemas/repository_info/properties/storage_size/type" + }, + { + "pointer": "/components/schemas/repository_list_entry/properties/description/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-3433b42e6550", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_list_entry/properties/description/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/repository_list_entry/properties/description/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-dda7391614bd", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_list_entry/properties/description/type", + "destinationPointer": "/components/schemas/repository_list_entry/properties/description/type" + }, + { + "pointer": "/components/schemas/repository_list_entry/properties/last_modified/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-bb137761a5e2", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_list_entry/properties/last_modified/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/repository_list_entry/properties/last_modified/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-4de50800605e", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_list_entry/properties/last_modified/type", + "destinationPointer": "/components/schemas/repository_list_entry/properties/last_modified/type" + }, + { + "pointer": "/components/schemas/repository_list_entry/properties/last_updated/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-7048a5c0fa51", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_list_entry/properties/last_updated/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/repository_list_entry/properties/last_updated/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-17edbfb92a97", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_list_entry/properties/last_updated/type", + "destinationPointer": "/components/schemas/repository_list_entry/properties/last_updated/type" + }, + { + "pointer": "/components/schemas/repository_list_entry/properties/repository_type/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-d20310dd5ae2", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_list_entry/properties/repository_type/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/repository_list_entry/properties/repository_type/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-f86e7bbc38a4", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/repository_list_entry/properties/repository_type/type", + "destinationPointer": "/components/schemas/repository_list_entry/properties/repository_type/type" + }, + { + "pointer": "/components/schemas/tag/properties/last_updated/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-68b24c8c5109", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/tag/properties/last_updated/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/tag/properties/last_updated/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-a26b67fb6339", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/tag/properties/last_updated/type", + "destinationPointer": "/components/schemas/tag/properties/last_updated/type" + }, + { + "pointer": "/components/schemas/tag/properties/tag_last_pulled/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-cb1f15cd0a83", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/tag/properties/tag_last_pulled/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/tag/properties/tag_last_pulled/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-3709a230a429", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/tag/properties/tag_last_pulled/type", + "destinationPointer": "/components/schemas/tag/properties/tag_last_pulled/type" + }, + { + "pointer": "/components/schemas/tag/properties/tag_last_pushed/nullable", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-689c7a489f31", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/tag/properties/tag_last_pushed/nullable", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/tag/properties/tag_last_pushed/type", + "beforePresent": true, + "afterPresent": true, + "before": "string", + "after": [ + "string", + "null" + ], + "id": "hub-aea53f482c72", + "stage": "oas30-schema-semantics", + "classification": "mechanical conversion", + "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", + "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/tag/properties/tag_last_pushed/type", + "destinationPointer": "/components/schemas/tag/properties/tag_last_pushed/type" + }, + { + "pointer": "/paths/~1v2~1access-tokens/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2AccessTokens", + "id": "hub-f8cbd35e78df", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1access-tokens/get/operationId" + }, + { + "pointer": "/paths/~1v2~1access-tokens/post/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "postV2AccessTokens", + "id": "hub-afd4cf26e093", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1access-tokens/post/operationId" + }, + { + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/delete/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "deleteV2AccessTokensByUuid", + "id": "hub-4c342a5a6523", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1access-tokens~1{uuid}/delete/operationId" + }, + { + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2AccessTokensByUuid", + "id": "hub-4fcb33e51e3d", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1access-tokens~1{uuid}/get/operationId" + }, + { + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "patchV2AccessTokensByUuid", + "id": "hub-00969ade81fd", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/operationId" + }, + { + "pointer": "/paths/~1v2~1invites~1bulk/post/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "postV2InvitesBulk", + "id": "hub-d346b6e45684", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1invites~1bulk/post/operationId" + }, + { + "pointer": "/paths/~1v2~1invites~1{id}/delete/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "deleteV2InvitesById", + "id": "hub-c81d9b7f93da", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1invites~1{id}/delete/operationId" + }, + { + "pointer": "/paths/~1v2~1invites~1{id}~1resend/patch/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "patchV2InvitesByIdResend", + "id": "hub-55feefec6ccc", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1invites~1{id}~1resend/patch/operationId" + }, + { + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "headV2NamespacesByNamespaceRepositoriesByRepositoryTags", + "id": "hub-6ec409f24610", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/operationId" + }, + { + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "headV2NamespacesByNamespaceRepositoriesByRepositoryTagsByTag", + "id": "hub-cd3fa54d0bec", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2OrgsByNameAccessTokens", + "id": "hub-86bc936786d2", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "postV2OrgsByNameAccessTokens", + "id": "hub-36afe9a3a367", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2OrgsByNameSettings", + "id": "hub-fd160d644a0d", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{name}~1settings/get/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "putV2OrgsByNameSettings", + "id": "hub-30c79dee6ea5", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{name}~1settings/put/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "deleteV2OrgsByOrgNameAccessTokensByAccessTokenId", + "id": "hub-28cba8092f0d", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2OrgsByOrgNameAccessTokensByAccessTokenId", + "id": "hub-ac00804f74e2", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "patchV2OrgsByOrgNameAccessTokensByAccessTokenId", + "id": "hub-0143389a74a8", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2OrgsByOrgNameGroups", + "id": "hub-7aede6605aad", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "postV2OrgsByOrgNameGroups", + "id": "hub-2c5c68daf41b", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "deleteV2OrgsByOrgNameGroupsByGroupName", + "id": "hub-421de8c8e3f8", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2OrgsByOrgNameGroupsByGroupName", + "id": "hub-9d2c9cff8fea", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "patchV2OrgsByOrgNameGroupsByGroupName", + "id": "hub-1a150e13f5c0", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "putV2OrgsByOrgNameGroupsByGroupName", + "id": "hub-b88a4cb28cdf", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2OrgsByOrgNameGroupsByGroupNameMembers", + "id": "hub-e630bef3c6ed", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "postV2OrgsByOrgNameGroupsByGroupNameMembers", + "id": "hub-f6571b90ccc1", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "deleteV2OrgsByOrgNameGroupsByGroupNameMembersByUsername", + "id": "hub-751cc2434894", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2OrgsByOrgNameInvites", + "id": "hub-39565bc4387b", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2OrgsByOrgNameMembers", + "id": "hub-7a816176b210", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2OrgsByOrgNameMembersExport", + "id": "hub-53f01d4baf21", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "deleteV2OrgsByOrgNameMembersByUsername", + "id": "hub-4fe305418a38", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/operationId" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "putV2OrgsByOrgNameMembersByUsername", + "id": "hub-a33b621b26f7", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/operationId" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2Scim20ResourceTypes", + "id": "hub-f6e536e43752", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/operationId" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2Scim20ResourceTypesByName", + "id": "hub-5e3a1826a68f", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/operationId" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1Schemas/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2Scim20Schemas", + "id": "hub-78d7c72f266f", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1scim~12.0~1Schemas/get/operationId" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2Scim20SchemasById", + "id": "hub-98da271d89fe", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/operationId" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2Scim20ServiceProviderConfig", + "id": "hub-ad9109142d86", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/operationId" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1Users/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2Scim20Users", + "id": "hub-1de3a58d007a", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1scim~12.0~1Users/get/operationId" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1Users/post/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "postV2Scim20Users", + "id": "hub-5899924999f5", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1scim~12.0~1Users/post/operationId" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "getV2Scim20UsersById", + "id": "hub-b9e1e6211828", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/operationId" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/operationId", + "beforePresent": false, + "afterPresent": true, + "after": "putV2Scim20UsersById", + "id": "hub-f4368513b4a2", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/operationId" + }, + { + "pointer": "/tags", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "name": "changelog", + "x-displayName": "Changelog", + "description": "See the [Changelog](/reference/api/hub/changelog) for a summary of changes across Docker Hub API versions.\n" + }, + { + "name": "resources", + "x-displayName": "Resources", + "description": "The following resources are available to interact with the documented API:\n- [Docker Hub CLI tool](https://github.com/docker/hub-tool#readme) (currently experimental)\n" + }, + { + "name": "rate-limiting", + "x-displayName": "Rate Limiting", + "description": "The Docker Hub API is limited on the amount of requests you can perform per minute against it.\n\nIf you haven't hit the limit, each request to the API will return the following headers in the response.\n\n- `X-RateLimit-Limit` - The limit of requests per minute.\n- `X-RateLimit-Remaining` - The remaining amount of calls within the limit period.\n- `X-RateLimit-Reset` - The unix timestamp of when the remaining resets.\n\nIf you have hit the limit, you will receive a response status of `429` and the `Retry-After` header in the response.\n\nThe [`Retry-After` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After) specifies the number of seconds to wait until you can call the API again.\n\n**Note**: These rate limits are separate from anti-abuse and Docker Hub download, or pull rate limiting.\nTo learn more about Docker Hub pull rate limiting, see [Usage and limits](https://docs.docker.com/docker-hub/usage/).\n" + }, + { + "name": "authentication", + "x-displayName": "Authentication", + "description": "Most Docker Hub API endpoints require you to authenticate using your Docker credentials before using them.\n\nAdditionally, similar to the Docker Hub UI features, API endpoint responses may vary depending on your subscription (Personal, Pro, or Team) and your account's permissions.\n\nTo learn more about the features available in each subscription and to upgrade your existing subscription, see [Docker Pricing](https://www.docker.com/pricing?ref=Docs&refAction=DocsApiHub).\n\n# Types\n\nThe Docker Hub API supports the following authentication types.\n\nYou must use each authentication type with the [Create access token](#tag/authentication-api/operation/AuthCreateAccessToken) route to obtain a bearer token.\n\n## Password\nUsing a username and password is the most powerful, yet least secure way \nto authenticate with Docker as a user. It allows access to resources \nfor the user without scopes. \n\n_In general, it is recommended to use a personal access token (PAT) instead._\n\n_**The password authentication type is not available if your organization has SSO enforced.**_\n\n## Personal Access Token (PAT)\nUsing a username and PAT is the most secure way to authenticate with \nDocker as a user. PATs are scoped to specific resources and scopes.\n\nCurrently, a PAT is a more secure password due to limited functionality. \nIn the future, we may add fine-grained access like organization \naccess tokens for enhanced usage and security.\n\n## Organization Access Token (OAT)\nOrganization access tokens are scoped to specific resources and scopes \nin an organization. They are managed by organization owners. \n\nThese tokens are meant for automation and are not meant to be used by \nusers.\n\n# Labels\n\nThese labels will show up on routes in this reference that allow for use of bearer \ntokens issued from them.\n\n\n\n" + }, + { + "name": "authentication-api", + "x-displayName": "Authentication", + "description": "The authentication endpoints allow you to authenticate with Docker Hub APIs.\n\nFor more information, see [Authentication](#tag/authentication).\n" + }, + { + "name": "access-tokens", + "x-displayName": "Personal Access Tokens", + "description": "The Personal Access Token endpoints lets you manage personal access tokens. For more information, see [Access Tokens](https://docs.docker.com/security/access-tokens/personal-access-tokens/).\n\nYou can use a personal access token instead of a password in the [Docker CLI](https://docs.docker.com/engine/reference/commandline/cli/) or in the [Create an authentication token](#operation/PostUsersLogin) route to obtain a bearer token.\n\n### Scopes\n\nFor each scope grouping (in this case \"repo\"), you only need to define 1 scope as any lower scopes are assumed.\nFor example: If you define `repo:write`, the API assumes the scope of both `repo:read` *and* `repo:public_read` as well.\nIf you were to define both `repo:write` *and* `repo:read`, then `repo:read` is assumed by `repo:write` and ignored.\n\n***Treat your personal access token like your password and keep it secret. You cannot retrieve your token after it is generated.***\n" + }, + { + "name": "audit-logs", + "x-displayName": "Audit Logs", + "description": "The Audit Logs API endpoints allow you to query audit log events across a namespace.\n\nFor more information, see [Audit Logs](https://docs.docker.com/admin/activity-logs/).\n" + }, + { + "name": "org-settings", + "x-displayName": "Org Settings", + "description": "The Org Settings API endpoints allow you to manage your organization's settings.\n" + }, + { + "name": "repositories", + "x-displayName": "Repositories", + "description": "The repository endpoints allow you to access your repository's tags.\n" + }, + { + "name": "orgs", + "x-displayName": "Organizations", + "x-audience": "public", + "description": "The organization endpoints allow you to interact with and manage your organizations.\n\nFor more information, see [Organization administration overview](https://docs.docker.com/admin/organization/).\n" + }, + { + "name": "groups", + "x-displayName": "Groups (Teams)", + "x-audience": "public", + "description": "The groups endpoints allow you to manage your organization's teams and their members.\n\nFor more information, see [Create and manage a team](https://docs.docker.com/admin/organization/manage/manage-a-team/).\n" + }, + { + "name": "invites", + "x-displayName": "Invites", + "x-audience": "public", + "description": "The invites endpoints allow you to manage invites for users to join your Docker organization.\n\nFor more information, see [Invite members](https://docs.docker.com/admin/organization/manage/members/#invite-members).\n" + }, + { + "name": "scim", + "x-displayName": "SCIM", + "x-audience": "public", + "description": "SCIM is a provisioning system that lets you manage users within your identity provider (IdP).\n\nFor more information, see [System for Cross-domain Identity management](https://docs.docker.com/security/for-admins/provisioning/scim/).\n" + }, + { + "name": "org-access-tokens", + "x-displayName": "Organization Access Tokens", + "x-audience": "public", + "description": "The organization access token endpoints allow you to manage organization access tokens (OATs). See [Organization access tokens](https://docs.docker.com/security/for-admins/access-tokens/) for more information.\n\nOATs only authenticate requests to the modern namespace-scoped routes under `/v2/namespaces/{namespace}/repositories/`. Legacy repository paths are OAT unsupported, regardless of the token's scopes, and reject every OAT with `403 token issued from organization access token is not allowed`:\n\n- `GET /v2/repositories/{namespace}/{repository}` — use [Get repository](#tag/repositories/operation/GetRepository) instead.\n- `GET /v2/repositories/{namespace}` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n- `GET /v2/users/{username}/repositories` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n" + } + ], + "after": [ + { + "name": "changelog", + "description": "See the [Changelog](/reference/api/hub/changelog) for a summary of changes across Docker Hub API versions.\n", + "summary": "Changelog", + "kind": "info" + }, + { + "name": "resources", + "description": "The following resources are available to interact with the documented API:\n- [Docker Hub CLI tool](https://github.com/docker/hub-tool#readme) (currently experimental)\n", + "summary": "Resources", + "kind": "info" + }, + { + "name": "rate-limiting", + "description": "The Docker Hub API is limited on the amount of requests you can perform per minute against it.\n\nIf you haven't hit the limit, each request to the API will return the following headers in the response.\n\n- `X-RateLimit-Limit` - The limit of requests per minute.\n- `X-RateLimit-Remaining` - The remaining amount of calls within the limit period.\n- `X-RateLimit-Reset` - The unix timestamp of when the remaining resets.\n\nIf you have hit the limit, you will receive a response status of `429` and the `Retry-After` header in the response.\n\nThe [`Retry-After` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After) specifies the number of seconds to wait until you can call the API again.\n\n**Note**: These rate limits are separate from anti-abuse and Docker Hub download, or pull rate limiting.\nTo learn more about Docker Hub pull rate limiting, see [Usage and limits](https://docs.docker.com/docker-hub/usage/).\n", + "summary": "Rate Limiting", + "kind": "info" + }, + { + "name": "authentication", + "description": "Most Docker Hub API endpoints require you to authenticate using your Docker credentials before using them.\n\nAdditionally, similar to the Docker Hub UI features, API endpoint responses may vary depending on your subscription (Personal, Pro, or Team) and your account's permissions.\n\nTo learn more about the features available in each subscription and to upgrade your existing subscription, see [Docker Pricing](https://www.docker.com/pricing?ref=Docs&refAction=DocsApiHub).\n\n# Types\n\nThe Docker Hub API supports the following authentication types.\n\nYou must use each authentication type with the [Create access token](#tag/authentication-api/operation/AuthCreateAccessToken) route to obtain a bearer token.\n\n## Password\nUsing a username and password is the most powerful, yet least secure way \nto authenticate with Docker as a user. It allows access to resources \nfor the user without scopes. \n\n_In general, it is recommended to use a personal access token (PAT) instead._\n\n_**The password authentication type is not available if your organization has SSO enforced.**_\n\n## Personal Access Token (PAT)\nUsing a username and PAT is the most secure way to authenticate with \nDocker as a user. PATs are scoped to specific resources and scopes.\n\nCurrently, a PAT is a more secure password due to limited functionality. \nIn the future, we may add fine-grained access like organization \naccess tokens for enhanced usage and security.\n\n## Organization Access Token (OAT)\nOrganization access tokens are scoped to specific resources and scopes \nin an organization. They are managed by organization owners. \n\nThese tokens are meant for automation and are not meant to be used by \nusers.\n\n# Labels\n\nThese labels will show up on routes in this reference that allow for use of bearer \ntokens issued from them.\n\n\n\n", + "summary": "Authentication", + "kind": "info" + }, + { + "name": "authentication-api", + "description": "The authentication endpoints allow you to authenticate with Docker Hub APIs.\n\nFor more information, see [Authentication](#tag/authentication).\n", + "summary": "Authentication", + "kind": "nav" + }, + { + "name": "access-tokens", + "description": "The Personal Access Token endpoints lets you manage personal access tokens. For more information, see [Access Tokens](https://docs.docker.com/security/access-tokens/personal-access-tokens/).\n\nYou can use a personal access token instead of a password in the [Docker CLI](https://docs.docker.com/engine/reference/commandline/cli/) or in the [Create an authentication token](#operation/PostUsersLogin) route to obtain a bearer token.\n\n### Scopes\n\nFor each scope grouping (in this case \"repo\"), you only need to define 1 scope as any lower scopes are assumed.\nFor example: If you define `repo:write`, the API assumes the scope of both `repo:read` *and* `repo:public_read` as well.\nIf you were to define both `repo:write` *and* `repo:read`, then `repo:read` is assumed by `repo:write` and ignored.\n\n***Treat your personal access token like your password and keep it secret. You cannot retrieve your token after it is generated.***\n", + "summary": "Personal Access Tokens", + "kind": "nav" + }, + { + "name": "audit-logs", + "description": "The Audit Logs API endpoints allow you to query audit log events across a namespace.\n\nFor more information, see [Audit Logs](https://docs.docker.com/admin/activity-logs/).\n", + "summary": "Audit Logs", + "kind": "nav" + }, + { + "name": "org-settings", + "description": "The Org Settings API endpoints allow you to manage your organization's settings.\n", + "summary": "Org Settings", + "kind": "nav" + }, + { + "name": "repositories", + "description": "The repository endpoints allow you to access your repository's tags.\n", + "summary": "Repositories", + "kind": "nav" + }, + { + "name": "orgs", + "x-audience": "public", + "description": "The organization endpoints allow you to interact with and manage your organizations.\n\nFor more information, see [Organization administration overview](https://docs.docker.com/admin/organization/).\n", + "summary": "Organizations", + "kind": "nav" + }, + { + "name": "groups", + "x-audience": "public", + "description": "The groups endpoints allow you to manage your organization's teams and their members.\n\nFor more information, see [Create and manage a team](https://docs.docker.com/admin/organization/manage/manage-a-team/).\n", + "summary": "Groups (Teams)", + "kind": "nav" + }, + { + "name": "invites", + "x-audience": "public", + "description": "The invites endpoints allow you to manage invites for users to join your Docker organization.\n\nFor more information, see [Invite members](https://docs.docker.com/admin/organization/manage/members/#invite-members).\n", + "summary": "Invites", + "kind": "nav" + }, + { + "name": "scim", + "x-audience": "public", + "description": "SCIM is a provisioning system that lets you manage users within your identity provider (IdP).\n\nFor more information, see [System for Cross-domain Identity management](https://docs.docker.com/security/for-admins/provisioning/scim/).\n", + "summary": "SCIM", + "kind": "nav" + }, + { + "name": "org-access-tokens", + "x-audience": "public", + "description": "The organization access token endpoints allow you to manage organization access tokens (OATs). See [Organization access tokens](https://docs.docker.com/security/for-admins/access-tokens/) for more information.\n\nOATs only authenticate requests to the modern namespace-scoped routes under `/v2/namespaces/{namespace}/repositories/`. Legacy repository paths are OAT unsupported, regardless of the token's scopes, and reject every OAT with `403 token issued from organization access token is not allowed`:\n\n- `GET /v2/repositories/{namespace}/{repository}` — use [Get repository](#tag/repositories/operation/GetRepository) instead.\n- `GET /v2/repositories/{namespace}` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n- `GET /v2/users/{username}/repositories` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n", + "summary": "Organization Access Tokens", + "kind": "nav" + } + ], + "id": "hub-8d93cf25f3e7", + "stage": "editorial-metadata", + "classification": "editorial completion", + "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", + "evidence": "Existing operation summaries, paths, and tags", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/tags", + "destinationPointer": "/tags" + }, + { + "pointer": "/components/schemas/createOrgAccessTokenRequest/properties/label/required", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-56f5267c831d", + "stage": "property-required-correction", + "classification": "evidence-backed correction", + "rationale": "Move misplaced boolean property required flags to the parent required array; preserve the declared requiredness.", + "evidence": "Original property-level required: true declarations", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/createOrgAccessTokenRequest/properties/label/required", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/createOrgAccessTokenRequest/required", + "beforePresent": false, + "afterPresent": true, + "after": [ + "label" + ], + "id": "hub-8f8f2dc78a3c", + "stage": "property-required-correction", + "classification": "evidence-backed correction", + "rationale": "Move misplaced boolean property required flags to the parent required array; preserve the declared requiredness.", + "evidence": "Original property-level required: true declarations", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/components/schemas/createOrgAccessTokenRequest/required" + }, + { + "pointer": "/components/schemas/orgAccessTokenResource/properties/path/required", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-ef566a3ef04a", + "stage": "property-required-correction", + "classification": "evidence-backed correction", + "rationale": "Move misplaced boolean property required flags to the parent required array; preserve the declared requiredness.", + "evidence": "Original property-level required: true declarations", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/orgAccessTokenResource/properties/path/required", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/orgAccessTokenResource/properties/scopes/required", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-bc0d5d30d7e9", + "stage": "property-required-correction", + "classification": "evidence-backed correction", + "rationale": "Move misplaced boolean property required flags to the parent required array; preserve the declared requiredness.", + "evidence": "Original property-level required: true declarations", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/orgAccessTokenResource/properties/scopes/required", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/orgAccessTokenResource/properties/type/required", + "beforePresent": true, + "afterPresent": false, + "before": true, + "id": "hub-ea46f67c99f8", + "stage": "property-required-correction", + "classification": "evidence-backed correction", + "rationale": "Move misplaced boolean property required flags to the parent required array; preserve the declared requiredness.", + "evidence": "Original property-level required: true declarations", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/orgAccessTokenResource/properties/type/required", + "destinationPointer": null + }, + { + "pointer": "/components/schemas/orgAccessTokenResource/required", + "beforePresent": false, + "afterPresent": true, + "after": [ + "type", + "path", + "scopes" + ], + "id": "hub-60b71cffddb5", + "stage": "property-required-correction", + "classification": "evidence-backed correction", + "rationale": "Move misplaced boolean property required flags to the parent required array; preserve the declared requiredness.", + "evidence": "Original property-level required: true declarations", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/components/schemas/orgAccessTokenResource/required" + }, + { + "pointer": "/paths/~1v2~1auditlogs~1{account}/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "List audit log events for a given namespace.\n\n\n", + "after": "List audit log events for a given namespace.\n\n\n", + "id": "hub-cf10c2a6bb54", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1auditlogs~1{account}/get/description", + "destinationPointer": "/paths/~1v2~1auditlogs~1{account}/get/description" + }, + { + "pointer": "/paths/~1v2~1auditlogs~1{account}~1actions/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "List audit log actions for a namespace to be used as a filter for querying audit log events.\n\n\n", + "after": "List audit log actions for a namespace to be used as a filter for querying audit log events.\n\n\n", + "id": "hub-37ef6ed3805f", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1auditlogs~1{account}~1actions/get/description", + "destinationPointer": "/paths/~1v2~1auditlogs~1{account}~1actions/get/description" + }, + { + "pointer": "/paths/~1v2~1invites~1bulk/post/description", + "beforePresent": true, + "afterPresent": true, + "before": "Create multiple invites by emails or DockerIDs. Only a team owner can create invites.\n\n\n", + "after": "Create multiple invites by emails or DockerIDs. Only a team owner can create invites.\n\n\n", + "id": "hub-71965f574da9", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1invites~1bulk/post/description", + "destinationPointer": "/paths/~1v2~1invites~1bulk/post/description" + }, + { + "pointer": "/paths/~1v2~1invites~1{id}/delete/description", + "beforePresent": true, + "afterPresent": true, + "before": "Mark the invite as cancelled so it doesn't show up on the list of pending invites\n\n\n", + "after": "Mark the invite as cancelled so it doesn't show up on the list of pending invites\n\n\n", + "id": "hub-711cffa504e9", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1invites~1{id}/delete/description", + "destinationPointer": "/paths/~1v2~1invites~1{id}/delete/description" + }, + { + "pointer": "/paths/~1v2~1invites~1{id}~1resend/patch/description", + "beforePresent": true, + "afterPresent": true, + "before": "Resend a pending invite to the user, any org owner can resend an invite\n\n\n", + "after": "Resend a pending invite to the user, any org owner can resend an invite\n\n\n", + "id": "hub-d7aacf942e38", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1invites~1{id}~1resend/patch/description", + "destinationPointer": "/paths/~1v2~1invites~1{id}~1resend/patch/description" + }, + { + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "Returns a list of repositories within the specified namespace (organization or user).\n\nPublic repositories are accessible to everyone, while private repositories require appropriate authentication and permissions.\n\n\n\n**OAT listing behavior**: an OAT with the `scope-repository-list` scope sees all repositories including private ones. An OAT without that scope only sees public repositories. This filtering is silent: the response is a normal `200` with no indication that private repositories were withheld.\n", + "after": "Returns a list of repositories within the specified namespace (organization or user).\n\nPublic repositories are accessible to everyone, while private repositories require appropriate authentication and permissions.\n\n\n\n**OAT listing behavior**: an OAT with the `scope-repository-list` scope sees all repositories including private ones. An OAT without that scope only sees public repositories. This filtering is silent: the response is a normal `200` with no indication that private repositories were withheld.\n", + "id": "hub-8bce03fbb9e7", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/description", + "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/description" + }, + { + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/description", + "beforePresent": true, + "afterPresent": true, + "before": "Creates a new repository within the specified namespace. The repository will be created\nwith the provided metadata including name, description, and privacy settings.\n\n\n", + "after": "Creates a new repository within the specified namespace. The repository will be created\nwith the provided metadata including name, description, and privacy settings.\n\n\n", + "id": "hub-df5fa500573c", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/description", + "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/description" + }, + { + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "Returns a repository within the specified namespace (organization or user).\n\nPublic repositories are accessible to everyone, while private repositories require appropriate authentication and permissions.\n\n\n", + "after": "Returns a repository within the specified namespace (organization or user).\n\nPublic repositories are accessible to everyone, while private repositories require appropriate authentication and permissions.\n\n\n", + "id": "hub-c814561d26d7", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/description", + "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/description" + }, + { + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/description", + "beforePresent": true, + "afterPresent": true, + "before": "Check a repository within the specified namespace (organization or user).\n\nPublic repositories are accessible to everyone, while private repositories require appropriate authentication and permissions.\n\n\n", + "after": "Check a repository within the specified namespace (organization or user).\n\nPublic repositories are accessible to everyone, while private repositories require appropriate authentication and permissions.\n\n\n", + "id": "hub-758e684d0c26", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/description", + "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/description" + }, + { + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/description", + "beforePresent": true, + "afterPresent": true, + "before": "Updates the immutable tags configuration for this repository.\n\n**Only users with administrative privileges for the repository can modify these settings.**\n\n\n", + "after": "Updates the immutable tags configuration for this repository.\n\n**Only users with administrative privileges for the repository can modify these settings.**\n\n\n", + "id": "hub-4b6236e32079", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/description", + "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/description" + }, + { + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/description", + "beforePresent": true, + "afterPresent": true, + "before": "Validates the immutable tags regex passed in the request body and returns a list of tags matching it in this repository.\n\n**Only users with administrative privileges for the repository can call this endpoint.**\n\n\n", + "after": "Validates the immutable tags regex passed in the request body and returns a list of tags matching it in this repository.\n\n**Only users with administrative privileges for the repository can call this endpoint.**\n\n\n", + "id": "hub-cddc6551a6fe", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/description", + "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/description" + }, + { + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "Returns the list of tags for the specified repository.\n\n\n", + "after": "Returns the list of tags for the specified repository.\n\n\n", + "id": "hub-7c829bae5c5b", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/description", + "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/description" + }, + { + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/description", + "beforePresent": true, + "afterPresent": true, + "before": "Checks whether the repository has any tags.\n\n\n", + "after": "Checks whether the repository has any tags.\n\n\n", + "id": "hub-ae31a1fd6c15", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/description", + "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/description" + }, + { + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "Returns details for a specific tag in the specified repository.\n\n\n", + "after": "Returns details for a specific tag in the specified repository.\n\n\n", + "id": "hub-1711bdf8c01b", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/description", + "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/description" + }, + { + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/description", + "beforePresent": true, + "afterPresent": true, + "before": "Checks whether the specified tag exists in the repository.\n\n\n", + "after": "Checks whether the specified tag exists in the repository.\n\n\n", + "id": "hub-ca9f4292d078", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/description", + "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "\n", + "id": "hub-19258b60eb71", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/description", + "beforePresent": true, + "afterPresent": true, + "before": "Create a new group within an organization.\n\n\n", + "after": "Create a new group within an organization.\n\n\n", + "id": "hub-491d43e3b974", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "\n", + "id": "hub-483cbb8b69e9", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "\n", + "id": "hub-9f8a2c14c2e4", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "\n", + "id": "hub-5d12989466a8", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "\n", + "id": "hub-88797cb50eee", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "List the members (users) that are in a group.\nIf user is owner of the org or has otherwise elevated permissions, they can search by email and the result will also contain emails.\n\n\n", + "after": "List the members (users) that are in a group.\nIf user is owner of the org or has otherwise elevated permissions, they can search by email and the result will also contain emails.\n\n\n", + "id": "hub-a969dea6c391", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "\n", + "id": "hub-2392b3255468", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "\n", + "id": "hub-fb34d26a19a7", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "Return all pending invites for a given org, only team owners can call this endpoint\n\n\n", + "after": "Return all pending invites for a given org, only team owners can call this endpoint\n\n\n", + "id": "hub-9e69ed836422", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "Returns a list of members for an organization.\n\n_The following fields are only visible to orgs with insights enabled._\n\n- `last_logged_in_at`\n- `last_seen_at`\n- `last_desktop_version`\n\nTo make visible, please see [View Insights for organization users](https://docs.docker.com/admin/insights/#view-insights-for-organization-users).\n\n\n", + "after": "Returns a list of members for an organization.\n\n_The following fields are only visible to orgs with insights enabled._\n\n- `last_logged_in_at`\n- `last_seen_at`\n- `last_desktop_version`\n\nTo make visible, please see [View Insights for organization users](https://docs.docker.com/admin/insights/#view-insights-for-organization-users).\n\n\n", + "id": "hub-a8f046f807cc", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "Export members of an organization as a CSV\n\n\n", + "after": "Export members of an organization as a CSV\n\n\n", + "id": "hub-ef7a52226e0d", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/description", + "beforePresent": true, + "afterPresent": true, + "before": "Removes the member from the org, ie. all groups in the org, unless they're the last owner\n\n\n", + "after": "Removes the member from the org, ie. all groups in the org, unless they're the last owner\n\n\n", + "id": "hub-a63ee0d1e822", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/description", + "beforePresent": true, + "afterPresent": true, + "before": "Updates the role of a member in the organization.\n***Only users in the \"owners\" group of the organization can use this endpoint.***\n\n\n", + "after": "Updates the role of a member in the organization.\n***Only users in the \"owners\" group of the organization can use this endpoint.***\n\n\n", + "id": "hub-08bc49612a6e", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/description" + }, + { + "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/description", + "beforePresent": true, + "afterPresent": true, + "before": "Assigns an organization group (team) to a repository with a specified permission level.\n\n\n", + "after": "Assigns an organization group (team) to a repository with a specified permission level.\n\n\n", + "id": "hub-078a1d5f4794", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/description", + "destinationPointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/description" + }, + { + "pointer": "/paths/~1v2~1users~1login/post/description", + "beforePresent": true, + "afterPresent": true, + "before": "Creates and returns a bearer token in JWT format that you can use to authenticate with Docker Hub APIs.\n\nThe returned token is used in the HTTP Authorization header like `Authorization: Bearer {TOKEN}`.\n\n_**As of September 16, 2024, this route requires a personal access token (PAT) instead of a password if your organization has SSO enforced.**_\n\n
\n Deprecated: Use [Create access token] instead.\n
\n", + "after": "Creates and returns a bearer token in JWT format that you can use to authenticate with Docker Hub APIs.\n\nThe returned token is used in the HTTP Authorization header like `Authorization: Bearer {TOKEN}`.\n\n_**As of September 16, 2024, this route requires a personal access token (PAT) instead of a password if your organization has SSO enforced.**_\n\n\n Deprecated: Use [Create access token](#tag/authentication-api/operation/AuthCreateAccessToken) instead.\n\n", + "id": "hub-d071d281f6bc", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1users~1login/post/description", + "destinationPointer": "/paths/~1v2~1users~1login/post/description" + }, + { + "pointer": "/tags", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "name": "changelog", + "description": "See the [Changelog](/reference/api/hub/changelog) for a summary of changes across Docker Hub API versions.\n", + "summary": "Changelog", + "kind": "info" + }, + { + "name": "resources", + "description": "The following resources are available to interact with the documented API:\n- [Docker Hub CLI tool](https://github.com/docker/hub-tool#readme) (currently experimental)\n", + "summary": "Resources", + "kind": "info" + }, + { + "name": "rate-limiting", + "description": "The Docker Hub API is limited on the amount of requests you can perform per minute against it.\n\nIf you haven't hit the limit, each request to the API will return the following headers in the response.\n\n- `X-RateLimit-Limit` - The limit of requests per minute.\n- `X-RateLimit-Remaining` - The remaining amount of calls within the limit period.\n- `X-RateLimit-Reset` - The unix timestamp of when the remaining resets.\n\nIf you have hit the limit, you will receive a response status of `429` and the `Retry-After` header in the response.\n\nThe [`Retry-After` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After) specifies the number of seconds to wait until you can call the API again.\n\n**Note**: These rate limits are separate from anti-abuse and Docker Hub download, or pull rate limiting.\nTo learn more about Docker Hub pull rate limiting, see [Usage and limits](https://docs.docker.com/docker-hub/usage/).\n", + "summary": "Rate Limiting", + "kind": "info" + }, + { + "name": "authentication", + "description": "Most Docker Hub API endpoints require you to authenticate using your Docker credentials before using them.\n\nAdditionally, similar to the Docker Hub UI features, API endpoint responses may vary depending on your subscription (Personal, Pro, or Team) and your account's permissions.\n\nTo learn more about the features available in each subscription and to upgrade your existing subscription, see [Docker Pricing](https://www.docker.com/pricing?ref=Docs&refAction=DocsApiHub).\n\n# Types\n\nThe Docker Hub API supports the following authentication types.\n\nYou must use each authentication type with the [Create access token](#tag/authentication-api/operation/AuthCreateAccessToken) route to obtain a bearer token.\n\n## Password\nUsing a username and password is the most powerful, yet least secure way \nto authenticate with Docker as a user. It allows access to resources \nfor the user without scopes. \n\n_In general, it is recommended to use a personal access token (PAT) instead._\n\n_**The password authentication type is not available if your organization has SSO enforced.**_\n\n## Personal Access Token (PAT)\nUsing a username and PAT is the most secure way to authenticate with \nDocker as a user. PATs are scoped to specific resources and scopes.\n\nCurrently, a PAT is a more secure password due to limited functionality. \nIn the future, we may add fine-grained access like organization \naccess tokens for enhanced usage and security.\n\n## Organization Access Token (OAT)\nOrganization access tokens are scoped to specific resources and scopes \nin an organization. They are managed by organization owners. \n\nThese tokens are meant for automation and are not meant to be used by \nusers.\n\n# Labels\n\nThese labels will show up on routes in this reference that allow for use of bearer \ntokens issued from them.\n\n\n\n", + "summary": "Authentication", + "kind": "info" + }, + { + "name": "authentication-api", + "description": "The authentication endpoints allow you to authenticate with Docker Hub APIs.\n\nFor more information, see [Authentication](#tag/authentication).\n", + "summary": "Authentication", + "kind": "nav" + }, + { + "name": "access-tokens", + "description": "The Personal Access Token endpoints lets you manage personal access tokens. For more information, see [Access Tokens](https://docs.docker.com/security/access-tokens/personal-access-tokens/).\n\nYou can use a personal access token instead of a password in the [Docker CLI](https://docs.docker.com/engine/reference/commandline/cli/) or in the [Create an authentication token](#operation/PostUsersLogin) route to obtain a bearer token.\n\n### Scopes\n\nFor each scope grouping (in this case \"repo\"), you only need to define 1 scope as any lower scopes are assumed.\nFor example: If you define `repo:write`, the API assumes the scope of both `repo:read` *and* `repo:public_read` as well.\nIf you were to define both `repo:write` *and* `repo:read`, then `repo:read` is assumed by `repo:write` and ignored.\n\n***Treat your personal access token like your password and keep it secret. You cannot retrieve your token after it is generated.***\n", + "summary": "Personal Access Tokens", + "kind": "nav" + }, + { + "name": "audit-logs", + "description": "The Audit Logs API endpoints allow you to query audit log events across a namespace.\n\nFor more information, see [Audit Logs](https://docs.docker.com/admin/activity-logs/).\n", + "summary": "Audit Logs", + "kind": "nav" + }, + { + "name": "org-settings", + "description": "The Org Settings API endpoints allow you to manage your organization's settings.\n", + "summary": "Org Settings", + "kind": "nav" + }, + { + "name": "repositories", + "description": "The repository endpoints allow you to access your repository's tags.\n", + "summary": "Repositories", + "kind": "nav" + }, + { + "name": "orgs", + "x-audience": "public", + "description": "The organization endpoints allow you to interact with and manage your organizations.\n\nFor more information, see [Organization administration overview](https://docs.docker.com/admin/organization/).\n", + "summary": "Organizations", + "kind": "nav" + }, + { + "name": "groups", + "x-audience": "public", + "description": "The groups endpoints allow you to manage your organization's teams and their members.\n\nFor more information, see [Create and manage a team](https://docs.docker.com/admin/organization/manage/manage-a-team/).\n", + "summary": "Groups (Teams)", + "kind": "nav" + }, + { + "name": "invites", + "x-audience": "public", + "description": "The invites endpoints allow you to manage invites for users to join your Docker organization.\n\nFor more information, see [Invite members](https://docs.docker.com/admin/organization/manage/members/#invite-members).\n", + "summary": "Invites", + "kind": "nav" + }, + { + "name": "scim", + "x-audience": "public", + "description": "SCIM is a provisioning system that lets you manage users within your identity provider (IdP).\n\nFor more information, see [System for Cross-domain Identity management](https://docs.docker.com/security/for-admins/provisioning/scim/).\n", + "summary": "SCIM", + "kind": "nav" + }, + { + "name": "org-access-tokens", + "x-audience": "public", + "description": "The organization access token endpoints allow you to manage organization access tokens (OATs). See [Organization access tokens](https://docs.docker.com/security/for-admins/access-tokens/) for more information.\n\nOATs only authenticate requests to the modern namespace-scoped routes under `/v2/namespaces/{namespace}/repositories/`. Legacy repository paths are OAT unsupported, regardless of the token's scopes, and reject every OAT with `403 token issued from organization access token is not allowed`:\n\n- `GET /v2/repositories/{namespace}/{repository}` — use [Get repository](#tag/repositories/operation/GetRepository) instead.\n- `GET /v2/repositories/{namespace}` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n- `GET /v2/users/{username}/repositories` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n", + "summary": "Organization Access Tokens", + "kind": "nav" + } + ], + "after": [ + { + "name": "changelog", + "description": "See the [Changelog](/reference/api/hub/changelog) for a summary of changes across Docker Hub API versions.\n", + "summary": "Changelog", + "kind": "info" + }, + { + "name": "resources", + "description": "The following resources are available to interact with the documented API:\n- [Docker Hub CLI tool](https://github.com/docker/hub-tool#readme) (currently experimental)\n", + "summary": "Resources", + "kind": "info" + }, + { + "name": "rate-limiting", + "description": "The Docker Hub API is limited on the amount of requests you can perform per minute against it.\n\nIf you haven't hit the limit, each request to the API will return the following headers in the response.\n\n- `X-RateLimit-Limit` - The limit of requests per minute.\n- `X-RateLimit-Remaining` - The remaining amount of calls within the limit period.\n- `X-RateLimit-Reset` - The unix timestamp of when the remaining resets.\n\nIf you have hit the limit, you will receive a response status of `429` and the `Retry-After` header in the response.\n\nThe [`Retry-After` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After) specifies the number of seconds to wait until you can call the API again.\n\n**Note**: These rate limits are separate from anti-abuse and Docker Hub download, or pull rate limiting.\nTo learn more about Docker Hub pull rate limiting, see [Usage and limits](https://docs.docker.com/docker-hub/usage/).\n", + "summary": "Rate Limiting", + "kind": "info" + }, + { + "name": "authentication", + "description": "Most Docker Hub API endpoints require you to authenticate using your Docker credentials before using them.\n\nAdditionally, similar to the Docker Hub UI features, API endpoint responses may vary depending on your subscription (Personal, Pro, or Team) and your account's permissions.\n\nTo learn more about the features available in each subscription and to upgrade your existing subscription, see [Docker Pricing](https://www.docker.com/pricing?ref=Docs&refAction=DocsApiHub).\n\n# Types\n\nThe Docker Hub API supports the following authentication types.\n\nYou must use each authentication type with the [Create access token](#tag/authentication-api/operation/AuthCreateAccessToken) route to obtain a bearer token.\n\n## Password\nUsing a username and password is the most powerful, yet least secure way \nto authenticate with Docker as a user. It allows access to resources \nfor the user without scopes. \n\n_In general, it is recommended to use a personal access token (PAT) instead._\n\n_**The password authentication type is not available if your organization has SSO enforced.**_\n\n## Personal Access Token (PAT)\nUsing a username and PAT is the most secure way to authenticate with \nDocker as a user. PATs are scoped to specific resources and scopes.\n\nCurrently, a PAT is a more secure password due to limited functionality. \nIn the future, we may add fine-grained access like organization \naccess tokens for enhanced usage and security.\n\n## Organization Access Token (OAT)\nOrganization access tokens are scoped to specific resources and scopes \nin an organization. They are managed by organization owners. \n\nThese tokens are meant for automation and are not meant to be used by \nusers.\n\n# Labels\n\nThese labels will show up on routes in this reference that allow for use of bearer \ntokens issued from them.\n\n\n\n", + "summary": "Authentication", + "kind": "info" + }, + { + "name": "authentication-api", + "description": "The authentication endpoints allow you to authenticate with Docker Hub APIs.\n\nFor more information, see [Authentication](#tag/authentication).\n", + "summary": "Authentication", + "kind": "nav" + }, + { + "name": "access-tokens", + "description": "The Personal Access Token endpoints lets you manage personal access tokens. For more information, see [Access Tokens](https://docs.docker.com/security/access-tokens/personal-access-tokens/).\n\nYou can use a personal access token instead of a password in the [Docker CLI](https://docs.docker.com/engine/reference/commandline/cli/) or in the [Create an authentication token](#operation/PostUsersLogin) route to obtain a bearer token.\n\n### Scopes\n\nFor each scope grouping (in this case \"repo\"), you only need to define 1 scope as any lower scopes are assumed.\nFor example: If you define `repo:write`, the API assumes the scope of both `repo:read` *and* `repo:public_read` as well.\nIf you were to define both `repo:write` *and* `repo:read`, then `repo:read` is assumed by `repo:write` and ignored.\n\n***Treat your personal access token like your password and keep it secret. You cannot retrieve your token after it is generated.***\n", + "summary": "Personal Access Tokens", + "kind": "nav" + }, + { + "name": "audit-logs", + "description": "The Audit Logs API endpoints allow you to query audit log events across a namespace.\n\nFor more information, see [Audit Logs](https://docs.docker.com/admin/activity-logs/).\n", + "summary": "Audit Logs", + "kind": "nav" + }, + { + "name": "org-settings", + "description": "The Org Settings API endpoints allow you to manage your organization's settings.\n", + "summary": "Org Settings", + "kind": "nav" + }, + { + "name": "repositories", + "description": "The repository endpoints allow you to access your repository's tags.\n", + "summary": "Repositories", + "kind": "nav" + }, + { + "name": "orgs", + "x-audience": "public", + "description": "The organization endpoints allow you to interact with and manage your organizations.\n\nFor more information, see [Organization administration overview](https://docs.docker.com/admin/organization/).\n", + "summary": "Organizations", + "kind": "nav" + }, + { + "name": "groups", + "x-audience": "public", + "description": "The groups endpoints allow you to manage your organization's teams and their members.\n\nFor more information, see [Create and manage a team](https://docs.docker.com/admin/organization/manage/manage-a-team/).\n", + "summary": "Groups (Teams)", + "kind": "nav" + }, + { + "name": "invites", + "x-audience": "public", + "description": "The invites endpoints allow you to manage invites for users to join your Docker organization.\n\nFor more information, see [Invite members](https://docs.docker.com/admin/organization/manage/members/#invite-members).\n", + "summary": "Invites", + "kind": "nav" + }, + { + "name": "scim", + "x-audience": "public", + "description": "SCIM is a provisioning system that lets you manage users within your identity provider (IdP).\n\nFor more information, see [System for Cross-domain Identity management](https://docs.docker.com/security/for-admins/provisioning/scim/).\n", + "summary": "SCIM", + "kind": "nav" + }, + { + "name": "org-access-tokens", + "x-audience": "public", + "description": "The organization access token endpoints allow you to manage organization access tokens (OATs). See [Organization access tokens](https://docs.docker.com/security/for-admins/access-tokens/) for more information.\n\nOATs only authenticate requests to the modern namespace-scoped routes under `/v2/namespaces/{namespace}/repositories/`. Legacy repository paths are OAT unsupported, regardless of the token's scopes, and reject every OAT with `403 token issued from organization access token is not allowed`:\n\n- `GET /v2/repositories/{namespace}/{repository}` — use [Get repository](#tag/repositories/operation/GetRepository) instead.\n- `GET /v2/repositories/{namespace}` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n- `GET /v2/users/{username}/repositories` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n", + "summary": "Organization Access Tokens", + "kind": "nav" + } + ], + "id": "hub-8c67a3d8bd5a", + "stage": "portable-descriptions", + "classification": "editorial completion", + "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", + "evidence": "Docker profile S12", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/tags", + "destinationPointer": "/tags" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "Get groups of an organization.", + "id": "hub-e81c4f02da4d", + "stage": "empty-description-completion", + "classification": "editorial completion", + "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", + "evidence": "Existing operation summary", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "Delete an organization group.", + "id": "hub-90d2bf1f1840", + "stage": "empty-description-completion", + "classification": "editorial completion", + "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", + "evidence": "Existing operation summary", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "Get a group of an organization.", + "id": "hub-3984c74c1439", + "stage": "empty-description-completion", + "classification": "editorial completion", + "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", + "evidence": "Existing operation summary", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "Update some details for an organization group.", + "id": "hub-14585f035f98", + "stage": "empty-description-completion", + "classification": "editorial completion", + "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", + "evidence": "Existing operation summary", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "Update the details for an organization group.", + "id": "hub-2d209be6dab1", + "stage": "empty-description-completion", + "classification": "editorial completion", + "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", + "evidence": "Existing operation summary", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "Add a member to a group.", + "id": "hub-428a2404142d", + "stage": "empty-description-completion", + "classification": "editorial completion", + "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", + "evidence": "Existing operation summary", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/description" + }, + { + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/description", + "beforePresent": true, + "afterPresent": true, + "before": "\n", + "after": "Remove a user from a group.", + "id": "hub-50aea6b744b0", + "stage": "empty-description-completion", + "classification": "editorial completion", + "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", + "evidence": "Existing operation summary", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/description", + "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/description" + }, + { + "pointer": "/components/schemas/team_repo/allOf", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "$ref": "#/components/responses/team_repo" + } + ], + "after": [ + { + "$ref": "#/components/schemas/repository_info" + } + ], + "id": "hub-f335bd60404f", + "stage": "hub-team-schema-assumption", + "classification": "provisional assumption", + "rationale": "Replace the missing response reference with the existing repository schema, the likely base of a team repository. Product owner must verify returned fields.", + "evidence": "components.schemas.team_repo and existing repository response definition", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/components/schemas/team_repo/allOf", + "destinationPointer": "/components/schemas/team_repo/allOf" + }, + { + "pointer": "/components/securitySchemes/scimToken", + "beforePresent": false, + "afterPresent": true, + "after": { + "type": "http", + "scheme": "bearer", + "description": "Use the SCIM provisioning token configured for the organization." + }, + "id": "hub-9809789ee63e", + "stage": "scim-auth-context", + "classification": "evidence-backed correction", + "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", + "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/components/securitySchemes/scimToken" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/security", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "bearerSCIMAuth": [] + } + ], + "after": [ + { + "scimToken": [] + } + ], + "id": "hub-8f39ee63e16c", + "stage": "scim-auth-context", + "classification": "evidence-backed correction", + "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", + "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/security", + "destinationPointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/security" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/security", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "bearerSCIMAuth": [] + } + ], + "after": [ + { + "scimToken": [] + } + ], + "id": "hub-03dc3581d4c0", + "stage": "scim-auth-context", + "classification": "evidence-backed correction", + "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", + "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/security", + "destinationPointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/security" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1Schemas/get/security", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "bearerSCIMAuth": [] + } + ], + "after": [ + { + "scimToken": [] + } + ], + "id": "hub-5a6d51f54bbf", + "stage": "scim-auth-context", + "classification": "evidence-backed correction", + "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", + "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1scim~12.0~1Schemas/get/security", + "destinationPointer": "/paths/~1v2~1scim~12.0~1Schemas/get/security" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/security", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "bearerSCIMAuth": [] + } + ], + "after": [ + { + "scimToken": [] + } + ], + "id": "hub-e2bd8446c1d5", + "stage": "scim-auth-context", + "classification": "evidence-backed correction", + "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", + "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/security", + "destinationPointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/security" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/security", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "bearerSCIMAuth": [] + } + ], + "after": [ + { + "scimToken": [] + } + ], + "id": "hub-4b8fdeb71056", + "stage": "scim-auth-context", + "classification": "evidence-backed correction", + "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", + "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/security", + "destinationPointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/security" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1Users/get/security", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "bearerSCIMAuth": [] + } + ], + "after": [ + { + "scimToken": [] + } + ], + "id": "hub-ecf88ecedb9e", + "stage": "scim-auth-context", + "classification": "evidence-backed correction", + "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", + "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1scim~12.0~1Users/get/security", + "destinationPointer": "/paths/~1v2~1scim~12.0~1Users/get/security" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1Users/post/security", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "bearerSCIMAuth": [] + } + ], + "after": [ + { + "scimToken": [] + } + ], + "id": "hub-a24fdb1bdff4", + "stage": "scim-auth-context", + "classification": "evidence-backed correction", + "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", + "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1scim~12.0~1Users/post/security", + "destinationPointer": "/paths/~1v2~1scim~12.0~1Users/post/security" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/security", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "bearerSCIMAuth": [] + } + ], + "after": [ + { + "scimToken": [] + } + ], + "id": "hub-3e8afbee54cd", + "stage": "scim-auth-context", + "classification": "evidence-backed correction", + "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", + "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/security", + "destinationPointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/security" + }, + { + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/security", + "beforePresent": true, + "afterPresent": true, + "before": [ + { + "bearerSCIMAuth": [] + } + ], + "after": [ + { + "scimToken": [] + } + ], + "id": "hub-56082273dc18", + "stage": "scim-auth-context", + "classification": "evidence-backed correction", + "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", + "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/security", + "destinationPointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/security" + }, + { + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/200/content", + "beforePresent": true, + "afterPresent": false, + "before": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/repository_info" + }, + "example": { + "name": "my-app", + "namespace": "myorganization", + "repository_type": "image", + "status": 1, + "status_description": "Active", + "description": "A sample application repository", + "is_private": false, + "is_automated": false, + "star_count": 0, + "pull_count": 0, + "last_updated": "2025-01-20T10:30:00Z", + "date_registered": "2025-01-20T10:30:00Z", + "collaborator_count": 0, + "hub_user": "myorganization", + "has_starred": false, + "full_description": "This is a comprehensive description of my application repository that contains additional details about the project.", + "media_types": [], + "content_types": [], + "categories": [], + "immutable_tags_settings": { + "enabled": false, + "rules": [] + }, + "storage_size": null, + "source": null + } + } + }, + "id": "hub-2284c2bd0c92", + "stage": "head-response-bodies", + "classification": "evidence-backed correction", + "rationale": "HEAD responses transfer headers without a response body. Preserve headers and status codes; remove declared content from HEAD responses.", + "evidence": "RFC 9110 section 9.3.2", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/200/content", + "destinationPointer": null + }, + { + "pointer": "/security", + "beforePresent": false, + "afterPresent": true, + "after": [], + "id": "hub-2b9d4937db9a", + "stage": "explicit-root-security", + "classification": "editorial completion", + "rationale": "Make the existing absence of inherited HTTP authentication explicit. Local socket permissions remain connection metadata.", + "evidence": "OpenAPI root security inheritance; existing source operation policies", + "owner": "docker/docs (product authority to confirm)", + "sourcePointer": null, + "destinationPointer": "/security" + } + ] +} diff --git a/hack/api-docs/adoption/hub.patch b/hack/api-docs/adoption/hub.patch new file mode 100644 index 000000000000..b94f13a6a2dd --- /dev/null +++ b/hack/api-docs/adoption/hub.patch @@ -0,0 +1,2056 @@ +--- original/hub.yaml ++++ converted/hub.yaml +@@ -1,6 +1,4 @@ +-# yaml-language-server: $schema=https://raw.githubusercontent.com/OAI/OpenAPI-Specification/refs/heads/main/schemas/v3.0/schema.yaml +- +-openapi: 3.0.3 ++openapi: 3.2.0 + info: + title: Docker HUB API + version: 2-beta +@@ -21,16 +19,17 @@ + url: https://hub.docker.com + tags: + - name: changelog +- x-displayName: Changelog + description: | + See the [Changelog](/reference/api/hub/changelog) for a summary of changes across Docker Hub API versions. ++ summary: Changelog ++ kind: info + - name: resources +- x-displayName: Resources + description: | + The following resources are available to interact with the documented API: + - [Docker Hub CLI tool](https://github.com/docker/hub-tool#readme) (currently experimental) ++ summary: Resources ++ kind: info + - name: rate-limiting +- x-displayName: Rate Limiting + description: | + The Docker Hub API is limited on the amount of requests you can perform per minute against it. + +@@ -46,9 +45,10 @@ + + **Note**: These rate limits are separate from anti-abuse and Docker Hub download, or pull rate limiting. + To learn more about Docker Hub pull rate limiting, see [Usage and limits](https://docs.docker.com/docker-hub/usage/). ++ summary: Rate Limiting ++ kind: info + - name: authentication +- x-displayName: Authentication +- description: | ++ description: |+ + Most Docker Hub API endpoints require you to authenticate using your Docker credentials before using them. + + Additionally, similar to the Docker Hub UI features, API endpoint responses may vary depending on your subscription (Personal, Pro, or Team) and your account's permissions. +@@ -90,16 +90,18 @@ + These labels will show up on routes in this reference that allow for use of bearer + tokens issued from them. + +- +- ++ ++ ++ summary: Authentication ++ kind: info + - name: authentication-api +- x-displayName: Authentication + description: | + The authentication endpoints allow you to authenticate with Docker Hub APIs. + + For more information, see [Authentication](#tag/authentication). ++ summary: Authentication ++ kind: nav + - name: access-tokens +- x-displayName: Personal Access Tokens + description: | + The Personal Access Token endpoints lets you manage personal access tokens. For more information, see [Access Tokens](https://docs.docker.com/security/access-tokens/personal-access-tokens/). + +@@ -112,50 +114,58 @@ + If you were to define both `repo:write` *and* `repo:read`, then `repo:read` is assumed by `repo:write` and ignored. + + ***Treat your personal access token like your password and keep it secret. You cannot retrieve your token after it is generated.*** ++ summary: Personal Access Tokens ++ kind: nav + - name: audit-logs +- x-displayName: Audit Logs + description: | + The Audit Logs API endpoints allow you to query audit log events across a namespace. + + For more information, see [Audit Logs](https://docs.docker.com/admin/activity-logs/). ++ summary: Audit Logs ++ kind: nav + - name: org-settings +- x-displayName: Org Settings + description: | + The Org Settings API endpoints allow you to manage your organization's settings. ++ summary: Org Settings ++ kind: nav + - name: repositories +- x-displayName: Repositories + description: | + The repository endpoints allow you to access your repository's tags. ++ summary: Repositories ++ kind: nav + - name: orgs +- x-displayName: Organizations + x-audience: public + description: | + The organization endpoints allow you to interact with and manage your organizations. + + For more information, see [Organization administration overview](https://docs.docker.com/admin/organization/). ++ summary: Organizations ++ kind: nav + - name: groups +- x-displayName: Groups (Teams) + x-audience: public + description: | + The groups endpoints allow you to manage your organization's teams and their members. + + For more information, see [Create and manage a team](https://docs.docker.com/admin/organization/manage/manage-a-team/). ++ summary: Groups (Teams) ++ kind: nav + - name: invites +- x-displayName: Invites + x-audience: public + description: | + The invites endpoints allow you to manage invites for users to join your Docker organization. + + For more information, see [Invite members](https://docs.docker.com/admin/organization/manage/members/#invite-members). ++ summary: Invites ++ kind: nav + - name: scim +- x-displayName: SCIM + x-audience: public + description: | + SCIM is a provisioning system that lets you manage users within your identity provider (IdP). + + For more information, see [System for Cross-domain Identity management](https://docs.docker.com/security/for-admins/provisioning/scim/). ++ summary: SCIM ++ kind: nav + - name: org-access-tokens +- x-displayName: Organization Access Tokens + x-audience: public + description: | + The organization access token endpoints allow you to manage organization access tokens (OATs). See [Organization access tokens](https://docs.docker.com/security/for-admins/access-tokens/) for more information. +@@ -165,6 +175,8 @@ + - `GET /v2/repositories/{namespace}/{repository}` — use [Get repository](#tag/repositories/operation/GetRepository) instead. + - `GET /v2/repositories/{namespace}` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead. + - `GET /v2/users/{username}/repositories` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead. ++ summary: Organization Access Tokens ++ kind: nav + paths: + /v2/users/login: + post: +@@ -174,16 +186,16 @@ + operationId: PostUsersLogin + security: [] + deprecated: true +- description: | ++ description: |+ + Creates and returns a bearer token in JWT format that you can use to authenticate with Docker Hub APIs. + + The returned token is used in the HTTP Authorization header like `Authorization: Bearer {TOKEN}`. + + _**As of September 16, 2024, this route requires a personal access token (PAT) instead of a password if your organization has SSO enforced.**_ + +-
+- Deprecated: Use [Create access token] instead. +-
++ ++ Deprecated: Use [Create access token](#tag/authentication-api/operation/AuthCreateAccessToken) instead. ++ + requestBody: + content: + application/json: +@@ -310,6 +322,7 @@ + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthorized" ++ operationId: postV2AccessTokens + get: + summary: List personal access tokens + description: Returns a paginated list of personal access tokens. +@@ -339,6 +352,7 @@ + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthorized" ++ operationId: getV2AccessTokens + /v2/access-tokens/{uuid}: + parameters: + - in: path +@@ -371,6 +385,7 @@ + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthorized" ++ operationId: patchV2AccessTokensByUuid + get: + summary: Get personal access token + description: Returns a personal access token by UUID. +@@ -395,6 +410,7 @@ + $ref: "#/components/responses/Unauthorized" + "404": + $ref: "#/components/responses/NotFound" ++ operationId: getV2AccessTokensByUuid + delete: + summary: Delete personal access token + description: | +@@ -410,13 +426,14 @@ + $ref: "#/components/responses/Unauthorized" + "404": + $ref: "#/components/responses/NotFound" ++ operationId: deleteV2AccessTokensByUuid + /v2/auditlogs/{account}/actions: + get: + summary: List audit log actions +- description: | ++ description: |+ + List audit log actions for a namespace to be used as a filter for querying audit log events. + +- ++ + operationId: AuditLogs_ListAuditActions + security: + - bearerAuth: [] +@@ -707,10 +724,10 @@ + /v2/auditlogs/{account}: + get: + summary: List audit log events +- description: | ++ description: |+ + List audit log events for a given namespace. + +- ++ + operationId: AuditLogs_ListAuditLogs + security: + - bearerAuth: [] +@@ -732,7 +749,7 @@ + data: + digest: sha256:c1ae9c435032a276f80220c7d9b40f76266bbe79243d34f9cda30b76fe114dfa + tag: latest +- timestamp: "2021-02-19T01:34:35Z" ++ timestamp: 2021-02-19T01:34:35Z + action_description: | + pushed the tag latest with the digest sha256:c1ae9c435032a to the repository docker/example + - account: docker +@@ -742,12 +759,12 @@ + data: + lease_id: l_3EgPuRCjtUqT279CFPOQWcO8zOf + resource_type: run_4cpu_8mem +- started_at: "2026-06-04T18:24:21Z" +- updated_at: "2026-06-04T18:36:43Z" ++ started_at: 2026-06-04T18:24:21Z ++ updated_at: 2026-06-04T18:36:43Z + org_id: b908ca6e-b9a9-4a53-a9a5-6bec96f72432 + user_id: ecae6747-e42c-43cb-925d-cfce1ab32b02 +- timestamp: "2026-06-04T18:36:43Z" +- action_description: "offload lease 'l_3EgPuRCjtUqT279CFPOQWcO8zOf' ended, ran for '12m22s'" ++ timestamp: 2026-06-04T18:36:43Z ++ action_description: offload lease 'l_3EgPuRCjtUqT279CFPOQWcO8zOf' ended, ran for '12m22s' + "429": + description: "" + content: +@@ -858,6 +875,7 @@ + $ref: "#/components/responses/Forbidden" + "404": + $ref: "#/components/responses/NotFound" ++ operationId: getV2OrgsByNameSettings + put: + summary: Update organization settings + description: | +@@ -900,6 +918,7 @@ + $ref: "#/components/responses/Forbidden" + "404": + $ref: "#/components/responses/NotFound" ++ operationId: putV2OrgsByNameSettings + /v2/orgs/{name}/access-tokens: + post: + summary: Create access token +@@ -930,6 +949,7 @@ + $ref: "#/components/responses/Forbidden" + "404": + $ref: "#/components/responses/NotFound" ++ operationId: postV2OrgsByNameAccessTokens + get: + summary: List access tokens + description: | +@@ -962,7 +982,7 @@ + $ref: "#/components/responses/Forbidden" + "404": + $ref: "#/components/responses/NotFound" +- ++ operationId: getV2OrgsByNameAccessTokens + /v2/orgs/{org_name}/access-tokens/{access_token_id}: + parameters: + - $ref: "#/components/parameters/org_name" +@@ -972,7 +992,7 @@ + schema: + type: string + description: The ID of the access token to retrieve +- example: "a7a5ef25-8889-43a0-8cc7-f2a94268e861" ++ example: a7a5ef25-8889-43a0-8cc7-f2a94268e861 + get: + summary: Get access token + description: | +@@ -994,6 +1014,7 @@ + $ref: "#/components/responses/Forbidden" + "404": + $ref: "#/components/responses/NotFound" ++ operationId: getV2OrgsByOrgNameAccessTokensByAccessTokenId + patch: + summary: Update access token + description: | +@@ -1021,6 +1042,7 @@ + $ref: "#/components/responses/Forbidden" + "404": + $ref: "#/components/responses/NotFound" ++ operationId: patchV2OrgsByOrgNameAccessTokensByAccessTokenId + delete: + summary: Delete access token + description: | +@@ -1038,6 +1060,7 @@ + $ref: "#/components/responses/Forbidden" + "404": + $ref: "#/components/responses/NotFound" ++ operationId: deleteV2OrgsByOrgNameAccessTokensByAccessTokenId + /v2/namespaces/{namespace}/repositories/{repository}/tags: + parameters: + - $ref: "#/components/parameters/namespace" +@@ -1045,10 +1068,10 @@ + get: + operationId: ListRepositoryTags + summary: List repository tags +- description: | ++ description: |+ + Returns the list of tags for the specified repository. + +- ++ + tags: + - repositories + security: +@@ -1075,10 +1098,10 @@ + $ref: "#/components/responses/NotFound" + head: + summary: Check repository tags +- description: | ++ description: |+ + Checks whether the repository has any tags. + +- ++ + tags: + - repositories + security: +@@ -1090,6 +1113,7 @@ + $ref: "#/components/responses/Forbidden" + "404": + $ref: "#/components/responses/NotFound" ++ operationId: headV2NamespacesByNamespaceRepositoriesByRepositoryTags + /v2/namespaces/{namespace}/repositories/{repository}/tags/{tag}: + parameters: + - $ref: "#/components/parameters/namespace" +@@ -1098,10 +1122,10 @@ + get: + operationId: GetRepositoryTag + summary: Read repository tag +- description: | ++ description: |+ + Returns details for a specific tag in the specified repository. + +- ++ + tags: + - repositories + security: +@@ -1115,10 +1139,10 @@ + $ref: "#/components/responses/NotFound" + head: + summary: Check repository tag +- description: | ++ description: |+ + Checks whether the specified tag exists in the repository. + +- ++ + tags: + - repositories + security: +@@ -1130,19 +1154,20 @@ + $ref: "#/components/responses/Forbidden" + "404": + $ref: "#/components/responses/NotFound" ++ operationId: headV2NamespacesByNamespaceRepositoriesByRepositoryTagsByTag + /v2/namespaces/{namespace}/repositories/{repository}/immutabletags: + parameters: + - $ref: "#/components/parameters/namespace" + - $ref: "#/components/parameters/repository" + patch: + operationId: UpdateRepositoryImmutableTags +- summary: "Update repository immutable tags" +- description: | ++ summary: Update repository immutable tags ++ description: |+ + Updates the immutable tags configuration for this repository. + + **Only users with administrative privileges for the repository can modify these settings.** + +- ++ + tags: + - repositories + security: +@@ -1150,15 +1175,15 @@ + requestBody: + $ref: "#/components/requestBodies/update_repository_immutable_tags_request" + responses: +- 200: ++ "200": + $ref: "#/components/responses/update_repository_immutable_tags_response" +- 400: ++ "400": + $ref: "#/components/responses/bad_request" +- 401: ++ "401": + $ref: "#/components/responses/unauthorized" +- 403: ++ "403": + $ref: "#/components/responses/forbidden" +- 404: ++ "404": + $ref: "#/components/responses/not_found" + /v2/namespaces/{namespace}/repositories/{repository}/immutabletags/verify: + parameters: +@@ -1166,13 +1191,13 @@ + - $ref: "#/components/parameters/repository" + post: + operationId: VerifyRepositoryImmutableTags +- summary: "Verify repository immutable tags" +- description: | ++ summary: Verify repository immutable tags ++ description: |+ + Validates the immutable tags regex passed in the request body and returns a list of tags matching it in this repository. + + **Only users with administrative privileges for the repository can call this endpoint.** + +- ++ + tags: + - repositories + security: +@@ -1180,15 +1205,15 @@ + requestBody: + $ref: "#/components/requestBodies/immutable_tags_verify_request" + responses: +- 200: ++ "200": + $ref: "#/components/responses/immutable_tags_verify_response" +- 400: ++ "400": + $ref: "#/components/responses/bad_request" +- 401: ++ "401": + $ref: "#/components/responses/unauthorized" +- 403: ++ "403": + $ref: "#/components/responses/forbidden" +- 404: ++ "404": + $ref: "#/components/responses/not_found" + /v2/repositories/{namespace}/{repository}/groups: + parameters: +@@ -1196,10 +1221,10 @@ + - $ref: "#/components/parameters/repository" + post: + summary: Assign a group (Team) to a repository for access +- description: | ++ description: |+ + Assigns an organization group (team) to a repository with a specified permission level. + +- ++ + tags: + - repositories + operationId: CreateRepositoryGroup +@@ -1213,7 +1238,7 @@ + $ref: "#/components/schemas/RepositoryGroupCreationRequest" + example: + group_id: 12345 +- permission: "write" ++ permission: write + responses: + "200": + description: Repository group permission created successfully +@@ -1222,8 +1247,8 @@ + schema: + $ref: "#/components/schemas/RepositoryGroup" + example: +- group_name: "developers" +- permission: "write" ++ group_name: developers ++ permission: write + group_id: 12345 + "400": + description: Bad Request - Invalid request parameters +@@ -1248,14 +1273,14 @@ + + Public repositories are accessible to everyone, while private repositories require appropriate authentication and permissions. + +- ++ + + **OAT listing behavior**: an OAT with the `scope-repository-list` scope sees all repositories including private ones. An OAT without that scope only sees public repositories. This filtering is silent: the response is a normal `200` with no indication that private repositories were withheld. + tags: + - repositories + security: + - bearerAuth: [] +- - {} # Allow anonymous access for public repositories ++ - {} + parameters: + - in: query + name: page +@@ -1309,59 +1334,59 @@ + repositories_list: + value: + count: 287 +- next: "https://hub.docker.com/v2/namespaces/docker/repositories?page=2&page_size=2" ++ next: https://hub.docker.com/v2/namespaces/docker/repositories?page=2&page_size=2 + previous: null + results: +- - name: "highland_builder" +- namespace: "docker" +- repository_type: "image" ++ - name: highland_builder ++ namespace: docker ++ repository_type: image + status: 1 +- status_description: "active" +- description: "Image for performing Docker build requests" ++ status_description: active ++ description: Image for performing Docker build requests + is_private: false + star_count: 7 + pull_count: 15722123 +- last_updated: "2023-06-20T10:44:45.459826Z" +- last_modified: "2024-10-16T13:48:34.145251Z" +- date_registered: "2015-05-19T21:13:35.937763Z" ++ last_updated: 2023-06-20T10:44:45.459826Z ++ last_modified: 2024-10-16T13:48:34.145251Z ++ date_registered: 2015-05-19T21:13:35.937763Z + affiliation: "" + media_types: +- - "application/octet-stream" +- - "application/vnd.docker.container.image.v1+json" +- - "application/vnd.docker.distribution.manifest.v1+prettyjws" ++ - application/octet-stream ++ - application/vnd.docker.container.image.v1+json ++ - application/vnd.docker.distribution.manifest.v1+prettyjws + content_types: +- - "unrecognized" +- - "image" ++ - unrecognized ++ - image + categories: +- - name: "Languages & frameworks" +- slug: "languages-and-frameworks" +- - name: "Integration & delivery" +- slug: "integration-and-delivery" +- - name: "Operating systems" +- slug: "operating-systems" ++ - name: Languages & frameworks ++ slug: languages-and-frameworks ++ - name: Integration & delivery ++ slug: integration-and-delivery ++ - name: Operating systems ++ slug: operating-systems + storage_size: 488723114800 +- - name: "whalesay" +- namespace: "docker" ++ - name: whalesay ++ namespace: docker + repository_type: null + status: 1 +- status_description: "active" +- description: "An image for use in the Docker demo tutorial" ++ status_description: active ++ description: An image for use in the Docker demo tutorial + is_private: false + star_count: 757 + pull_count: 130737682 +- last_updated: "2015-06-19T19:06:27.388123Z" +- last_modified: "2024-10-16T13:48:34.145251Z" +- date_registered: "2015-06-09T18:16:36.527329Z" ++ last_updated: 2015-06-19T19:06:27.388123Z ++ last_modified: 2024-10-16T13:48:34.145251Z ++ date_registered: 2015-06-09T18:16:36.527329Z + affiliation: "" + media_types: +- - "application/vnd.docker.distribution.manifest.v1+prettyjws" ++ - application/vnd.docker.distribution.manifest.v1+prettyjws + content_types: +- - "image" ++ - image + categories: +- - name: "Languages & frameworks" +- slug: "languages-and-frameworks" +- - name: "Integration & delivery" +- slug: "integration-and-delivery" ++ - name: Languages & frameworks ++ slug: languages-and-frameworks ++ - name: Integration & delivery ++ slug: integration-and-delivery + storage_size: 103666708 + "400": + description: Bad Request - Invalid request parameters +@@ -1375,10 +1400,8 @@ + value: + fields: + ordering: +- [ +- "Invalid ordering value. Must be one of: name, -name, last_updated, -last_updated, pull_count, -pull_count", +- ] +- text: "Invalid ordering value" ++ - "Invalid ordering value. Must be one of: name, -name, last_updated, -last_updated, pull_count, -pull_count" ++ text: Invalid ordering value + "401": + $ref: "#/components/responses/unauthorized" + "403": +@@ -1391,11 +1414,11 @@ + $ref: "#/components/schemas/error" + post: + summary: Create a new repository +- description: | ++ description: |+ + Creates a new repository within the specified namespace. The repository will be created + with the provided metadata including name, description, and privacy settings. + +- ++ + operationId: CreateRepository + tags: + - repositories +@@ -1408,36 +1431,36 @@ + schema: + $ref: "#/components/schemas/repo_creation_request" + example: +- name: "my-app" +- namespace: "myorganization" +- description: "A sample application repository" +- full_description: "This is a comprehensive description of my application repository that contains additional details about the project." +- registry: "docker.io" ++ name: my-app ++ namespace: myorganization ++ description: A sample application repository ++ full_description: This is a comprehensive description of my application repository that contains additional details about the project. ++ registry: docker.io + is_private: false + responses: +- 201: ++ "201": + description: Repository created successfully + content: + application/json: + schema: + $ref: "#/components/schemas/repository_info" + example: +- name: "my-app" +- namespace: "myorganization" +- repository_type: "image" ++ name: my-app ++ namespace: myorganization ++ repository_type: image + status: 1 +- status_description: "Active" +- description: "A sample application repository" ++ status_description: Active ++ description: A sample application repository + is_private: false + is_automated: false + star_count: 0 + pull_count: 0 +- last_updated: "2025-01-20T10:30:00Z" +- date_registered: "2025-01-20T10:30:00Z" ++ last_updated: 2025-01-20T10:30:00Z ++ date_registered: 2025-01-20T10:30:00Z + collaborator_count: 0 +- hub_user: "myorganization" ++ hub_user: myorganization + has_starred: false +- full_description: "This is a comprehensive description of my application repository that contains additional details about the project." ++ full_description: This is a comprehensive description of my application repository that contains additional details about the project. + media_types: [] + content_types: [] + categories: [] +@@ -1446,15 +1469,15 @@ + rules: [] + storage_size: null + source: null +- 400: ++ "400": + $ref: "#/components/responses/bad_request" +- 401: ++ "401": + $ref: "#/components/responses/unauthorized" +- 403: ++ "403": + $ref: "#/components/responses/forbidden" +- 404: ++ "404": + $ref: "#/components/responses/not_found" +- 500: ++ "500": + $ref: "#/components/responses/internal_error" + /v2/namespaces/{namespace}/repositories/{repository}: + parameters: +@@ -1463,40 +1486,40 @@ + get: + operationId: GetRepository + summary: Get repository in a namespace +- description: | ++ description: |+ + Returns a repository within the specified namespace (organization or user). + + Public repositories are accessible to everyone, while private repositories require appropriate authentication and permissions. + +- ++ + tags: + - repositories + security: + - bearerAuth: [] +- - {} # Allow anonymous access for public repositories ++ - {} + responses: +- 200: ++ "200": + content: + application/json: + schema: + $ref: "#/components/schemas/repository_info" + example: +- name: "my-app" +- namespace: "myorganization" +- repository_type: "image" ++ name: my-app ++ namespace: myorganization ++ repository_type: image + status: 1 +- status_description: "Active" +- description: "A sample application repository" ++ status_description: Active ++ description: A sample application repository + is_private: false + is_automated: false + star_count: 0 + pull_count: 0 +- last_updated: "2025-01-20T10:30:00Z" +- date_registered: "2025-01-20T10:30:00Z" ++ last_updated: 2025-01-20T10:30:00Z ++ date_registered: 2025-01-20T10:30:00Z + collaborator_count: 0 +- hub_user: "myorganization" ++ hub_user: myorganization + has_starred: false +- full_description: "This is a comprehensive description of my application repository that contains additional details about the project." ++ full_description: This is a comprehensive description of my application repository that contains additional details about the project. + media_types: [] + content_types: [] + categories: [] +@@ -1505,66 +1528,37 @@ + rules: [] + storage_size: null + source: null +- 401: ++ "401": + $ref: "#/components/responses/unauthorized" +- 403: ++ "403": + $ref: "#/components/responses/forbidden" +- 404: ++ "404": + $ref: "#/components/responses/not_found" +- 500: ++ "500": + $ref: "#/components/responses/internal_error" + head: + operationId: CheckRepository + summary: Check repository in a namespace +- description: | ++ description: |+ + Check a repository within the specified namespace (organization or user). + + Public repositories are accessible to everyone, while private repositories require appropriate authentication and permissions. + +- ++ + tags: + - repositories + security: + - bearerAuth: [] +- - {} # Allow anonymous access for public repositories ++ - {} + responses: +- 200: +- content: +- application/json: +- schema: +- $ref: "#/components/schemas/repository_info" +- example: +- name: "my-app" +- namespace: "myorganization" +- repository_type: "image" +- status: 1 +- status_description: "Active" +- description: "A sample application repository" +- is_private: false +- is_automated: false +- star_count: 0 +- pull_count: 0 +- last_updated: "2025-01-20T10:30:00Z" +- date_registered: "2025-01-20T10:30:00Z" +- collaborator_count: 0 +- hub_user: "myorganization" +- has_starred: false +- full_description: "This is a comprehensive description of my application repository that contains additional details about the project." +- media_types: [] +- content_types: [] +- categories: [] +- immutable_tags_settings: +- enabled: false +- rules: [] +- storage_size: null +- source: null +- 401: ++ "200": {} ++ "401": + $ref: "#/components/responses/unauthorized" +- 403: ++ "403": + $ref: "#/components/responses/forbidden" +- 404: ++ "404": + $ref: "#/components/responses/not_found" +- 500: ++ "500": + $ref: "#/components/responses/internal_error" + /v2/orgs/{org_name}/members: + parameters: +@@ -1577,7 +1571,7 @@ + - $ref: "#/components/parameters/role" + get: + summary: List org members +- description: | ++ description: |+ + Returns a list of members for an organization. + + _The following fields are only visible to orgs with insights enabled._ +@@ -1588,7 +1582,7 @@ + + To make visible, please see [View Insights for organization users](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). + +- ++ + tags: + - orgs + security: +@@ -1610,15 +1604,16 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: getV2OrgsByOrgNameMembers + /v2/orgs/{org_name}/members/export: + parameters: + - $ref: "#/components/parameters/org_name" + get: + summary: Export org members CSV +- description: | ++ description: |+ + Export members of an organization as a CSV + +- ++ + tags: + - orgs + security: +@@ -1682,6 +1677,7 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: getV2OrgsByOrgNameMembersExport + /v2/orgs/{org_name}/members/{username}: + x-audience: public + parameters: +@@ -1689,11 +1685,11 @@ + - $ref: "#/components/parameters/username" + put: + summary: Update org member (role) +- description: | ++ description: |+ + Updates the role of a member in the organization. + ***Only users in the "owners" group of the organization can use this endpoint.*** + +- ++ + tags: + - orgs + security: +@@ -1729,12 +1725,13 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: putV2OrgsByOrgNameMembersByUsername + delete: + summary: Remove member from org +- description: | ++ description: |+ + Removes the member from the org, ie. all groups in the org, unless they're the last owner + +- ++ + tags: + - orgs + security: +@@ -1750,16 +1747,17 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: deleteV2OrgsByOrgNameMembersByUsername + /v2/orgs/{org_name}/invites: + x-audience: public + parameters: + - $ref: "#/components/parameters/org_name" + get: + summary: List org invites +- description: | ++ description: |+ + Return all pending invites for a given org, only team owners can call this endpoint + +- ++ + tags: + - invites + security: +@@ -1782,14 +1780,14 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: getV2OrgsByOrgNameInvites + /v2/orgs/{org_name}/groups: + x-audience: public + parameters: + - $ref: "#/components/parameters/org_name" + get: + summary: Get groups of an organization +- description: | +- ++ description: Get groups of an organization. + tags: + - groups + security: +@@ -1833,12 +1831,13 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: getV2OrgsByOrgNameGroups + post: + summary: Create a new group +- description: | ++ description: |+ + Create a new group within an organization. + +- ++ + tags: + - groups + security: +@@ -1867,6 +1866,7 @@ + $ref: "#/components/responses/unauthorized" + "403": + $ref: "#/components/responses/forbidden" ++ operationId: postV2OrgsByOrgNameGroups + /v2/orgs/{org_name}/groups/{group_name}: + x-audience: public + parameters: +@@ -1874,8 +1874,7 @@ + - $ref: "#/components/parameters/group_name" + get: + summary: Get a group of an organization +- description: | +- ++ description: Get a group of an organization. + tags: + - groups + security: +@@ -1893,10 +1892,10 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: getV2OrgsByOrgNameGroupsByGroupName + put: + summary: Update the details for an organization group +- description: | +- ++ description: Update the details for an organization group. + tags: + - groups + security: +@@ -1925,10 +1924,10 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: putV2OrgsByOrgNameGroupsByGroupName + patch: + summary: Update some details for an organization group +- description: | +- ++ description: Update some details for an organization group. + tags: + - groups + security: +@@ -1962,10 +1961,10 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: patchV2OrgsByOrgNameGroupsByGroupName + delete: + summary: Delete an organization group +- description: | +- ++ description: Delete an organization group. + tags: + - groups + security: +@@ -1979,6 +1978,7 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: deleteV2OrgsByOrgNameGroupsByGroupName + /v2/orgs/{org_name}/groups/{group_name}/members: + x-audience: public + get: +@@ -1995,11 +1995,11 @@ + type: string + description: Search members by username, full_name or email. + summary: List members of a group +- description: | ++ description: |+ + List the members (users) that are in a group. + If user is owner of the org or has otherwise elevated permissions, they can search by email and the result will also contain emails. + +- ++ + tags: + - groups + responses: +@@ -2028,13 +2028,13 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: getV2OrgsByOrgNameGroupsByGroupNameMembers + post: + parameters: + - $ref: "#/components/parameters/org_name" + - $ref: "#/components/parameters/group_name" + summary: Add a member to a group +- description: | +- ++ description: Add a member to a group. + tags: + - groups + security: +@@ -2052,6 +2052,7 @@ + $ref: "#/components/responses/not_found" + "500": + $ref: "#/components/responses/internal_error" ++ operationId: postV2OrgsByOrgNameGroupsByGroupNameMembers + /v2/orgs/{org_name}/groups/{group_name}/members/{username}: + x-audience: public + parameters: +@@ -2060,8 +2061,7 @@ + - $ref: "#/components/parameters/username" + delete: + summary: Remove a user from a group +- description: | +- ++ description: Remove a user from a group. + tags: + - groups + security: +@@ -2075,6 +2075,7 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: deleteV2OrgsByOrgNameGroupsByGroupNameMembersByUsername + /v2/invites/{id}: + x-audience: public + parameters: +@@ -2085,10 +2086,10 @@ + type: string + delete: + summary: Cancel an invite +- description: | ++ description: |+ + Mark the invite as cancelled so it doesn't show up on the list of pending invites + +- ++ + tags: + - invites + security: +@@ -2102,6 +2103,7 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: deleteV2InvitesById + /v2/invites/{id}/resend: + x-audience: public + parameters: +@@ -2112,10 +2114,10 @@ + required: true + patch: + summary: Resend an invite +- description: | ++ description: |+ + Resend a pending invite to the user, any org owner can resend an invite + +- ++ + tags: + - invites + security: +@@ -2129,16 +2131,17 @@ + $ref: "#/components/responses/forbidden" + "404": + $ref: "#/components/responses/not_found" ++ operationId: patchV2InvitesByIdResend + /v2/invites/bulk: + x-audience: public + parameters: + - $ref: "#/components/parameters/bulk_invite" + post: + summary: Bulk create invites +- description: | ++ description: |+ + Create multiple invites by emails or DockerIDs. Only a team owner can create invites. + +- ++ + tags: + - invites + requestBody: +@@ -2159,6 +2162,7 @@ + $ref: "#/components/responses/bad_request" + "409": + $ref: "#/components/responses/conflict" ++ operationId: postV2InvitesBulk + /v2/scim/2.0/ServiceProviderConfig: + x-audience: public + get: +@@ -2168,7 +2172,7 @@ + tags: + - scim + security: +- - bearerSCIMAuth: [] ++ - scimToken: [] + responses: + "200": + $ref: "#/components/responses/scim_get_service_provider_config_resp" +@@ -2176,6 +2180,7 @@ + $ref: "#/components/responses/scim_unauthorized" + "500": + $ref: "#/components/responses/scim_error" ++ operationId: getV2Scim20ServiceProviderConfig + /v2/scim/2.0/ResourceTypes: + x-audience: public + get: +@@ -2185,7 +2190,7 @@ + tags: + - scim + security: +- - bearerSCIMAuth: [] ++ - scimToken: [] + responses: + "200": + $ref: "#/components/responses/scim_get_resource_types_resp" +@@ -2193,6 +2198,7 @@ + $ref: "#/components/responses/scim_unauthorized" + "500": + $ref: "#/components/responses/scim_error" ++ operationId: getV2Scim20ResourceTypes + /v2/scim/2.0/ResourceTypes/{name}: + x-audience: public + get: +@@ -2209,7 +2215,7 @@ + example: User + required: true + security: +- - bearerSCIMAuth: [] ++ - scimToken: [] + responses: + "200": + $ref: "#/components/responses/scim_get_resource_type_resp" +@@ -2219,6 +2225,7 @@ + $ref: "#/components/responses/scim_not_found" + "500": + $ref: "#/components/responses/scim_error" ++ operationId: getV2Scim20ResourceTypesByName + /v2/scim/2.0/Schemas: + x-audience: public + get: +@@ -2228,7 +2235,7 @@ + tags: + - scim + security: +- - bearerSCIMAuth: [] ++ - scimToken: [] + responses: + "200": + $ref: "#/components/responses/scim_get_schemas_resp" +@@ -2236,6 +2243,7 @@ + $ref: "#/components/responses/scim_unauthorized" + "500": + $ref: "#/components/responses/scim_error" ++ operationId: getV2Scim20Schemas + /v2/scim/2.0/Schemas/{id}: + x-audience: public + get: +@@ -2252,7 +2260,7 @@ + example: urn:ietf:params:scim:schemas:core:2.0:User + required: true + security: +- - bearerSCIMAuth: [] ++ - scimToken: [] + responses: + "200": + $ref: "#/components/responses/scim_get_schema_resp" +@@ -2262,6 +2270,7 @@ + $ref: "#/components/responses/scim_not_found" + "500": + $ref: "#/components/responses/scim_error" ++ operationId: getV2Scim20SchemasById + /v2/scim/2.0/Users: + x-audience: public + get: +@@ -2292,7 +2301,7 @@ + tags: + - scim + security: +- - bearerSCIMAuth: [] ++ - scimToken: [] + parameters: + - name: startIndex + in: query +@@ -2342,6 +2351,7 @@ + $ref: "#/components/responses/scim_not_found" + "500": + $ref: "#/components/responses/scim_error" ++ operationId: getV2Scim20Users + post: + summary: Create user + description: | +@@ -2349,7 +2359,7 @@ + tags: + - scim + security: +- - bearerSCIMAuth: [] ++ - scimToken: [] + requestBody: + $ref: "#/components/requestBodies/scim_create_user_request" + responses: +@@ -2367,6 +2377,7 @@ + $ref: "#/components/responses/scim_conflict" + "500": + $ref: "#/components/responses/scim_error" ++ operationId: postV2Scim20Users + /v2/scim/2.0/Users/{id}: + x-audience: public + parameters: +@@ -2378,7 +2389,7 @@ + tags: + - scim + security: +- - bearerSCIMAuth: [] ++ - scimToken: [] + responses: + "200": + $ref: "#/components/responses/scim_get_user_resp" +@@ -2392,6 +2403,7 @@ + $ref: "#/components/responses/scim_not_found" + "500": + $ref: "#/components/responses/scim_error" ++ operationId: getV2Scim20UsersById + put: + summary: Update a user + description: | +@@ -2399,7 +2411,7 @@ + tags: + - scim + security: +- - bearerSCIMAuth: [] ++ - scimToken: [] + requestBody: + $ref: "#/components/requestBodies/scim_update_user_request" + responses: +@@ -2417,6 +2429,7 @@ + $ref: "#/components/responses/scim_conflict" + "500": + $ref: "#/components/responses/scim_error" ++ operationId: putV2Scim20UsersById + components: + responses: + BadRequest: +@@ -2679,8 +2692,8 @@ + type: string + description: List of immutable tag rules + example: +- - "v.*" +- - ".*-RELEASE" ++ - v.* ++ - .*-RELEASE + required: + - immutable_tags + - immutable_tags_rules +@@ -2698,26 +2711,26 @@ + Letters must be lowercase. + minLength: 2 + maxLength: 255 +- pattern: "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" +- example: "my-app" ++ pattern: ^[a-z0-9]+(?:[._-][a-z0-9]+)*$ ++ example: my-app + namespace: + type: string + description: The namespace where the repository will be created +- example: "myorganization" ++ example: myorganization + description: + type: string + description: Short description of the repository + maxLength: 100 +- example: "A sample application repository" ++ example: A sample application repository + full_description: + type: string + description: Detailed description of the repository + maxLength: 25000 +- example: "This is a comprehensive description of my application repository that contains additional details about the project, its purpose, usage instructions, and other relevant information." ++ example: This is a comprehensive description of my application repository that contains additional details about the project, its purpose, usage instructions, and other relevant information. + registry: + type: string + description: The registry where the repository will be hosted +- example: "docker.io" ++ example: docker.io + is_private: + type: boolean + description: Whether the repository should be private +@@ -2741,20 +2754,26 @@ + - read: Can view and pull from the repository + - write: Can view, pull, and push to the repository + - admin: Can view, pull, push, and manage repository settings +- enum: ["read", "write", "admin"] +- example: "write" ++ enum: ++ - read ++ - write ++ - admin ++ example: write + RepositoryGroup: + type: object + properties: + group_name: + type: string + description: The name of the group +- example: "developers" ++ example: developers + permission: + type: string + description: The permission level granted to the group +- enum: ["read", "write", "admin"] +- example: "write" ++ enum: ++ - read ++ - write ++ - admin ++ example: write + group_id: + type: integer + format: int64 +@@ -2773,8 +2792,9 @@ + type: string + description: Repository namespace + repository_type: +- type: string +- nullable: true ++ type: ++ - string ++ - "null" + description: Type of the repository + status: + type: integer +@@ -2802,45 +2822,50 @@ + last_updated: + type: string + format: date-time +- example: "2021-01-05T21:06:53.506400Z" ++ example: 2021-01-05T21:06:53.506400Z + description: ISO 8601 timestamp of when repository was last updated + last_modified: +- type: string ++ type: ++ - string ++ - "null" + format: date-time +- example: "2021-01-05T21:06:53.506400Z" +- nullable: true ++ example: 2021-01-05T21:06:53.506400Z + description: ISO 8601 timestamp of when repository was last modified + date_registered: + type: string + format: date-time +- example: "2021-01-05T21:06:53.506400Z" ++ example: 2021-01-05T21:06:53.506400Z + description: ISO 8601 timestamp of when repository was created + collaborator_count: + type: integer + format: int64 + description: Number of collaborators + affiliation: +- type: string +- nullable: true ++ type: ++ - string ++ - "null" + description: Repository affiliation + hub_user: +- type: string +- nullable: true ++ type: ++ - string ++ - "null" + description: Hub user information + has_starred: + type: boolean + description: Whether the current user has starred this repository + full_description: +- type: string +- nullable: true ++ type: ++ - string ++ - "null" + description: Full description of the repository + permissions: + $ref: "#/components/schemas/repo_permissions" + media_types: + type: array + items: +- type: string +- nullable: true ++ type: ++ - string ++ - "null" + description: Supported media types + content_types: + type: array +@@ -2855,13 +2880,15 @@ + immutable_tags_settings: + $ref: "#/components/schemas/immutable_tags_settings" + storage_size: +- type: integer ++ type: ++ - integer ++ - "null" + format: int64 +- nullable: true + description: Storage size in bytes + source: +- type: string +- nullable: true ++ type: ++ - string ++ - "null" + description: Source of the repository, where it was created from + required: + - user +@@ -2918,9 +2945,9 @@ + properties: + regex: + type: string +- pattern: '^[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*(\\/[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*)*$' +- description: 'Immutable tags rule regex pattern. Must match format: [a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*(\\/[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*)*' +- example: "v.*" ++ pattern: ^[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*(\\/[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*)*$ ++ description: "Immutable tags rule regex pattern. Must match format: [a-z0-9]+((\\\\.|_|__|-+)[a-z0-9]+)*(\\\\/[a-z0-9]+((\\\\.|_|__|-+)[a-z0-9]+)*)*" ++ example: v.* + required: + - regex + immutable_tags_verify_response: +@@ -2932,9 +2959,9 @@ + type: string + description: List of tags that match the provided regex pattern + example: +- - "v1.0.0" +- - "v2.1.3" +- - "latest" ++ - v1.0.0 ++ - v2.1.3 ++ - latest + required: + - tags + repository_list_entry: +@@ -2943,20 +2970,21 @@ + name: + type: string + description: Name of the repository +- example: "hello-world" ++ example: hello-world + namespace: + type: string + description: Namespace (organization or username) that owns the repository +- example: "docker" ++ example: docker + repository_type: +- type: string ++ type: ++ - string ++ - "null" + description: Type of repository + enum: + - image + - plugin + - null +- example: "image" +- nullable: true ++ example: image + status: + type: integer + description: Repository status code +@@ -2967,12 +2995,13 @@ + enum: + - active + - inactive +- example: "active" ++ example: active + description: +- type: string ++ type: ++ - string ++ - "null" + description: Repository description +- nullable: true +- example: "Hello World! (an example of minimal Dockerization)" ++ example: Hello World! (an example of minimal Dockerization) + is_private: + type: boolean + description: Whether the repository is private +@@ -2988,22 +3017,24 @@ + minimum: 0 + example: 50000000 + last_updated: +- type: string ++ type: ++ - string ++ - "null" + format: date-time + description: ISO 8601 timestamp of when the repository was last updated +- example: "2023-12-01T10:30:00Z" +- nullable: true ++ example: 2023-12-01T10:30:00Z + last_modified: +- type: string ++ type: ++ - string ++ - "null" + format: date-time + description: ISO 8601 timestamp of when the repository was last modified +- example: "2023-12-01T10:30:00Z" +- nullable: true ++ example: 2023-12-01T10:30:00Z + date_registered: + type: string + format: date-time + description: ISO 8601 timestamp of when the repository was created +- example: "2013-06-19T19:07:54Z" ++ example: 2013-06-19T19:07:54Z + affiliation: + type: string + description: User's affiliation with the repository (empty string if no affiliation) +@@ -3014,14 +3045,14 @@ + items: + type: string + example: +- - "application/vnd.docker.plugin.v1+json" ++ - application/vnd.docker.plugin.v1+json + content_types: + type: array + description: Content types supported by this repository + items: + type: string + example: +- - "plugin" ++ - plugin + categories: + type: array + description: Categories associated with this repository +@@ -3042,14 +3073,14 @@ + name: + type: string + description: Human-readable name of the category +- example: "Databases" ++ example: Databases + minLength: 1 + slug: + type: string + description: URL-friendly identifier for the category +- example: "databases" ++ example: databases + minLength: 1 +- pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*$" ++ pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$ + description: Repository category for classification and discovery + list_repositories_response: + allOf: +@@ -3094,7 +3125,6 @@ + This token can be used in the HTTP Authorization header as a JWT to authenticate with the Docker Hub APIs. + type: string + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c +- nullable: false + PostUsersLoginErrorResponse: + description: failed user login response or second factor required + type: object +@@ -3105,13 +3135,13 @@ + description: Description of the error. + type: string + example: Incorrect authentication credentials +- nullable: false + login_2fa_token: + description: | + Short time lived token to be used on `/v2/users/2fa-login` to complete the authentication. This field is present only if 2FA is enabled. +- type: string ++ type: ++ - string ++ - "null" + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c +- nullable: true + Users2FALoginRequest: + description: Second factor user login details + type: object +@@ -3136,7 +3166,6 @@ + description: Description of the error. + type: string + example: Incorrect authentication credentials +- nullable: false + protobufAny: + type: object + properties: +@@ -3254,11 +3283,12 @@ + example: some user agent + created_at: + type: string +- example: "2021-07-20T12:00:00.000000Z" ++ example: 2021-07-20T12:00:00.000000Z + last_used: +- type: string ++ type: ++ - string ++ - "null" + example: null +- nullable: true + generated_by: + type: string + example: manual +@@ -3280,7 +3310,7 @@ + expires_at: + type: string + format: date-time +- example: "2021-10-28T18:30:19.520861Z" ++ example: 2021-10-28T18:30:19.520861Z + createAccessTokenRequest: + type: object + required: +@@ -3307,7 +3337,7 @@ + Optional expiration date for the token. + If omitted, the token will remain valid indefinitely. + format: date-time +- example: "2021-10-28T18:30:19.520861Z" ++ example: 2021-10-28T18:30:19.520861Z + createAccessTokensResponse: + $ref: "#/components/schemas/accessToken" + getAccessTokensResponse: +@@ -3372,9 +3402,10 @@ + type: object + properties: + digest: +- type: string ++ type: ++ - string ++ - "null" + description: image layer digest +- nullable: true + size: + type: integer + description: size of the layer +@@ -3394,9 +3425,10 @@ + type: string + description: CPU variant + digest: +- type: string ++ type: ++ - string ++ - "null" + description: image digest +- nullable: true + layers: + type: array + items: +@@ -3420,15 +3452,17 @@ + - inactive + description: Status of the image + last_pulled: +- type: string +- example: "2021-01-05T21:06:53.506400Z" ++ type: ++ - string ++ - "null" ++ example: 2021-01-05T21:06:53.506400Z + description: datetime of last pull +- nullable: true + last_pushed: +- type: string +- example: "2021-01-05T21:06:53.506400Z" ++ type: ++ - string ++ - "null" ++ example: 2021-01-05T21:06:53.506400Z + description: datetime of last push +- nullable: true + tag: + type: object + properties: +@@ -3442,10 +3476,11 @@ + type: integer + description: ID of the user that pushed the tag + last_updated: +- type: string +- example: "2021-01-05T21:06:53.506400Z" ++ type: ++ - string ++ - "null" ++ example: 2021-01-05T21:06:53.506400Z + description: datetime of last update +- nullable: true + last_updater: + type: integer + description: ID of the last user that updated the tag +@@ -3471,15 +3506,17 @@ + - inactive + description: whether a tag has been pushed to or pulled in the past month + tag_last_pulled: +- type: string +- example: "2021-01-05T21:06:53.506400Z" ++ type: ++ - string ++ - "null" ++ example: 2021-01-05T21:06:53.506400Z + description: datetime of last pull +- nullable: true + tag_last_pushed: +- type: string +- example: "2021-01-05T21:06:53.506400Z" ++ type: ++ - string ++ - "null" ++ example: 2021-01-05T21:06:53.506400Z + description: datetime of last push +- nullable: true + paginated_tags: + allOf: + - $ref: "#/components/schemas/page" +@@ -3496,13 +3533,15 @@ + type: integer + description: total number of results available across all pages + next: +- type: string ++ type: ++ - string ++ - "null" + description: link to next page of results if any +- nullable: true + previous: +- type: string ++ type: ++ - string ++ - "null" + description: link to previous page of results if any +- nullable: true + scim_schema_attribute: + type: object + properties: +@@ -3570,7 +3609,7 @@ + example: owners + created_at: + type: string +- example: "2021-10-28T18:30:19.520861Z" ++ example: 2021-10-28T18:30:19.520861Z + bulk_invite: + type: object + properties: +@@ -3599,7 +3638,7 @@ + invitee: invitee@docker.com + org: docker + team: owners +- created_at: "2021-10-28T18:30:19.520861Z" ++ created_at: 2021-10-28T18:30:19.520861Z + - invitee: invitee2@docker.com + status: existing_org_member + - invitee: invitee3@docker.com +@@ -3641,7 +3680,7 @@ + example: Docker Inc + date_joined: + type: string +- example: "2021-01-05T21:06:53.506400Z" ++ example: 2021-01-05T21:06:53.506400Z + full_name: + type: string + example: Jon Snow +@@ -3704,21 +3743,20 @@ + description: | + Last time the user logged in. To access this field, you must have insights visible for your organization. See + [Insights](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). +- example: "2021-01-05T21:06:53.506400Z" ++ example: 2021-01-05T21:06:53.506400Z + last_seen_at: + type: string + format: date-time + description: | + Last time the user was seen. To access this field, you must have insights visible for your organization. See + [Insights](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). +- example: "2021-01-05T21:06:53.506400Z" ++ example: 2021-01-05T21:06:53.506400Z + last_desktop_version: + type: string + description: | + Last desktop version the user used. To access this field, you must have insights visible for your organization. See + [Insights](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). + example: 4.29.0 +- + org_member_paginated: + type: object + properties: +@@ -3779,7 +3817,7 @@ + date_joined: + type: string + format: date-time +- example: "2021-01-05T21:06:53.506400Z" ++ example: 2021-01-05T21:06:53.506400Z + full_name: + type: string + example: John Snow +@@ -4034,41 +4072,43 @@ + type: string + format: date-time + description: The creation date for the user as a RFC3339 formatted string. +- example: "2022-05-20T00:54:18Z" ++ example: 2022-05-20T00:54:18Z + lastModified: + type: string + format: date-time + description: The date the user was last modified as a RFC3339 formatted string. +- example: "2022-05-20T00:54:18Z" ++ example: 2022-05-20T00:54:18Z + orgAccessToken: + type: object + properties: + id: + type: string +- example: "a7a5ef25-8889-43a0-8cc7-f2a94268e861" ++ example: a7a5ef25-8889-43a0-8cc7-f2a94268e861 + label: + type: string +- example: "My organization token" ++ example: My organization token + created_by: + type: string +- example: "johndoe" ++ example: johndoe + is_active: + type: boolean + example: true + created_at: + type: string + format: date-time +- example: "2022-05-20T00:54:18Z" ++ example: 2022-05-20T00:54:18Z + expires_at: +- type: string ++ type: ++ - string ++ - "null" + format: date-time +- example: "2023-05-20T00:54:18Z" +- nullable: true ++ example: 2023-05-20T00:54:18Z + last_used_at: +- type: string ++ type: ++ - string ++ - "null" + format: date-time +- example: "2022-06-15T12:30:45Z" +- nullable: true ++ example: 2022-06-15T12:30:45Z + orgAccessTokenResource: + type: object + properties: +@@ -4077,12 +4117,11 @@ + enum: + - TYPE_REPO + - TYPE_ORG +- example: "TYPE_REPO" ++ example: TYPE_REPO + description: The type of resource +- required: true + path: + type: string +- example: "myorg/myrepo" ++ example: myorg/myrepo + description: | + The path of the resource. The format of this will change depending on the type of resource. + +@@ -4090,14 +4129,16 @@ + - Must be an existing repository name (e.g., "myorg/myrepo") + - Can use glob patterns (e.g., "myorg/*" for all repositories in the organization) + - Use "*/*/public" to reference all public repositories +- required: true + scopes: + type: array + description: The scopes this token has access to + items: + type: string +- example: "scope-image-pull" +- required: true ++ example: scope-image-pull ++ required: ++ - type ++ - path ++ - scopes + getOrgAccessTokensResponse: + type: object + properties: +@@ -4130,23 +4171,25 @@ + label: + type: string + description: Label for the access token +- example: "My organization token" +- required: true ++ example: My organization token + description: + type: string + description: Description of the access token +- example: "Token for CI/CD pipeline" ++ example: Token for CI/CD pipeline + resources: + type: array + description: Resources this token has access to + items: + $ref: "#/components/schemas/orgAccessTokenResource" + expires_at: +- type: string ++ type: ++ - string ++ - "null" + format: date-time + description: Expiration date for the token +- example: "2023-05-20T00:54:18Z" +- nullable: true ++ example: 2023-05-20T00:54:18Z ++ required: ++ - label + createOrgAccessTokenResponse: + type: object + allOf: +@@ -4154,33 +4197,35 @@ + properties: + id: + type: string +- example: "a7a5ef25-8889-43a0-8cc7-f2a94268e861" ++ example: a7a5ef25-8889-43a0-8cc7-f2a94268e861 + label: + type: string +- example: "My organization token" ++ example: My organization token + is_active: + type: boolean + example: true + created_at: + type: string + format: date-time +- example: "2022-05-20T00:54:18Z" ++ example: 2022-05-20T00:54:18Z + expires_at: +- type: string ++ type: ++ - string ++ - "null" + format: date-time +- example: "2023-05-20T00:54:18Z" +- nullable: true ++ example: 2023-05-20T00:54:18Z + last_used_at: +- type: string ++ type: ++ - string ++ - "null" + format: date-time +- example: "2022-06-15T12:30:45Z" +- nullable: true ++ example: 2022-06-15T12:30:45Z + - type: object + properties: + token: + type: string + description: The actual token value that can be used for authentication +- example: "dckr_oat_7awgM4jG5SQvxcvmNzhKj8PQjxo" ++ example: dckr_oat_7awgM4jG5SQvxcvmNzhKj8PQjxo + resources: + type: array + items: +@@ -4191,11 +4236,11 @@ + label: + type: string + description: Label for the access token +- example: "My organization token" ++ example: My organization token + description: + type: string + description: Description of the access token +- example: "Token for CI/CD pipeline" ++ example: Token for CI/CD pipeline + resources: + type: array + description: Resources this token has access to +@@ -4218,7 +4263,7 @@ + $ref: "#/components/schemas/orgAccessTokenResource" + team_repo: + allOf: +- - $ref: "#/components/responses/team_repo" ++ - $ref: "#/components/schemas/repository_info" + properties: + group_name: + type: string +@@ -4442,6 +4487,10 @@ + bearerSCIMAuth: + type: http + scheme: bearer ++ scimToken: ++ type: http ++ scheme: bearer ++ description: Use the SCIM provisioning token configured for the organization. + x-tagGroups: + - name: General + tags: +@@ -4462,3 +4511,5 @@ + - org-access-tokens + - groups + - invites ++jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base ++security: [] From 58e1621aadd22b0eaecbb8c706b07d258af482a3 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 9 Sep 2026 11:42:37 +0000 Subject: [PATCH 04/13] docs: integrate unified API rendering into site builds --- Dockerfile | 7 +- _vale/config/vocabularies/Docker/accept.txt | 1 + assets/api-reference/reference.css | 596 ++++ assets/api-reference/reference.js | 65 + content/reference/api/_content.gotmpl | 22 + content/reference/api/_index.md | 6 - content/reference/api/dvp/latest.md | 9 - content/reference/api/hub/latest.md | 7 - content/reference/api/registry/latest.md | 7 - hack/api-docs/README.md | 75 + hack/api-docs/adoption/README.md | 34 + hack/api-docs/adoption/source-lock.json | 53 + hack/api-docs/browser-checks.mjs | 106 + hack/api-docs/catalog.json | 54 + hack/api-docs/dialects/lock.json | 20 + hack/api-docs/dialects/oas-dialect.json | 25 + hack/api-docs/dialects/oas-document.json | 1666 ++++++++++ hack/api-docs/dialects/oas-vocabulary.json | 87 + hack/api-docs/flatten.mjs | 34 + hack/api-docs/go.mod | 18 + hack/api-docs/go.sum | 30 + hack/api-docs/known-issues.json | 2892 +++++++++++++++++ hack/api-docs/main.go | 764 +++++ hack/api-docs/main_test.go | 208 ++ hack/api-docs/model.go | 249 ++ hack/api-docs/run.sh | 42 + hack/api-docs/testdata/duplicate-key.yaml | 102 + hack/api-docs/testdata/invalid-example.yaml | 101 + hack/api-docs/testdata/invalid-info.yaml | 100 + hack/api-docs/testdata/invalid-item-type.yaml | 101 + .../api-docs/testdata/invalid-stream-ref.yaml | 101 + .../api-docs/testdata/profile-missing-id.yaml | 100 + hack/api-docs/testdata/schemas/event.yaml | 9 + hack/api-docs/testdata/valid.yaml | 101 + hack/api-docs/vacuum.yaml | 24 + hack/api-docs/verify-output.mjs | 161 + hugo.yaml | 4 + .../_partials/api-reference/description.html | 13 + .../api-reference/legacy-fragments.html | 47 + .../_partials/api-reference/manual-link.html | 11 + .../_partials/api-reference/navigation.html | 36 + .../api-reference/overview-tags.html | 11 + layouts/_partials/api-reference/path.html | 4 + layouts/_partials/api-reference/schema.html | 85 + layouts/_partials/content-default.html | 1 + layouts/_partials/sidebar/sections.html | 4 +- layouts/alias.html | 31 + layouts/api-docs.html | 367 +++ layouts/api-docs.markdown.md | 154 + layouts/baseof.html | 1 + netlify.toml | 3 +- 51 files changed, 8716 insertions(+), 33 deletions(-) create mode 100644 assets/api-reference/reference.css create mode 100644 assets/api-reference/reference.js create mode 100644 content/reference/api/_content.gotmpl delete mode 100644 content/reference/api/_index.md delete mode 100644 content/reference/api/dvp/latest.md delete mode 100644 content/reference/api/hub/latest.md delete mode 100644 content/reference/api/registry/latest.md create mode 100644 hack/api-docs/README.md create mode 100644 hack/api-docs/adoption/README.md create mode 100644 hack/api-docs/adoption/source-lock.json create mode 100644 hack/api-docs/browser-checks.mjs create mode 100644 hack/api-docs/catalog.json create mode 100644 hack/api-docs/dialects/lock.json create mode 100644 hack/api-docs/dialects/oas-dialect.json create mode 100644 hack/api-docs/dialects/oas-document.json create mode 100644 hack/api-docs/dialects/oas-vocabulary.json create mode 100644 hack/api-docs/flatten.mjs create mode 100644 hack/api-docs/go.mod create mode 100644 hack/api-docs/go.sum create mode 100644 hack/api-docs/known-issues.json create mode 100644 hack/api-docs/main.go create mode 100644 hack/api-docs/main_test.go create mode 100644 hack/api-docs/model.go create mode 100755 hack/api-docs/run.sh create mode 100644 hack/api-docs/testdata/duplicate-key.yaml create mode 100644 hack/api-docs/testdata/invalid-example.yaml create mode 100644 hack/api-docs/testdata/invalid-info.yaml create mode 100644 hack/api-docs/testdata/invalid-item-type.yaml create mode 100644 hack/api-docs/testdata/invalid-stream-ref.yaml create mode 100644 hack/api-docs/testdata/profile-missing-id.yaml create mode 100644 hack/api-docs/testdata/schemas/event.yaml create mode 100644 hack/api-docs/testdata/valid.yaml create mode 100644 hack/api-docs/vacuum.yaml create mode 100644 hack/api-docs/verify-output.mjs create mode 100644 layouts/_partials/api-reference/description.html create mode 100644 layouts/_partials/api-reference/legacy-fragments.html create mode 100644 layouts/_partials/api-reference/manual-link.html create mode 100644 layouts/_partials/api-reference/navigation.html create mode 100644 layouts/_partials/api-reference/overview-tags.html create mode 100644 layouts/_partials/api-reference/path.html create mode 100644 layouts/_partials/api-reference/schema.html create mode 100644 layouts/alias.html create mode 100644 layouts/api-docs.html create mode 100644 layouts/api-docs.markdown.md diff --git a/Dockerfile b/Dockerfile index b0ab6a5993cf..8aea2c2ecfb9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,6 +12,7 @@ ARG PAGEFIND_VERSION=1.5.2 # base defines the generic base stage FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS base RUN apk add --no-cache \ + bash \ git \ nodejs \ npm \ @@ -41,6 +42,9 @@ WORKDIR /project COPY --from=hugo /out/hugo /bin/hugo COPY --from=npm /out/node_modules node_modules COPY . . +RUN --mount=type=cache,target=/root/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + ./hack/api-docs/run.sh test && ./hack/api-docs/run.sh generate # build creates production builds with Hugo FROM build-base AS build @@ -58,7 +62,8 @@ RUN --mount=type=cache,target=/tmp/hugo_cache \ --printUnusedTemplates \ -b $DOCS_URL \ -e $HUGO_ENV -RUN ./hack/flatten-and-resolve.js public +RUN node hack/api-docs/flatten.mjs public +RUN node hack/api-docs/verify-output.mjs public # lint lints markdown files FROM ghcr.io/rvben/rumdl:0.2.49-alpine AS lint diff --git a/_vale/config/vocabularies/Docker/accept.txt b/_vale/config/vocabularies/Docker/accept.txt index 75ac4e3e93b7..910369f45322 100644 --- a/_vale/config/vocabularies/Docker/accept.txt +++ b/_vale/config/vocabularies/Docker/accept.txt @@ -449,3 +449,4 @@ superset tokenization WebGL Xubuntu +Netlify diff --git a/assets/api-reference/reference.css b/assets/api-reference/reference.css new file mode 100644 index 000000000000..862feee37c89 --- /dev/null +++ b/assets/api-reference/reference.css @@ -0,0 +1,596 @@ +/* Scoped reference tokens inherit Docker's palette and installed typefaces. */ +.api-reference, +.api-nav { + --api-text: var(--color-gray-800, #2c333f); + --api-muted: var(--color-gray-600, #566581); + --api-line: var(--color-gray-100, #e7eaef); + --api-surface: var(--color-background-light, #f9f9fa); + --api-paper: #fff; + --api-link: var(--color-blue-600, #0d4df2); + --api-selected: var(--color-blue-50, #f6f8fe); + --api-mono: "Roboto Mono", ui-monospace, monospace; + color: var(--api-text); +} +.dark .api-reference, +.dark .api-nav { + --api-text: var(--color-gray-100, #e7eaef); + --api-muted: var(--color-gray-300, #a9b4c6); + --api-line: var(--color-gray-800, #2c333f); + --api-surface: var(--color-gray-900, #1e2129); + --api-paper: var(--color-background-dark, #10151b); + --api-link: var(--color-blue-300, #7ba4f4); + --api-selected: #17243b; + color-scheme: dark; +} +.api-reference { + max-width: 1440px; + margin: auto; + font-size: 15px; + line-height: 1.7; + overflow-wrap: anywhere; +} +.api-reference h1 { + font-size: 32px; + font-weight: 550; + letter-spacing: -0.025em; + line-height: 1.25; + margin: 28px 0 20px; + text-wrap: balance; +} +.api-reference h2 { + font-size: 20px; + font-weight: 550; + letter-spacing: -0.015em; + line-height: 1.4; + margin: 36px 0 14px; +} +.api-reference h3, +.api-reference h4 { + font-size: 15px; + font-weight: 550; + line-height: 1.5; + margin: 20px 0 8px; +} +.api-reference p { + margin: 10px 0; + max-width: 72ch; +} +.api-reference .prose { + color: var(--api-text); + font-size: inherit; + line-height: inherit; + max-width: 72ch; +} +.api-reference .prose > :first-child { + margin-top: 0; +} +.api-reference .prose > :last-child { + margin-bottom: 0; +} +.api-reference .prose li > p { + margin: 6px 0; +} +.api-reference .prose :is(h1, h2, h3, h4, h5, h6) > a { + color: inherit; + text-decoration: none; +} +.api-reference .prose :is(h1, h2, h3, h4, h5, h6) > a:hover { + text-decoration: underline; +} +.api-overview { + max-width: 72ch; + margin: 32px 0; +} +.api-reference .api-overview .prose :is(h3, h4) { + font-size: 17px; + font-weight: 550; + line-height: 1.4; + margin: 28px 0 12px; +} +.api-reference a, +.api-nav a { + color: var(--api-link); + text-underline-offset: 3px; +} +.api-reference a:hover { + text-decoration: underline; +} +.api-reference :is(a, button, input, select, summary):focus-visible, +.api-nav a:focus-visible { + outline: 2px solid var(--api-link); + outline-offset: 4px; + border-radius: 3px; +} +.api-reference code { + font-family: var(--api-mono); + font-size: 13px; + font-weight: 400; + overflow-wrap: anywhere; +} +.api-reference .prose code::before, +.api-reference .prose code::after { + content: none; +} +.api-reference pre { + background: var(--api-surface); + color: var(--api-text); + border: 1px solid var(--api-line); + padding: 18px 20px; + border-radius: 6px; + overflow: auto; + font-family: var(--api-mono); + font-size: 13px; + line-height: 1.75; + max-height: 34rem; + margin: 14px 0; + tab-size: 2; +} +.api-reference pre code { + font: inherit; + padding: 0; + background: none; + color: inherit; +} +.api-reference summary { + cursor: pointer; + padding: 6px 0; + font-size: 13px; + color: var(--api-muted); +} +.api-reference summary::marker { + color: var(--api-muted); + font-size: 10px; +} +.api-reference summary:hover { + color: var(--api-link); +} +.api-eyebrow, +.api-label { + font-size: 13px; + font-weight: 500; + color: var(--api-muted); +} +.api-reference .api-eyebrow { + margin-top: 28px; + margin-bottom: -16px; +} +.api-lead { + font-size: 17px; + color: var(--api-muted); +} +.api-cards { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 16px; + margin: 32px 0; +} +.api-card { + display: block; + border: 1px solid var(--api-line); + border-radius: 10px; + padding: 26px; +} +.api-card:hover { + background: var(--api-selected); + border-color: var(--api-link); + text-decoration: none !important; +} +.api-card h2 { + margin: 12px 0; + color: var(--api-text); +} +.api-card p { + color: var(--api-muted); +} +.api-card > span:last-child { + display: inline-block; + margin-top: 10px; + font-size: 14px; +} +.api-crumbs { + display: flex; + flex-wrap: wrap; + gap: 8px; + align-items: center; + color: var(--api-muted); + font-size: 13px; + margin-bottom: 12px; +} +.api-crumbs a { + color: var(--api-muted); +} +.api-tools { + display: flex; + flex-wrap: wrap; + gap: 12px 24px; + align-items: center; + font-size: 13px; + padding-bottom: 20px; + border-bottom: 1px solid var(--api-line); +} +.api-tools > label { + margin-right: auto; +} +.api-reference label { + font-size: 13px; + color: var(--api-muted); +} +.api-reference select, +.api-reference input { + border: 1px solid var(--api-line); + border-radius: 6px; + background: var(--api-paper); + padding: 8px 10px; + color: var(--api-text); + font: inherit; + font-size: 14px; + max-width: 100%; +} +.api-reference select { + margin-left: 8px; +} +.api-reference input::placeholder { + color: var(--api-muted); +} +.api-connection { + max-width: 72ch; + margin: 32px 0; +} +.api-filter-label { + display: block; + margin: 16px 0 24px; +} +.api-filter-label input { + display: block; + width: 100%; + max-width: 36rem; + margin: 8px 0; +} +.api-operation-row { + display: grid; + grid-template-columns: 64px minmax(0, 1.2fr) minmax(0, 1fr); + align-items: start; + gap: 16px; + padding: 16px 8px; + border-bottom: 1px solid var(--api-line); + font-size: 14px; +} +.api-operation-row > span:last-child { + color: var(--api-muted); +} +.api-operation-row:hover { + background: var(--api-selected); + text-decoration: none !important; +} +.api-method { + display: inline-block; + font-size: 11px; + font-weight: 650; + background: var(--api-selected); + color: var(--api-link); + border-radius: 4px; + padding: 4px 8px; + line-height: 1.5; + white-space: nowrap; + width: fit-content; + flex-shrink: 0; +} +.api-method[data-method="POST"] { + background: #ebf9ee; + color: #216e4b; +} +.api-method[data-method="DELETE"] { + background: #fff0ef; + color: #ad3039; +} +.api-method[data-method="PATCH"], +.api-method[data-method="PUT"] { + background: #fff5e0; + color: #865514; +} +.dark .api-method[data-method="POST"] { + background: #173728; + color: #a9e5bd; +} +.dark .api-method[data-method="DELETE"] { + background: #3d2229; + color: #f5b6b6; +} +.dark .api-method[data-method="PATCH"], +.dark .api-method[data-method="PUT"] { + background: #392e1c; + color: #edcd96; +} +.api-signature { + display: flex; + align-items: baseline; + gap: 14px; + background: var(--api-surface); + border: 1px solid var(--api-line); + border-radius: 6px; + padding: 14px 18px; + margin: 0 0 28px; +} +.api-signature code { + font-size: 14px; +} +.api-operation-grid { + display: grid; + grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); + gap: 40px; + align-items: start; +} +.api-reading { + min-width: 0; +} +.api-description { + margin-bottom: 32px; +} +.api-description:empty { + display: none; +} +.api-request { + position: sticky; + top: 88px; + max-height: calc(100dvh - 112px); + overflow: auto; + min-width: 0; + border: 1px solid var(--api-line); + border-radius: 8px; + padding: 20px; + background: var(--api-surface); + font-size: 13px; + line-height: 1.65; +} +.api-request-heading { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; +} +.api-request-heading h2 { + margin: 0; + font-size: 15px; + letter-spacing: 0; +} +.api-request-heading > span { + color: var(--api-muted); + font-size: 12px; +} +.api-request > p { + color: var(--api-muted); + margin: 12px 0; +} +.api-request pre { + background: var(--api-paper); + padding: 16px; + white-space: pre-wrap; + overflow-wrap: anywhere; +} +.api-request pre code { + word-break: break-all; +} +.api-request button { + border: 1px solid var(--api-line); + background: var(--api-paper); + color: var(--api-text); + padding: 7px 12px; + border-radius: 5px; + font-size: 13px; + font-weight: 500; + cursor: pointer; +} +.api-request button:hover { + border-color: var(--api-link); + color: var(--api-link); +} +.api-source-details { + border-top: 1px solid var(--api-line); + margin-top: 16px; + padding-top: 8px; +} +.api-field { + border-top: 1px solid var(--api-line); + padding: 16px 0; + margin: 0; +} +.api-field h3 { + display: flex; + flex-wrap: wrap; + gap: 10px; + align-items: baseline; + margin: 0 0 10px; +} +.api-field h3 code, +.api-field > summary code { + color: var(--api-text); + font-weight: 500; +} +.api-field small { + font-size: 12px; + font-weight: 400; + color: var(--api-muted); +} +.api-field .api-required { + color: var(--api-text); + font-size: 12px; +} +.api-field .api-field { + border-top: 0; + border-left: 1px solid var(--api-line); + margin: 12px 0 0 4px; + padding: 0 0 0 16px; +} +.api-type, +.api-ref, +.api-constraints { + font-size: 13px; + color: var(--api-muted); +} +.api-variant { + border-top: 1px solid var(--api-line); + margin-top: 24px; + padding-top: 20px; +} +.api-variant > h3 { + display: flex; + gap: 10px; + align-items: baseline; + margin-top: 0; +} +.api-status { + border: 1px solid var(--api-line); + padding: 1px 6px; + border-radius: 4px; +} +.api-media { + color: var(--api-muted); +} +.api-schema-links { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); + gap: 0 28px; + margin: 0; + padding: 0; + list-style: none; +} +.api-schema-links li { + min-width: 0; + border-bottom: 1px solid var(--api-line); +} +.api-schema-links a { + display: flex; + align-items: center; + height: 100%; + min-height: 44px; + padding: 10px 8px; +} +.api-schema-links a:hover { + background: var(--api-selected); +} +.api-nav { + padding: 20px 8px; + font-size: 14px; + line-height: 1.5; +} +.api-nav a { + display: block; + padding: 7px 10px; + margin: 2px 0; + color: var(--api-muted); +} +.api-nav a:hover { + color: var(--api-link); + background: var(--api-selected); +} +.api-nav a[aria-current="page"] { + background: var(--api-selected); + color: var(--api-link); + font-weight: 500; + box-shadow: inset 2px 0 var(--api-link); +} +.api-nav h2 { + font-size: 16px; + font-weight: 550; + margin: 24px 10px 4px; +} +.api-nav .api-nav-version { + color: var(--api-muted); + font-size: 13px; + margin: 0 10px 16px; +} +.api-nav h3 { + font-size: 13px; + font-weight: 550; + margin: 26px 10px 8px; +} +.api-nav .api-nav-operation { + display: grid; + grid-template-columns: 42px minmax(0, 1fr); + gap: 8px; + align-items: baseline; +} +.api-nav small { + font-size: 11px; + font-weight: 600; + color: var(--api-link); +} +.api-nav small[data-method="POST"] { + color: #216e4b; +} +.api-nav small[data-method="DELETE"] { + color: #ad3039; +} +.api-nav small[data-method="PATCH"], +.api-nav small[data-method="PUT"] { + color: #865514; +} +.dark .api-nav small[data-method="POST"] { + color: #a9e5bd; +} +.dark .api-nav small[data-method="DELETE"] { + color: #f5b6b6; +} +.dark .api-nav small[data-method="PATCH"], +.dark .api-nav small[data-method="PUT"] { + color: #edcd96; +} +.api-nav .api-nav-back { + font-size: 13px; + color: var(--api-link); +} +.api-reference [hidden] { + display: none !important; +} +.api-reference[data-api-view="schema"] > .prose { + margin-bottom: 24px; +} +.api-reference[data-api-view="schema"] > .api-field { + max-width: 80ch; +} +@media (max-width: 1199px) { + .api-operation-grid { + grid-template-columns: 1fr; + gap: 28px; + } + .api-request { + position: static; + max-height: none; + overflow: visible; + grid-row: 1; + } +} +@media (max-width: 767px) { + main > div:has(> .api-reference) { + padding: 24px 20px; + } + .api-cards { + grid-template-columns: 1fr; + } + .api-reference h1 { + font-size: 28px; + } + .api-operation-row { + grid-template-columns: 56px minmax(0, 1fr); + gap: 6px 12px; + } + .api-operation-row > span:last-child { + grid-column: 2; + } + .api-tools { + gap: 14px 20px; + } + .api-tools > label { + flex-basis: 100%; + } + .api-signature { + padding: 12px; + gap: 10px; + } + .api-signature code { + font-size: 13px; + } + .api-request { + padding: 16px; + } +} diff --git a/assets/api-reference/reference.js b/assets/api-reference/reference.js new file mode 100644 index 000000000000..244fff83f8d8 --- /dev/null +++ b/assets/api-reference/reference.js @@ -0,0 +1,65 @@ +document.querySelectorAll("[data-api-version]").forEach((select) => + select.addEventListener("change", () => { + location.href = select.value; + }), +); +document.querySelectorAll("[data-api-filter]").forEach((input) => + input.addEventListener("input", () => { + const term = input.value.toLocaleLowerCase(); + document.querySelectorAll("[data-api-filter-item]").forEach((row) => { + row.hidden = !row.textContent.toLocaleLowerCase().includes(term); + }); + }), +); +document.querySelectorAll("[data-api-copy]").forEach((button) => + button.addEventListener("click", async () => { + try { + await navigator.clipboard.writeText( + button.parentElement.querySelector("[data-api-copy-source]") + .textContent, + ); + button.textContent = "Copied"; + } catch { + button.textContent = "Select and copy the request"; + } + }), +); +document.querySelectorAll("[data-api-example-select]").forEach((select) => { + const update = () => + select + .closest("[data-api-examples]") + .querySelectorAll("[data-api-example]") + .forEach((example) => { + example.hidden = example.dataset.apiExample !== select.value; + }); + select.addEventListener("change", update); + update(); +}); + +document.querySelectorAll("[data-api-media-select]").forEach((select) => + select.addEventListener("change", () => { + document.querySelectorAll("[data-api-media]").forEach((variant) => { + variant.hidden = Boolean( + select.value && + variant.dataset.apiMedia && + select.value !== variant.dataset.apiMedia, + ); + }); + }), +); + +// Resolve historical single-page fragments using generated, same-origin links. +function resolveLegacyFragment() { + let fragment; + try { + fragment = decodeURIComponent(location.hash.slice(1)); + } catch { + return; + } + const target = document.getElementById(fragment); + if (target?.hasAttribute("data-api-legacy-fragment")) { + location.replace(target.href); + } +} +resolveLegacyFragment(); +window.addEventListener("hashchange", resolveLegacyFragment); diff --git a/content/reference/api/_content.gotmpl b/content/reference/api/_content.gotmpl new file mode 100644 index 000000000000..d229e946d87a --- /dev/null +++ b/content/reference/api/_content.gotmpl @@ -0,0 +1,22 @@ +{{- $data := index hugo.Data "api-reference" -}} +{{- if not $data }} + {{ errorf "API reference data missing: run ./hack/api-docs/run.sh generate before Hugo" }} +{{ end -}} +{{- if ne (int $data.modelVersion) 1 }} + {{ errorf "Unsupported API presentation model version" }} +{{ end -}} +{{- .AddPage (dict "path" "." "kind" "section" "title" "Docker APIs" "linkTitle" "API reference" "description" "Explore Docker HTTP APIs, connection requirements, and versioned references." "layout" "api-docs" "params" (dict "view" "catalog" "keywords" (slice "API" "HTTP" "OpenAPI"))) -}} +{{- range $api := $data.apis -}} + {{- $path := strings.TrimPrefix "/reference/api/" $api.url | strings.TrimSuffix "/" -}} + {{- $aliases := slice -}} + {{- if eq $api.id "dvp" }} + {{ $aliases = slice "/reference/api/hub/dvp/" }} + {{ end -}} + {{- $.AddPage (dict "linkTitle" "Latest" "path" $path "url" $api.url "aliases" $aliases "kind" "section" "title" (printf "%s API %v" $api.title $api.version) "description" (printf "%s HTTP API reference, version %v." $api.title $api.version) "layout" "api-docs" "params" (dict "view" "overview" "apiID" $api.id "keywords" (slice "API" $api.product))) -}} + {{- range $op := $api.operations -}} + {{- $.AddPage (dict "path" (printf "%s/operations/%s" $path (crypto.SHA256 $op.id)) "url" $op.url "title" $op.summary "description" (printf "%s %s — %s API %v." $op.method $op.path $api.title $api.version) "layout" "api-docs" "params" (dict "view" "operation" "apiID" $api.id "operationID" $op.id "keywords" (slice $op.method $op.path $op.id))) -}} + {{- end -}} + {{- range $schema := $api.schemas -}} + {{- $.AddPage (dict "path" (printf "%s/schemas/%s" $path (crypto.SHA256 $schema.name)) "url" $schema.url "title" $schema.name "description" (printf "%s schema in %s API %v." $schema.name $api.title $api.version) "layout" "api-docs" "params" (dict "view" "schema" "apiID" $api.id "schemaName" $schema.name "keywords" (slice "schema" $schema.name))) -}} + {{- end -}} +{{- end -}} diff --git a/content/reference/api/_index.md b/content/reference/api/_index.md deleted file mode 100644 index 53ae13d37bd4..000000000000 --- a/content/reference/api/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: API reference -build: - render: never ---- - diff --git a/content/reference/api/dvp/latest.md b/content/reference/api/dvp/latest.md deleted file mode 100644 index 1ef4fdf075ba..000000000000 --- a/content/reference/api/dvp/latest.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -layout: api -description: Reference documentation and Swagger (OpenAPI) specification for the Docker Verified Publisher API. -title: Docker Verified Publisher API reference -linkTitle: Latest -weight: 1 -aliases: - - /reference/api/hub/dvp/ ---- diff --git a/content/reference/api/hub/latest.md b/content/reference/api/hub/latest.md deleted file mode 100644 index 15fd57a3db7f..000000000000 --- a/content/reference/api/hub/latest.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -layout: api -description: Reference documentation and Swagger (OpenAPI) specification for the Docker Hub API. -title: Docker Hub API reference -linkTitle: Latest -weight: 1 ---- diff --git a/content/reference/api/registry/latest.md b/content/reference/api/registry/latest.md deleted file mode 100644 index 7df6e5971659..000000000000 --- a/content/reference/api/registry/latest.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -layout: api -title: Supported registry API for Docker Hub -linktitle: Latest -description: "Supported registry API endpoints." -keywords: registry, on-prem, images, tags, repository, distribution, api, advanced ---- diff --git a/hack/api-docs/README.md b/hack/api-docs/README.md new file mode 100644 index 000000000000..5e3eed6741e3 --- /dev/null +++ b/hack/api-docs/README.md @@ -0,0 +1,75 @@ +# API reference build + +This tool validates the Hub, DVP, and Registry OpenAPI sources in +`content/reference/api/` and generates presentation data for Hugo. Engine and +AI Governance retain their existing sources and renderers. + +## Commands + +Use the Go version declared in `go.mod`, Hugo, and the site's Node dependencies. +From the repository root: + +```console +$ npm ci +$ ./hack/api-docs/run.sh test +$ ./hack/api-docs/run.sh generate +$ hugo server +``` + +For a static build with HTML/Markdown checks, run +`./hack/api-docs/run.sh build`. To serve that build on port 1314, run +`./hack/api-docs/run.sh serve`. Set `DOCS_URL` and `DOCS_PORT` when using another +address. Run generation again after changing a specification or catalog entry. + +Docker builds and Netlify deploy previews run generation before Hugo. Generated +data, validation reports, binaries, and local builds go under `tmp/api-reference/`. +Hugo reports an error if the generated data is absent. + +## Pipeline + +1. Parse the authoritative YAML with `libopenapi` and preserve source values and + reference identities. Verify locked OpenAPI dialect resources. +2. Run Vacuum policy checks and JSON Schema validation of schemas and supplied + examples, followed by documentation profile checks. +3. Generate presentation model version 1: operations, effective security and + servers, parameters, media variants, examples, schema links, and provenance. +4. Render HTML and Markdown through the content adapter and `api-docs` templates. +5. Preserve API Markdown examples during site processing and check generated + operation, parameter, media, schema, and link coverage. + +The published YAML URLs still serve the source files directly. There is no +conversion step, snapshot dependency, Node migration package, or source archive +in the build. Historical conversion evidence lives in [adoption](adoption/README.md). + +## Validation baseline + +`check` is strict and reports every documentation profile failure: + +```console +$ ./hack/api-docs/run.sh check +``` + +Generation explicitly uses `--allow-known-issues`. The checked-in +`known-issues.json` records 289 inherited issues: 268 for Hub, 17 for DVP, and +four for Registry. Entries match the entire source digest, diagnostic digest, +rule, and source pointer. Parse failures, unresolved references, and unsupported +features cannot be waived. Unrecorded diagnostics fail the build. + +This baseline is review debt, not approval of API behavior. Strict validation +fails until the issues are resolved. Any source edit requires deliberate review +of the affected baseline entries; the build never refreshes them automatically. +Product decisions listed in the adoption record remain merge blockers for this +draft implementation. + +## Tests and scope + +Go fixtures cover dialects, references, recursion, boolean schemas, examples, +security overrides, server and parameter precedence, and request generation. +`verify-output.mjs` checks all 181 generated HTML/Markdown pairs and retention of +Engine v1.40–v1.56 in ReDoc, unchanged Governance rendering, and byte-identical +published specifications. `browser-checks.mjs` exports a Playwright check for +navigation, legacy fragments, filtering, requests, and narrow screens. + +Callbacks and webhook navigation are unsupported and fail validation. Request +examples are POSIX shell templates; they do not make service calls. Specification +conversion and source-owner adoption remain separate from page rendering. diff --git a/hack/api-docs/adoption/README.md b/hack/api-docs/adoption/README.md new file mode 100644 index 000000000000..b9e24ec5ea79 --- /dev/null +++ b/hack/api-docs/adoption/README.md @@ -0,0 +1,34 @@ +# Local API source adoption + +This directory preserves the source-review evidence from +[the API documentation prototype](https://github.com/docker/docs/pull/26043). +The sibling implementation reads the authoritative local files directly. +No migration scripts or duplicate source snapshots are required to build it. + +The JSON ledgers retain before/after values, source pointers, classifications, +evidence, and stable change IDs. Textual patches show the original conversions. +`source-lock.json` identifies the baseline revision and source digests. Historical +profile names and paths in these records describe that conversion, rather than +runtime inputs. Keep these records unchanged when making subsequent corrections; +record those corrections in separate reviewed commits. + +| API | Recorded changes | Review before merge | +| --- | ---: | --- | +| [Hub](hub.json) | 157 | Confirm the provisional `team_repo` response schema. Review requiredness corrections, assigned operation IDs, and the inherited example mismatches. Preserve separate SCIM credentials. | +| [DVP](dvp.json) | 14 | Confirm operation-level security matches service behavior and the documented legacy login flow remains supported. Preserve authentication server overrides. | +| [Registry](registry.json) | 7 | Confirm `info.version: 2` and the bearer security declaration, including anonymous access alternatives. | + +The runtime validation baseline is in `../known-issues.json`. Its 289 entries +remain visible in generated validation reports, without exposing migration +administration in reference pages. Resolve or explicitly approve the remaining +quality debt before production adoption. Contract assumptions require product +evidence; accepting documentation debt does not confirm those assumptions. + +Published YAML retains its URL but changes to OpenAPI 3.2. Consumers of the YAML +must be considered before release: URL compatibility does not imply parser +compatibility. Existing page URLs, the DVP alias, and operation/tag/schema +fragment links remain supported. JavaScript follows historical operation +fragments to individual pages; without it, the overview supplies ordinary links. + +Engine and Governance migration, historical Engine conversion, SDK catalogs, +and broader site information architecture are outside this implementation. diff --git a/hack/api-docs/adoption/source-lock.json b/hack/api-docs/adoption/source-lock.json new file mode 100644 index 000000000000..239f8b20bc97 --- /dev/null +++ b/hack/api-docs/adoption/source-lock.json @@ -0,0 +1,53 @@ +{ + "revision": "371255294cf8db2ee20206bf5cc9c165a3a1ea16", + "tools": { + "swagger2openapi": "7.0.8", + "yaml": "2.8.1", + "libopenapi": "0.38.7", + "vacuum": "0.30.3", + "jsonschema": "6.0.3", + "oasdiff": "1.31.0" + }, + "sources": [ + { + "id": "hub", + "product": "hub", + "title": "Docker Hub", + "source": "content/reference/api/hub/latest.yaml", + "owner": "docker/docs (product authority to confirm)", + "manual": "/manuals/docker-hub/", + "connection": "hosted", + "auth": "Use the documented Hub token exchange. SCIM operations use a separate provisioning token.", + "guides": [ + "/manuals/security/provisioning/scim/provision-scim.md" + ], + "sha256": "aeefa9b62b10d70f9e28e9508d5a4c1361e0a541e209ff0af9ed2544b0cb415e" + }, + { + "id": "dvp", + "product": "dvp", + "title": "Publisher analytics", + "source": "content/reference/api/dvp/latest.yaml", + "owner": "docker/docs (product authority to confirm)", + "manual": "/manuals/docker-hub/repos/manage/trusted-content/insights-analytics.md", + "connection": "hosted", + "auth": "Analytics calls use a bearer token. The copied source retains the legacy login flow pending product confirmation.", + "guides": [], + "sha256": "4aeacaaa1237609c3dd9cec43f9807a229ac98a0e9b837f291c02df3cf89172a" + }, + { + "id": "registry", + "product": "registry", + "title": "Registry", + "source": "content/reference/api/registry/latest.yaml", + "owner": "docker/docs (product authority to confirm)", + "manual": "/manuals/docker-hub/repos/", + "connection": "hosted", + "auth": "Follow the WWW-Authenticate challenge and obtain a repository-scoped registry token. This is separate from the Hub API token exchange.", + "guides": [ + "/reference/api/registry/auth.md" + ], + "sha256": "229198e078ee30400c0359311f5baaf23a1f80563a1c2e82834f17f2db0d9fd1" + } + ] +} diff --git a/hack/api-docs/browser-checks.mjs b/hack/api-docs/browser-checks.mjs new file mode 100644 index 000000000000..7f3b846521f0 --- /dev/null +++ b/hack/api-docs/browser-checks.mjs @@ -0,0 +1,106 @@ +// Run with a Playwright Page against a built site; no product API calls. +export default async function verify(page, base = "http://localhost:1314") { + const results = []; + const assert = (condition, message) => { + if (!condition) throw Error(message); + results.push(message); + }; + await page.setViewportSize({ width: 1440, height: 1000 }); + await page.goto(base + "/reference/api/"); + assert( + (await page.locator(".api-card").count()) === 5, + "Five API catalog entries", + ); + assert( + (await page.locator("nav.navbar-font").count()) === 1, + "Catalog retains Reference sidebar", + ); + await page.goto(base + "/reference/api/dvp/latest/"); + assert( + (await page.locator(".api-nav").count()) === 1 && + (await page.locator("nav.navbar-font").count()) === 0, + "Reference uses local navigation", + ); + const first = page.locator("[data-api-filter-item]").first(); + const operationURL = await first.getAttribute("href"); + const operationID = operationURL.split("/").filter(Boolean).at(-1); + await page.goto(base + "/reference/api/hub/dvp/#operation/" + operationID); + await page.waitForURL("**" + operationURL); + assert( + page.url().endsWith(operationURL), + "DVP alias preserves legacy operation fragment", + ); + await page.context().grantPermissions(["clipboard-read", "clipboard-write"]); + const copy = page.locator("[data-api-copy]"); + await copy.focus(); + await page.keyboard.press("Enter"); + await page.waitForFunction( + () => document.querySelector("[data-api-copy]").textContent === "Copied", + ); + assert( + (await page.evaluate(() => navigator.clipboard.readText())).includes( + "curl", + ), + "Keyboard copies a request", + ); + await page.locator(".api-nav-back").focus(); + await page.keyboard.press("Enter"); + await page.waitForURL("**/reference/api/"); + assert( + (await page.locator("nav.navbar-font").count()) === 1, + "Keyboard back link restores catalog", + ); + await page.goto(base + "/reference/api/hub/latest/"); + await page.locator("[data-api-filter]").fill("token"); + const rows = page.locator("[data-api-filter-item]:visible"); + assert( + (await rows.count()) > 0 && + (await rows.allTextContents()).every((x) => + x.toLowerCase().includes("token"), + ), + "Operation filtering", + ); + const schemaURL = await page + .locator(".api-schema-links a") + .first() + .getAttribute("href"); + await page.goto(base + schemaURL); + assert( + (await page.locator('[data-api-view="schema"]').count()) === 1, + "Linked schema page", + ); + await page.setViewportSize({ width: 390, height: 844 }); + await page.goto(base + operationURL); + assert( + await page.evaluate( + () => document.documentElement.scrollWidth <= innerWidth + 1, + ), + "No narrow-screen document overflow", + ); + await page.goto(base + "/reference/api/engine/version/v1.56/"); + assert( + (await page.locator("redoc").count()) === 1, + "Latest Engine retains ReDoc", + ); + await page.goto(base + "/reference/api/ai-governance/"); + assert( + (await page.locator("[data-api-view]").count()) === 0 && + (await page.locator("h1").count()) > 0, + "Governance retains existing renderer", + ); + const context = await page + .context() + .browser() + .newContext({ javaScriptEnabled: false }); + try { + const staticPage = await context.newPage(); + await staticPage.goto(base + operationURL); + assert( + (await staticPage.locator("[data-api-copy-source]").count()) === 1, + "Request content exists without JavaScript", + ); + } finally { + await context.close(); + } + return results; +} diff --git a/hack/api-docs/catalog.json b/hack/api-docs/catalog.json new file mode 100644 index 000000000000..0623cc62a5e6 --- /dev/null +++ b/hack/api-docs/catalog.json @@ -0,0 +1,54 @@ +{ + "modelVersion": 1, + "profileVersion": "docker-docs-1", + "dialect": "https://spec.openapis.org/oas/3.1/dialect/base", + "apis": [ + { + "id": "hub", + "product": "hub", + "title": "Docker Hub", + "source": "content/reference/api/hub/latest.yaml", + "owner": "docker/docs", + "manual": "/manuals/docker-hub/", + "connection": "hosted", + "auth": "Use the documented Hub token exchange. SCIM operations use a separate provisioning token.", + "guides": ["/manuals/security/provisioning/scim/provision-scim.md"] + }, + { + "id": "dvp", + "product": "dvp", + "title": "Publisher analytics", + "source": "content/reference/api/dvp/latest.yaml", + "owner": "docker/docs", + "manual": "/manuals/docker-hub/repos/manage/trusted-content/insights-analytics.md", + "connection": "hosted", + "auth": "Analytics calls use a bearer token. The authentication operations use the Docker Hub server shown in their reference.", + "guides": [] + }, + { + "id": "registry", + "product": "registry", + "title": "Registry", + "source": "content/reference/api/registry/latest.yaml", + "owner": "docker/docs", + "manual": "/manuals/docker-hub/repos/", + "connection": "hosted", + "auth": "Follow the WWW-Authenticate challenge and obtain a repository-scoped registry token. This is separate from the Hub API token exchange.", + "guides": ["/reference/api/registry/auth.md"] + } + ], + "legacyAPIs": [ + { + "title": "AI Governance", + "url": "/reference/api/ai-governance/", + "connection": "hosted", + "description": "Organization policy and access controls." + }, + { + "title": "Docker Engine", + "url": "/reference/api/engine/", + "connection": "unix", + "description": "Manage containers, images, networks, and volumes." + } + ] +} diff --git a/hack/api-docs/dialects/lock.json b/hack/api-docs/dialects/lock.json new file mode 100644 index 000000000000..7fb2c1b1cdad --- /dev/null +++ b/hack/api-docs/dialects/lock.json @@ -0,0 +1,20 @@ +[ + { + "file": "oas-dialect.json", + "uri": "https://spec.openapis.org/oas/3.1/dialect/base", + "resolvedURL": "https://spec.openapis.org/oas/3.1/dialect/base", + "sha256": "8a0e89e365dadbebce2921ce6244340c1090e9d544c60d977e9ad6b97a61227b" + }, + { + "file": "oas-vocabulary.json", + "uri": "https://spec.openapis.org/oas/3.1/meta/base", + "resolvedURL": "https://spec.openapis.org/oas/3.1/meta/base", + "sha256": "267a88226e64e96dfc8c89dbd7e863160c84715e0fb893ca1d9fbf9f830f1f54" + }, + { + "file": "oas-document.json", + "uri": "https://spec.openapis.org/oas/3.2/schema/2025-09-17", + "resolvedURL": "https://spec.openapis.org/oas/3.2/schema/2025-09-17", + "sha256": "0c9d74bf25f9b9388b2d81e421ef60fdefa9feffa94898dadfc501b342b3bfcc" + } +] diff --git a/hack/api-docs/dialects/oas-dialect.json b/hack/api-docs/dialects/oas-dialect.json new file mode 100644 index 000000000000..eae8386e8ad3 --- /dev/null +++ b/hack/api-docs/dialects/oas-dialect.json @@ -0,0 +1,25 @@ +{ + "$id": "https://spec.openapis.org/oas/3.1/dialect/base", + "$schema": "https://json-schema.org/draft/2020-12/schema", + + "title": "OpenAPI 3.1 Schema Object Dialect", + "description": "A JSON Schema dialect describing schemas found in OpenAPI documents", + + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/core": true, + "https://json-schema.org/draft/2020-12/vocab/applicator": true, + "https://json-schema.org/draft/2020-12/vocab/unevaluated": true, + "https://json-schema.org/draft/2020-12/vocab/validation": true, + "https://json-schema.org/draft/2020-12/vocab/meta-data": true, + "https://json-schema.org/draft/2020-12/vocab/format-annotation": true, + "https://json-schema.org/draft/2020-12/vocab/content": true, + "https://spec.openapis.org/oas/3.1/vocab/base": false + }, + + "$dynamicAnchor": "meta", + + "allOf": [ + { "$ref": "https://json-schema.org/draft/2020-12/schema" }, + { "$ref": "https://spec.openapis.org/oas/3.1/meta/base" } + ] +} diff --git a/hack/api-docs/dialects/oas-document.json b/hack/api-docs/dialects/oas-document.json new file mode 100644 index 000000000000..9453eeb20bec --- /dev/null +++ b/hack/api-docs/dialects/oas-document.json @@ -0,0 +1,1666 @@ +{ + "$id": "https://spec.openapis.org/oas/3.2/schema/2025-09-17", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "The description of OpenAPI v3.2.x Documents without Schema Object validation", + "type": "object", + "properties": { + "openapi": { + "type": "string", + "pattern": "^3\\.2\\.\\d+(-.+)?$" + }, + "$self": { + "type": "string", + "format": "uri-reference", + "$comment": "MUST NOT contain a fragment", + "pattern": "^[^#]*$" + }, + "info": { + "$ref": "#/$defs/info" + }, + "jsonSchemaDialect": { + "type": "string", + "format": "uri-reference", + "default": "https://spec.openapis.org/oas/3.2/dialect/2025-09-17" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/$defs/server" + }, + "default": [ + { + "url": "/" + } + ] + }, + "paths": { + "$ref": "#/$defs/paths" + }, + "webhooks": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/path-item" + } + }, + "components": { + "$ref": "#/$defs/components" + }, + "security": { + "type": "array", + "items": { + "$ref": "#/$defs/security-requirement" + } + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/$defs/tag" + } + }, + "externalDocs": { + "$ref": "#/$defs/external-documentation" + } + }, + "required": [ + "openapi", + "info" + ], + "anyOf": [ + { + "required": [ + "paths" + ] + }, + { + "required": [ + "components" + ] + }, + { + "required": [ + "webhooks" + ] + } + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false, + "$defs": { + "info": { + "$comment": "https://spec.openapis.org/oas/v3.2#info-object", + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "termsOfService": { + "type": "string", + "format": "uri-reference" + }, + "contact": { + "$ref": "#/$defs/contact" + }, + "license": { + "$ref": "#/$defs/license" + }, + "version": { + "type": "string" + } + }, + "required": [ + "title", + "version" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "contact": { + "$comment": "https://spec.openapis.org/oas/v3.2#contact-object", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri-reference" + }, + "email": { + "type": "string", + "format": "email" + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "license": { + "$comment": "https://spec.openapis.org/oas/v3.2#license-object", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri-reference" + } + }, + "required": [ + "name" + ], + "dependentSchemas": { + "identifier": { + "not": { + "required": [ + "url" + ] + } + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "server": { + "$comment": "https://spec.openapis.org/oas/v3.2#server-object", + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "variables": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/server-variable" + } + } + }, + "required": [ + "url" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "server-variable": { + "$comment": "https://spec.openapis.org/oas/v3.2#server-variable-object", + "type": "object", + "properties": { + "enum": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1 + }, + "default": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "default" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "components": { + "$comment": "https://spec.openapis.org/oas/v3.2#components-object", + "type": "object", + "properties": { + "schemas": { + "type": "object", + "additionalProperties": { + "$dynamicRef": "#meta" + } + }, + "responses": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/response-or-reference" + } + }, + "parameters": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/parameter-or-reference" + } + }, + "examples": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/example-or-reference" + } + }, + "requestBodies": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/request-body-or-reference" + } + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/header-or-reference" + } + }, + "securitySchemes": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/security-scheme-or-reference" + } + }, + "links": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/link-or-reference" + } + }, + "callbacks": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/callbacks-or-reference" + } + }, + "pathItems": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/path-item" + } + }, + "mediaTypes": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/media-type-or-reference" + } + } + }, + "patternProperties": { + "^(?:schemas|responses|parameters|examples|requestBodies|headers|securitySchemes|links|callbacks|pathItems|mediaTypes)$": { + "$comment": "Enumerating all of the property names in the regex above is necessary for unevaluatedProperties to work as expected", + "propertyNames": { + "pattern": "^[a-zA-Z0-9._-]+$" + } + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "paths": { + "$comment": "https://spec.openapis.org/oas/v3.2#paths-object", + "type": "object", + "patternProperties": { + "^/": { + "$ref": "#/$defs/path-item" + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "path-item": { + "$comment": "https://spec.openapis.org/oas/v3.2#path-item-object", + "type": "object", + "properties": { + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/$defs/server" + } + }, + "parameters": { + "$ref": "#/$defs/parameters" + }, + "additionalOperations": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/operation" + }, + "propertyNames": { + "$comment": "RFC9110 restricts methods to \"1*tchar\" in ABNF", + "pattern": "^[a-zA-Z0-9!#$%&'*+.^_`|~-]+$", + "not": { + "enum": [ + "GET", + "PUT", + "POST", + "DELETE", + "OPTIONS", + "HEAD", + "PATCH", + "TRACE", + "QUERY" + ] + } + } + }, + "get": { + "$ref": "#/$defs/operation" + }, + "put": { + "$ref": "#/$defs/operation" + }, + "post": { + "$ref": "#/$defs/operation" + }, + "delete": { + "$ref": "#/$defs/operation" + }, + "options": { + "$ref": "#/$defs/operation" + }, + "head": { + "$ref": "#/$defs/operation" + }, + "patch": { + "$ref": "#/$defs/operation" + }, + "trace": { + "$ref": "#/$defs/operation" + }, + "query": { + "$ref": "#/$defs/operation" + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "operation": { + "$comment": "https://spec.openapis.org/oas/v3.2#operation-object", + "type": "object", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/$defs/external-documentation" + }, + "operationId": { + "type": "string" + }, + "parameters": { + "$ref": "#/$defs/parameters" + }, + "requestBody": { + "$ref": "#/$defs/request-body-or-reference" + }, + "responses": { + "$ref": "#/$defs/responses" + }, + "callbacks": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/callbacks-or-reference" + } + }, + "deprecated": { + "default": false, + "type": "boolean" + }, + "security": { + "type": "array", + "items": { + "$ref": "#/$defs/security-requirement" + } + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/$defs/server" + } + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "external-documentation": { + "$comment": "https://spec.openapis.org/oas/v3.2#external-documentation-object", + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri-reference" + } + }, + "required": [ + "url" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/$defs/parameter-or-reference" + }, + "not": { + "allOf": [ + { + "contains": { + "type": "object", + "properties": { + "in": { + "const": "query" + } + }, + "required": [ + "in" + ] + } + }, + { + "contains": { + "type": "object", + "properties": { + "in": { + "const": "querystring" + } + }, + "required": [ + "in" + ] + } + } + ] + }, + "contains": { + "type": "object", + "properties": { + "in": { + "const": "querystring" + } + }, + "required": [ + "in" + ] + }, + "minContains": 0, + "maxContains": 1 + }, + "parameter": { + "$comment": "https://spec.openapis.org/oas/v3.2#parameter-object", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "in": { + "enum": [ + "query", + "querystring", + "header", + "path", + "cookie" + ] + }, + "description": { + "type": "string" + }, + "required": { + "default": false, + "type": "boolean" + }, + "deprecated": { + "default": false, + "type": "boolean" + }, + "schema": { + "$dynamicRef": "#meta" + }, + "content": { + "$ref": "#/$defs/content", + "minProperties": 1, + "maxProperties": 1 + } + }, + "required": [ + "name", + "in" + ], + "oneOf": [ + { + "required": [ + "schema" + ] + }, + { + "required": [ + "content" + ] + } + ], + "allOf": [ + { + "$ref": "#/$defs/examples" + }, + { + "$ref": "#/$defs/specification-extensions" + }, + { + "if": { + "properties": { + "in": { + "const": "query" + } + } + }, + "then": { + "properties": { + "allowEmptyValue": { + "default": false, + "type": "boolean" + } + } + } + }, + { + "if": { + "properties": { + "in": { + "const": "querystring" + } + } + }, + "then": { + "required": [ + "content" + ] + } + } + ], + "dependentSchemas": { + "schema": { + "properties": { + "style": { + "type": "string" + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "default": false, + "type": "boolean" + } + }, + "allOf": [ + { + "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-path" + }, + { + "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-header" + }, + { + "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-query" + }, + { + "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-cookie" + }, + { + "$ref": "#/$defs/styles-for-form" + } + ], + "$defs": { + "styles-for-path": { + "if": { + "properties": { + "in": { + "const": "path" + } + } + }, + "then": { + "properties": { + "style": { + "default": "simple", + "enum": [ + "matrix", + "label", + "simple" + ] + }, + "required": { + "const": true + } + }, + "required": [ + "required" + ] + } + }, + "styles-for-header": { + "if": { + "properties": { + "in": { + "const": "header" + } + } + }, + "then": { + "properties": { + "style": { + "default": "simple", + "const": "simple" + } + } + } + }, + "styles-for-query": { + "if": { + "properties": { + "in": { + "const": "query" + } + } + }, + "then": { + "properties": { + "style": { + "default": "form", + "enum": [ + "form", + "spaceDelimited", + "pipeDelimited", + "deepObject" + ] + } + } + } + }, + "styles-for-cookie": { + "if": { + "properties": { + "in": { + "const": "cookie" + } + } + }, + "then": { + "properties": { + "style": { + "default": "form", + "enum": [ + "form", + "cookie" + ] + } + } + } + } + } + } + }, + "unevaluatedProperties": false + }, + "parameter-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/parameter" + } + }, + "request-body": { + "$comment": "https://spec.openapis.org/oas/v3.2#request-body-object", + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "content": { + "$ref": "#/$defs/content" + }, + "required": { + "default": false, + "type": "boolean" + } + }, + "required": [ + "content" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "request-body-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/request-body" + } + }, + "content": { + "$comment": "https://spec.openapis.org/oas/v3.2#fixed-fields-10", + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/media-type-or-reference" + }, + "propertyNames": { + "format": "media-range" + } + }, + "media-type": { + "$comment": "https://spec.openapis.org/oas/v3.2#media-type-object", + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "schema": { + "$dynamicRef": "#meta" + }, + "itemSchema": { + "$dynamicRef": "#meta" + }, + "encoding": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/encoding" + } + }, + "prefixEncoding": { + "type": "array", + "items": { + "$ref": "#/$defs/encoding" + } + }, + "itemEncoding": { + "$ref": "#/$defs/encoding" + } + }, + "dependentSchemas": { + "encoding": { + "properties": { + "prefixEncoding": false, + "itemEncoding": false + } + } + }, + "allOf": [ + { + "$ref": "#/$defs/examples" + }, + { + "$ref": "#/$defs/specification-extensions" + } + ], + "unevaluatedProperties": false + }, + "media-type-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/media-type" + } + }, + "encoding": { + "$comment": "https://spec.openapis.org/oas/v3.2#encoding-object", + "type": "object", + "properties": { + "contentType": { + "type": "string", + "format": "media-range" + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/header-or-reference" + } + }, + "style": { + "enum": [ + "form", + "spaceDelimited", + "pipeDelimited", + "deepObject" + ] + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "type": "boolean" + }, + "encoding": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/encoding" + } + }, + "prefixEncoding": { + "type": "array", + "items": { + "$ref": "#/$defs/encoding" + } + }, + "itemEncoding": { + "$ref": "#/$defs/encoding" + } + }, + "dependentSchemas": { + "encoding": { + "properties": { + "prefixEncoding": false, + "itemEncoding": false + } + }, + "style": { + "properties": { + "allowReserved": { + "default": false + } + } + }, + "explode": { + "properties": { + "style": { + "default": "form" + }, + "allowReserved": { + "default": false + } + } + }, + "allowReserved": { + "properties": { + "style": { + "default": "form" + } + } + } + }, + "allOf": [ + { + "$ref": "#/$defs/specification-extensions" + }, + { + "$ref": "#/$defs/styles-for-form" + } + ], + "unevaluatedProperties": false + }, + "responses": { + "$comment": "https://spec.openapis.org/oas/v3.2#responses-object", + "type": "object", + "properties": { + "default": { + "$ref": "#/$defs/response-or-reference" + } + }, + "patternProperties": { + "^[1-5](?:[0-9]{2}|XX)$": { + "$ref": "#/$defs/response-or-reference" + } + }, + "minProperties": 1, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false, + "if": { + "$comment": "either default, or at least one response code property must exist", + "patternProperties": { + "^[1-5](?:[0-9]{2}|XX)$": false + } + }, + "then": { + "required": [ + "default" + ] + } + }, + "response": { + "$comment": "https://spec.openapis.org/oas/v3.2#response-object", + "type": "object", + "properties": { + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/header-or-reference" + } + }, + "content": { + "$ref": "#/$defs/content" + }, + "links": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/link-or-reference" + } + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "response-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/response" + } + }, + "callbacks": { + "$comment": "https://spec.openapis.org/oas/v3.2#callback-object", + "type": "object", + "$ref": "#/$defs/specification-extensions", + "additionalProperties": { + "$ref": "#/$defs/path-item" + } + }, + "callbacks-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/callbacks" + } + }, + "example": { + "$comment": "https://spec.openapis.org/oas/v3.2#example-object", + "type": "object", + "properties": { + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dataValue": true, + "serializedValue": { + "type": "string" + }, + "value": true, + "externalValue": { + "type": "string", + "format": "uri-reference" + } + }, + "allOf": [ + { + "not": { + "required": [ + "value", + "externalValue" + ] + } + }, + { + "not": { + "required": [ + "value", + "dataValue" + ] + } + }, + { + "not": { + "required": [ + "value", + "serializedValue" + ] + } + }, + { + "not": { + "required": [ + "serializedValue", + "externalValue" + ] + } + } + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "example-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/example" + } + }, + "link": { + "$comment": "https://spec.openapis.org/oas/v3.2#link-object", + "type": "object", + "properties": { + "operationRef": { + "type": "string", + "format": "uri-reference" + }, + "operationId": { + "type": "string" + }, + "parameters": { + "$ref": "#/$defs/map-of-strings" + }, + "requestBody": true, + "description": { + "type": "string" + }, + "server": { + "$ref": "#/$defs/server" + } + }, + "oneOf": [ + { + "required": [ + "operationRef" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "link-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/link" + } + }, + "header": { + "$comment": "https://spec.openapis.org/oas/v3.2#header-object", + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "required": { + "default": false, + "type": "boolean" + }, + "deprecated": { + "default": false, + "type": "boolean" + }, + "schema": { + "$dynamicRef": "#meta" + }, + "content": { + "$ref": "#/$defs/content", + "minProperties": 1, + "maxProperties": 1 + } + }, + "oneOf": [ + { + "required": [ + "schema" + ] + }, + { + "required": [ + "content" + ] + } + ], + "dependentSchemas": { + "schema": { + "properties": { + "style": { + "default": "simple", + "const": "simple" + }, + "explode": { + "default": false, + "type": "boolean" + }, + "allowReserved": { + "default": false, + "type": "boolean" + } + } + } + }, + "allOf": [ + { + "$ref": "#/$defs/examples" + }, + { + "$ref": "#/$defs/specification-extensions" + } + ], + "unevaluatedProperties": false + }, + "header-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/header" + } + }, + "tag": { + "$comment": "https://spec.openapis.org/oas/v3.2#tag-object", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/$defs/external-documentation" + }, + "parent": { + "type": "string" + }, + "kind": { + "type": "string" + } + }, + "required": [ + "name" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "reference": { + "$comment": "https://spec.openapis.org/oas/v3.2#reference-object", + "type": "object", + "properties": { + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "schema": { + "$comment": "https://spec.openapis.org/oas/v3.2#schema-object", + "$dynamicAnchor": "meta", + "type": [ + "object", + "boolean" + ] + }, + "security-scheme": { + "$comment": "https://spec.openapis.org/oas/v3.2#security-scheme-object", + "type": "object", + "properties": { + "type": { + "enum": [ + "apiKey", + "http", + "mutualTLS", + "oauth2", + "openIdConnect" + ] + }, + "description": { + "type": "string" + }, + "deprecated": { + "default": false, + "type": "boolean" + } + }, + "required": [ + "type" + ], + "allOf": [ + { + "$ref": "#/$defs/specification-extensions" + }, + { + "$ref": "#/$defs/security-scheme/$defs/type-apikey" + }, + { + "$ref": "#/$defs/security-scheme/$defs/type-http" + }, + { + "$ref": "#/$defs/security-scheme/$defs/type-http-bearer" + }, + { + "$ref": "#/$defs/security-scheme/$defs/type-oauth2" + }, + { + "$ref": "#/$defs/security-scheme/$defs/type-oidc" + } + ], + "unevaluatedProperties": false, + "$defs": { + "type-apikey": { + "if": { + "properties": { + "type": { + "const": "apiKey" + } + } + }, + "then": { + "properties": { + "name": { + "type": "string" + }, + "in": { + "enum": [ + "query", + "header", + "cookie" + ] + } + }, + "required": [ + "name", + "in" + ] + } + }, + "type-http": { + "if": { + "properties": { + "type": { + "const": "http" + } + } + }, + "then": { + "properties": { + "scheme": { + "type": "string" + } + }, + "required": [ + "scheme" + ] + } + }, + "type-http-bearer": { + "if": { + "properties": { + "type": { + "const": "http" + }, + "scheme": { + "type": "string", + "pattern": "^[Bb][Ee][Aa][Rr][Ee][Rr]$" + } + }, + "required": [ + "type", + "scheme" + ] + }, + "then": { + "properties": { + "bearerFormat": { + "type": "string" + } + } + } + }, + "type-oauth2": { + "if": { + "properties": { + "type": { + "const": "oauth2" + } + } + }, + "then": { + "properties": { + "flows": { + "$ref": "#/$defs/oauth-flows" + }, + "oauth2MetadataUrl": { + "type": "string", + "format": "uri-reference" + } + }, + "required": [ + "flows" + ] + } + }, + "type-oidc": { + "if": { + "properties": { + "type": { + "const": "openIdConnect" + } + } + }, + "then": { + "properties": { + "openIdConnectUrl": { + "type": "string", + "format": "uri-reference" + } + }, + "required": [ + "openIdConnectUrl" + ] + } + } + } + }, + "security-scheme-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/security-scheme" + } + }, + "oauth-flows": { + "type": "object", + "properties": { + "implicit": { + "$ref": "#/$defs/oauth-flows/$defs/implicit" + }, + "password": { + "$ref": "#/$defs/oauth-flows/$defs/password" + }, + "clientCredentials": { + "$ref": "#/$defs/oauth-flows/$defs/client-credentials" + }, + "authorizationCode": { + "$ref": "#/$defs/oauth-flows/$defs/authorization-code" + }, + "deviceAuthorization": { + "$ref": "#/$defs/oauth-flows/$defs/device-authorization" + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false, + "$defs": { + "implicit": { + "type": "object", + "properties": { + "authorizationUrl": { + "type": "string", + "format": "uri-reference" + }, + "refreshUrl": { + "type": "string", + "format": "uri-reference" + }, + "scopes": { + "$ref": "#/$defs/map-of-strings" + } + }, + "required": [ + "authorizationUrl", + "scopes" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "password": { + "type": "object", + "properties": { + "tokenUrl": { + "type": "string", + "format": "uri-reference" + }, + "refreshUrl": { + "type": "string", + "format": "uri-reference" + }, + "scopes": { + "$ref": "#/$defs/map-of-strings" + } + }, + "required": [ + "tokenUrl", + "scopes" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "client-credentials": { + "type": "object", + "properties": { + "tokenUrl": { + "type": "string", + "format": "uri-reference" + }, + "refreshUrl": { + "type": "string", + "format": "uri-reference" + }, + "scopes": { + "$ref": "#/$defs/map-of-strings" + } + }, + "required": [ + "tokenUrl", + "scopes" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "authorization-code": { + "type": "object", + "properties": { + "authorizationUrl": { + "type": "string", + "format": "uri-reference" + }, + "tokenUrl": { + "type": "string", + "format": "uri-reference" + }, + "refreshUrl": { + "type": "string", + "format": "uri-reference" + }, + "scopes": { + "$ref": "#/$defs/map-of-strings" + } + }, + "required": [ + "authorizationUrl", + "tokenUrl", + "scopes" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "device-authorization": { + "type": "object", + "properties": { + "deviceAuthorizationUrl": { + "type": "string", + "format": "uri-reference" + }, + "tokenUrl": { + "type": "string", + "format": "uri-reference" + }, + "refreshUrl": { + "type": "string", + "format": "uri-reference" + }, + "scopes": { + "$ref": "#/$defs/map-of-strings" + } + }, + "required": [ + "deviceAuthorizationUrl", + "tokenUrl", + "scopes" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + } + } + }, + "security-requirement": { + "$comment": "https://spec.openapis.org/oas/v3.2#security-requirement-object", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "specification-extensions": { + "$comment": "https://spec.openapis.org/oas/v3.2#specification-extensions", + "patternProperties": { + "^x-": true + } + }, + "examples": { + "properties": { + "example": true, + "examples": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/example-or-reference" + } + } + }, + "not": { + "required": [ + "example", + "examples" + ] + } + }, + "map-of-strings": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "styles-for-form": { + "if": { + "properties": { + "style": { + "const": "form" + } + }, + "required": [ + "style" + ] + }, + "then": { + "properties": { + "explode": { + "default": true + } + } + }, + "else": { + "properties": { + "explode": { + "default": false + } + } + } + } + } +} diff --git a/hack/api-docs/dialects/oas-vocabulary.json b/hack/api-docs/dialects/oas-vocabulary.json new file mode 100644 index 000000000000..a7a59f1c7d13 --- /dev/null +++ b/hack/api-docs/dialects/oas-vocabulary.json @@ -0,0 +1,87 @@ +{ + "$id": "https://spec.openapis.org/oas/3.1/meta/base", + "$schema": "https://json-schema.org/draft/2020-12/schema", + + "title": "OAS Base vocabulary", + "description": "A JSON Schema Vocabulary used in the OpenAPI Schema Dialect", + + "$vocabulary": { + "https://spec.openapis.org/oas/3.1/vocab/base": true + }, + + "$dynamicAnchor": "meta", + + "type": ["object", "boolean"], + "properties": { + "example": true, + "discriminator": { "$ref": "#/$defs/discriminator" }, + "externalDocs": { "$ref": "#/$defs/external-docs" }, + "xml": { "$ref": "#/$defs/xml" } + }, + + "$defs": { + "extensible": { + "patternProperties": { + "^x-": true + } + }, + + "discriminator": { + "$ref": "#/$defs/extensible", + "type": "object", + "properties": { + "propertyName": { + "type": "string" + }, + "mapping": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "required": ["propertyName"], + "unevaluatedProperties": false + }, + + "external-docs": { + "$ref": "#/$defs/extensible", + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri-reference" + }, + "description": { + "type": "string" + } + }, + "required": ["url"], + "unevaluatedProperties": false + }, + + "xml": { + "$ref": "#/$defs/extensible", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string", + "format": "uri" + }, + "prefix": { + "type": "string" + }, + "attribute": { + "type": "boolean" + }, + "wrapped": { + "type": "boolean" + } + }, + "unevaluatedProperties": false + } + } +} diff --git a/hack/api-docs/flatten.mjs b/hack/api-docs/flatten.mjs new file mode 100644 index 000000000000..03ac5257cfee --- /dev/null +++ b/hack/api-docs/flatten.mjs @@ -0,0 +1,34 @@ +// The site postprocessor rewrites URL-like strings inside fenced JSON too. +// Keep generated reference Markdown intact; its links already target published URLs. +import fs from "node:fs"; +import path from "node:path"; +import { execFileSync } from "node:child_process"; +const root = path.resolve(import.meta.dirname, "../.."); +const site = path.resolve(process.argv[2] || "public"); +const data = JSON.parse( + fs.readFileSync(path.join(root, "tmp/api-reference/data/api-reference.json")), +); +const urls = [ + "/reference/api/", + ...data.apis.flatMap((api) => [ + api.url, + ...api.operations.map((op) => op.url), + ...api.schemas.map((schema) => schema.url), + ]), +]; +const saved = urls + .map((url) => path.join(site, url, "index.md")) + .map((p) => [p, fs.readFileSync(p)]); +for (const [p] of saved) fs.unlinkSync(p); +try { + execFileSync( + process.execPath, + [path.join(root, "hack/flatten-and-resolve.js"), site], + { stdio: "inherit" }, + ); +} finally { + for (const [p, b] of saved) { + const dest = path.basename(p) === "index.md" ? path.dirname(p) + ".md" : p; + fs.writeFileSync(dest, b); + } +} diff --git a/hack/api-docs/go.mod b/hack/api-docs/go.mod new file mode 100644 index 000000000000..6f45e2016a8f --- /dev/null +++ b/hack/api-docs/go.mod @@ -0,0 +1,18 @@ +module github.com/docker/docs/hack/api-docs + +go 1.26.5 + +require ( + github.com/pb33f/libopenapi v0.38.7 + github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 +) + +require ( + github.com/bahlo/generic-list-go v0.2.0 // indirect + github.com/buger/jsonparser v1.1.2 // indirect + github.com/pb33f/jsonpath v0.8.2 // indirect + github.com/pb33f/ordered-map/v2 v2.3.1 // indirect + go.yaml.in/yaml/v4 v4.0.0-rc.6 // indirect + golang.org/x/sync v0.22.0 // indirect + golang.org/x/text v0.14.0 // indirect +) diff --git a/hack/api-docs/go.sum b/hack/api-docs/go.sum new file mode 100644 index 000000000000..304e372c1e29 --- /dev/null +++ b/hack/api-docs/go.sum @@ -0,0 +1,30 @@ +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= +github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk= +github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= +github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/pb33f/jsonpath v0.8.2 h1:Ou4C7zjYClBm97dfZjDCjdZGusJoynv/vrtiEKNfj2Y= +github.com/pb33f/jsonpath v0.8.2/go.mod h1:zBV5LJW4OQOPatmQE2QdKpGQJvhDTlE5IEj6ASaRNTo= +github.com/pb33f/libopenapi v0.38.7 h1:Q2jfgRPdnU38WW8wQvrX2HEPGiqsxj01PX1BHmAEihc= +github.com/pb33f/libopenapi v0.38.7/go.mod h1:naZ03Auhn7i+RJtMv8ck8l7Ag8E2/x2w66j9vsDFL38= +github.com/pb33f/ordered-map/v2 v2.3.1 h1:5319HDO0aw4DA4gzi+zv4FXU9UlSs3xGZ40wcP1nBjY= +github.com/pb33f/ordered-map/v2 v2.3.1/go.mod h1:qxFQgd0PkVUtOMCkTapqotNgzRhMPL7VvaHKbd1HnmQ= +github.com/pb33f/testify v0.1.0 h1:g48/HDU/jn2COspS4nM0scptxiKTJ4DnbX/4ehK6IZ8= +github.com/pb33f/testify v0.1.0/go.mod h1:nq283P/jJ8hXMmdhAqfj7BJIz0y+6IOHj9q0044rKt4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 h1:1EYB5IzjZawrrnELUi78f9fPu57HuXjmddZPjrls/28= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4= +go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/hack/api-docs/known-issues.json b/hack/api-docs/known-issues.json new file mode 100644 index 000000000000..02617e123cc6 --- /dev/null +++ b/hack/api-docs/known-issues.json @@ -0,0 +1,2892 @@ +[ + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "example", + "pointer": "/components/schemas/Users2FALoginRequest/properties/code/example", + "messageSha256": "f524c4289cac4e74fc655a117925b19d205e8cf4a84d0e4eb580376857270d11", + "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", + "diagnostic": "jsonschema validation failed with 'source:hub#/components/schemas/Users2FALoginRequest/properties/code'\n- at '': got number, want string", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "example", + "pointer": "/components/schemas/getAccessTokensResponse/properties/next/example", + "messageSha256": "24b1ae1c7680ae4c77e6a2324f37604bae76ac9ec0005c305c53d25bf07d1de1", + "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", + "diagnostic": "jsonschema validation failed with 'source:hub#/components/schemas/getAccessTokensResponse/properties/next'\n- at '': got null, want string", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "example", + "pointer": "/components/schemas/getAccessTokensResponse/properties/previous/example", + "messageSha256": "70abcbf84044398b484ca7b512025a5f8e827352875dfc8e04071e76c195e4b0", + "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", + "diagnostic": "jsonschema validation failed with 'source:hub#/components/schemas/getAccessTokensResponse/properties/previous'\n- at '': got null, want string", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "example", + "pointer": "/components/schemas/immutable_tags_verify_request/properties/regex/example", + "messageSha256": "c5e7204226bdc3c0252c721ed6ef8bcdd36f4f6f2e5a10c8a7da220e9fc8fa8c", + "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", + "diagnostic": "jsonschema validation failed with 'source:hub#/components/schemas/immutable_tags_verify_request/properties/regex'\n- at '': 'v.*' does not match pattern '^[a-z0-9]+((\\\\\\\\.|_|__|-+)[a-z0-9]+)*(\\\\\\\\/[a-z0-9]+((\\\\\\\\.|_|__|-+)[a-z0-9]+)*)*$'", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "example", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/200/content/application~1json/schema/properties/next/example", + "messageSha256": "c38485c83b9ebe4bca6b5ce33378e8b8fb1b8ec3d6c5edf1d0023bd44e4e2fd8", + "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", + "diagnostic": "jsonschema validation failed with 'source:hub#/paths/~1v2~1orgs~1%7Borg_name%7D~1groups/get/responses/200/content/application~1json/schema/properties/next'\n- at '': got null, want string", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "example", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/200/content/application~1json/schema/properties/previous/example", + "messageSha256": "b3f9ac6897f3b48d85c63dae690b86569e284aeed8ade6390c34f511496a93c1", + "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", + "diagnostic": "jsonschema validation failed with 'source:hub#/paths/~1v2~1orgs~1%7Borg_name%7D~1groups/get/responses/200/content/application~1json/schema/properties/previous'\n- at '': got null, want string", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "example", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/200/content/application~1json/schema/properties/next/example", + "messageSha256": "5a161ce722f225c2468a5db8c0c3b9a7794e7847d24645bc11e219b182cd9996", + "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", + "diagnostic": "jsonschema validation failed with 'source:hub#/paths/~1v2~1orgs~1%7Borg_name%7D~1groups~1%7Bgroup_name%7D~1members/get/responses/200/content/application~1json/schema/properties/next'\n- at '': got null, want string", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "example", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/200/content/application~1json/schema/properties/previous/example", + "messageSha256": "0afb130b19f561c0c4587e8d27ffbdce7c2c56b516dd609f9dad68c697ae68dd", + "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", + "diagnostic": "jsonschema validation failed with 'source:hub#/paths/~1v2~1orgs~1%7Borg_name%7D~1groups~1%7Bgroup_name%7D~1members/get/responses/200/content/application~1json/schema/properties/previous'\n- at '': got null, want string", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "example", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/201/content/application~1json/example", + "messageSha256": "1a244af81ade4ef2616b9ee5bf28edeed2bac6f56a35a4a58210ab73bf0ca6d7", + "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", + "diagnostic": "jsonschema validation failed with 'source:hub#/paths/~1v2~1namespaces~1%7Bnamespace%7D~1repositories/post/responses/201/content/application~1json/schema'\n- at '': missing properties 'user', 'permissions'", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "example", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/200/content/application~1json/example", + "messageSha256": "e1b27ea692b2fda83285b9884f9f852d6c64f77f153e06138d27be7d958ffa16", + "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", + "diagnostic": "jsonschema validation failed with 'source:hub#/paths/~1v2~1namespaces~1%7Bnamespace%7D~1repositories~1%7Brepository%7D/get/responses/200/content/application~1json/schema'\n- at '': missing properties 'user', 'permissions'", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1access-tokens/get/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1access-tokens/get/parameters/1/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens/get/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens/get/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens/post/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens/post/responses/201/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens/post/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens/post/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/get/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/delete/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/delete/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1auditlogs~1{account}/get/responses/500/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1auditlogs~1{account}/get/responses/default/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1auditlogs~1{account}~1actions/get/responses/500/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1auditlogs~1{account}~1actions/get/responses/default/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1auth~1token/post/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1auth~1token/post/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1auth~1token/post/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1invites~1bulk/post/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1invites~1bulk/post/responses/202/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1invites~1bulk/post/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1invites~1bulk/post/responses/409/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1invites~1{id}/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1invites~1{id}/delete/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1invites~1{id}/delete/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1invites~1{id}/delete/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1invites~1{id}~1resend/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1invites~1{id}~1resend/patch/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1invites~1{id}~1resend/patch/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1invites~1{id}~1resend/patch/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/500/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/parameters/1/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/500/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/parameters/1/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/500/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/parameters/1/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/parameters/1/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/parameters/1/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/parameters/1/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/parameters/1/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/parameters/2/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/parameters/1/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/parameters/2/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/parameters/1/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/201/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/201/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/responses/500/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/parameters/5/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/parameters/6/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/200/content/text~1csv", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/parameters/1/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/responses/400/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/responses/403/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/responses/404/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/responses/200/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/responses/401/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/responses/500/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/responses/200/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/responses/401/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/responses/404/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/responses/500/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Schemas/get/responses/200/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Schemas/get/responses/401/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Schemas/get/responses/500/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/responses/200/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/responses/401/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/responses/404/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/responses/500/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/responses/200/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/responses/401/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/responses/500/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1scim~12.0~1Users/get/parameters/0/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1scim~12.0~1Users/get/parameters/1/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1scim~12.0~1Users/get/parameters/2/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S8", + "pointer": "/paths/~1v2~1scim~12.0~1Users/get/parameters/4/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/200/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/400/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/401/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/403/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/404/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/500/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/post/requestBody/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/201/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/400/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/401/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/403/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/404/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/409/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/500/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/responses/200/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/responses/400/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/responses/401/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/responses/403/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/responses/404/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/responses/500/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/requestBody/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/200/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/400/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/401/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/403/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/404/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/409/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/500/content/application~1scim+json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1users~12fa-login/post/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1users~12fa-login/post/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1users~12fa-login/post/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1users~1login/post/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1users~1login/post/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "hub", + "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "rule": "S11", + "pointer": "/paths/~1v2~1users~1login/post/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "example", + "pointer": "/components/schemas/Users2FALoginRequest/properties/code/example", + "messageSha256": "d216ebf62163620dd035cbcdc4bca82e17f62bd9e4e722a533dc171fd4eb7253", + "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", + "diagnostic": "jsonschema validation failed with 'source:dvp#/components/schemas/Users2FALoginRequest/properties/code'\n- at '': got number, want string", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1namespaces/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1namespaces~1{namespace}/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1namespaces~1{namespace}~1pulls/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years~1{year}~1{timespantype}/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years~1{year}~1{timespantype}~1{timespan}/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years~1{year}~1{timespantype}~1{timespan}~1{dataview}/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1namespaces~1{namespace}~1repos~1{repo}~1pulls/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1repos~1pulls/get/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1v2~1users~12fa-login/post/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1v2~1users~12fa-login/post/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1v2~1users~12fa-login/post/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1v2~1users~1login/post/requestBody/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1v2~1users~1login/post/responses/200/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "dvp", + "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", + "rule": "S11", + "pointer": "/paths/~1v2~1users~1login/post/responses/401/content/application~1json", + "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", + "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", + "diagnostic": "Media variant needs a reviewed example or transfer fixture", + "ownerReview": "required" + }, + { + "api": "registry", + "sha256": "3257829998629249bd9bd27a79996f922169e0c98677b67fb1dc87f565391a01", + "rule": "S8", + "pointer": "/paths/~1v2~1{name}~1blobs~1uploads~1{uuid}/get/parameters/2/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "registry", + "sha256": "3257829998629249bd9bd27a79996f922169e0c98677b67fb1dc87f565391a01", + "rule": "S8", + "pointer": "/paths/~1v2~1{name}~1blobs~1uploads~1{uuid}/put/parameters/3/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "registry", + "sha256": "3257829998629249bd9bd27a79996f922169e0c98677b67fb1dc87f565391a01", + "rule": "S8", + "pointer": "/paths/~1v2~1{name}~1blobs~1uploads~1{uuid}/delete/parameters/2/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + }, + { + "api": "registry", + "sha256": "3257829998629249bd9bd27a79996f922169e0c98677b67fb1dc87f565391a01", + "rule": "S8", + "pointer": "/paths/~1v2~1{name}~1blobs~1uploads~1{uuid}/patch/parameters/2/description", + "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", + "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", + "diagnostic": "Parameter description requires editorial review", + "ownerReview": "required" + } +] diff --git a/hack/api-docs/main.go b/hack/api-docs/main.go new file mode 100644 index 000000000000..fd4abe32cbf8 --- /dev/null +++ b/hack/api-docs/main.go @@ -0,0 +1,764 @@ +// api-docs prepares a source-preserving reference model for Docker API documentation. +package main + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "net/url" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/pb33f/libopenapi" + "github.com/pb33f/libopenapi/datamodel" + js "github.com/santhosh-tekuri/jsonschema/v6" + yaml "go.yaml.in/yaml/v4" +) + +type Object = map[string]any + +const dialect = "https://spec.openapis.org/oas/3.1/dialect/base" + +var methods = []string{"get", "put", "post", "delete", "options", "head", "patch", "trace", "query"} + +func obj(v any) Object { + m, _ := v.(map[string]any) + if m == nil { + return Object{} + } + return m +} +func arr(v any) []any { a, _ := v.([]any); return a } +func str(v any) string { s, _ := v.(string); return s } +func keys(m Object) []string { + a := make([]string, 0, len(m)) + for k := range m { + a = append(a, k) + } + sort.Strings(a) + return a +} +func hash(b []byte) string { s := sha256.Sum256(b); return hex.EncodeToString(s[:]) } +func encoded(v any) []byte { + b, e := json.MarshalIndent(v, "", " ") + if e != nil { + panic(e) + } + return append(b, '\n') +} +func esc(s string) string { return strings.ReplaceAll(strings.ReplaceAll(s, "~", "~0"), "/", "~1") } +func pointer(root any, p string) (any, error) { + if p == "" { + return root, nil + } + if !strings.HasPrefix(p, "/") { + return nil, fmt.Errorf("unsupported pointer %s", p) + } + for _, k := range strings.Split(p[1:], "/") { + k = strings.ReplaceAll(strings.ReplaceAll(k, "~1", "/"), "~0", "~") + switch v := root.(type) { + case map[string]any: + var ok bool + root, ok = v[k] + if !ok { + return nil, fmt.Errorf("missing pointer %s", p) + } + case []any: + var n int + if _, e := fmt.Sscanf(k, "%d", &n); e != nil || n < 0 || n >= len(v) { + return nil, fmt.Errorf("invalid array pointer %s", p) + } + root = v[n] + default: + return nil, fmt.Errorf("non-container pointer %s", p) + } + } + return root, nil +} +func readJSON(p string) (any, error) { + b, e := os.ReadFile(p) + if e != nil { + return nil, e + } + return js.UnmarshalJSON(bytes.NewReader(b)) +} +func writeJSON(p string, v any) error { + if e := os.MkdirAll(filepath.Dir(p), 0755); e != nil { + return e + } + return os.WriteFile(p, encoded(v), 0644) +} + +type Diagnostic struct { + Rule string `json:"rule"` + Pointer string `json:"pointer"` + Message string `json:"message"` + Waivable bool `json:"waivable"` + Excepted bool `json:"excepted"` + Reason string `json:"reason,omitempty"` +} +type Source struct { + ID string `json:"id"` + Product string `json:"product"` + Title string `json:"title"` + Source string `json:"source"` + Owner string `json:"owner"` + Manual string `json:"manual"` + Connection string `json:"connection"` + Auth string `json:"auth"` + Guides []string `json:"guides"` +} +type Registry struct{ resources map[string]any } + +func (r *Registry) Load(uri string) (any, error) { + if v, ok := r.resources[uri]; ok { + return v, nil + } + return nil, fmt.Errorf("unlocked resource: %s", uri) +} + +type Document struct { + Root Object + URI string + Registry *Registry + Diagnostics []Diagnostic + Schemas map[string]any + Locations map[string]int + Compiler *js.Compiler + Compiled map[string]*js.Schema + Digest string + Source Source + SchemaCount int + ExampleCount int +} + +func (d *Document) issue(rule, p, msg string, waivable bool) { + d.Diagnostics = append(d.Diagnostics, Diagnostic{Rule: rule, Pointer: p, Message: strings.ReplaceAll(msg, d.URI, "source:"+d.Source.ID), Waivable: waivable}) +} +func walk(v any, p string, fn func(Object, string)) { + switch n := v.(type) { + case map[string]any: + fn(n, p) + for _, k := range keys(n) { + walk(n[k], p+"/"+esc(k), fn) + } + case []any: + for i, x := range n { + walk(x, fmt.Sprintf("%s/%d", p, i), fn) + } + } +} +func strictSource(file string) (Object, libopenapi.Document, error) { + b, e := os.ReadFile(file) + if e != nil { + return nil, nil, e + } + cfg := datamodel.NewDocumentConfiguration() + cfg.AllowRemoteReferences = false + cfg.AllowFileReferences = false + cfg.SkipExternalRefResolution = true + doc, e := libopenapi.NewDocumentWithConfiguration(b, cfg) + if e != nil { + return nil, nil, e + } + v, e := strictFragment(file) + return obj(v), doc, e +} + +// YAML timestamp scalars are strings in the JSON data model. Decode source nodes +// explicitly: libopenapi's JSON convenience view normalizes their spelling. +func strictFragment(file string) (any, error) { + b, e := os.ReadFile(file) + if e != nil { + return nil, e + } + var node yaml.Node + if e = yaml.Unmarshal(b, &node); e != nil { + return nil, e + } + v, e := sourceValue(&node, map[*yaml.Node]bool{}) + if e != nil { + return nil, e + } + raw, e := json.Marshal(v) + if e != nil { + return nil, e + } + return js.UnmarshalJSON(bytes.NewReader(raw)) +} +func sourceValue(n *yaml.Node, active map[*yaml.Node]bool) (any, error) { + if active[n] { + return nil, errors.New("cyclic YAML alias") + } + active[n] = true + defer delete(active, n) + switch n.Kind { + case yaml.DocumentNode: + if len(n.Content) != 1 { + return nil, errors.New("expected one YAML document") + } + return sourceValue(n.Content[0], active) + case yaml.AliasNode: + return sourceValue(n.Alias, active) + case yaml.MappingNode: + m := Object{} + for i := 0; i < len(n.Content); i += 2 { + k := n.Content[i] + if k.Kind != yaml.ScalarNode || k.Value == "<<" { + return nil, errors.New("complex/merge YAML keys are outside the source profile") + } + if _, ok := m[k.Value]; ok { + return nil, fmt.Errorf("duplicate key %s at line %d", k.Value, k.Line) + } + v, e := sourceValue(n.Content[i+1], active) + if e != nil { + return nil, e + } + m[k.Value] = v + } + return m, nil + case yaml.SequenceNode: + a := []any{} + for _, c := range n.Content { + v, e := sourceValue(c, active) + if e != nil { + return nil, e + } + a = append(a, v) + } + return a, nil + case yaml.ScalarNode: + if n.Tag == "!!str" || n.Tag == "!!timestamp" { + return n.Value, nil + } + var v any + e := n.Decode(&v) + return v, e + } + return nil, errors.New("unsupported YAML node") +} + +func loadDocument(file, metaDir string) (*Document, error) { + abs, _ := filepath.Abs(file) + root, parsed, e := strictSource(abs) + if e != nil { + return nil, e + } + uri := (&url.URL{Scheme: "file", Path: abs}).String() + b, _ := os.ReadFile(file) + d := &Document{Root: root, URI: uri, Diagnostics: []Diagnostic{}, Registry: &Registry{resources: map[string]any{uri: root}}, Schemas: map[string]any{}, Locations: map[string]int{}, Compiled: map[string]*js.Schema{}, Digest: hash(b)} + // libopenapi's typed model supplies operation views/locations; schema serialization is never used. + model, modelErr := parsed.BuildV3Model() + if modelErr == nil && model != nil && model.Model.Paths != nil { + for p, item := range model.Model.Paths.PathItems.FromOldest() { + for m, op := range item.GetOperations().FromOldest() { + if op.GoLow().RootNode != nil { + d.Locations["/paths/"+esc(p)+"/"+m] = op.GoLow().RootNode.Line + } + } + } + } + // All file resources are acquired before compilation, under a bounded source directory. + var acquire func(any, string) error + acquire = func(v any, base string) error { + var failure error + walk(v, "", func(n Object, _ string) { + for _, k := range []string{"$ref", "$dynamicRef"} { + ref, ok := n[k].(string) + if !ok { + return + } + u, er := url.Parse(ref) + if er != nil { + failure = er + return + } + bu, _ := url.Parse(base) + u = bu.ResolveReference(u) + u.Fragment = "" + id := u.String() + if _, ok := d.Registry.resources[id]; ok { + return + } + if u.Scheme != "file" { + failure = fmt.Errorf("unlocked reference %s", id) + return + } + rel, er := filepath.Rel(filepath.Dir(abs), u.Path) + if er != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) { + failure = fmt.Errorf("reference escapes package: %s", ref) + return + } + r, er := strictFragment(u.Path) + if er != nil { + failure = er + return + } + d.Registry.resources[id] = r + if er = acquire(r, id); er != nil { + failure = er + } + } + }) + return failure + } + if e = acquire(root, uri); e != nil { + return nil, e + } + lockRaw, e := os.ReadFile(filepath.Join(metaDir, "lock.json")) + if e != nil { + return nil, e + } + var lock []struct{ File, URI, SHA256 string } + if e = json.Unmarshal(lockRaw, &lock); e != nil { + return nil, e + } + for _, l := range lock { + b, e := os.ReadFile(filepath.Join(metaDir, l.File)) + if e != nil { + return nil, e + } + if hash(b) != l.SHA256 { + return nil, fmt.Errorf("dialect digest mismatch: %s", l.File) + } + v, e := js.UnmarshalJSON(bytes.NewReader(b)) + if e != nil { + return nil, e + } + d.Registry.resources[l.URI] = v + if id := str(obj(v)["$id"]); id != "" { + d.Registry.resources[id] = v + } + } + d.Compiler = js.NewCompiler() + d.Compiler.DefaultDraft(js.Draft2020) + d.Compiler.UseLoader(d.Registry) + for id, v := range d.Registry.resources { + if e = d.Compiler.AddResource(id, v); e != nil { + return nil, e + } + } + return d, nil +} +func (d *Document) resolve(v any) any { + seen := map[string]bool{} + for { + r := str(obj(v)["$ref"]) + if r == "" { + return v + } + if seen[r] { + return v + } + seen[r] = true + u, e := url.Parse(r) + if e != nil { + return v + } + base, _ := url.Parse(d.URI) + u = base.ResolveReference(u) + frag := u.Fragment + u.Fragment = "" + target, ok := d.Registry.resources[u.String()] + if !ok { + return v + } + resolved, e := pointer(target, frag) + if e != nil { + return v + } + merged := Object{} + for k, x := range obj(resolved) { + merged[k] = x + } + for _, k := range []string{"summary", "description"} { + if x, ok := obj(v)[k]; ok { + merged[k] = x + } + } + if len(merged) == 0 { + return resolved + } + v = merged + } +} +func (d *Document) schemaRoots(v any, p string) { + switch n := v.(type) { + case map[string]any: + for _, k := range keys(n) { + x := n[k] + q := p + "/" + esc(k) + if k == "schemas" && p == "/components" { + for name, s := range obj(x) { + d.Schemas[q+"/"+esc(name)] = s + } + } else if k == "schema" || k == "itemSchema" { + d.Schemas[q] = x + } else if !strings.HasPrefix(k, "x-") && k != "example" && k != "examples" && k != "value" { + d.schemaRoots(x, q) + } + } + case []any: + for i, x := range n { + d.schemaRoots(x, fmt.Sprintf("%s/%d", p, i)) + } + } +} +func (d *Document) validate(metaDir string) { + if d.Root["openapi"] != "3.2.0" { + d.issue("S1", "/openapi", "Expected OpenAPI 3.2.0", false) + } + if d.Root["jsonSchemaDialect"] != dialect { + d.issue("S1", "/jsonSchemaDialect", "Expected the selected OAS dialect", false) + } + documentSchema, e := d.Compiler.Compile("https://spec.openapis.org/oas/3.2/schema/2025-09-17") + if e != nil { + d.issue("structure", "", e.Error(), false) + } else if e = documentSchema.Validate(d.Root); e != nil { + d.issue("structure", "", e.Error(), false) + } + // OAS Reference Objects also need explicit validation: a document schema cannot prove their target exists. + walk(d.Root, "", func(n Object, p string) { + if r := str(n["$ref"]); r != "" { + u, er := url.Parse(r) + if er != nil { + d.issue("reference", p, er.Error(), false) + return + } + base, _ := url.Parse(d.URI) + u = base.ResolveReference(u) + frag := u.Fragment + u.Fragment = "" + v, ok := d.Registry.resources[u.String()] + if !ok { + d.issue("reference", p, "Unregistered resource "+r, false) + } else if strings.HasPrefix(frag, "/") { + if _, er = pointer(v, frag); er != nil { + d.issue("reference", p, er.Error(), false) + } + } + } + }) + if len(obj(d.Root["webhooks"])) > 0 { + d.issue("capability", "/webhooks", "Webhook navigation is not supported by the reference renderer", false) + } + walk(d.Root, "", func(n Object, p string) { + if len(obj(n["callbacks"])) > 0 { + d.issue("capability", p+"/callbacks", "Callback navigation is not supported by the reference renderer", false) + } + }) + d.schemaRoots(d.Root, "") + schemaMeta, e := d.Compiler.Compile(dialect) + if e != nil { + d.issue("dialect", "", e.Error(), false) + return + } + for _, p := range keys(d.Schemas) { + s := d.Schemas[p] + d.SchemaCount++ + if e = schemaMeta.Validate(s); e != nil { + d.issue("schema", p, e.Error(), false) + continue + } + compiled, e := d.Compiler.Compile(d.URI + "#" + p) + if e != nil { + d.issue("schema", p, e.Error(), false) + continue + } + d.Compiled[p] = compiled + d.schemaExamples(s, p) + } + // Media, parameter and header examples are separate from examples nested inside schemas. + walk(d.Root, "", func(n Object, p string) { + schemaKey := "schema" + if _, ok := n["itemSchema"]; ok { + schemaKey = "itemSchema" + } + c := d.Compiled[p+"/"+schemaKey] + if c == nil { + return + } + if v, ok := n["example"]; ok { + d.example(c, v, p+"/example") + } + for _, name := range keys(obj(n["examples"])) { + ex := obj(d.resolve(obj(n["examples"])[name])) + if v, ok := ex["value"]; ok { + d.example(c, v, p+"/examples/"+esc(name)+"/value") + } + if _, ok := ex["externalValue"]; ok { + d.issue("example-external", p+"/examples/"+esc(name), "External example requires a locked media fixture", true) + } + } + }) + ids := map[string]bool{} + tags := map[string]string{} + for _, raw := range arr(d.Root["tags"]) { + t := obj(raw) + tags[str(t["name"])] = str(t["kind"]) + } + for _, op := range d.operations() { + id := str(op["id"]) + p := str(op["pointer"]) + if id == "" || ids[id] { + d.issue("S4", p, "Operation ID must be present and unique", false) + } + ids[id] = true + opTags := arr(op["tags"]) + if len(opTags) == 0 || tags[str(opTags[0])] != "nav" { + d.issue("S5", p+"/tags", "The first operation tag must identify a declared navigation group", false) + } + for _, tag := range opTags { + if _, ok := tags[str(tag)]; !ok { + d.issue("S5", p+"/tags", "Operation tag is undeclared: "+str(tag), false) + } + } + if len(arr(op["servers"])) == 0 && d.Source.Connection != "unix" { + d.issue("S6", p, "Operation needs effective servers or a local connection profile", false) + } + if strings.TrimSpace(str(op["description"])) == "" { + d.issue("S4", p+"/description", "Operation description required", true) + } + for _, pr := range arr(op["parameters"]) { + param := obj(pr) + if str(param["description"]) == "" { + d.issue("S8", str(param["pointer"])+"/description", "Parameter description requires editorial review", true) + } + } + for _, variant := range arr(op["variants"]) { + v := obj(variant) + if str(v["media"]) != "" && len(arr(v["examples"])) == 0 { + d.issue("S11", str(v["pointer"]), "Media variant needs a reviewed example or transfer fixture", true) + } + } + } +} +func (d *Document) schemaExamples(s any, p string) { + n := obj(s) + if len(n) == 0 { + return + } + if _, ok := n["$schema"]; ok && n["$schema"] != dialect { + d.issue("S1", p+"/$schema", "Schema dialect override is outside the profile", false) + } + c, e := d.Compiler.Compile(d.URI + "#" + p) + if e == nil { + if v, ok := n["example"]; ok { + d.example(c, v, p+"/example") + } + for i, v := range arr(n["examples"]) { + d.example(c, v, fmt.Sprintf("%s/examples/%d", p, i)) + } + } + for k, x := range n { + switch k { + case "properties", "patternProperties", "$defs", "dependentSchemas": + for _, name := range keys(obj(x)) { + d.schemaExamples(obj(x)[name], p+"/"+k+"/"+esc(name)) + } + case "allOf", "anyOf", "oneOf", "prefixItems": + for i, v := range arr(x) { + d.schemaExamples(v, fmt.Sprintf("%s/%s/%d", p, k, i)) + } + case "items", "additionalProperties", "unevaluatedProperties", "contains", "not", "if", "then", "else", "contentSchema", "propertyNames": + d.schemaExamples(x, p+"/"+k) + } + } +} +func (d *Document) example(c *js.Schema, v any, p string) { + d.ExampleCount++ + if e := c.Validate(v); e != nil { + d.issue("example", p, e.Error(), true) + } +} +func (d *Document) effective(root, item, op Object, k string) any { + if v, ok := op[k]; ok { + return v + } + if k == "servers" { + if v, ok := item[k]; ok { + return v + } + } + return root[k] +} +func (d *Document) parameters(item, op Object, p string) []any { + a := []any{} + positions := map[string]int{} + for i, container := range []Object{item, op} { + for j, raw := range arr(container["parameters"]) { + v := obj(d.resolve(raw)) + c := Object{} + for k, x := range v { + c[k] = x + } + prefix := p + if i == 0 { + prefix = p[:strings.LastIndex(p, "/")] + } + c["pointer"] = fmt.Sprintf("%s/parameters/%d", prefix, j) + key := str(v["in"]) + ":" + str(v["name"]) + if n, ok := positions[key]; ok { + a[n] = c + } else { + positions[key] = len(a) + a = append(a, c) + } + } + } + return a +} +func exampleList(v Object) []any { + out := []any{} + if x, ok := v["example"]; ok { + out = append(out, Object{"name": "Example", "value": x}) + } + for _, name := range keys(obj(v["examples"])) { + x := obj(obj(v["examples"])[name]) + if value, ok := x["value"]; ok { + out = append(out, Object{"name": name, "value": value}) + } + } + return out +} +func (d *Document) variants(op Object, p string) []any { + out := []any{} + add := func(direction, status string, raw any, ptr string) { + container := obj(d.resolve(raw)) + content := obj(container["content"]) + if len(content) == 0 { + out = append(out, Object{"direction": direction, "status": status, "description": container["description"], "headers": container["headers"], "media": "", "pointer": ptr, "examples": []any{}}) + } + for _, media := range keys(content) { + v := obj(content[media]) + a := Object{"direction": direction, "status": status, "description": container["description"], "headers": container["headers"], "media": media, "pointer": ptr + "/content/" + esc(media), "examples": d.mediaExamples(v), "required": container["required"]} + for _, k := range []string{"schema", "itemSchema", "encoding"} { + if s, ok := v[k]; ok { + a[k] = s + } + } + out = append(out, a) + } + } + if v, ok := op["requestBody"]; ok { + add("Request", "", v, p+"/requestBody") + } + for _, code := range keys(obj(op["responses"])) { + add("Response", code, obj(op["responses"])[code], p+"/responses/"+esc(code)) + } + return out +} +func (d *Document) operations() []Object { + out := []Object{} + for _, path := range keys(obj(d.Root["paths"])) { + item := obj(d.resolve(obj(d.Root["paths"])[path])) + ms := append([]string{}, methods...) + for m := range obj(item["additionalOperations"]) { + ms = append(ms, m) + } + for _, method := range ms { + raw, ok := item[method] + extra := !ok + if !ok { + raw, ok = obj(item["additionalOperations"])[method] + } + if !ok { + continue + } + op := obj(raw) + p := "/paths/" + esc(path) + "/" + method + if extra { + p = "/paths/" + esc(path) + "/additionalOperations/" + esc(method) + } + v := Object{"id": op["operationId"], "method": strings.ToUpper(method), "path": path, "pointer": p, "line": d.Locations[p], "summary": op["summary"], "description": op["description"], "tags": op["tags"], "deprecated": op["deprecated"], "servers": d.effective(d.Root, item, op, "servers"), "security": d.effective(d.Root, item, op, "security"), "parameters": d.parameters(item, op, p), "variants": d.variants(op, p), "raw": op} + out = append(out, v) + } + } + return out +} +func main() { + if e := run(); e != nil { + fmt.Fprintln(os.Stderr, e) + os.Exit(1) + } +} +func run() error { + if len(os.Args) < 3 { + return errors.New("usage: api-docs check|generate|inspect ROOT [--allow-known-issues]") + } + command := os.Args[1] + if command != "check" && command != "generate" && command != "inspect" { + return fmt.Errorf("unknown command: %s", command) + } + if len(os.Args) > 4 || (len(os.Args) == 4 && os.Args[3] != "--allow-known-issues") { + return errors.New("unexpected arguments") + } + root, _ := filepath.Abs(os.Args[2]) + dir := filepath.Join(root, "hack/api-docs") + meta := filepath.Join(dir, "dialects") + catalogRaw, e := os.ReadFile(filepath.Join(dir, "catalog.json")) + if e != nil { + return e + } + var catalog struct { + APIs []Source `json:"apis"` + LegacyAPIs []Object `json:"legacyAPIs"` + } + if e = json.Unmarshal(catalogRaw, &catalog); e != nil { + return e + } + allowKnown := len(os.Args) > 3 && os.Args[3] == "--allow-known-issues" + exceptions, e := readJSON(filepath.Join(dir, "known-issues.json")) + if e != nil { + return e + } + reports := []any{} + models := []any{} + blocking := 0 + for _, src := range catalog.APIs { + d, e := loadDocument(filepath.Join(root, src.Source), meta) + if e != nil { + return fmt.Errorf("%s: %w", src.ID, e) + } + d.Source = src + d.validate(meta) + for i := range d.Diagnostics { + diag := &d.Diagnostics[i] + for _, raw := range arr(exceptions) { + x := obj(raw) + if diag.Waivable && x["api"] == src.ID && x["sha256"] == d.Digest && x["rule"] == diag.Rule && x["pointer"] == diag.Pointer && x["messageSha256"] == hash([]byte(diag.Message)) && str(x["reason"]) != "" { + diag.Excepted = true + diag.Reason = str(x["reason"]) + break + } + } + if !diag.Excepted || !allowKnown { + blocking++ + } + } + reports = append(reports, Object{"api": src.ID, "sha256": d.Digest, "schemas": d.SchemaCount, "examples": d.ExampleCount, "operations": len(d.operations()), "diagnostics": d.Diagnostics}) + models = append(models, d.model()) + fmt.Printf("%s: %d operations, %d schema roots, %d examples, %d diagnostics\n", src.ID, len(d.operations()), d.SchemaCount, d.ExampleCount, len(d.Diagnostics)) + } + out := filepath.Join(root, "tmp/api-reference") + if e = writeJSON(filepath.Join(out, "validation.json"), reports); e != nil { + return e + } + if command == "inspect" { + return nil + } + if blocking > 0 { + return fmt.Errorf("%d blocking diagnostics; see tmp/api-reference/validation.json", blocking) + } + if command == "generate" { + if e = writeJSON(filepath.Join(out, "data/api-reference.json"), Object{"modelVersion": 1, "apis": models, "legacyAPIs": catalog.LegacyAPIs}); e != nil { + return e + } + } + return nil +} diff --git a/hack/api-docs/main_test.go b/hack/api-docs/main_test.go new file mode 100644 index 000000000000..ca4719b6d46f --- /dev/null +++ b/hack/api-docs/main_test.go @@ -0,0 +1,208 @@ +package main + +import ( + js "github.com/santhosh-tekuri/jsonschema/v6" + "os" + "path/filepath" + "reflect" + "strings" + "testing" +) + +func fixture(t *testing.T, name string) *Document { + t.Helper() + d, e := loadDocument(filepath.Join("testdata", name), "dialects") + if e != nil { + t.Fatal(e) + } + d.Source = Source{ID: "test"} + return d +} +func TestActualDialectAndReferences(t *testing.T) { + d := fixture(t, "valid.yaml") + d.validate("") + for _, x := range d.Diagnostics { + if !x.Waivable { + t.Errorf("%s: %s", x.Rule, x.Message) + } + } + if len(d.operations()) != 4 { + t.Fatal("operation omitted") + } + var query Object + for _, op := range d.operations() { + if op["method"] == "QUERY" { + query = op + } + } + if query == nil { + t.Fatal("QUERY omitted") + } + if obj(arr(query["servers"])[0])["url"] != "https://search.example.test" { + t.Fatal("path server override lost") + } + p := obj(arr(query["parameters"])[0]) + if p["example"] != jsonNumber("0") { + t.Fatalf("parameter override/zero lost: %#v", p["example"]) + } + if len(arr(query["parameters"])) != 1 { + t.Fatal("duplicate overridden parameter") + } +} +func jsonNumber(s string) any { + v, e := js.UnmarshalJSON(strings.NewReader(s)) + if e != nil { + panic(e) + } + return v +} +func TestNegativeFixtures(t *testing.T) { + for _, tc := range []struct{ name, rule string }{{"invalid-info.yaml", "structure"}, {"invalid-item-type.yaml", "schema"}, {"invalid-example.yaml", "example"}, {"profile-missing-id.yaml", "S4"}} { + t.Run(tc.name, func(t *testing.T) { + d := fixture(t, tc.name) + d.validate("") + found := false + for _, x := range d.Diagnostics { + found = found || x.Rule == tc.rule + } + if !found { + t.Fatalf("missing %s diagnostic: %+v", tc.rule, d.Diagnostics) + } + }) + } + for _, name := range []string{"duplicate-key.yaml", "invalid-stream-ref.yaml"} { + t.Run(name, func(t *testing.T) { + d, e := loadDocument(filepath.Join("testdata", name), "dialects") + if e == nil { + d.validate("") + for _, x := range d.Diagnostics { + if !x.Waivable { + return + } + } + t.Fatal("invalid source accepted") + } + }) + } +} +func TestSchemaSemantics(t *testing.T) { + d := fixture(t, "valid.yaml") + c := d.Compiler + cases := []struct { + name string + schema any + valid, invalid any + }{{"boolean false", false, nil, "x"}, {"ref siblings", Object{"$defs": Object{"base": Object{"type": "object", "required": []any{"a"}}}, "$ref": "#/$defs/base", "required": []any{"b"}}, Object{"a": true, "b": true}, Object{"b": true}}, {"recursive", Object{"type": "object", "properties": Object{"next": Object{"$ref": "#"}}}, Object{"next": Object{}}, Object{"next": 1}}, {"anchor", Object{"$defs": Object{"x": Object{"$anchor": "x", "type": "boolean"}}, "$ref": "#x"}, false, "false"}, {"dynamic", Object{"$dynamicAnchor": "node", "type": "object", "properties": Object{"child": Object{"$dynamicRef": "#node"}}}, Object{"child": Object{}}, Object{"child": false}}} + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + uri := "https://fixtures.test/" + strings.ReplaceAll(tc.name, " ", "-") + s := tc.schema + if m, ok := s.(map[string]any); ok { + m["$schema"] = dialect + } + if e := c.AddResource(uri, s); e != nil { + t.Fatal(e) + } + compiled, e := c.Compile(uri) + if e != nil { + t.Fatal(e) + } + if tc.valid != nil { + if e = compiled.Validate(tc.valid); e != nil { + t.Fatal(e) + } + } + if e = compiled.Validate(tc.invalid); e == nil { + t.Fatal("invalid example accepted") + } + }) + } +} +func TestAuthAndCurl(t *testing.T) { + schemes := Object{"bearer": Object{"type": "http", "scheme": "bearer"}, "key": Object{"type": "apiKey", "in": "header", "name": "X-Key"}} + op := Object{"method": "GET", "path": "/flag/{id}", "servers": []any{Object{"url": "https://api.test"}}, "securitySchemes": schemes, "security": []any{Object{"bearer": []any{}, "key": []any{}}, Object{}}, "parameters": []any{Object{"name": "id", "in": "path", "required": true, "example": "a/b"}, Object{"name": "enabled", "in": "query", "example": false}, Object{"name": "limit", "in": "query", "example": 0}}} + curl, _ := curlExample(Source{}, op) + for _, want := range []string{"a%2Fb", "enabled=false", "limit=0", "${TOKEN}", "X-Key: ${API_KEY}"} { + if !strings.Contains(curl, want) { + t.Errorf("missing %s: %s", want, curl) + } + } + op["security"] = []any{} + curl, _ = curlExample(Source{}, op) + if strings.Contains(curl, "Authorization") { + t.Fatal("anonymous operation gained auth") + } + op["method"] = "HEAD" + curl, _ = curlExample(Source{Connection: "unix", ID: "engine-1.56"}, op) + if !strings.Contains(curl, "--head") || !strings.Contains(curl, "--unix-socket") { + t.Fatal(curl) + } + d := &Document{} + root := Object{"security": []any{Object{"bearer": []any{}}}} + if !reflect.DeepEqual(d.effective(root, Object{}, Object{"security": []any{}}, "security"), []any{}) { + t.Fatal("empty override lost") + } +} +func TestFalseSchemaAndExamplePreserved(t *testing.T) { + b, e := os.ReadFile("testdata/valid.yaml") + if e != nil { + t.Fatal(e) + } + tmp := t.TempDir() + if e = os.WriteFile(filepath.Join(tmp, "spec.yaml"), []byte(strings.ReplaceAll(string(b), "schema: true", "schema: false")), 0600); e != nil { + t.Fatal(e) + } + if e = os.Mkdir(filepath.Join(tmp, "schemas"), 0700); e != nil { + t.Fatal(e) + } + event, _ := os.ReadFile("testdata/schemas/event.yaml") + os.WriteFile(filepath.Join(tmp, "schemas/event.yaml"), event, 0600) + d, e := loadDocument(filepath.Join(tmp, "spec.yaml"), "dialects") + if e != nil { + t.Fatal(e) + } + d.validate("") + v, e := pointer(d.Root, "/paths/~1search/query/responses/200/content/application~1json/schema") + if e != nil || v != false { + t.Fatal("false schema changed") + } + for _, op := range d.operations() { + if op["path"] == "/public" { + ex := obj(arr(obj(arr(op["variants"])[0])["examples"])[0]) + if ex["value"] != false { + t.Fatal("false example omitted") + } + } + } +} + +func TestTimestampStringsRetainSpelling(t *testing.T) { + p := filepath.Join(t.TempDir(), "schema.yaml") + if e := os.WriteFile(p, []byte("type: string\nexample: 2021-01-05T21:06:53.506400Z\n"), 0600); e != nil { + t.Fatal(e) + } + v, e := strictFragment(p) + if e != nil { + t.Fatal(e) + } + if obj(v)["example"] != "2021-01-05T21:06:53.506400Z" { + t.Fatalf("timestamp spelling changed: %v", v) + } +} +func TestCaseSensitiveSchemaRoutes(t *testing.T) { + if slug("Error") == slug("error") { + t.Fatal("schema route collision") + } +} +func TestUnlockedResourcesAndUnknownDialect(t *testing.T) { + d := fixture(t, "valid.yaml") + if _, e := d.Compiler.Compile("https://unlocked.test/schema"); e == nil { + t.Fatal("unlocked schema fetched") + } + if e := d.Compiler.AddResource("https://fixtures.test/custom", Object{"$schema": "https://unlocked.test/dialect", "type": "object"}); e != nil { + t.Fatal(e) + } + if _, e := d.Compiler.Compile("https://fixtures.test/custom"); e == nil { + t.Fatal("unknown dialect accepted") + } +} diff --git a/hack/api-docs/model.go b/hack/api-docs/model.go new file mode 100644 index 000000000000..313ecd0afca0 --- /dev/null +++ b/hack/api-docs/model.go @@ -0,0 +1,249 @@ +package main + +import ( + "net/url" + "sort" + "strings" +) + +func route(id string) string { + return "/reference/api/" + id + "/latest/" +} +func slug(s string) string { return url.PathEscape(s) } +func (d *Document) model() Object { + ops := d.operations() + schemas := []any{} + schemaURLs := Object{} + for _, name := range keys(obj(obj(d.Root["components"])["schemas"])) { + p := "/components/schemas/" + esc(name) + u := route(d.Source.ID) + "schemas/" + slug(name) + "/" + schemaURLs["#"+p] = u + schemas = append(schemas, Object{"name": name, "pointer": p, "url": u, "schema": obj(obj(d.Root["components"])["schemas"])[name]}) + } + for _, op := range ops { + for _, raw := range arr(op["variants"]) { + v := obj(raw) + c := d.Compiled[str(v["pointer"])+"/schema"] + if c != nil { + for _, rawEx := range arr(v["examples"]) { + ex := obj(rawEx) + ex["valid"] = c.Validate(ex["value"]) == nil + } + } + } + } + for _, op := range ops { + op["url"] = route(d.Source.ID) + "operations/" + slug(str(op["id"])) + "/" + op["securitySchemes"] = obj(d.Root["components"])["securitySchemes"] + op["curl"], op["curlNotes"] = curlExample(d.Source, op) + op["references"] = refs(op["raw"], schemaURLs) + op["requestSchema"] = firstRequestSchema(op) + } + return Object{"id": d.Source.ID, "product": d.Source.Product, "title": d.Source.Title, "version": obj(d.Root["info"])["version"], "description": obj(d.Root["info"])["description"], "url": route(d.Source.ID), "manual": d.Source.Manual, "guides": d.Source.Guides, "connection": d.Source.Connection, "auth": d.Source.Auth, "servers": d.Root["servers"], "securitySchemes": obj(d.Root["components"])["securitySchemes"], "tags": d.Root["tags"], "operations": ops, "schemas": schemas, "schemaURLs": schemaURLs, "digest": d.Digest, "owner": d.Source.Owner, "source": d.Source.Source, "sourceURL": "/" + strings.TrimPrefix(d.Source.Source, "content/"), "diagnostics": d.Diagnostics, "schemaCount": d.SchemaCount, "exampleCount": d.ExampleCount} +} +func refs(v any, urls Object) []any { + found := map[string]bool{} + walk(v, "", func(n Object, _ string) { + if s := str(n["$ref"]); s != "" { + found[s] = true + } + }) + out := []any{} + names := []string{} + for n := range found { + names = append(names, n) + } + sort.Strings(names) + for _, n := range names { + out = append(out, Object{"ref": n, "url": urls[n]}) + } + return out +} +func firstRequestSchema(op Object) any { + for _, v := range arr(op["variants"]) { + m := obj(v) + if m["direction"] == "Request" { + return m["schema"] + } + } + return nil +} +func shell(s string) string { return "'" + strings.ReplaceAll(s, "'", "'\"'\"'") + "'" } +func scalar(v any) string { + if s, ok := v.(string); ok { + return s + } + return strings.TrimSpace(string(encoded(v))) +} +func parameterValue(p Object) (any, bool) { + if v, ok := p["example"]; ok { + return v, true + } + s := obj(p["schema"]) + if v, ok := s["example"]; ok { + return v, true + } + if a := arr(s["examples"]); len(a) > 0 { + return a[0], true + } + return nil, false +} +func curlExample(src Source, op Object) (string, []string) { + notes := []string{} + args := []string{"curl"} + if op["method"] == "HEAD" { + args = append(args, "--head") + } else { + args = append(args, "--request "+str(op["method"])) + } + server := "" + if a := arr(op["servers"]); len(a) > 0 { + m := obj(a[0]) + server = str(m["url"]) + for name, v := range obj(m["variables"]) { + server = strings.ReplaceAll(server, "{"+name+"}", str(obj(v)["default"])) + } + } + if src.Connection == "unix" { + args = append(args, "--unix-socket \"${DOCKER_SOCKET:-/var/run/docker.sock}\"") + if !strings.HasPrefix(server, "/") { + server = "/v" + strings.TrimPrefix(src.ID, "engine-") + } + server = "http://localhost" + server + } + if server == "" { + server = "https://" + notes = append(notes, "Set the API server address.") + } + target := strings.TrimRight(server, "/") + str(op["path"]) + query := []string{} + for _, raw := range arr(op["parameters"]) { + p := obj(raw) + name := str(p["name"]) + v, has := parameterValue(p) + required, _ := p["required"].(bool) + if !has && !required { + continue + } + value := "<" + strings.ToUpper(name) + ">" + if has { + value = scalar(v) + } + location := str(p["in"]) + if location == "path" { + part := value + if has { + part = url.PathEscape(value) + } + target = strings.ReplaceAll(target, "{"+name+"}", part) + } else if location == "header" { + args = append(args, "--header "+shell(name+": "+value)) + } else if location == "query" { + style := str(p["style"]) + if style == "" { + style = "form" + } + explode := true + if x, ok := p["explode"].(bool); ok { + explode = x + } + if list, ok := v.([]any); ok && style == "form" { + parts := []string{} + for _, x := range list { + parts = append(parts, scalar(x)) + } + if explode { + for _, x := range parts { + query = append(query, url.QueryEscape(name)+"="+url.QueryEscape(x)) + } + } else { + query = append(query, url.QueryEscape(name)+"="+url.QueryEscape(strings.Join(parts, ","))) + } + } else if len(obj(v)) > 0 || style != "form" { + notes = append(notes, "Serialize "+name+" using its documented "+style+" rules; this parameter is not generated.") + } else { + query = append(query, url.QueryEscape(name)+"="+url.QueryEscape(value)) + } + } else { + notes = append(notes, "Supply "+name+" using its documented "+location+" encoding.") + } + } + if len(query) > 0 { + target += "?" + strings.Join(query, "&") + } + security := arr(op["security"]) + if len(security) > 0 { + first := obj(security[0]) + for _, scheme := range keys(first) { + definition := obj(obj(op["securitySchemes"])[scheme]) + switch { + case definition["type"] == "http" && definition["scheme"] == "bearer": + token := "TOKEN" + if scheme == "scimToken" { + token = "SCIM_TOKEN" + } + if scheme == "registryToken" { + token = "REGISTRY_TOKEN" + } + args = append(args, "--header \"Authorization: Bearer ${"+token+"}\"") + case definition["type"] == "apiKey" && definition["in"] == "header": + args = append(args, "--header \""+str(definition["name"])+": ${API_KEY}\"") + default: + notes = append(notes, "Configure authentication scheme "+scheme+" using its documented transport or credential format.") + } + } + if len(security) > 1 { + notes = append(notes, "This example uses the first authentication alternative. Review the complete requirements.") + } + } + for _, raw := range arr(op["variants"]) { + v := obj(raw) + if v["direction"] != "Request" { + continue + } + media := str(v["media"]) + if media == "" { + continue + } + args = append(args, "--header "+shell("Content-Type: "+media)) + examples := arr(v["examples"]) + if len(examples) > 0 && obj(examples[0])["valid"] != false && strings.Contains(media, "json") { + args = append(args, "--data-raw "+shell(strings.TrimSpace(string(encoded(obj(examples[0])["value"]))))) + } else { + args = append(args, "--data-binary @request-body") + notes = append(notes, "Prepare request-body using the selected media type and schema.") + } + break + } + args = append(args, shell(target)) + return strings.Join(args, " \\\n "), notes +} + +// Examples are annotations: retrieve them without flattening schema constraints. +func (d *Document) mediaExamples(v Object) []any { + out := exampleList(v) + if len(out) > 0 { + return out + } + s := v["schema"] + seen := map[string]bool{} + for s != nil { + n := obj(s) + if x, ok := n["example"]; ok { + return []any{Object{"name": "Schema example", "value": x}} + } + if xs := arr(n["examples"]); len(xs) > 0 { + for _, x := range xs { + out = append(out, Object{"name": "Schema example", "value": x}) + } + return out + } + ref := str(n["$ref"]) + if ref == "" || seen[ref] { + break + } + seen[ref] = true + s = d.resolve(n) + } + return out +} diff --git a/hack/api-docs/run.sh b/hack/api-docs/run.sh new file mode 100755 index 000000000000..72a009c8952c --- /dev/null +++ b/hack/api-docs/run.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail +ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) +cd "$ROOT" +BIN="$ROOT/tmp/api-reference/bin" +mkdir -p "$BIN" "$ROOT/tmp/api-reference/reports" +export GOWORK=off +bootstrap() { + (cd hack/api-docs && go build -o "$BIN/api-docs" .) + if [[ ! -x "$BIN/vacuum-v0.30.3" ]]; then + GOBIN="$BIN" go install github.com/daveshanley/vacuum@v0.30.3 + mv "$BIN/vacuum" "$BIN/vacuum-v0.30.3" + fi +} +policy() { + for api in hub dvp registry; do + "$BIN/vacuum-v0.30.3" lint --no-update-check --remote=false --ruleset hack/api-docs/vacuum.yaml --fail-severity error --min-score 0 --no-banner --no-style --details "content/reference/api/$api/latest.yaml" > "tmp/api-reference/reports/$api-vacuum.txt" 2>&1 || { + cat "tmp/api-reference/reports/$api-vacuum.txt"; return 1; + } + done +} +generate() { + bootstrap + policy + "$BIN/api-docs" generate "$ROOT" --allow-known-issues +} +case "${1:-build}" in + bootstrap) bootstrap ;; + check) bootstrap; policy; "$BIN/api-docs" check "$ROOT" ;; + generate) generate ;; + test) (cd hack/api-docs && go test ./...) ;; + build|serve) + generate + hugo --destination tmp/api-reference/site --baseURL "${DOCS_URL:-http://localhost:1314}" --cleanDestinationDir + node hack/api-docs/flatten.mjs tmp/api-reference/site + node hack/api-docs/verify-output.mjs tmp/api-reference/site + if [[ "${1:-build}" == serve ]]; then + exec python3 -m http.server "${DOCS_PORT:-1314}" --bind 127.0.0.1 --directory tmp/api-reference/site + fi + ;; + *) printf '%s\n' 'Usage: run.sh bootstrap|check|generate|test|build|serve' >&2; exit 2 ;; +esac diff --git a/hack/api-docs/testdata/duplicate-key.yaml b/hack/api-docs/testdata/duplicate-key.yaml new file mode 100644 index 000000000000..739c796ab82b --- /dev/null +++ b/hack/api-docs/testdata/duplicate-key.yaml @@ -0,0 +1,102 @@ +openapi: 3.2.0 +jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base +info: + title: Docker documentation tooling fixture + version: '1' + version: '2' + description: Component capability fixture. +servers: +- url: https://api.example.test/v1 +security: +- bearerAuth: [] +tags: +- name: operations + summary: Operations + kind: nav + description: Fixture operations. +paths: + /events: + get: + operationId: listEvents + tags: + - operations + summary: List events + responses: + '200': + description: Event stream + content: + text/event-stream: + itemSchema: + $ref: ./schemas/event.yaml + /search: + parameters: + - name: limit + in: query + schema: + type: integer + example: 10 + servers: + - url: https://search.example.test + query: + operationId: querySearch + tags: + - operations + summary: Search + parameters: + - name: limit + in: query + schema: + type: integer + example: 0 + responses: + '200': + description: Search result + content: + application/json: + schema: true + /public: + get: + operationId: getPublic + tags: + - operations + summary: Public result + security: [] + responses: + '200': + description: A flag + content: + application/json: + schema: + type: boolean + example: false + /items: + get: + operationId: getItems + tags: + - operations + summary: Get items + responses: + '200': + description: Item + content: + application/json: + schema: + $ref: '#/components/schemas/Item' + description: Description beside a reference. +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + schemas: + Item: + type: object + required: + - id + properties: + id: + type: integer + next: + anyOf: + - $ref: '#/components/schemas/Item' + - type: 'null' diff --git a/hack/api-docs/testdata/invalid-example.yaml b/hack/api-docs/testdata/invalid-example.yaml new file mode 100644 index 000000000000..37015deb1a44 --- /dev/null +++ b/hack/api-docs/testdata/invalid-example.yaml @@ -0,0 +1,101 @@ +openapi: 3.2.0 +jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base +info: + title: Docker documentation tooling fixture + version: '1' + description: Component capability fixture. +servers: +- url: https://api.example.test/v1 +security: +- bearerAuth: [] +tags: +- name: operations + summary: Operations + kind: nav + description: Fixture operations. +paths: + /events: + get: + operationId: listEvents + tags: + - operations + summary: List events + responses: + '200': + description: Event stream + content: + text/event-stream: + itemSchema: + $ref: ./schemas/event.yaml + /search: + parameters: + - name: limit + in: query + schema: + type: integer + example: 10 + servers: + - url: https://search.example.test + query: + operationId: querySearch + tags: + - operations + summary: Search + parameters: + - name: limit + in: query + schema: + type: integer + example: 0 + responses: + '200': + description: Search result + content: + application/json: + schema: true + /public: + get: + operationId: getPublic + tags: + - operations + summary: Public result + security: [] + responses: + '200': + description: A flag + content: + application/json: + schema: + type: boolean + example: not-a-boolean + /items: + get: + operationId: getItems + tags: + - operations + summary: Get items + responses: + '200': + description: Item + content: + application/json: + schema: + $ref: '#/components/schemas/Item' + description: Description beside a reference. +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + schemas: + Item: + type: object + required: + - id + properties: + id: + type: integer + next: + anyOf: + - $ref: '#/components/schemas/Item' + - type: 'null' diff --git a/hack/api-docs/testdata/invalid-info.yaml b/hack/api-docs/testdata/invalid-info.yaml new file mode 100644 index 000000000000..3280debcaee6 --- /dev/null +++ b/hack/api-docs/testdata/invalid-info.yaml @@ -0,0 +1,100 @@ +openapi: 3.2.0 +jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base +info: + title: Docker documentation tooling fixture + description: Component capability fixture. +servers: +- url: https://api.example.test/v1 +security: +- bearerAuth: [] +tags: +- name: operations + summary: Operations + kind: nav + description: Fixture operations. +paths: + /events: + get: + operationId: listEvents + tags: + - operations + summary: List events + responses: + '200': + description: Event stream + content: + text/event-stream: + itemSchema: + $ref: ./schemas/event.yaml + /search: + parameters: + - name: limit + in: query + schema: + type: integer + example: 10 + servers: + - url: https://search.example.test + query: + operationId: querySearch + tags: + - operations + summary: Search + parameters: + - name: limit + in: query + schema: + type: integer + example: 0 + responses: + '200': + description: Search result + content: + application/json: + schema: true + /public: + get: + operationId: getPublic + tags: + - operations + summary: Public result + security: [] + responses: + '200': + description: A flag + content: + application/json: + schema: + type: boolean + example: false + /items: + get: + operationId: getItems + tags: + - operations + summary: Get items + responses: + '200': + description: Item + content: + application/json: + schema: + $ref: '#/components/schemas/Item' + description: Description beside a reference. +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + schemas: + Item: + type: object + required: + - id + properties: + id: + type: integer + next: + anyOf: + - $ref: '#/components/schemas/Item' + - type: 'null' diff --git a/hack/api-docs/testdata/invalid-item-type.yaml b/hack/api-docs/testdata/invalid-item-type.yaml new file mode 100644 index 000000000000..524584656267 --- /dev/null +++ b/hack/api-docs/testdata/invalid-item-type.yaml @@ -0,0 +1,101 @@ +openapi: 3.2.0 +jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base +info: + title: Docker documentation tooling fixture + version: '1' + description: Component capability fixture. +servers: +- url: https://api.example.test/v1 +security: +- bearerAuth: [] +tags: +- name: operations + summary: Operations + kind: nav + description: Fixture operations. +paths: + /events: + get: + operationId: listEvents + tags: + - operations + summary: List events + responses: + '200': + description: Event stream + content: + text/event-stream: + itemSchema: + type: definitely-invalid + /search: + parameters: + - name: limit + in: query + schema: + type: integer + example: 10 + servers: + - url: https://search.example.test + query: + operationId: querySearch + tags: + - operations + summary: Search + parameters: + - name: limit + in: query + schema: + type: integer + example: 0 + responses: + '200': + description: Search result + content: + application/json: + schema: true + /public: + get: + operationId: getPublic + tags: + - operations + summary: Public result + security: [] + responses: + '200': + description: A flag + content: + application/json: + schema: + type: boolean + example: false + /items: + get: + operationId: getItems + tags: + - operations + summary: Get items + responses: + '200': + description: Item + content: + application/json: + schema: + $ref: '#/components/schemas/Item' + description: Description beside a reference. +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + schemas: + Item: + type: object + required: + - id + properties: + id: + type: integer + next: + anyOf: + - $ref: '#/components/schemas/Item' + - type: 'null' diff --git a/hack/api-docs/testdata/invalid-stream-ref.yaml b/hack/api-docs/testdata/invalid-stream-ref.yaml new file mode 100644 index 000000000000..7d4edd2052bb --- /dev/null +++ b/hack/api-docs/testdata/invalid-stream-ref.yaml @@ -0,0 +1,101 @@ +openapi: 3.2.0 +jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base +info: + title: Docker documentation tooling fixture + version: '1' + description: Component capability fixture. +servers: +- url: https://api.example.test/v1 +security: +- bearerAuth: [] +tags: +- name: operations + summary: Operations + kind: nav + description: Fixture operations. +paths: + /events: + get: + operationId: listEvents + tags: + - operations + summary: List events + responses: + '200': + description: Event stream + content: + text/event-stream: + itemSchema: + $ref: ./schemas/missing.yaml + /search: + parameters: + - name: limit + in: query + schema: + type: integer + example: 10 + servers: + - url: https://search.example.test + query: + operationId: querySearch + tags: + - operations + summary: Search + parameters: + - name: limit + in: query + schema: + type: integer + example: 0 + responses: + '200': + description: Search result + content: + application/json: + schema: true + /public: + get: + operationId: getPublic + tags: + - operations + summary: Public result + security: [] + responses: + '200': + description: A flag + content: + application/json: + schema: + type: boolean + example: false + /items: + get: + operationId: getItems + tags: + - operations + summary: Get items + responses: + '200': + description: Item + content: + application/json: + schema: + $ref: '#/components/schemas/Item' + description: Description beside a reference. +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + schemas: + Item: + type: object + required: + - id + properties: + id: + type: integer + next: + anyOf: + - $ref: '#/components/schemas/Item' + - type: 'null' diff --git a/hack/api-docs/testdata/profile-missing-id.yaml b/hack/api-docs/testdata/profile-missing-id.yaml new file mode 100644 index 000000000000..99fba5ceccbd --- /dev/null +++ b/hack/api-docs/testdata/profile-missing-id.yaml @@ -0,0 +1,100 @@ +openapi: 3.2.0 +jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base +info: + title: Docker documentation tooling fixture + version: '1' + description: Component capability fixture. +servers: +- url: https://api.example.test/v1 +security: +- bearerAuth: [] +tags: +- name: operations + summary: Operations + kind: nav + description: Fixture operations. +paths: + /events: + get: + operationId: listEvents + tags: + - operations + summary: List events + responses: + '200': + description: Event stream + content: + text/event-stream: + itemSchema: + $ref: ./schemas/event.yaml + /search: + parameters: + - name: limit + in: query + schema: + type: integer + example: 10 + servers: + - url: https://search.example.test + query: + operationId: querySearch + tags: + - operations + summary: Search + parameters: + - name: limit + in: query + schema: + type: integer + example: 0 + responses: + '200': + description: Search result + content: + application/json: + schema: true + /public: + get: + tags: + - operations + summary: Public result + security: [] + responses: + '200': + description: A flag + content: + application/json: + schema: + type: boolean + example: false + /items: + get: + operationId: getItems + tags: + - operations + summary: Get items + responses: + '200': + description: Item + content: + application/json: + schema: + $ref: '#/components/schemas/Item' + description: Description beside a reference. +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + schemas: + Item: + type: object + required: + - id + properties: + id: + type: integer + next: + anyOf: + - $ref: '#/components/schemas/Item' + - type: 'null' diff --git a/hack/api-docs/testdata/schemas/event.yaml b/hack/api-docs/testdata/schemas/event.yaml new file mode 100644 index 000000000000..b158529a5656 --- /dev/null +++ b/hack/api-docs/testdata/schemas/event.yaml @@ -0,0 +1,9 @@ +type: object +required: +- event +- data +properties: + event: + type: string + data: + type: string diff --git a/hack/api-docs/testdata/valid.yaml b/hack/api-docs/testdata/valid.yaml new file mode 100644 index 000000000000..5863f4b25c20 --- /dev/null +++ b/hack/api-docs/testdata/valid.yaml @@ -0,0 +1,101 @@ +openapi: 3.2.0 +jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base +info: + title: Docker documentation tooling fixture + version: '1' + description: Component capability fixture. +servers: +- url: https://api.example.test/v1 +security: +- bearerAuth: [] +tags: +- name: operations + summary: Operations + kind: nav + description: Fixture operations. +paths: + /events: + get: + operationId: listEvents + tags: + - operations + summary: List events + responses: + '200': + description: Event stream + content: + text/event-stream: + itemSchema: + $ref: ./schemas/event.yaml + /search: + parameters: + - name: limit + in: query + schema: + type: integer + example: 10 + servers: + - url: https://search.example.test + query: + operationId: querySearch + tags: + - operations + summary: Search + parameters: + - name: limit + in: query + schema: + type: integer + example: 0 + responses: + '200': + description: Search result + content: + application/json: + schema: true + /public: + get: + operationId: getPublic + tags: + - operations + summary: Public result + security: [] + responses: + '200': + description: A flag + content: + application/json: + schema: + type: boolean + example: false + /items: + get: + operationId: getItems + tags: + - operations + summary: Get items + responses: + '200': + description: Item + content: + application/json: + schema: + $ref: '#/components/schemas/Item' + description: Description beside a reference. +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + schemas: + Item: + type: object + required: + - id + properties: + id: + type: integer + next: + anyOf: + - $ref: '#/components/schemas/Item' + - type: 'null' diff --git a/hack/api-docs/vacuum.yaml b/hack/api-docs/vacuum.yaml new file mode 100644 index 000000000000..e3fdaa5d5a43 --- /dev/null +++ b/hack/api-docs/vacuum.yaml @@ -0,0 +1,24 @@ +# Structural and dialect validation run against locked OAI schemas in the Go command. +# Vacuum supplies independently named Docker policy rules with source locations. +rules: + docker-operation-id: + description: Every operation needs a stable operation ID. + severity: error + given: $.paths[*][get,put,post,delete,options,head,patch,trace,query] + then: + field: operationId + function: truthy + docker-info-description: + description: Every API needs an overview. + severity: error + given: $.info + then: + field: description + function: truthy + docker-info-version: + description: Every API needs a version identity. + severity: error + given: $.info + then: + field: version + function: truthy diff --git a/hack/api-docs/verify-output.mjs b/hack/api-docs/verify-output.mjs new file mode 100644 index 000000000000..43cfae89a5b4 --- /dev/null +++ b/hack/api-docs/verify-output.mjs @@ -0,0 +1,161 @@ +import fs from "node:fs"; +import path from "node:path"; +import { isDeepStrictEqual } from "node:util"; +const root = path.resolve(import.meta.dirname, "../.."); +const base = path.resolve(process.argv[2] || "public"); +const data = JSON.parse( + fs.readFileSync(path.join(root, "tmp/api-reference/data/api-reference.json")), +); +const decode = (s) => + s + .replace(/&#(\d+);/g, (_, n) => String.fromCodePoint(Number(n))) + .replaceAll("&", "&") + .replaceAll(""", '"') + .replaceAll("'", "'") + .replaceAll("<", "<") + .replaceAll(">", ">"); +// Hugo's production minifier removes optional attribute quotes. +function attributes(html, name) { + const pattern = new RegExp( + `\\s${name}=(?:"([^"]*)"|'([^']*)'|([^\\s>]+))`, + "g", + ); + return [...html.matchAll(pattern)].map((m) => decode(m[1] ?? m[2] ?? m[3])); +} +let count = 0; +const problems = []; +function check(url) { + const htmlPath = path.join(base, url, "index.html"); + const mdPath = path.join(base, url.replace(/\/$/, "")) + ".md"; + if (!fs.existsSync(htmlPath) || !fs.existsSync(mdPath)) { + problems.push(`Missing HTML/Markdown: ${url}`); + return ["", ""]; + } + const html = fs.readFileSync(htmlPath, "utf8"), + md = fs.readFileSync(mdPath, "utf8"); + count++; + return [decode(html), md]; +} +check("/reference/api/"); +for (const api of data.apis) { + check(api.url); + const publishedSource = fs.readFileSync(path.join(base, api.sourceURL)); + if (!publishedSource.equals(fs.readFileSync(path.join(root, api.source)))) + problems.push(`Published specification differs from source: ${api.id}`); + + for (const op of api.operations) { + const [html, md] = check(op.url); + for (const variant of op.variants) + if ( + !attributes(html, "data-api-variant").includes(variant.pointer) || + !md.includes(`### ${variant.direction} ${variant.status}`) + ) + problems.push(`Missing variant: ${op.url} ${variant.pointer}`); + for (const p of op.parameters) + if ( + !attributes(html, "data-api-parameter").includes(p.name) || + !md.includes(`### ${p.name}`) + ) + problems.push(`Missing parameter: ${op.url} ${p.name}`); + if (!html.includes(op.path) || !md.includes(op.method + " " + op.path)) + problems.push(`Missing operation signature: ${op.url}`); + if (!md.includes(op.curl)) + problems.push(`Request example mismatch: ${op.url}`); + } + for (const schema of api.schemas) { + const [html, md] = check(schema.url); + if ( + ![...md.matchAll(/```json\n([\s\S]*?)\n```/g)].some((m) => { + try { + return isDeepStrictEqual(JSON.parse(m[1]), schema.schema); + } catch { + return false; + } + }) + ) + problems.push(`Incomplete Markdown schema: ${schema.url}`); + if (!html.includes(schema.name)) + problems.push(`Missing schema heading: ${schema.url}`); + } +} +// Check API reference links in every generated preview page, including copied specification prose. +function files(dir) { + return fs + .readdirSync(dir, { withFileTypes: true }) + .flatMap((e) => + e.isDirectory() + ? files(path.join(dir, e.name)) + : [path.join(dir, e.name)], + ); +} +for (const file of [...files(path.join(base, "reference/api"))].filter((p) => + p.endsWith(".html"), +)) { + const html = fs.readFileSync(file, "utf8"); + if (!html.includes("data-api-view=")) continue; + for (const href of attributes(html, "href")) { + let url; + try { + url = new URL(href, "http://localhost:1314/" + path.relative(base, file)); + } catch { + continue; + } + if ( + url.hostname !== "localhost" || + !url.pathname.startsWith("/reference/api/") + ) + continue; + const target = path.join( + base, + decodeURIComponent(url.pathname), + url.pathname.endsWith("/") ? "index.html" : "", + ); + if (!fs.existsSync(target)) + problems.push(`Broken API link: ${path.relative(base, file)} -> ${href}`); + } +} +const governance = fs.readFileSync( + path.join(base, "reference/api/ai-governance/index.html"), + "utf8", +); +if (governance.includes("data-api-view=")) + problems.push("Governance renderer changed"); +if (fs.existsSync(path.join(base, "api-prototype"))) + problems.push("Unexpected prototype routes"); +// Historical Engine pages must keep the original renderer at their existing URLs. +for (let minor = 40; minor <= 56; minor++) { + const url = `/reference/api/engine/version/v1.${minor}/`; + const html = fs.readFileSync(path.join(base, url, "index.html"), "utf8"); + if (!html.includes(" n + fs.statSync(p).size, + 0, +); +fs.writeFileSync( + path.join(root, "tmp/api-reference/reports/output.json"), + JSON.stringify( + { htmlMarkdownPagePairs: count, referenceBytes: bytes, result: "pass" }, + null, + 2, + ) + "\n", +); +console.log( + `Verified ${count} HTML/Markdown page pairs and API reference links.`, +); diff --git a/hugo.yaml b/hugo.yaml index adef38e31097..831f2a6b2b9c 100644 --- a/hugo.yaml +++ b/hugo.yaml @@ -327,6 +327,10 @@ module: extended: false min: "0.156.0" mounts: + - source: data + target: data + - source: tmp/api-reference/data + target: data # Mount the assets directory so it doesn't get overwritten - source: assets target: assets diff --git a/layouts/_partials/api-reference/description.html b/layouts/_partials/api-reference/description.html new file mode 100644 index 000000000000..1616cc83a7f5 --- /dev/null +++ b/layouts/_partials/api-reference/description.html @@ -0,0 +1,13 @@ +{{- $text := .text | default "" -}} +{{- $api := .api -}} +{{- range $api.operations -}} + {{- $text = replace $text (printf "(#operation/%s)" .id) (printf "(%s)" .url) -}} + {{- $text = replaceRE (printf "\\(#tag/[^)]+/operation/%s\\)" .id) (printf "(%s)" .url) $text -}} +{{- end -}} +{{- range $api.schemas -}} + {{- $text = replace $text (printf "(#schema-%s)" .name) (printf "(%s)" .url) -}} +{{- end -}} +{{- range $api.tags -}} + {{- $text = replace $text (printf "(#tag/%s)" .name) (printf "(%s#tag-%s)" $api.url (.name | urlize)) -}} +{{- end -}} +{{- return $text -}} diff --git a/layouts/_partials/api-reference/legacy-fragments.html b/layouts/_partials/api-reference/legacy-fragments.html new file mode 100644 index 000000000000..fe67327e48ce --- /dev/null +++ b/layouts/_partials/api-reference/legacy-fragments.html @@ -0,0 +1,47 @@ +{{/* Keep fragment destinations as ordinary links for clients without JavaScript. */}} +
+ Links from the previous reference +
    + {{ range .operations }} + {{ $op := . }} + {{ range slice (printf "operation/%s" .id) (printf "operation-%s" .id) }} +
  • + {{ $op.summary }} +
  • + {{ end }} + {{ range .tags }} +
  • + {{ $op.summary }} +
  • + {{ end }} + {{ end }} + {{ range .schemas }} + {{ $schema := . }} + {{ range slice (printf "schema-%s" .name) (printf "schema-%s" (.name | urlize)) | uniq }} +
  • + {{ $schema.name }} +
  • + {{ end }} + {{ end }} + {{ $api := . }} + {{ range .tags }} +
  • + {{ .summary }} +
  • + {{ end }} +
+
diff --git a/layouts/_partials/api-reference/manual-link.html b/layouts/_partials/api-reference/manual-link.html new file mode 100644 index 000000000000..0b92028d75f7 --- /dev/null +++ b/layouts/_partials/api-reference/manual-link.html @@ -0,0 +1,11 @@ +{{ $data := index hugo.Data "api-reference" }} +{{ range $data.apis }} + {{ $manual := site.GetPage .manual }} + {{ if and $manual (eq $manual.RelPermalink $.RelPermalink) }} +

+ Explore the {{ .title }} API {{ .version }} → +

+ {{ end }} +{{ end }} diff --git a/layouts/_partials/api-reference/navigation.html b/layouts/_partials/api-reference/navigation.html new file mode 100644 index 000000000000..3a814260e04e --- /dev/null +++ b/layouts/_partials/api-reference/navigation.html @@ -0,0 +1,36 @@ +{{ $data := index hugo.Data "api-reference" }} + diff --git a/layouts/_partials/api-reference/overview-tags.html b/layouts/_partials/api-reference/overview-tags.html new file mode 100644 index 000000000000..796138cc1c00 --- /dev/null +++ b/layouts/_partials/api-reference/overview-tags.html @@ -0,0 +1,11 @@ +{{- /* Navigation placeholders and schema-only links are covered by the indexes. */ -}} +{{- $visible := slice -}} +{{- range .tags -}} + {{- $description := strings.TrimSpace (.description | default "") -}} + {{- $placeholder := or (eq $description (printf "%s reference." .summary)) (eq $description (printf "%s operations." .name)) -}} + {{- $schemaLink := findRE `^\[[^\]]+\]\(#schema-[^)]+\)$` $description -}} + {{- if and $description (not $placeholder) (not $schemaLink) -}} + {{- $visible = $visible | append . -}} + {{- end -}} +{{- end -}} +{{- return $visible -}} diff --git a/layouts/_partials/api-reference/path.html b/layouts/_partials/api-reference/path.html new file mode 100644 index 000000000000..cb8045e25430 --- /dev/null +++ b/layouts/_partials/api-reference/path.html @@ -0,0 +1,4 @@ +{{- /* Break long paths between segments without changing their copied text. */ -}} +{{- range $i, $segment := split . "/" -}} + {{- if $i -}}/{{- end -}}{{- $segment -}} +{{- end -}} diff --git a/layouts/_partials/api-reference/schema.html b/layouts/_partials/api-reference/schema.html new file mode 100644 index 000000000000..d044f93dafab --- /dev/null +++ b/layouts/_partials/api-reference/schema.html @@ -0,0 +1,85 @@ +{{ $s := .schema }}{{ $api := .api }}{{ $depth := .depth }} +{{ if reflect.IsMap $s }} + {{ with index $s "$ref" }} + {{ $url := index $api.schemaURLs . }} +

+ Schema: + {{ if $url }} + {{ strings.TrimPrefix "#/components/schemas/" . }} + {{ else }} + {{ . }} + {{ end }} +

+ {{ end }} + {{ with $s.type }} +

+ Type: + {{ if reflect.IsSlice . }} + {{ delimit . " | " }} + {{ else }} + {{ . }} + {{ end }} +

+ {{ end }} + {{ with $s.description }} +
{{ . | markdownify }}
+ {{ end }} + {{ if lt $depth 3 }} + {{ range $name,$v := $s.properties }} +
+ + {{ $name }}{{ if in $s.required $name }} + · required + {{ end }}{{ if $v.readOnly }} + · response only + {{ end }}{{ if $v.writeOnly }}· request only{{ end }} + + {{ partial "api-reference/schema.html" (dict "schema" $v "api" $api "depth" (add $depth 1)) }} +
+ {{ end }} + {{ range $keyword := slice "allOf" "oneOf" "anyOf" }} + {{ with index $s $keyword }} +
+ + {{ if eq $keyword "allOf" }} + All constraints apply + {{ else if eq $keyword "oneOf" }} + Exactly one alternative must match + {{ else }} + One or more alternatives must match + {{ end }} + + {{ range . }} + {{ partial "api-reference/schema.html" (dict "schema" . "api" $api "depth" (add $depth 1)) }} + {{ end }} +
+ {{ end }} + {{ end }} + {{ if isset $s "items" }} +
+ Array item + {{ partial "api-reference/schema.html" (dict "schema" $s.items "api" $api "depth" (add $depth 1)) }} +
+ {{ end }} + {{ end }} + {{ if or (ge $depth 3) (not (index $s "$ref")) (gt (len $s) 1) }} +
+ All schema constraints and annotations +
{{ $s | jsonify (dict "indent" "  ") }}
+
+ {{ end }} +{{ else }} +

+ {{ if eq $s false }} + No value satisfies this schema. + {{ else if eq $s true }} + Any value satisfies this schema. + {{ else }} + No schema is declared. + {{ end }} +

+{{ end }} diff --git a/layouts/_partials/content-default.html b/layouts/_partials/content-default.html index 9d7c32067066..73580a30d58c 100644 --- a/layouts/_partials/content-default.html +++ b/layouts/_partials/content-default.html @@ -12,6 +12,7 @@

{{ .Title | safeHTML }}

{{ partialCached "pagemeta.html" . . }}
+{{ partial "api-reference/manual-link.html" . }} {{ .Content }} {{- if and (eq .Type "guides") (not .IsSection) (ne .CurrentSection .FirstSection) -}} {{- with .PrevInSection -}} diff --git a/layouts/_partials/sidebar/sections.html b/layouts/_partials/sidebar/sections.html index ab1650ff1a86..0bd06b5dcd8a 100644 --- a/layouts/_partials/sidebar/sections.html +++ b/layouts/_partials/sidebar/sections.html @@ -30,7 +30,7 @@ {{- end }} {{- $ungrouped := where $pages "Params.sidebar.group" "==" nil }} {{- range $ungrouped }} - {{- if .IsSection }} + {{- if and .IsSection (not .Params.apiID) }} {{- template "renderList" (dict "section" . "revealHidden" $revealHidden) }} {{- else }} {{- template "renderSingle" . }} @@ -43,7 +43,7 @@ {{ . }} {{- range where $pages "Params.sidebar.group" . }} - {{- if .IsSection }} + {{- if and .IsSection (not .Params.apiID) }} {{- template "renderList" (dict "section" . "revealHidden" $revealHidden) }} {{- else }} {{- template "renderSingle" . }} diff --git a/layouts/alias.html b/layouts/alias.html new file mode 100644 index 000000000000..644449552ce0 --- /dev/null +++ b/layouts/alias.html @@ -0,0 +1,31 @@ +{{ if eq .Page.Params.apiID "dvp" }} + + + + + Redirecting + + + + + + Continue to the documentation + + +{{ else }} + + + + {{ .Permalink }} + + + + + +{{ end }} diff --git a/layouts/api-docs.html b/layouts/api-docs.html new file mode 100644 index 000000000000..8415d179c350 --- /dev/null +++ b/layouts/api-docs.html @@ -0,0 +1,367 @@ +{{ define "head-extra" }} + {{ $style := resources.Get "api-reference/reference.css" | fingerprint }} + + {{ $script := resources.Get "api-reference/reference.js" | fingerprint }} + +{{ end }} +{{ define "left" }} + {{ partial "sidebar/mainnav.html" . }} + {{ if eq .Params.view "catalog" }} + {{ partial "sidebar/sections.html" . }} + {{ else }} + {{ partial "api-reference/navigation.html" . }} + {{ end }} +{{ end }} +{{ define "main" }} +
+ {{ $data := index hugo.Data "api-reference" }} + {{ $api := dict }}{{ range $data.apis }} + {{ if eq .id $.Params.apiID }}{{ $api = . }}{{ end }} + {{ end }} + {{ if eq .Params.view "catalog" }} +

Developer reference

+

Docker APIs

+

+ Build with Docker, from your local daemon to hosted services. +

+

+ Choose an API to find connection guidance, operations, and data models. +

+ + {{ else }} + +
+ Product manualDownload OpenAPI specificationMarkdown +
+ + {{ if eq .Params.view "overview" }} +

+ {{ if eq $api.connection "unix" }} + User-operated API + {{ else }} + Hosted API + {{ end }} +

+

{{ $api.title }} API

+

+ API {{ $api.version }} · {{ len $api.operations }} operations · + {{ len $api.schemas }} named schemas +

+
+

Overview

+
+ {{ partial "api-reference/description.html" (dict "text" $api.description "api" $api) | markdownify }} +
+
+
+

+ {{ if eq $api.connection "unix" }} + Connecting to + {{ $api.title }} + {{ else }} + Connecting to the {{ $api.title }} API + {{ end }} +

+

{{ $api.auth }}

+ {{ if eq $api.connection "unix" }} +
curl --unix-socket /var/run/docker.sock http://localhost/v{{ $api.version }}/version
+ {{ else }} + {{ range $api.servers }}{{ .url }}{{ end }} + {{ end }}{{ range $api.guides }} + {{ $guide := site.GetPage (index (split . "#") 0) }} +

{{ $guide.Title }}

+ {{ end }} +
+
+ {{ $overviewTags := partial "api-reference/overview-tags.html" $api }} + {{ range $api.tags }} + {{ if not (in $overviewTags .) }} + + {{ end }} + {{ end }} + {{ range $overviewTags }} +
+

{{ .summary }}

+
+ {{ partial "api-reference/description.html" (dict "text" .description "api" $api) | markdownify }} +
+
+ {{ end }} +
+

Operations

+ +
+ {{ range $api.operations }} + {{ .method }}{{ partial "api-reference/path.html" .path }}{{ .summary }} + {{ end }} +
+

Schemas

+ + {{ partial "api-reference/legacy-fragments.html" $api }} + {{ else if eq .Params.view "operation" }} + {{ range $api.operations }} + {{ if eq .id $.Params.operationID }} +

{{ .summary }}

+
+ {{ .method }}{{ partial "api-reference/path.html" .path }}{{ if .deprecated }} + Deprecated + {{ end }} +
+
+
+
+ {{ partial "api-reference/description.html" (dict "text" .description "api" $api) | markdownify }} +
+

Connection and access

+

{{ $api.auth }}

+ {{ if and (eq $api.product "engine") (where .parameters "name" "X-Registry-Auth") }} +

+ X-Registry-Auth delegates registry credentials + and does not authenticate the daemon caller. +

+ {{ end }} + {{ range .servers }} +

+ {{ .url }}{{ with .description }} + — + {{ . }} + {{ end }} +

+ {{ end }} + {{ if not .security }} +

+ No HTTP authentication requirement is declared for this + operation. Transport access controls can still apply. +

+ {{ else }} +

+ Use one of these alternatives. Requirements within an + alternative apply together. +

+
    + {{ range .security }} +
  • + {{ $first := true }}{{ range $name, $scopes := . }} + {{ if not $first }} + AND + {{ end }}{{ $first = false }}{{ $name }}{{ with $scopes }} + ({{ delimit . ", " }}) + {{ end }} + {{ end }}{{ if $first }}Anonymous access{{ end }} +
  • + {{ end }} +
+ {{ end }} +

Parameters

+ {{ if not .parameters }} +

No parameters are declared.

+ {{ end }} + {{ range .parameters }} +
+

+ {{ .name }} + {{ .in }} + {{ if .required }} + Required + {{ end }} +

+
+ {{ partial "api-reference/description.html" (dict "text" .description "api" $api) | markdownify }} +
+ {{ if isset . "schema" }} + {{ partial "api-reference/schema.html" (dict "schema" .schema "api" $api "depth" 0) }} + {{ end }}{{ with .content }} +
{{ . | jsonify (dict "indent" "  ") }}
+ {{ end }}{{ with .style }} +

Serialization: {{ . }}

+ {{ end }} +
+ {{ end }} +

Request and responses

+ + {{ range $i, $v := .variants }} +
+

+ {{ $v.direction | humanize }} + {{ with $v.status }} + {{ . }} + {{ end }} +

+
+ {{ partial "api-reference/description.html" (dict "text" $v.description "api" $api) | markdownify }} +
+ {{ if $v.media }} +

{{ $v.media }}

+ {{ else }} +

No response content is declared.

+ {{ end }} + {{ with $v.headers }} +

Headers

+ {{ range $name,$header := . }} +
+ {{ $name }} +

{{ $header.description }}

+
{{ $header | jsonify (dict "indent" "  ") }}
+
+ {{ end }} + {{ end }} + {{ if isset $v "schema" }} + {{ partial "api-reference/schema.html" (dict "schema" $v.schema "api" $api "depth" 0) }} + {{ end }} + {{ if isset $v "itemSchema" }} +

Stream item

+ {{ partial "api-reference/schema.html" (dict "schema" $v.itemSchema "api" $api "depth" 0) }} + {{ end }} + {{ if $v.examples }} +
+ {{ if gt (len $v.examples) 1 }} + + {{ end }}{{ range $j,$ex := $v.examples }} +
+

{{ $ex.name }}

+ {{ if eq $ex.valid false }} +

+ Source example does not satisfy its schema; + owner review is required. +

+ {{ end }} +
{{ $ex.value | jsonify (dict "indent" "  ") }}
+
+ {{ end }} +
+ {{ end }} +
+ {{ end }} +

Referenced schemas

+ {{ range .references }} + {{ if .url }} +

{{ .ref }}

+ {{ end }} + {{ end }} +
+ Complete operation contract +
{{ .raw | jsonify (dict "indent" "  ") }}
+
+
+ +
+ {{ end }} + {{ end }} + {{ else if eq .Params.view "schema" }} + {{ range $api.schemas }} + {{ if eq .name $.Params.schemaName }} +

Schema

+

{{ .name }}

+ {{ partial "api-reference/schema.html" (dict "schema" .schema "api" $api "depth" 0) }} + {{ end }} + {{ end }} + {{ end }} + {{ end }} +
+{{ end }} diff --git a/layouts/api-docs.markdown.md b/layouts/api-docs.markdown.md new file mode 100644 index 000000000000..4319f550a3f4 --- /dev/null +++ b/layouts/api-docs.markdown.md @@ -0,0 +1,154 @@ +{{- $data := index hugo.Data "api-reference" -}} +{{- $api := dict -}}{{- range $data.apis -}}{{- if eq .id $.Params.apiID -}}{{- $api = . -}}{{- end -}}{{- end -}} +# {{ .Title }} + +{{ if eq .Params.view "catalog" }} +Choose a Docker HTTP API: +{{ range $data.apis }} +- [{{ .title }} API {{ .version }}]({{ .url }}): {{ len .operations }} operations; {{ .connection }} connection +{{ end }} +{{ range $data.legacyAPIs }} +- [{{ .title }}]({{ .url }}): {{ .description }} +{{ end }} +{{ else }} +[API catalog](/reference/api/) · [{{ $api.title }} overview]({{ $api.url }}) · [Product manual]({{ ref . $api.manual }}) · [OpenAPI specification]({{ $api.sourceURL }}) + +API version: {{ $api.version }} + +{{ if eq .Params.view "overview" }} +## Overview + +{{ partial "api-reference/description.html" (dict "text" $api.description "api" $api) }} +## {{ if eq $api.connection "unix" }}Connecting to {{ $api.title }}{{ else }}Connecting to the {{ $api.title }} API{{ end }} + +{{ $api.auth }} +{{ range $api.servers }} +Server: `{{ .url }}` +{{ end }} +{{ if eq $api.connection "unix" }} +```console +curl --unix-socket /var/run/docker.sock http://localhost/v{{ $api.version }}/version +``` +{{ end }} +{{ range $api.guides }} +{{ $guide := site.GetPage (index (split . "#") 0) }} +- [{{ $guide.Title }}]({{ ref $ . }}) +{{ end }} + +{{ range (partial "api-reference/overview-tags.html" $api) }} +## {{ .summary }} + +{{ partial "api-reference/description.html" (dict "text" .description "api" $api) }} +{{ end }} +## Operations +{{ range $api.operations }} +- [{{ .method }} {{ .path }}]({{ .url }}): {{ .summary }} +{{ end }} +## Schemas +{{ range $api.schemas }} +- [{{ .name }}]({{ .url }}) +{{ end }} +{{ else if eq .Params.view "operation" }} +{{ range $api.operations }}{{ if eq .id $.Params.operationID }} +`{{ .method }} {{ .path }}` + +{{ partial "api-reference/description.html" (dict "text" .description "api" $api) }} +{{ if .deprecated }} +Deprecated operation. +{{ end }} +## Connection and access + +{{ $api.auth }} +{{ if and (eq $api.product "engine") (where .parameters "name" "X-Registry-Auth") }} +`X-Registry-Auth` delegates registry credentials and does not authenticate the daemon caller. +{{ end }} +{{ range .servers }} +Server: `{{ .url }}` +{{ end }} +Effective security: alternatives are OR; schemes within an alternative are AND. An empty array declares no HTTP authentication requirement. + +```json +{{ .security | jsonify (dict "indent" " ") }} +``` +## Example request + +Replace placeholders and provide the required credentials or request body. + +```console +{{ .curl }} +``` +{{ range .curlNotes }} +{{ . }} +{{ end }} +## Parameters +{{ range .parameters }} +### {{ .name }} + +Location: {{ .in }}. Required: {{ if .required }}yes{{ else }}no{{ end }}. + +{{ partial "api-reference/description.html" (dict "text" .description "api" $api) }} + +```json +{{ . | jsonify (dict "indent" " ") }} +``` +{{ end }} +## Request and responses +{{ range .variants }} +### {{ .direction }} {{ .status }} {{ .media }} + +{{ partial "api-reference/description.html" (dict "text" .description "api" $api) }} +{{ if not .media }} +No response content is declared. +{{ end }} +{{ if isset . "schema" }} +Schema: + +```json +{{ .schema | jsonify (dict "indent" " ") }} +``` +{{ end }} +{{ if isset . "itemSchema" }} +Stream item schema: + +```json +{{ .itemSchema | jsonify (dict "indent" " ") }} +``` +{{ end }} +{{ with .headers }} +Headers: + +```json +{{ . | jsonify (dict "indent" " ") }} +``` +{{ end }} +{{ range .examples }} +{{ .name }}: +{{ if eq .valid false }} +Source example does not satisfy its schema; owner review is required. +{{ end }} +```json +{{ .value | jsonify (dict "indent" " ") }} +``` +{{ end }} +{{ end }} +## Complete operation contract + +```json +{{ .raw | jsonify (dict "indent" " ") }} +``` + +## Referenced schemas +{{ range .references }} +- {{ if .url }}[{{ .ref }}]({{ .url }}){{ else }}`{{ .ref }}`{{ end }} +{{ end }} +{{ end }}{{ end }} +{{ else if eq .Params.view "schema" }} +{{ range $api.schemas }}{{ if eq .name $.Params.schemaName }} +Schema constraints and annotations: + +```json +{{ .schema | jsonify (dict "indent" " ") }} +``` +{{ end }}{{ end }} +{{ end }} +{{ end }} diff --git a/layouts/baseof.html b/layouts/baseof.html index 823d4a087912..87dfff2839fd 100644 --- a/layouts/baseof.html +++ b/layouts/baseof.html @@ -2,6 +2,7 @@ {{ partial "head.html" . }} + {{ block "head-extra" . }}{{ end }} Date: Wed, 9 Sep 2026 12:26:17 +0000 Subject: [PATCH 05/13] docs: remove migration records from API implementation --- hack/api-docs/README.md | 7 +- hack/api-docs/adoption/README.md | 34 - hack/api-docs/adoption/dvp.json | 389 --- hack/api-docs/adoption/dvp.patch | 692 ------ hack/api-docs/adoption/hub.json | 2950 ----------------------- hack/api-docs/adoption/hub.patch | 2056 ---------------- hack/api-docs/adoption/registry.json | 247 -- hack/api-docs/adoption/registry.patch | 606 ----- hack/api-docs/adoption/source-lock.json | 53 - 9 files changed, 4 insertions(+), 7030 deletions(-) delete mode 100644 hack/api-docs/adoption/README.md delete mode 100644 hack/api-docs/adoption/dvp.json delete mode 100644 hack/api-docs/adoption/dvp.patch delete mode 100644 hack/api-docs/adoption/hub.json delete mode 100644 hack/api-docs/adoption/hub.patch delete mode 100644 hack/api-docs/adoption/registry.json delete mode 100644 hack/api-docs/adoption/registry.patch delete mode 100644 hack/api-docs/adoption/source-lock.json diff --git a/hack/api-docs/README.md b/hack/api-docs/README.md index 5e3eed6741e3..8190179f52f4 100644 --- a/hack/api-docs/README.md +++ b/hack/api-docs/README.md @@ -39,7 +39,8 @@ Hugo reports an error if the generated data is absent. The published YAML URLs still serve the source files directly. There is no conversion step, snapshot dependency, Node migration package, or source archive -in the build. Historical conversion evidence lives in [adoption](adoption/README.md). +in the build. The source diff and +[prototype PR](https://github.com/docker/docs/pull/26043) provide migration context. ## Validation baseline @@ -58,8 +59,8 @@ features cannot be waived. Unrecorded diagnostics fail the build. This baseline is review debt, not approval of API behavior. Strict validation fails until the issues are resolved. Any source edit requires deliberate review of the affected baseline entries; the build never refreshes them automatically. -Product decisions listed in the adoption record remain merge blockers for this -draft implementation. +The implementation PR tracks the product decisions that require confirmation +before merge. ## Tests and scope diff --git a/hack/api-docs/adoption/README.md b/hack/api-docs/adoption/README.md deleted file mode 100644 index b9e24ec5ea79..000000000000 --- a/hack/api-docs/adoption/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Local API source adoption - -This directory preserves the source-review evidence from -[the API documentation prototype](https://github.com/docker/docs/pull/26043). -The sibling implementation reads the authoritative local files directly. -No migration scripts or duplicate source snapshots are required to build it. - -The JSON ledgers retain before/after values, source pointers, classifications, -evidence, and stable change IDs. Textual patches show the original conversions. -`source-lock.json` identifies the baseline revision and source digests. Historical -profile names and paths in these records describe that conversion, rather than -runtime inputs. Keep these records unchanged when making subsequent corrections; -record those corrections in separate reviewed commits. - -| API | Recorded changes | Review before merge | -| --- | ---: | --- | -| [Hub](hub.json) | 157 | Confirm the provisional `team_repo` response schema. Review requiredness corrections, assigned operation IDs, and the inherited example mismatches. Preserve separate SCIM credentials. | -| [DVP](dvp.json) | 14 | Confirm operation-level security matches service behavior and the documented legacy login flow remains supported. Preserve authentication server overrides. | -| [Registry](registry.json) | 7 | Confirm `info.version: 2` and the bearer security declaration, including anonymous access alternatives. | - -The runtime validation baseline is in `../known-issues.json`. Its 289 entries -remain visible in generated validation reports, without exposing migration -administration in reference pages. Resolve or explicitly approve the remaining -quality debt before production adoption. Contract assumptions require product -evidence; accepting documentation debt does not confirm those assumptions. - -Published YAML retains its URL but changes to OpenAPI 3.2. Consumers of the YAML -must be considered before release: URL compatibility does not imply parser -compatibility. Existing page URLs, the DVP alias, and operation/tag/schema -fragment links remain supported. JavaScript follows historical operation -fragments to individual pages; without it, the overview supplies ordinary links. - -Engine and Governance migration, historical Engine conversion, SDK catalogs, -and broader site information architecture are outside this implementation. diff --git a/hack/api-docs/adoption/dvp.json b/hack/api-docs/adoption/dvp.json deleted file mode 100644 index 034699bd2ccd..000000000000 --- a/hack/api-docs/adoption/dvp.json +++ /dev/null @@ -1,389 +0,0 @@ -{ - "api": "dvp", - "source": { - "id": "dvp", - "product": "dvp", - "title": "Publisher analytics", - "source": "content/reference/api/dvp/latest.yaml", - "owner": "docker/docs (product authority to confirm)", - "manual": "/manuals/docker-hub/repos/manage/trusted-content/insights-analytics.md", - "connection": "hosted", - "auth": "Analytics calls use a bearer token. The copied source retains the legacy login flow pending product confirmation.", - "guides": [], - "sha256": "4aeacaaa1237609c3dd9cec43f9807a229ac98a0e9b837f291c02df3cf89172a" - }, - "convertedSha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "profile": "docker-docs-prototype-1", - "changes": [ - { - "pointer": "/jsonSchemaDialect", - "beforePresent": false, - "afterPresent": true, - "after": "https://spec.openapis.org/oas/3.1/dialect/base", - "id": "dvp-03ee85af235e", - "stage": "oas32-header", - "classification": "mechanical conversion", - "rationale": "Adopt the common OpenAPI version and its selected schema dialect.", - "evidence": "API-DOCUMENTATION-ARCHITECTURE.md S1", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/jsonSchemaDialect" - }, - { - "pointer": "/openapi", - "beforePresent": true, - "afterPresent": true, - "before": "3.0.0", - "after": "3.2.0", - "id": "dvp-71377657b6ae", - "stage": "oas32-header", - "classification": "mechanical conversion", - "rationale": "Adopt the common OpenAPI version and its selected schema dialect.", - "evidence": "API-DOCUMENTATION-ARCHITECTURE.md S1", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/openapi", - "destinationPointer": "/openapi" - }, - { - "pointer": "/components/schemas/PostUsers2FALoginErrorResponse/properties/detail/nullable", - "beforePresent": true, - "afterPresent": false, - "before": false, - "id": "dvp-4a84441cce53", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/PostUsers2FALoginErrorResponse/properties/detail/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/PostUsersLoginErrorResponse/properties/detail/nullable", - "beforePresent": true, - "afterPresent": false, - "before": false, - "id": "dvp-209f129099a9", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/PostUsersLoginErrorResponse/properties/detail/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "dvp-74ca1738d170", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "dvp-14920c5fdaca", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/type", - "destinationPointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/type" - }, - { - "pointer": "/components/schemas/PostUsersLoginSuccessResponse/properties/token/nullable", - "beforePresent": true, - "afterPresent": false, - "before": false, - "id": "dvp-f4382a2a3adb", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/PostUsersLoginSuccessResponse/properties/token/nullable", - "destinationPointer": null - }, - { - "pointer": "/tags", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "name": "authentication", - "x-displayName": "Authentication Endpoints" - }, - { - "name": "namespaces", - "x-displayName": "Namespace data" - }, - { - "name": "discovery", - "x-displayName": "Discovery" - }, - { - "name": "responseDataFile", - "x-displayName": "ResponseDataFile", - "description": "\n" - }, - { - "name": "yearModel", - "x-displayName": "Year Data Model", - "description": "\n" - }, - { - "name": "monthModel", - "x-displayName": "Month Data Model", - "description": "\n" - }, - { - "name": "weekModel", - "x-displayName": "Week Data Model", - "description": "\n" - } - ], - "after": [ - { - "name": "authentication", - "summary": "Authentication Endpoints", - "kind": "nav", - "description": "Authentication Endpoints reference." - }, - { - "name": "namespaces", - "summary": "Namespace data", - "kind": "nav", - "description": "Namespace data reference." - }, - { - "name": "discovery", - "summary": "Discovery", - "kind": "nav", - "description": "Discovery reference." - }, - { - "name": "responseDataFile", - "description": "[ResponseDataFile](#schema-ResponseDataFile)\n", - "summary": "ResponseDataFile", - "kind": "info" - }, - { - "name": "yearModel", - "description": "[YearModel](#schema-YearModel)\n", - "summary": "Year Data Model", - "kind": "info" - }, - { - "name": "monthModel", - "description": "[MonthModel](#schema-MonthModel)\n", - "summary": "Month Data Model", - "kind": "info" - }, - { - "name": "weekModel", - "description": "[WeekModel](#schema-WeekModel)\n", - "summary": "Week Data Model", - "kind": "info" - } - ], - "id": "dvp-8d93cf25f3e7", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/tags", - "destinationPointer": "/tags" - }, - { - "pointer": "/tags", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "name": "authentication", - "summary": "Authentication Endpoints", - "kind": "nav", - "description": "Authentication Endpoints reference." - }, - { - "name": "namespaces", - "summary": "Namespace data", - "kind": "nav", - "description": "Namespace data reference." - }, - { - "name": "discovery", - "summary": "Discovery", - "kind": "nav", - "description": "Discovery reference." - }, - { - "name": "responseDataFile", - "description": "\n", - "summary": "ResponseDataFile", - "kind": "info" - }, - { - "name": "yearModel", - "description": "\n", - "summary": "Year Data Model", - "kind": "info" - }, - { - "name": "monthModel", - "description": "\n", - "summary": "Month Data Model", - "kind": "info" - }, - { - "name": "weekModel", - "description": "\n", - "summary": "Week Data Model", - "kind": "info" - } - ], - "after": [ - { - "name": "authentication", - "summary": "Authentication Endpoints", - "kind": "nav", - "description": "Authentication Endpoints reference." - }, - { - "name": "namespaces", - "summary": "Namespace data", - "kind": "nav", - "description": "Namespace data reference." - }, - { - "name": "discovery", - "summary": "Discovery", - "kind": "nav", - "description": "Discovery reference." - }, - { - "name": "responseDataFile", - "description": "[ResponseDataFile](#schema-ResponseDataFile)\n", - "summary": "ResponseDataFile", - "kind": "info" - }, - { - "name": "yearModel", - "description": "[YearModel](#schema-YearModel)\n", - "summary": "Year Data Model", - "kind": "info" - }, - { - "name": "monthModel", - "description": "[MonthModel](#schema-MonthModel)\n", - "summary": "Month Data Model", - "kind": "info" - }, - { - "name": "weekModel", - "description": "[WeekModel](#schema-WeekModel)\n", - "summary": "Week Data Model", - "kind": "info" - } - ], - "id": "dvp-8c67a3d8bd5a", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/tags", - "destinationPointer": "/tags" - }, - { - "pointer": "/components/securitySchemes/HubAuth/type", - "beforePresent": true, - "afterPresent": true, - "before": "https", - "after": "http", - "id": "dvp-0825c9518516", - "stage": "dvp-structural-correction", - "classification": "evidence-backed correction", - "rationale": "Use the standard http bearer scheme and move invalid path security to each operation without changing the documented requirement.", - "evidence": "Existing HubAuth bearer definition and path-level security declarations", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/securitySchemes/HubAuth/type", - "destinationPointer": "/components/securitySchemes/HubAuth/type" - }, - { - "pointer": "/features.openapi", - "beforePresent": true, - "afterPresent": false, - "before": { - "schemaDefinitionsTagName": "Schemas" - }, - "id": "dvp-133a84bacaf5", - "stage": "dvp-structural-correction", - "classification": "evidence-backed correction", - "rationale": "Use the standard http bearer scheme and move invalid path security to each operation without changing the documented requirement.", - "evidence": "Existing HubAuth bearer definition and path-level security declarations", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/features.openapi", - "destinationPointer": null - }, - { - "pointer": "/paths/~1v2~1users~12fa-login/security", - "beforePresent": true, - "afterPresent": false, - "before": [], - "id": "dvp-bbb175aad84a", - "stage": "dvp-structural-correction", - "classification": "evidence-backed correction", - "rationale": "Use the standard http bearer scheme and move invalid path security to each operation without changing the documented requirement.", - "evidence": "Existing HubAuth bearer definition and path-level security declarations", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1users~12fa-login/security", - "destinationPointer": null - }, - { - "pointer": "/paths/~1v2~1users~1login/security", - "beforePresent": true, - "afterPresent": false, - "before": [], - "id": "dvp-a0ab3de3a681", - "stage": "dvp-structural-correction", - "classification": "evidence-backed correction", - "rationale": "Use the standard http bearer scheme and move invalid path security to each operation without changing the documented requirement.", - "evidence": "Existing HubAuth bearer definition and path-level security declarations", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1users~1login/security", - "destinationPointer": null - }, - { - "pointer": "/x-features-openapi", - "beforePresent": false, - "afterPresent": true, - "after": { - "schemaDefinitionsTagName": "Schemas" - }, - "id": "dvp-b66b5e3c3512", - "stage": "dvp-structural-correction", - "classification": "evidence-backed correction", - "rationale": "Use the standard http bearer scheme and move invalid path security to each operation without changing the documented requirement.", - "evidence": "Existing HubAuth bearer definition and path-level security declarations", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/x-features-openapi" - } - ] -} diff --git a/hack/api-docs/adoption/dvp.patch b/hack/api-docs/adoption/dvp.patch deleted file mode 100644 index b7aa184cbba6..000000000000 --- a/hack/api-docs/adoption/dvp.patch +++ /dev/null @@ -1,692 +0,0 @@ ---- original/dvp.yaml -+++ converted/dvp.yaml -@@ -1,4 +1,4 @@ --openapi: 3.0.0 -+openapi: 3.2.0 - info: - title: DVP Data API - version: 1.0.0 -@@ -6,75 +6,79 @@ - url: https://docs.docker.com/assets/images/logo-docker-main.png - href: /reference - description: | -- The Docker DVP Data API allows [Docker Verified Publishers](https://docs.docker.com/docker-hub/publish/) to view image pull analytics data for their namespaces. Analytics data can be retrieved in a CSV as raw data, or in a summary format. -- -- #### Summary data -- -- In your summary data CSV, you will have access to the data points listed below. You can request summary data for a complete week (Monday through Sunday) or for a complete month (available on the first day of the following month). -- -- There are two levels of summary data: -- -- - Repository-level, a summary of every namespace and repository -- - Tag- or digest-level, a summary of every namespace, repository, and reference -- (tag or digest) -- -- The summary data formats contain the following data points: -- -- - Unique IP address count -- - Pulls by tag count -- - Pulls by digest count -- - Version check count -- -- #### Raw data -- -- In your raw data CSV you will have access to the data points listed below. You can request raw data for a complete week (Monday through Sunday) or for a complete month (available on the first day of the following month). **Note:** each action is represented as a single row. -- -- - Type (industry) -- - Host (cloud provider) -- - Country (geolocation) -- - Timestamp -- - Namespace -- - Repository -- - Reference (digest is always included, tag is provided when available) -- - HTTP request method -- - Action, one of the following: -- - Pull by tag -- - Pull by digest -- - Version check -- - User-Agent -- -+ The Docker DVP Data API allows [Docker Verified Publishers](https://docs.docker.com/docker-hub/publish/) to view image pull analytics data for their namespaces. Analytics data can be retrieved in a CSV as raw data, or in a summary format. -+ -+ #### Summary data -+ -+ In your summary data CSV, you will have access to the data points listed below. You can request summary data for a complete week (Monday through Sunday) or for a complete month (available on the first day of the following month). -+ -+ There are two levels of summary data: -+ -+ - Repository-level, a summary of every namespace and repository -+ - Tag- or digest-level, a summary of every namespace, repository, and reference -+ (tag or digest) -+ -+ The summary data formats contain the following data points: -+ -+ - Unique IP address count -+ - Pulls by tag count -+ - Pulls by digest count -+ - Version check count -+ -+ #### Raw data -+ -+ In your raw data CSV you will have access to the data points listed below. You can request raw data for a complete week (Monday through Sunday) or for a complete month (available on the first day of the following month). **Note:** each action is represented as a single row. -+ -+ - Type (industry) -+ - Host (cloud provider) -+ - Country (geolocation) -+ - Timestamp -+ - Namespace -+ - Repository -+ - Reference (digest is always included, tag is provided when available) -+ - HTTP request method -+ - Action, one of the following: -+ - Pull by tag -+ - Pull by digest -+ - Version check -+ - User-Agent - servers: - - url: https://hub.docker.com/api/publisher/analytics/v1 - security: - - HubAuth: [] -- --features.openapi: -- schemaDefinitionsTagName: Schemas -- - tags: - - name: authentication -- x-displayName: Authentication Endpoints -+ summary: Authentication Endpoints -+ kind: nav -+ description: Authentication Endpoints reference. - - name: namespaces -- x-displayName: Namespace data -+ summary: Namespace data -+ kind: nav -+ description: Namespace data reference. - - name: discovery -- x-displayName: Discovery -+ summary: Discovery -+ kind: nav -+ description: Discovery reference. - - name: responseDataFile -- x-displayName: ResponseDataFile - description: | -- -+ [ResponseDataFile](#schema-ResponseDataFile) -+ summary: ResponseDataFile -+ kind: info - - name: yearModel -- x-displayName: Year Data Model - description: | -- -+ [YearModel](#schema-YearModel) -+ summary: Year Data Model -+ kind: info - - name: monthModel -- x-displayName: Month Data Model - description: | -- -+ [MonthModel](#schema-MonthModel) -+ summary: Month Data Model -+ kind: info - - name: weekModel -- x-displayName: Week Data Model - description: | -- -- -+ [WeekModel](#schema-WeekModel) -+ summary: Week Data Model -+ kind: info - x-tagGroups: - - name: API - tags: -@@ -87,10 +91,8 @@ - - yearModel - - monthModel - - weekModel -- - paths: - /v2/users/login: -- security: [] - servers: - - url: https://hub.docker.com - post: -@@ -114,20 +116,19 @@ - description: Login details. - required: true - responses: -- 200: -+ "200": - description: Authentication successful - content: - application/json: - schema: - $ref: "#/components/schemas/PostUsersLoginSuccessResponse" -- 401: -+ "401": - description: Authentication failed or second factor required - content: - application/json: - schema: - $ref: "#/components/schemas/PostUsersLoginErrorResponse" - /v2/users/2fa-login: -- security: [] - servers: - - url: https://hub.docker.com - post: -@@ -153,53 +154,54 @@ - description: Login details. - required: true - responses: -- 200: -+ "200": - description: Authentication successful - content: - application/json: - schema: - $ref: "#/components/schemas/PostUsersLoginSuccessResponse" -- 401: -+ "401": - description: Authentication failed or second factor required - content: - application/json: - schema: - $ref: "#/components/schemas/PostUsers2FALoginErrorResponse" -- -- - /: - get: -- tags: [discovery] -+ tags: -+ - discovery - summary: Get namespaces and repos - description: Gets a list of your namespaces and repos which have data available. - operationId: getNamespaces - responses: -- '200': -+ "200": - description: Success - content: - application/json: - schema: -- $ref: '#/components/schemas/NamespaceData' -+ $ref: "#/components/schemas/NamespaceData" - /namespaces: - get: -- tags: [discovery] -+ tags: -+ - discovery - summary: Get user's namespaces - description: Get metadata associated with the namespaces the user has access to, including extra repos associated with the namespaces. - operationId: getUserNamespaces - responses: -- '200': -+ "200": - description: Success - content: - application/json: - schema: - type: array - items: -- $ref: '#/components/schemas/NamespaceMetadata' -- '401': -+ $ref: "#/components/schemas/NamespaceMetadata" -+ "401": - description: Authentication failed or second factor required - /namespaces/{namespace}: - get: -- tags: [discovery] -+ tags: -+ - discovery - summary: Get namespace - description: Gets metadata associated with specified namespace, including extra repos associated with the namespace. - operationId: getNamespace -@@ -211,15 +213,16 @@ - required: true - description: Namespace to fetch data for - responses: -- '200': -+ "200": - description: Success - content: - application/json: - schema: -- $ref: '#/components/schemas/NamespaceMetadata' -+ $ref: "#/components/schemas/NamespaceMetadata" - /namespaces/{namespace}/pulls: - get: -- tags: [namespaces] -+ tags: -+ - namespaces - summary: Get pull data - description: Gets pulls for the given namespace. - operationId: getNamespacePulls -@@ -233,33 +236,34 @@ - - in: query - name: timespan - schema: -- $ref: '#/components/schemas/TimespanType' -+ $ref: "#/components/schemas/TimespanType" - required: false - description: Timespan type for fetching data - - in: query - name: period - schema: -- $ref: '#/components/schemas/PeriodType' -+ $ref: "#/components/schemas/PeriodType" - required: false - description: Relative period of the period to fetch data - - in: query - name: group - schema: -- $ref: '#/components/schemas/GroupType' -+ $ref: "#/components/schemas/GroupType" - required: false - description: Field to group the data by - responses: -- '200': -+ "200": - description: Success - content: - application/json: - schema: -- $ref: '#/components/schemas/PullData' -- '404': -+ $ref: "#/components/schemas/PullData" -+ "404": - description: Not found - namespace doesn't exist or user does not have permission to access it - /namespaces/{namespace}/repos/{repo}/pulls: - get: -- tags: [namespaces] -+ tags: -+ - namespaces - summary: Get pull data - description: Gets pulls for the given repo. - operationId: getRepoPulls -@@ -279,33 +283,34 @@ - - in: query - name: timespan - schema: -- $ref: '#/components/schemas/TimespanType' -+ $ref: "#/components/schemas/TimespanType" - required: false - description: Timespan type for fetching data - - in: query - name: period - schema: -- $ref: '#/components/schemas/PeriodType' -+ $ref: "#/components/schemas/PeriodType" - required: false - description: Relative period of the period to fetch data - - in: query - name: group - schema: -- $ref: '#/components/schemas/GroupType' -+ $ref: "#/components/schemas/GroupType" - required: false - description: Field to group the data by - responses: -- '200': -+ "200": - description: Success - content: - application/json: - schema: -- $ref: '#/components/schemas/PullData' -- '404': -+ $ref: "#/components/schemas/PullData" -+ "404": - description: Not found - repo doesn't exist or user does not have permission to access it - /namespaces/{namespace}/pulls/exports/years: - get: -- tags: [namespaces] -+ tags: -+ - namespaces - summary: Get years with data - description: Gets a list of years that have data for the given namespace. - operationId: getNamespaceYears -@@ -317,15 +322,16 @@ - required: true - description: Namespace to fetch data for - responses: -- '200': -+ "200": - description: Success - content: - application/json: - schema: -- $ref: '#/components/schemas/YearData' -+ $ref: "#/components/schemas/YearData" - /namespaces/{namespace}/pulls/exports/years/{year}/{timespantype}: - get: -- tags: [namespaces] -+ tags: -+ - namespaces - summary: Get timespans with data - description: Gets a list of timespans of the given type that have data for the given namespace and year. - operationId: getNamespaceTimespans -@@ -345,19 +351,20 @@ - - in: path - name: timespantype - schema: -- $ref: '#/components/schemas/TimespanType' -+ $ref: "#/components/schemas/TimespanType" - required: true - description: Type of timespan to fetch data for - responses: -- '200': -+ "200": - description: Success - content: - application/json: - schema: -- $ref: '#/components/schemas/TimespanData' -+ $ref: "#/components/schemas/TimespanData" - /namespaces/{namespace}/pulls/exports/years/{year}/{timespantype}/{timespan}: - get: -- tags: [namespaces] -+ tags: -+ - namespaces - summary: Get namespace metadata for timespan - description: Gets info about data for the given namespace and timespan. - operationId: getNamespaceTimespanMetadata -@@ -377,7 +384,7 @@ - - in: path - name: timespantype - schema: -- $ref: '#/components/schemas/TimespanType' -+ $ref: "#/components/schemas/TimespanType" - required: true - description: Type of timespan to fetch data for - - in: path -@@ -387,17 +394,18 @@ - required: true - description: Timespan to fetch data for - responses: -- '200': -+ "200": - description: Success - content: - application/json: - schema: -- $ref: '#/components/schemas/TimespanModel' -- '404': -+ $ref: "#/components/schemas/TimespanModel" -+ "404": - description: Not Found - /namespaces/{namespace}/pulls/exports/years/{year}/{timespantype}/{timespan}/{dataview}: - get: -- tags: [namespaces] -+ tags: -+ - namespaces - summary: Get namespace data for timespan - description: Gets a list of URLs that can be used to download the pull data for the given namespace and timespan. - operationId: getNamespaceDataByTimespan -@@ -417,7 +425,7 @@ - - in: path - name: timespantype - schema: -- $ref: '#/components/schemas/TimespanType' -+ $ref: "#/components/schemas/TimespanType" - required: true - description: Type of timespan to fetch data for - - in: path -@@ -429,19 +437,20 @@ - - in: path - name: dataview - schema: -- $ref: '#/components/schemas/DataviewType' -+ $ref: "#/components/schemas/DataviewType" - required: true - description: Type of data to fetch - responses: -- '200': -+ "200": - description: Success - content: - application/json: - schema: -- $ref: '#/components/schemas/ResponseData' -+ $ref: "#/components/schemas/ResponseData" - /repos/pulls: - get: -- tags: [namespaces] -+ tags: -+ - namespaces - summary: Get pull data for multiple repos - description: Gets pull for the given repos. - operationId: getManyReposPulls -@@ -457,29 +466,28 @@ - - in: query - name: timespan - schema: -- $ref: '#/components/schemas/TimespanType' -+ $ref: "#/components/schemas/TimespanType" - required: false - description: Timespan type for fetching data - - in: query - name: period - schema: -- $ref: '#/components/schemas/PeriodType' -+ $ref: "#/components/schemas/PeriodType" - required: false - description: Relative period of the period to fetch data - - in: query - name: group - schema: -- $ref: '#/components/schemas/GroupType' -+ $ref: "#/components/schemas/GroupType" - required: false - description: Field to group the data by - responses: -- '200': -+ "200": - description: Success - content: - application/json: - schema: -- $ref: '#/components/schemas/ReposPullData' -- -+ $ref: "#/components/schemas/ReposPullData" - components: - schemas: - UsersLoginRequest: -@@ -494,9 +502,7 @@ - type: string - example: myusername - password: -- description: -- The password or personal access token (PAT) of the Docker Hub -- account to authenticate with. -+ description: The password or personal access token (PAT) of the Docker Hub account to authenticate with. - type: string - example: hunter2 - PostUsersLoginSuccessResponse: -@@ -510,7 +516,6 @@ - This token can be used in the HTTP Authorization header as a JWT to authenticate with the Docker Hub APIs. - type: string - example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c -- nullable: false - PostUsersLoginErrorResponse: - description: failed user login response or second factor required - type: object -@@ -521,15 +526,12 @@ - description: Description of the error. - type: string - example: Incorrect authentication credentials -- nullable: false - login_2fa_token: -- description: -- Short-lived token to be used on `/v2/users/2fa-login` to -- complete the authentication. This field is present only if 2FA is -- enabled. -- type: string -+ description: Short-lived token to be used on `/v2/users/2fa-login` to complete the authentication. This field is present only if 2FA is enabled. -+ type: -+ - string -+ - "null" - example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c -- nullable: true - Users2FALoginRequest: - description: Second factor user login details - type: object -@@ -542,9 +544,7 @@ - type: string - example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c - code: -- description: -- The Time-based One-Time Password of the Docker Hub account to -- authenticate with. -+ description: The Time-based One-Time Password of the Docker Hub account to authenticate with. - type: string - example: 123456 - PostUsers2FALoginErrorResponse: -@@ -555,16 +555,14 @@ - description: Description of the error. - type: string - example: Incorrect authentication credentials -- nullable: false -- - ResponseData: - properties: - data: - type: array - description: | - List of urls to download the data. When the data is large, the data will be split into multiple files. -- items: -- $ref: '#/components/schemas/ResponseDataFile' -+ items: -+ $ref: "#/components/schemas/ResponseDataFile" - ResponseDataFile: - properties: - url: -@@ -589,31 +587,31 @@ - datasets: - type: array - items: -- $ref: '#/components/schemas/DatasetModel' -+ $ref: "#/components/schemas/DatasetModel" - DatasetModel: - properties: - name: -- $ref: '#/components/schemas/DatasetType' -+ $ref: "#/components/schemas/DatasetType" - views: - type: array - items: -- $ref: '#/components/schemas/DataviewType' -+ $ref: "#/components/schemas/DataviewType" - timespans: - type: array - items: -- $ref: '#/components/schemas/TimespanType' -+ $ref: "#/components/schemas/TimespanType" - PullData: - properties: - pulls: - type: array - items: -- $ref: '#/components/schemas/PullModel' -+ $ref: "#/components/schemas/PullModel" - ReposPullData: - properties: - repos: - type: object - additionalProperties: -- $ref: '#/components/schemas/PullData' -+ $ref: "#/components/schemas/PullData" - PullModel: - properties: - start: -@@ -630,13 +628,12 @@ - type: integer - country: - type: string -- - YearData: - properties: - years: - type: array - items: -- $ref: '#/components/schemas/YearModel' -+ $ref: "#/components/schemas/YearModel" - YearModel: - properties: - year: -@@ -646,7 +643,7 @@ - months: - type: array - items: -- $ref: '#/components/schemas/MonthModel' -+ $ref: "#/components/schemas/MonthModel" - MonthModel: - properties: - month: -@@ -656,37 +653,50 @@ - weeks: - type: array - items: -- $ref: '#/components/schemas/WeekModel' -+ $ref: "#/components/schemas/WeekModel" - WeekModel: - properties: - week: - type: integer - TimespanType: - type: string -- enum: [months,weeks] -+ enum: -+ - months -+ - weeks - PeriodType: - type: string -- enum: [last-2-months,last-3-months,last-6-months,last-12-months] -+ enum: -+ - last-2-months -+ - last-3-months -+ - last-6-months -+ - last-12-months - DataviewType: - type: string -- enum: [raw,summary,repo-summary,namespace-summary] -+ enum: -+ - raw -+ - summary -+ - repo-summary -+ - namespace-summary - DatasetType: - type: string -- enum: [pulls] -+ enum: -+ - pulls - TimespanModel: - oneOf: -- - $ref: '#/components/schemas/MonthModel' -- - $ref: '#/components/schemas/WeekModel' -+ - $ref: "#/components/schemas/MonthModel" -+ - $ref: "#/components/schemas/WeekModel" - TimespanData: - oneOf: -- - $ref: '#/components/schemas/MonthData' -- - $ref: '#/components/schemas/WeekData' -+ - $ref: "#/components/schemas/MonthData" -+ - $ref: "#/components/schemas/WeekData" - GroupType: - type: string -- enum: [repo,namespace] -+ enum: -+ - repo -+ - namespace - securitySchemes: - HubAuth: -- type: https -+ type: http - scheme: bearer - bearerFormat: JWT - description: | -@@ -694,3 +704,6 @@ - - This authentication documentation is duplicated from the [Hub API Authentication docs](https://docs.docker.com/reference/api/hub/latest/#tag/authentication) - x-displayName: Docker Hub Authentication -+jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base -+x-features-openapi: -+ schemaDefinitionsTagName: Schemas diff --git a/hack/api-docs/adoption/hub.json b/hack/api-docs/adoption/hub.json deleted file mode 100644 index 49a9323bf289..000000000000 --- a/hack/api-docs/adoption/hub.json +++ /dev/null @@ -1,2950 +0,0 @@ -{ - "api": "hub", - "source": { - "id": "hub", - "product": "hub", - "title": "Docker Hub", - "source": "content/reference/api/hub/latest.yaml", - "owner": "docker/docs (product authority to confirm)", - "manual": "/manuals/docker-hub/", - "connection": "hosted", - "auth": "Use the documented Hub token exchange. SCIM operations use a separate provisioning token.", - "guides": [ - "/manuals/security/provisioning/scim/provision-scim.md" - ], - "sha256": "aeefa9b62b10d70f9e28e9508d5a4c1361e0a541e209ff0af9ed2544b0cb415e" - }, - "convertedSha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "profile": "docker-docs-prototype-1", - "changes": [ - { - "pointer": "/jsonSchemaDialect", - "beforePresent": false, - "afterPresent": true, - "after": "https://spec.openapis.org/oas/3.1/dialect/base", - "id": "hub-03ee85af235e", - "stage": "oas32-header", - "classification": "mechanical conversion", - "rationale": "Adopt the common OpenAPI version and its selected schema dialect.", - "evidence": "API-DOCUMENTATION-ARCHITECTURE.md S1", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/jsonSchemaDialect" - }, - { - "pointer": "/openapi", - "beforePresent": true, - "afterPresent": true, - "before": "3.0.3", - "after": "3.2.0", - "id": "hub-71377657b6ae", - "stage": "oas32-header", - "classification": "mechanical conversion", - "rationale": "Adopt the common OpenAPI version and its selected schema dialect.", - "evidence": "API-DOCUMENTATION-ARCHITECTURE.md S1", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/openapi", - "destinationPointer": "/openapi" - }, - { - "pointer": "/components/schemas/PostUsers2FALoginErrorResponse/properties/detail/nullable", - "beforePresent": true, - "afterPresent": false, - "before": false, - "id": "hub-4a84441cce53", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/PostUsers2FALoginErrorResponse/properties/detail/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/PostUsersLoginErrorResponse/properties/detail/nullable", - "beforePresent": true, - "afterPresent": false, - "before": false, - "id": "hub-209f129099a9", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/PostUsersLoginErrorResponse/properties/detail/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-74ca1738d170", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-14920c5fdaca", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/type", - "destinationPointer": "/components/schemas/PostUsersLoginErrorResponse/properties/login_2fa_token/type" - }, - { - "pointer": "/components/schemas/PostUsersLoginSuccessResponse/properties/token/nullable", - "beforePresent": true, - "afterPresent": false, - "before": false, - "id": "hub-f4382a2a3adb", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/PostUsersLoginSuccessResponse/properties/token/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/accessToken/properties/last_used/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-419d1bfbeeec", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/accessToken/properties/last_used/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/accessToken/properties/last_used/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-03403114b7b9", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/accessToken/properties/last_used/type", - "destinationPointer": "/components/schemas/accessToken/properties/last_used/type" - }, - { - "pointer": "/components/schemas/createOrgAccessTokenRequest/properties/expires_at/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-25ea10e8d019", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/createOrgAccessTokenRequest/properties/expires_at/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/createOrgAccessTokenRequest/properties/expires_at/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-4251302b3c95", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/createOrgAccessTokenRequest/properties/expires_at/type", - "destinationPointer": "/components/schemas/createOrgAccessTokenRequest/properties/expires_at/type" - }, - { - "pointer": "/components/schemas/createOrgAccessTokenResponse/allOf", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "a7a5ef25-8889-43a0-8cc7-f2a94268e861" - }, - "label": { - "type": "string", - "example": "My organization token" - }, - "is_active": { - "type": "boolean", - "example": true - }, - "created_at": { - "type": "string", - "format": "date-time", - "example": "2022-05-20T00:54:18Z" - }, - "expires_at": { - "type": "string", - "format": "date-time", - "example": "2023-05-20T00:54:18Z", - "nullable": true - }, - "last_used_at": { - "type": "string", - "format": "date-time", - "example": "2022-06-15T12:30:45Z", - "nullable": true - } - } - }, - { - "type": "object", - "properties": { - "token": { - "type": "string", - "description": "The actual token value that can be used for authentication", - "example": "dckr_oat_7awgM4jG5SQvxcvmNzhKj8PQjxo" - }, - "resources": { - "type": "array", - "items": { - "$ref": "#/components/schemas/orgAccessTokenResource" - } - } - } - } - ], - "after": [ - { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "a7a5ef25-8889-43a0-8cc7-f2a94268e861" - }, - "label": { - "type": "string", - "example": "My organization token" - }, - "is_active": { - "type": "boolean", - "example": true - }, - "created_at": { - "type": "string", - "format": "date-time", - "example": "2022-05-20T00:54:18Z" - }, - "expires_at": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "example": "2023-05-20T00:54:18Z" - }, - "last_used_at": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "example": "2022-06-15T12:30:45Z" - } - } - }, - { - "type": "object", - "properties": { - "token": { - "type": "string", - "description": "The actual token value that can be used for authentication", - "example": "dckr_oat_7awgM4jG5SQvxcvmNzhKj8PQjxo" - }, - "resources": { - "type": "array", - "items": { - "$ref": "#/components/schemas/orgAccessTokenResource" - } - } - } - } - ], - "id": "hub-6c45e809bb08", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/createOrgAccessTokenResponse/allOf", - "destinationPointer": "/components/schemas/createOrgAccessTokenResponse/allOf" - }, - { - "pointer": "/components/schemas/image/properties/digest/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-7b78462e893b", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/image/properties/digest/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/image/properties/digest/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-549328d76dcd", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/image/properties/digest/type", - "destinationPointer": "/components/schemas/image/properties/digest/type" - }, - { - "pointer": "/components/schemas/image/properties/last_pulled/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-5499989516b9", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/image/properties/last_pulled/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/image/properties/last_pulled/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-443454d8717b", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/image/properties/last_pulled/type", - "destinationPointer": "/components/schemas/image/properties/last_pulled/type" - }, - { - "pointer": "/components/schemas/image/properties/last_pushed/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-d2b5e9cbe250", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/image/properties/last_pushed/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/image/properties/last_pushed/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-f68167523b21", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/image/properties/last_pushed/type", - "destinationPointer": "/components/schemas/image/properties/last_pushed/type" - }, - { - "pointer": "/components/schemas/layer/properties/digest/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-983b2bb794e8", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/layer/properties/digest/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/layer/properties/digest/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-3e1807d3a49e", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/layer/properties/digest/type", - "destinationPointer": "/components/schemas/layer/properties/digest/type" - }, - { - "pointer": "/components/schemas/orgAccessToken/properties/expires_at/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-1dd2703f9cc7", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/orgAccessToken/properties/expires_at/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/orgAccessToken/properties/expires_at/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-e97055a90965", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/orgAccessToken/properties/expires_at/type", - "destinationPointer": "/components/schemas/orgAccessToken/properties/expires_at/type" - }, - { - "pointer": "/components/schemas/orgAccessToken/properties/last_used_at/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-4770a0e1fc68", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/orgAccessToken/properties/last_used_at/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/orgAccessToken/properties/last_used_at/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-bcb75b8a4856", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/orgAccessToken/properties/last_used_at/type", - "destinationPointer": "/components/schemas/orgAccessToken/properties/last_used_at/type" - }, - { - "pointer": "/components/schemas/page/properties/next/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-5f51929ee3be", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/page/properties/next/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/page/properties/next/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-1c9303e797fd", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/page/properties/next/type", - "destinationPointer": "/components/schemas/page/properties/next/type" - }, - { - "pointer": "/components/schemas/page/properties/previous/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-f55371c00ee8", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/page/properties/previous/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/page/properties/previous/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-aaf9dcecb4e7", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/page/properties/previous/type", - "destinationPointer": "/components/schemas/page/properties/previous/type" - }, - { - "pointer": "/components/schemas/repository_info/properties/affiliation/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-db0ca8c6118b", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/affiliation/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/repository_info/properties/affiliation/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-53c12223e744", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/affiliation/type", - "destinationPointer": "/components/schemas/repository_info/properties/affiliation/type" - }, - { - "pointer": "/components/schemas/repository_info/properties/full_description/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-693d06466546", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/full_description/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/repository_info/properties/full_description/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-f2a62661a71f", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/full_description/type", - "destinationPointer": "/components/schemas/repository_info/properties/full_description/type" - }, - { - "pointer": "/components/schemas/repository_info/properties/hub_user/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-586430b24161", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/hub_user/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/repository_info/properties/hub_user/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-8b002c0c2379", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/hub_user/type", - "destinationPointer": "/components/schemas/repository_info/properties/hub_user/type" - }, - { - "pointer": "/components/schemas/repository_info/properties/last_modified/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-51ed4d2375e7", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/last_modified/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/repository_info/properties/last_modified/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-e3991fed6abd", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/last_modified/type", - "destinationPointer": "/components/schemas/repository_info/properties/last_modified/type" - }, - { - "pointer": "/components/schemas/repository_info/properties/media_types/items/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-e5cd63f7e46b", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/media_types/items/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/repository_info/properties/media_types/items/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-d4542159a0cb", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/media_types/items/type", - "destinationPointer": "/components/schemas/repository_info/properties/media_types/items/type" - }, - { - "pointer": "/components/schemas/repository_info/properties/repository_type/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-3ed558f36655", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/repository_type/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/repository_info/properties/repository_type/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-572974596a5e", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/repository_type/type", - "destinationPointer": "/components/schemas/repository_info/properties/repository_type/type" - }, - { - "pointer": "/components/schemas/repository_info/properties/source/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-e33e16e370d0", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/source/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/repository_info/properties/source/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-8e2a47ca4188", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/source/type", - "destinationPointer": "/components/schemas/repository_info/properties/source/type" - }, - { - "pointer": "/components/schemas/repository_info/properties/storage_size/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-a9dd6412fb55", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/storage_size/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/repository_info/properties/storage_size/type", - "beforePresent": true, - "afterPresent": true, - "before": "integer", - "after": [ - "integer", - "null" - ], - "id": "hub-3cb15ac31d13", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_info/properties/storage_size/type", - "destinationPointer": "/components/schemas/repository_info/properties/storage_size/type" - }, - { - "pointer": "/components/schemas/repository_list_entry/properties/description/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-3433b42e6550", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_list_entry/properties/description/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/repository_list_entry/properties/description/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-dda7391614bd", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_list_entry/properties/description/type", - "destinationPointer": "/components/schemas/repository_list_entry/properties/description/type" - }, - { - "pointer": "/components/schemas/repository_list_entry/properties/last_modified/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-bb137761a5e2", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_list_entry/properties/last_modified/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/repository_list_entry/properties/last_modified/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-4de50800605e", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_list_entry/properties/last_modified/type", - "destinationPointer": "/components/schemas/repository_list_entry/properties/last_modified/type" - }, - { - "pointer": "/components/schemas/repository_list_entry/properties/last_updated/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-7048a5c0fa51", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_list_entry/properties/last_updated/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/repository_list_entry/properties/last_updated/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-17edbfb92a97", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_list_entry/properties/last_updated/type", - "destinationPointer": "/components/schemas/repository_list_entry/properties/last_updated/type" - }, - { - "pointer": "/components/schemas/repository_list_entry/properties/repository_type/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-d20310dd5ae2", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_list_entry/properties/repository_type/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/repository_list_entry/properties/repository_type/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-f86e7bbc38a4", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/repository_list_entry/properties/repository_type/type", - "destinationPointer": "/components/schemas/repository_list_entry/properties/repository_type/type" - }, - { - "pointer": "/components/schemas/tag/properties/last_updated/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-68b24c8c5109", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/tag/properties/last_updated/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/tag/properties/last_updated/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-a26b67fb6339", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/tag/properties/last_updated/type", - "destinationPointer": "/components/schemas/tag/properties/last_updated/type" - }, - { - "pointer": "/components/schemas/tag/properties/tag_last_pulled/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-cb1f15cd0a83", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/tag/properties/tag_last_pulled/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/tag/properties/tag_last_pulled/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-3709a230a429", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/tag/properties/tag_last_pulled/type", - "destinationPointer": "/components/schemas/tag/properties/tag_last_pulled/type" - }, - { - "pointer": "/components/schemas/tag/properties/tag_last_pushed/nullable", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-689c7a489f31", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/tag/properties/tag_last_pushed/nullable", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/tag/properties/tag_last_pushed/type", - "beforePresent": true, - "afterPresent": true, - "before": "string", - "after": [ - "string", - "null" - ], - "id": "hub-aea53f482c72", - "stage": "oas30-schema-semantics", - "classification": "mechanical conversion", - "rationale": "Translate OpenAPI 3.0 nullable and exclusive bounds into JSON Schema constraints; preserve sibling assertions.", - "evidence": "OpenAPI 3.0 Schema Object and JSON Schema 2020-12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/tag/properties/tag_last_pushed/type", - "destinationPointer": "/components/schemas/tag/properties/tag_last_pushed/type" - }, - { - "pointer": "/paths/~1v2~1access-tokens/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2AccessTokens", - "id": "hub-f8cbd35e78df", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1access-tokens/get/operationId" - }, - { - "pointer": "/paths/~1v2~1access-tokens/post/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "postV2AccessTokens", - "id": "hub-afd4cf26e093", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1access-tokens/post/operationId" - }, - { - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/delete/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "deleteV2AccessTokensByUuid", - "id": "hub-4c342a5a6523", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1access-tokens~1{uuid}/delete/operationId" - }, - { - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2AccessTokensByUuid", - "id": "hub-4fcb33e51e3d", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1access-tokens~1{uuid}/get/operationId" - }, - { - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "patchV2AccessTokensByUuid", - "id": "hub-00969ade81fd", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/operationId" - }, - { - "pointer": "/paths/~1v2~1invites~1bulk/post/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "postV2InvitesBulk", - "id": "hub-d346b6e45684", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1invites~1bulk/post/operationId" - }, - { - "pointer": "/paths/~1v2~1invites~1{id}/delete/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "deleteV2InvitesById", - "id": "hub-c81d9b7f93da", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1invites~1{id}/delete/operationId" - }, - { - "pointer": "/paths/~1v2~1invites~1{id}~1resend/patch/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "patchV2InvitesByIdResend", - "id": "hub-55feefec6ccc", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1invites~1{id}~1resend/patch/operationId" - }, - { - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "headV2NamespacesByNamespaceRepositoriesByRepositoryTags", - "id": "hub-6ec409f24610", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/operationId" - }, - { - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "headV2NamespacesByNamespaceRepositoriesByRepositoryTagsByTag", - "id": "hub-cd3fa54d0bec", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2OrgsByNameAccessTokens", - "id": "hub-86bc936786d2", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "postV2OrgsByNameAccessTokens", - "id": "hub-36afe9a3a367", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2OrgsByNameSettings", - "id": "hub-fd160d644a0d", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{name}~1settings/get/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "putV2OrgsByNameSettings", - "id": "hub-30c79dee6ea5", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{name}~1settings/put/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "deleteV2OrgsByOrgNameAccessTokensByAccessTokenId", - "id": "hub-28cba8092f0d", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2OrgsByOrgNameAccessTokensByAccessTokenId", - "id": "hub-ac00804f74e2", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "patchV2OrgsByOrgNameAccessTokensByAccessTokenId", - "id": "hub-0143389a74a8", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2OrgsByOrgNameGroups", - "id": "hub-7aede6605aad", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "postV2OrgsByOrgNameGroups", - "id": "hub-2c5c68daf41b", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "deleteV2OrgsByOrgNameGroupsByGroupName", - "id": "hub-421de8c8e3f8", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2OrgsByOrgNameGroupsByGroupName", - "id": "hub-9d2c9cff8fea", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "patchV2OrgsByOrgNameGroupsByGroupName", - "id": "hub-1a150e13f5c0", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "putV2OrgsByOrgNameGroupsByGroupName", - "id": "hub-b88a4cb28cdf", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2OrgsByOrgNameGroupsByGroupNameMembers", - "id": "hub-e630bef3c6ed", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "postV2OrgsByOrgNameGroupsByGroupNameMembers", - "id": "hub-f6571b90ccc1", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "deleteV2OrgsByOrgNameGroupsByGroupNameMembersByUsername", - "id": "hub-751cc2434894", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2OrgsByOrgNameInvites", - "id": "hub-39565bc4387b", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2OrgsByOrgNameMembers", - "id": "hub-7a816176b210", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2OrgsByOrgNameMembersExport", - "id": "hub-53f01d4baf21", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "deleteV2OrgsByOrgNameMembersByUsername", - "id": "hub-4fe305418a38", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/operationId" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "putV2OrgsByOrgNameMembersByUsername", - "id": "hub-a33b621b26f7", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/operationId" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2Scim20ResourceTypes", - "id": "hub-f6e536e43752", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/operationId" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2Scim20ResourceTypesByName", - "id": "hub-5e3a1826a68f", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/operationId" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1Schemas/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2Scim20Schemas", - "id": "hub-78d7c72f266f", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1scim~12.0~1Schemas/get/operationId" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2Scim20SchemasById", - "id": "hub-98da271d89fe", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/operationId" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2Scim20ServiceProviderConfig", - "id": "hub-ad9109142d86", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/operationId" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1Users/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2Scim20Users", - "id": "hub-1de3a58d007a", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1scim~12.0~1Users/get/operationId" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1Users/post/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "postV2Scim20Users", - "id": "hub-5899924999f5", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1scim~12.0~1Users/post/operationId" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "getV2Scim20UsersById", - "id": "hub-b9e1e6211828", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/operationId" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/operationId", - "beforePresent": false, - "afterPresent": true, - "after": "putV2Scim20UsersById", - "id": "hub-f4368513b4a2", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/operationId" - }, - { - "pointer": "/tags", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "name": "changelog", - "x-displayName": "Changelog", - "description": "See the [Changelog](/reference/api/hub/changelog) for a summary of changes across Docker Hub API versions.\n" - }, - { - "name": "resources", - "x-displayName": "Resources", - "description": "The following resources are available to interact with the documented API:\n- [Docker Hub CLI tool](https://github.com/docker/hub-tool#readme) (currently experimental)\n" - }, - { - "name": "rate-limiting", - "x-displayName": "Rate Limiting", - "description": "The Docker Hub API is limited on the amount of requests you can perform per minute against it.\n\nIf you haven't hit the limit, each request to the API will return the following headers in the response.\n\n- `X-RateLimit-Limit` - The limit of requests per minute.\n- `X-RateLimit-Remaining` - The remaining amount of calls within the limit period.\n- `X-RateLimit-Reset` - The unix timestamp of when the remaining resets.\n\nIf you have hit the limit, you will receive a response status of `429` and the `Retry-After` header in the response.\n\nThe [`Retry-After` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After) specifies the number of seconds to wait until you can call the API again.\n\n**Note**: These rate limits are separate from anti-abuse and Docker Hub download, or pull rate limiting.\nTo learn more about Docker Hub pull rate limiting, see [Usage and limits](https://docs.docker.com/docker-hub/usage/).\n" - }, - { - "name": "authentication", - "x-displayName": "Authentication", - "description": "Most Docker Hub API endpoints require you to authenticate using your Docker credentials before using them.\n\nAdditionally, similar to the Docker Hub UI features, API endpoint responses may vary depending on your subscription (Personal, Pro, or Team) and your account's permissions.\n\nTo learn more about the features available in each subscription and to upgrade your existing subscription, see [Docker Pricing](https://www.docker.com/pricing?ref=Docs&refAction=DocsApiHub).\n\n# Types\n\nThe Docker Hub API supports the following authentication types.\n\nYou must use each authentication type with the [Create access token](#tag/authentication-api/operation/AuthCreateAccessToken) route to obtain a bearer token.\n\n## Password\nUsing a username and password is the most powerful, yet least secure way \nto authenticate with Docker as a user. It allows access to resources \nfor the user without scopes. \n\n_In general, it is recommended to use a personal access token (PAT) instead._\n\n_**The password authentication type is not available if your organization has SSO enforced.**_\n\n## Personal Access Token (PAT)\nUsing a username and PAT is the most secure way to authenticate with \nDocker as a user. PATs are scoped to specific resources and scopes.\n\nCurrently, a PAT is a more secure password due to limited functionality. \nIn the future, we may add fine-grained access like organization \naccess tokens for enhanced usage and security.\n\n## Organization Access Token (OAT)\nOrganization access tokens are scoped to specific resources and scopes \nin an organization. They are managed by organization owners. \n\nThese tokens are meant for automation and are not meant to be used by \nusers.\n\n# Labels\n\nThese labels will show up on routes in this reference that allow for use of bearer \ntokens issued from them.\n\n\n\n" - }, - { - "name": "authentication-api", - "x-displayName": "Authentication", - "description": "The authentication endpoints allow you to authenticate with Docker Hub APIs.\n\nFor more information, see [Authentication](#tag/authentication).\n" - }, - { - "name": "access-tokens", - "x-displayName": "Personal Access Tokens", - "description": "The Personal Access Token endpoints lets you manage personal access tokens. For more information, see [Access Tokens](https://docs.docker.com/security/access-tokens/personal-access-tokens/).\n\nYou can use a personal access token instead of a password in the [Docker CLI](https://docs.docker.com/engine/reference/commandline/cli/) or in the [Create an authentication token](#operation/PostUsersLogin) route to obtain a bearer token.\n\n### Scopes\n\nFor each scope grouping (in this case \"repo\"), you only need to define 1 scope as any lower scopes are assumed.\nFor example: If you define `repo:write`, the API assumes the scope of both `repo:read` *and* `repo:public_read` as well.\nIf you were to define both `repo:write` *and* `repo:read`, then `repo:read` is assumed by `repo:write` and ignored.\n\n***Treat your personal access token like your password and keep it secret. You cannot retrieve your token after it is generated.***\n" - }, - { - "name": "audit-logs", - "x-displayName": "Audit Logs", - "description": "The Audit Logs API endpoints allow you to query audit log events across a namespace.\n\nFor more information, see [Audit Logs](https://docs.docker.com/admin/activity-logs/).\n" - }, - { - "name": "org-settings", - "x-displayName": "Org Settings", - "description": "The Org Settings API endpoints allow you to manage your organization's settings.\n" - }, - { - "name": "repositories", - "x-displayName": "Repositories", - "description": "The repository endpoints allow you to access your repository's tags.\n" - }, - { - "name": "orgs", - "x-displayName": "Organizations", - "x-audience": "public", - "description": "The organization endpoints allow you to interact with and manage your organizations.\n\nFor more information, see [Organization administration overview](https://docs.docker.com/admin/organization/).\n" - }, - { - "name": "groups", - "x-displayName": "Groups (Teams)", - "x-audience": "public", - "description": "The groups endpoints allow you to manage your organization's teams and their members.\n\nFor more information, see [Create and manage a team](https://docs.docker.com/admin/organization/manage/manage-a-team/).\n" - }, - { - "name": "invites", - "x-displayName": "Invites", - "x-audience": "public", - "description": "The invites endpoints allow you to manage invites for users to join your Docker organization.\n\nFor more information, see [Invite members](https://docs.docker.com/admin/organization/manage/members/#invite-members).\n" - }, - { - "name": "scim", - "x-displayName": "SCIM", - "x-audience": "public", - "description": "SCIM is a provisioning system that lets you manage users within your identity provider (IdP).\n\nFor more information, see [System for Cross-domain Identity management](https://docs.docker.com/security/for-admins/provisioning/scim/).\n" - }, - { - "name": "org-access-tokens", - "x-displayName": "Organization Access Tokens", - "x-audience": "public", - "description": "The organization access token endpoints allow you to manage organization access tokens (OATs). See [Organization access tokens](https://docs.docker.com/security/for-admins/access-tokens/) for more information.\n\nOATs only authenticate requests to the modern namespace-scoped routes under `/v2/namespaces/{namespace}/repositories/`. Legacy repository paths are OAT unsupported, regardless of the token's scopes, and reject every OAT with `403 token issued from organization access token is not allowed`:\n\n- `GET /v2/repositories/{namespace}/{repository}` — use [Get repository](#tag/repositories/operation/GetRepository) instead.\n- `GET /v2/repositories/{namespace}` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n- `GET /v2/users/{username}/repositories` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n" - } - ], - "after": [ - { - "name": "changelog", - "description": "See the [Changelog](/reference/api/hub/changelog) for a summary of changes across Docker Hub API versions.\n", - "summary": "Changelog", - "kind": "info" - }, - { - "name": "resources", - "description": "The following resources are available to interact with the documented API:\n- [Docker Hub CLI tool](https://github.com/docker/hub-tool#readme) (currently experimental)\n", - "summary": "Resources", - "kind": "info" - }, - { - "name": "rate-limiting", - "description": "The Docker Hub API is limited on the amount of requests you can perform per minute against it.\n\nIf you haven't hit the limit, each request to the API will return the following headers in the response.\n\n- `X-RateLimit-Limit` - The limit of requests per minute.\n- `X-RateLimit-Remaining` - The remaining amount of calls within the limit period.\n- `X-RateLimit-Reset` - The unix timestamp of when the remaining resets.\n\nIf you have hit the limit, you will receive a response status of `429` and the `Retry-After` header in the response.\n\nThe [`Retry-After` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After) specifies the number of seconds to wait until you can call the API again.\n\n**Note**: These rate limits are separate from anti-abuse and Docker Hub download, or pull rate limiting.\nTo learn more about Docker Hub pull rate limiting, see [Usage and limits](https://docs.docker.com/docker-hub/usage/).\n", - "summary": "Rate Limiting", - "kind": "info" - }, - { - "name": "authentication", - "description": "Most Docker Hub API endpoints require you to authenticate using your Docker credentials before using them.\n\nAdditionally, similar to the Docker Hub UI features, API endpoint responses may vary depending on your subscription (Personal, Pro, or Team) and your account's permissions.\n\nTo learn more about the features available in each subscription and to upgrade your existing subscription, see [Docker Pricing](https://www.docker.com/pricing?ref=Docs&refAction=DocsApiHub).\n\n# Types\n\nThe Docker Hub API supports the following authentication types.\n\nYou must use each authentication type with the [Create access token](#tag/authentication-api/operation/AuthCreateAccessToken) route to obtain a bearer token.\n\n## Password\nUsing a username and password is the most powerful, yet least secure way \nto authenticate with Docker as a user. It allows access to resources \nfor the user without scopes. \n\n_In general, it is recommended to use a personal access token (PAT) instead._\n\n_**The password authentication type is not available if your organization has SSO enforced.**_\n\n## Personal Access Token (PAT)\nUsing a username and PAT is the most secure way to authenticate with \nDocker as a user. PATs are scoped to specific resources and scopes.\n\nCurrently, a PAT is a more secure password due to limited functionality. \nIn the future, we may add fine-grained access like organization \naccess tokens for enhanced usage and security.\n\n## Organization Access Token (OAT)\nOrganization access tokens are scoped to specific resources and scopes \nin an organization. They are managed by organization owners. \n\nThese tokens are meant for automation and are not meant to be used by \nusers.\n\n# Labels\n\nThese labels will show up on routes in this reference that allow for use of bearer \ntokens issued from them.\n\n\n\n", - "summary": "Authentication", - "kind": "info" - }, - { - "name": "authentication-api", - "description": "The authentication endpoints allow you to authenticate with Docker Hub APIs.\n\nFor more information, see [Authentication](#tag/authentication).\n", - "summary": "Authentication", - "kind": "nav" - }, - { - "name": "access-tokens", - "description": "The Personal Access Token endpoints lets you manage personal access tokens. For more information, see [Access Tokens](https://docs.docker.com/security/access-tokens/personal-access-tokens/).\n\nYou can use a personal access token instead of a password in the [Docker CLI](https://docs.docker.com/engine/reference/commandline/cli/) or in the [Create an authentication token](#operation/PostUsersLogin) route to obtain a bearer token.\n\n### Scopes\n\nFor each scope grouping (in this case \"repo\"), you only need to define 1 scope as any lower scopes are assumed.\nFor example: If you define `repo:write`, the API assumes the scope of both `repo:read` *and* `repo:public_read` as well.\nIf you were to define both `repo:write` *and* `repo:read`, then `repo:read` is assumed by `repo:write` and ignored.\n\n***Treat your personal access token like your password and keep it secret. You cannot retrieve your token after it is generated.***\n", - "summary": "Personal Access Tokens", - "kind": "nav" - }, - { - "name": "audit-logs", - "description": "The Audit Logs API endpoints allow you to query audit log events across a namespace.\n\nFor more information, see [Audit Logs](https://docs.docker.com/admin/activity-logs/).\n", - "summary": "Audit Logs", - "kind": "nav" - }, - { - "name": "org-settings", - "description": "The Org Settings API endpoints allow you to manage your organization's settings.\n", - "summary": "Org Settings", - "kind": "nav" - }, - { - "name": "repositories", - "description": "The repository endpoints allow you to access your repository's tags.\n", - "summary": "Repositories", - "kind": "nav" - }, - { - "name": "orgs", - "x-audience": "public", - "description": "The organization endpoints allow you to interact with and manage your organizations.\n\nFor more information, see [Organization administration overview](https://docs.docker.com/admin/organization/).\n", - "summary": "Organizations", - "kind": "nav" - }, - { - "name": "groups", - "x-audience": "public", - "description": "The groups endpoints allow you to manage your organization's teams and their members.\n\nFor more information, see [Create and manage a team](https://docs.docker.com/admin/organization/manage/manage-a-team/).\n", - "summary": "Groups (Teams)", - "kind": "nav" - }, - { - "name": "invites", - "x-audience": "public", - "description": "The invites endpoints allow you to manage invites for users to join your Docker organization.\n\nFor more information, see [Invite members](https://docs.docker.com/admin/organization/manage/members/#invite-members).\n", - "summary": "Invites", - "kind": "nav" - }, - { - "name": "scim", - "x-audience": "public", - "description": "SCIM is a provisioning system that lets you manage users within your identity provider (IdP).\n\nFor more information, see [System for Cross-domain Identity management](https://docs.docker.com/security/for-admins/provisioning/scim/).\n", - "summary": "SCIM", - "kind": "nav" - }, - { - "name": "org-access-tokens", - "x-audience": "public", - "description": "The organization access token endpoints allow you to manage organization access tokens (OATs). See [Organization access tokens](https://docs.docker.com/security/for-admins/access-tokens/) for more information.\n\nOATs only authenticate requests to the modern namespace-scoped routes under `/v2/namespaces/{namespace}/repositories/`. Legacy repository paths are OAT unsupported, regardless of the token's scopes, and reject every OAT with `403 token issued from organization access token is not allowed`:\n\n- `GET /v2/repositories/{namespace}/{repository}` — use [Get repository](#tag/repositories/operation/GetRepository) instead.\n- `GET /v2/repositories/{namespace}` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n- `GET /v2/users/{username}/repositories` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n", - "summary": "Organization Access Tokens", - "kind": "nav" - } - ], - "id": "hub-8d93cf25f3e7", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/tags", - "destinationPointer": "/tags" - }, - { - "pointer": "/components/schemas/createOrgAccessTokenRequest/properties/label/required", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-56f5267c831d", - "stage": "property-required-correction", - "classification": "evidence-backed correction", - "rationale": "Move misplaced boolean property required flags to the parent required array; preserve the declared requiredness.", - "evidence": "Original property-level required: true declarations", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/createOrgAccessTokenRequest/properties/label/required", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/createOrgAccessTokenRequest/required", - "beforePresent": false, - "afterPresent": true, - "after": [ - "label" - ], - "id": "hub-8f8f2dc78a3c", - "stage": "property-required-correction", - "classification": "evidence-backed correction", - "rationale": "Move misplaced boolean property required flags to the parent required array; preserve the declared requiredness.", - "evidence": "Original property-level required: true declarations", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/components/schemas/createOrgAccessTokenRequest/required" - }, - { - "pointer": "/components/schemas/orgAccessTokenResource/properties/path/required", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-ef566a3ef04a", - "stage": "property-required-correction", - "classification": "evidence-backed correction", - "rationale": "Move misplaced boolean property required flags to the parent required array; preserve the declared requiredness.", - "evidence": "Original property-level required: true declarations", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/orgAccessTokenResource/properties/path/required", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/orgAccessTokenResource/properties/scopes/required", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-bc0d5d30d7e9", - "stage": "property-required-correction", - "classification": "evidence-backed correction", - "rationale": "Move misplaced boolean property required flags to the parent required array; preserve the declared requiredness.", - "evidence": "Original property-level required: true declarations", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/orgAccessTokenResource/properties/scopes/required", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/orgAccessTokenResource/properties/type/required", - "beforePresent": true, - "afterPresent": false, - "before": true, - "id": "hub-ea46f67c99f8", - "stage": "property-required-correction", - "classification": "evidence-backed correction", - "rationale": "Move misplaced boolean property required flags to the parent required array; preserve the declared requiredness.", - "evidence": "Original property-level required: true declarations", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/orgAccessTokenResource/properties/type/required", - "destinationPointer": null - }, - { - "pointer": "/components/schemas/orgAccessTokenResource/required", - "beforePresent": false, - "afterPresent": true, - "after": [ - "type", - "path", - "scopes" - ], - "id": "hub-60b71cffddb5", - "stage": "property-required-correction", - "classification": "evidence-backed correction", - "rationale": "Move misplaced boolean property required flags to the parent required array; preserve the declared requiredness.", - "evidence": "Original property-level required: true declarations", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/components/schemas/orgAccessTokenResource/required" - }, - { - "pointer": "/paths/~1v2~1auditlogs~1{account}/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "List audit log events for a given namespace.\n\n\n", - "after": "List audit log events for a given namespace.\n\n\n", - "id": "hub-cf10c2a6bb54", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1auditlogs~1{account}/get/description", - "destinationPointer": "/paths/~1v2~1auditlogs~1{account}/get/description" - }, - { - "pointer": "/paths/~1v2~1auditlogs~1{account}~1actions/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "List audit log actions for a namespace to be used as a filter for querying audit log events.\n\n\n", - "after": "List audit log actions for a namespace to be used as a filter for querying audit log events.\n\n\n", - "id": "hub-37ef6ed3805f", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1auditlogs~1{account}~1actions/get/description", - "destinationPointer": "/paths/~1v2~1auditlogs~1{account}~1actions/get/description" - }, - { - "pointer": "/paths/~1v2~1invites~1bulk/post/description", - "beforePresent": true, - "afterPresent": true, - "before": "Create multiple invites by emails or DockerIDs. Only a team owner can create invites.\n\n\n", - "after": "Create multiple invites by emails or DockerIDs. Only a team owner can create invites.\n\n\n", - "id": "hub-71965f574da9", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1invites~1bulk/post/description", - "destinationPointer": "/paths/~1v2~1invites~1bulk/post/description" - }, - { - "pointer": "/paths/~1v2~1invites~1{id}/delete/description", - "beforePresent": true, - "afterPresent": true, - "before": "Mark the invite as cancelled so it doesn't show up on the list of pending invites\n\n\n", - "after": "Mark the invite as cancelled so it doesn't show up on the list of pending invites\n\n\n", - "id": "hub-711cffa504e9", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1invites~1{id}/delete/description", - "destinationPointer": "/paths/~1v2~1invites~1{id}/delete/description" - }, - { - "pointer": "/paths/~1v2~1invites~1{id}~1resend/patch/description", - "beforePresent": true, - "afterPresent": true, - "before": "Resend a pending invite to the user, any org owner can resend an invite\n\n\n", - "after": "Resend a pending invite to the user, any org owner can resend an invite\n\n\n", - "id": "hub-d7aacf942e38", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1invites~1{id}~1resend/patch/description", - "destinationPointer": "/paths/~1v2~1invites~1{id}~1resend/patch/description" - }, - { - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "Returns a list of repositories within the specified namespace (organization or user).\n\nPublic repositories are accessible to everyone, while private repositories require appropriate authentication and permissions.\n\n\n\n**OAT listing behavior**: an OAT with the `scope-repository-list` scope sees all repositories including private ones. An OAT without that scope only sees public repositories. This filtering is silent: the response is a normal `200` with no indication that private repositories were withheld.\n", - "after": "Returns a list of repositories within the specified namespace (organization or user).\n\nPublic repositories are accessible to everyone, while private repositories require appropriate authentication and permissions.\n\n\n\n**OAT listing behavior**: an OAT with the `scope-repository-list` scope sees all repositories including private ones. An OAT without that scope only sees public repositories. This filtering is silent: the response is a normal `200` with no indication that private repositories were withheld.\n", - "id": "hub-8bce03fbb9e7", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/description", - "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/description" - }, - { - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/description", - "beforePresent": true, - "afterPresent": true, - "before": "Creates a new repository within the specified namespace. The repository will be created\nwith the provided metadata including name, description, and privacy settings.\n\n\n", - "after": "Creates a new repository within the specified namespace. The repository will be created\nwith the provided metadata including name, description, and privacy settings.\n\n\n", - "id": "hub-df5fa500573c", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/description", - "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/description" - }, - { - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "Returns a repository within the specified namespace (organization or user).\n\nPublic repositories are accessible to everyone, while private repositories require appropriate authentication and permissions.\n\n\n", - "after": "Returns a repository within the specified namespace (organization or user).\n\nPublic repositories are accessible to everyone, while private repositories require appropriate authentication and permissions.\n\n\n", - "id": "hub-c814561d26d7", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/description", - "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/description" - }, - { - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/description", - "beforePresent": true, - "afterPresent": true, - "before": "Check a repository within the specified namespace (organization or user).\n\nPublic repositories are accessible to everyone, while private repositories require appropriate authentication and permissions.\n\n\n", - "after": "Check a repository within the specified namespace (organization or user).\n\nPublic repositories are accessible to everyone, while private repositories require appropriate authentication and permissions.\n\n\n", - "id": "hub-758e684d0c26", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/description", - "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/description" - }, - { - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/description", - "beforePresent": true, - "afterPresent": true, - "before": "Updates the immutable tags configuration for this repository.\n\n**Only users with administrative privileges for the repository can modify these settings.**\n\n\n", - "after": "Updates the immutable tags configuration for this repository.\n\n**Only users with administrative privileges for the repository can modify these settings.**\n\n\n", - "id": "hub-4b6236e32079", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/description", - "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/description" - }, - { - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/description", - "beforePresent": true, - "afterPresent": true, - "before": "Validates the immutable tags regex passed in the request body and returns a list of tags matching it in this repository.\n\n**Only users with administrative privileges for the repository can call this endpoint.**\n\n\n", - "after": "Validates the immutable tags regex passed in the request body and returns a list of tags matching it in this repository.\n\n**Only users with administrative privileges for the repository can call this endpoint.**\n\n\n", - "id": "hub-cddc6551a6fe", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/description", - "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/description" - }, - { - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "Returns the list of tags for the specified repository.\n\n\n", - "after": "Returns the list of tags for the specified repository.\n\n\n", - "id": "hub-7c829bae5c5b", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/description", - "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/description" - }, - { - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/description", - "beforePresent": true, - "afterPresent": true, - "before": "Checks whether the repository has any tags.\n\n\n", - "after": "Checks whether the repository has any tags.\n\n\n", - "id": "hub-ae31a1fd6c15", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/description", - "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/description" - }, - { - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "Returns details for a specific tag in the specified repository.\n\n\n", - "after": "Returns details for a specific tag in the specified repository.\n\n\n", - "id": "hub-1711bdf8c01b", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/description", - "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/description" - }, - { - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/description", - "beforePresent": true, - "afterPresent": true, - "before": "Checks whether the specified tag exists in the repository.\n\n\n", - "after": "Checks whether the specified tag exists in the repository.\n\n\n", - "id": "hub-ca9f4292d078", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/description", - "destinationPointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "\n", - "id": "hub-19258b60eb71", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/description", - "beforePresent": true, - "afterPresent": true, - "before": "Create a new group within an organization.\n\n\n", - "after": "Create a new group within an organization.\n\n\n", - "id": "hub-491d43e3b974", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "\n", - "id": "hub-483cbb8b69e9", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "\n", - "id": "hub-9f8a2c14c2e4", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "\n", - "id": "hub-5d12989466a8", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "\n", - "id": "hub-88797cb50eee", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "List the members (users) that are in a group.\nIf user is owner of the org or has otherwise elevated permissions, they can search by email and the result will also contain emails.\n\n\n", - "after": "List the members (users) that are in a group.\nIf user is owner of the org or has otherwise elevated permissions, they can search by email and the result will also contain emails.\n\n\n", - "id": "hub-a969dea6c391", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "\n", - "id": "hub-2392b3255468", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "\n", - "id": "hub-fb34d26a19a7", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "Return all pending invites for a given org, only team owners can call this endpoint\n\n\n", - "after": "Return all pending invites for a given org, only team owners can call this endpoint\n\n\n", - "id": "hub-9e69ed836422", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "Returns a list of members for an organization.\n\n_The following fields are only visible to orgs with insights enabled._\n\n- `last_logged_in_at`\n- `last_seen_at`\n- `last_desktop_version`\n\nTo make visible, please see [View Insights for organization users](https://docs.docker.com/admin/insights/#view-insights-for-organization-users).\n\n\n", - "after": "Returns a list of members for an organization.\n\n_The following fields are only visible to orgs with insights enabled._\n\n- `last_logged_in_at`\n- `last_seen_at`\n- `last_desktop_version`\n\nTo make visible, please see [View Insights for organization users](https://docs.docker.com/admin/insights/#view-insights-for-organization-users).\n\n\n", - "id": "hub-a8f046f807cc", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "Export members of an organization as a CSV\n\n\n", - "after": "Export members of an organization as a CSV\n\n\n", - "id": "hub-ef7a52226e0d", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/description", - "beforePresent": true, - "afterPresent": true, - "before": "Removes the member from the org, ie. all groups in the org, unless they're the last owner\n\n\n", - "after": "Removes the member from the org, ie. all groups in the org, unless they're the last owner\n\n\n", - "id": "hub-a63ee0d1e822", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/description", - "beforePresent": true, - "afterPresent": true, - "before": "Updates the role of a member in the organization.\n***Only users in the \"owners\" group of the organization can use this endpoint.***\n\n\n", - "after": "Updates the role of a member in the organization.\n***Only users in the \"owners\" group of the organization can use this endpoint.***\n\n\n", - "id": "hub-08bc49612a6e", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/description" - }, - { - "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/description", - "beforePresent": true, - "afterPresent": true, - "before": "Assigns an organization group (team) to a repository with a specified permission level.\n\n\n", - "after": "Assigns an organization group (team) to a repository with a specified permission level.\n\n\n", - "id": "hub-078a1d5f4794", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/description", - "destinationPointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/description" - }, - { - "pointer": "/paths/~1v2~1users~1login/post/description", - "beforePresent": true, - "afterPresent": true, - "before": "Creates and returns a bearer token in JWT format that you can use to authenticate with Docker Hub APIs.\n\nThe returned token is used in the HTTP Authorization header like `Authorization: Bearer {TOKEN}`.\n\n_**As of September 16, 2024, this route requires a personal access token (PAT) instead of a password if your organization has SSO enforced.**_\n\n
\n Deprecated: Use [Create access token] instead.\n
\n", - "after": "Creates and returns a bearer token in JWT format that you can use to authenticate with Docker Hub APIs.\n\nThe returned token is used in the HTTP Authorization header like `Authorization: Bearer {TOKEN}`.\n\n_**As of September 16, 2024, this route requires a personal access token (PAT) instead of a password if your organization has SSO enforced.**_\n\n\n Deprecated: Use [Create access token](#tag/authentication-api/operation/AuthCreateAccessToken) instead.\n\n", - "id": "hub-d071d281f6bc", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1users~1login/post/description", - "destinationPointer": "/paths/~1v2~1users~1login/post/description" - }, - { - "pointer": "/tags", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "name": "changelog", - "description": "See the [Changelog](/reference/api/hub/changelog) for a summary of changes across Docker Hub API versions.\n", - "summary": "Changelog", - "kind": "info" - }, - { - "name": "resources", - "description": "The following resources are available to interact with the documented API:\n- [Docker Hub CLI tool](https://github.com/docker/hub-tool#readme) (currently experimental)\n", - "summary": "Resources", - "kind": "info" - }, - { - "name": "rate-limiting", - "description": "The Docker Hub API is limited on the amount of requests you can perform per minute against it.\n\nIf you haven't hit the limit, each request to the API will return the following headers in the response.\n\n- `X-RateLimit-Limit` - The limit of requests per minute.\n- `X-RateLimit-Remaining` - The remaining amount of calls within the limit period.\n- `X-RateLimit-Reset` - The unix timestamp of when the remaining resets.\n\nIf you have hit the limit, you will receive a response status of `429` and the `Retry-After` header in the response.\n\nThe [`Retry-After` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After) specifies the number of seconds to wait until you can call the API again.\n\n**Note**: These rate limits are separate from anti-abuse and Docker Hub download, or pull rate limiting.\nTo learn more about Docker Hub pull rate limiting, see [Usage and limits](https://docs.docker.com/docker-hub/usage/).\n", - "summary": "Rate Limiting", - "kind": "info" - }, - { - "name": "authentication", - "description": "Most Docker Hub API endpoints require you to authenticate using your Docker credentials before using them.\n\nAdditionally, similar to the Docker Hub UI features, API endpoint responses may vary depending on your subscription (Personal, Pro, or Team) and your account's permissions.\n\nTo learn more about the features available in each subscription and to upgrade your existing subscription, see [Docker Pricing](https://www.docker.com/pricing?ref=Docs&refAction=DocsApiHub).\n\n# Types\n\nThe Docker Hub API supports the following authentication types.\n\nYou must use each authentication type with the [Create access token](#tag/authentication-api/operation/AuthCreateAccessToken) route to obtain a bearer token.\n\n## Password\nUsing a username and password is the most powerful, yet least secure way \nto authenticate with Docker as a user. It allows access to resources \nfor the user without scopes. \n\n_In general, it is recommended to use a personal access token (PAT) instead._\n\n_**The password authentication type is not available if your organization has SSO enforced.**_\n\n## Personal Access Token (PAT)\nUsing a username and PAT is the most secure way to authenticate with \nDocker as a user. PATs are scoped to specific resources and scopes.\n\nCurrently, a PAT is a more secure password due to limited functionality. \nIn the future, we may add fine-grained access like organization \naccess tokens for enhanced usage and security.\n\n## Organization Access Token (OAT)\nOrganization access tokens are scoped to specific resources and scopes \nin an organization. They are managed by organization owners. \n\nThese tokens are meant for automation and are not meant to be used by \nusers.\n\n# Labels\n\nThese labels will show up on routes in this reference that allow for use of bearer \ntokens issued from them.\n\n\n\n", - "summary": "Authentication", - "kind": "info" - }, - { - "name": "authentication-api", - "description": "The authentication endpoints allow you to authenticate with Docker Hub APIs.\n\nFor more information, see [Authentication](#tag/authentication).\n", - "summary": "Authentication", - "kind": "nav" - }, - { - "name": "access-tokens", - "description": "The Personal Access Token endpoints lets you manage personal access tokens. For more information, see [Access Tokens](https://docs.docker.com/security/access-tokens/personal-access-tokens/).\n\nYou can use a personal access token instead of a password in the [Docker CLI](https://docs.docker.com/engine/reference/commandline/cli/) or in the [Create an authentication token](#operation/PostUsersLogin) route to obtain a bearer token.\n\n### Scopes\n\nFor each scope grouping (in this case \"repo\"), you only need to define 1 scope as any lower scopes are assumed.\nFor example: If you define `repo:write`, the API assumes the scope of both `repo:read` *and* `repo:public_read` as well.\nIf you were to define both `repo:write` *and* `repo:read`, then `repo:read` is assumed by `repo:write` and ignored.\n\n***Treat your personal access token like your password and keep it secret. You cannot retrieve your token after it is generated.***\n", - "summary": "Personal Access Tokens", - "kind": "nav" - }, - { - "name": "audit-logs", - "description": "The Audit Logs API endpoints allow you to query audit log events across a namespace.\n\nFor more information, see [Audit Logs](https://docs.docker.com/admin/activity-logs/).\n", - "summary": "Audit Logs", - "kind": "nav" - }, - { - "name": "org-settings", - "description": "The Org Settings API endpoints allow you to manage your organization's settings.\n", - "summary": "Org Settings", - "kind": "nav" - }, - { - "name": "repositories", - "description": "The repository endpoints allow you to access your repository's tags.\n", - "summary": "Repositories", - "kind": "nav" - }, - { - "name": "orgs", - "x-audience": "public", - "description": "The organization endpoints allow you to interact with and manage your organizations.\n\nFor more information, see [Organization administration overview](https://docs.docker.com/admin/organization/).\n", - "summary": "Organizations", - "kind": "nav" - }, - { - "name": "groups", - "x-audience": "public", - "description": "The groups endpoints allow you to manage your organization's teams and their members.\n\nFor more information, see [Create and manage a team](https://docs.docker.com/admin/organization/manage/manage-a-team/).\n", - "summary": "Groups (Teams)", - "kind": "nav" - }, - { - "name": "invites", - "x-audience": "public", - "description": "The invites endpoints allow you to manage invites for users to join your Docker organization.\n\nFor more information, see [Invite members](https://docs.docker.com/admin/organization/manage/members/#invite-members).\n", - "summary": "Invites", - "kind": "nav" - }, - { - "name": "scim", - "x-audience": "public", - "description": "SCIM is a provisioning system that lets you manage users within your identity provider (IdP).\n\nFor more information, see [System for Cross-domain Identity management](https://docs.docker.com/security/for-admins/provisioning/scim/).\n", - "summary": "SCIM", - "kind": "nav" - }, - { - "name": "org-access-tokens", - "x-audience": "public", - "description": "The organization access token endpoints allow you to manage organization access tokens (OATs). See [Organization access tokens](https://docs.docker.com/security/for-admins/access-tokens/) for more information.\n\nOATs only authenticate requests to the modern namespace-scoped routes under `/v2/namespaces/{namespace}/repositories/`. Legacy repository paths are OAT unsupported, regardless of the token's scopes, and reject every OAT with `403 token issued from organization access token is not allowed`:\n\n- `GET /v2/repositories/{namespace}/{repository}` — use [Get repository](#tag/repositories/operation/GetRepository) instead.\n- `GET /v2/repositories/{namespace}` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n- `GET /v2/users/{username}/repositories` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n", - "summary": "Organization Access Tokens", - "kind": "nav" - } - ], - "after": [ - { - "name": "changelog", - "description": "See the [Changelog](/reference/api/hub/changelog) for a summary of changes across Docker Hub API versions.\n", - "summary": "Changelog", - "kind": "info" - }, - { - "name": "resources", - "description": "The following resources are available to interact with the documented API:\n- [Docker Hub CLI tool](https://github.com/docker/hub-tool#readme) (currently experimental)\n", - "summary": "Resources", - "kind": "info" - }, - { - "name": "rate-limiting", - "description": "The Docker Hub API is limited on the amount of requests you can perform per minute against it.\n\nIf you haven't hit the limit, each request to the API will return the following headers in the response.\n\n- `X-RateLimit-Limit` - The limit of requests per minute.\n- `X-RateLimit-Remaining` - The remaining amount of calls within the limit period.\n- `X-RateLimit-Reset` - The unix timestamp of when the remaining resets.\n\nIf you have hit the limit, you will receive a response status of `429` and the `Retry-After` header in the response.\n\nThe [`Retry-After` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After) specifies the number of seconds to wait until you can call the API again.\n\n**Note**: These rate limits are separate from anti-abuse and Docker Hub download, or pull rate limiting.\nTo learn more about Docker Hub pull rate limiting, see [Usage and limits](https://docs.docker.com/docker-hub/usage/).\n", - "summary": "Rate Limiting", - "kind": "info" - }, - { - "name": "authentication", - "description": "Most Docker Hub API endpoints require you to authenticate using your Docker credentials before using them.\n\nAdditionally, similar to the Docker Hub UI features, API endpoint responses may vary depending on your subscription (Personal, Pro, or Team) and your account's permissions.\n\nTo learn more about the features available in each subscription and to upgrade your existing subscription, see [Docker Pricing](https://www.docker.com/pricing?ref=Docs&refAction=DocsApiHub).\n\n# Types\n\nThe Docker Hub API supports the following authentication types.\n\nYou must use each authentication type with the [Create access token](#tag/authentication-api/operation/AuthCreateAccessToken) route to obtain a bearer token.\n\n## Password\nUsing a username and password is the most powerful, yet least secure way \nto authenticate with Docker as a user. It allows access to resources \nfor the user without scopes. \n\n_In general, it is recommended to use a personal access token (PAT) instead._\n\n_**The password authentication type is not available if your organization has SSO enforced.**_\n\n## Personal Access Token (PAT)\nUsing a username and PAT is the most secure way to authenticate with \nDocker as a user. PATs are scoped to specific resources and scopes.\n\nCurrently, a PAT is a more secure password due to limited functionality. \nIn the future, we may add fine-grained access like organization \naccess tokens for enhanced usage and security.\n\n## Organization Access Token (OAT)\nOrganization access tokens are scoped to specific resources and scopes \nin an organization. They are managed by organization owners. \n\nThese tokens are meant for automation and are not meant to be used by \nusers.\n\n# Labels\n\nThese labels will show up on routes in this reference that allow for use of bearer \ntokens issued from them.\n\n\n\n", - "summary": "Authentication", - "kind": "info" - }, - { - "name": "authentication-api", - "description": "The authentication endpoints allow you to authenticate with Docker Hub APIs.\n\nFor more information, see [Authentication](#tag/authentication).\n", - "summary": "Authentication", - "kind": "nav" - }, - { - "name": "access-tokens", - "description": "The Personal Access Token endpoints lets you manage personal access tokens. For more information, see [Access Tokens](https://docs.docker.com/security/access-tokens/personal-access-tokens/).\n\nYou can use a personal access token instead of a password in the [Docker CLI](https://docs.docker.com/engine/reference/commandline/cli/) or in the [Create an authentication token](#operation/PostUsersLogin) route to obtain a bearer token.\n\n### Scopes\n\nFor each scope grouping (in this case \"repo\"), you only need to define 1 scope as any lower scopes are assumed.\nFor example: If you define `repo:write`, the API assumes the scope of both `repo:read` *and* `repo:public_read` as well.\nIf you were to define both `repo:write` *and* `repo:read`, then `repo:read` is assumed by `repo:write` and ignored.\n\n***Treat your personal access token like your password and keep it secret. You cannot retrieve your token after it is generated.***\n", - "summary": "Personal Access Tokens", - "kind": "nav" - }, - { - "name": "audit-logs", - "description": "The Audit Logs API endpoints allow you to query audit log events across a namespace.\n\nFor more information, see [Audit Logs](https://docs.docker.com/admin/activity-logs/).\n", - "summary": "Audit Logs", - "kind": "nav" - }, - { - "name": "org-settings", - "description": "The Org Settings API endpoints allow you to manage your organization's settings.\n", - "summary": "Org Settings", - "kind": "nav" - }, - { - "name": "repositories", - "description": "The repository endpoints allow you to access your repository's tags.\n", - "summary": "Repositories", - "kind": "nav" - }, - { - "name": "orgs", - "x-audience": "public", - "description": "The organization endpoints allow you to interact with and manage your organizations.\n\nFor more information, see [Organization administration overview](https://docs.docker.com/admin/organization/).\n", - "summary": "Organizations", - "kind": "nav" - }, - { - "name": "groups", - "x-audience": "public", - "description": "The groups endpoints allow you to manage your organization's teams and their members.\n\nFor more information, see [Create and manage a team](https://docs.docker.com/admin/organization/manage/manage-a-team/).\n", - "summary": "Groups (Teams)", - "kind": "nav" - }, - { - "name": "invites", - "x-audience": "public", - "description": "The invites endpoints allow you to manage invites for users to join your Docker organization.\n\nFor more information, see [Invite members](https://docs.docker.com/admin/organization/manage/members/#invite-members).\n", - "summary": "Invites", - "kind": "nav" - }, - { - "name": "scim", - "x-audience": "public", - "description": "SCIM is a provisioning system that lets you manage users within your identity provider (IdP).\n\nFor more information, see [System for Cross-domain Identity management](https://docs.docker.com/security/for-admins/provisioning/scim/).\n", - "summary": "SCIM", - "kind": "nav" - }, - { - "name": "org-access-tokens", - "x-audience": "public", - "description": "The organization access token endpoints allow you to manage organization access tokens (OATs). See [Organization access tokens](https://docs.docker.com/security/for-admins/access-tokens/) for more information.\n\nOATs only authenticate requests to the modern namespace-scoped routes under `/v2/namespaces/{namespace}/repositories/`. Legacy repository paths are OAT unsupported, regardless of the token's scopes, and reject every OAT with `403 token issued from organization access token is not allowed`:\n\n- `GET /v2/repositories/{namespace}/{repository}` — use [Get repository](#tag/repositories/operation/GetRepository) instead.\n- `GET /v2/repositories/{namespace}` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n- `GET /v2/users/{username}/repositories` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead.\n", - "summary": "Organization Access Tokens", - "kind": "nav" - } - ], - "id": "hub-8c67a3d8bd5a", - "stage": "portable-descriptions", - "classification": "editorial completion", - "rationale": "Remove renderer-only badges/HTML presentation, retaining their text and Markdown links.", - "evidence": "Docker profile S12", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/tags", - "destinationPointer": "/tags" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "Get groups of an organization.", - "id": "hub-e81c4f02da4d", - "stage": "empty-description-completion", - "classification": "editorial completion", - "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", - "evidence": "Existing operation summary", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "Delete an organization group.", - "id": "hub-90d2bf1f1840", - "stage": "empty-description-completion", - "classification": "editorial completion", - "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", - "evidence": "Existing operation summary", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "Get a group of an organization.", - "id": "hub-3984c74c1439", - "stage": "empty-description-completion", - "classification": "editorial completion", - "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", - "evidence": "Existing operation summary", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "Update some details for an organization group.", - "id": "hub-14585f035f98", - "stage": "empty-description-completion", - "classification": "editorial completion", - "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", - "evidence": "Existing operation summary", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "Update the details for an organization group.", - "id": "hub-2d209be6dab1", - "stage": "empty-description-completion", - "classification": "editorial completion", - "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", - "evidence": "Existing operation summary", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "Add a member to a group.", - "id": "hub-428a2404142d", - "stage": "empty-description-completion", - "classification": "editorial completion", - "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", - "evidence": "Existing operation summary", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/description" - }, - { - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/description", - "beforePresent": true, - "afterPresent": true, - "before": "\n", - "after": "Remove a user from a group.", - "id": "hub-50aea6b744b0", - "stage": "empty-description-completion", - "classification": "editorial completion", - "rationale": "Replace descriptions that contained only presentation markup with the existing operation summary.", - "evidence": "Existing operation summary", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/description", - "destinationPointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/description" - }, - { - "pointer": "/components/schemas/team_repo/allOf", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "$ref": "#/components/responses/team_repo" - } - ], - "after": [ - { - "$ref": "#/components/schemas/repository_info" - } - ], - "id": "hub-f335bd60404f", - "stage": "hub-team-schema-assumption", - "classification": "provisional assumption", - "rationale": "Replace the missing response reference with the existing repository schema, the likely base of a team repository. Product owner must verify returned fields.", - "evidence": "components.schemas.team_repo and existing repository response definition", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/components/schemas/team_repo/allOf", - "destinationPointer": "/components/schemas/team_repo/allOf" - }, - { - "pointer": "/components/securitySchemes/scimToken", - "beforePresent": false, - "afterPresent": true, - "after": { - "type": "http", - "scheme": "bearer", - "description": "Use the SCIM provisioning token configured for the organization." - }, - "id": "hub-9809789ee63e", - "stage": "scim-auth-context", - "classification": "evidence-backed correction", - "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", - "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/components/securitySchemes/scimToken" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/security", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "bearerSCIMAuth": [] - } - ], - "after": [ - { - "scimToken": [] - } - ], - "id": "hub-8f39ee63e16c", - "stage": "scim-auth-context", - "classification": "evidence-backed correction", - "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", - "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/security", - "destinationPointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/security" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/security", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "bearerSCIMAuth": [] - } - ], - "after": [ - { - "scimToken": [] - } - ], - "id": "hub-03dc3581d4c0", - "stage": "scim-auth-context", - "classification": "evidence-backed correction", - "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", - "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/security", - "destinationPointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/security" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1Schemas/get/security", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "bearerSCIMAuth": [] - } - ], - "after": [ - { - "scimToken": [] - } - ], - "id": "hub-5a6d51f54bbf", - "stage": "scim-auth-context", - "classification": "evidence-backed correction", - "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", - "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1scim~12.0~1Schemas/get/security", - "destinationPointer": "/paths/~1v2~1scim~12.0~1Schemas/get/security" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/security", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "bearerSCIMAuth": [] - } - ], - "after": [ - { - "scimToken": [] - } - ], - "id": "hub-e2bd8446c1d5", - "stage": "scim-auth-context", - "classification": "evidence-backed correction", - "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", - "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/security", - "destinationPointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/security" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/security", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "bearerSCIMAuth": [] - } - ], - "after": [ - { - "scimToken": [] - } - ], - "id": "hub-4b8fdeb71056", - "stage": "scim-auth-context", - "classification": "evidence-backed correction", - "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", - "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/security", - "destinationPointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/security" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1Users/get/security", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "bearerSCIMAuth": [] - } - ], - "after": [ - { - "scimToken": [] - } - ], - "id": "hub-ecf88ecedb9e", - "stage": "scim-auth-context", - "classification": "evidence-backed correction", - "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", - "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1scim~12.0~1Users/get/security", - "destinationPointer": "/paths/~1v2~1scim~12.0~1Users/get/security" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1Users/post/security", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "bearerSCIMAuth": [] - } - ], - "after": [ - { - "scimToken": [] - } - ], - "id": "hub-a24fdb1bdff4", - "stage": "scim-auth-context", - "classification": "evidence-backed correction", - "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", - "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1scim~12.0~1Users/post/security", - "destinationPointer": "/paths/~1v2~1scim~12.0~1Users/post/security" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/security", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "bearerSCIMAuth": [] - } - ], - "after": [ - { - "scimToken": [] - } - ], - "id": "hub-3e8afbee54cd", - "stage": "scim-auth-context", - "classification": "evidence-backed correction", - "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", - "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/security", - "destinationPointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/security" - }, - { - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/security", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "bearerSCIMAuth": [] - } - ], - "after": [ - { - "scimToken": [] - } - ], - "id": "hub-56082273dc18", - "stage": "scim-auth-context", - "classification": "evidence-backed correction", - "rationale": "Declare the separate provisioning token for SCIM operations instead of inheriting Hub credential exchange guidance.", - "evidence": "content/manuals/security/provisioning/scim/provision-scim.md", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/security", - "destinationPointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/security" - }, - { - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/200/content", - "beforePresent": true, - "afterPresent": false, - "before": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/repository_info" - }, - "example": { - "name": "my-app", - "namespace": "myorganization", - "repository_type": "image", - "status": 1, - "status_description": "Active", - "description": "A sample application repository", - "is_private": false, - "is_automated": false, - "star_count": 0, - "pull_count": 0, - "last_updated": "2025-01-20T10:30:00Z", - "date_registered": "2025-01-20T10:30:00Z", - "collaborator_count": 0, - "hub_user": "myorganization", - "has_starred": false, - "full_description": "This is a comprehensive description of my application repository that contains additional details about the project.", - "media_types": [], - "content_types": [], - "categories": [], - "immutable_tags_settings": { - "enabled": false, - "rules": [] - }, - "storage_size": null, - "source": null - } - } - }, - "id": "hub-2284c2bd0c92", - "stage": "head-response-bodies", - "classification": "evidence-backed correction", - "rationale": "HEAD responses transfer headers without a response body. Preserve headers and status codes; remove declared content from HEAD responses.", - "evidence": "RFC 9110 section 9.3.2", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/200/content", - "destinationPointer": null - }, - { - "pointer": "/security", - "beforePresent": false, - "afterPresent": true, - "after": [], - "id": "hub-2b9d4937db9a", - "stage": "explicit-root-security", - "classification": "editorial completion", - "rationale": "Make the existing absence of inherited HTTP authentication explicit. Local socket permissions remain connection metadata.", - "evidence": "OpenAPI root security inheritance; existing source operation policies", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/security" - } - ] -} diff --git a/hack/api-docs/adoption/hub.patch b/hack/api-docs/adoption/hub.patch deleted file mode 100644 index b94f13a6a2dd..000000000000 --- a/hack/api-docs/adoption/hub.patch +++ /dev/null @@ -1,2056 +0,0 @@ ---- original/hub.yaml -+++ converted/hub.yaml -@@ -1,6 +1,4 @@ --# yaml-language-server: $schema=https://raw.githubusercontent.com/OAI/OpenAPI-Specification/refs/heads/main/schemas/v3.0/schema.yaml -- --openapi: 3.0.3 -+openapi: 3.2.0 - info: - title: Docker HUB API - version: 2-beta -@@ -21,16 +19,17 @@ - url: https://hub.docker.com - tags: - - name: changelog -- x-displayName: Changelog - description: | - See the [Changelog](/reference/api/hub/changelog) for a summary of changes across Docker Hub API versions. -+ summary: Changelog -+ kind: info - - name: resources -- x-displayName: Resources - description: | - The following resources are available to interact with the documented API: - - [Docker Hub CLI tool](https://github.com/docker/hub-tool#readme) (currently experimental) -+ summary: Resources -+ kind: info - - name: rate-limiting -- x-displayName: Rate Limiting - description: | - The Docker Hub API is limited on the amount of requests you can perform per minute against it. - -@@ -46,9 +45,10 @@ - - **Note**: These rate limits are separate from anti-abuse and Docker Hub download, or pull rate limiting. - To learn more about Docker Hub pull rate limiting, see [Usage and limits](https://docs.docker.com/docker-hub/usage/). -+ summary: Rate Limiting -+ kind: info - - name: authentication -- x-displayName: Authentication -- description: | -+ description: |+ - Most Docker Hub API endpoints require you to authenticate using your Docker credentials before using them. - - Additionally, similar to the Docker Hub UI features, API endpoint responses may vary depending on your subscription (Personal, Pro, or Team) and your account's permissions. -@@ -90,16 +90,18 @@ - These labels will show up on routes in this reference that allow for use of bearer - tokens issued from them. - -- -- -+ -+ -+ summary: Authentication -+ kind: info - - name: authentication-api -- x-displayName: Authentication - description: | - The authentication endpoints allow you to authenticate with Docker Hub APIs. - - For more information, see [Authentication](#tag/authentication). -+ summary: Authentication -+ kind: nav - - name: access-tokens -- x-displayName: Personal Access Tokens - description: | - The Personal Access Token endpoints lets you manage personal access tokens. For more information, see [Access Tokens](https://docs.docker.com/security/access-tokens/personal-access-tokens/). - -@@ -112,50 +114,58 @@ - If you were to define both `repo:write` *and* `repo:read`, then `repo:read` is assumed by `repo:write` and ignored. - - ***Treat your personal access token like your password and keep it secret. You cannot retrieve your token after it is generated.*** -+ summary: Personal Access Tokens -+ kind: nav - - name: audit-logs -- x-displayName: Audit Logs - description: | - The Audit Logs API endpoints allow you to query audit log events across a namespace. - - For more information, see [Audit Logs](https://docs.docker.com/admin/activity-logs/). -+ summary: Audit Logs -+ kind: nav - - name: org-settings -- x-displayName: Org Settings - description: | - The Org Settings API endpoints allow you to manage your organization's settings. -+ summary: Org Settings -+ kind: nav - - name: repositories -- x-displayName: Repositories - description: | - The repository endpoints allow you to access your repository's tags. -+ summary: Repositories -+ kind: nav - - name: orgs -- x-displayName: Organizations - x-audience: public - description: | - The organization endpoints allow you to interact with and manage your organizations. - - For more information, see [Organization administration overview](https://docs.docker.com/admin/organization/). -+ summary: Organizations -+ kind: nav - - name: groups -- x-displayName: Groups (Teams) - x-audience: public - description: | - The groups endpoints allow you to manage your organization's teams and their members. - - For more information, see [Create and manage a team](https://docs.docker.com/admin/organization/manage/manage-a-team/). -+ summary: Groups (Teams) -+ kind: nav - - name: invites -- x-displayName: Invites - x-audience: public - description: | - The invites endpoints allow you to manage invites for users to join your Docker organization. - - For more information, see [Invite members](https://docs.docker.com/admin/organization/manage/members/#invite-members). -+ summary: Invites -+ kind: nav - - name: scim -- x-displayName: SCIM - x-audience: public - description: | - SCIM is a provisioning system that lets you manage users within your identity provider (IdP). - - For more information, see [System for Cross-domain Identity management](https://docs.docker.com/security/for-admins/provisioning/scim/). -+ summary: SCIM -+ kind: nav - - name: org-access-tokens -- x-displayName: Organization Access Tokens - x-audience: public - description: | - The organization access token endpoints allow you to manage organization access tokens (OATs). See [Organization access tokens](https://docs.docker.com/security/for-admins/access-tokens/) for more information. -@@ -165,6 +175,8 @@ - - `GET /v2/repositories/{namespace}/{repository}` — use [Get repository](#tag/repositories/operation/GetRepository) instead. - - `GET /v2/repositories/{namespace}` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead. - - `GET /v2/users/{username}/repositories` — use [List repositories](#tag/repositories/operation/listNamespaceRepositories) instead. -+ summary: Organization Access Tokens -+ kind: nav - paths: - /v2/users/login: - post: -@@ -174,16 +186,16 @@ - operationId: PostUsersLogin - security: [] - deprecated: true -- description: | -+ description: |+ - Creates and returns a bearer token in JWT format that you can use to authenticate with Docker Hub APIs. - - The returned token is used in the HTTP Authorization header like `Authorization: Bearer {TOKEN}`. - - _**As of September 16, 2024, this route requires a personal access token (PAT) instead of a password if your organization has SSO enforced.**_ - --
-- Deprecated: Use [Create access token] instead. --
-+ -+ Deprecated: Use [Create access token](#tag/authentication-api/operation/AuthCreateAccessToken) instead. -+ - requestBody: - content: - application/json: -@@ -310,6 +322,7 @@ - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthorized" -+ operationId: postV2AccessTokens - get: - summary: List personal access tokens - description: Returns a paginated list of personal access tokens. -@@ -339,6 +352,7 @@ - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthorized" -+ operationId: getV2AccessTokens - /v2/access-tokens/{uuid}: - parameters: - - in: path -@@ -371,6 +385,7 @@ - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthorized" -+ operationId: patchV2AccessTokensByUuid - get: - summary: Get personal access token - description: Returns a personal access token by UUID. -@@ -395,6 +410,7 @@ - $ref: "#/components/responses/Unauthorized" - "404": - $ref: "#/components/responses/NotFound" -+ operationId: getV2AccessTokensByUuid - delete: - summary: Delete personal access token - description: | -@@ -410,13 +426,14 @@ - $ref: "#/components/responses/Unauthorized" - "404": - $ref: "#/components/responses/NotFound" -+ operationId: deleteV2AccessTokensByUuid - /v2/auditlogs/{account}/actions: - get: - summary: List audit log actions -- description: | -+ description: |+ - List audit log actions for a namespace to be used as a filter for querying audit log events. - -- -+ - operationId: AuditLogs_ListAuditActions - security: - - bearerAuth: [] -@@ -707,10 +724,10 @@ - /v2/auditlogs/{account}: - get: - summary: List audit log events -- description: | -+ description: |+ - List audit log events for a given namespace. - -- -+ - operationId: AuditLogs_ListAuditLogs - security: - - bearerAuth: [] -@@ -732,7 +749,7 @@ - data: - digest: sha256:c1ae9c435032a276f80220c7d9b40f76266bbe79243d34f9cda30b76fe114dfa - tag: latest -- timestamp: "2021-02-19T01:34:35Z" -+ timestamp: 2021-02-19T01:34:35Z - action_description: | - pushed the tag latest with the digest sha256:c1ae9c435032a to the repository docker/example - - account: docker -@@ -742,12 +759,12 @@ - data: - lease_id: l_3EgPuRCjtUqT279CFPOQWcO8zOf - resource_type: run_4cpu_8mem -- started_at: "2026-06-04T18:24:21Z" -- updated_at: "2026-06-04T18:36:43Z" -+ started_at: 2026-06-04T18:24:21Z -+ updated_at: 2026-06-04T18:36:43Z - org_id: b908ca6e-b9a9-4a53-a9a5-6bec96f72432 - user_id: ecae6747-e42c-43cb-925d-cfce1ab32b02 -- timestamp: "2026-06-04T18:36:43Z" -- action_description: "offload lease 'l_3EgPuRCjtUqT279CFPOQWcO8zOf' ended, ran for '12m22s'" -+ timestamp: 2026-06-04T18:36:43Z -+ action_description: offload lease 'l_3EgPuRCjtUqT279CFPOQWcO8zOf' ended, ran for '12m22s' - "429": - description: "" - content: -@@ -858,6 +875,7 @@ - $ref: "#/components/responses/Forbidden" - "404": - $ref: "#/components/responses/NotFound" -+ operationId: getV2OrgsByNameSettings - put: - summary: Update organization settings - description: | -@@ -900,6 +918,7 @@ - $ref: "#/components/responses/Forbidden" - "404": - $ref: "#/components/responses/NotFound" -+ operationId: putV2OrgsByNameSettings - /v2/orgs/{name}/access-tokens: - post: - summary: Create access token -@@ -930,6 +949,7 @@ - $ref: "#/components/responses/Forbidden" - "404": - $ref: "#/components/responses/NotFound" -+ operationId: postV2OrgsByNameAccessTokens - get: - summary: List access tokens - description: | -@@ -962,7 +982,7 @@ - $ref: "#/components/responses/Forbidden" - "404": - $ref: "#/components/responses/NotFound" -- -+ operationId: getV2OrgsByNameAccessTokens - /v2/orgs/{org_name}/access-tokens/{access_token_id}: - parameters: - - $ref: "#/components/parameters/org_name" -@@ -972,7 +992,7 @@ - schema: - type: string - description: The ID of the access token to retrieve -- example: "a7a5ef25-8889-43a0-8cc7-f2a94268e861" -+ example: a7a5ef25-8889-43a0-8cc7-f2a94268e861 - get: - summary: Get access token - description: | -@@ -994,6 +1014,7 @@ - $ref: "#/components/responses/Forbidden" - "404": - $ref: "#/components/responses/NotFound" -+ operationId: getV2OrgsByOrgNameAccessTokensByAccessTokenId - patch: - summary: Update access token - description: | -@@ -1021,6 +1042,7 @@ - $ref: "#/components/responses/Forbidden" - "404": - $ref: "#/components/responses/NotFound" -+ operationId: patchV2OrgsByOrgNameAccessTokensByAccessTokenId - delete: - summary: Delete access token - description: | -@@ -1038,6 +1060,7 @@ - $ref: "#/components/responses/Forbidden" - "404": - $ref: "#/components/responses/NotFound" -+ operationId: deleteV2OrgsByOrgNameAccessTokensByAccessTokenId - /v2/namespaces/{namespace}/repositories/{repository}/tags: - parameters: - - $ref: "#/components/parameters/namespace" -@@ -1045,10 +1068,10 @@ - get: - operationId: ListRepositoryTags - summary: List repository tags -- description: | -+ description: |+ - Returns the list of tags for the specified repository. - -- -+ - tags: - - repositories - security: -@@ -1075,10 +1098,10 @@ - $ref: "#/components/responses/NotFound" - head: - summary: Check repository tags -- description: | -+ description: |+ - Checks whether the repository has any tags. - -- -+ - tags: - - repositories - security: -@@ -1090,6 +1113,7 @@ - $ref: "#/components/responses/Forbidden" - "404": - $ref: "#/components/responses/NotFound" -+ operationId: headV2NamespacesByNamespaceRepositoriesByRepositoryTags - /v2/namespaces/{namespace}/repositories/{repository}/tags/{tag}: - parameters: - - $ref: "#/components/parameters/namespace" -@@ -1098,10 +1122,10 @@ - get: - operationId: GetRepositoryTag - summary: Read repository tag -- description: | -+ description: |+ - Returns details for a specific tag in the specified repository. - -- -+ - tags: - - repositories - security: -@@ -1115,10 +1139,10 @@ - $ref: "#/components/responses/NotFound" - head: - summary: Check repository tag -- description: | -+ description: |+ - Checks whether the specified tag exists in the repository. - -- -+ - tags: - - repositories - security: -@@ -1130,19 +1154,20 @@ - $ref: "#/components/responses/Forbidden" - "404": - $ref: "#/components/responses/NotFound" -+ operationId: headV2NamespacesByNamespaceRepositoriesByRepositoryTagsByTag - /v2/namespaces/{namespace}/repositories/{repository}/immutabletags: - parameters: - - $ref: "#/components/parameters/namespace" - - $ref: "#/components/parameters/repository" - patch: - operationId: UpdateRepositoryImmutableTags -- summary: "Update repository immutable tags" -- description: | -+ summary: Update repository immutable tags -+ description: |+ - Updates the immutable tags configuration for this repository. - - **Only users with administrative privileges for the repository can modify these settings.** - -- -+ - tags: - - repositories - security: -@@ -1150,15 +1175,15 @@ - requestBody: - $ref: "#/components/requestBodies/update_repository_immutable_tags_request" - responses: -- 200: -+ "200": - $ref: "#/components/responses/update_repository_immutable_tags_response" -- 400: -+ "400": - $ref: "#/components/responses/bad_request" -- 401: -+ "401": - $ref: "#/components/responses/unauthorized" -- 403: -+ "403": - $ref: "#/components/responses/forbidden" -- 404: -+ "404": - $ref: "#/components/responses/not_found" - /v2/namespaces/{namespace}/repositories/{repository}/immutabletags/verify: - parameters: -@@ -1166,13 +1191,13 @@ - - $ref: "#/components/parameters/repository" - post: - operationId: VerifyRepositoryImmutableTags -- summary: "Verify repository immutable tags" -- description: | -+ summary: Verify repository immutable tags -+ description: |+ - Validates the immutable tags regex passed in the request body and returns a list of tags matching it in this repository. - - **Only users with administrative privileges for the repository can call this endpoint.** - -- -+ - tags: - - repositories - security: -@@ -1180,15 +1205,15 @@ - requestBody: - $ref: "#/components/requestBodies/immutable_tags_verify_request" - responses: -- 200: -+ "200": - $ref: "#/components/responses/immutable_tags_verify_response" -- 400: -+ "400": - $ref: "#/components/responses/bad_request" -- 401: -+ "401": - $ref: "#/components/responses/unauthorized" -- 403: -+ "403": - $ref: "#/components/responses/forbidden" -- 404: -+ "404": - $ref: "#/components/responses/not_found" - /v2/repositories/{namespace}/{repository}/groups: - parameters: -@@ -1196,10 +1221,10 @@ - - $ref: "#/components/parameters/repository" - post: - summary: Assign a group (Team) to a repository for access -- description: | -+ description: |+ - Assigns an organization group (team) to a repository with a specified permission level. - -- -+ - tags: - - repositories - operationId: CreateRepositoryGroup -@@ -1213,7 +1238,7 @@ - $ref: "#/components/schemas/RepositoryGroupCreationRequest" - example: - group_id: 12345 -- permission: "write" -+ permission: write - responses: - "200": - description: Repository group permission created successfully -@@ -1222,8 +1247,8 @@ - schema: - $ref: "#/components/schemas/RepositoryGroup" - example: -- group_name: "developers" -- permission: "write" -+ group_name: developers -+ permission: write - group_id: 12345 - "400": - description: Bad Request - Invalid request parameters -@@ -1248,14 +1273,14 @@ - - Public repositories are accessible to everyone, while private repositories require appropriate authentication and permissions. - -- -+ - - **OAT listing behavior**: an OAT with the `scope-repository-list` scope sees all repositories including private ones. An OAT without that scope only sees public repositories. This filtering is silent: the response is a normal `200` with no indication that private repositories were withheld. - tags: - - repositories - security: - - bearerAuth: [] -- - {} # Allow anonymous access for public repositories -+ - {} - parameters: - - in: query - name: page -@@ -1309,59 +1334,59 @@ - repositories_list: - value: - count: 287 -- next: "https://hub.docker.com/v2/namespaces/docker/repositories?page=2&page_size=2" -+ next: https://hub.docker.com/v2/namespaces/docker/repositories?page=2&page_size=2 - previous: null - results: -- - name: "highland_builder" -- namespace: "docker" -- repository_type: "image" -+ - name: highland_builder -+ namespace: docker -+ repository_type: image - status: 1 -- status_description: "active" -- description: "Image for performing Docker build requests" -+ status_description: active -+ description: Image for performing Docker build requests - is_private: false - star_count: 7 - pull_count: 15722123 -- last_updated: "2023-06-20T10:44:45.459826Z" -- last_modified: "2024-10-16T13:48:34.145251Z" -- date_registered: "2015-05-19T21:13:35.937763Z" -+ last_updated: 2023-06-20T10:44:45.459826Z -+ last_modified: 2024-10-16T13:48:34.145251Z -+ date_registered: 2015-05-19T21:13:35.937763Z - affiliation: "" - media_types: -- - "application/octet-stream" -- - "application/vnd.docker.container.image.v1+json" -- - "application/vnd.docker.distribution.manifest.v1+prettyjws" -+ - application/octet-stream -+ - application/vnd.docker.container.image.v1+json -+ - application/vnd.docker.distribution.manifest.v1+prettyjws - content_types: -- - "unrecognized" -- - "image" -+ - unrecognized -+ - image - categories: -- - name: "Languages & frameworks" -- slug: "languages-and-frameworks" -- - name: "Integration & delivery" -- slug: "integration-and-delivery" -- - name: "Operating systems" -- slug: "operating-systems" -+ - name: Languages & frameworks -+ slug: languages-and-frameworks -+ - name: Integration & delivery -+ slug: integration-and-delivery -+ - name: Operating systems -+ slug: operating-systems - storage_size: 488723114800 -- - name: "whalesay" -- namespace: "docker" -+ - name: whalesay -+ namespace: docker - repository_type: null - status: 1 -- status_description: "active" -- description: "An image for use in the Docker demo tutorial" -+ status_description: active -+ description: An image for use in the Docker demo tutorial - is_private: false - star_count: 757 - pull_count: 130737682 -- last_updated: "2015-06-19T19:06:27.388123Z" -- last_modified: "2024-10-16T13:48:34.145251Z" -- date_registered: "2015-06-09T18:16:36.527329Z" -+ last_updated: 2015-06-19T19:06:27.388123Z -+ last_modified: 2024-10-16T13:48:34.145251Z -+ date_registered: 2015-06-09T18:16:36.527329Z - affiliation: "" - media_types: -- - "application/vnd.docker.distribution.manifest.v1+prettyjws" -+ - application/vnd.docker.distribution.manifest.v1+prettyjws - content_types: -- - "image" -+ - image - categories: -- - name: "Languages & frameworks" -- slug: "languages-and-frameworks" -- - name: "Integration & delivery" -- slug: "integration-and-delivery" -+ - name: Languages & frameworks -+ slug: languages-and-frameworks -+ - name: Integration & delivery -+ slug: integration-and-delivery - storage_size: 103666708 - "400": - description: Bad Request - Invalid request parameters -@@ -1375,10 +1400,8 @@ - value: - fields: - ordering: -- [ -- "Invalid ordering value. Must be one of: name, -name, last_updated, -last_updated, pull_count, -pull_count", -- ] -- text: "Invalid ordering value" -+ - "Invalid ordering value. Must be one of: name, -name, last_updated, -last_updated, pull_count, -pull_count" -+ text: Invalid ordering value - "401": - $ref: "#/components/responses/unauthorized" - "403": -@@ -1391,11 +1414,11 @@ - $ref: "#/components/schemas/error" - post: - summary: Create a new repository -- description: | -+ description: |+ - Creates a new repository within the specified namespace. The repository will be created - with the provided metadata including name, description, and privacy settings. - -- -+ - operationId: CreateRepository - tags: - - repositories -@@ -1408,36 +1431,36 @@ - schema: - $ref: "#/components/schemas/repo_creation_request" - example: -- name: "my-app" -- namespace: "myorganization" -- description: "A sample application repository" -- full_description: "This is a comprehensive description of my application repository that contains additional details about the project." -- registry: "docker.io" -+ name: my-app -+ namespace: myorganization -+ description: A sample application repository -+ full_description: This is a comprehensive description of my application repository that contains additional details about the project. -+ registry: docker.io - is_private: false - responses: -- 201: -+ "201": - description: Repository created successfully - content: - application/json: - schema: - $ref: "#/components/schemas/repository_info" - example: -- name: "my-app" -- namespace: "myorganization" -- repository_type: "image" -+ name: my-app -+ namespace: myorganization -+ repository_type: image - status: 1 -- status_description: "Active" -- description: "A sample application repository" -+ status_description: Active -+ description: A sample application repository - is_private: false - is_automated: false - star_count: 0 - pull_count: 0 -- last_updated: "2025-01-20T10:30:00Z" -- date_registered: "2025-01-20T10:30:00Z" -+ last_updated: 2025-01-20T10:30:00Z -+ date_registered: 2025-01-20T10:30:00Z - collaborator_count: 0 -- hub_user: "myorganization" -+ hub_user: myorganization - has_starred: false -- full_description: "This is a comprehensive description of my application repository that contains additional details about the project." -+ full_description: This is a comprehensive description of my application repository that contains additional details about the project. - media_types: [] - content_types: [] - categories: [] -@@ -1446,15 +1469,15 @@ - rules: [] - storage_size: null - source: null -- 400: -+ "400": - $ref: "#/components/responses/bad_request" -- 401: -+ "401": - $ref: "#/components/responses/unauthorized" -- 403: -+ "403": - $ref: "#/components/responses/forbidden" -- 404: -+ "404": - $ref: "#/components/responses/not_found" -- 500: -+ "500": - $ref: "#/components/responses/internal_error" - /v2/namespaces/{namespace}/repositories/{repository}: - parameters: -@@ -1463,40 +1486,40 @@ - get: - operationId: GetRepository - summary: Get repository in a namespace -- description: | -+ description: |+ - Returns a repository within the specified namespace (organization or user). - - Public repositories are accessible to everyone, while private repositories require appropriate authentication and permissions. - -- -+ - tags: - - repositories - security: - - bearerAuth: [] -- - {} # Allow anonymous access for public repositories -+ - {} - responses: -- 200: -+ "200": - content: - application/json: - schema: - $ref: "#/components/schemas/repository_info" - example: -- name: "my-app" -- namespace: "myorganization" -- repository_type: "image" -+ name: my-app -+ namespace: myorganization -+ repository_type: image - status: 1 -- status_description: "Active" -- description: "A sample application repository" -+ status_description: Active -+ description: A sample application repository - is_private: false - is_automated: false - star_count: 0 - pull_count: 0 -- last_updated: "2025-01-20T10:30:00Z" -- date_registered: "2025-01-20T10:30:00Z" -+ last_updated: 2025-01-20T10:30:00Z -+ date_registered: 2025-01-20T10:30:00Z - collaborator_count: 0 -- hub_user: "myorganization" -+ hub_user: myorganization - has_starred: false -- full_description: "This is a comprehensive description of my application repository that contains additional details about the project." -+ full_description: This is a comprehensive description of my application repository that contains additional details about the project. - media_types: [] - content_types: [] - categories: [] -@@ -1505,66 +1528,37 @@ - rules: [] - storage_size: null - source: null -- 401: -+ "401": - $ref: "#/components/responses/unauthorized" -- 403: -+ "403": - $ref: "#/components/responses/forbidden" -- 404: -+ "404": - $ref: "#/components/responses/not_found" -- 500: -+ "500": - $ref: "#/components/responses/internal_error" - head: - operationId: CheckRepository - summary: Check repository in a namespace -- description: | -+ description: |+ - Check a repository within the specified namespace (organization or user). - - Public repositories are accessible to everyone, while private repositories require appropriate authentication and permissions. - -- -+ - tags: - - repositories - security: - - bearerAuth: [] -- - {} # Allow anonymous access for public repositories -+ - {} - responses: -- 200: -- content: -- application/json: -- schema: -- $ref: "#/components/schemas/repository_info" -- example: -- name: "my-app" -- namespace: "myorganization" -- repository_type: "image" -- status: 1 -- status_description: "Active" -- description: "A sample application repository" -- is_private: false -- is_automated: false -- star_count: 0 -- pull_count: 0 -- last_updated: "2025-01-20T10:30:00Z" -- date_registered: "2025-01-20T10:30:00Z" -- collaborator_count: 0 -- hub_user: "myorganization" -- has_starred: false -- full_description: "This is a comprehensive description of my application repository that contains additional details about the project." -- media_types: [] -- content_types: [] -- categories: [] -- immutable_tags_settings: -- enabled: false -- rules: [] -- storage_size: null -- source: null -- 401: -+ "200": {} -+ "401": - $ref: "#/components/responses/unauthorized" -- 403: -+ "403": - $ref: "#/components/responses/forbidden" -- 404: -+ "404": - $ref: "#/components/responses/not_found" -- 500: -+ "500": - $ref: "#/components/responses/internal_error" - /v2/orgs/{org_name}/members: - parameters: -@@ -1577,7 +1571,7 @@ - - $ref: "#/components/parameters/role" - get: - summary: List org members -- description: | -+ description: |+ - Returns a list of members for an organization. - - _The following fields are only visible to orgs with insights enabled._ -@@ -1588,7 +1582,7 @@ - - To make visible, please see [View Insights for organization users](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). - -- -+ - tags: - - orgs - security: -@@ -1610,15 +1604,16 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: getV2OrgsByOrgNameMembers - /v2/orgs/{org_name}/members/export: - parameters: - - $ref: "#/components/parameters/org_name" - get: - summary: Export org members CSV -- description: | -+ description: |+ - Export members of an organization as a CSV - -- -+ - tags: - - orgs - security: -@@ -1682,6 +1677,7 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: getV2OrgsByOrgNameMembersExport - /v2/orgs/{org_name}/members/{username}: - x-audience: public - parameters: -@@ -1689,11 +1685,11 @@ - - $ref: "#/components/parameters/username" - put: - summary: Update org member (role) -- description: | -+ description: |+ - Updates the role of a member in the organization. - ***Only users in the "owners" group of the organization can use this endpoint.*** - -- -+ - tags: - - orgs - security: -@@ -1729,12 +1725,13 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: putV2OrgsByOrgNameMembersByUsername - delete: - summary: Remove member from org -- description: | -+ description: |+ - Removes the member from the org, ie. all groups in the org, unless they're the last owner - -- -+ - tags: - - orgs - security: -@@ -1750,16 +1747,17 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: deleteV2OrgsByOrgNameMembersByUsername - /v2/orgs/{org_name}/invites: - x-audience: public - parameters: - - $ref: "#/components/parameters/org_name" - get: - summary: List org invites -- description: | -+ description: |+ - Return all pending invites for a given org, only team owners can call this endpoint - -- -+ - tags: - - invites - security: -@@ -1782,14 +1780,14 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: getV2OrgsByOrgNameInvites - /v2/orgs/{org_name}/groups: - x-audience: public - parameters: - - $ref: "#/components/parameters/org_name" - get: - summary: Get groups of an organization -- description: | -- -+ description: Get groups of an organization. - tags: - - groups - security: -@@ -1833,12 +1831,13 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: getV2OrgsByOrgNameGroups - post: - summary: Create a new group -- description: | -+ description: |+ - Create a new group within an organization. - -- -+ - tags: - - groups - security: -@@ -1867,6 +1866,7 @@ - $ref: "#/components/responses/unauthorized" - "403": - $ref: "#/components/responses/forbidden" -+ operationId: postV2OrgsByOrgNameGroups - /v2/orgs/{org_name}/groups/{group_name}: - x-audience: public - parameters: -@@ -1874,8 +1874,7 @@ - - $ref: "#/components/parameters/group_name" - get: - summary: Get a group of an organization -- description: | -- -+ description: Get a group of an organization. - tags: - - groups - security: -@@ -1893,10 +1892,10 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: getV2OrgsByOrgNameGroupsByGroupName - put: - summary: Update the details for an organization group -- description: | -- -+ description: Update the details for an organization group. - tags: - - groups - security: -@@ -1925,10 +1924,10 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: putV2OrgsByOrgNameGroupsByGroupName - patch: - summary: Update some details for an organization group -- description: | -- -+ description: Update some details for an organization group. - tags: - - groups - security: -@@ -1962,10 +1961,10 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: patchV2OrgsByOrgNameGroupsByGroupName - delete: - summary: Delete an organization group -- description: | -- -+ description: Delete an organization group. - tags: - - groups - security: -@@ -1979,6 +1978,7 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: deleteV2OrgsByOrgNameGroupsByGroupName - /v2/orgs/{org_name}/groups/{group_name}/members: - x-audience: public - get: -@@ -1995,11 +1995,11 @@ - type: string - description: Search members by username, full_name or email. - summary: List members of a group -- description: | -+ description: |+ - List the members (users) that are in a group. - If user is owner of the org or has otherwise elevated permissions, they can search by email and the result will also contain emails. - -- -+ - tags: - - groups - responses: -@@ -2028,13 +2028,13 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: getV2OrgsByOrgNameGroupsByGroupNameMembers - post: - parameters: - - $ref: "#/components/parameters/org_name" - - $ref: "#/components/parameters/group_name" - summary: Add a member to a group -- description: | -- -+ description: Add a member to a group. - tags: - - groups - security: -@@ -2052,6 +2052,7 @@ - $ref: "#/components/responses/not_found" - "500": - $ref: "#/components/responses/internal_error" -+ operationId: postV2OrgsByOrgNameGroupsByGroupNameMembers - /v2/orgs/{org_name}/groups/{group_name}/members/{username}: - x-audience: public - parameters: -@@ -2060,8 +2061,7 @@ - - $ref: "#/components/parameters/username" - delete: - summary: Remove a user from a group -- description: | -- -+ description: Remove a user from a group. - tags: - - groups - security: -@@ -2075,6 +2075,7 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: deleteV2OrgsByOrgNameGroupsByGroupNameMembersByUsername - /v2/invites/{id}: - x-audience: public - parameters: -@@ -2085,10 +2086,10 @@ - type: string - delete: - summary: Cancel an invite -- description: | -+ description: |+ - Mark the invite as cancelled so it doesn't show up on the list of pending invites - -- -+ - tags: - - invites - security: -@@ -2102,6 +2103,7 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: deleteV2InvitesById - /v2/invites/{id}/resend: - x-audience: public - parameters: -@@ -2112,10 +2114,10 @@ - required: true - patch: - summary: Resend an invite -- description: | -+ description: |+ - Resend a pending invite to the user, any org owner can resend an invite - -- -+ - tags: - - invites - security: -@@ -2129,16 +2131,17 @@ - $ref: "#/components/responses/forbidden" - "404": - $ref: "#/components/responses/not_found" -+ operationId: patchV2InvitesByIdResend - /v2/invites/bulk: - x-audience: public - parameters: - - $ref: "#/components/parameters/bulk_invite" - post: - summary: Bulk create invites -- description: | -+ description: |+ - Create multiple invites by emails or DockerIDs. Only a team owner can create invites. - -- -+ - tags: - - invites - requestBody: -@@ -2159,6 +2162,7 @@ - $ref: "#/components/responses/bad_request" - "409": - $ref: "#/components/responses/conflict" -+ operationId: postV2InvitesBulk - /v2/scim/2.0/ServiceProviderConfig: - x-audience: public - get: -@@ -2168,7 +2172,7 @@ - tags: - - scim - security: -- - bearerSCIMAuth: [] -+ - scimToken: [] - responses: - "200": - $ref: "#/components/responses/scim_get_service_provider_config_resp" -@@ -2176,6 +2180,7 @@ - $ref: "#/components/responses/scim_unauthorized" - "500": - $ref: "#/components/responses/scim_error" -+ operationId: getV2Scim20ServiceProviderConfig - /v2/scim/2.0/ResourceTypes: - x-audience: public - get: -@@ -2185,7 +2190,7 @@ - tags: - - scim - security: -- - bearerSCIMAuth: [] -+ - scimToken: [] - responses: - "200": - $ref: "#/components/responses/scim_get_resource_types_resp" -@@ -2193,6 +2198,7 @@ - $ref: "#/components/responses/scim_unauthorized" - "500": - $ref: "#/components/responses/scim_error" -+ operationId: getV2Scim20ResourceTypes - /v2/scim/2.0/ResourceTypes/{name}: - x-audience: public - get: -@@ -2209,7 +2215,7 @@ - example: User - required: true - security: -- - bearerSCIMAuth: [] -+ - scimToken: [] - responses: - "200": - $ref: "#/components/responses/scim_get_resource_type_resp" -@@ -2219,6 +2225,7 @@ - $ref: "#/components/responses/scim_not_found" - "500": - $ref: "#/components/responses/scim_error" -+ operationId: getV2Scim20ResourceTypesByName - /v2/scim/2.0/Schemas: - x-audience: public - get: -@@ -2228,7 +2235,7 @@ - tags: - - scim - security: -- - bearerSCIMAuth: [] -+ - scimToken: [] - responses: - "200": - $ref: "#/components/responses/scim_get_schemas_resp" -@@ -2236,6 +2243,7 @@ - $ref: "#/components/responses/scim_unauthorized" - "500": - $ref: "#/components/responses/scim_error" -+ operationId: getV2Scim20Schemas - /v2/scim/2.0/Schemas/{id}: - x-audience: public - get: -@@ -2252,7 +2260,7 @@ - example: urn:ietf:params:scim:schemas:core:2.0:User - required: true - security: -- - bearerSCIMAuth: [] -+ - scimToken: [] - responses: - "200": - $ref: "#/components/responses/scim_get_schema_resp" -@@ -2262,6 +2270,7 @@ - $ref: "#/components/responses/scim_not_found" - "500": - $ref: "#/components/responses/scim_error" -+ operationId: getV2Scim20SchemasById - /v2/scim/2.0/Users: - x-audience: public - get: -@@ -2292,7 +2301,7 @@ - tags: - - scim - security: -- - bearerSCIMAuth: [] -+ - scimToken: [] - parameters: - - name: startIndex - in: query -@@ -2342,6 +2351,7 @@ - $ref: "#/components/responses/scim_not_found" - "500": - $ref: "#/components/responses/scim_error" -+ operationId: getV2Scim20Users - post: - summary: Create user - description: | -@@ -2349,7 +2359,7 @@ - tags: - - scim - security: -- - bearerSCIMAuth: [] -+ - scimToken: [] - requestBody: - $ref: "#/components/requestBodies/scim_create_user_request" - responses: -@@ -2367,6 +2377,7 @@ - $ref: "#/components/responses/scim_conflict" - "500": - $ref: "#/components/responses/scim_error" -+ operationId: postV2Scim20Users - /v2/scim/2.0/Users/{id}: - x-audience: public - parameters: -@@ -2378,7 +2389,7 @@ - tags: - - scim - security: -- - bearerSCIMAuth: [] -+ - scimToken: [] - responses: - "200": - $ref: "#/components/responses/scim_get_user_resp" -@@ -2392,6 +2403,7 @@ - $ref: "#/components/responses/scim_not_found" - "500": - $ref: "#/components/responses/scim_error" -+ operationId: getV2Scim20UsersById - put: - summary: Update a user - description: | -@@ -2399,7 +2411,7 @@ - tags: - - scim - security: -- - bearerSCIMAuth: [] -+ - scimToken: [] - requestBody: - $ref: "#/components/requestBodies/scim_update_user_request" - responses: -@@ -2417,6 +2429,7 @@ - $ref: "#/components/responses/scim_conflict" - "500": - $ref: "#/components/responses/scim_error" -+ operationId: putV2Scim20UsersById - components: - responses: - BadRequest: -@@ -2679,8 +2692,8 @@ - type: string - description: List of immutable tag rules - example: -- - "v.*" -- - ".*-RELEASE" -+ - v.* -+ - .*-RELEASE - required: - - immutable_tags - - immutable_tags_rules -@@ -2698,26 +2711,26 @@ - Letters must be lowercase. - minLength: 2 - maxLength: 255 -- pattern: "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" -- example: "my-app" -+ pattern: ^[a-z0-9]+(?:[._-][a-z0-9]+)*$ -+ example: my-app - namespace: - type: string - description: The namespace where the repository will be created -- example: "myorganization" -+ example: myorganization - description: - type: string - description: Short description of the repository - maxLength: 100 -- example: "A sample application repository" -+ example: A sample application repository - full_description: - type: string - description: Detailed description of the repository - maxLength: 25000 -- example: "This is a comprehensive description of my application repository that contains additional details about the project, its purpose, usage instructions, and other relevant information." -+ example: This is a comprehensive description of my application repository that contains additional details about the project, its purpose, usage instructions, and other relevant information. - registry: - type: string - description: The registry where the repository will be hosted -- example: "docker.io" -+ example: docker.io - is_private: - type: boolean - description: Whether the repository should be private -@@ -2741,20 +2754,26 @@ - - read: Can view and pull from the repository - - write: Can view, pull, and push to the repository - - admin: Can view, pull, push, and manage repository settings -- enum: ["read", "write", "admin"] -- example: "write" -+ enum: -+ - read -+ - write -+ - admin -+ example: write - RepositoryGroup: - type: object - properties: - group_name: - type: string - description: The name of the group -- example: "developers" -+ example: developers - permission: - type: string - description: The permission level granted to the group -- enum: ["read", "write", "admin"] -- example: "write" -+ enum: -+ - read -+ - write -+ - admin -+ example: write - group_id: - type: integer - format: int64 -@@ -2773,8 +2792,9 @@ - type: string - description: Repository namespace - repository_type: -- type: string -- nullable: true -+ type: -+ - string -+ - "null" - description: Type of the repository - status: - type: integer -@@ -2802,45 +2822,50 @@ - last_updated: - type: string - format: date-time -- example: "2021-01-05T21:06:53.506400Z" -+ example: 2021-01-05T21:06:53.506400Z - description: ISO 8601 timestamp of when repository was last updated - last_modified: -- type: string -+ type: -+ - string -+ - "null" - format: date-time -- example: "2021-01-05T21:06:53.506400Z" -- nullable: true -+ example: 2021-01-05T21:06:53.506400Z - description: ISO 8601 timestamp of when repository was last modified - date_registered: - type: string - format: date-time -- example: "2021-01-05T21:06:53.506400Z" -+ example: 2021-01-05T21:06:53.506400Z - description: ISO 8601 timestamp of when repository was created - collaborator_count: - type: integer - format: int64 - description: Number of collaborators - affiliation: -- type: string -- nullable: true -+ type: -+ - string -+ - "null" - description: Repository affiliation - hub_user: -- type: string -- nullable: true -+ type: -+ - string -+ - "null" - description: Hub user information - has_starred: - type: boolean - description: Whether the current user has starred this repository - full_description: -- type: string -- nullable: true -+ type: -+ - string -+ - "null" - description: Full description of the repository - permissions: - $ref: "#/components/schemas/repo_permissions" - media_types: - type: array - items: -- type: string -- nullable: true -+ type: -+ - string -+ - "null" - description: Supported media types - content_types: - type: array -@@ -2855,13 +2880,15 @@ - immutable_tags_settings: - $ref: "#/components/schemas/immutable_tags_settings" - storage_size: -- type: integer -+ type: -+ - integer -+ - "null" - format: int64 -- nullable: true - description: Storage size in bytes - source: -- type: string -- nullable: true -+ type: -+ - string -+ - "null" - description: Source of the repository, where it was created from - required: - - user -@@ -2918,9 +2945,9 @@ - properties: - regex: - type: string -- pattern: '^[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*(\\/[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*)*$' -- description: 'Immutable tags rule regex pattern. Must match format: [a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*(\\/[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*)*' -- example: "v.*" -+ pattern: ^[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*(\\/[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*)*$ -+ description: "Immutable tags rule regex pattern. Must match format: [a-z0-9]+((\\\\.|_|__|-+)[a-z0-9]+)*(\\\\/[a-z0-9]+((\\\\.|_|__|-+)[a-z0-9]+)*)*" -+ example: v.* - required: - - regex - immutable_tags_verify_response: -@@ -2932,9 +2959,9 @@ - type: string - description: List of tags that match the provided regex pattern - example: -- - "v1.0.0" -- - "v2.1.3" -- - "latest" -+ - v1.0.0 -+ - v2.1.3 -+ - latest - required: - - tags - repository_list_entry: -@@ -2943,20 +2970,21 @@ - name: - type: string - description: Name of the repository -- example: "hello-world" -+ example: hello-world - namespace: - type: string - description: Namespace (organization or username) that owns the repository -- example: "docker" -+ example: docker - repository_type: -- type: string -+ type: -+ - string -+ - "null" - description: Type of repository - enum: - - image - - plugin - - null -- example: "image" -- nullable: true -+ example: image - status: - type: integer - description: Repository status code -@@ -2967,12 +2995,13 @@ - enum: - - active - - inactive -- example: "active" -+ example: active - description: -- type: string -+ type: -+ - string -+ - "null" - description: Repository description -- nullable: true -- example: "Hello World! (an example of minimal Dockerization)" -+ example: Hello World! (an example of minimal Dockerization) - is_private: - type: boolean - description: Whether the repository is private -@@ -2988,22 +3017,24 @@ - minimum: 0 - example: 50000000 - last_updated: -- type: string -+ type: -+ - string -+ - "null" - format: date-time - description: ISO 8601 timestamp of when the repository was last updated -- example: "2023-12-01T10:30:00Z" -- nullable: true -+ example: 2023-12-01T10:30:00Z - last_modified: -- type: string -+ type: -+ - string -+ - "null" - format: date-time - description: ISO 8601 timestamp of when the repository was last modified -- example: "2023-12-01T10:30:00Z" -- nullable: true -+ example: 2023-12-01T10:30:00Z - date_registered: - type: string - format: date-time - description: ISO 8601 timestamp of when the repository was created -- example: "2013-06-19T19:07:54Z" -+ example: 2013-06-19T19:07:54Z - affiliation: - type: string - description: User's affiliation with the repository (empty string if no affiliation) -@@ -3014,14 +3045,14 @@ - items: - type: string - example: -- - "application/vnd.docker.plugin.v1+json" -+ - application/vnd.docker.plugin.v1+json - content_types: - type: array - description: Content types supported by this repository - items: - type: string - example: -- - "plugin" -+ - plugin - categories: - type: array - description: Categories associated with this repository -@@ -3042,14 +3073,14 @@ - name: - type: string - description: Human-readable name of the category -- example: "Databases" -+ example: Databases - minLength: 1 - slug: - type: string - description: URL-friendly identifier for the category -- example: "databases" -+ example: databases - minLength: 1 -- pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*$" -+ pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$ - description: Repository category for classification and discovery - list_repositories_response: - allOf: -@@ -3094,7 +3125,6 @@ - This token can be used in the HTTP Authorization header as a JWT to authenticate with the Docker Hub APIs. - type: string - example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c -- nullable: false - PostUsersLoginErrorResponse: - description: failed user login response or second factor required - type: object -@@ -3105,13 +3135,13 @@ - description: Description of the error. - type: string - example: Incorrect authentication credentials -- nullable: false - login_2fa_token: - description: | - Short time lived token to be used on `/v2/users/2fa-login` to complete the authentication. This field is present only if 2FA is enabled. -- type: string -+ type: -+ - string -+ - "null" - example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c -- nullable: true - Users2FALoginRequest: - description: Second factor user login details - type: object -@@ -3136,7 +3166,6 @@ - description: Description of the error. - type: string - example: Incorrect authentication credentials -- nullable: false - protobufAny: - type: object - properties: -@@ -3254,11 +3283,12 @@ - example: some user agent - created_at: - type: string -- example: "2021-07-20T12:00:00.000000Z" -+ example: 2021-07-20T12:00:00.000000Z - last_used: -- type: string -+ type: -+ - string -+ - "null" - example: null -- nullable: true - generated_by: - type: string - example: manual -@@ -3280,7 +3310,7 @@ - expires_at: - type: string - format: date-time -- example: "2021-10-28T18:30:19.520861Z" -+ example: 2021-10-28T18:30:19.520861Z - createAccessTokenRequest: - type: object - required: -@@ -3307,7 +3337,7 @@ - Optional expiration date for the token. - If omitted, the token will remain valid indefinitely. - format: date-time -- example: "2021-10-28T18:30:19.520861Z" -+ example: 2021-10-28T18:30:19.520861Z - createAccessTokensResponse: - $ref: "#/components/schemas/accessToken" - getAccessTokensResponse: -@@ -3372,9 +3402,10 @@ - type: object - properties: - digest: -- type: string -+ type: -+ - string -+ - "null" - description: image layer digest -- nullable: true - size: - type: integer - description: size of the layer -@@ -3394,9 +3425,10 @@ - type: string - description: CPU variant - digest: -- type: string -+ type: -+ - string -+ - "null" - description: image digest -- nullable: true - layers: - type: array - items: -@@ -3420,15 +3452,17 @@ - - inactive - description: Status of the image - last_pulled: -- type: string -- example: "2021-01-05T21:06:53.506400Z" -+ type: -+ - string -+ - "null" -+ example: 2021-01-05T21:06:53.506400Z - description: datetime of last pull -- nullable: true - last_pushed: -- type: string -- example: "2021-01-05T21:06:53.506400Z" -+ type: -+ - string -+ - "null" -+ example: 2021-01-05T21:06:53.506400Z - description: datetime of last push -- nullable: true - tag: - type: object - properties: -@@ -3442,10 +3476,11 @@ - type: integer - description: ID of the user that pushed the tag - last_updated: -- type: string -- example: "2021-01-05T21:06:53.506400Z" -+ type: -+ - string -+ - "null" -+ example: 2021-01-05T21:06:53.506400Z - description: datetime of last update -- nullable: true - last_updater: - type: integer - description: ID of the last user that updated the tag -@@ -3471,15 +3506,17 @@ - - inactive - description: whether a tag has been pushed to or pulled in the past month - tag_last_pulled: -- type: string -- example: "2021-01-05T21:06:53.506400Z" -+ type: -+ - string -+ - "null" -+ example: 2021-01-05T21:06:53.506400Z - description: datetime of last pull -- nullable: true - tag_last_pushed: -- type: string -- example: "2021-01-05T21:06:53.506400Z" -+ type: -+ - string -+ - "null" -+ example: 2021-01-05T21:06:53.506400Z - description: datetime of last push -- nullable: true - paginated_tags: - allOf: - - $ref: "#/components/schemas/page" -@@ -3496,13 +3533,15 @@ - type: integer - description: total number of results available across all pages - next: -- type: string -+ type: -+ - string -+ - "null" - description: link to next page of results if any -- nullable: true - previous: -- type: string -+ type: -+ - string -+ - "null" - description: link to previous page of results if any -- nullable: true - scim_schema_attribute: - type: object - properties: -@@ -3570,7 +3609,7 @@ - example: owners - created_at: - type: string -- example: "2021-10-28T18:30:19.520861Z" -+ example: 2021-10-28T18:30:19.520861Z - bulk_invite: - type: object - properties: -@@ -3599,7 +3638,7 @@ - invitee: invitee@docker.com - org: docker - team: owners -- created_at: "2021-10-28T18:30:19.520861Z" -+ created_at: 2021-10-28T18:30:19.520861Z - - invitee: invitee2@docker.com - status: existing_org_member - - invitee: invitee3@docker.com -@@ -3641,7 +3680,7 @@ - example: Docker Inc - date_joined: - type: string -- example: "2021-01-05T21:06:53.506400Z" -+ example: 2021-01-05T21:06:53.506400Z - full_name: - type: string - example: Jon Snow -@@ -3704,21 +3743,20 @@ - description: | - Last time the user logged in. To access this field, you must have insights visible for your organization. See - [Insights](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). -- example: "2021-01-05T21:06:53.506400Z" -+ example: 2021-01-05T21:06:53.506400Z - last_seen_at: - type: string - format: date-time - description: | - Last time the user was seen. To access this field, you must have insights visible for your organization. See - [Insights](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). -- example: "2021-01-05T21:06:53.506400Z" -+ example: 2021-01-05T21:06:53.506400Z - last_desktop_version: - type: string - description: | - Last desktop version the user used. To access this field, you must have insights visible for your organization. See - [Insights](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). - example: 4.29.0 -- - org_member_paginated: - type: object - properties: -@@ -3779,7 +3817,7 @@ - date_joined: - type: string - format: date-time -- example: "2021-01-05T21:06:53.506400Z" -+ example: 2021-01-05T21:06:53.506400Z - full_name: - type: string - example: John Snow -@@ -4034,41 +4072,43 @@ - type: string - format: date-time - description: The creation date for the user as a RFC3339 formatted string. -- example: "2022-05-20T00:54:18Z" -+ example: 2022-05-20T00:54:18Z - lastModified: - type: string - format: date-time - description: The date the user was last modified as a RFC3339 formatted string. -- example: "2022-05-20T00:54:18Z" -+ example: 2022-05-20T00:54:18Z - orgAccessToken: - type: object - properties: - id: - type: string -- example: "a7a5ef25-8889-43a0-8cc7-f2a94268e861" -+ example: a7a5ef25-8889-43a0-8cc7-f2a94268e861 - label: - type: string -- example: "My organization token" -+ example: My organization token - created_by: - type: string -- example: "johndoe" -+ example: johndoe - is_active: - type: boolean - example: true - created_at: - type: string - format: date-time -- example: "2022-05-20T00:54:18Z" -+ example: 2022-05-20T00:54:18Z - expires_at: -- type: string -+ type: -+ - string -+ - "null" - format: date-time -- example: "2023-05-20T00:54:18Z" -- nullable: true -+ example: 2023-05-20T00:54:18Z - last_used_at: -- type: string -+ type: -+ - string -+ - "null" - format: date-time -- example: "2022-06-15T12:30:45Z" -- nullable: true -+ example: 2022-06-15T12:30:45Z - orgAccessTokenResource: - type: object - properties: -@@ -4077,12 +4117,11 @@ - enum: - - TYPE_REPO - - TYPE_ORG -- example: "TYPE_REPO" -+ example: TYPE_REPO - description: The type of resource -- required: true - path: - type: string -- example: "myorg/myrepo" -+ example: myorg/myrepo - description: | - The path of the resource. The format of this will change depending on the type of resource. - -@@ -4090,14 +4129,16 @@ - - Must be an existing repository name (e.g., "myorg/myrepo") - - Can use glob patterns (e.g., "myorg/*" for all repositories in the organization) - - Use "*/*/public" to reference all public repositories -- required: true - scopes: - type: array - description: The scopes this token has access to - items: - type: string -- example: "scope-image-pull" -- required: true -+ example: scope-image-pull -+ required: -+ - type -+ - path -+ - scopes - getOrgAccessTokensResponse: - type: object - properties: -@@ -4130,23 +4171,25 @@ - label: - type: string - description: Label for the access token -- example: "My organization token" -- required: true -+ example: My organization token - description: - type: string - description: Description of the access token -- example: "Token for CI/CD pipeline" -+ example: Token for CI/CD pipeline - resources: - type: array - description: Resources this token has access to - items: - $ref: "#/components/schemas/orgAccessTokenResource" - expires_at: -- type: string -+ type: -+ - string -+ - "null" - format: date-time - description: Expiration date for the token -- example: "2023-05-20T00:54:18Z" -- nullable: true -+ example: 2023-05-20T00:54:18Z -+ required: -+ - label - createOrgAccessTokenResponse: - type: object - allOf: -@@ -4154,33 +4197,35 @@ - properties: - id: - type: string -- example: "a7a5ef25-8889-43a0-8cc7-f2a94268e861" -+ example: a7a5ef25-8889-43a0-8cc7-f2a94268e861 - label: - type: string -- example: "My organization token" -+ example: My organization token - is_active: - type: boolean - example: true - created_at: - type: string - format: date-time -- example: "2022-05-20T00:54:18Z" -+ example: 2022-05-20T00:54:18Z - expires_at: -- type: string -+ type: -+ - string -+ - "null" - format: date-time -- example: "2023-05-20T00:54:18Z" -- nullable: true -+ example: 2023-05-20T00:54:18Z - last_used_at: -- type: string -+ type: -+ - string -+ - "null" - format: date-time -- example: "2022-06-15T12:30:45Z" -- nullable: true -+ example: 2022-06-15T12:30:45Z - - type: object - properties: - token: - type: string - description: The actual token value that can be used for authentication -- example: "dckr_oat_7awgM4jG5SQvxcvmNzhKj8PQjxo" -+ example: dckr_oat_7awgM4jG5SQvxcvmNzhKj8PQjxo - resources: - type: array - items: -@@ -4191,11 +4236,11 @@ - label: - type: string - description: Label for the access token -- example: "My organization token" -+ example: My organization token - description: - type: string - description: Description of the access token -- example: "Token for CI/CD pipeline" -+ example: Token for CI/CD pipeline - resources: - type: array - description: Resources this token has access to -@@ -4218,7 +4263,7 @@ - $ref: "#/components/schemas/orgAccessTokenResource" - team_repo: - allOf: -- - $ref: "#/components/responses/team_repo" -+ - $ref: "#/components/schemas/repository_info" - properties: - group_name: - type: string -@@ -4442,6 +4487,10 @@ - bearerSCIMAuth: - type: http - scheme: bearer -+ scimToken: -+ type: http -+ scheme: bearer -+ description: Use the SCIM provisioning token configured for the organization. - x-tagGroups: - - name: General - tags: -@@ -4462,3 +4511,5 @@ - - org-access-tokens - - groups - - invites -+jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base -+security: [] diff --git a/hack/api-docs/adoption/registry.json b/hack/api-docs/adoption/registry.json deleted file mode 100644 index 35d8f50dffa6..000000000000 --- a/hack/api-docs/adoption/registry.json +++ /dev/null @@ -1,247 +0,0 @@ -{ - "api": "registry", - "source": { - "id": "registry", - "product": "registry", - "title": "Registry", - "source": "content/reference/api/registry/latest.yaml", - "owner": "docker/docs (product authority to confirm)", - "manual": "/manuals/docker-hub/repos/", - "connection": "hosted", - "auth": "Follow the WWW-Authenticate challenge and obtain a repository-scoped registry token. This is separate from the Hub API token exchange.", - "guides": [ - "/reference/api/registry/auth.md" - ], - "sha256": "229198e078ee30400c0359311f5baaf23a1f80563a1c2e82834f17f2db0d9fd1" - }, - "convertedSha256": "3257829998629249bd9bd27a79996f922169e0c98677b67fb1dc87f565391a01", - "profile": "docker-docs-prototype-1", - "changes": [ - { - "pointer": "/jsonSchemaDialect", - "beforePresent": false, - "afterPresent": true, - "after": "https://spec.openapis.org/oas/3.1/dialect/base", - "id": "registry-03ee85af235e", - "stage": "oas32-header", - "classification": "mechanical conversion", - "rationale": "Adopt the common OpenAPI version and its selected schema dialect.", - "evidence": "API-DOCUMENTATION-ARCHITECTURE.md S1", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/jsonSchemaDialect" - }, - { - "pointer": "/openapi", - "beforePresent": true, - "afterPresent": true, - "before": "3.0.3", - "after": "3.2.0", - "id": "registry-71377657b6ae", - "stage": "oas32-header", - "classification": "mechanical conversion", - "rationale": "Adopt the common OpenAPI version and its selected schema dialect.", - "evidence": "API-DOCUMENTATION-ARCHITECTURE.md S1", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/openapi", - "destinationPointer": "/openapi" - }, - { - "pointer": "/tags", - "beforePresent": true, - "afterPresent": true, - "before": [ - { - "name": "overview", - "x-displayName": "Overview", - "description": "All endpoints in this API are prefixed by the version and repository name, for example:\n\n```\n/v2//\n```\n\nThis format provides structured access control and URI-based scoping of image operations.\n\nFor example, to interact with the `library/ubuntu` repository, use:\n\n```\n/v2/library/ubuntu/\n```\n\nRepository names must meet these requirements:\n1. Consist of path components matching `[a-z0-9]+(?:[._-][a-z0-9]+)*`\n2. If more than one component, they must be separated by `/`\n3. Full repository name must be fewer than 256 characters\n" - }, - { - "name": "authentication", - "x-displayName": "Authentication", - "description": "Specifies registry authentication.\n", - "externalDocs": { - "description": "Detailed authentication workflow and token usage", - "url": "https://docs.docker.com/reference/api/registry/auth/" - } - }, - { - "name": "Manifests", - "x-displayName": "Manifests", - "description": "Image manifests are JSON documents that describe an image: its configuration blob, the digests of each layer blob, and metadata such as media‑types and annotations.\n" - }, - { - "name": "Blobs", - "x-displayName": "Blobs", - "description": "Blobs are the binary objects referenced from manifests:\nthe config JSON and one or more compressed layer tarballs.\n" - }, - { - "name": "pull", - "x-displayName": "Pulling Images", - "description": "Pulling an image involves retrieving the manifest and downloading each of the image's layer blobs. This section outlines the general steps followed by a working example.\n\n1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/).\n2. [Get the image manifest](#operation/GetImageManifest).\n3. If the response in the previous step is a multi-architecture manifest list, you must do the following:\n - Parse the `manifests[]` array to locate the digest for your target platform (e.g., `linux/amd64`).\n - [Get the image manifest](#operation/GetImageManifest) using the located digest.\n4. [Check if the blob exists](#operation/CheckBlobExists) before downloading. The client should send a `HEAD` request for each layer digest.\n5. [Download each layer blob](#operation/GetBlob) using the digest obtained from the manifest. The client should send a `GET` request for each layer digest.\n\nThe following bash script example pulls `library/ubuntu:latest` from Docker Hub.\n\n```bash\n#!/bin/bash\n\n# Step 1: Get a bearer token\nTOKEN=$(curl -s \"https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/ubuntu:pull\" | jq -r .token)\n\n# Step 2: Get the image manifest. In this example, an image manifest list is returned.\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Accept: application/vnd.docker.distribution.manifest.list.v2+json\" \\\n https://registry-1.docker.io/v2/library/ubuntu/manifests/latest \\\n -o manifest-list.json\n\n# Step 3a: Parse the `manifests[]` array to locate the digest for your target platform (e.g., `linux/amd64`).\nIMAGE_MANIFEST_DIGEST=$(jq -r '.manifests[] | select(.platform.architecture == \"amd64\" and .platform.os == \"linux\") | .digest' manifest-list.json)\n\n# Step 3b: Get the platform-specific image manifest\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Accept: application/vnd.docker.distribution.manifest.v2+json\" \\\n https://registry-1.docker.io/v2/library/ubuntu/manifests/$IMAGE_MANIFEST_DIGEST \\\n -o manifest.json\n\n# Step 4: Send a HEAD request to check if the layer blob exists\nDIGEST=$(jq -r '.layers[0].digest' manifest.json)\ncurl -I -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST\n\n# Step 5: Download the layer blob\ncurl -L -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST\n```\n\nThis example pulls the manifest and the first layer for the `ubuntu:latest` image on the `linux/amd64` platform. Repeat steps 4 and 5 for each digest in the `.layers[]` array in the manifest.\n" - }, - { - "name": "push", - "x-displayName": "Pushing Images", - "description": "Pushing an image involves uploading any image blobs (such as the config or layers), and then uploading the manifest that references those blobs.\n\nThis section outlines the basic steps to push an image using the registry API.\n\n1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/)\n\n2. [Check if the blob exists](#operation/CheckBlobExists) using a `HEAD` request for each blob digest.\n\n3. If the blob does not exist, [upload the blob](#operation/CompleteBlobUpload) using a monolithic `PUT` request:\n - First, [initiate the upload](#operation/InitiateBlobUpload) with `POST`.\n - Then [upload and complete](#operation/CompleteBlobUpload) with `PUT`.\n\n **Note**: Alternatively, you can upload the blob in multiple chunks by using `PATCH` requests to send each chunk, followed by a final `PUT` request to complete the upload. This is known as a [chunked upload](#operation/UploadBlobChunk) and is useful for large blobs or when resuming interrupted uploads.\n\n\n4. [Upload the image manifest](#operation/PutImageManifest) using a `PUT` request to associate the config and layers.\n\nThe following bash script example pushes a dummy config blob and manifest to `yourusername/helloworld:latest` on Docker Hub. You can replace `yourusername` with your Docker Hub username and `dckr_pat` with your Docker Hub personal access token.\n\n```bash\n#!/bin/bash\n\nUSERNAME=yourusername\nPASSWORD=dckr_pat\nREPO=yourusername/helloworld\nTAG=latest\nCONFIG=config.json\nMIME_TYPE=application/vnd.docker.container.image.v1+json\n\n# Step 1: Get a bearer token\nTOKEN=$(curl -s -u \"$USERNAME:$PASSWORD\" \\\n\"https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:push,pull\" \\\n| jq -r .token)\n\n# Create a dummy config blob and compute its digest\necho '{\"architecture\":\"amd64\",\"os\":\"linux\",\"config\":{},\"rootfs\":{\"type\":\"layers\",\"diff_ids\":[]}}' > $CONFIG\nDIGEST=\"sha256:$(sha256sum $CONFIG | awk '{print $1}')\"\n\n# Step 2: Check if the blob exists\nSTATUS=$(curl -s -o /dev/null -w \"%{http_code}\" -I \\\n -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/$REPO/blobs/$DIGEST)\n\nif [ \"$STATUS\" != \"200\" ]; then\n # Step 3: Upload blob using monolithic upload\n LOCATION=$(curl -sI -X POST \\\n -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/$REPO/blobs/uploads/ \\\n | grep -i Location | tr -d '\\r' | awk '{print $2}')\n\n curl -s -X PUT \"$LOCATION&digest=$DIGEST\" \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/octet-stream\" \\\n --data-binary @$CONFIG\nfi\n\n# Step 4: Upload the manifest that references the config blob\nMANIFEST=$(cat < **Note**\n>\n> Manifest deletion operations may experience latency and could return a `500 Internal Server Error` during deletion. The system automatically retries the deletion in the background, so the manifest will eventually be removed. You do not need to manually retry the request.\n\nThis section outlines the basic steps to delete an image using the registry API.\n\n1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/).\n2. [Get the manifest](#operation/GetImageManifest) using the image's tag.\n3. Retrieve the `Docker-Content-Digest` header from the manifest response. This digest uniquely identifies the manifest.\n4. [Delete the manifest](#operation/DeleteImageManifest) using a `DELETE` request and the digest.\n\nThe following bash script example deletes the `latest` tag from `yourusername/helloworld` on Docker Hub. Replace `yourusername` with your Docker Hub username and `dckr_pat` with your Docker Hub personal access token.\n\n```bash\n#!/bin/bash\n\nUSERNAME=yourusername\nPASSWORD=dckr_pat\nREPO=yourusername/helloworld\nTAG=latest\n\n# Step 1: Get a bearer token\nTOKEN=$(curl -s -u \"$USERNAME:$PASSWORD\" \\\n \"https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:pull,push,delete\" \\\n | jq -r .token)\n\n# Step 2 and 3: Get the manifest and extract the digest from response headers\nDIGEST=$(curl -sI -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Accept: application/vnd.docker.distribution.manifest.v2+json\" \\\n https://registry-1.docker.io/v2/$REPO/manifests/$TAG \\\n | grep -i Docker-Content-Digest | tr -d '\\r' | awk '{print $2}')\n\necho \"Deleting manifest with digest: $DIGEST\"\n\n# Step 4: Delete the manifest by digest\ncurl -s -X DELETE \\\n -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/$REPO/manifests/$DIGEST\n\necho \"Deleted image: $REPO@$DIGEST\"\n```\n\nThis example deletes the manifest for the `latest` tag. To fully delete all references to an image, ensure no other tags or referrers point to the same manifest digest.\n" - } - ], - "after": [ - { - "name": "overview", - "description": "All endpoints in this API are prefixed by the version and repository name, for example:\n\n```\n/v2//\n```\n\nThis format provides structured access control and URI-based scoping of image operations.\n\nFor example, to interact with the `library/ubuntu` repository, use:\n\n```\n/v2/library/ubuntu/\n```\n\nRepository names must meet these requirements:\n1. Consist of path components matching `[a-z0-9]+(?:[._-][a-z0-9]+)*`\n2. If more than one component, they must be separated by `/`\n3. Full repository name must be fewer than 256 characters\n", - "summary": "Overview", - "kind": "info" - }, - { - "name": "authentication", - "description": "Specifies registry authentication.\n", - "externalDocs": { - "description": "Detailed authentication workflow and token usage", - "url": "https://docs.docker.com/reference/api/registry/auth/" - }, - "summary": "Authentication", - "kind": "info" - }, - { - "name": "Manifests", - "description": "Image manifests are JSON documents that describe an image: its configuration blob, the digests of each layer blob, and metadata such as media‑types and annotations.\n", - "summary": "Manifests", - "kind": "nav" - }, - { - "name": "Blobs", - "description": "Blobs are the binary objects referenced from manifests:\nthe config JSON and one or more compressed layer tarballs.\n", - "summary": "Blobs", - "kind": "nav" - }, - { - "name": "pull", - "description": "Pulling an image involves retrieving the manifest and downloading each of the image's layer blobs. This section outlines the general steps followed by a working example.\n\n1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/).\n2. [Get the image manifest](#operation/GetImageManifest).\n3. If the response in the previous step is a multi-architecture manifest list, you must do the following:\n - Parse the `manifests[]` array to locate the digest for your target platform (e.g., `linux/amd64`).\n - [Get the image manifest](#operation/GetImageManifest) using the located digest.\n4. [Check if the blob exists](#operation/CheckBlobExists) before downloading. The client should send a `HEAD` request for each layer digest.\n5. [Download each layer blob](#operation/GetBlob) using the digest obtained from the manifest. The client should send a `GET` request for each layer digest.\n\nThe following bash script example pulls `library/ubuntu:latest` from Docker Hub.\n\n```bash\n#!/bin/bash\n\n# Step 1: Get a bearer token\nTOKEN=$(curl -s \"https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/ubuntu:pull\" | jq -r .token)\n\n# Step 2: Get the image manifest. In this example, an image manifest list is returned.\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Accept: application/vnd.docker.distribution.manifest.list.v2+json\" \\\n https://registry-1.docker.io/v2/library/ubuntu/manifests/latest \\\n -o manifest-list.json\n\n# Step 3a: Parse the `manifests[]` array to locate the digest for your target platform (e.g., `linux/amd64`).\nIMAGE_MANIFEST_DIGEST=$(jq -r '.manifests[] | select(.platform.architecture == \"amd64\" and .platform.os == \"linux\") | .digest' manifest-list.json)\n\n# Step 3b: Get the platform-specific image manifest\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Accept: application/vnd.docker.distribution.manifest.v2+json\" \\\n https://registry-1.docker.io/v2/library/ubuntu/manifests/$IMAGE_MANIFEST_DIGEST \\\n -o manifest.json\n\n# Step 4: Send a HEAD request to check if the layer blob exists\nDIGEST=$(jq -r '.layers[0].digest' manifest.json)\ncurl -I -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST\n\n# Step 5: Download the layer blob\ncurl -L -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST\n```\n\nThis example pulls the manifest and the first layer for the `ubuntu:latest` image on the `linux/amd64` platform. Repeat steps 4 and 5 for each digest in the `.layers[]` array in the manifest.\n", - "summary": "Pulling Images", - "kind": "info" - }, - { - "name": "push", - "description": "Pushing an image involves uploading any image blobs (such as the config or layers), and then uploading the manifest that references those blobs.\n\nThis section outlines the basic steps to push an image using the registry API.\n\n1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/)\n\n2. [Check if the blob exists](#operation/CheckBlobExists) using a `HEAD` request for each blob digest.\n\n3. If the blob does not exist, [upload the blob](#operation/CompleteBlobUpload) using a monolithic `PUT` request:\n - First, [initiate the upload](#operation/InitiateBlobUpload) with `POST`.\n - Then [upload and complete](#operation/CompleteBlobUpload) with `PUT`.\n\n **Note**: Alternatively, you can upload the blob in multiple chunks by using `PATCH` requests to send each chunk, followed by a final `PUT` request to complete the upload. This is known as a [chunked upload](#operation/UploadBlobChunk) and is useful for large blobs or when resuming interrupted uploads.\n\n\n4. [Upload the image manifest](#operation/PutImageManifest) using a `PUT` request to associate the config and layers.\n\nThe following bash script example pushes a dummy config blob and manifest to `yourusername/helloworld:latest` on Docker Hub. You can replace `yourusername` with your Docker Hub username and `dckr_pat` with your Docker Hub personal access token.\n\n```bash\n#!/bin/bash\n\nUSERNAME=yourusername\nPASSWORD=dckr_pat\nREPO=yourusername/helloworld\nTAG=latest\nCONFIG=config.json\nMIME_TYPE=application/vnd.docker.container.image.v1+json\n\n# Step 1: Get a bearer token\nTOKEN=$(curl -s -u \"$USERNAME:$PASSWORD\" \\\n\"https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:push,pull\" \\\n| jq -r .token)\n\n# Create a dummy config blob and compute its digest\necho '{\"architecture\":\"amd64\",\"os\":\"linux\",\"config\":{},\"rootfs\":{\"type\":\"layers\",\"diff_ids\":[]}}' > $CONFIG\nDIGEST=\"sha256:$(sha256sum $CONFIG | awk '{print $1}')\"\n\n# Step 2: Check if the blob exists\nSTATUS=$(curl -s -o /dev/null -w \"%{http_code}\" -I \\\n -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/$REPO/blobs/$DIGEST)\n\nif [ \"$STATUS\" != \"200\" ]; then\n # Step 3: Upload blob using monolithic upload\n LOCATION=$(curl -sI -X POST \\\n -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/$REPO/blobs/uploads/ \\\n | grep -i Location | tr -d '\\r' | awk '{print $2}')\n\n curl -s -X PUT \"$LOCATION&digest=$DIGEST\" \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/octet-stream\" \\\n --data-binary @$CONFIG\nfi\n\n# Step 4: Upload the manifest that references the config blob\nMANIFEST=$(cat < **Note**\n>\n> Manifest deletion operations may experience latency and could return a `500 Internal Server Error` during deletion. The system automatically retries the deletion in the background, so the manifest will eventually be removed. You do not need to manually retry the request.\n\nThis section outlines the basic steps to delete an image using the registry API.\n\n1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/).\n2. [Get the manifest](#operation/GetImageManifest) using the image's tag.\n3. Retrieve the `Docker-Content-Digest` header from the manifest response. This digest uniquely identifies the manifest.\n4. [Delete the manifest](#operation/DeleteImageManifest) using a `DELETE` request and the digest.\n\nThe following bash script example deletes the `latest` tag from `yourusername/helloworld` on Docker Hub. Replace `yourusername` with your Docker Hub username and `dckr_pat` with your Docker Hub personal access token.\n\n```bash\n#!/bin/bash\n\nUSERNAME=yourusername\nPASSWORD=dckr_pat\nREPO=yourusername/helloworld\nTAG=latest\n\n# Step 1: Get a bearer token\nTOKEN=$(curl -s -u \"$USERNAME:$PASSWORD\" \\\n \"https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:pull,push,delete\" \\\n | jq -r .token)\n\n# Step 2 and 3: Get the manifest and extract the digest from response headers\nDIGEST=$(curl -sI -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Accept: application/vnd.docker.distribution.manifest.v2+json\" \\\n https://registry-1.docker.io/v2/$REPO/manifests/$TAG \\\n | grep -i Docker-Content-Digest | tr -d '\\r' | awk '{print $2}')\n\necho \"Deleting manifest with digest: $DIGEST\"\n\n# Step 4: Delete the manifest by digest\ncurl -s -X DELETE \\\n -H \"Authorization: Bearer $TOKEN\" \\\n https://registry-1.docker.io/v2/$REPO/manifests/$DIGEST\n\necho \"Deleted image: $REPO@$DIGEST\"\n```\n\nThis example deletes the manifest for the `latest` tag. To fully delete all references to an image, ensure no other tags or referrers point to the same manifest digest.\n", - "summary": "Deleting Images", - "kind": "info" - } - ], - "id": "registry-8d93cf25f3e7", - "stage": "editorial-metadata", - "classification": "editorial completion", - "rationale": "Supply conservative operation descriptions and stable IDs; declare primary navigation tags without changing endpoint behavior.", - "evidence": "Existing operation summaries, paths, and tags", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/tags", - "destinationPointer": "/tags" - }, - { - "pointer": "/components", - "beforePresent": false, - "afterPresent": true, - "after": { - "securitySchemes": { - "registryToken": { - "type": "http", - "scheme": "bearer", - "description": "Follow the WWW-Authenticate challenge and obtain a repository-scoped registry token. This is separate from the Hub API token exchange." - } - } - }, - "id": "registry-28462495ac89", - "stage": "registry-version-auth-assumption", - "classification": "provisional assumption", - "rationale": "Use protocol version 2 as provisional info.version and declare challenge-acquired bearer access. Confirm anonymous/public access alternatives and version identity with Hub owners.", - "evidence": "Registry description and content/reference/api/registry/auth.md", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/components" - }, - { - "pointer": "/info/version", - "beforePresent": false, - "afterPresent": true, - "after": "2", - "id": "registry-4d1e2c3e182a", - "stage": "registry-version-auth-assumption", - "classification": "provisional assumption", - "rationale": "Use protocol version 2 as provisional info.version and declare challenge-acquired bearer access. Confirm anonymous/public access alternatives and version identity with Hub owners.", - "evidence": "Registry description and content/reference/api/registry/auth.md", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/info/version" - }, - { - "pointer": "/security", - "beforePresent": false, - "afterPresent": true, - "after": [ - { - "registryToken": [] - } - ], - "id": "registry-ccc57ca992b3", - "stage": "registry-version-auth-assumption", - "classification": "provisional assumption", - "rationale": "Use protocol version 2 as provisional info.version and declare challenge-acquired bearer access. Confirm anonymous/public access alternatives and version identity with Hub owners.", - "evidence": "Registry description and content/reference/api/registry/auth.md", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": null, - "destinationPointer": "/security" - }, - { - "pointer": "/paths/~1v2~1{name}~1blobs~1{digest}/head/responses/200/content", - "beforePresent": true, - "afterPresent": false, - "before": { - "application/json": { - "examples": { - "blob-check-request": { - "summary": "Sample request", - "value": { - "method": "HEAD", - "url": "/v2/library/ubuntu/blobs/sha256:abc123def4567890...", - "headers": { - "Authorization": "Bearer ", - "Accept": "*/*" - } - } - }, - "blob-check-response": { - "summary": "Sample 200 response headers", - "value": { - "status": "200 OK", - "headers": { - "Docker-Content-Digest": "sha256:abc123def4567890...", - "Content-Length": 32654, - "Content-Type": "application/octet-stream" - } - } - } - } - } - }, - "id": "registry-585e6c6be138", - "stage": "head-response-bodies", - "classification": "evidence-backed correction", - "rationale": "HEAD responses transfer headers without a response body. Preserve headers and status codes; remove declared content from HEAD responses.", - "evidence": "RFC 9110 section 9.3.2", - "owner": "docker/docs (product authority to confirm)", - "sourcePointer": "/paths/~1v2~1{name}~1blobs~1{digest}/head/responses/200/content", - "destinationPointer": null - } - ] -} diff --git a/hack/api-docs/adoption/registry.patch b/hack/api-docs/adoption/registry.patch deleted file mode 100644 index 6335a9c0a28a..000000000000 --- a/hack/api-docs/adoption/registry.patch +++ /dev/null @@ -1,606 +0,0 @@ ---- original/registry.yaml -+++ converted/registry.yaml -@@ -1,4 +1,4 @@ --openapi: 3.0.3 -+openapi: 3.2.0 - info: - title: Supported registry API for Docker Hub - description: | -@@ -11,14 +11,13 @@ - It focuses on pulling, pushing, and deleting images. It does not cover the full OCI Distribution Specification. - - For the complete OCI specification, see [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec). -+ version: "2" - servers: - - description: Docker Hub registry API - x-audience: public - url: https://registry-1.docker.io -- - tags: - - name: overview -- x-displayName: Overview - description: | - All endpoints in this API are prefixed by the version and repository name, for example: - -@@ -38,29 +37,28 @@ - 1. Consist of path components matching `[a-z0-9]+(?:[._-][a-z0-9]+)*` - 2. If more than one component, they must be separated by `/` - 3. Full repository name must be fewer than 256 characters -- -- -+ summary: Overview -+ kind: info - - name: authentication -- x-displayName: Authentication - description: | - Specifies registry authentication. - externalDocs: - description: Detailed authentication workflow and token usage - url: https://docs.docker.com/reference/api/registry/auth/ -- -+ summary: Authentication -+ kind: info - - name: Manifests -- x-displayName: Manifests - description: | - Image manifests are JSON documents that describe an image: its configuration blob, the digests of each layer blob, and metadata such as media‑types and annotations. -- -+ summary: Manifests -+ kind: nav - - name: Blobs -- x-displayName: Blobs - description: | - Blobs are the binary objects referenced from manifests: - the config JSON and one or more compressed layer tarballs. -- -+ summary: Blobs -+ kind: nav - - name: pull -- x-displayName: Pulling Images - description: | - Pulling an image involves retrieving the manifest and downloading each of the image's layer blobs. This section outlines the general steps followed by a working example. - -@@ -79,94 +77,93 @@ - - # Step 1: Get a bearer token - TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/ubuntu:pull" | jq -r .token) -- -+ - # Step 2: Get the image manifest. In this example, an image manifest list is returned. - curl -s -H "Authorization: Bearer $TOKEN" \ - -H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" \ - https://registry-1.docker.io/v2/library/ubuntu/manifests/latest \ - -o manifest-list.json -- -+ - # Step 3a: Parse the `manifests[]` array to locate the digest for your target platform (e.g., `linux/amd64`). - IMAGE_MANIFEST_DIGEST=$(jq -r '.manifests[] | select(.platform.architecture == "amd64" and .platform.os == "linux") | .digest' manifest-list.json) -- -+ - # Step 3b: Get the platform-specific image manifest - curl -s -H "Authorization: Bearer $TOKEN" \ - -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ - https://registry-1.docker.io/v2/library/ubuntu/manifests/$IMAGE_MANIFEST_DIGEST \ - -o manifest.json -- -+ - # Step 4: Send a HEAD request to check if the layer blob exists - DIGEST=$(jq -r '.layers[0].digest' manifest.json) - curl -I -H "Authorization: Bearer $TOKEN" \ - https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST -- -+ - # Step 5: Download the layer blob - curl -L -H "Authorization: Bearer $TOKEN" \ - https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST - ``` -- -- This example pulls the manifest and the first layer for the `ubuntu:latest` image on the `linux/amd64` platform. Repeat steps 4 and 5 for each digest in the `.layers[]` array in the manifest. -- - -+ This example pulls the manifest and the first layer for the `ubuntu:latest` image on the `linux/amd64` platform. Repeat steps 4 and 5 for each digest in the `.layers[]` array in the manifest. -+ summary: Pulling Images -+ kind: info - - name: push -- x-displayName: Pushing Images - description: | - Pushing an image involves uploading any image blobs (such as the config or layers), and then uploading the manifest that references those blobs. -- -+ - This section outlines the basic steps to push an image using the registry API. -- -+ - 1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/) -- -+ - 2. [Check if the blob exists](#operation/CheckBlobExists) using a `HEAD` request for each blob digest. -- -+ - 3. If the blob does not exist, [upload the blob](#operation/CompleteBlobUpload) using a monolithic `PUT` request: - - First, [initiate the upload](#operation/InitiateBlobUpload) with `POST`. - - Then [upload and complete](#operation/CompleteBlobUpload) with `PUT`. - - **Note**: Alternatively, you can upload the blob in multiple chunks by using `PATCH` requests to send each chunk, followed by a final `PUT` request to complete the upload. This is known as a [chunked upload](#operation/UploadBlobChunk) and is useful for large blobs or when resuming interrupted uploads. - -- -+ - 4. [Upload the image manifest](#operation/PutImageManifest) using a `PUT` request to associate the config and layers. -- -+ - The following bash script example pushes a dummy config blob and manifest to `yourusername/helloworld:latest` on Docker Hub. You can replace `yourusername` with your Docker Hub username and `dckr_pat` with your Docker Hub personal access token. -- -+ - ```bash - #!/bin/bash -- -+ - USERNAME=yourusername - PASSWORD=dckr_pat - REPO=yourusername/helloworld - TAG=latest - CONFIG=config.json - MIME_TYPE=application/vnd.docker.container.image.v1+json -- -+ - # Step 1: Get a bearer token - TOKEN=$(curl -s -u "$USERNAME:$PASSWORD" \ - "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:push,pull" \ - | jq -r .token) -- -+ - # Create a dummy config blob and compute its digest - echo '{"architecture":"amd64","os":"linux","config":{},"rootfs":{"type":"layers","diff_ids":[]}}' > $CONFIG - DIGEST="sha256:$(sha256sum $CONFIG | awk '{print $1}')" -- -+ - # Step 2: Check if the blob exists - STATUS=$(curl -s -o /dev/null -w "%{http_code}" -I \ - -H "Authorization: Bearer $TOKEN" \ - https://registry-1.docker.io/v2/$REPO/blobs/$DIGEST) -- -+ - if [ "$STATUS" != "200" ]; then - # Step 3: Upload blob using monolithic upload - LOCATION=$(curl -sI -X POST \ - -H "Authorization: Bearer $TOKEN" \ - https://registry-1.docker.io/v2/$REPO/blobs/uploads/ \ - | grep -i Location | tr -d '\r' | awk '{print $2}') -- -+ - curl -s -X PUT "$LOCATION&digest=$DIGEST" \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/octet-stream" \ - --data-binary @$CONFIG - fi -- -+ - # Step 4: Upload the manifest that references the config blob - MANIFEST=$(cat <` header. -- - x-codeSamples: - - lang: Bash - label: cURL -@@ -300,7 +296,7 @@ - required: false - description: | - Media type(s) the client supports for the manifest. -- -+ - The registry supports the following media types: - - application/vnd.docker.distribution.manifest.v2+json - - application/vnd.docker.distribution.manifest.list.v2+json -@@ -308,7 +304,6 @@ - - application/vnd.oci.image.index.v1+json - schema: - type: string -- - responses: - "200": - description: Manifest fetched successfully. -@@ -367,28 +362,19 @@ - docker-manifest: - summary: Docker image manifest (schema v2) - value: -- { -- "schemaVersion": 2, -- "mediaType": "application/vnd.docker.distribution.manifest.v2+json", -- "config": { -- "mediaType": "application/vnd.docker.container.image.v1+json", -- "size": 7023, -- "digest": "sha256:123456abcdef..." -- }, -- "layers": [ -- { -- "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", -- "size": 32654, -- "digest": "sha256:abcdef123456..." -- }, -- { -- "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", -- "size": 16724, -- "digest": "sha256:7890abcdef12..." -- } -- ] -- } -- -+ schemaVersion: 2 -+ mediaType: application/vnd.docker.distribution.manifest.v2+json -+ config: -+ mediaType: application/vnd.docker.container.image.v1+json -+ size: 7023 -+ digest: sha256:123456abcdef... -+ layers: -+ - mediaType: application/vnd.docker.image.rootfs.diff.tar.gzip -+ size: 32654 -+ digest: sha256:abcdef123456... -+ - mediaType: application/vnd.docker.image.rootfs.diff.tar.gzip -+ size: 16724 -+ digest: sha256:7890abcdef12... - "400": - description: Invalid name or reference. - "401": -@@ -399,8 +385,6 @@ - description: Repository or manifest not found. - "429": - description: Too many requests. -- -- - put: - tags: - - Manifests -@@ -459,7 +443,6 @@ - schema: - type: string - example: application/vnd.docker.distribution.manifest.v2+json -- - requestBody: - required: true - content: -@@ -512,28 +495,20 @@ - digest: - type: string - example: sha256:abcdef123456... -- - examples: - sample-manifest: - summary: Sample Docker image manifest (schema v2) - value: -- { -- "schemaVersion": 2, -- "mediaType": "application/vnd.docker.distribution.manifest.v2+json", -- "config": { -- "mediaType": "application/vnd.docker.container.image.v1+json", -- "size": 7023, -- "digest": "sha256:123456abcdef..." -- }, -- "layers": [ -- { -- "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", -- "size": 32654, -- "digest": "sha256:abcdef123456..." -- } -- ] -- } -- -+ schemaVersion: 2 -+ mediaType: application/vnd.docker.distribution.manifest.v2+json -+ config: -+ mediaType: application/vnd.docker.container.image.v1+json -+ size: 7023 -+ digest: sha256:123456abcdef... -+ layers: -+ - mediaType: application/vnd.docker.image.rootfs.diff.tar.gzip -+ size: 32654 -+ digest: sha256:abcdef123456... - responses: - "201": - description: Manifest created successfully. -@@ -578,7 +553,6 @@ - - Determining the digest or size of a manifest before downloading or deleting - - This endpoint requires authentication with pull scope. -- - parameters: - - name: name - in: path -@@ -642,12 +616,12 @@ - schema: - type: string - example: application/vnd.docker.distribution.manifest.v2+json -- "404": -- description: Manifest not found. - "401": - description: Authentication required. - "403": - description: Access denied. -+ "404": -+ description: Manifest not found. - "429": - description: Too many requests. - delete: -@@ -733,7 +707,6 @@ - curl -i -X POST \ - -H "Authorization: Bearer $TOKEN" \ - https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/ -- - - lang: Bash - label: cURL (Cross-Repository Blob Mount) - source: | -@@ -741,7 +714,6 @@ - curl -i -X POST \ - -H "Authorization: Bearer $TOKEN" \ - "https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/?mount=sha256:abc123def456...&from=library/busybox" -- - parameters: - - name: name - in: path -@@ -770,7 +742,6 @@ - schema: - type: string - description: Bearer token for authentication with `push` scope -- - responses: - "201": - description: Blob successfully mounted from another repository. -@@ -865,7 +836,6 @@ - schema: - type: string - example: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6... -- - responses: - "200": - description: Blob exists -@@ -885,32 +855,12 @@ - schema: - type: string - example: application/octet-stream -- content: -- application/json: -- examples: -- blob-check-request: -- summary: Sample request -- value: -- method: HEAD -- url: /v2/library/ubuntu/blobs/sha256:abc123def4567890... -- headers: -- Authorization: Bearer -- Accept: '*/*' -- blob-check-response: -- summary: Sample 200 response headers -- value: -- status: 200 OK -- headers: -- Docker-Content-Digest: sha256:abc123def4567890... -- Content-Length: 32654 -- Content-Type: application/octet-stream -- -- "404": -- description: Blob not found - "401": - description: Authentication required - "403": - description: Access denied -+ "404": -+ description: Blob not found - "429": - description: Too many requests - get: -@@ -957,7 +907,6 @@ - type: string - description: Bearer token with pull scope - example: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6... -- - responses: - "200": - description: Blob content returned directly -@@ -985,8 +934,7 @@ - examples: - small-layer: - summary: Example binary blob (gzipped tar layer) -- value: "" -- -+ value: - "307": - description: Temporary redirect to blob location - headers: -@@ -1031,7 +979,7 @@ - in: path - required: true - description: Repository Name -- example : library/ubuntu -+ example: library/ubuntu - schema: - type: string - - name: uuid -@@ -1047,7 +995,6 @@ - schema: - type: string - example: Bearer eyJhbGciOi... -- - responses: - "204": - description: Upload in progress. No body is returned. -@@ -1075,7 +1022,6 @@ - description: Upload session not found - "429": - description: Too many requests -- - put: - tags: - - Blobs -@@ -1089,7 +1035,6 @@ - This endpoint supports: - - Monolithic uploads (upload entire blob in this request) - - Finalizing chunked uploads (last chunk plus `digest`) -- - x-codeSamples: - - lang: Bash - label: cURL -@@ -1100,8 +1045,6 @@ - -H "Content-Type: application/octet-stream" \ - --data-binary @layer.tar.gz \ - "https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123?digest=sha256:abcd1234..." -- -- - parameters: - - name: name - in: path -@@ -1130,7 +1073,6 @@ - schema: - type: string - example: Bearer eyJhbGciOi... -- - requestBody: - required: false - content: -@@ -1141,8 +1083,7 @@ - examples: - layer-upload: - summary: Layer tarball blob -- value: "" -- -+ value: - responses: - "201": - description: Upload completed successfully -@@ -1174,7 +1115,6 @@ - description: Requested range not satisfiable (if used in chunked mode) - "429": - description: Too many requests -- - patch: - tags: - - Blobs -@@ -1229,7 +1169,6 @@ - type: string - example: bytes 0-65535 - description: Optional. Byte range of the chunk being sent -- - requestBody: - required: true - content: -@@ -1240,8 +1179,7 @@ - examples: - chunk-0: - summary: Upload chunk 0 of a blob -- value: "" -- -+ value: - responses: - "202": - description: Chunk accepted and stored -@@ -1288,7 +1226,6 @@ - - The client wants to clean up unused upload sessions - - After cancellation, the UUID is no longer valid and a new `POST` must be issued to restart the upload. -- - x-codeSamples: - - lang: Bash - label: cURL -@@ -1297,7 +1234,6 @@ - curl -X DELETE \ - -H "Authorization: Bearer $TOKEN" \ - https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123` -- - parameters: - - name: name - in: path -@@ -1319,7 +1255,6 @@ - schema: - type: string - example: Bearer eyJhbGciOi... -- - responses: - "204": - description: Upload session cancelled successfully. No body is returned. -@@ -1337,8 +1272,6 @@ - description: Upload session not found - "429": - description: Too many requests -- -- - x-tagGroups: - - name: General - tags: -@@ -1351,3 +1284,12 @@ - tags: - - Manifests - - Blobs -+jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base -+components: -+ securitySchemes: -+ registryToken: -+ type: http -+ scheme: bearer -+ description: Follow the WWW-Authenticate challenge and obtain a repository-scoped registry token. This is separate from the Hub API token exchange. -+security: -+ - registryToken: [] diff --git a/hack/api-docs/adoption/source-lock.json b/hack/api-docs/adoption/source-lock.json deleted file mode 100644 index 239f8b20bc97..000000000000 --- a/hack/api-docs/adoption/source-lock.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "revision": "371255294cf8db2ee20206bf5cc9c165a3a1ea16", - "tools": { - "swagger2openapi": "7.0.8", - "yaml": "2.8.1", - "libopenapi": "0.38.7", - "vacuum": "0.30.3", - "jsonschema": "6.0.3", - "oasdiff": "1.31.0" - }, - "sources": [ - { - "id": "hub", - "product": "hub", - "title": "Docker Hub", - "source": "content/reference/api/hub/latest.yaml", - "owner": "docker/docs (product authority to confirm)", - "manual": "/manuals/docker-hub/", - "connection": "hosted", - "auth": "Use the documented Hub token exchange. SCIM operations use a separate provisioning token.", - "guides": [ - "/manuals/security/provisioning/scim/provision-scim.md" - ], - "sha256": "aeefa9b62b10d70f9e28e9508d5a4c1361e0a541e209ff0af9ed2544b0cb415e" - }, - { - "id": "dvp", - "product": "dvp", - "title": "Publisher analytics", - "source": "content/reference/api/dvp/latest.yaml", - "owner": "docker/docs (product authority to confirm)", - "manual": "/manuals/docker-hub/repos/manage/trusted-content/insights-analytics.md", - "connection": "hosted", - "auth": "Analytics calls use a bearer token. The copied source retains the legacy login flow pending product confirmation.", - "guides": [], - "sha256": "4aeacaaa1237609c3dd9cec43f9807a229ac98a0e9b837f291c02df3cf89172a" - }, - { - "id": "registry", - "product": "registry", - "title": "Registry", - "source": "content/reference/api/registry/latest.yaml", - "owner": "docker/docs (product authority to confirm)", - "manual": "/manuals/docker-hub/repos/", - "connection": "hosted", - "auth": "Follow the WWW-Authenticate challenge and obtain a repository-scoped registry token. This is separate from the Hub API token exchange.", - "guides": [ - "/reference/api/registry/auth.md" - ], - "sha256": "229198e078ee30400c0359311f5baaf23a1f80563a1c2e82834f17f2db0d9fd1" - } - ] -} From 0f626efb38889eb767a51591e07d0954d93261c9 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 9 Sep 2026 12:29:30 +0000 Subject: [PATCH 06/13] docs: simplify API aliases and remove legacy fragment redirects --- assets/api-reference/reference.js | 16 ------- hack/api-docs/README.md | 2 +- hack/api-docs/browser-checks.mjs | 10 ++-- hack/api-docs/verify-output.mjs | 11 ----- .../api-reference/legacy-fragments.html | 47 ------------------- layouts/alias.html | 31 ------------ layouts/api-docs.html | 1 - 7 files changed, 6 insertions(+), 112 deletions(-) delete mode 100644 layouts/_partials/api-reference/legacy-fragments.html delete mode 100644 layouts/alias.html diff --git a/assets/api-reference/reference.js b/assets/api-reference/reference.js index 244fff83f8d8..7c51e1843235 100644 --- a/assets/api-reference/reference.js +++ b/assets/api-reference/reference.js @@ -47,19 +47,3 @@ document.querySelectorAll("[data-api-media-select]").forEach((select) => }); }), ); - -// Resolve historical single-page fragments using generated, same-origin links. -function resolveLegacyFragment() { - let fragment; - try { - fragment = decodeURIComponent(location.hash.slice(1)); - } catch { - return; - } - const target = document.getElementById(fragment); - if (target?.hasAttribute("data-api-legacy-fragment")) { - location.replace(target.href); - } -} -resolveLegacyFragment(); -window.addEventListener("hashchange", resolveLegacyFragment); diff --git a/hack/api-docs/README.md b/hack/api-docs/README.md index 8190179f52f4..a9d004987b96 100644 --- a/hack/api-docs/README.md +++ b/hack/api-docs/README.md @@ -69,7 +69,7 @@ security overrides, server and parameter precedence, and request generation. `verify-output.mjs` checks all 181 generated HTML/Markdown pairs and retention of Engine v1.40–v1.56 in ReDoc, unchanged Governance rendering, and byte-identical published specifications. `browser-checks.mjs` exports a Playwright check for -navigation, legacy fragments, filtering, requests, and narrow screens. +navigation, page aliases, filtering, requests, and narrow screens. Callbacks and webhook navigation are unsupported and fail validation. Request examples are POSIX shell templates; they do not make service calls. Specification diff --git a/hack/api-docs/browser-checks.mjs b/hack/api-docs/browser-checks.mjs index 7f3b846521f0..a5eb05d5b614 100644 --- a/hack/api-docs/browser-checks.mjs +++ b/hack/api-docs/browser-checks.mjs @@ -23,13 +23,13 @@ export default async function verify(page, base = "http://localhost:1314") { ); const first = page.locator("[data-api-filter-item]").first(); const operationURL = await first.getAttribute("href"); - const operationID = operationURL.split("/").filter(Boolean).at(-1); - await page.goto(base + "/reference/api/hub/dvp/#operation/" + operationID); - await page.waitForURL("**" + operationURL); + await page.goto(base + "/reference/api/hub/dvp/"); + await page.waitForURL("**/reference/api/dvp/latest/"); assert( - page.url().endsWith(operationURL), - "DVP alias preserves legacy operation fragment", + page.url().endsWith("/reference/api/dvp/latest/"), + "DVP alias reaches overview", ); + await page.goto(base + operationURL); await page.context().grantPermissions(["clipboard-read", "clipboard-write"]); const copy = page.locator("[data-api-copy]"); await copy.focus(); diff --git a/hack/api-docs/verify-output.mjs b/hack/api-docs/verify-output.mjs index 43cfae89a5b4..97ac5fe7d9ac 100644 --- a/hack/api-docs/verify-output.mjs +++ b/hack/api-docs/verify-output.mjs @@ -129,17 +129,6 @@ for (let minor = 40; minor <= 56; minor++) { if (!html.includes(" - Links from the previous reference -
    - {{ range .operations }} - {{ $op := . }} - {{ range slice (printf "operation/%s" .id) (printf "operation-%s" .id) }} -
  • - {{ $op.summary }} -
  • - {{ end }} - {{ range .tags }} -
  • - {{ $op.summary }} -
  • - {{ end }} - {{ end }} - {{ range .schemas }} - {{ $schema := . }} - {{ range slice (printf "schema-%s" .name) (printf "schema-%s" (.name | urlize)) | uniq }} -
  • - {{ $schema.name }} -
  • - {{ end }} - {{ end }} - {{ $api := . }} - {{ range .tags }} -
  • - {{ .summary }} -
  • - {{ end }} -
- diff --git a/layouts/alias.html b/layouts/alias.html deleted file mode 100644 index 644449552ce0..000000000000 --- a/layouts/alias.html +++ /dev/null @@ -1,31 +0,0 @@ -{{ if eq .Page.Params.apiID "dvp" }} - - - - - Redirecting - - - - - - Continue to the documentation - - -{{ else }} - - - - {{ .Permalink }} - - - - - -{{ end }} diff --git a/layouts/api-docs.html b/layouts/api-docs.html index 8415d179c350..572c36f9df87 100644 --- a/layouts/api-docs.html +++ b/layouts/api-docs.html @@ -165,7 +165,6 @@

Schemas

{{ end }} - {{ partial "api-reference/legacy-fragments.html" $api }} {{ else if eq .Params.view "operation" }} {{ range $api.operations }} {{ if eq .id $.Params.operationID }} From 62bb9b09551063ee4988b7d1eb8c872c1c8b925c Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 9 Sep 2026 12:36:58 +0000 Subject: [PATCH 07/13] docs: organize API processor inputs and validation resources --- hack/api-docs/README.md | 16 ++++++++++-- hack/api-docs/main.go | 25 +++++++++++-------- hack/api-docs/main_test.go | 6 ++--- hack/api-docs/model.go | 2 +- hack/api-docs/run.sh | 8 +++--- hack/api-docs/{catalog.json => sources.json} | 6 ----- .../{ => validation}/dialects/lock.json | 0 .../dialects/oas-dialect.json | 0 .../dialects/oas-document.json | 0 .../dialects/oas-vocabulary.json | 0 .../{ => validation}/known-issues.json | 0 .../{vacuum.yaml => validation/rules.yaml} | 0 layouts/api-docs.html | 13 ++++++++-- layouts/api-docs.markdown.md | 8 ++++-- 14 files changed, 55 insertions(+), 29 deletions(-) rename hack/api-docs/{catalog.json => sources.json} (72%) rename hack/api-docs/{ => validation}/dialects/lock.json (100%) rename hack/api-docs/{ => validation}/dialects/oas-dialect.json (100%) rename hack/api-docs/{ => validation}/dialects/oas-document.json (100%) rename hack/api-docs/{ => validation}/dialects/oas-vocabulary.json (100%) rename hack/api-docs/{ => validation}/known-issues.json (100%) rename hack/api-docs/{vacuum.yaml => validation/rules.yaml} (100%) diff --git a/hack/api-docs/README.md b/hack/api-docs/README.md index a9d004987b96..37f116f98f61 100644 --- a/hack/api-docs/README.md +++ b/hack/api-docs/README.md @@ -19,12 +19,24 @@ $ hugo server For a static build with HTML/Markdown checks, run `./hack/api-docs/run.sh build`. To serve that build on port 1314, run `./hack/api-docs/run.sh serve`. Set `DOCS_URL` and `DOCS_PORT` when using another -address. Run generation again after changing a specification or catalog entry. +address. Run generation again after changing a specification or source manifest entry. Docker builds and Netlify deploy previews run generation before Hugo. Generated data, validation reports, binaries, and local builds go under `tmp/api-reference/`. Hugo reports an error if the generated data is absent. +## Processor inputs + +`sources.json` registers input specifications and their product/manual +relationships. Both generation and the validation wrapper use this manifest. +Hugo reads the generated presentation data, rather than this file. Authentication +descriptions come from the specifications and linked guides. + +`validation/` contains the Vacuum rules, known-issue baseline, and locked official +schema resources. `testdata/` contains validation fixtures. The presentation model +version and supported dialect are defined by the processor, not configurable +manifest fields. + ## Pipeline 1. Parse the authoritative YAML with `libopenapi` and preserve source values and @@ -51,7 +63,7 @@ $ ./hack/api-docs/run.sh check ``` Generation explicitly uses `--allow-known-issues`. The checked-in -`known-issues.json` records 289 inherited issues: 268 for Hub, 17 for DVP, and +`validation/known-issues.json` records 289 inherited issues: 268 for Hub, 17 for DVP, and four for Registry. Entries match the entire source digest, diagnostic digest, rule, and source pointer. Parse failures, unresolved references, and unsupported features cannot be waived. Unrecorded diagnostics fail the build. diff --git a/hack/api-docs/main.go b/hack/api-docs/main.go index fd4abe32cbf8..98b5a2e70c8f 100644 --- a/hack/api-docs/main.go +++ b/hack/api-docs/main.go @@ -110,7 +110,6 @@ type Source struct { Owner string `json:"owner"` Manual string `json:"manual"` Connection string `json:"connection"` - Auth string `json:"auth"` Guides []string `json:"guides"` } type Registry struct{ resources map[string]any } @@ -689,10 +688,10 @@ func main() { } func run() error { if len(os.Args) < 3 { - return errors.New("usage: api-docs check|generate|inspect ROOT [--allow-known-issues]") + return errors.New("usage: api-docs check|generate|inspect|sources ROOT [--allow-known-issues]") } command := os.Args[1] - if command != "check" && command != "generate" && command != "inspect" { + if command != "check" && command != "generate" && command != "inspect" && command != "sources" { return fmt.Errorf("unknown command: %s", command) } if len(os.Args) > 4 || (len(os.Args) == 4 && os.Args[3] != "--allow-known-issues") { @@ -700,27 +699,33 @@ func run() error { } root, _ := filepath.Abs(os.Args[2]) dir := filepath.Join(root, "hack/api-docs") - meta := filepath.Join(dir, "dialects") - catalogRaw, e := os.ReadFile(filepath.Join(dir, "catalog.json")) + meta := filepath.Join(dir, "validation", "dialects") + manifestRaw, e := os.ReadFile(filepath.Join(dir, "sources.json")) if e != nil { return e } - var catalog struct { + var manifest struct { APIs []Source `json:"apis"` LegacyAPIs []Object `json:"legacyAPIs"` } - if e = json.Unmarshal(catalogRaw, &catalog); e != nil { + if e = json.Unmarshal(manifestRaw, &manifest); e != nil { return e } + if command == "sources" { + for _, src := range manifest.APIs { + fmt.Printf("%s\t%s\n", src.ID, src.Source) + } + return nil + } allowKnown := len(os.Args) > 3 && os.Args[3] == "--allow-known-issues" - exceptions, e := readJSON(filepath.Join(dir, "known-issues.json")) + exceptions, e := readJSON(filepath.Join(dir, "validation", "known-issues.json")) if e != nil { return e } reports := []any{} models := []any{} blocking := 0 - for _, src := range catalog.APIs { + for _, src := range manifest.APIs { d, e := loadDocument(filepath.Join(root, src.Source), meta) if e != nil { return fmt.Errorf("%s: %w", src.ID, e) @@ -756,7 +761,7 @@ func run() error { return fmt.Errorf("%d blocking diagnostics; see tmp/api-reference/validation.json", blocking) } if command == "generate" { - if e = writeJSON(filepath.Join(out, "data/api-reference.json"), Object{"modelVersion": 1, "apis": models, "legacyAPIs": catalog.LegacyAPIs}); e != nil { + if e = writeJSON(filepath.Join(out, "data/api-reference.json"), Object{"modelVersion": 1, "apis": models, "legacyAPIs": manifest.LegacyAPIs}); e != nil { return e } } diff --git a/hack/api-docs/main_test.go b/hack/api-docs/main_test.go index ca4719b6d46f..3bfd06857fe3 100644 --- a/hack/api-docs/main_test.go +++ b/hack/api-docs/main_test.go @@ -11,7 +11,7 @@ import ( func fixture(t *testing.T, name string) *Document { t.Helper() - d, e := loadDocument(filepath.Join("testdata", name), "dialects") + d, e := loadDocument(filepath.Join("testdata", name), "validation/dialects") if e != nil { t.Fatal(e) } @@ -72,7 +72,7 @@ func TestNegativeFixtures(t *testing.T) { } for _, name := range []string{"duplicate-key.yaml", "invalid-stream-ref.yaml"} { t.Run(name, func(t *testing.T) { - d, e := loadDocument(filepath.Join("testdata", name), "dialects") + d, e := loadDocument(filepath.Join("testdata", name), "validation/dialects") if e == nil { d.validate("") for _, x := range d.Diagnostics { @@ -157,7 +157,7 @@ func TestFalseSchemaAndExamplePreserved(t *testing.T) { } event, _ := os.ReadFile("testdata/schemas/event.yaml") os.WriteFile(filepath.Join(tmp, "schemas/event.yaml"), event, 0600) - d, e := loadDocument(filepath.Join(tmp, "spec.yaml"), "dialects") + d, e := loadDocument(filepath.Join(tmp, "spec.yaml"), "validation/dialects") if e != nil { t.Fatal(e) } diff --git a/hack/api-docs/model.go b/hack/api-docs/model.go index 313ecd0afca0..4ea52b6ad1d1 100644 --- a/hack/api-docs/model.go +++ b/hack/api-docs/model.go @@ -39,7 +39,7 @@ func (d *Document) model() Object { op["references"] = refs(op["raw"], schemaURLs) op["requestSchema"] = firstRequestSchema(op) } - return Object{"id": d.Source.ID, "product": d.Source.Product, "title": d.Source.Title, "version": obj(d.Root["info"])["version"], "description": obj(d.Root["info"])["description"], "url": route(d.Source.ID), "manual": d.Source.Manual, "guides": d.Source.Guides, "connection": d.Source.Connection, "auth": d.Source.Auth, "servers": d.Root["servers"], "securitySchemes": obj(d.Root["components"])["securitySchemes"], "tags": d.Root["tags"], "operations": ops, "schemas": schemas, "schemaURLs": schemaURLs, "digest": d.Digest, "owner": d.Source.Owner, "source": d.Source.Source, "sourceURL": "/" + strings.TrimPrefix(d.Source.Source, "content/"), "diagnostics": d.Diagnostics, "schemaCount": d.SchemaCount, "exampleCount": d.ExampleCount} + return Object{"id": d.Source.ID, "product": d.Source.Product, "title": d.Source.Title, "version": obj(d.Root["info"])["version"], "description": obj(d.Root["info"])["description"], "url": route(d.Source.ID), "manual": d.Source.Manual, "guides": d.Source.Guides, "connection": d.Source.Connection, "servers": d.Root["servers"], "securitySchemes": obj(d.Root["components"])["securitySchemes"], "tags": d.Root["tags"], "operations": ops, "schemas": schemas, "schemaURLs": schemaURLs, "digest": d.Digest, "owner": d.Source.Owner, "source": d.Source.Source, "sourceURL": "/" + strings.TrimPrefix(d.Source.Source, "content/"), "diagnostics": d.Diagnostics, "schemaCount": d.SchemaCount, "exampleCount": d.ExampleCount} } func refs(v any, urls Object) []any { found := map[string]bool{} diff --git a/hack/api-docs/run.sh b/hack/api-docs/run.sh index 72a009c8952c..b65fd477cdd4 100755 --- a/hack/api-docs/run.sh +++ b/hack/api-docs/run.sh @@ -13,11 +13,13 @@ bootstrap() { fi } policy() { - for api in hub dvp registry; do - "$BIN/vacuum-v0.30.3" lint --no-update-check --remote=false --ruleset hack/api-docs/vacuum.yaml --fail-severity error --min-score 0 --no-banner --no-style --details "content/reference/api/$api/latest.yaml" > "tmp/api-reference/reports/$api-vacuum.txt" 2>&1 || { + local sources + sources=$("$BIN/api-docs" sources "$ROOT") + while IFS=$'\t' read -r api source; do + "$BIN/vacuum-v0.30.3" lint --no-update-check --remote=false --ruleset hack/api-docs/validation/rules.yaml --fail-severity error --min-score 0 --no-banner --no-style --details "$source" > "tmp/api-reference/reports/$api-vacuum.txt" 2>&1 || { cat "tmp/api-reference/reports/$api-vacuum.txt"; return 1; } - done + done <<< "$sources" } generate() { bootstrap diff --git a/hack/api-docs/catalog.json b/hack/api-docs/sources.json similarity index 72% rename from hack/api-docs/catalog.json rename to hack/api-docs/sources.json index 0623cc62a5e6..d10f149e096d 100644 --- a/hack/api-docs/catalog.json +++ b/hack/api-docs/sources.json @@ -1,7 +1,4 @@ { - "modelVersion": 1, - "profileVersion": "docker-docs-1", - "dialect": "https://spec.openapis.org/oas/3.1/dialect/base", "apis": [ { "id": "hub", @@ -11,7 +8,6 @@ "owner": "docker/docs", "manual": "/manuals/docker-hub/", "connection": "hosted", - "auth": "Use the documented Hub token exchange. SCIM operations use a separate provisioning token.", "guides": ["/manuals/security/provisioning/scim/provision-scim.md"] }, { @@ -22,7 +18,6 @@ "owner": "docker/docs", "manual": "/manuals/docker-hub/repos/manage/trusted-content/insights-analytics.md", "connection": "hosted", - "auth": "Analytics calls use a bearer token. The authentication operations use the Docker Hub server shown in their reference.", "guides": [] }, { @@ -33,7 +28,6 @@ "owner": "docker/docs", "manual": "/manuals/docker-hub/repos/", "connection": "hosted", - "auth": "Follow the WWW-Authenticate challenge and obtain a repository-scoped registry token. This is separate from the Hub API token exchange.", "guides": ["/reference/api/registry/auth.md"] } ], diff --git a/hack/api-docs/dialects/lock.json b/hack/api-docs/validation/dialects/lock.json similarity index 100% rename from hack/api-docs/dialects/lock.json rename to hack/api-docs/validation/dialects/lock.json diff --git a/hack/api-docs/dialects/oas-dialect.json b/hack/api-docs/validation/dialects/oas-dialect.json similarity index 100% rename from hack/api-docs/dialects/oas-dialect.json rename to hack/api-docs/validation/dialects/oas-dialect.json diff --git a/hack/api-docs/dialects/oas-document.json b/hack/api-docs/validation/dialects/oas-document.json similarity index 100% rename from hack/api-docs/dialects/oas-document.json rename to hack/api-docs/validation/dialects/oas-document.json diff --git a/hack/api-docs/dialects/oas-vocabulary.json b/hack/api-docs/validation/dialects/oas-vocabulary.json similarity index 100% rename from hack/api-docs/dialects/oas-vocabulary.json rename to hack/api-docs/validation/dialects/oas-vocabulary.json diff --git a/hack/api-docs/known-issues.json b/hack/api-docs/validation/known-issues.json similarity index 100% rename from hack/api-docs/known-issues.json rename to hack/api-docs/validation/known-issues.json diff --git a/hack/api-docs/vacuum.yaml b/hack/api-docs/validation/rules.yaml similarity index 100% rename from hack/api-docs/vacuum.yaml rename to hack/api-docs/validation/rules.yaml diff --git a/layouts/api-docs.html b/layouts/api-docs.html index 572c36f9df87..097688e2a024 100644 --- a/layouts/api-docs.html +++ b/layouts/api-docs.html @@ -113,7 +113,12 @@

Connecting to the {{ $api.title }} API {{ end }}

-

{{ $api.auth }}

+ {{ range $name, $scheme := $api.securitySchemes }} + {{ with $scheme.description }} +

{{ index $scheme "x-displayName" | default $name }}

+
{{ . | markdownify }}
+ {{ end }} + {{ end }} {{ if eq $api.connection "unix" }}
curl --unix-socket /var/run/docker.sock http://localhost/v{{ $api.version }}/version
{{ else }} @@ -183,7 +188,11 @@

{{ .summary }}

{{ partial "api-reference/description.html" (dict "text" .description "api" $api) | markdownify }}

Connection and access

-

{{ $api.auth }}

+

+ API connection and authentication guidance +

{{ if and (eq $api.product "engine") (where .parameters "name" "X-Registry-Auth") }}

X-Registry-Auth delegates registry credentials diff --git a/layouts/api-docs.markdown.md b/layouts/api-docs.markdown.md index 4319f550a3f4..ad1cf4166530 100644 --- a/layouts/api-docs.markdown.md +++ b/layouts/api-docs.markdown.md @@ -21,7 +21,11 @@ API version: {{ $api.version }} {{ partial "api-reference/description.html" (dict "text" $api.description "api" $api) }} ## {{ if eq $api.connection "unix" }}Connecting to {{ $api.title }}{{ else }}Connecting to the {{ $api.title }} API{{ end }} -{{ $api.auth }} +{{ range $name, $scheme := $api.securitySchemes }}{{ with $scheme.description }} +### {{ index $scheme "x-displayName" | default $name }} + +{{ . }} +{{ end }}{{ end }} {{ range $api.servers }} Server: `{{ .url }}` {{ end }} @@ -58,7 +62,7 @@ Deprecated operation. {{ end }} ## Connection and access -{{ $api.auth }} +[API connection and authentication guidance]({{ $api.url }}#authentication) {{ if and (eq $api.product "engine") (where .parameters "name" "X-Registry-Auth") }} `X-Registry-Auth` delegates registry credentials and does not authenticate the daemon caller. {{ end }} From f8df8249f1813f623273d280477acb7c1f1d10cb Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 9 Sep 2026 12:48:36 +0000 Subject: [PATCH 08/13] docs: use shared Markdown processing for API references --- Dockerfile | 3 +- hack/api-docs/README.md | 9 +++-- hack/api-docs/flatten.mjs | 34 ------------------ hack/api-docs/run.sh | 2 +- hack/flatten-and-resolve.js | 42 ++++++++++++---------- hack/test/flatten-and-resolve.mjs | 58 +++++++++++++++++++++++++++++++ layouts/api-docs.markdown.md | 2 ++ netlify.toml | 2 +- 8 files changed, 95 insertions(+), 57 deletions(-) delete mode 100644 hack/api-docs/flatten.mjs create mode 100644 hack/test/flatten-and-resolve.mjs diff --git a/Dockerfile b/Dockerfile index 8aea2c2ecfb9..c0d288a83d11 100644 --- a/Dockerfile +++ b/Dockerfile @@ -62,7 +62,8 @@ RUN --mount=type=cache,target=/tmp/hugo_cache \ --printUnusedTemplates \ -b $DOCS_URL \ -e $HUGO_ENV -RUN node hack/api-docs/flatten.mjs public +RUN node --test hack/test/flatten-and-resolve.mjs +RUN node hack/flatten-and-resolve.js public RUN node hack/api-docs/verify-output.mjs public # lint lints markdown files diff --git a/hack/api-docs/README.md b/hack/api-docs/README.md index 37f116f98f61..69719588c607 100644 --- a/hack/api-docs/README.md +++ b/hack/api-docs/README.md @@ -46,8 +46,13 @@ manifest fields. 3. Generate presentation model version 1: operations, effective security and servers, parameters, media variants, examples, schema links, and provenance. 4. Render HTML and Markdown through the content adapter and `api-docs` templates. -5. Preserve API Markdown examples during site processing and check generated - operation, parameter, media, schema, and link coverage. +5. Run the shared site flattening script, then check generated operation, + parameter, media, schema, and link coverage. + +Generated API Markdown includes ``. The shared +`hack/flatten-and-resolve.js` script moves these files to their flattened paths +without rewriting their content. Their links already use published URLs. +Handwritten pages retain the existing link processing. The published YAML URLs still serve the source files directly. There is no conversion step, snapshot dependency, Node migration package, or source archive diff --git a/hack/api-docs/flatten.mjs b/hack/api-docs/flatten.mjs deleted file mode 100644 index 03ac5257cfee..000000000000 --- a/hack/api-docs/flatten.mjs +++ /dev/null @@ -1,34 +0,0 @@ -// The site postprocessor rewrites URL-like strings inside fenced JSON too. -// Keep generated reference Markdown intact; its links already target published URLs. -import fs from "node:fs"; -import path from "node:path"; -import { execFileSync } from "node:child_process"; -const root = path.resolve(import.meta.dirname, "../.."); -const site = path.resolve(process.argv[2] || "public"); -const data = JSON.parse( - fs.readFileSync(path.join(root, "tmp/api-reference/data/api-reference.json")), -); -const urls = [ - "/reference/api/", - ...data.apis.flatMap((api) => [ - api.url, - ...api.operations.map((op) => op.url), - ...api.schemas.map((schema) => schema.url), - ]), -]; -const saved = urls - .map((url) => path.join(site, url, "index.md")) - .map((p) => [p, fs.readFileSync(p)]); -for (const [p] of saved) fs.unlinkSync(p); -try { - execFileSync( - process.execPath, - [path.join(root, "hack/flatten-and-resolve.js"), site], - { stdio: "inherit" }, - ); -} finally { - for (const [p, b] of saved) { - const dest = path.basename(p) === "index.md" ? path.dirname(p) + ".md" : p; - fs.writeFileSync(dest, b); - } -} diff --git a/hack/api-docs/run.sh b/hack/api-docs/run.sh index b65fd477cdd4..62310293a7c6 100755 --- a/hack/api-docs/run.sh +++ b/hack/api-docs/run.sh @@ -34,7 +34,7 @@ case "${1:-build}" in build|serve) generate hugo --destination tmp/api-reference/site --baseURL "${DOCS_URL:-http://localhost:1314}" --cleanDestinationDir - node hack/api-docs/flatten.mjs tmp/api-reference/site + node hack/flatten-and-resolve.js tmp/api-reference/site node hack/api-docs/verify-output.mjs tmp/api-reference/site if [[ "${1:-build}" == serve ]]; then exec python3 -m http.server "${DOCS_PORT:-1314}" --bind 127.0.0.1 --directory tmp/api-reference/site diff --git a/hack/flatten-and-resolve.js b/hack/flatten-and-resolve.js index 04532d343eb5..111887092c55 100755 --- a/hack/flatten-and-resolve.js +++ b/hack/flatten-and-resolve.js @@ -9,6 +9,7 @@ * 3. Strips /manuals/ prefix from paths (Hugo config removes this) * 4. Resolves all relative links to absolute HTML paths for RAG ingestion * + * Pages starting with are flattened without content changes. * Usage: node flatten-and-resolve.js [public-dir] */ @@ -16,6 +17,7 @@ const fs = require('fs'); const path = require('path'); const PUBLIC_DIR = path.resolve(process.argv[2] || 'public'); +const SKIP_LINK_REWRITING = ''; if (!fs.existsSync(PUBLIC_DIR)) { console.error(`Error: Directory ${PUBLIC_DIR} does not exist`); @@ -62,27 +64,29 @@ function flattenIndexFiles() { // Read content and fix sibling links let content = fs.readFileSync(file, 'utf8'); - // Rewrite relative links that don't start with /, ../, or http - // These are sibling files that will become children after flattening - content = content.replace( - /\[([^\]]+)\]\(([a-zA-Z0-9][^):]*)\)/g, - (match, text, link) => { - // Skip if it's a URL or starts with special chars - if (link.startsWith('http://') || link.startsWith('https://') || - link.startsWith('#')) { - return match; + if (!content.startsWith(SKIP_LINK_REWRITING)) { + // Rewrite relative links that don't start with /, ../, or http + // These are sibling files that will become children after flattening + content = content.replace( + /\[([^\]]+)\]\(([a-zA-Z0-9][^):]*)\)/g, + (match, text, link) => { + // Skip if it's a URL or starts with special chars + if (link.startsWith('http://') || link.startsWith('https://') || + link.startsWith('#')) { + return match; + } + return `[${text}](${dirname}/${link})`; } - return `[${text}](${dirname}/${link})`; - } - ); + ); - // Also fix reference-style links - content = content.replace( - /^\[([^\]]+)\]:\s+([a-zA-Z0-9][^: ]*\.md)$/gm, - (match, ref, link) => `[${ref}]: ${dirname}/${link}` - ); + // Also fix reference-style links + content = content.replace( + /^\[([^\]]+)\]:\s+([a-zA-Z0-9][^: ]*\.md)$/gm, + (match, ref, link) => `[${ref}]: ${dirname}/${link}` + ); - fs.writeFileSync(file, content, 'utf8'); + fs.writeFileSync(file, content, 'utf8'); + } // Move file up one level const parentDir = path.dirname(dir); @@ -111,6 +115,7 @@ function fixIndexReferences() { const parentDirname = path.basename(parentDir); let content = fs.readFileSync(file, 'utf8'); + if (content.startsWith(SKIP_LINK_REWRITING)) continue; const original = content; // Fix path/_index.md or path/index.md -> path.md @@ -146,6 +151,7 @@ function resolveLinks() { for (const file of mdFiles) { let content = fs.readFileSync(file, 'utf8'); + if (content.startsWith(SKIP_LINK_REWRITING)) continue; const original = content; // Process inline links: [text](path) diff --git a/hack/test/flatten-and-resolve.mjs b/hack/test/flatten-and-resolve.mjs new file mode 100644 index 000000000000..c8a9d6037c07 --- /dev/null +++ b/hack/test/flatten-and-resolve.mjs @@ -0,0 +1,58 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { execFileSync } from "node:child_process"; + +const script = path.resolve(import.meta.dirname, "../flatten-and-resolve.js"); + +test("flattens generated pages unchanged while resolving handwritten reference links", () => { + const site = fs.mkdtempSync(path.join(os.tmpdir(), "docs-flatten-")); + const generated = + "\n\n# API\n\n" + + "[Guide](/reference/api/registry/auth/)\n\n" + + '```json\n{"path":"/manuals/example/index.md","text":"[sample](file.md)"}\n```\n'; + const write = (name, value) => { + const file = path.join(site, name); + fs.mkdirSync(path.dirname(file), { recursive: true }); + fs.writeFileSync(file, value); + }; + try { + write("reference/api/index.md", generated); + write("reference/api/registry/latest/index.md", generated); + write( + "reference/api/registry/auth/index.md", + "# Guide\n\n[Example](example.md)\n", + ); + write("reference/api/registry/auth/example.md", "# Example\n"); + for (let run = 0; run < 2; run++) { + execFileSync(process.execPath, [script, site], { stdio: "pipe" }); + assert.equal( + fs.readFileSync(path.join(site, "reference/api.md"), "utf8"), + generated, + ); + assert.equal( + fs.readFileSync( + path.join(site, "reference/api/registry/latest.md"), + "utf8", + ), + generated, + ); + assert.ok( + !fs.existsSync( + path.join(site, "reference/api/registry/latest/index.md"), + ), + ); + assert.match( + fs.readFileSync( + path.join(site, "reference/api/registry/auth.md"), + "utf8", + ), + /\[Example\]\(\/reference\/api\/registry\/auth\/example\/\)/, + ); + } + } finally { + fs.rmSync(site, { recursive: true, force: true }); + } +}); diff --git a/layouts/api-docs.markdown.md b/layouts/api-docs.markdown.md index ad1cf4166530..53f9c83c22d0 100644 --- a/layouts/api-docs.markdown.md +++ b/layouts/api-docs.markdown.md @@ -1,5 +1,7 @@ {{- $data := index hugo.Data "api-reference" -}} {{- $api := dict -}}{{- range $data.apis -}}{{- if eq .id $.Params.apiID -}}{{- $api = . -}}{{- end -}}{{- end -}} + + # {{ .Title }} {{ if eq .Params.view "catalog" }} diff --git a/netlify.toml b/netlify.toml index c98538809bf0..000114a4bb03 100644 --- a/netlify.toml +++ b/netlify.toml @@ -11,4 +11,4 @@ HUGO_ENVIRONMENT = "preview" SECRETS_SCAN_OMIT_PATHS = "public/contribute/file-conventions/index.html" [context.deploy-preview] -command = "./hack/api-docs/run.sh generate && hugo --gc --minify -b $DEPLOY_PRIME_URL && node hack/api-docs/flatten.mjs && node hack/api-docs/verify-output.mjs && npx pagefind@v1.5.2" +command = "./hack/api-docs/run.sh generate && hugo --gc --minify -b $DEPLOY_PRIME_URL && node hack/flatten-and-resolve.js && node hack/api-docs/verify-output.mjs && npx pagefind@v1.5.2" From 19d7c36dff640b3883041b8c144cab276af1dbbb Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 9 Sep 2026 12:58:36 +0000 Subject: [PATCH 09/13] docs: resolve Markdown links before flattening all pages --- hack/api-docs/README.md | 8 +- hack/flatten-and-resolve.js | 307 +++++-------------- hack/test/flatten-and-resolve.mjs | 65 +++- layouts/api-docs.markdown.md | 2 - package-lock.json | 476 ++++++++++++++++++++++++++++++ package.json | 1 + 6 files changed, 626 insertions(+), 233 deletions(-) diff --git a/hack/api-docs/README.md b/hack/api-docs/README.md index 69719588c607..cb878e32e99b 100644 --- a/hack/api-docs/README.md +++ b/hack/api-docs/README.md @@ -49,10 +49,10 @@ manifest fields. 5. Run the shared site flattening script, then check generated operation, parameter, media, schema, and link coverage. -Generated API Markdown includes ``. The shared -`hack/flatten-and-resolve.js` script moves these files to their flattened paths -without rewriting their content. Their links already use published URLs. -Handwritten pages retain the existing link processing. +The shared `hack/flatten-and-resolve.js` script resolves Markdown link destinations +relative to each original file, then moves `index.md` files to flattened paths. +It preserves code examples and other text. API pages use the same processing as +other pages; links that already use published URLs remain unchanged. The published YAML URLs still serve the source files directly. There is no conversion step, snapshot dependency, Node migration package, or source archive diff --git a/hack/flatten-and-resolve.js b/hack/flatten-and-resolve.js index 111887092c55..b79ca5e21208 100755 --- a/hack/flatten-and-resolve.js +++ b/hack/flatten-and-resolve.js @@ -1,242 +1,99 @@ #!/usr/bin/env node /** - * Flattens markdown directory structure and resolves all links to absolute paths. - * - * This script: - * 1. Moves index.md files up one level (ai/model-runner/index.md -> ai/model-runner.md) - * 2. Fixes _index.md and index.md references in links - * 3. Strips /manuals/ prefix from paths (Hugo config removes this) - * 4. Resolves all relative links to absolute HTML paths for RAG ingestion - * - * Pages starting with are flattened without content changes. - * Usage: node flatten-and-resolve.js [public-dir] + * Resolve Markdown links relative to each original file, then flatten index.md. + * Only link destinations change; examples and other text stay byte-identical. + * Usage: node hack/flatten-and-resolve.js [public-dir] */ - -const fs = require('fs'); -const path = require('path'); - -const PUBLIC_DIR = path.resolve(process.argv[2] || 'public'); -const SKIP_LINK_REWRITING = ''; - -if (!fs.existsSync(PUBLIC_DIR)) { - console.error(`Error: Directory ${PUBLIC_DIR} does not exist`); - process.exit(1); +const fs = require("node:fs"); +const path = require("node:path"); + +const publicDir = path.resolve(process.argv[2] || "public"); + +function markdownFiles(dir) { + return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => { + const file = path.join(dir, entry.name); + return entry.isDirectory() + ? markdownFiles(file) + : file.endsWith(".md") + ? [file] + : []; + }); } -/** - * Recursively find all files matching a predicate - */ -function findFiles(dir, predicate) { - const results = []; - const entries = fs.readdirSync(dir, { withFileTypes: true }); - - for (const entry of entries) { - const fullPath = path.join(dir, entry.name); - if (entry.isDirectory()) { - results.push(...findFiles(fullPath, predicate)); - } else if (entry.isFile() && predicate(entry.name)) { - results.push(fullPath); - } - } - - return results; +function resolveLink(link, file) { + // External URLs, protocol-relative URLs, and same-page anchors are complete. + if (/^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i.test(link)) return link; + const [, pathname, suffix] = link.match(/^([^?#]*)(.*)$/s); + if (!pathname) return link; + let url = pathname.startsWith("/") + ? pathname + : "/" + + path + .relative(publicDir, path.resolve(path.dirname(file), pathname)) + .split(path.sep) + .join("/"); + url = url.replace(/^\/manuals\//, "/"); + url = url.replace(/\/_?index\.md$/, "/").replace(/\.md$/, "/"); + return url + suffix; } -/** - * Step 1: Flatten index.md files - * Move path/to/section/index.md -> path/to/section.md - * Before moving, rewrite sibling links (e.g., "get-started.md" -> "section/get-started.md") - */ -function flattenIndexFiles() { - const indexFiles = findFiles(PUBLIC_DIR, name => name === 'index.md'); - let count = 0; - - for (const file of indexFiles) { - // Skip root index.md - if (file === path.join(PUBLIC_DIR, 'index.md')) { - continue; - } - - const dir = path.dirname(file); - const dirname = path.basename(dir); - - // Read content and fix sibling links - let content = fs.readFileSync(file, 'utf8'); - - if (!content.startsWith(SKIP_LINK_REWRITING)) { - // Rewrite relative links that don't start with /, ../, or http - // These are sibling files that will become children after flattening - content = content.replace( - /\[([^\]]+)\]\(([a-zA-Z0-9][^):]*)\)/g, - (match, text, link) => { - // Skip if it's a URL or starts with special chars - if (link.startsWith('http://') || link.startsWith('https://') || - link.startsWith('#')) { - return match; - } - return `[${text}](${dirname}/${link})`; - } - ); - - // Also fix reference-style links - content = content.replace( - /^\[([^\]]+)\]:\s+([a-zA-Z0-9][^: ]*\.md)$/gm, - (match, ref, link) => `[${ref}]: ${dirname}/${link}` - ); - - fs.writeFileSync(file, content, 'utf8'); - } - - // Move file up one level - const parentDir = path.dirname(dir); - const newPath = path.join(parentDir, `${dirname}.md`); - fs.renameSync(file, newPath); - - count++; +// Micromark provides exact destination spans, excluding labels, titles, and code. +// Apply edits backwards so offsets stay valid and formatting stays untouched. +function rewriteLinks(content, events, file) { + const destinations = events + .filter( + ([event, token]) => + event === "enter" && + ["resourceDestinationString", "definitionDestinationString"].includes( + token.type, + ), + ) + .map(([, token]) => token) + .sort((a, b) => b.start.offset - a.start.offset); + for (const token of destinations) { + const start = token.start.offset; + const end = token.end.offset; + const destination = content.slice(start, end); + content = + content.slice(0, start) + + resolveLink(destination, file) + + content.slice(end); } - - console.log(`Flattened ${count} index.md files`); - return count; + return content; } -/** - * Step 2: Fix _index.md and index.md references in all files - * Also strip /manuals/ prefix from paths - */ -function fixIndexReferences() { - const mdFiles = findFiles(PUBLIC_DIR, name => name.endsWith('.md')); - let count = 0; - - for (const file of mdFiles) { - const dir = path.dirname(file); - const dirname = path.basename(dir); - const parentDir = path.dirname(dir); - const parentDirname = path.basename(parentDir); - - let content = fs.readFileSync(file, 'utf8'); - if (content.startsWith(SKIP_LINK_REWRITING)) continue; - const original = content; - - // Fix path/_index.md or path/index.md -> path.md - content = content.replace(/([a-zA-Z0-9_/-]+)\/_?index\.md/g, '$1.md'); - - // Fix bare _index.md or index.md -> ../dirname.md - content = content.replace(/_?index\.md/g, `../${dirname}.md`); - - // Fix ../_index.md that became ...md -> ../../parentdirname.md - if (parentDir !== PUBLIC_DIR) { - content = content.replace(/\.\.\.md/g, `../../${parentDirname}.md`); - } - - // Strip /manuals/ prefix (both /manuals/ and manuals/) - content = content.replace(/\/?manuals\//g, '/'); - +async function main() { + const { parse, preprocess, postprocess } = await import("micromark"); + const files = markdownFiles(publicDir); + let rewritten = 0; + let flattened = 0; + for (const file of files) { + const original = fs.readFileSync(file, "utf8"); + const events = postprocess( + parse() + .document() + .write(preprocess()(original, "utf8", true)), + ); + const content = rewriteLinks(original, events, file); if (content !== original) { - fs.writeFileSync(file, content, 'utf8'); - count++; + fs.writeFileSync(file, content); + rewritten++; } - } - - console.log(`Fixed _index.md references in ${count} files`); - return count; -} - -/** - * Step 3: Resolve all relative links to absolute HTML paths - */ -function resolveLinks() { - const mdFiles = findFiles(PUBLIC_DIR, name => name.endsWith('.md')); - let count = 0; - - for (const file of mdFiles) { - let content = fs.readFileSync(file, 'utf8'); - if (content.startsWith(SKIP_LINK_REWRITING)) continue; - const original = content; - - // Process inline links: [text](path) - content = content.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, text, link) => { - const resolved = resolveLinkPath(link, file); - return `[${text}](${resolved})`; - }); - - // Process reference-style links: [ref]: path - content = content.replace(/^\[([^\]]+)\]:\s+(.+)$/gm, (match, ref, link) => { - const resolved = resolveLinkPath(link, file); - return `[${ref}]: ${resolved}`; - }); - - if (content !== original) { - fs.writeFileSync(file, content, 'utf8'); - count++; + if ( + path.basename(file) === "index.md" && + file !== path.join(publicDir, "index.md") + ) { + fs.renameSync(file, path.dirname(file) + ".md"); + flattened++; } } - - console.log(`Resolved links in ${count} files`); - return count; + console.log( + `Markdown: rewrote links in ${rewritten} files; flattened ${flattened} index.md files`, + ); } -/** - * Resolve a link path to absolute HTML format - */ -function resolveLinkPath(linkPath, currentFile) { - // Skip external URLs and mailto - if (linkPath.startsWith('http://') || linkPath.startsWith('https://') || - linkPath.startsWith('mailto:')) { - return linkPath; - } - - // Skip same-page anchors - if (linkPath.startsWith('#')) { - return linkPath; - } - - // Split path and anchor - const hashIndex = linkPath.indexOf('#'); - const pathPart = hashIndex >= 0 ? linkPath.substring(0, hashIndex) : linkPath; - const anchorPart = hashIndex >= 0 ? linkPath.substring(hashIndex) : ''; - - if (!pathPart) { - // Just an anchor - return linkPath; - } - - // Handle absolute paths - just convert to HTML format - if (pathPart.startsWith('/')) { - return toHtmlPath(pathPart) + anchorPart; - } - - // Resolve relative path to absolute - const currentDir = path.dirname(currentFile); - const absolutePath = path.resolve(currentDir, pathPart); - const relativePath = path.relative(PUBLIC_DIR, absolutePath); - - // Convert to URL path (forward slashes) - const urlPath = '/' + relativePath.split(path.sep).join('/'); - - return toHtmlPath(urlPath) + anchorPart; -} - -/** - * Convert a path to HTML format (strip .md, add trailing /) - */ -function toHtmlPath(urlPath) { - if (urlPath.endsWith('.md')) { - return urlPath.slice(0, -3) + '/'; - } - return urlPath; -} - -// Main execution -console.log('Starting markdown flattening and link resolution...'); -console.log(''); - -const flattenCount = flattenIndexFiles(); -const fixCount = fixIndexReferences(); -const resolveCount = resolveLinks(); - -console.log(''); -console.log('Done!'); -console.log(`- Flattened: ${flattenCount} files`); -console.log(`- Fixed references: ${fixCount} files`); -console.log(`- Resolved links: ${resolveCount} files`); +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/hack/test/flatten-and-resolve.mjs b/hack/test/flatten-and-resolve.mjs index c8a9d6037c07..697287c35350 100644 --- a/hack/test/flatten-and-resolve.mjs +++ b/hack/test/flatten-and-resolve.mjs @@ -7,10 +7,10 @@ import { execFileSync } from "node:child_process"; const script = path.resolve(import.meta.dirname, "../flatten-and-resolve.js"); -test("flattens generated pages unchanged while resolving handwritten reference links", () => { +test("flattens all pages while preserving examples and resolving documentation links", () => { const site = fs.mkdtempSync(path.join(os.tmpdir(), "docs-flatten-")); const generated = - "\n\n# API\n\n" + + "# API\n\n" + "[Guide](/reference/api/registry/auth/)\n\n" + '```json\n{"path":"/manuals/example/index.md","text":"[sample](file.md)"}\n```\n'; const write = (name, value) => { @@ -56,3 +56,64 @@ test("flattens generated pages unchanged while resolving handwritten reference l fs.rmSync(site, { recursive: true, force: true }); } }); + +test("rewrites only destinations and preserves Markdown syntax", () => { + const site = fs.mkdtempSync(path.join(os.tmpdir(), "docs-links-")); + const cases = [ + ["[Guide](/manuals/engine/_index.md#install)", "[Guide](/engine/#install)"], + ["[Parent](../index.md)", "[Parent](/guide/)"], + ["[Root](/index.md)", "[Root](/)"], + [ + '[Title]( "A title")', + '[Title]( "A title")', + ], + [ + "[Nested **label**](file(test).md?q=1#part)", + "[Nested **label**](/guide/section/file(test)/?q=1#part)", + ], + ["[`odd ] bracket`](file.md)", "[`odd ] bracket`](/guide/section/file/)"], + [ + "![Image [label]](picture.png)", + "![Image [label]](/guide/section/picture.png)", + ], + [ + '[ref]: /manuals/engine/index.md "Title"\n\n[Reference][ref]', + '[ref]: /engine/ "Title"\n\n[Reference][ref]', + ], + ["> - [Guide](file.md)", "> - [Guide](/guide/section/file/)"], + [ + "[External](https://example.com/manuals/index.md)", + "[External](https://example.com/manuals/index.md)", + ], + [ + "[CDN](//example.com/manuals/index.md)", + "[CDN](//example.com/manuals/index.md)", + ], + ["[Mail](mailto:docs@example.com)", "[Mail](mailto:docs@example.com)"], + ["[Anchor](#example)", "[Anchor](#example)"], + ["`[Example](/manuals/index.md)`", "`[Example](/manuals/index.md)`"], + [" [Example](/manuals/index.md)", " [Example](/manuals/index.md)"], + [ + '~~~json\n{"file":"/manuals/index.md"}\n~~~', + '~~~json\n{"file":"/manuals/index.md"}\n~~~', + ], + [ + "A literal /manuals/example/index.md filename.", + "A literal /manuals/example/index.md filename.", + ], + ]; + try { + fs.mkdirSync(path.join(site, "guide/section"), { recursive: true }); + fs.writeFileSync( + path.join(site, "guide/section/index.md"), + cases.map(([before]) => before).join("\n\n"), + ); + execFileSync(process.execPath, [script, site]); + assert.equal( + fs.readFileSync(path.join(site, "guide/section.md"), "utf8"), + cases.map(([, after]) => after).join("\n\n"), + ); + } finally { + fs.rmSync(site, { recursive: true, force: true }); + } +}); diff --git a/layouts/api-docs.markdown.md b/layouts/api-docs.markdown.md index 53f9c83c22d0..ad1cf4166530 100644 --- a/layouts/api-docs.markdown.md +++ b/layouts/api-docs.markdown.md @@ -1,7 +1,5 @@ {{- $data := index hugo.Data "api-reference" -}} {{- $api := dict -}}{{- range $data.apis -}}{{- if eq .id $.Params.apiID -}}{{- $api = . -}}{{- end -}}{{- end -}} - - # {{ .Title }} {{ if eq .Params.view "catalog" }} diff --git a/package-lock.json b/package-lock.json index bd39c8b94840..53d434980a39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "highlight.js": "11.11.1", "marked": "17.0.4", "mermaid": "11.15.0", + "micromark": "4.0.2", "tailwindcss": "4.2.1" }, "devDependencies": { @@ -1173,11 +1174,24 @@ "@types/d3-selection": "*" } }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/geojson": { "version": "7946.0.16", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==" }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" + }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -1229,6 +1243,15 @@ "node": ">=8" } }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -1728,6 +1751,34 @@ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==" }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/delaunator": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", @@ -1736,6 +1787,14 @@ "robust-predicates": "^3.0.2" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -1748,6 +1807,18 @@ "node": ">=0.10" } }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/dompurify": { "version": "3.4.6", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.6.tgz", @@ -2241,6 +2312,406 @@ "node": ">= 20" } }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -2263,6 +2734,11 @@ "node": ">=4" } }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", diff --git a/package.json b/package.json index 8cc4272493ba..bb4de3c29c77 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "highlight.js": "11.11.1", "marked": "17.0.4", "mermaid": "11.15.0", + "micromark": "4.0.2", "tailwindcss": "4.2.1" }, "devDependencies": { From 0f29d9658bf78e5868174044fb5a912a0efe1688 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 9 Sep 2026 13:17:19 +0000 Subject: [PATCH 10/13] docs: preserve examples through schema reference chains Example lookup skipped annotations on intermediate schema references, incorrectly reporting valid examples as missing. Follow each reference in sequence and retain the external resource base, with regression coverage for annotation precedence, false and zero values, and cycles. --- hack/api-docs/main_test.go | 33 +++++++++++++++++++++++++++++++++ hack/api-docs/model.go | 22 +++++++++++++++++++--- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/hack/api-docs/main_test.go b/hack/api-docs/main_test.go index 3bfd06857fe3..ee815f37d8d1 100644 --- a/hack/api-docs/main_test.go +++ b/hack/api-docs/main_test.go @@ -176,6 +176,39 @@ func TestFalseSchemaAndExamplePreserved(t *testing.T) { } } +func TestMediaExamplesFollowReferenceAnnotations(t *testing.T) { + d := &Document{URI: "https://example.test/api.yaml", Registry: &Registry{resources: map[string]any{ + "https://example.test/api.yaml": Object{ + "alias": Object{"$ref": "#/base", "examples": []any{false, jsonNumber("0")}}, + "base": Object{"example": "base example"}, + "cycle": Object{"$ref": "#/cycle"}, + }, + "https://example.test/schemas/alias.yaml": Object{"$ref": "base.yaml"}, + "https://example.test/schemas/base.yaml": Object{"example": "external example"}, + }}} + for _, tc := range []struct { + name string + media Object + values []any + }{ + {"intermediate annotations", Object{"schema": Object{"$ref": "#/alias"}}, []any{false, jsonNumber("0")}}, + {"nearest schema annotation", Object{"schema": Object{"$ref": "#/alias", "example": "local"}}, []any{"local"}}, + {"media annotation", Object{"example": false, "schema": Object{"$ref": "#/alias"}}, []any{false}}, + {"relative external reference", Object{"schema": Object{"$ref": "schemas/alias.yaml"}}, []any{"external example"}}, + {"cycle", Object{"schema": Object{"$ref": "#/cycle"}}, []any{}}, + } { + t.Run(tc.name, func(t *testing.T) { + values := []any{} + for _, ex := range d.mediaExamples(tc.media) { + values = append(values, obj(ex)["value"]) + } + if !reflect.DeepEqual(values, tc.values) { + t.Fatalf("examples = %#v, want %#v", values, tc.values) + } + }) + } +} + func TestTimestampStringsRetainSpelling(t *testing.T) { p := filepath.Join(t.TempDir(), "schema.yaml") if e := os.WriteFile(p, []byte("type: string\nexample: 2021-01-05T21:06:53.506400Z\n"), 0600); e != nil { diff --git a/hack/api-docs/model.go b/hack/api-docs/model.go index 4ea52b6ad1d1..b0b684c60886 100644 --- a/hack/api-docs/model.go +++ b/hack/api-docs/model.go @@ -227,6 +227,7 @@ func (d *Document) mediaExamples(v Object) []any { } s := v["schema"] seen := map[string]bool{} + base, _ := url.Parse(d.URI) for s != nil { n := obj(s) if x, ok := n["example"]; ok { @@ -239,11 +240,26 @@ func (d *Document) mediaExamples(v Object) []any { return out } ref := str(n["$ref"]) - if ref == "" || seen[ref] { + if ref == "" { break } - seen[ref] = true - s = d.resolve(n) + u, err := url.Parse(ref) + if err != nil { + break + } + u = base.ResolveReference(u) + if seen[u.String()] { + break + } + seen[u.String()] = true + fragment := u.Fragment + u.Fragment = "" + // Follow one reference at a time so intermediate schema annotations survive. + s, err = pointer(d.Registry.resources[u.String()], fragment) + if err != nil { + break + } + base = u } return out } From d54c63731147035a319dc6d9a9b22598dfbe9eb9 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 9 Sep 2026 13:17:34 +0000 Subject: [PATCH 11/13] docs: resolve straightforward API validation issues The API migration baseline mixed missing descriptions and examples with unresolved response contracts. Complete parameter descriptions, quote 2FA codes, and add examples based on documented fields without changing API constraints. Remove 121 resolved entries and group the remaining 168 by the evidence needed before merge. --- content/reference/api/dvp/latest.yaml | 20 +- content/reference/api/hub/latest.yaml | 282 +++- content/reference/api/registry/latest.yaml | 12 +- hack/api-docs/README.md | 46 +- hack/api-docs/validation/known-issues.json | 1662 +++----------------- 5 files changed, 563 insertions(+), 1459 deletions(-) diff --git a/content/reference/api/dvp/latest.yaml b/content/reference/api/dvp/latest.yaml index 3d0c606a0c72..4e7e562fde51 100644 --- a/content/reference/api/dvp/latest.yaml +++ b/content/reference/api/dvp/latest.yaml @@ -491,6 +491,9 @@ paths: components: schemas: UsersLoginRequest: + examples: + - username: myusername + password: hunter2 description: User login details type: object required: @@ -506,6 +509,8 @@ components: type: string example: hunter2 PostUsersLoginSuccessResponse: + examples: + - token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c description: successful user login response type: object properties: @@ -517,6 +522,8 @@ components: type: string example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c PostUsersLoginErrorResponse: + examples: + - detail: Incorrect authentication credentials description: failed user login response or second factor required type: object required: @@ -533,6 +540,9 @@ components: - "null" example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c Users2FALoginRequest: + examples: + - login_2fa_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + code: "123456" description: Second factor user login details type: object required: @@ -546,8 +556,10 @@ components: code: description: The Time-based One-Time Password of the Docker Hub account to authenticate with. type: string - example: 123456 + example: "123456" PostUsers2FALoginErrorResponse: + examples: + - detail: Incorrect authentication credentials description: failed second factor login response. type: object properties: @@ -571,6 +583,9 @@ components: type: integer format: int64 NamespaceData: + examples: + - namespaces: + - myorganization properties: namespaces: type: array @@ -629,6 +644,9 @@ components: country: type: string YearData: + examples: + - years: + - year: 2025 properties: years: type: array diff --git a/content/reference/api/hub/latest.yaml b/content/reference/api/hub/latest.yaml index e5eb668ef321..473731cdc6a3 100644 --- a/content/reference/api/hub/latest.yaml +++ b/content/reference/api/hub/latest.yaml @@ -269,6 +269,9 @@ paths: content: application/json: schema: + examples: + - identifier: myusername + secret: dckr_pat_124509ugsdjga93 description: Request to create access token type: object required: @@ -331,12 +334,14 @@ paths: security: - bearerAuth: [] parameters: - - in: query + - description: Page number to return. + in: query name: page schema: type: number default: 1 - - in: query + - description: Number of results per page. + in: query name: page_size schema: type: number @@ -355,7 +360,8 @@ paths: operationId: getV2AccessTokens /v2/access-tokens/{uuid}: parameters: - - in: path + - description: UUID of the personal access token. + in: path name: uuid required: true schema: @@ -399,6 +405,20 @@ paths: content: application/json: schema: + examples: + - uuid: b30bbf97-506c-4ecd-aabc-842f3cb484fb + client_id: HUB + creator_ip: 127.0.0.1 + creator_ua: some user agent + created_at: "2021-07-20T12:00:00.000000Z" + last_used: null + generated_by: manual + is_active: true + token: "" + token_label: My read only token + scopes: + - repo:read + expires_at: "2021-10-28T18:30:19.520861Z" allOf: - $ref: "#/components/schemas/accessToken" - type: object @@ -893,6 +913,11 @@ paths: content: application/json: schema: + examples: + - restricted_images: + enabled: true + allow_official_images: true + allow_verified_publishers: true required: - restricted_images properties: @@ -959,12 +984,14 @@ paths: security: - bearerAuth: [] parameters: - - in: query + - description: Page number to return. + in: query name: page schema: type: number default: 1 - - in: query + - description: Number of results per page. + in: query name: page_size schema: type: number @@ -1699,6 +1726,8 @@ paths: content: application/json: schema: + examples: + - role: owner required: - role properties: @@ -1768,6 +1797,14 @@ paths: content: application/json: schema: + examples: + - data: + - id: e36eca69-4cc8-4f17-9845-ae8c2b832691 + inviter_username: moby + invitee: invitee@docker.com + org: docker + team: owners + created_at: "2021-10-28T18:30:19.520861Z" type: object properties: data: @@ -1846,6 +1883,9 @@ paths: content: application/json: schema: + examples: + - name: developers + description: Development team required: - name properties: @@ -1904,6 +1944,9 @@ paths: content: application/json: schema: + examples: + - name: developers + description: Development team required: - name properties: @@ -1936,6 +1979,9 @@ paths: content: application/json: schema: + examples: + - description: Development team + role: member properties: name: type: string @@ -2079,7 +2125,8 @@ paths: /v2/invites/{id}: x-audience: public parameters: - - in: path + - description: ID of the invitation. + in: path name: id required: true schema: @@ -2107,7 +2154,8 @@ paths: /v2/invites/{id}/resend: x-audience: public parameters: - - in: path + - description: ID of the invitation. + in: path name: id schema: type: string @@ -2208,7 +2256,8 @@ paths: tags: - scim parameters: - - name: name + - description: Name of the SCIM resource type. + name: name in: path schema: type: string @@ -2253,7 +2302,8 @@ paths: tags: - scim parameters: - - name: id + - description: URN identifying the SCIM schema. + name: id in: path schema: type: string @@ -2308,7 +2358,7 @@ paths: schema: type: integer minimum: 1 - description: "" + description: "One-based index of the first result to return." example: 1 - name: count in: query @@ -2316,16 +2366,17 @@ paths: type: integer minimum: 1 maximum: 200 - description: "" + description: "Maximum number of results to return." example: 10 - name: filter in: query schema: type: string - description: "" + description: "SCIM filter expression used to select users." example: userName eq "jon.snow@docker.com" - $ref: "#/components/parameters/scim_attributes" - - name: sortOrder + - description: Sort direction applied to the attribute specified by sortBy. + name: sortOrder in: query schema: type: string @@ -2508,6 +2559,13 @@ components: description: Bad Request content: application/scim+json: + examples: + error: + summary: Example error envelope + value: + schemas: + - urn:ietf:params:scim:api:messages:2.0:Error + status: "400" schema: allOf: - $ref: "#/components/schemas/scim_error" @@ -2521,6 +2579,13 @@ components: description: Unauthorized content: application/scim+json: + examples: + error: + summary: Example error envelope + value: + schemas: + - urn:ietf:params:scim:api:messages:2.0:Error + status: "401" schema: allOf: - $ref: "#/components/schemas/scim_error" @@ -2531,6 +2596,13 @@ components: description: Forbidden content: application/scim+json: + examples: + error: + summary: Example error envelope + value: + schemas: + - urn:ietf:params:scim:api:messages:2.0:Error + status: "403" schema: allOf: - $ref: "#/components/schemas/scim_error" @@ -2541,6 +2613,13 @@ components: description: Not Found content: application/scim+json: + examples: + error: + summary: Example error envelope + value: + schemas: + - urn:ietf:params:scim:api:messages:2.0:Error + status: "404" schema: allOf: - $ref: "#/components/schemas/scim_error" @@ -2551,6 +2630,13 @@ components: description: Conflict content: application/scim+json: + examples: + error: + summary: Example error envelope + value: + schemas: + - urn:ietf:params:scim:api:messages:2.0:Error + status: "409" schema: allOf: - $ref: "#/components/schemas/scim_error" @@ -2561,6 +2647,13 @@ components: description: Internal Error content: application/scim+json: + examples: + error: + summary: Example error envelope + value: + schemas: + - urn:ietf:params:scim:api:messages:2.0:Error + status: "500" schema: allOf: - $ref: "#/components/schemas/scim_error" @@ -2951,6 +3044,11 @@ components: required: - regex immutable_tags_verify_response: + examples: + - tags: + - v1.0.0 + - v2.1.3 + - latest type: object properties: tags: @@ -3092,6 +3190,9 @@ components: items: $ref: "#/components/schemas/repository_list_entry" UsersLoginRequest: + examples: + - username: myusername + password: p@ssw0rd description: User login details type: object required: @@ -3108,6 +3209,8 @@ components: type: string example: p@ssw0rd AuthCreateTokenResponse: + examples: + - access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c description: successful access token response type: object properties: @@ -3116,6 +3219,8 @@ components: type: string example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c PostUsersLoginSuccessResponse: + examples: + - token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c description: successful user login response type: object properties: @@ -3126,6 +3231,8 @@ components: type: string example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c PostUsersLoginErrorResponse: + examples: + - detail: Incorrect authentication credentials description: failed user login response or second factor required type: object required: @@ -3143,6 +3250,9 @@ components: - "null" example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c Users2FALoginRequest: + examples: + - login_2fa_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + code: "123456" description: Second factor user login details type: object required: @@ -3157,8 +3267,10 @@ components: description: | The Time-based One-Time Password of the Docker Hub account to authenticate with. type: string - example: 123456 + example: "123456" PostUsers2FALoginErrorResponse: + examples: + - detail: Incorrect authentication credentials description: failed second factor login response. type: object properties: @@ -3312,6 +3424,10 @@ components: format: date-time example: 2021-10-28T18:30:19.520861Z createAccessTokenRequest: + examples: + - token_label: My read only token + scopes: + - repo:read type: object required: - token_label @@ -3339,6 +3455,20 @@ components: format: date-time example: 2021-10-28T18:30:19.520861Z createAccessTokensResponse: + examples: + - uuid: b30bbf97-506c-4ecd-aabc-842f3cb484fb + client_id: HUB + creator_ip: 127.0.0.1 + creator_ua: some user agent + created_at: "2021-07-20T12:00:00.000000Z" + last_used: null + generated_by: manual + is_active: true + token: a7a5ef25-8889-43a0-8cc7-f2a94268e861 + token_label: My read only token + scopes: + - repo:read + expires_at: "2021-10-28T18:30:19.520861Z" $ref: "#/components/schemas/accessToken" getAccessTokensResponse: type: object @@ -3366,6 +3496,9 @@ components: type: string example: "" patchAccessTokenRequest: + examples: + - token_label: My read only token + is_active: false type: object properties: token_label: @@ -3379,6 +3512,11 @@ components: patchAccessTokenResponse: $ref: "#/components/schemas/accessToken" orgSettings: + examples: + - restricted_images: + enabled: true + allow_official_images: true + allow_verified_publishers: true type: object properties: restricted_images: @@ -3941,6 +4079,14 @@ components: type: string example: oauthbearertoken scim_resource_type: + examples: + - schemas: + - urn:ietf:params:scim:schemas:core:2.0:ResourceType + id: User + name: User + description: User + endpoint: /Users + schema: urn:ietf:params:scim:schemas:core:2.0:User type: object properties: schemas: @@ -3965,6 +4111,13 @@ components: type: string example: urn:ietf:params:scim:schemas:core:2.0:User scim_schema: + examples: + - schemas: + - urn:ietf:params:scim:schemas:core:2.0:Schema + id: urn:ietf:params:scim:schemas:core:2.0:User + name: User + description: User Account + attributes: [] type: object properties: schemas: @@ -4036,6 +4189,28 @@ components: example: d80f7c79-7730-49d8-9a41-7c42fb622d9c description: The unique identifier for the user. A v4 UUID. scim_user: + examples: + - schemas: + - urn:ietf:params:scim:schemas:core:2.0:User + id: d80f7c79-7730-49d8-9a41-7c42fb622d9c + userName: jon.snow@docker.com + name: + givenName: Jon + familyName: Snow + displayName: jonsnow + active: true + emails: + - value: jon.snow@docker.com + display: jon.snow@docker.com + primary: true + groups: + - value: nightswatch + display: nightswatch + meta: + resourceType: User + location: https://hub.docker.com/v2/scim/2.0/Users/d80f7c79-7730-49d8-9a41-7c42fb622d9c + created: "2022-05-20T00:54:18Z" + lastModified: "2022-05-20T00:54:18Z" type: object properties: schemas: @@ -4156,6 +4331,19 @@ components: items: $ref: "#/components/schemas/orgAccessToken" getOrgAccessTokenResponse: + examples: + - id: a7a5ef25-8889-43a0-8cc7-f2a94268e861 + label: My organization token + created_by: johndoe + is_active: true + created_at: "2022-05-20T00:54:18Z" + expires_at: "2023-05-20T00:54:18Z" + last_used_at: "2022-06-15T12:30:45Z" + resources: + - type: TYPE_REPO + path: myorg/myrepo + scopes: + - scope-image-pull allOf: - $ref: "#/components/schemas/orgAccessToken" - type: object @@ -4166,6 +4354,14 @@ components: items: $ref: "#/components/schemas/orgAccessTokenResource" createOrgAccessTokenRequest: + examples: + - label: My organization token + description: Token for CI/CD pipeline + resources: + - type: TYPE_REPO + path: myorg/myrepo + scopes: + - scope-image-pull type: object properties: label: @@ -4191,6 +4387,19 @@ components: required: - label createOrgAccessTokenResponse: + examples: + - id: a7a5ef25-8889-43a0-8cc7-f2a94268e861 + label: My organization token + is_active: true + created_at: "2022-05-20T00:54:18Z" + expires_at: "2023-05-20T00:54:18Z" + last_used_at: "2022-06-15T12:30:45Z" + token: dckr_oat_7awgM4jG5SQvxcvmNzhKj8PQjxo + resources: + - type: TYPE_REPO + path: myorg/myrepo + scopes: + - scope-image-pull type: object allOf: - type: object @@ -4231,6 +4440,15 @@ components: items: $ref: "#/components/schemas/orgAccessTokenResource" updateOrgAccessTokenRequest: + examples: + - label: My organization token + description: Token for CI/CD pipeline + resources: + - type: TYPE_REPO + path: myorg/myrepo + scopes: + - scope-image-pull + is_active: true type: object properties: label: @@ -4251,6 +4469,19 @@ components: description: Whether the token is active example: true updateOrgAccessTokenResponse: + examples: + - id: a7a5ef25-8889-43a0-8cc7-f2a94268e861 + label: My organization token + created_by: johndoe + is_active: true + created_at: "2022-05-20T00:54:18Z" + expires_at: "2023-05-20T00:54:18Z" + last_used_at: "2022-06-15T12:30:45Z" + resources: + - type: TYPE_REPO + path: myorg/myrepo + scopes: + - scope-image-pull type: object allOf: - $ref: "#/components/schemas/orgAccessToken" @@ -4277,18 +4508,21 @@ components: - admin parameters: namespace: + description: Namespace of the repository, such as a user or organization name. in: path name: namespace required: true schema: type: string repository: + description: Name of the repository within the namespace. in: path name: repository required: true schema: type: string tag: + description: Name of the image tag. in: path name: tag required: true @@ -4358,6 +4592,7 @@ components: example: d80f7c79-7730-49d8-9a41-7c42fb622d9c required: true type: + description: Filter members by membership type. in: query name: type schema: @@ -4368,6 +4603,7 @@ components: - member example: all role: + description: Filter members by their organization role. in: query name: role schema: @@ -4389,6 +4625,15 @@ components: content: application/json: schema: + examples: + - org: docker + team: owners + role: member + invitees: + - invitee1DockerId + - invitee2@docker.com + - invitee3@docker.com + dry_run: true type: object required: - org @@ -4425,6 +4670,13 @@ components: content: application/scim+json: schema: + examples: + - schemas: + - urn:ietf:params:scim:schemas:core:2.0:User + userName: jon.snow@docker.com + name: + givenName: Jon + familyName: Snow type: object required: - schemas @@ -4460,6 +4712,8 @@ components: content: application/json: schema: + examples: + - member: jonsnow type: object required: - member diff --git a/content/reference/api/registry/latest.yaml b/content/reference/api/registry/latest.yaml index 809419006d80..3fa7e4baaa8a 100644 --- a/content/reference/api/registry/latest.yaml +++ b/content/reference/api/registry/latest.yaml @@ -989,7 +989,8 @@ paths: schema: type: string example: abc123 - - name: Authorization + - description: Bearer token for registry authentication. + name: Authorization in: header required: true schema: @@ -1067,7 +1068,8 @@ paths: schema: type: string example: sha256:abcd1234... - - name: Authorization + - description: Bearer token for registry authentication. + name: Authorization in: header required: true schema: @@ -1156,7 +1158,8 @@ paths: schema: type: string example: abc123 - - name: Authorization + - description: Bearer token for registry authentication. + name: Authorization in: header required: true schema: @@ -1249,7 +1252,8 @@ paths: schema: type: string example: abc123 - - name: Authorization + - description: Bearer token for registry authentication. + name: Authorization in: header required: true schema: diff --git a/hack/api-docs/README.md b/hack/api-docs/README.md index cb878e32e99b..84a6f0ac543c 100644 --- a/hack/api-docs/README.md +++ b/hack/api-docs/README.md @@ -68,16 +68,54 @@ $ ./hack/api-docs/run.sh check ``` Generation explicitly uses `--allow-known-issues`. The checked-in -`validation/known-issues.json` records 289 inherited issues: 268 for Hub, 17 for DVP, and -four for Registry. Entries match the entire source digest, diagnostic digest, +`validation/known-issues.json` records 168 remaining issues: 160 for Hub and eight +for DVP. Registry has no remaining baseline entries. Entries match the entire source digest, diagnostic digest, rule, and source pointer. Parse failures, unresolved references, and unsupported features cannot be waived. Unrecorded diagnostics fail the build. This baseline is review debt, not approval of API behavior. Strict validation fails until the issues are resolved. Any source edit requires deliberate review of the affected baseline entries; the build never refreshes them automatically. -The implementation PR tracks the product decisions that require confirmation -before merge. +Resolve the baseline before merging the implementation PR, then remove the +exception file and the generation override. A passing documentation check does +not settle the separate product decisions about authentication and response +contracts. + +### Issue triage + +The first pass resolved 121 of the original 289 entries: + +| Straightforward fix | Entries resolved | +| --- | ---: | +| Parameter descriptions derived from endpoint context and existing documentation | 43 | +| Quote the Hub and DVP 2FA examples to match their string schemas | 2 | +| Complete request and response examples using documented fields and values | 76 | + +Shared parameters and responses account for multiple entries. Examples use +existing field annotations where available; team requests and DVP namespace/year +responses use illustrative values. SCIM error examples contain the declared +schema identifier and status, without inventing service error messages. These +are documentation examples, not captured service responses. Example lookup also +needed a fix to retain annotations on intermediate schema references. + +The remaining entries need investigation before selecting a correction: + +| Area | Entries | Evidence or decision needed | +| --- | ---: | --- | +| Hub error responses | 128 | Review payloads for `Error`, `error`, `ValueError`, and `rpcStatus`, plus two responses without schemas. Establish which fields each error returns. Object schemas using `items` leave error-map values unconstrained. | +| Hub pagination | 10 | Resolve six null/string conflicts and supply four list examples. Confirm page-boundary values and keep counts, links, and result arrays consistent. | +| Hub repositories and tags | 8 | Confirm the immutable-tag regex contract and two repository examples missing required `user` and `permissions` fields. Complete five media examples after resolving those contracts. | +| Hub teams, members, and invitations | 8 | Check four team responses, the member response and list wrapper, the bulk-invitation wrapper, and CSV export. The export requires `Role` but defines `Permission`; its array schema also needs a representation suitable for CSV. | +| Hub personal token update | 1 | Confirm whether the update response returns or redacts the token. The shared schema has a token value, while the retrieval endpoint documents an empty string. | +| Hub SCIM | 5 | Verify list-envelope casing, service-provider capabilities, and update semantics before completing examples. The source uses `resources` in list responses and `enabled` in updates, while user objects use `active`. | +| DVP analytics | 8 | Obtain representative metadata, pull, and export-download payloads. Resolve overlapping month/week `oneOf` branches: neither branch requires its distinguishing property. | + +Counts include both missing examples and example/schema mismatches. The exact +locations remain in `validation/known-issues.json`; `check` writes diagnostics to +`tmp/api-reference/validation.json`. Repeated error responses are the largest +group, so investigate their shared schemas first. After each group is resolved, +validate its examples and remove its baseline entries. Do not replace a +conflicting example merely to make it pass, or loosen a schema without evidence. ## Tests and scope diff --git a/hack/api-docs/validation/known-issues.json b/hack/api-docs/validation/known-issues.json index 02617e123cc6..74ef42e60548 100644 --- a/hack/api-docs/validation/known-issues.json +++ b/hack/api-docs/validation/known-issues.json @@ -1,17 +1,7 @@ [ { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "example", - "pointer": "/components/schemas/Users2FALoginRequest/properties/code/example", - "messageSha256": "f524c4289cac4e74fc655a117925b19d205e8cf4a84d0e4eb580376857270d11", - "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", - "diagnostic": "jsonschema validation failed with 'source:hub#/components/schemas/Users2FALoginRequest/properties/code'\n- at '': got number, want string", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "example", "pointer": "/components/schemas/getAccessTokensResponse/properties/next/example", "messageSha256": "24b1ae1c7680ae4c77e6a2324f37604bae76ac9ec0005c305c53d25bf07d1de1", @@ -21,7 +11,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "example", "pointer": "/components/schemas/getAccessTokensResponse/properties/previous/example", "messageSha256": "70abcbf84044398b484ca7b512025a5f8e827352875dfc8e04071e76c195e4b0", @@ -31,7 +21,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "example", "pointer": "/components/schemas/immutable_tags_verify_request/properties/regex/example", "messageSha256": "c5e7204226bdc3c0252c721ed6ef8bcdd36f4f6f2e5a10c8a7da220e9fc8fa8c", @@ -41,7 +31,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "example", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/200/content/application~1json/schema/properties/next/example", "messageSha256": "c38485c83b9ebe4bca6b5ce33378e8b8fb1b8ec3d6c5edf1d0023bd44e4e2fd8", @@ -51,7 +41,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "example", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/200/content/application~1json/schema/properties/previous/example", "messageSha256": "b3f9ac6897f3b48d85c63dae690b86569e284aeed8ade6390c34f511496a93c1", @@ -61,7 +51,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "example", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/200/content/application~1json/schema/properties/next/example", "messageSha256": "5a161ce722f225c2468a5db8c0c3b9a7794e7847d24645bc11e219b182cd9996", @@ -71,7 +61,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "example", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/200/content/application~1json/schema/properties/previous/example", "messageSha256": "0afb130b19f561c0c4587e8d27ffbdce7c2c56b516dd609f9dad68c697ae68dd", @@ -81,7 +71,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "example", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/201/content/application~1json/example", "messageSha256": "1a244af81ade4ef2616b9ee5bf28edeed2bac6f56a35a4a58210ab73bf0ca6d7", @@ -91,7 +81,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "example", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/200/content/application~1json/example", "messageSha256": "e1b27ea692b2fda83285b9884f9f852d6c64f77f153e06138d27be7d958ffa16", @@ -101,27 +91,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1access-tokens/get/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1access-tokens/get/parameters/1/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1access-tokens/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -131,7 +101,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1access-tokens/get/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -141,7 +111,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1access-tokens/get/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -151,27 +121,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens/post/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens/post/responses/201/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1access-tokens/post/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -181,7 +131,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1access-tokens/post/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -191,27 +141,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1access-tokens~1{uuid}/get/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -221,7 +151,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1access-tokens~1{uuid}/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -231,17 +161,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1access-tokens~1{uuid}/delete/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -251,7 +171,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1access-tokens~1{uuid}/delete/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -261,27 +181,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -291,7 +191,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -301,7 +201,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -311,7 +211,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1auditlogs~1{account}/get/responses/500/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -321,7 +221,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1auditlogs~1{account}/get/responses/default/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -331,7 +231,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1auditlogs~1{account}~1actions/get/responses/500/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -341,7 +241,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1auditlogs~1{account}~1actions/get/responses/default/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -351,27 +251,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1auth~1token/post/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1auth~1token/post/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1auth~1token/post/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -381,17 +261,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1invites~1bulk/post/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1invites~1bulk/post/responses/202/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -401,7 +271,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1invites~1bulk/post/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -411,7 +281,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1invites~1bulk/post/responses/409/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -421,17 +291,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1invites~1{id}/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1invites~1{id}/delete/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -441,7 +301,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1invites~1{id}/delete/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -451,7 +311,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1invites~1{id}/delete/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -461,17 +321,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1invites~1{id}~1resend/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1invites~1{id}~1resend/patch/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -481,7 +331,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1invites~1{id}~1resend/patch/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -491,7 +341,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1invites~1{id}~1resend/patch/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -501,17 +351,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -521,7 +361,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -531,7 +371,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -541,17 +381,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -561,7 +391,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -571,7 +401,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -581,7 +411,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -591,7 +421,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/500/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -601,27 +431,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/parameters/1/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -631,7 +441,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -641,7 +451,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -651,7 +461,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/500/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -661,27 +471,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/parameters/1/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -691,7 +481,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -701,7 +491,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -711,7 +501,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/500/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -721,27 +511,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/parameters/1/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/requestBody/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -751,7 +521,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -761,7 +531,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -771,7 +541,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -781,7 +551,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -791,7 +561,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -801,27 +571,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/parameters/1/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/requestBody/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -831,17 +581,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -851,7 +591,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -861,7 +601,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -871,7 +611,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -881,27 +621,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/parameters/1/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -911,7 +631,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -921,7 +641,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -931,27 +651,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/parameters/1/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -961,7 +661,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -971,37 +671,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/parameters/1/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/parameters/2/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1011,7 +681,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1021,7 +691,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1031,37 +701,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/parameters/1/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/parameters/2/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1071,7 +711,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1081,27 +721,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/parameters/1/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1111,7 +731,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1121,7 +741,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1131,7 +751,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1141,9 +761,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/requestBody/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1151,9 +771,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/201/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1161,9 +781,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/400/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1171,9 +791,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/401/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1181,9 +801,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/403/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1191,9 +811,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/404/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1201,9 +821,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/200/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1211,9 +831,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/401/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1221,9 +841,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/403/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1231,9 +851,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/404/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1241,9 +861,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/requestBody/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1251,9 +871,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/200/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1261,9 +881,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/401/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1271,9 +891,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/403/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1281,9 +901,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/404/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1291,9 +911,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/200/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1301,9 +921,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/401/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1311,9 +931,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/403/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1321,9 +941,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/404/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1331,9 +951,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/responses/401/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1341,9 +961,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/responses/403/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1351,9 +971,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/responses/404/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1361,9 +981,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/requestBody/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1371,9 +991,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/200/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/201/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1381,9 +1001,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/401/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1391,9 +1011,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/403/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1401,9 +1021,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/404/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1411,9 +1031,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/200/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1421,9 +1041,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/401/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1431,9 +1051,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/403/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1441,9 +1061,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/404/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1451,9 +1071,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/requestBody/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1461,9 +1081,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/201/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1471,9 +1091,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/400/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1481,9 +1101,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/401/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1491,9 +1111,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/403/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1501,9 +1121,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/200/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1511,9 +1131,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/401/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1521,9 +1141,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/403/content/application~1json", + "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -1531,117 +1151,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1651,7 +1161,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1661,7 +1171,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1671,7 +1181,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1681,7 +1191,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1691,7 +1201,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1701,7 +1211,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1711,17 +1221,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1731,7 +1231,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1741,7 +1241,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1751,7 +1251,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/responses/500/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1761,7 +1261,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1771,7 +1271,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1781,7 +1281,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1791,17 +1291,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1811,7 +1301,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1821,7 +1311,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1831,27 +1321,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/parameters/5/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/parameters/6/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1861,7 +1331,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1871,7 +1341,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1881,7 +1351,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1891,7 +1361,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1901,7 +1371,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/200/content/text~1csv", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1911,7 +1381,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1921,7 +1391,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1931,7 +1401,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1941,7 +1411,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1951,17 +1421,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1971,7 +1431,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1981,7 +1441,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -1991,7 +1451,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -2001,7 +1461,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -2011,7 +1471,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -2021,7 +1481,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -2031,7 +1491,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -2041,7 +1501,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -2051,27 +1511,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/parameters/1/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/responses/400/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -2081,7 +1521,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/responses/401/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -2091,7 +1531,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/responses/403/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -2101,7 +1541,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/responses/404/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -2111,7 +1551,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/responses/200/content/application~1scim+json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -2121,77 +1561,7 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/responses/401/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/responses/500/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/responses/200/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/responses/401/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/responses/404/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes~1{name}/get/responses/500/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", "pointer": "/paths/~1v2~1scim~12.0~1Schemas/get/responses/200/content/application~1scim+json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", @@ -2201,39 +1571,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Schemas/get/responses/401/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Schemas/get/responses/500/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/responses/200/content/application~1scim+json", + "pointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/responses/200/content/application~1scim+json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -2241,9 +1581,9 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/responses/401/content/application~1scim+json", + "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/200/content/application~1scim+json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", @@ -2251,642 +1591,92 @@ }, { "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/responses/404/content/application~1scim+json", + "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/requestBody/content/application~1scim+json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", "ownerReview": "required" }, { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "api": "dvp", + "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Schemas~1{id}/get/responses/500/content/application~1scim+json", + "pointer": "/paths/~1namespaces/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", "ownerReview": "required" }, { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "api": "dvp", + "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/responses/200/content/application~1scim+json", + "pointer": "/paths/~1namespaces~1{namespace}/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", "ownerReview": "required" }, { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "api": "dvp", + "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/responses/401/content/application~1scim+json", + "pointer": "/paths/~1namespaces~1{namespace}~1pulls/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", "ownerReview": "required" }, { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "api": "dvp", + "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/responses/500/content/application~1scim+json", + "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years~1{year}~1{timespantype}/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", "ownerReview": "required" }, { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1scim~12.0~1Users/get/parameters/0/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1scim~12.0~1Users/get/parameters/1/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1scim~12.0~1Users/get/parameters/2/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S8", - "pointer": "/paths/~1v2~1scim~12.0~1Users/get/parameters/4/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "api": "dvp", + "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/200/content/application~1scim+json", + "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years~1{year}~1{timespantype}~1{timespan}/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", "ownerReview": "required" }, { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "api": "dvp", + "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/400/content/application~1scim+json", + "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years~1{year}~1{timespantype}~1{timespan}~1{dataview}/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", "ownerReview": "required" }, { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "api": "dvp", + "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/401/content/application~1scim+json", + "pointer": "/paths/~1namespaces~1{namespace}~1repos~1{repo}~1pulls/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", "ownerReview": "required" }, { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", + "api": "dvp", + "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/403/content/application~1scim+json", + "pointer": "/paths/~1repos~1pulls/get/responses/200/content/application~1json", "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/404/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/500/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/post/requestBody/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/201/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/400/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/401/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/403/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/404/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/409/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/post/responses/500/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/responses/200/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/responses/400/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/responses/401/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/responses/403/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/responses/404/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/get/responses/500/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/requestBody/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/200/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/400/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/401/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/403/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/404/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/409/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/responses/500/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1users~12fa-login/post/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1users~12fa-login/post/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1users~12fa-login/post/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1users~1login/post/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1users~1login/post/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "66915bfe9d67576c323ad221a0d953bff47d4bc7625722a99515c58e04937517", - "rule": "S11", - "pointer": "/paths/~1v2~1users~1login/post/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "example", - "pointer": "/components/schemas/Users2FALoginRequest/properties/code/example", - "messageSha256": "d216ebf62163620dd035cbcdc4bca82e17f62bd9e4e722a533dc171fd4eb7253", - "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", - "diagnostic": "jsonschema validation failed with 'source:dvp#/components/schemas/Users2FALoginRequest/properties/code'\n- at '': got number, want string", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1namespaces/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1namespaces~1{namespace}/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1namespaces~1{namespace}~1pulls/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years~1{year}~1{timespantype}/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years~1{year}~1{timespantype}~1{timespan}/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years~1{year}~1{timespantype}~1{timespan}~1{dataview}/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1namespaces~1{namespace}~1repos~1{repo}~1pulls/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1repos~1pulls/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1v2~1users~12fa-login/post/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1v2~1users~12fa-login/post/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1v2~1users~12fa-login/post/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1v2~1users~1login/post/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1v2~1users~1login/post/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "73858f23826bf049e375df4b5670c1815b517d96c339a3c7c75b1c79a2787010", - "rule": "S11", - "pointer": "/paths/~1v2~1users~1login/post/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "registry", - "sha256": "3257829998629249bd9bd27a79996f922169e0c98677b67fb1dc87f565391a01", - "rule": "S8", - "pointer": "/paths/~1v2~1{name}~1blobs~1uploads~1{uuid}/get/parameters/2/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "registry", - "sha256": "3257829998629249bd9bd27a79996f922169e0c98677b67fb1dc87f565391a01", - "rule": "S8", - "pointer": "/paths/~1v2~1{name}~1blobs~1uploads~1{uuid}/put/parameters/3/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "registry", - "sha256": "3257829998629249bd9bd27a79996f922169e0c98677b67fb1dc87f565391a01", - "rule": "S8", - "pointer": "/paths/~1v2~1{name}~1blobs~1uploads~1{uuid}/delete/parameters/2/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" - }, - { - "api": "registry", - "sha256": "3257829998629249bd9bd27a79996f922169e0c98677b67fb1dc87f565391a01", - "rule": "S8", - "pointer": "/paths/~1v2~1{name}~1blobs~1uploads~1{uuid}/patch/parameters/2/description", - "messageSha256": "4abc2b8c171a9f58475a0ee6f4a461b61b8acb5af0657064f5b4714cfa0516e7", - "reason": "Retain the source parameter definition; product documentation owner must add a meaningful description.", - "diagnostic": "Parameter description requires editorial review", - "ownerReview": "required" } ] From 51033c359de96930c8f224337b944cdea83d0a53 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 9 Sep 2026 13:35:14 +0000 Subject: [PATCH 12/13] docs: complete DVP response schemas and examples Correct object and null handling, distinguish month/week alternatives, and complete metadata definitions and response examples. Remove the remaining DVP validation exceptions and add regression coverage. Keep the tooling README focused on build commands, validation, and maintenance. --- content/reference/api/dvp/latest.yaml | 180 ++++++++++++++++++++- hack/api-docs/README.md | 64 ++------ hack/api-docs/main_test.go | 46 ++++++ hack/api-docs/validation/known-issues.json | 80 --------- 4 files changed, 233 insertions(+), 137 deletions(-) diff --git a/content/reference/api/dvp/latest.yaml b/content/reference/api/dvp/latest.yaml index 4e7e562fde51..292e2fe16c59 100644 --- a/content/reference/api/dvp/latest.yaml +++ b/content/reference/api/dvp/latest.yaml @@ -196,6 +196,25 @@ paths: type: array items: $ref: "#/components/schemas/NamespaceMetadata" + examples: + publishers: + summary: Namespace metadata + value: + - datasets: + - name: pulls + timespans: + - months + - weeks + views: + - raw + - summary + - repo-summary + - namespace-summary + - geo-repo-summary + extraRepos: null + namespace: org1 + publisherType: DVP + extensionPublisher: false "401": description: Authentication failed or second factor required /namespaces/{namespace}: @@ -447,6 +466,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ResponseData" + examples: + download: + summary: Illustrative download location + description: Use the signed URL returned by the API. The URL and file size in this example are illustrative. + value: + data: + - url: https://example.invalid/exports/pulls.csv.gz?X-Amz-Expires=21600&X-Amz-Signature=EXAMPLE + size: 1024 /repos/pulls: get: tags: @@ -571,17 +598,22 @@ components: properties: data: type: array - description: | - List of urls to download the data. When the data is large, the data will be split into multiple files. + description: Download URLs and file sizes for the export. items: $ref: "#/components/schemas/ResponseDataFile" + type: object + description: Download locations for the selected export. Large exports can span multiple files. ResponseDataFile: properties: url: type: string + format: uri + description: Signed download URL. URLs expire six hours after generation. size: type: integer format: int64 + description: Size of the file in bytes. + type: object NamespaceData: examples: - namespaces: @@ -591,18 +623,63 @@ components: type: array items: type: string + type: object NamespaceMetadata: properties: namespace: type: string extraRepos: - type: array + type: + - array + - "null" items: type: string + description: Additional repositories associated with the namespace. Null when none are configured. datasets: type: array items: $ref: "#/components/schemas/DatasetModel" + publisherType: + type: string + description: Publisher program associated with the namespace. + extensionPublisher: + type: boolean + description: Whether the namespace is an extension publisher. + type: object + examples: + - datasets: + - name: pulls + timespans: + - months + - weeks + views: + - raw + - summary + - repo-summary + - namespace-summary + - geo-repo-summary + extraRepos: null + namespace: org1 + publisherType: DVP + extensionPublisher: false + - datasets: + - name: pulls + timespans: + - months + - weeks + views: + - repo-summary + - namespace-summary + - name: extensions + timespans: + - months + - weeks + views: + - ext-summary + extraRepos: null + namespace: org4 + publisherType: DVP + extensionPublisher: true DatasetModel: properties: name: @@ -615,34 +692,88 @@ components: type: array items: $ref: "#/components/schemas/TimespanType" + type: object + description: Datasets and views available to the publisher, based on its entitlements. PullData: properties: pulls: - type: array + type: + - array + - "null" items: $ref: "#/components/schemas/PullModel" + description: Pull statistics for the selected interval. Null when no records are returned. + type: object + examples: + - pulls: + - end: "2022-08-07T00:00:00Z" + pullCount: 11 + repo: neo4j-admin + start: "2022-08-01T00:00:00Z" + ipCount: 10 + - end: "2022-08-14T00:00:00Z" + pullCount: 11 + repo: neo4j-admin + start: "2022-08-08T00:00:00Z" + ipCount: 10 + - pulls: null ReposPullData: properties: repos: type: object additionalProperties: $ref: "#/components/schemas/PullData" + type: object + examples: + - repos: + org2/neo4j-admin: + pulls: + - end: "2022-08-07T00:00:00Z" + pullCount: 11 + repo: neo4j-admin + start: "2022-08-01T00:00:00Z" + ipCount: 10 + - end: "2022-08-14T00:00:00Z" + pullCount: 11 + repo: neo4j-admin + start: "2022-08-08T00:00:00Z" + ipCount: 10 + org2/neo4j: + pulls: + - end: "2022-08-07T00:00:00Z" + pullCount: 272407 + repo: neo4j + start: "2022-08-01T00:00:00Z" + ipCount: 41490 + - end: "2022-08-14T00:00:00Z" + pullCount: 272407 + repo: neo4j + start: "2022-08-08T00:00:00Z" + ipCount: 41490 PullModel: properties: start: type: string + format: date-time + description: Start of the reporting interval in RFC 3339 format. end: type: string + format: date-time + description: End of the reporting interval in RFC 3339 format. repo: type: string + description: Repository name. Present for results grouped by repository. namespace: type: string + description: Namespace name. Present for results grouped by namespace. pullCount: type: integer ipCount: type: integer country: type: string + description: Country. Present for results grouped by geography and repository. + type: object YearData: examples: - years: @@ -652,30 +783,56 @@ components: type: array items: $ref: "#/components/schemas/YearModel" + type: object YearModel: properties: year: type: integer + type: object MonthData: properties: months: type: array items: $ref: "#/components/schemas/MonthModel" + type: object + required: + - months + examples: + - months: + - month: 5 + - month: 7 MonthModel: properties: month: type: integer + type: object + required: + - month + examples: + - month: 7 WeekData: properties: weeks: type: array items: $ref: "#/components/schemas/WeekModel" + type: object + required: + - weeks + examples: + - weeks: + - week: 31 + - week: 32 WeekModel: properties: week: type: integer + type: object + required: + - week + examples: + - week: 31 TimespanType: type: string enum: @@ -695,18 +852,33 @@ components: - summary - repo-summary - namespace-summary + - geo-repo-summary + - ext-summary + - ext-premium-summary + - ext-premium-geo DatasetType: type: string enum: - pulls + - extensions TimespanModel: oneOf: - $ref: "#/components/schemas/MonthModel" - $ref: "#/components/schemas/WeekModel" + examples: + - month: 7 + - week: 31 TimespanData: oneOf: - $ref: "#/components/schemas/MonthData" - $ref: "#/components/schemas/WeekData" + examples: + - months: + - month: 5 + - month: 7 + - weeks: + - week: 31 + - week: 32 GroupType: type: string enum: diff --git a/hack/api-docs/README.md b/hack/api-docs/README.md index 84a6f0ac543c..2f85bdce7f40 100644 --- a/hack/api-docs/README.md +++ b/hack/api-docs/README.md @@ -56,8 +56,7 @@ other pages; links that already use published URLs remain unchanged. The published YAML URLs still serve the source files directly. There is no conversion step, snapshot dependency, Node migration package, or source archive -in the build. The source diff and -[prototype PR](https://github.com/docker/docs/pull/26043) provide migration context. +in the build. ## Validation baseline @@ -67,55 +66,15 @@ in the build. The source diff and $ ./hack/api-docs/run.sh check ``` -Generation explicitly uses `--allow-known-issues`. The checked-in -`validation/known-issues.json` records 168 remaining issues: 160 for Hub and eight -for DVP. Registry has no remaining baseline entries. Entries match the entire source digest, diagnostic digest, -rule, and source pointer. Parse failures, unresolved references, and unsupported -features cannot be waived. Unrecorded diagnostics fail the build. - -This baseline is review debt, not approval of API behavior. Strict validation -fails until the issues are resolved. Any source edit requires deliberate review -of the affected baseline entries; the build never refreshes them automatically. -Resolve the baseline before merging the implementation PR, then remove the -exception file and the generation override. A passing documentation check does -not settle the separate product decisions about authentication and response -contracts. - -### Issue triage - -The first pass resolved 121 of the original 289 entries: - -| Straightforward fix | Entries resolved | -| --- | ---: | -| Parameter descriptions derived from endpoint context and existing documentation | 43 | -| Quote the Hub and DVP 2FA examples to match their string schemas | 2 | -| Complete request and response examples using documented fields and values | 76 | - -Shared parameters and responses account for multiple entries. Examples use -existing field annotations where available; team requests and DVP namespace/year -responses use illustrative values. SCIM error examples contain the declared -schema identifier and status, without inventing service error messages. These -are documentation examples, not captured service responses. Example lookup also -needed a fix to retain annotations on intermediate schema references. - -The remaining entries need investigation before selecting a correction: - -| Area | Entries | Evidence or decision needed | -| --- | ---: | --- | -| Hub error responses | 128 | Review payloads for `Error`, `error`, `ValueError`, and `rpcStatus`, plus two responses without schemas. Establish which fields each error returns. Object schemas using `items` leave error-map values unconstrained. | -| Hub pagination | 10 | Resolve six null/string conflicts and supply four list examples. Confirm page-boundary values and keep counts, links, and result arrays consistent. | -| Hub repositories and tags | 8 | Confirm the immutable-tag regex contract and two repository examples missing required `user` and `permissions` fields. Complete five media examples after resolving those contracts. | -| Hub teams, members, and invitations | 8 | Check four team responses, the member response and list wrapper, the bulk-invitation wrapper, and CSV export. The export requires `Role` but defines `Permission`; its array schema also needs a representation suitable for CSV. | -| Hub personal token update | 1 | Confirm whether the update response returns or redacts the token. The shared schema has a token value, while the retrieval endpoint documents an empty string. | -| Hub SCIM | 5 | Verify list-envelope casing, service-provider capabilities, and update semantics before completing examples. The source uses `resources` in list responses and `enabled` in updates, while user objects use `active`. | -| DVP analytics | 8 | Obtain representative metadata, pull, and export-download payloads. Resolve overlapping month/week `oneOf` branches: neither branch requires its distinguishing property. | - -Counts include both missing examples and example/schema mismatches. The exact -locations remain in `validation/known-issues.json`; `check` writes diagnostics to -`tmp/api-reference/validation.json`. Repeated error responses are the largest -group, so investigate their shared schemas first. After each group is resolved, -validate its examples and remove its baseline entries. Do not replace a -conflicting example merely to make it pass, or loosen a schema without evidence. +Generation uses `--allow-known-issues`. The checked-in +`validation/known-issues.json` records explicit exceptions for unresolved Hub +diagnostics. Entries match the source digest, diagnostic digest, rule, and source +pointer. Parse failures, unresolved references, and unsupported features cannot +be waived. Unrecorded diagnostics fail the build. + +Strict validation reports all diagnostics, including recorded exceptions. +Reports are written to `tmp/api-reference/validation.json`. The build never +refreshes the baseline automatically. ## Tests and scope @@ -127,5 +86,4 @@ published specifications. `browser-checks.mjs` exports a Playwright check for navigation, page aliases, filtering, requests, and narrow screens. Callbacks and webhook navigation are unsupported and fail validation. Request -examples are POSIX shell templates; they do not make service calls. Specification -conversion and source-owner adoption remain separate from page rendering. +examples are POSIX shell templates; they do not make service calls. diff --git a/hack/api-docs/main_test.go b/hack/api-docs/main_test.go index ee815f37d8d1..7fe6ec3eea16 100644 --- a/hack/api-docs/main_test.go +++ b/hack/api-docs/main_test.go @@ -209,6 +209,52 @@ func TestMediaExamplesFollowReferenceAnnotations(t *testing.T) { } } +func TestDVPResponseContracts(t *testing.T) { + d, err := loadDocument(filepath.Join("..", "..", "content", "reference", "api", "dvp", "latest.yaml"), "validation/dialects") + if err != nil { + t.Fatal(err) + } + d.Source = Source{ID: "dvp"} + d.validate("") + if len(d.Diagnostics) != 0 { + t.Fatalf("DVP must pass without exceptions: %+v", d.Diagnostics) + } + for _, tc := range []struct { + schema string + value string + valid bool + }{ + {"TimespanModel", `{"month":7}`, true}, + {"TimespanModel", `{"week":31}`, true}, + {"TimespanModel", `{}`, false}, + {"TimespanModel", `{"month":7,"week":31}`, false}, + {"TimespanModel", `{"month":{"month":7}}`, false}, + {"TimespanModel", `7`, false}, + {"TimespanData", `{"months":[{"month":5},{"month":7}]}`, true}, + {"TimespanData", `{"weeks":[]}`, true}, + {"TimespanData", `{"months":[],"weeks":[]}`, false}, + {"TimespanData", `{"months":[{}]}`, false}, + {"TimespanData", `{"weeks":null}`, false}, + {"NamespaceMetadata", `{"namespace":"org1","extraRepos":null,"extensionPublisher":false}`, true}, + {"PullData", `{"pulls":null}`, true}, + {"PullData", `{"pulls":[{"start":"2022-08-01T00:00:00Z","pullCount":0}]}`, true}, + } { + t.Run(tc.schema+"/"+tc.value, func(t *testing.T) { + s, err := d.Compiler.Compile(d.URI + "#/components/schemas/" + tc.schema) + if err != nil { + t.Fatal(err) + } + value, err := js.UnmarshalJSON(strings.NewReader(tc.value)) + if err != nil { + t.Fatal(err) + } + if err := s.Validate(value); (err == nil) != tc.valid { + t.Fatalf("valid = %t, want %t: %v", err == nil, tc.valid, err) + } + }) + } +} + func TestTimestampStringsRetainSpelling(t *testing.T) { p := filepath.Join(t.TempDir(), "schema.yaml") if e := os.WriteFile(p, []byte("type: string\nexample: 2021-01-05T21:06:53.506400Z\n"), 0600); e != nil { diff --git a/hack/api-docs/validation/known-issues.json b/hack/api-docs/validation/known-issues.json index 74ef42e60548..1c025cf574a8 100644 --- a/hack/api-docs/validation/known-issues.json +++ b/hack/api-docs/validation/known-issues.json @@ -1598,85 +1598,5 @@ "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", "diagnostic": "Media variant needs a reviewed example or transfer fixture", "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", - "rule": "S11", - "pointer": "/paths/~1namespaces/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", - "rule": "S11", - "pointer": "/paths/~1namespaces~1{namespace}/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", - "rule": "S11", - "pointer": "/paths/~1namespaces~1{namespace}~1pulls/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", - "rule": "S11", - "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years~1{year}~1{timespantype}/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", - "rule": "S11", - "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years~1{year}~1{timespantype}~1{timespan}/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", - "rule": "S11", - "pointer": "/paths/~1namespaces~1{namespace}~1pulls~1exports~1years~1{year}~1{timespantype}~1{timespan}~1{dataview}/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", - "rule": "S11", - "pointer": "/paths/~1namespaces~1{namespace}~1repos~1{repo}~1pulls/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "dvp", - "sha256": "5789e35fd48f88ede3d1e7f3c11b8f3f0fea9ba17e6705e2244423dd2b9f9377", - "rule": "S11", - "pointer": "/paths/~1repos~1pulls/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" } ] From 390c5a093e4ba195209e434b63da9dd4d6d5e5d6 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 9 Sep 2026 14:01:11 +0000 Subject: [PATCH 13/13] docs: complete local API contracts and require strict validation Correct Hub response shapes, nullable fields, token examples, and SCIM contracts. Keep Registry scoped to its documented endpoints while expressing authentication and media negotiation through OpenAPI fields. Remove the validation exception baseline, render text examples without JSON escaping, and verify corrected contracts and HTML/Markdown example parity. --- content/reference/api/hub/latest.yaml | 714 ++++++--- content/reference/api/registry/latest.yaml | 118 +- hack/api-docs/README.md | 18 +- hack/api-docs/contracts_test.go | 125 ++ hack/api-docs/main.go | 87 +- hack/api-docs/main_test.go | 6 +- hack/api-docs/model.go | 42 +- hack/api-docs/run.sh | 2 +- hack/api-docs/testdata/valid.yaml | 69 +- hack/api-docs/validation/known-issues.json | 1602 -------------------- hack/api-docs/verify-output.mjs | 10 +- layouts/api-docs.html | 8 +- layouts/api-docs.markdown.md | 7 +- 13 files changed, 797 insertions(+), 2011 deletions(-) create mode 100644 hack/api-docs/contracts_test.go delete mode 100644 hack/api-docs/validation/known-issues.json diff --git a/content/reference/api/hub/latest.yaml b/content/reference/api/hub/latest.yaml index 473731cdc6a3..05ce1e7e3de6 100644 --- a/content/reference/api/hub/latest.yaml +++ b/content/reference/api/hub/latest.yaml @@ -414,7 +414,7 @@ paths: last_used: null generated_by: manual is_active: true - token: "" + token: "***" token_label: My read only token scopes: - repo:read @@ -425,7 +425,7 @@ paths: properties: token: type: string - example: "" + example: "***" "401": $ref: "#/components/responses/Unauthorized" "404": @@ -725,13 +725,26 @@ paths: description: "" content: application/json: - schema: {} + schema: + $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: internal error + errinfo: null default: description: An unexpected error response. content: application/json: schema: - $ref: "#/components/schemas/rpcStatus" + $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: internal error + errinfo: null parameters: - name: account description: Namespace to query audit log actions for. @@ -799,13 +812,26 @@ paths: description: "" content: application/json: - schema: {} + schema: + $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: internal error + errinfo: null default: description: An unexpected error response. content: application/json: schema: - $ref: "#/components/schemas/rpcStatus" + $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: internal error + errinfo: null parameters: - name: account description: Namespace to query audit logs for. @@ -1283,6 +1309,12 @@ paths: application/json: schema: $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: bad request + errinfo: null "401": $ref: "#/components/responses/unauthorized" "403": @@ -1439,6 +1471,12 @@ paths: application/json: schema: $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: not found + errinfo: null post: summary: Create a new repository description: |+ @@ -1482,8 +1520,8 @@ paths: is_automated: false star_count: 0 pull_count: 0 - last_updated: 2025-01-20T10:30:00Z - date_registered: 2025-01-20T10:30:00Z + last_updated: "2025-01-20T10:30:00Z" + date_registered: "2025-01-20T10:30:00Z" collaborator_count: 0 hub_user: myorganization has_starred: false @@ -1496,6 +1534,11 @@ paths: rules: [] storage_size: null source: null + user: myorganization + permissions: + read: true + write: true + admin: true "400": $ref: "#/components/responses/bad_request" "401": @@ -1541,8 +1584,8 @@ paths: is_automated: false star_count: 0 pull_count: 0 - last_updated: 2025-01-20T10:30:00Z - date_registered: 2025-01-20T10:30:00Z + last_updated: "2025-01-20T10:30:00Z" + date_registered: "2025-01-20T10:30:00Z" collaborator_count: 0 hub_user: myorganization has_starred: false @@ -1555,6 +1598,11 @@ paths: rules: [] storage_size: null source: null + user: myorganization + permissions: + read: true + write: true + admin: true "401": $ref: "#/components/responses/unauthorized" "403": @@ -1620,9 +1668,7 @@ paths: content: application/json: schema: - type: array - items: - $ref: "#/components/schemas/org_member_paginated" + $ref: "#/components/schemas/org_member_paginated" "400": $ref: "#/components/responses/bad_request" "401": @@ -1651,46 +1697,11 @@ paths: content: text/csv: schema: - type: array - items: - type: object - required: - - Name - - Username - - Email - - Type - - Role - - Date Joined - properties: - Name: - type: string - description: First and last name of the member - Username: - type: string - description: Username of the member - Email: - type: string - description: Email address of the member - Type: - type: string - description: Type of the member - enum: - - Invitee - - User - Permission: - type: string - description: Permission of the member - enum: - - Owner - - Member - Teams: - type: string - description: Comma-separated list of teams the member is part of - example: team-1, team-2 - Date Joined: - type: string - description: Date the member joined the organization - example: 2020-01-01 15:00:51.193355 +0000 UTC + type: string + description: "CSV columns: Name, Username, Email, Type, Role, Teams, and Date Joined. The Role column contains the assigned role label. When administrative insights are available, the export also includes Last Logged-in Date, Docker Desktop Version, Last Seen Date, and Opted Out Analytics." + example: | + Name,Username,Email,Type,Role,Teams,Date Joined + Jon Snow,dockeruser,example@docker.com,User,Owner,owners,2021-01-05 21:06:53.5064 +0000 UTC headers: Content-Disposition: schema: @@ -1853,15 +1864,31 @@ paths: type: number example: 1 next: - type: string + type: + - string + - "null" example: null previous: - type: string + type: + - string + - "null" example: null results: type: array items: $ref: "#/components/schemas/org_group" + type: object + examples: + - count: 1 + next: null + previous: null + results: + - id: 10 + uuid: e36eca69-4cc8-4f17-9845-ae8c2b832691 + name: developers + description: Development team + member_count: 1 + role: member "401": $ref: "#/components/responses/unauthorized" "403": @@ -2059,15 +2086,31 @@ paths: type: number example: 1 next: - type: string + type: + - string + - "null" example: null previous: - type: string + type: + - string + - "null" example: null results: type: array items: $ref: "#/components/schemas/group_member" + type: object + examples: + - count: 1 + next: null + previous: null + results: + - id: 0ab70deb065a43fcacd55d48caa945d8 + username: dockeruser + full_name: Jon Snow + type: User + date_joined: "2021-01-05T21:06:53.506400Z" + email: example@docker.com "401": $ref: "#/components/responses/unauthorized" "403": @@ -2202,10 +2245,7 @@ paths: content: application/json: schema: - type: object - properties: - invitees: - $ref: "#/components/schemas/bulk_invite" + $ref: "#/components/schemas/bulk_invite" "400": $ref: "#/components/responses/bad_request" "409": @@ -2488,25 +2528,49 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ValueError" + $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: bad request + errinfo: null Unauthorized: description: Unauthorized content: application/json: schema: - $ref: "#/components/schemas/Error" + $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: unauthorized + errinfo: null Forbidden: description: Forbidden content: application/json: schema: - $ref: "#/components/schemas/Error" + $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: permission denied + errinfo: null NotFound: description: Not Found content: application/json: schema: - $ref: "#/components/schemas/Error" + $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: not found + errinfo: null list_tags: description: list repository tags content: @@ -2525,36 +2589,72 @@ components: application/json: schema: $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: bad request + errinfo: null unauthorized: description: Unauthorized content: application/json: schema: $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: unauthorized + errinfo: null forbidden: description: Forbidden content: application/json: schema: $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: permission denied + errinfo: null not_found: description: Not Found content: application/json: schema: $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: not found + errinfo: null conflict: description: Conflict content: application/json: schema: $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: conflict + errinfo: null internal_error: description: Internal content: application/json: schema: $ref: "#/components/schemas/error" + examples: + error: + summary: Example error response + value: + message: internal error + errinfo: null scim_bad_request: description: Bad Request content: @@ -2681,10 +2781,22 @@ components: totalResults: type: integer example: 1 - resources: + Resources: type: array items: $ref: "#/components/schemas/scim_resource_type" + examples: + - schemas: + - urn:ietf:params:scim:api:messages:2.0:ListResponse + totalResults: 1 + Resources: + - schemas: + - urn:ietf:params:scim:schemas:core:2.0:ResourceType + id: User + name: User + description: User + endpoint: /Users + schema: urn:ietf:params:scim:schemas:core:2.0:User scim_get_resource_type_resp: description: "" content: @@ -2706,10 +2818,21 @@ components: totalResults: type: integer example: 1 - resources: + Resources: type: array items: $ref: "#/components/schemas/scim_schema" + examples: + - schemas: + - urn:ietf:params:scim:api:messages:2.0:ListResponse + totalResults: 1 + Resources: + - schemas: + - urn:ietf:params:scim:schemas:core:2.0:Schema + id: urn:ietf:params:scim:schemas:core:2.0:User + name: User + description: User Account + attributes: [] scim_get_schema_resp: description: "" content: @@ -2738,10 +2861,38 @@ components: itemsPerPage: type: integer example: 10 - resources: + Resources: type: array items: $ref: "#/components/schemas/scim_user" + examples: + - schemas: + - urn:ietf:params:scim:api:messages:2.0:ListResponse + totalResults: 1 + Resources: + - schemas: + - urn:ietf:params:scim:schemas:core:2.0:User + id: d80f7c79-7730-49d8-9a41-7c42fb622d9c + userName: jon.snow@docker.com + name: + givenName: Jon + familyName: Snow + displayName: jonsnow + active: true + emails: + - value: jon.snow@docker.com + display: jon.snow@docker.com + primary: true + groups: + - value: nightswatch + display: nightswatch + meta: + resourceType: User + location: https://hub.docker.com/v2/scim/2.0/Users/d80f7c79-7730-49d8-9a41-7c42fb622d9c + created: "2022-05-20T00:54:18Z" + lastModified: "2022-05-20T00:54:18Z" + startIndex: 1 + itemsPerPage: 1 scim_create_user_resp: description: "" content: @@ -2790,6 +2941,11 @@ components: required: - immutable_tags - immutable_tags_rules + examples: + - immutable_tags: true + immutable_tags_rules: + - v.* + - .*-RELEASE repo_creation_request: type: object required: @@ -2915,19 +3071,19 @@ components: last_updated: type: string format: date-time - example: 2021-01-05T21:06:53.506400Z + example: "2021-01-05T21:06:53.506400Z" description: ISO 8601 timestamp of when repository was last updated last_modified: type: - string - "null" format: date-time - example: 2021-01-05T21:06:53.506400Z + example: "2021-01-05T21:06:53.506400Z" description: ISO 8601 timestamp of when repository was last modified date_registered: type: string format: date-time - example: 2021-01-05T21:06:53.506400Z + example: "2021-01-05T21:06:53.506400Z" description: ISO 8601 timestamp of when repository was created collaborator_count: type: integer @@ -3003,6 +3159,36 @@ components: - content_types - categories - immutable_tags_settings + examples: + - name: my-app + namespace: myorganization + repository_type: image + status: 1 + status_description: Active + description: A sample application repository + is_private: false + is_automated: false + star_count: 0 + pull_count: 0 + last_updated: "2025-01-20T10:30:00Z" + date_registered: "2025-01-20T10:30:00Z" + collaborator_count: 0 + hub_user: myorganization + has_starred: false + full_description: This is a comprehensive description of my application repository that contains additional details about the project. + media_types: [] + content_types: [] + categories: [] + immutable_tags_settings: + enabled: false + rules: [] + storage_size: null + source: null + user: myorganization + permissions: + read: true + write: true + admin: true repo_permissions: type: object properties: @@ -3038,11 +3224,13 @@ components: properties: regex: type: string - pattern: ^[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*(\\/[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*)*$ - description: "Immutable tags rule regex pattern. Must match format: [a-z0-9]+((\\\\.|_|__|-+)[a-z0-9]+)*(\\\\/[a-z0-9]+((\\\\.|_|__|-+)[a-z0-9]+)*)*" + pattern: ^[^,]*$ + description: Regular expression using Go regular expression syntax. Commas are not permitted. example: v.* required: - regex + examples: + - regex: v.* immutable_tags_verify_response: examples: - tags: @@ -3278,26 +3466,6 @@ components: description: Description of the error. type: string example: Incorrect authentication credentials - protobufAny: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - rpcStatus: - type: object - properties: - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - $ref: "#/components/schemas/protobufAny" AuditLogAction: type: object properties: @@ -3361,23 +3529,6 @@ components: action_description: type: string description: Audit log event. - ValueError: - type: object - description: Used to error if input validation fails. - properties: - fields: - type: object - items: - type: string - text: - type: string - Error: - type: object - properties: - detail: - type: string - message: - type: string accessToken: type: object properties: @@ -3395,7 +3546,7 @@ components: example: some user agent created_at: type: string - example: 2021-07-20T12:00:00.000000Z + example: "2021-07-20T12:00:00.000000Z" last_used: type: - string @@ -3410,6 +3561,7 @@ components: token: type: string example: a7a5ef25-8889-43a0-8cc7-f2a94268e861 + description: Token value returned on creation. Later responses redact the value as ***. token_label: type: string example: My read only token @@ -3420,9 +3572,11 @@ components: items: type: string expires_at: - type: string + type: + - string + - "null" format: date-time - example: 2021-10-28T18:30:19.520861Z + example: "2021-10-28T18:30:19.520861Z" createAccessTokenRequest: examples: - token_label: My read only token @@ -3477,10 +3631,14 @@ components: type: number example: 1 next: - type: string + type: + - string + - "null" example: null previous: - type: string + type: + - string + - "null" example: null active_count: type: number @@ -3494,7 +3652,26 @@ components: properties: token: type: string - example: "" + example: "***" + examples: + - count: 1 + active_count: 1 + next: null + previous: null + results: + - uuid: b30bbf97-506c-4ecd-aabc-842f3cb484fb + client_id: HUB + creator_ip: 127.0.0.1 + creator_ua: some user agent + created_at: "2021-07-20T12:00:00.000000Z" + last_used: null + generated_by: manual + is_active: true + token: "***" + token_label: My read only token + scopes: + - repo:read + expires_at: "2021-10-28T18:30:19.520861Z" patchAccessTokenRequest: examples: - token_label: My read only token @@ -3511,6 +3688,20 @@ components: example: false patchAccessTokenResponse: $ref: "#/components/schemas/accessToken" + examples: + - uuid: b30bbf97-506c-4ecd-aabc-842f3cb484fb + client_id: HUB + creator_ip: 127.0.0.1 + creator_ua: some user agent + created_at: "2021-07-20T12:00:00.000000Z" + last_used: null + generated_by: manual + is_active: true + token: "***" + token_label: My read only token + scopes: + - repo:read + expires_at: "2021-10-28T18:30:19.520861Z" orgSettings: examples: - restricted_images: @@ -3557,10 +3748,14 @@ components: type: string description: CPU architecture features: - type: string + type: + - string + - "null" description: CPU features variant: - type: string + type: + - string + - "null" description: CPU variant digest: type: @@ -3575,10 +3770,14 @@ components: type: string description: operating system os_features: - type: string + type: + - string + - "null" description: OS features os_version: - type: string + type: + - string + - "null" description: OS version size: type: integer @@ -3593,13 +3792,13 @@ components: type: - string - "null" - example: 2021-01-05T21:06:53.506400Z + example: "2021-01-05T21:06:53.506400Z" description: datetime of last pull last_pushed: type: - string - "null" - example: 2021-01-05T21:06:53.506400Z + example: "2021-01-05T21:06:53.506400Z" description: datetime of last push tag: type: object @@ -3608,8 +3807,11 @@ components: type: integer description: tag ID images: - type: object - $ref: "#/components/schemas/image" + type: + - array + - "null" + items: + $ref: "#/components/schemas/image" creator: type: integer description: ID of the user that pushed the tag @@ -3617,7 +3819,7 @@ components: type: - string - "null" - example: 2021-01-05T21:06:53.506400Z + example: "2021-01-05T21:06:53.506400Z" description: datetime of last update last_updater: type: integer @@ -3635,26 +3837,50 @@ components: type: integer description: compressed size (sum of all layers) of the tagged image v2: - type: string - description: repository API version - status: - type: string - enum: - - active - - inactive - description: whether a tag has been pushed to or pulled in the past month + type: boolean + description: Whether the tag uses the Registry V2 format. tag_last_pulled: type: - string - "null" - example: 2021-01-05T21:06:53.506400Z + example: "2021-01-05T21:06:53.506400Z" description: datetime of last pull tag_last_pushed: type: - string - "null" - example: 2021-01-05T21:06:53.506400Z + example: "2021-01-05T21:06:53.506400Z" description: datetime of last push + tag_status: + type: string + enum: + - active + - inactive + description: whether a tag has been pushed to or pulled in the past month + examples: + - id: 12345 + name: latest + last_updated: "2021-01-05T21:06:53.506400Z" + full_size: 123456 + v2: true + images: + - architecture: amd64 + features: null + variant: null + os: linux + os_features: null + os_version: null + size: 123456 + status: active + last_pulled: null + last_pushed: "2021-01-05T21:06:53.506400Z" + creator: 1234 + last_updater: 1234 + last_updater_username: dockeruser + repository: 5678 + tag_status: active + tag_last_pulled: null + tag_last_pushed: "2021-01-05T21:06:53.506400Z" paginated_tags: allOf: - $ref: "#/components/schemas/page" @@ -3664,6 +3890,34 @@ components: type: array items: $ref: "#/components/schemas/tag" + examples: + - count: 1 + next: null + previous: null + results: + - id: 12345 + name: latest + last_updated: "2021-01-05T21:06:53.506400Z" + full_size: 123456 + v2: true + images: + - architecture: amd64 + features: null + variant: null + os: linux + os_features: null + os_version: null + size: 123456 + status: active + last_pulled: null + last_pushed: "2021-01-05T21:06:53.506400Z" + creator: 1234 + last_updater: 1234 + last_updater_username: dockeruser + repository: 5678 + tag_status: active + tag_last_pulled: null + tag_last_pushed: "2021-01-05T21:06:53.506400Z" page: type: object properties: @@ -3785,13 +4039,16 @@ components: type: object properties: errinfo: - type: object - items: - type: string + type: + - object + - "null" + additionalProperties: true + description: Additional error context, when available. detail: type: string message: type: string + description: Error details vary by endpoint. The message describes the failure; errinfo can contain additional context. scim_error: type: object properties: @@ -3876,25 +4133,40 @@ components: example: example@docker.com deprecated: true last_logged_in_at: - type: string + type: + - string + - "null" format: date-time description: | - Last time the user logged in. To access this field, you must have insights visible for your organization. See + Last time the user logged in. To access this field, you must have insights visible for your organization. See [Insights](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). - example: 2021-01-05T21:06:53.506400Z + example: "2021-01-05T21:06:53.506400Z" last_seen_at: - type: string + type: + - string + - "null" format: date-time description: | - Last time the user was seen. To access this field, you must have insights visible for your organization. See + Last time the user was seen. To access this field, you must have insights visible for your organization. See [Insights](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). - example: 2021-01-05T21:06:53.506400Z + example: "2021-01-05T21:06:53.506400Z" last_desktop_version: type: string description: | - Last desktop version the user used. To access this field, you must have insights visible for your organization. See + Last desktop version the user used. To access this field, you must have insights visible for your organization. See [Insights](https://docs.docker.com/admin/insights/#view-insights-for-organization-users). example: 4.29.0 + examples: + - id: 0ab70deb065a43fcacd55d48caa945d8 + username: dockeruser + full_name: Jon Snow + type: User + date_joined: "2021-01-05T21:06:53.506400Z" + email: example@docker.com + role: Owner + groups: + - owners + is_guest: false org_member_paginated: type: object properties: @@ -3903,18 +4175,37 @@ components: description: The total number of items that match with the search. example: 120 previous: - type: string + type: + - string + - "null" description: The URL or link for the previous page of items. - example: https://hub.docker.com/v2/some/resources/items?page=1&page_size=20 + example: null next: - type: string + type: + - string + - "null" description: The URL or link for the next page of items. - example: https://hub.docker.com/v2/some/resources/items?page=3&page_size=20 + example: null results: type: array description: List of accounts. items: $ref: "#/components/schemas/org_member" + examples: + - count: 1 + next: null + previous: null + results: + - id: 0ab70deb065a43fcacd55d48caa945d8 + username: dockeruser + full_name: Jon Snow + type: User + date_joined: "2021-01-05T21:06:53.506400Z" + email: example@docker.com + role: Owner + groups: + - owners + is_guest: false org_group: type: object properties: @@ -3938,10 +4229,19 @@ components: example: 10 description: Member count of the group role: - type: string + type: + - string + - "null" description: | Role assigned to the team. A core role (`owner`, `editor`, or `member`) or the name of a custom role (not the label or UUID). + examples: + - id: 10 + uuid: e36eca69-4cc8-4f17-9845-ae8c2b832691 + name: developers + description: Development team + member_count: 1 + role: member group_member: type: object properties: @@ -4025,7 +4325,8 @@ components: properties: supported: type: boolean - example: false + example: true + type: object bulk: type: object properties: @@ -4044,7 +4345,7 @@ components: example: true maxResults: type: integer - example: 99999 + example: 200 changePassword: type: object properties: @@ -4064,20 +4365,44 @@ components: type: boolean example: false authenticationSchemes: - type: object - properties: - name: - type: string - example: OAuth 2.0 Bearer Token - description: - type: string - example: The OAuth 2.0 Bearer Token Authentication scheme. OAuth enables clients to access protected resources by obtaining an access token, which is defined in RFC 6750 as "a string representing an access authorization issued to the client", rather than using the resource owner's credentials directly. - specUri: - type: string - example: http://tools.ietf.org/html/rfc6750 - type: - type: string - example: oauthbearertoken + type: array + items: + type: object + properties: + name: + type: string + example: OAuth 2.0 Bearer Token + description: + type: string + example: The OAuth 2.0 Bearer Token Authentication scheme. OAuth enables clients to access protected resources by obtaining an access token, which is defined in RFC 6750 as "a string representing an access authorization issued to the client", rather than using the resource owner's credentials directly. + specUri: + type: string + example: http://tools.ietf.org/html/rfc6750 + type: + type: string + example: oauthbearertoken + examples: + - schemas: + - urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig + patch: + supported: true + bulk: + supported: false + maxOperations: 0 + maxPayloadSize: 0 + filter: + supported: true + maxResults: 200 + changePassword: + supported: false + sort: + supported: true + etag: + supported: false + authenticationSchemes: + - name: OAuth 2.0 Bearer Token + specUri: http://tools.ietf.org/html/rfc6750 + type: oauthbearertoken scim_resource_type: examples: - schemas: @@ -4321,15 +4646,31 @@ components: type: number example: 10 next: - type: string - example: https://hub.docker.com/v2/orgs/docker/access-tokens?page=2&page_size=10 + type: + - string + - "null" + example: null previous: - type: string - example: https://hub.docker.com/v2/orgs/docker/access-tokens?page=1&page_size=10 + type: + - string + - "null" + example: null results: type: array items: $ref: "#/components/schemas/orgAccessToken" + examples: + - total: 1 + next: null + previous: null + results: + - id: a7a5ef25-8889-43a0-8cc7-f2a94268e861 + label: My organization token + created_by: johndoe + is_active: true + created_at: "2022-05-20T00:54:18Z" + expires_at: "2023-05-20T00:54:18Z" + last_used_at: "2022-06-15T12:30:45Z" getOrgAccessTokenResponse: examples: - id: a7a5ef25-8889-43a0-8cc7-f2a94268e861 @@ -4492,20 +4833,6 @@ components: description: Resources this token has access to items: $ref: "#/components/schemas/orgAccessTokenResource" - team_repo: - allOf: - - $ref: "#/components/schemas/repository_info" - properties: - group_name: - type: string - description: Name of the group - permission: - type: string - description: Repo access permission - enum: - - read - - write - - admin parameters: namespace: description: Namespace of the repository, such as a user or organization name. @@ -4696,17 +5023,26 @@ components: type: object required: - schemas + - userName properties: schemas: $ref: "#/components/schemas/scim_user_schemas" name: - allOf: - - $ref: "#/components/schemas/scim_user_name" - - description: If this is omitted from the request, the update will skip the update on it. We will only ever change the name, but not clear it. - enabled: + $ref: "#/components/schemas/scim_user_name" + userName: + $ref: "#/components/schemas/scim_user_username" + active: type: boolean default: false - description: If this is omitted from the request, it will default to false resulting in a deactivated user. + description: Whether the user is active. Defaults to false when omitted. + examples: + - schemas: + - urn:ietf:params:scim:schemas:core:2.0:User + userName: jon.snow@docker.com + name: + givenName: Jon + familyName: Snow + active: true add_member_to_org_group: required: true content: diff --git a/content/reference/api/registry/latest.yaml b/content/reference/api/registry/latest.yaml index 3fa7e4baaa8a..e28bb4506f9c 100644 --- a/content/reference/api/registry/latest.yaml +++ b/content/reference/api/registry/latest.yaml @@ -256,6 +256,13 @@ paths: The manifest contains metadata about the image, including configuration and layer digests. It is required for pulling images from the registry. This endpoint requires authentication. Use the `Authorization: Bearer ` header. + + Use the `Accept` header to select the manifest representation. Supported media types: + + - `application/vnd.docker.distribution.manifest.v2+json` + - `application/vnd.docker.distribution.manifest.list.v2+json` + - `application/vnd.oci.image.manifest.v1+json` + - `application/vnd.oci.image.index.v1+json` x-codeSamples: - lang: Bash label: cURL @@ -285,25 +292,6 @@ paths: value: sha256:abc123def456... schema: type: string - - name: Authorization - in: header - required: true - description: RFC7235-compliant authorization header (e.g., `Bearer `). - schema: - type: string - - name: Accept - in: header - required: false - description: | - Media type(s) the client supports for the manifest. - - The registry supports the following media types: - - application/vnd.docker.distribution.manifest.v2+json - - application/vnd.docker.distribution.manifest.list.v2+json - - application/vnd.oci.image.manifest.v1+json - - application/vnd.oci.image.index.v1+json - schema: - type: string responses: "200": description: Manifest fetched successfully. @@ -430,19 +418,6 @@ paths: value: sha256:abc123def456... schema: type: string - - name: Authorization - in: header - required: true - description: RFC7235-compliant authorization header (e.g., `Bearer `). - schema: - type: string - - name: Content-Type - in: header - required: true - description: Media type of the manifest being uploaded. - schema: - type: string - example: application/vnd.docker.distribution.manifest.v2+json requestBody: required: true content: @@ -553,6 +528,13 @@ paths: - Determining the digest or size of a manifest before downloading or deleting This endpoint requires authentication with pull scope. + + Use the `Accept` header to select the manifest representation. Supported media types: + + - `application/vnd.docker.distribution.manifest.v2+json` + - `application/vnd.docker.distribution.manifest.list.v2+json` + - `application/vnd.oci.image.manifest.v1+json` + - `application/vnd.oci.image.index.v1+json` parameters: - name: name in: path @@ -574,20 +556,6 @@ paths: value: sha256:abc123def456... schema: type: string - - name: Authorization - in: header - required: true - schema: - type: string - description: Bearer token for authentication - - name: Accept - in: header - required: false - schema: - type: string - example: application/vnd.docker.distribution.manifest.v2+json - description: | - Media type of the manifest to check. The response will match one of the accepted types. x-codeSamples: - lang: Bash label: cURL @@ -654,12 +622,6 @@ paths: example: sha256:abc123def456... schema: type: string - - name: Authorization - in: header - required: true - description: Bearer token with `delete` access - schema: - type: string x-codeSamples: - lang: Bash label: cURL @@ -736,12 +698,6 @@ paths: schema: type: string example: library/busybox - - name: Authorization - in: header - required: true - schema: - type: string - description: Bearer token for authentication with `push` scope responses: "201": description: Blob successfully mounted from another repository. @@ -829,13 +785,6 @@ paths: schema: type: string example: sha256:abc123def4567890... - - name: Authorization - in: header - required: true - description: Bearer token with pull or push scope - schema: - type: string - example: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6... responses: "200": description: Blob exists @@ -900,13 +849,6 @@ paths: schema: type: string example: sha256:abc123def456... - - name: Authorization - in: header - required: true - schema: - type: string - description: Bearer token with pull scope - example: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6... responses: "200": description: Blob content returned directly @@ -971,7 +913,7 @@ paths: label: cURL source: | # GET upload status - curl -I \ + curl --include --request GET \ -H "Authorization: Bearer $TOKEN" \ https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123 parameters: @@ -989,13 +931,6 @@ paths: schema: type: string example: abc123 - - description: Bearer token for registry authentication. - name: Authorization - in: header - required: true - schema: - type: string - example: Bearer eyJhbGciOi... responses: "204": description: Upload in progress. No body is returned. @@ -1068,13 +1003,6 @@ paths: schema: type: string example: sha256:abcd1234... - - description: Bearer token for registry authentication. - name: Authorization - in: header - required: true - schema: - type: string - example: Bearer eyJhbGciOi... requestBody: required: false content: @@ -1158,13 +1086,6 @@ paths: schema: type: string example: abc123 - - description: Bearer token for registry authentication. - name: Authorization - in: header - required: true - schema: - type: string - example: Bearer eyJhbGciOi... - name: Content-Range in: header required: false @@ -1252,13 +1173,6 @@ paths: schema: type: string example: abc123 - - description: Bearer token for registry authentication. - name: Authorization - in: header - required: true - schema: - type: string - example: Bearer eyJhbGciOi... responses: "204": description: Upload session cancelled successfully. No body is returned. @@ -1294,6 +1208,6 @@ components: registryToken: type: http scheme: bearer - description: Follow the WWW-Authenticate challenge and obtain a repository-scoped registry token. This is separate from the Hub API token exchange. + description: Follow the WWW-Authenticate challenge and obtain a repository-scoped registry bearer token. Public image pulls can obtain a token without account credentials; the registry request still sends that token. This token exchange is separate from Hub API authentication. security: - registryToken: [] diff --git a/hack/api-docs/README.md b/hack/api-docs/README.md index 2f85bdce7f40..5288e522477a 100644 --- a/hack/api-docs/README.md +++ b/hack/api-docs/README.md @@ -32,7 +32,7 @@ relationships. Both generation and the validation wrapper use this manifest. Hugo reads the generated presentation data, rather than this file. Authentication descriptions come from the specifications and linked guides. -`validation/` contains the Vacuum rules, known-issue baseline, and locked official +`validation/` contains the Vacuum rules and locked official schema resources. `testdata/` contains validation fixtures. The presentation model version and supported dialect are defined by the processor, not configurable manifest fields. @@ -58,7 +58,7 @@ The published YAML URLs still serve the source files directly. There is no conversion step, snapshot dependency, Node migration package, or source archive in the build. -## Validation baseline +## Validation `check` is strict and reports every documentation profile failure: @@ -66,21 +66,15 @@ in the build. $ ./hack/api-docs/run.sh check ``` -Generation uses `--allow-known-issues`. The checked-in -`validation/known-issues.json` records explicit exceptions for unresolved Hub -diagnostics. Entries match the source digest, diagnostic digest, rule, and source -pointer. Parse failures, unresolved references, and unsupported features cannot -be waived. Unrecorded diagnostics fail the build. - -Strict validation reports all diagnostics, including recorded exceptions. -Reports are written to `tmp/api-reference/validation.json`. The build never -refreshes the baseline automatically. +Generation runs the same strict validation. Any diagnostic fails the build; +there is no exception baseline. Reports are written to +`tmp/api-reference/validation.json`. ## Tests and scope Go fixtures cover dialects, references, recursion, boolean schemas, examples, security overrides, server and parameter precedence, and request generation. -`verify-output.mjs` checks all 181 generated HTML/Markdown pairs and retention of +`verify-output.mjs` checks all generated HTML/Markdown pairs and retention of Engine v1.40–v1.56 in ReDoc, unchanged Governance rendering, and byte-identical published specifications. `browser-checks.mjs` exports a Playwright check for navigation, page aliases, filtering, requests, and narrow screens. diff --git a/hack/api-docs/contracts_test.go b/hack/api-docs/contracts_test.go new file mode 100644 index 000000000000..9163401c934f --- /dev/null +++ b/hack/api-docs/contracts_test.go @@ -0,0 +1,125 @@ +package main + +import ( + "path/filepath" + "strings" + "testing" +) + +func localDocument(t *testing.T, api string) *Document { + t.Helper() + d, err := loadDocument(filepath.Join("..", "..", "content", "reference", "api", api, "latest.yaml"), "validation/dialects") + if err != nil { + t.Fatal(err) + } + d.Source = Source{ID: api} + d.validate("") + if len(d.Diagnostics) != 0 { + t.Fatalf("%s must pass strict validation: %+v", api, d.Diagnostics) + } + return d +} + +func TestHubResponseContracts(t *testing.T) { + d := localDocument(t, "hub") + for _, tc := range []struct { + pointer, value string + valid bool + }{ + {"/components/schemas/error", `{"message":"not found","errinfo":null}`, true}, + {"/components/schemas/error", `{"errinfo":{"field":["invalid"],"limit":5}}`, true}, + {"/components/schemas/error", `{"errinfo":[]}`, false}, + {"/components/schemas/getAccessTokensResponse", `{"next":null,"previous":null,"results":[]}`, true}, + {"/components/schemas/getOrgAccessTokensResponse", `{"next":null,"previous":null,"results":[]}`, true}, + {"/components/schemas/org_member_paginated", `{"count":0,"next":null,"previous":null,"results":[]}`, true}, + {"/components/schemas/org_member_paginated", `[]`, false}, + {"/components/schemas/bulk_invite", `{"invitees":[]}`, true}, + {"/components/schemas/bulk_invite", `{"invitees":{"invitees":[]}}`, false}, + {"/components/schemas/tag", `{"v2":true,"images":[{"architecture":"amd64","variant":null,"features":null,"os_features":null,"os_version":null}]}`, true}, + {"/components/schemas/tag", `{"v2":"true","images":{}}`, false}, + {"/components/schemas/immutable_tags_verify_request", `{"regex":"v.*"}`, true}, + {"/components/schemas/immutable_tags_verify_request", `{"regex":"v1,v2"}`, false}, + {"/components/schemas/scim_service_provider_config", `{"authenticationSchemes":[{"type":"oauthbearertoken"}]}`, true}, + {"/components/schemas/scim_service_provider_config", `{"authenticationSchemes":{}}`, false}, + {"/components/requestBodies/scim_update_user_request/content/application~1scim+json/schema", `{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],"userName":"user@example.com","active":false}`, true}, + {"/components/requestBodies/scim_update_user_request/content/application~1scim+json/schema", `{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"]}`, false}, + {"/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/200/content/text~1csv/schema", `"Name,Username\nUser,dockeruser\n"`, true}, + {"/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/200/content/text~1csv/schema", `[{"Name":"User"}]`, false}, + } { + t.Run(tc.pointer+"/"+tc.value, func(t *testing.T) { + s, err := d.Compiler.Compile(d.URI + "#" + tc.pointer) + if err != nil { + t.Fatal(err) + } + if err := s.Validate(jsonNumber(tc.value)); (err == nil) != tc.valid { + t.Fatalf("valid = %t, want %t: %v", err == nil, tc.valid, err) + } + }) + } + for _, response := range []string{"scim_get_resource_types_resp", "scim_get_schemas_resp", "scim_get_users_resp"} { + v, err := pointer(d.Root, "/components/responses/"+response+"/content/application~1scim+json/schema/properties") + if err != nil { + t.Fatal(err) + } + if obj(v)["Resources"] == nil || obj(v)["resources"] != nil { + t.Fatalf("incorrect SCIM list field casing: %s", response) + } + } +} + +func TestRegistryRequests(t *testing.T) { + d := localDocument(t, "registry") + for _, raw := range arr(d.model()["operations"]) { + op := obj(raw) + curl := str(op["curl"]) + if strings.Count(curl, "Authorization:") != 1 || !strings.Contains(curl, "${REGISTRY_TOKEN}") { + t.Errorf("incorrect registry authentication: %s", curl) + } + if strings.Count(curl, "Content-Type:") > 1 { + t.Errorf("duplicate content type: %s", curl) + } + if (op["id"] == "GetImageManifest" || op["id"] == "HeadImageManifest") && !strings.Contains(curl, "Accept: application/vnd.docker.distribution.manifest.v2+json") { + t.Errorf("missing manifest negotiation: %s", curl) + } + if op["id"] == "GetBlobUploadStatus" && !strings.Contains(curl, "--request GET") { + t.Errorf("incorrect upload status method: %s", curl) + } + } +} + +func TestReservedHeaderParameters(t *testing.T) { + for _, name := range []string{"Authorization", "accept", "CONTENT-TYPE", "Content-Range"} { + t.Run(name, func(t *testing.T) { + d := fixture(t, "valid.yaml") + op := obj(obj(obj(d.Root["paths"])["/public"])["get"]) + op["parameters"] = []any{Object{"name": name, "in": "header", "description": "Header value.", "schema": Object{"type": "string"}}} + d.validate("") + found := false + for _, diag := range d.Diagnostics { + found = found || (diag.Rule == "S8" && strings.Contains(diag.Message, "ignores")) + } + if found != (name != "Content-Range") { + t.Fatalf("unexpected header validation: %+v", d.Diagnostics) + } + }) + } +} + +func TestExampleText(t *testing.T) { + for _, tc := range []struct { + media string + value any + text, language string + }{ + {"text/csv", "Name,Username\nUser,dockeruser\n", "Name,Username\nUser,dockeruser\n", "text"}, + {"text/plain", "&\n", "&\n", "text"}, + {"application/json", "a\nb", `"a\nb"`, "json"}, + {"application/scim+json", false, "false", "json"}, + {"application/json", jsonNumber("0"), "0", "json"}, + } { + text, language := exampleText(tc.media, tc.value) + if text != tc.text || language != tc.language { + t.Errorf("got %q (%s), want %q (%s)", text, language, tc.text, tc.language) + } + } +} diff --git a/hack/api-docs/main.go b/hack/api-docs/main.go index 98b5a2e70c8f..26a809d93f0d 100644 --- a/hack/api-docs/main.go +++ b/hack/api-docs/main.go @@ -95,12 +95,9 @@ func writeJSON(p string, v any) error { } type Diagnostic struct { - Rule string `json:"rule"` - Pointer string `json:"pointer"` - Message string `json:"message"` - Waivable bool `json:"waivable"` - Excepted bool `json:"excepted"` - Reason string `json:"reason,omitempty"` + Rule string `json:"rule"` + Pointer string `json:"pointer"` + Message string `json:"message"` } type Source struct { ID string `json:"id"` @@ -136,8 +133,8 @@ type Document struct { ExampleCount int } -func (d *Document) issue(rule, p, msg string, waivable bool) { - d.Diagnostics = append(d.Diagnostics, Diagnostic{Rule: rule, Pointer: p, Message: strings.ReplaceAll(msg, d.URI, "source:"+d.Source.ID), Waivable: waivable}) +func (d *Document) issue(rule, p, msg string) { + d.Diagnostics = append(d.Diagnostics, Diagnostic{Rule: rule, Pointer: p, Message: strings.ReplaceAll(msg, d.URI, "source:"+d.Source.ID)}) } func walk(v any, p string, fn func(Object, string)) { switch n := v.(type) { @@ -410,23 +407,23 @@ func (d *Document) schemaRoots(v any, p string) { } func (d *Document) validate(metaDir string) { if d.Root["openapi"] != "3.2.0" { - d.issue("S1", "/openapi", "Expected OpenAPI 3.2.0", false) + d.issue("S1", "/openapi", "Expected OpenAPI 3.2.0") } if d.Root["jsonSchemaDialect"] != dialect { - d.issue("S1", "/jsonSchemaDialect", "Expected the selected OAS dialect", false) + d.issue("S1", "/jsonSchemaDialect", "Expected the selected OAS dialect") } documentSchema, e := d.Compiler.Compile("https://spec.openapis.org/oas/3.2/schema/2025-09-17") if e != nil { - d.issue("structure", "", e.Error(), false) + d.issue("structure", "", e.Error()) } else if e = documentSchema.Validate(d.Root); e != nil { - d.issue("structure", "", e.Error(), false) + d.issue("structure", "", e.Error()) } // OAS Reference Objects also need explicit validation: a document schema cannot prove their target exists. walk(d.Root, "", func(n Object, p string) { if r := str(n["$ref"]); r != "" { u, er := url.Parse(r) if er != nil { - d.issue("reference", p, er.Error(), false) + d.issue("reference", p, er.Error()) return } base, _ := url.Parse(d.URI) @@ -435,38 +432,38 @@ func (d *Document) validate(metaDir string) { u.Fragment = "" v, ok := d.Registry.resources[u.String()] if !ok { - d.issue("reference", p, "Unregistered resource "+r, false) + d.issue("reference", p, "Unregistered resource "+r) } else if strings.HasPrefix(frag, "/") { if _, er = pointer(v, frag); er != nil { - d.issue("reference", p, er.Error(), false) + d.issue("reference", p, er.Error()) } } } }) if len(obj(d.Root["webhooks"])) > 0 { - d.issue("capability", "/webhooks", "Webhook navigation is not supported by the reference renderer", false) + d.issue("capability", "/webhooks", "Webhook navigation is not supported by the reference renderer") } walk(d.Root, "", func(n Object, p string) { if len(obj(n["callbacks"])) > 0 { - d.issue("capability", p+"/callbacks", "Callback navigation is not supported by the reference renderer", false) + d.issue("capability", p+"/callbacks", "Callback navigation is not supported by the reference renderer") } }) d.schemaRoots(d.Root, "") schemaMeta, e := d.Compiler.Compile(dialect) if e != nil { - d.issue("dialect", "", e.Error(), false) + d.issue("dialect", "", e.Error()) return } for _, p := range keys(d.Schemas) { s := d.Schemas[p] d.SchemaCount++ if e = schemaMeta.Validate(s); e != nil { - d.issue("schema", p, e.Error(), false) + d.issue("schema", p, e.Error()) continue } compiled, e := d.Compiler.Compile(d.URI + "#" + p) if e != nil { - d.issue("schema", p, e.Error(), false) + d.issue("schema", p, e.Error()) continue } d.Compiled[p] = compiled @@ -491,7 +488,7 @@ func (d *Document) validate(metaDir string) { d.example(c, v, p+"/examples/"+esc(name)+"/value") } if _, ok := ex["externalValue"]; ok { - d.issue("example-external", p+"/examples/"+esc(name), "External example requires a locked media fixture", true) + d.issue("example-external", p+"/examples/"+esc(name), "External example requires a locked media fixture") } } }) @@ -505,34 +502,40 @@ func (d *Document) validate(metaDir string) { id := str(op["id"]) p := str(op["pointer"]) if id == "" || ids[id] { - d.issue("S4", p, "Operation ID must be present and unique", false) + d.issue("S4", p, "Operation ID must be present and unique") } ids[id] = true opTags := arr(op["tags"]) if len(opTags) == 0 || tags[str(opTags[0])] != "nav" { - d.issue("S5", p+"/tags", "The first operation tag must identify a declared navigation group", false) + d.issue("S5", p+"/tags", "The first operation tag must identify a declared navigation group") } for _, tag := range opTags { if _, ok := tags[str(tag)]; !ok { - d.issue("S5", p+"/tags", "Operation tag is undeclared: "+str(tag), false) + d.issue("S5", p+"/tags", "Operation tag is undeclared: "+str(tag)) } } if len(arr(op["servers"])) == 0 && d.Source.Connection != "unix" { - d.issue("S6", p, "Operation needs effective servers or a local connection profile", false) + d.issue("S6", p, "Operation needs effective servers or a local connection profile") } if strings.TrimSpace(str(op["description"])) == "" { - d.issue("S4", p+"/description", "Operation description required", true) + d.issue("S4", p+"/description", "Operation description required") } for _, pr := range arr(op["parameters"]) { param := obj(pr) + if param["in"] == "header" { + switch strings.ToLower(str(param["name"])) { + case "authorization", "accept", "content-type": + d.issue("S8", str(param["pointer"]), "OpenAPI ignores this header parameter; use security or media types") + } + } if str(param["description"]) == "" { - d.issue("S8", str(param["pointer"])+"/description", "Parameter description requires editorial review", true) + d.issue("S8", str(param["pointer"])+"/description", "Parameter description requires editorial review") } } for _, variant := range arr(op["variants"]) { v := obj(variant) if str(v["media"]) != "" && len(arr(v["examples"])) == 0 { - d.issue("S11", str(v["pointer"]), "Media variant needs a reviewed example or transfer fixture", true) + d.issue("S11", str(v["pointer"]), "Media variant needs a reviewed example or transfer fixture") } } } @@ -543,7 +546,7 @@ func (d *Document) schemaExamples(s any, p string) { return } if _, ok := n["$schema"]; ok && n["$schema"] != dialect { - d.issue("S1", p+"/$schema", "Schema dialect override is outside the profile", false) + d.issue("S1", p+"/$schema", "Schema dialect override is outside the profile") } c, e := d.Compiler.Compile(d.URI + "#" + p) if e == nil { @@ -572,7 +575,7 @@ func (d *Document) schemaExamples(s any, p string) { func (d *Document) example(c *js.Schema, v any, p string) { d.ExampleCount++ if e := c.Validate(v); e != nil { - d.issue("example", p, e.Error(), true) + d.issue("example", p, e.Error()) } } func (d *Document) effective(root, item, op Object, k string) any { @@ -688,13 +691,13 @@ func main() { } func run() error { if len(os.Args) < 3 { - return errors.New("usage: api-docs check|generate|inspect|sources ROOT [--allow-known-issues]") + return errors.New("usage: api-docs check|generate|inspect|sources ROOT") } command := os.Args[1] if command != "check" && command != "generate" && command != "inspect" && command != "sources" { return fmt.Errorf("unknown command: %s", command) } - if len(os.Args) > 4 || (len(os.Args) == 4 && os.Args[3] != "--allow-known-issues") { + if len(os.Args) > 3 { return errors.New("unexpected arguments") } root, _ := filepath.Abs(os.Args[2]) @@ -717,11 +720,6 @@ func run() error { } return nil } - allowKnown := len(os.Args) > 3 && os.Args[3] == "--allow-known-issues" - exceptions, e := readJSON(filepath.Join(dir, "validation", "known-issues.json")) - if e != nil { - return e - } reports := []any{} models := []any{} blocking := 0 @@ -732,20 +730,7 @@ func run() error { } d.Source = src d.validate(meta) - for i := range d.Diagnostics { - diag := &d.Diagnostics[i] - for _, raw := range arr(exceptions) { - x := obj(raw) - if diag.Waivable && x["api"] == src.ID && x["sha256"] == d.Digest && x["rule"] == diag.Rule && x["pointer"] == diag.Pointer && x["messageSha256"] == hash([]byte(diag.Message)) && str(x["reason"]) != "" { - diag.Excepted = true - diag.Reason = str(x["reason"]) - break - } - } - if !diag.Excepted || !allowKnown { - blocking++ - } - } + blocking += len(d.Diagnostics) reports = append(reports, Object{"api": src.ID, "sha256": d.Digest, "schemas": d.SchemaCount, "examples": d.ExampleCount, "operations": len(d.operations()), "diagnostics": d.Diagnostics}) models = append(models, d.model()) fmt.Printf("%s: %d operations, %d schema roots, %d examples, %d diagnostics\n", src.ID, len(d.operations()), d.SchemaCount, d.ExampleCount, len(d.Diagnostics)) diff --git a/hack/api-docs/main_test.go b/hack/api-docs/main_test.go index 7fe6ec3eea16..a905bc8dfbac 100644 --- a/hack/api-docs/main_test.go +++ b/hack/api-docs/main_test.go @@ -22,9 +22,7 @@ func TestActualDialectAndReferences(t *testing.T) { d := fixture(t, "valid.yaml") d.validate("") for _, x := range d.Diagnostics { - if !x.Waivable { - t.Errorf("%s: %s", x.Rule, x.Message) - } + t.Errorf("%s: %s", x.Rule, x.Message) } if len(d.operations()) != 4 { t.Fatal("operation omitted") @@ -76,7 +74,7 @@ func TestNegativeFixtures(t *testing.T) { if e == nil { d.validate("") for _, x := range d.Diagnostics { - if !x.Waivable { + if x.Rule == "reference" || x.Rule == "schema" { return } } diff --git a/hack/api-docs/model.go b/hack/api-docs/model.go index b0b684c60886..b7d519e77991 100644 --- a/hack/api-docs/model.go +++ b/hack/api-docs/model.go @@ -23,18 +23,25 @@ func (d *Document) model() Object { for _, op := range ops { for _, raw := range arr(op["variants"]) { v := obj(raw) - c := d.Compiled[str(v["pointer"])+"/schema"] - if c != nil { - for _, rawEx := range arr(v["examples"]) { - ex := obj(rawEx) - ex["valid"] = c.Validate(ex["value"]) == nil - } + for _, rawEx := range arr(v["examples"]) { + ex := obj(rawEx) + ex["text"], ex["language"] = exampleText(str(v["media"]), ex["value"]) } } } for _, op := range ops { op["url"] = route(d.Source.ID) + "operations/" + slug(str(op["id"])) + "/" op["securitySchemes"] = obj(d.Root["components"])["securitySchemes"] + op["acceptMedia"] = responseMedia(op) + // HEAD negotiates the GET representation but has no response body. + if op["method"] == "HEAD" && op["acceptMedia"] == "" { + for _, get := range ops { + if get["method"] == "GET" && get["path"] == op["path"] { + op["acceptMedia"] = responseMedia(get) + break + } + } + } op["curl"], op["curlNotes"] = curlExample(d.Source, op) op["references"] = refs(op["raw"], schemaURLs) op["requestSchema"] = firstRequestSchema(op) @@ -88,6 +95,24 @@ func parameterValue(p Object) (any, bool) { } return nil, false } + +func exampleText(media string, value any) (string, string) { + if s, ok := value.(string); ok && !strings.Contains(media, "json") { + return s, "text" + } + return strings.TrimSpace(string(encoded(value))), "json" +} + +func responseMedia(op Object) string { + for _, raw := range arr(op["variants"]) { + v := obj(raw) + if v["direction"] == "Response" && strings.HasPrefix(str(v["status"]), "2") && str(v["media"]) != "" { + return str(v["media"]) + } + } + return "" +} + func curlExample(src Source, op Object) (string, []string) { notes := []string{} args := []string{"curl"} @@ -196,6 +221,9 @@ func curlExample(src Source, op Object) (string, []string) { notes = append(notes, "This example uses the first authentication alternative. Review the complete requirements.") } } + if media := str(op["acceptMedia"]); media != "" { + args = append(args, "--header "+shell("Accept: "+media)) + } for _, raw := range arr(op["variants"]) { v := obj(raw) if v["direction"] != "Request" { @@ -207,7 +235,7 @@ func curlExample(src Source, op Object) (string, []string) { } args = append(args, "--header "+shell("Content-Type: "+media)) examples := arr(v["examples"]) - if len(examples) > 0 && obj(examples[0])["valid"] != false && strings.Contains(media, "json") { + if len(examples) > 0 && strings.Contains(media, "json") { args = append(args, "--data-raw "+shell(strings.TrimSpace(string(encoded(obj(examples[0])["value"]))))) } else { args = append(args, "--data-binary @request-body") diff --git a/hack/api-docs/run.sh b/hack/api-docs/run.sh index 62310293a7c6..e132d20253b0 100755 --- a/hack/api-docs/run.sh +++ b/hack/api-docs/run.sh @@ -24,7 +24,7 @@ policy() { generate() { bootstrap policy - "$BIN/api-docs" generate "$ROOT" --allow-known-issues + "$BIN/api-docs" generate "$ROOT" } case "${1:-build}" in bootstrap) bootstrap ;; diff --git a/hack/api-docs/testdata/valid.yaml b/hack/api-docs/testdata/valid.yaml index 5863f4b25c20..3ec382de30c6 100644 --- a/hack/api-docs/testdata/valid.yaml +++ b/hack/api-docs/testdata/valid.yaml @@ -2,66 +2,73 @@ openapi: 3.2.0 jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base info: title: Docker documentation tooling fixture - version: '1' + version: "1" description: Component capability fixture. servers: -- url: https://api.example.test/v1 + - url: https://api.example.test/v1 security: -- bearerAuth: [] + - bearerAuth: [] tags: -- name: operations - summary: Operations - kind: nav - description: Fixture operations. + - name: operations + summary: Operations + kind: nav + description: Fixture operations. paths: /events: get: operationId: listEvents tags: - - operations + - operations summary: List events + description: List events. responses: - '200': + "200": description: Event stream content: text/event-stream: itemSchema: $ref: ./schemas/event.yaml + example: { event: message, data: hello } /search: parameters: - - name: limit - in: query - schema: - type: integer - example: 10 + - name: limit + in: query + description: Maximum number of results. + schema: + type: integer + example: 10 servers: - - url: https://search.example.test + - url: https://search.example.test query: operationId: querySearch tags: - - operations + - operations summary: Search + description: Search. parameters: - - name: limit - in: query - schema: - type: integer - example: 0 + - name: limit + in: query + description: Maximum number of results. + schema: + type: integer + example: 0 responses: - '200': + "200": description: Search result content: application/json: schema: true + example: 0 /public: get: operationId: getPublic tags: - - operations + - operations summary: Public result + description: Public result. security: [] responses: - '200': + "200": description: A flag content: application/json: @@ -72,16 +79,18 @@ paths: get: operationId: getItems tags: - - operations + - operations summary: Get items + description: Get items. responses: - '200': + "200": description: Item content: application/json: schema: - $ref: '#/components/schemas/Item' + $ref: "#/components/schemas/Item" description: Description beside a reference. + example: { id: 1, next: { id: 2, next: null } } components: securitySchemes: bearerAuth: @@ -91,11 +100,11 @@ components: Item: type: object required: - - id + - id properties: id: type: integer next: anyOf: - - $ref: '#/components/schemas/Item' - - type: 'null' + - $ref: "#/components/schemas/Item" + - type: "null" diff --git a/hack/api-docs/validation/known-issues.json b/hack/api-docs/validation/known-issues.json deleted file mode 100644 index 1c025cf574a8..000000000000 --- a/hack/api-docs/validation/known-issues.json +++ /dev/null @@ -1,1602 +0,0 @@ -[ - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "example", - "pointer": "/components/schemas/getAccessTokensResponse/properties/next/example", - "messageSha256": "24b1ae1c7680ae4c77e6a2324f37604bae76ac9ec0005c305c53d25bf07d1de1", - "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", - "diagnostic": "jsonschema validation failed with 'source:hub#/components/schemas/getAccessTokensResponse/properties/next'\n- at '': got null, want string", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "example", - "pointer": "/components/schemas/getAccessTokensResponse/properties/previous/example", - "messageSha256": "70abcbf84044398b484ca7b512025a5f8e827352875dfc8e04071e76c195e4b0", - "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", - "diagnostic": "jsonschema validation failed with 'source:hub#/components/schemas/getAccessTokensResponse/properties/previous'\n- at '': got null, want string", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "example", - "pointer": "/components/schemas/immutable_tags_verify_request/properties/regex/example", - "messageSha256": "c5e7204226bdc3c0252c721ed6ef8bcdd36f4f6f2e5a10c8a7da220e9fc8fa8c", - "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", - "diagnostic": "jsonschema validation failed with 'source:hub#/components/schemas/immutable_tags_verify_request/properties/regex'\n- at '': 'v.*' does not match pattern '^[a-z0-9]+((\\\\\\\\.|_|__|-+)[a-z0-9]+)*(\\\\\\\\/[a-z0-9]+((\\\\\\\\.|_|__|-+)[a-z0-9]+)*)*$'", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "example", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/200/content/application~1json/schema/properties/next/example", - "messageSha256": "c38485c83b9ebe4bca6b5ce33378e8b8fb1b8ec3d6c5edf1d0023bd44e4e2fd8", - "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", - "diagnostic": "jsonschema validation failed with 'source:hub#/paths/~1v2~1orgs~1%7Borg_name%7D~1groups/get/responses/200/content/application~1json/schema/properties/next'\n- at '': got null, want string", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "example", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/200/content/application~1json/schema/properties/previous/example", - "messageSha256": "b3f9ac6897f3b48d85c63dae690b86569e284aeed8ade6390c34f511496a93c1", - "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", - "diagnostic": "jsonschema validation failed with 'source:hub#/paths/~1v2~1orgs~1%7Borg_name%7D~1groups/get/responses/200/content/application~1json/schema/properties/previous'\n- at '': got null, want string", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "example", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/200/content/application~1json/schema/properties/next/example", - "messageSha256": "5a161ce722f225c2468a5db8c0c3b9a7794e7847d24645bc11e219b182cd9996", - "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", - "diagnostic": "jsonschema validation failed with 'source:hub#/paths/~1v2~1orgs~1%7Borg_name%7D~1groups~1%7Bgroup_name%7D~1members/get/responses/200/content/application~1json/schema/properties/next'\n- at '': got null, want string", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "example", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/200/content/application~1json/schema/properties/previous/example", - "messageSha256": "0afb130b19f561c0c4587e8d27ffbdce7c2c56b516dd609f9dad68c697ae68dd", - "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", - "diagnostic": "jsonschema validation failed with 'source:hub#/paths/~1v2~1orgs~1%7Borg_name%7D~1groups~1%7Bgroup_name%7D~1members/get/responses/200/content/application~1json/schema/properties/previous'\n- at '': got null, want string", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "example", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/201/content/application~1json/example", - "messageSha256": "1a244af81ade4ef2616b9ee5bf28edeed2bac6f56a35a4a58210ab73bf0ca6d7", - "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", - "diagnostic": "jsonschema validation failed with 'source:hub#/paths/~1v2~1namespaces~1%7Bnamespace%7D~1repositories/post/responses/201/content/application~1json/schema'\n- at '': missing properties 'user', 'permissions'", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "example", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/200/content/application~1json/example", - "messageSha256": "e1b27ea692b2fda83285b9884f9f852d6c64f77f153e06138d27be7d958ffa16", - "reason": "Retain the original example and its schema for review; the owner must resolve the reported mismatch without weakening the contract.", - "diagnostic": "jsonschema validation failed with 'source:hub#/paths/~1v2~1namespaces~1%7Bnamespace%7D~1repositories~1%7Brepository%7D/get/responses/200/content/application~1json/schema'\n- at '': missing properties 'user', 'permissions'", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens/get/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens/get/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens/post/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens/post/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/get/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/delete/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/delete/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1access-tokens~1{uuid}/patch/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1auditlogs~1{account}/get/responses/500/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1auditlogs~1{account}/get/responses/default/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1auditlogs~1{account}~1actions/get/responses/500/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1auditlogs~1{account}~1actions/get/responses/default/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1auth~1token/post/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1invites~1bulk/post/responses/202/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1invites~1bulk/post/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1invites~1bulk/post/responses/409/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1invites~1{id}/delete/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1invites~1{id}/delete/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1invites~1{id}/delete/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1invites~1{id}~1resend/patch/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1invites~1{id}~1resend/patch/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1invites~1{id}~1resend/patch/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories/post/responses/500/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/get/responses/500/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}/head/responses/500/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags/patch/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/requestBody/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1immutabletags~1verify/post/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags/head/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1namespaces~1{namespace}~1repositories~1{repository}~1tags~1{tag}/head/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1access-tokens/post/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{name}~1settings/put/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/delete/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1access-tokens~1{access_token_id}/patch/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/201/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups/post/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/put/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/delete/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}/patch/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members/post/responses/500/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1groups~1{group_name}~1members~1{username}/delete/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1invites/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/200/content/text~1csv", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1export/get/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/200/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/put/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1orgs~1{org_name}~1members~1{username}/delete/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/responses/400/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/responses/401/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/responses/403/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1repositories~1{namespace}~1{repository}~1groups/post/responses/404/content/application~1json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1ResourceTypes/get/responses/200/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Schemas/get/responses/200/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1ServiceProviderConfig/get/responses/200/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users/get/responses/200/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - }, - { - "api": "hub", - "sha256": "265549ea018adbd1b49afaab933f13398f180ac6761038ecc4f8286db5a15966", - "rule": "S11", - "pointer": "/paths/~1v2~1scim~12.0~1Users~1{id}/put/requestBody/content/application~1scim+json", - "messageSha256": "8a826fb6e84b59ba3811a6e54c377b89a5c7c39a2bf8ca3427729604ba518ed1", - "reason": "Retain the documented media variant; product owner must supply a verified example or transfer fixture.", - "diagnostic": "Media variant needs a reviewed example or transfer fixture", - "ownerReview": "required" - } -] diff --git a/hack/api-docs/verify-output.mjs b/hack/api-docs/verify-output.mjs index 97ac5fe7d9ac..33001b850d7d 100644 --- a/hack/api-docs/verify-output.mjs +++ b/hack/api-docs/verify-output.mjs @@ -45,12 +45,20 @@ for (const api of data.apis) { for (const op of api.operations) { const [html, md] = check(op.url); - for (const variant of op.variants) + for (const variant of op.variants) { if ( !attributes(html, "data-api-variant").includes(variant.pointer) || !md.includes(`### ${variant.direction} ${variant.status}`) ) problems.push(`Missing variant: ${op.url} ${variant.pointer}`); + for (const example of variant.examples) { + if ( + !html.includes(example.text.trim()) || + !md.includes("```" + example.language + "\n" + example.text) + ) + problems.push(`Example mismatch: ${op.url} ${variant.pointer}`); + } + } for (const p of op.parameters) if ( !attributes(html, "data-api-parameter").includes(p.name) || diff --git a/layouts/api-docs.html b/layouts/api-docs.html index 097688e2a024..6303b9fe73e6 100644 --- a/layouts/api-docs.html +++ b/layouts/api-docs.html @@ -321,13 +321,7 @@

Stream item

{{ end }}{{ range $j,$ex := $v.examples }}

{{ $ex.name }}

- {{ if eq $ex.valid false }} -

- Source example does not satisfy its schema; - owner review is required. -

- {{ end }} -
{{ $ex.value | jsonify (dict "indent" "  ") }}
+
{{ $ex.text }}
{{ end }} diff --git a/layouts/api-docs.markdown.md b/layouts/api-docs.markdown.md index ad1cf4166530..5f6e679b27cd 100644 --- a/layouts/api-docs.markdown.md +++ b/layouts/api-docs.markdown.md @@ -127,11 +127,8 @@ Headers: {{ end }} {{ range .examples }} {{ .name }}: -{{ if eq .valid false }} -Source example does not satisfy its schema; owner review is required. -{{ end }} -```json -{{ .value | jsonify (dict "indent" " ") }} +```{{ .language }} +{{ .text }} ``` {{ end }} {{ end }}