Update spec to include tag history endpoint#606
Conversation
ba1f62d to
dd534be
Compare
| When `n` is zero, this endpoint MUST return an empty array. | ||
| When `n` is not specified, the registry MAY apply a default limit. | ||
|
|
||
| - **`before`** *string (RFC 3339 timestamp)*, OPTIONAL |
There was a problem hiding this comment.
maybe from or ot (older than)
| - **`before`** *string (RFC 3339 timestamp)*, OPTIONAL | |
| - **`ot`** *string (RFC 3339 timestamp)*, OPTIONAL |
|
|
||
| - **`before`** *string (RFC 3339 timestamp)*, OPTIONAL | ||
|
|
||
| When provided, only entries whose `org.opencontainers.tag.created` value is strictly less than (i.e. older than) `before` will be returned. |
There was a problem hiding this comment.
| When provided, only entries whose `org.opencontainers.tag.created` value is strictly less than (i.e. older than) `before` will be returned. | |
| When provided, only entries whose `org.opencontainers.tag.created` value is strictly less than (i.e. older than) the `ot` timestamp will be returned. |
| When `n` is zero, this endpoint MUST return an empty array. | ||
| When `n` is not specified, the registry MAY apply a default limit. | ||
|
|
||
| - **`before`** *string (RFC 3339 timestamp)*, OPTIONAL |
There was a problem hiding this comment.
is there a chance to have two results with the exact same time stamp..
There was a problem hiding this comment.
Perhaps a registry could consider every update of a tag as a delete followed by a create and so the timestamp would be the same.
|
|
||
| When provided, only entries whose `org.opencontainers.tag.created` value is strictly less than (i.e. older than) `before` will be returned. | ||
| This is used for time-based pagination: pass the `org.opencontainers.tag.created` value of the last entry returned in the previous response to retrieve the next page. | ||
|
|
There was a problem hiding this comment.
another idea would be to include a "newer-than" option, or a "between" timestamp1/timestamp2 allowing a client to query new tags or a time range..
Signed-off-by: Jeff Carter <[email protected]>
sudo-bmitch
left a comment
There was a problem hiding this comment.
Here's some early feedback. I still need to spend some time implementing this before considering approving, and we need a conformance test.
| ] | ||
| ``` | ||
|
|
||
| Results MUST be sorted in descending order by the history entry timestamp, which is either the `org.opencontainers.tag.created` annotation value or the `org.opencontainers.tag.deleted` annotation value (i.e. the most recent entry appears first). |
There was a problem hiding this comment.
In image spec, we use the prefix org.opencontainers.image. For distribution, perhaps we should standardize on org.opencontainers.distribution to avoid conflicts with other specs?
| - **`mediaType`** *string*, REQUIRED | ||
|
|
||
| MUST be `application/vnd.oci.empty.v1+json`. | ||
|
|
||
| - **`digest`** *string*, REQUIRED | ||
|
|
||
| MUST be `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a`. | ||
|
|
||
| - **`size`** *integer*, REQUIRED | ||
|
|
||
| MUST be `2`. | ||
|
|
||
| - **`data`** *string*, REQUIRED | ||
|
|
||
| MUST be `e30=`. | ||
|
|
||
| - **`annotations`** *map of strings*, REQUIRED | ||
|
|
||
| Annotations associated with the historical tag entry. MUST include: | ||
|
|
||
| - **`org.opencontainers.tag.deleted`** *string*, REQUIRED | ||
|
|
||
| The RFC 3339 timestamp at which the tag was deleted. Used as the sort key and as the cursor for time-based pagination. |
There was a problem hiding this comment.
I'd rephrase to use the descriptor of the deleted entry. And now with so much overlap, I think we can probably merge the two create/delete sections and then document the two possible annotations.
| - **`mediaType`** *string*, REQUIRED | |
| MUST be `application/vnd.oci.empty.v1+json`. | |
| - **`digest`** *string*, REQUIRED | |
| MUST be `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a`. | |
| - **`size`** *integer*, REQUIRED | |
| MUST be `2`. | |
| - **`data`** *string*, REQUIRED | |
| MUST be `e30=`. | |
| - **`annotations`** *map of strings*, REQUIRED | |
| Annotations associated with the historical tag entry. MUST include: | |
| - **`org.opencontainers.tag.deleted`** *string*, REQUIRED | |
| The RFC 3339 timestamp at which the tag was deleted. Used as the sort key and as the cursor for time-based pagination. | |
| - **`mediaType`** *string*, REQUIRED | |
| The media type of the manifest this tag previously pointed to at that point in time. | |
| - **`size`** *integer*, REQUIRED | |
| The size in bytes of the manifest. | |
| - **`digest`** *string*, REQUIRED | |
| The digest of the manifest, in the form `<algorithm>:<encoded>`. | |
| - **`annotations`** *map of strings*, REQUIRED | |
| Annotations associated with the historical tag entry. MUST include: | |
| - **`org.opencontainers.distribution.tag.deleted`** *string*, REQUIRED | |
| The RFC 3339 timestamp at which the tag was deleted. Used as the sort key and as the cursor for time-based pagination. |
|
|
||
| ##### Query Parameters | ||
|
|
||
| The following query parameters MAY be provided: |
There was a problem hiding this comment.
Perhaps there could also be a query parameter for "digest" such that a client could verify that a tag did point at the manifest when given an image reference like image:tag@sha256....
It would return 404 if the digest isn't in the history but otherwise returning the expected JSON array of descriptor objects that includes the digest. I'm not sure if that'd be just the one descriptor (or two if deleted?) or perhaps up to n. And it should respect the other query parameters like before and so also 404 if the digest is not before the specified date.
There was a problem hiding this comment.
I added a comment for this above:
If a pinned digest is provided with the tag, the registry MUST return a `404 Not Found` if the digest is not part of the tag's history.
This might cover it? Or we could send digest as a separate query param... maybe that's better?
There was a problem hiding this comment.
👍 I like pinned digest in the tag, no need for a query parameter when we already have the format. Oh, but I don't see the pinned digest format defined in spec.md? 🤔
I think it may need guidance on what they should return when passed a pinned digest? Probably the only guarantee is that it must be in the list of n (barring before making it no longer in the list and thus 404).
Signed-off-by: Jeff Carter <[email protected]>
|
|
||
| A successful request MUST return a `200 OK` response code. | ||
| If the repository does not exist, the registry MUST return a `404 Not Found` response code. | ||
| If the tag has no history or the registry does not implement this extension, the registry MUST return a `404 Not Found` response code. |
There was a problem hiding this comment.
Should this have a MUST/SHOULD respond with UNSUPPORTED in the error code for "registry does not implement this" case? Or perhaps some other recommended required error codes for the other 404 responses so that users of the API can know which it is. Or maybe the n=0 trick is the correct way to figure out if history is supported?
Related:
If the tag has no history [...] the registry MUST return a
404 Not Found
when
nis zero, this endpoint MUST return an empty array
These seem conflicting. Perhaps a clarification is needed?
There was a problem hiding this comment.
In other words, does n=0 override the "repository does not exist" 404 or just the "no history" 404 or "registry does not implement this extension" 404 and what about the pinned digest 404?
There was a problem hiding this comment.
Yes, those do some conflicting, good catch.
Currently most http routers on an unknown path would return 404 by default, hence the "return 404 if not supported". If we forced an UNSUPPORTED it'd require registries to explicitly update to say they aren't handling it, vs it being the default
There was a problem hiding this comment.
I think the appropriate thing to do is return an empty response with 200 OK if there is no history - this seems to make more sense?
There was a problem hiding this comment.
🤔 Could it have no history? What does that mean? Does that mean nothing was ever tagged as this? Or just that the registry hasn't yet recorded history? But if it has at least the current tagged image and they support the history endpoint, it must have a minimum history of one, right? So, 404 is correct, the tag does not exist as an image, or it would have history. Returning an empty list for every tag that doesn't exist seems odd.
Signed-off-by: Jeff Carter <[email protected]>
Signed-off-by: Jeff Carter <[email protected]>
Signed-off-by: Jeff Carter <[email protected]>
| `<name>` is the namespace of the repository, and `<tag>` is the name of the tag whose history is being queried. | ||
|
|
||
| A successful request MUST return a `200 OK` response code. | ||
| If the repository does not exist, the registry MUST return a `404 Not Found` response code. |
There was a problem hiding this comment.
If the repository does not exist, the registry MUST return a
404 Not Foundresponse code.
When
nis zero, this endpoint MUST return an empty array, useful for determining if history is available (200) or not (404) for the tag query.
I think someone could interpret that this should they return 200 and an empty list when n=0 even if the repository does not exist.
Updates distribution spec to include new endpoint for retrieving the history of a given tag. The response is a json list of descriptors,including the created timestamp and sorted in descending order (newest first).
The list can be paged.