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.**_
-
\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.**_
+
+-
+ {{ 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.
+
\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.**_
-
--