Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add github-release package type #418

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

bdehamer
Copy link

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/bar@v1.0.0

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/bar@v1.0.0

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.

@jkowalleck jkowalleck linked an issue Mar 18, 2025 that may be closed by this pull request
jkowalleck
jkowalleck previously approved these changes Mar 18, 2025
@jkowalleck
Copy link
Member

jkowalleck commented Mar 18, 2025

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

couldyou add those to the spec?

jkowalleck
jkowalleck previously approved these changes Mar 18, 2025
@bdehamer
Copy link
Author

bdehamer commented Mar 18, 2025

@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/bar@v1.0.0?file_name=bin-linux.tgz

@prabhu
Copy link

prabhu commented Mar 19, 2025

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"
    ]
  }

@bdehamer
Copy link
Author

bdehamer commented Apr 3, 2025

@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.

@jaimergp
Copy link

jaimergp commented Apr 3, 2025

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.

@bdehamer
Copy link
Author

bdehamer commented Apr 3, 2025

@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?

bdehamer added 2 commits April 3, 2025 16:50
Signed-off-by: Brian DeHamer <bdehamer@github.com>
Signed-off-by: Brian DeHamer <bdehamer@github.com>
@bdehamer bdehamer force-pushed the bdehamer/github-release branch from 2804d56 to 56783d3 Compare April 3, 2025 23:52
bdehamer added 2 commits April 3, 2025 16:52
Signed-off-by: Brian DeHamer <bdehamer@github.com>
Signed-off-by: Brian DeHamer <bdehamer@github.com>
@bdehamer bdehamer force-pushed the bdehamer/github-release branch from 56783d3 to 4975be7 Compare April 3, 2025 23:52
@bdehamer
Copy link
Author

bdehamer commented Apr 3, 2025

@jaimergp I documented the checksum qualifier and also added a test in test-suite-data.json

> When percent-encoding is required, all characters MUST be encoded except for the colon ':'.
fix examples for `github-release` examples

> When percent-encoding is required, all characters MUST be encoded except for the colon ':'.
@jkowalleck jkowalleck requested a review from a team April 4, 2025 06:29
@pombredanne
Copy link
Member

Hey, I posted some comment in #299 (comment) ... I need to think more about that one and how we can discover a release.

@johnmhoran johnmhoran added this to the 1.1 milestone Apr 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Proposal: github-release type
6 participants