From 5419a379f49fe64194c936709ffde30ccd4a6cf5 Mon Sep 17 00:00:00 2001 From: Michelangelo Mori Date: Wed, 22 May 2024 12:05:19 +0200 Subject: [PATCH] Fix erroneous lookup in github webhook handler. While adding tests I erroneously changed a lookup in a package event json from ".package.package_version.container_metadata.tag.name" to ".package.package_version.tag_name", which turned out to be both (a) the wrong thing to do and (b) causing an internal server error because "tag_name" field is not available (anymore?) for package events. --- .../controlplane/handlers_githubwebhooks.go | 8 +- .../handlers_githubwebhooks_test.go | 79 +++- internal/controlplane/package-published.json | 345 ++++++++++++++++++ 3 files changed, 415 insertions(+), 17 deletions(-) create mode 100644 internal/controlplane/package-published.json diff --git a/internal/controlplane/handlers_githubwebhooks.go b/internal/controlplane/handlers_githubwebhooks.go index 864c6930a7..60cc98808c 100644 --- a/internal/controlplane/handlers_githubwebhooks.go +++ b/internal/controlplane/handlers_githubwebhooks.go @@ -712,13 +712,7 @@ func extractArtifactVersionFromPayload(ctx context.Context, payload map[string]a if err != nil { return nil, err } - // Previous lookup was done at this path - // ".package.package_version.container_metadata.tag.name", - // which is unfortunately not have available under go-github, - // as field "container_metadata" is missing form its structs. - // I suggest using the following, although it's still to be - // verified whether that's the right one. - tag, err := util.JQReadFrom[string](ctx, ".package.package_version.tag_name", payload) + tag, err := util.JQReadFrom[string](ctx, ".package.package_version.container_metadata.tag.name", payload) if err != nil { return nil, err } diff --git a/internal/controlplane/handlers_githubwebhooks_test.go b/internal/controlplane/handlers_githubwebhooks_test.go index e4ecdbfd24..a132a173b2 100644 --- a/internal/controlplane/handlers_githubwebhooks_test.go +++ b/internal/controlplane/handlers_githubwebhooks_test.go @@ -21,6 +21,7 @@ import ( "crypto/hmac" "crypto/sha256" "database/sql" + _ "embed" "encoding/hex" "encoding/json" "fmt" @@ -51,6 +52,9 @@ import ( "github.com/stacklok/minder/internal/util/testqueue" ) +//go:embed package-published.json +var rawPackageEventPublished string + // MockClient is a mock implementation of the GitHub client. type MockClient struct { mock.Mock @@ -453,6 +457,7 @@ func (s *UnitTestSuite) TestHandlGitHubWebHook() { name string event string payload any + rawPayload []byte statusCode int queued bool }{ @@ -507,16 +512,21 @@ func (s *UnitTestSuite) TestHandlGitHubWebHook() { // https://docs.github.com/en/webhooks/webhook-events-and-payloads#package event: "package", // https://pkg.go.dev/github.com/google/go-github/v62@v62.0.0/github#PackageEvent - payload: &github.PackageEvent{ + payload: &packageEvent{ Action: github.String("published"), - Package: &github.Package{ + Package: &pkg{ Name: github.String("package-name"), PackageType: github.String("package-type"), // .package.package_version.container_metadata.tag.name - PackageVersion: &github.PackageVersion{ + PackageVersion: &packageVersion{ ID: github.Int64(1), Version: github.String("version"), - TagName: github.String("tagname"), + ContainerMedatata: &containerMetadata{ + Tag: &tag{ + Digest: github.String("digest"), + Name: github.String("tag"), + }, + }, }, Owner: &github.User{ Login: github.String("login"), @@ -535,20 +545,35 @@ func (s *UnitTestSuite) TestHandlGitHubWebHook() { statusCode: http.StatusOK, queued: true, }, + { + name: "package published raw payload", + // https://docs.github.com/en/webhooks/webhook-events-and-payloads#package + event: "package", + // https://pkg.go.dev/github.com/google/go-github/v62@v62.0.0/github#PackageEvent + rawPayload: []byte(rawPackageEventPublished), + statusCode: http.StatusOK, + queued: true, + }, { name: "package updated", // https://docs.github.com/en/webhooks/webhook-events-and-payloads#package event: "package", // https://pkg.go.dev/github.com/google/go-github/v62@v62.0.0/github#PackageEvent - payload: &github.PackageEvent{ + payload: &packageEvent{ Action: github.String("updated"), - Package: &github.Package{ + Package: &pkg{ Name: github.String("package-name"), PackageType: github.String("package-type"), - PackageVersion: &github.PackageVersion{ + // .package.package_version.container_metadata.tag.name + PackageVersion: &packageVersion{ ID: github.Int64(1), Version: github.String("version"), - TagName: github.String("tagname"), + ContainerMedatata: &containerMetadata{ + Tag: &tag{ + Digest: github.String("digest"), + Name: github.String("tag"), + }, + }, }, Owner: &github.User{ Login: github.String("login"), @@ -1636,8 +1661,13 @@ func (s *UnitTestSuite) TestHandlGitHubWebHook() { ts := httptest.NewServer(http.HandlerFunc(srv.HandleGitHubWebHook())) defer ts.Close() - packageJson, err := json.Marshal(tt.payload) - require.NoError(t, err, "failed to marshal package event") + var packageJson []byte + if tt.payload != nil { + packageJson, err = json.Marshal(tt.payload) + require.NoError(t, err, "failed to marshal package event") + } else { + packageJson = tt.rawPayload + } mac := hmac.New(sha256.New, []byte("test")) mac.Write(packageJson) @@ -1955,6 +1985,35 @@ type garbage struct { Garbage *string `json:"garbage,omitempty"` } +type packageEvent struct { + Action *string `json:"action,omitempty"` + Repo *github.Repository `json:"repository,omitempty"` + Org *github.Organization `json:"org,omitempty"` + Package *pkg `json:"package,omitempty"` +} + +type pkg struct { + Name *string `json:"name,omitempty"` + PackageType *string `json:"package_type,omitempty"` + PackageVersion *packageVersion `json:"package_version,omitempty"` + Owner *github.User `json:"owner,omitempty"` +} + +type packageVersion struct { + ID *int64 `json:"id,omitempty"` + Version *string `json:"version,omitempty"` + ContainerMedatata *containerMetadata `json:"container_metadata,omitempty"` +} + +type containerMetadata struct { + Tag *tag `json:"tag,omitempty"` +} + +type tag struct { + Digest *string `json:"digest,omitempty"` + Name *string `json:"name,omitempty"` +} + type branchProtectionConfigurationEvent struct { Action *string `json:"action,omitempty"` Repo *github.Repository `json:"repo,omitempty"` diff --git a/internal/controlplane/package-published.json b/internal/controlplane/package-published.json new file mode 100644 index 0000000000..2b689ff953 --- /dev/null +++ b/internal/controlplane/package-published.json @@ -0,0 +1,345 @@ +{ + "action": "published", + "package": { + "id": 12345, + "name": "demo-repo-go-debug", + "namespace": "stacklok", + "description": "", + "ecosystem": "CONTAINER", + "package_type": "CONTAINER", + "html_url": "https://github.com/stacklok/packages/12345", + "created_at": "2024-05-22T07:35:16Z", + "updated_at": "2024-05-22T07:35:19Z", + "owner": { + "login": "stacklok", + "id": 12345, + "node_id": "node_id", + "avatar_url": "https://avatars.githubusercontent.com/u/0?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/stacklok", + "html_url": "https://github.com/stacklok", + "followers_url": "https://api.github.com/users/stacklok/followers", + "following_url": "https://api.github.com/users/stacklok/following{/other_user}", + "gists_url": "https://api.github.com/users/stacklok/gists{/gist_id}", + "starred_url": "https://api.github.com/users/stacklok/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/stacklok/subscriptions", + "organizations_url": "https://api.github.com/users/stacklok/orgs", + "repos_url": "https://api.github.com/users/stacklok/repos", + "events_url": "https://api.github.com/users/stacklok/events{/privacy}", + "received_events_url": "https://api.github.com/users/stacklok/received_events", + "type": "User", + "site_admin": false + }, + "package_version": { + "id": 12345, + "version": "sha256:286c55a3aaaf75c5bab173d81f356ffda453c434ebf5fe580285dc4f92c2935d", + "name": "sha256:286c55a3aaaf75c5bab173d81f356ffda453c434ebf5fe580285dc4f92c2935d", + "description": "", + "summary": "", + "body": { + "repository": { + "repository": { + "id": 12345, + "name": "demo-repo-go-debug", + "owner_id": 12345, + "parent_id": null, + "sandbox": null, + "updated_at": "2024-05-22T07:33:21.000Z", + "created_at": "2024-05-22T07:33:15.000Z", + "public": true, + "description": null, + "homepage": null, + "source_id": 12345, + "public_push": null, + "disk_usage": 0, + "locked": false, + "pushed_at": "2024-05-22T07:33:21.000Z", + "watcher_count": 0, + "public_fork_count": 0, + "primary_language_name_id": 403, + "has_issues": true, + "has_wiki": true, + "has_downloads": true, + "raw_data": { + "data": { + "created_by_user_id": 12345, + "primary_language_name": "Makefile", + "completed_onboarding_tasks": [] + } + }, + "organization_id": null, + "disabled_at": null, + "disabled_by": null, + "disabling_reason": null, + "health_status": null, + "pushed_at_usec": 620545, + "active": true, + "reflog_sync_enabled": false, + "made_public_at": "2024-05-22T07:33:15.000Z", + "user_hidden": 0, + "maintained": true, + "template": false, + "owner_login": "stacklok", + "world_writable_wiki": false, + "refset_updated_at": "2024-05-22T07:33:21.000Z", + "disabling_detail": null, + "archived_at": null, + "deleted_at": null + } + }, + "info": { + "type": "blob", + "oid": "d90b57bf61d57c7d4de873a0faa29b32ee14067a", + "mode": 33188, + "name": "README.md", + "path": "README.md", + "size": 1789, + "collection": true, + "data": "data", + "truncated": false, + "size_over_limit": false, + "encoding": "UTF-8", + "binary": false + }, + "attributes": {}, + "_mime_type": { + "extension": "md", + "content_type": "text/markdown", + "encoding": "quoted-printable" + }, + "async_data": { + "state": "fulfilled", + "source": null, + "value": "value" + }, + "detect_encoding": { + "encoding": "UTF-8", + "ruby_encoding": "UTF-8", + "confidence": 100 + }, + "encoding": "UTF-8", + "git_lfs_blob": null, + "ruby_encoding": "UTF-8", + "encoded_newlines_re": "(?-mix:\\r\\n|\\r|\\n)", + "language": { + "name": "Markdown", + "fs_name": null, + "type": "prose", + "types": [ + "data", + "markup", + "programming", + "prose" + ], + "color": "#083fa1", + "aliases": [ + "markdown", + "md", + "pandoc" + ], + "tm_scope": "text.md", + "ace_mode": "markdown", + "codemirror_mode": "gfm", + "codemirror_mime_type": "text/x-gfm", + "wrap": true, + "language_id": 222, + "extensions": [ + ".md", + ".livemd", + ".markdown", + ".mdown", + ".mdwn", + ".mkd", + ".mkdn", + ".mkdown", + ".ronn", + ".scd", + ".workbook" + ], + "interpreters": [], + "filenames": [ + "contents.lr" + ], + "popular": false, + "group_name": "Markdown" + }, + "_formatted": true + }, + "manifest": "", + "html_url": "https://github.com/users/stacklok/packages/container/demo-repo-go-debug/12345", + "target_commitish": "main", + "target_oid": "ddf4cae131bc8ac75cefd48b250df5043c9a7c0c", + "created_at": "0001-01-01T00:00:00Z", + "updated_at": "0001-01-01T00:00:00Z", + "metadata": [], + "container_metadata": { + "tag": { + "name": "", + "digest": "sha256:286c55a3aaaf75c5bab173d81f356ffda453c434ebf5fe580285dc4f92c2935d" + }, + "labels": { + "description": "", + "source": "", + "revision": "", + "image_url": "", + "licenses": "", + "all_labels": {} + }, + "manifest": { + "digest": "sha256:286c55a3aaaf75c5bab173d81f356ffda453c434ebf5fe580285dc4f92c2935d", + "media_type": "application/vnd.oci.image.manifest.v1+json", + "uri": "repositories/stacklok/demo-repo-go-debug/manifests/sha256:286c55a3aaaf75c5bab173d81f356ffda453c434ebf5fe580285dc4f92c2935d", + "size": 566, + "config": { + "digest": "sha256:3680432ff6916ba0dda0b7da6a36f81b48db98fa93eebd91734e8c973f463dae", + "media_type": "application/vnd.oci.image.config.v1+json", + "size": 167 + }, + "layers": [ + { + "digest": "sha256:de81d5a36829e6a82a55e9d1dc42ba9725159ebcd8d311acf5d6c54d7b3868c1", + "media_type": "application/vnd.in-toto+json", + "size": 1285 + } + ] + } + }, + "package_files": [], + "installation_command": "docker pull ghcr.io/stacklok/demo-repo-go-debug:", + "package_url": "ghcr.io/stacklok/demo-repo-go-debug:" + }, + "registry": { + "about_url": "https://docs.github.com/packages/learn-github-packages/introduction-to-github-packages", + "name": "GitHub CONTAINER registry", + "type": "CONTAINER", + "url": "https://CONTAINER.pkg.github.com/stacklok", + "vendor": "GitHub Inc" + } + }, + "repository": { + "id": 12345, + "node_id": "node_id", + "name": "demo-repo-go-debug", + "full_name": "stacklok/demo-repo-go-debug", + "private": false, + "owner": { + "login": "stacklok", + "id": 12345, + "node_id": "node_id", + "avatar_url": "https://avatars.githubusercontent.com/u/0?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/stacklok", + "html_url": "https://github.com/stacklok", + "followers_url": "https://api.github.com/users/stacklok/followers", + "following_url": "https://api.github.com/users/stacklok/following{/other_user}", + "gists_url": "https://api.github.com/users/stacklok/gists{/gist_id}", + "starred_url": "https://api.github.com/users/stacklok/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/stacklok/subscriptions", + "organizations_url": "https://api.github.com/users/stacklok/orgs", + "repos_url": "https://api.github.com/users/stacklok/repos", + "events_url": "https://api.github.com/users/stacklok/events{/privacy}", + "received_events_url": "https://api.github.com/users/stacklok/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/stacklok/demo-repo-go-debug", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/stacklok/demo-repo-go-debug", + "forks_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/forks", + "keys_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/teams", + "hooks_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/hooks", + "issue_events_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/issues/events{/number}", + "events_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/events", + "assignees_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/assignees{/user}", + "branches_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/branches{/branch}", + "tags_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/tags", + "blobs_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/statuses/{sha}", + "languages_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/languages", + "stargazers_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/stargazers", + "contributors_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/contributors", + "subscribers_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/subscribers", + "subscription_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/subscription", + "commits_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/contents/{+path}", + "compare_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/merges", + "archive_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/downloads", + "issues_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/issues{/number}", + "pulls_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/pulls{/number}", + "milestones_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/milestones{/number}", + "notifications_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/labels{/name}", + "releases_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/releases{/id}", + "deployments_url": "https://api.github.com/repos/stacklok/demo-repo-go-debug/deployments", + "created_at": "2024-05-22T07:33:15Z", + "updated_at": "2024-05-22T07:33:21Z", + "pushed_at": "2024-05-22T07:33:21Z", + "git_url": "git://github.com/stacklok/demo-repo-go-debug.git", + "ssh_url": "git@github.com:stacklok/demo-repo-go-debug.git", + "clone_url": "https://github.com/stacklok/demo-repo-go-debug.git", + "svn_url": "https://github.com/stacklok/demo-repo-go-debug", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Makefile", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": { + "key": "other", + "name": "Other", + "spdx_id": "NOASSERTION", + "url": null, + "node_id": "node_id" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "main" + }, + "sender": { + "login": "github-actions[bot]", + "id": 12345, + "node_id": "node_id", + "avatar_url": "https://avatars.githubusercontent.com/in/0?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "site_admin": false + } +}