Add `github-release` package type
Per: #299
Introduces a new github-release package type for identifying specific GitHub Releases.
There is some overlap here with the existing github package type -- in theory you can point to a GitHub release today with a github package type be identifying the release's tag:
pkg:github/foo/[email protected]
However, there may come a time when GitHub releases are decoupled from git tags and it would be helpful to have a way to disambiguate between a plain ol' GitHub repository tag and a named GitHub Release:
pkg:github-release/foo/[email protected]
The most immediate use case for this is in the context of in-toto release predicates where we need to be able to identify a specific GitHub release using a purl.
like the idea.
lets think about how a specific file from a release could be pointed out.
lets use this as an example: https://github.com/package-url/packageurl-python/releases/tag/v0.16.0
- how would i express that i need the asset https://github.com/package-url/packageurl-python/releases/download/v0.16.0/packageurl_python-0.16.0.tar.gz? answer is probably: well-known qualifier "file_name"
- how would i express that i need a certain file/asset? answer is probably: subpath
couldyou add those to the spec?
@jkowalleck
lets think about how a specific file from a release could be pointed out.
This is a good call out! I've added a file_name qualifier to the spec which would allow for the identification of a specific asset within the release. A GitHub "release" provides a flat namespace for uniquely named assets so I don't think we need to use subpath -- file_name alone should be sufficient to uniquely identify a particular asset published as part of a release.
pkg:github-release/foo/[email protected]?file_name=bin-linux.tgz
I like this type. Maybe we expand this a bit and document the various qualifiers including mandatory ones as well.
Required properties as per github
"required": [
"assets_url",
"upload_url",
"tarball_url",
"zipball_url",
"created_at",
"published_at",
"draft",
"id",
"node_id",
"author",
"html_url",
"name",
"prerelease",
"tag_name",
"target_commitish",
"assets",
"url"
]
Full release schema
{
"title": "Release",
"description": "A release.",
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"html_url": {
"type": "string",
"format": "uri"
},
"assets_url": {
"type": "string",
"format": "uri"
},
"upload_url": {
"type": "string"
},
"tarball_url": {
"type": [
"string",
"null"
],
"format": "uri"
},
"zipball_url": {
"type": [
"string",
"null"
],
"format": "uri"
},
"id": {
"type": "integer"
},
"node_id": {
"type": "string"
},
"tag_name": {
"description": "The name of the tag.",
"type": "string",
"examples": [
"v1.0.0"
]
},
"target_commitish": {
"description": "Specifies the commitish value that determines where the Git tag is created from.",
"type": "string",
"examples": [
"master"
]
},
"name": {
"type": [
"string",
"null"
]
},
"body": {
"type": [
"string",
"null"
]
},
"draft": {
"description": "true to create a draft (unpublished) release, false to create a published one.",
"type": "boolean",
"examples": [
false
]
},
"prerelease": {
"description": "Whether to identify the release as a prerelease or a full release.",
"type": "boolean",
"examples": [
false
]
},
"created_at": {
"type": "string",
"format": "date-time"
},
"published_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"author": {
"title": "Simple User",
"description": "A GitHub user.",
"type": "object",
"properties": {
"name": {
"type": [
"string",
"null"
]
},
"email": {
"type": [
"string",
"null"
]
},
"login": {
"type": "string",
"examples": [
"octocat"
]
},
"id": {
"type": "integer",
"format": "int64",
"examples": [
1
]
},
"node_id": {
"type": "string",
"examples": [
"MDQ6VXNlcjE="
]
},
"avatar_url": {
"type": "string",
"format": "uri",
"examples": [
"https://github.com/images/error/octocat_happy.gif"
]
},
"gravatar_id": {
"type": [
"string",
"null"
],
"examples": [
"41d064eb2195891e12d0413f63227ea7"
]
},
"url": {
"type": "string",
"format": "uri",
"examples": [
"https://api.github.com/users/octocat"
]
},
"html_url": {
"type": "string",
"format": "uri",
"examples": [
"https://github.com/octocat"
]
},
"followers_url": {
"type": "string",
"format": "uri",
"examples": [
"https://api.github.com/users/octocat/followers"
]
},
"following_url": {
"type": "string",
"examples": [
"https://api.github.com/users/octocat/following{/other_user}"
]
},
"gists_url": {
"type": "string",
"examples": [
"https://api.github.com/users/octocat/gists{/gist_id}"
]
},
"starred_url": {
"type": "string",
"examples": [
"https://api.github.com/users/octocat/starred{/owner}{/repo}"
]
},
"subscriptions_url": {
"type": "string",
"format": "uri",
"examples": [
"https://api.github.com/users/octocat/subscriptions"
]
},
"organizations_url": {
"type": "string",
"format": "uri",
"examples": [
"https://api.github.com/users/octocat/orgs"
]
},
"repos_url": {
"type": "string",
"format": "uri",
"examples": [
"https://api.github.com/users/octocat/repos"
]
},
"events_url": {
"type": "string",
"examples": [
"https://api.github.com/users/octocat/events{/privacy}"
]
},
"received_events_url": {
"type": "string",
"format": "uri",
"examples": [
"https://api.github.com/users/octocat/received_events"
]
},
"type": {
"type": "string",
"examples": [
"User"
]
},
"site_admin": {
"type": "boolean"
},
"starred_at": {
"type": "string",
"examples": [
"\"2020-07-09T00:17:55Z\""
]
},
"user_view_type": {
"type": "string",
"examples": [
"public"
]
}
},
"required": [
"avatar_url",
"events_url",
"followers_url",
"following_url",
"gists_url",
"gravatar_id",
"html_url",
"id",
"node_id",
"login",
"organizations_url",
"received_events_url",
"repos_url",
"site_admin",
"starred_url",
"subscriptions_url",
"type",
"url"
]
},
"assets": {
"type": "array",
"items": {
"title": "Release Asset",
"description": "Data related to a release.",
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"browser_download_url": {
"type": "string",
"format": "uri"
},
"id": {
"type": "integer"
},
"node_id": {
"type": "string"
},
"name": {
"description": "The file name of the asset.",
"type": "string",
"examples": [
"Team Environment"
]
},
"label": {
"type": [
"string",
"null"
]
},
"state": {
"description": "State of the release asset.",
"type": "string",
"enum": [
"uploaded",
"open"
]
},
"content_type": {
"type": "string"
},
"size": {
"type": "integer"
},
"download_count": {
"type": "integer"
},
"created_at": {
"type": "string",
"format": "date-time"
},
"updated_at": {
"type": "string",
"format": "date-time"
},
"uploader": {
"anyOf": [
{
"type": "null"
},
{
"title": "Simple User",
"description": "A GitHub user.",
"type": "object",
"properties": {
"name": {
"type": [
"string",
"null"
]
},
"email": {
"type": [
"string",
"null"
]
},
"login": {
"type": "string",
"examples": [
"octocat"
]
},
"id": {
"type": "integer",
"format": "int64",
"examples": [
1
]
},
"node_id": {
"type": "string",
"examples": [
"MDQ6VXNlcjE="
]
},
"avatar_url": {
"type": "string",
"format": "uri",
"examples": [
"https://github.com/images/error/octocat_happy.gif"
]
},
"gravatar_id": {
"type": [
"string",
"null"
],
"examples": [
"41d064eb2195891e12d0413f63227ea7"
]
},
"url": {
"type": "string",
"format": "uri",
"examples": [
"https://api.github.com/users/octocat"
]
},
"html_url": {
"type": "string",
"format": "uri",
"examples": [
"https://github.com/octocat"
]
},
"followers_url": {
"type": "string",
"format": "uri",
"examples": [
"https://api.github.com/users/octocat/followers"
]
},
"following_url": {
"type": "string",
"examples": [
"https://api.github.com/users/octocat/following{/other_user}"
]
},
"gists_url": {
"type": "string",
"examples": [
"https://api.github.com/users/octocat/gists{/gist_id}"
]
},
"starred_url": {
"type": "string",
"examples": [
"https://api.github.com/users/octocat/starred{/owner}{/repo}"
]
},
"subscriptions_url": {
"type": "string",
"format": "uri",
"examples": [
"https://api.github.com/users/octocat/subscriptions"
]
},
"organizations_url": {
"type": "string",
"format": "uri",
"examples": [
"https://api.github.com/users/octocat/orgs"
]
},
"repos_url": {
"type": "string",
"format": "uri",
"examples": [
"https://api.github.com/users/octocat/repos"
]
},
"events_url": {
"type": "string",
"examples": [
"https://api.github.com/users/octocat/events{/privacy}"
]
},
"received_events_url": {
"type": "string",
"format": "uri",
"examples": [
"https://api.github.com/users/octocat/received_events"
]
},
"type": {
"type": "string",
"examples": [
"User"
]
},
"site_admin": {
"type": "boolean"
},
"starred_at": {
"type": "string",
"examples": [
"\"2020-07-09T00:17:55Z\""
]
},
"user_view_type": {
"type": "string",
"examples": [
"public"
]
}
},
"required": [
"avatar_url",
"events_url",
"followers_url",
"following_url",
"gists_url",
"gravatar_id",
"html_url",
"id",
"node_id",
"login",
"organizations_url",
"received_events_url",
"repos_url",
"site_admin",
"starred_url",
"subscriptions_url",
"type",
"url"
]
}
]
}
},
"required": [
"id",
"name",
"content_type",
"size",
"state",
"url",
"node_id",
"download_count",
"label",
"uploader",
"browser_download_url",
"created_at",
"updated_at"
]
}
},
"body_html": {
"type": "string"
},
"body_text": {
"type": "string"
},
"mentions_count": {
"type": "integer"
},
"discussion_url": {
"description": "The URL of the release discussion.",
"type": "string",
"format": "uri"
},
"reactions": {
"title": "Reaction Rollup",
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"total_count": {
"type": "integer"
},
"+1": {
"type": "integer"
},
"-1": {
"type": "integer"
},
"laugh": {
"type": "integer"
},
"confused": {
"type": "integer"
},
"heart": {
"type": "integer"
},
"hooray": {
"type": "integer"
},
"eyes": {
"type": "integer"
},
"rocket": {
"type": "integer"
}
},
"required": [
"url",
"total_count",
"+1",
"-1",
"laugh",
"confused",
"heart",
"hooray",
"eyes",
"rocket"
]
}
},
"required": [
"assets_url",
"upload_url",
"tarball_url",
"zipball_url",
"created_at",
"published_at",
"draft",
"id",
"node_id",
"author",
"html_url",
"name",
"prerelease",
"tag_name",
"target_commitish",
"assets",
"url"
]
}
@prabhu I don't think its necessary capture all of the release's properties in the PURL. As long as there is enough information to uniquely identify a specific GitHub release we should be good.
Github Releases are mutable though. I can remove and reupload a new artifact with the same name. I think requiring the SHA256 or upload timestamp would be beneficial.
@jaimergp it turns out that the feature I'm working (the one which inspired the need for this new purl type) is to make releases immutable. When used in that context, the repo and tag should be sufficient to uniquely identify the release. Perhaps an optional checksum qualifier could be added to account for the current state of mutable releases?
@jaimergp I documented the checksum qualifier and also added a test in test-suite-data.json
Hey, I posted some comment in https://github.com/package-url/purl-spec/issues/299#issuecomment-2778692321 ... I need to think more about that one and how we can discover a release.
... and also in all cases, after the merge of PR #514, PURL types are now defined in JSON: :innocent: :grin:
- See #514
With the new approach... this PR would need to be updated.