github.com/google/go-github/v64@v64.0.0/github/security_advisories_test.go (about)

     1  // Copyright 2023 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package github
     7  
     8  import (
     9  	"context"
    10  	"fmt"
    11  	"net/http"
    12  	"strings"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/google/go-cmp/cmp"
    17  )
    18  
    19  func TestSecurityAdvisoriesService_RequestCVE(t *testing.T) {
    20  	client, mux, _, teardown := setup()
    21  	defer teardown()
    22  
    23  	mux.HandleFunc("/repos/o/r/security-advisories/ghsa_id_ok/cve", func(w http.ResponseWriter, r *http.Request) {
    24  		testMethod(t, r, "POST")
    25  		w.WriteHeader(http.StatusOK)
    26  	})
    27  
    28  	mux.HandleFunc("/repos/o/r/security-advisories/ghsa_id_accepted/cve", func(w http.ResponseWriter, r *http.Request) {
    29  		testMethod(t, r, "POST")
    30  		w.WriteHeader(http.StatusAccepted)
    31  	})
    32  
    33  	ctx := context.Background()
    34  	_, err := client.SecurityAdvisories.RequestCVE(ctx, "o", "r", "ghsa_id_ok")
    35  	if err != nil {
    36  		t.Errorf("SecurityAdvisoriesService.RequestCVE returned error: %v", err)
    37  	}
    38  
    39  	_, err = client.SecurityAdvisories.RequestCVE(ctx, "o", "r", "ghsa_id_accepted")
    40  	if err != nil {
    41  		t.Errorf("SecurityAdvisoriesService.RequestCVE returned error: %v", err)
    42  	}
    43  
    44  	const methodName = "RequestCVE"
    45  	testBadOptions(t, methodName, func() (err error) {
    46  		_, err = client.SecurityAdvisories.RequestCVE(ctx, "\n", "\n", "\n")
    47  		return err
    48  	})
    49  
    50  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    51  		resp, err := client.SecurityAdvisories.RequestCVE(ctx, "o", "r", "ghsa_id")
    52  		if err == nil {
    53  			t.Errorf("testNewRequestAndDoFailure %v should have return err", methodName)
    54  		}
    55  		return resp, err
    56  	})
    57  }
    58  
    59  func TestSecurityAdvisoriesService_CreateTemporaryPrivateFork(t *testing.T) {
    60  	client, mux, _, teardown := setup()
    61  	defer teardown()
    62  
    63  	mux.HandleFunc("/repos/o/r/security-advisories/ghsa_id/forks", func(w http.ResponseWriter, r *http.Request) {
    64  		testMethod(t, r, "POST")
    65  		fmt.Fprint(w, `{
    66  			"id": 1,
    67  			"node_id": "R_kgDPP3c6pQ",
    68  			"owner": {
    69  				"login": "owner",
    70  				"id": 2,
    71  				"node_id": "MDQ6VXFGcjYyMjcyMTQw",
    72  				"avatar_url": "https://avatars.githubusercontent.com/u/111111?v=4",
    73  				"html_url": "https://github.com/xxxxx",
    74  				"gravatar_id": "",
    75  				"type": "User",
    76  				"site_admin": false,
    77  				"url": "https://api.github.com/users/owner",
    78  				"events_url": "https://api.github.com/users/owner/events{/privacy}",
    79  				"following_url": "https://api.github.com/users/owner/following{/other_user}",
    80  				"followers_url": "https://api.github.com/users/owner/followers",
    81  				"gists_url": "https://api.github.com/users/owner/gists{/gist_id}",
    82  				"organizations_url": "https://api.github.com/users/owner/orgs",
    83  				"received_events_url": "https://api.github.com/users/owner/received_events",
    84  				"repos_url": "https://api.github.com/users/owner/repos",
    85  				"starred_url": "https://api.github.com/users/owner/starred{/owner}{/repo}",
    86  				"subscriptions_url": "https://api.github.com/users/owner/subscriptions"
    87  			},
    88  			"name": "repo-ghsa-xxxx-xxxx-xxxx",
    89  			"full_name": "owner/repo-ghsa-xxxx-xxxx-xxxx",
    90  			"default_branch": "master",
    91  			"created_at": "2023-12-08T17:22:41Z",
    92  			"pushed_at": "2023-12-03T11:27:08Z",
    93  			"updated_at": "2023-12-08T17:22:42Z",
    94  			"html_url": "https://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx",
    95  			"clone_url": "https://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx.git",
    96  			"git_url": "git://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx.git",
    97  			"ssh_url": "git@github.com:owner/repo-ghsa-xxxx-xxxx-xxxx.git",
    98  			"svn_url": "https://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx",
    99  			"fork": false,
   100  			"forks_count": 0,
   101  			"network_count": 0,
   102  			"open_issues_count": 0,
   103  			"open_issues": 0,
   104  			"stargazers_count": 0,
   105  			"subscribers_count": 0,
   106  			"watchers_count": 0,
   107  			"watchers": 0,
   108  			"size": 0,
   109  			"permissions": {
   110  				"admin": true,
   111  				"maintain": true,
   112  				"pull": true,
   113  				"push": true,
   114  				"triage": true
   115  			},
   116  			"allow_forking": true,
   117  			"web_commit_signoff_required": false,
   118  			"archived": false,
   119  			"disabled": false,
   120  			"private": true,
   121  			"has_issues": false,
   122  			"has_wiki": false,
   123  			"has_pages": false,
   124  			"has_projects": false,
   125  			"has_downloads": false,
   126  			"has_discussions": false,
   127  			"is_template": false,
   128  			"url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx",
   129  			"archive_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/{archive_format}{/ref}",
   130  			"assignees_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/assignees{/user}",
   131  			"blobs_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/blobs{/sha}",
   132  			"branches_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/branches{/branch}",
   133  			"collaborators_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/collaborators{/collaborator}",
   134  			"comments_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/comments{/number}",
   135  			"commits_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/commits{/sha}",
   136  			"compare_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/compare/{base}...{head}",
   137  			"contents_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/contents/{+path}",
   138  			"contributors_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/contributors",
   139  			"deployments_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/deployments",
   140  			"downloads_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/downloads",
   141  			"events_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/events",
   142  			"forks_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/forks",
   143  			"git_commits_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/commits{/sha}",
   144  			"git_refs_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/refs{/sha}",
   145  			"git_tags_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/tags{/sha}",
   146  			"hooks_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/hooks",
   147  			"issue_comment_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/issues/comments{/number}",
   148  			"issue_events_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/issues/events{/number}",
   149  			"issues_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/issues{/number}",
   150  			"keys_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/keys{/key_id}",
   151  			"labels_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/labels{/name}",
   152  			"languages_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/languages",
   153  			"merges_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/merges",
   154  			"milestones_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/milestones{/number}",
   155  			"notifications_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/notifications{?since,all,participating}",
   156  			"pulls_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/pulls{/number}",
   157  			"releases_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/releases{/id}",
   158  			"stargazers_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/stargazers",
   159  			"statuses_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/statuses/{sha}",
   160  			"subscribers_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/subscribers",
   161  			"subscription_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/subscription",
   162  			"tags_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/tags",
   163  			"teams_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/teams",
   164  			"visibility": "private"
   165  		}`)
   166  	})
   167  
   168  	ctx := context.Background()
   169  	fork, _, err := client.SecurityAdvisories.CreateTemporaryPrivateFork(ctx, "o", "r", "ghsa_id")
   170  	if err != nil {
   171  		t.Errorf("SecurityAdvisoriesService.CreateTemporaryPrivateFork returned error: %v", err)
   172  	}
   173  
   174  	want := &Repository{
   175  		ID:     Int64(1),
   176  		NodeID: String("R_kgDPP3c6pQ"),
   177  		Owner: &User{
   178  			Login:             String("owner"),
   179  			ID:                Int64(2),
   180  			NodeID:            String("MDQ6VXFGcjYyMjcyMTQw"),
   181  			AvatarURL:         String("https://avatars.githubusercontent.com/u/111111?v=4"),
   182  			HTMLURL:           String("https://github.com/xxxxx"),
   183  			GravatarID:        String(""),
   184  			Type:              String("User"),
   185  			SiteAdmin:         Bool(false),
   186  			URL:               String("https://api.github.com/users/owner"),
   187  			EventsURL:         String("https://api.github.com/users/owner/events{/privacy}"),
   188  			FollowingURL:      String("https://api.github.com/users/owner/following{/other_user}"),
   189  			FollowersURL:      String("https://api.github.com/users/owner/followers"),
   190  			GistsURL:          String("https://api.github.com/users/owner/gists{/gist_id}"),
   191  			OrganizationsURL:  String("https://api.github.com/users/owner/orgs"),
   192  			ReceivedEventsURL: String("https://api.github.com/users/owner/received_events"),
   193  			ReposURL:          String("https://api.github.com/users/owner/repos"),
   194  			StarredURL:        String("https://api.github.com/users/owner/starred{/owner}{/repo}"),
   195  			SubscriptionsURL:  String("https://api.github.com/users/owner/subscriptions"),
   196  		},
   197  		Name:             String("repo-ghsa-xxxx-xxxx-xxxx"),
   198  		FullName:         String("owner/repo-ghsa-xxxx-xxxx-xxxx"),
   199  		DefaultBranch:    String("master"),
   200  		CreatedAt:        &Timestamp{time.Date(2023, time.December, 8, 17, 22, 41, 0, time.UTC)},
   201  		PushedAt:         &Timestamp{time.Date(2023, time.December, 3, 11, 27, 8, 0, time.UTC)},
   202  		UpdatedAt:        &Timestamp{time.Date(2023, time.December, 8, 17, 22, 42, 0, time.UTC)},
   203  		HTMLURL:          String("https://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx"),
   204  		CloneURL:         String("https://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx.git"),
   205  		GitURL:           String("git://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx.git"),
   206  		SSHURL:           String("git@github.com:owner/repo-ghsa-xxxx-xxxx-xxxx.git"),
   207  		SVNURL:           String("https://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx"),
   208  		Fork:             Bool(false),
   209  		ForksCount:       Int(0),
   210  		NetworkCount:     Int(0),
   211  		OpenIssuesCount:  Int(0),
   212  		OpenIssues:       Int(0),
   213  		StargazersCount:  Int(0),
   214  		SubscribersCount: Int(0),
   215  		WatchersCount:    Int(0),
   216  		Watchers:         Int(0),
   217  		Size:             Int(0),
   218  		Permissions: map[string]bool{
   219  			"admin":    true,
   220  			"maintain": true,
   221  			"pull":     true,
   222  			"push":     true,
   223  			"triage":   true,
   224  		},
   225  		AllowForking:             Bool(true),
   226  		WebCommitSignoffRequired: Bool(false),
   227  		Archived:                 Bool(false),
   228  		Disabled:                 Bool(false),
   229  		Private:                  Bool(true),
   230  		HasIssues:                Bool(false),
   231  		HasWiki:                  Bool(false),
   232  		HasPages:                 Bool(false),
   233  		HasProjects:              Bool(false),
   234  		HasDownloads:             Bool(false),
   235  		HasDiscussions:           Bool(false),
   236  		IsTemplate:               Bool(false),
   237  		URL:                      String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx"),
   238  		ArchiveURL:               String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/{archive_format}{/ref}"),
   239  		AssigneesURL:             String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/assignees{/user}"),
   240  		BlobsURL:                 String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/blobs{/sha}"),
   241  		BranchesURL:              String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/branches{/branch}"),
   242  		CollaboratorsURL:         String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/collaborators{/collaborator}"),
   243  		CommentsURL:              String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/comments{/number}"),
   244  		CommitsURL:               String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/commits{/sha}"),
   245  		CompareURL:               String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/compare/{base}...{head}"),
   246  		ContentsURL:              String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/contents/{+path}"),
   247  		ContributorsURL:          String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/contributors"),
   248  		DeploymentsURL:           String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/deployments"),
   249  		DownloadsURL:             String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/downloads"),
   250  		EventsURL:                String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/events"),
   251  		ForksURL:                 String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/forks"),
   252  		GitCommitsURL:            String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/commits{/sha}"),
   253  		GitRefsURL:               String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/refs{/sha}"),
   254  		GitTagsURL:               String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/tags{/sha}"),
   255  		HooksURL:                 String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/hooks"),
   256  		IssueCommentURL:          String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/issues/comments{/number}"),
   257  		IssueEventsURL:           String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/issues/events{/number}"),
   258  		IssuesURL:                String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/issues{/number}"),
   259  		KeysURL:                  String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/keys{/key_id}"),
   260  		LabelsURL:                String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/labels{/name}"),
   261  		LanguagesURL:             String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/languages"),
   262  		MergesURL:                String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/merges"),
   263  		MilestonesURL:            String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/milestones{/number}"),
   264  		NotificationsURL:         String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/notifications{?since,all,participating}"),
   265  		PullsURL:                 String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/pulls{/number}"),
   266  		ReleasesURL:              String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/releases{/id}"),
   267  		StargazersURL:            String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/stargazers"),
   268  		StatusesURL:              String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/statuses/{sha}"),
   269  		SubscribersURL:           String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/subscribers"),
   270  		SubscriptionURL:          String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/subscription"),
   271  		TagsURL:                  String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/tags"),
   272  		TeamsURL:                 String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/teams"),
   273  		Visibility:               String("private"),
   274  	}
   275  	if !cmp.Equal(fork, want) {
   276  		t.Errorf("SecurityAdvisoriesService.CreateTemporaryPrivateFork returned %+v, want %+v", fork, want)
   277  	}
   278  
   279  	const methodName = "CreateTemporaryPrivateFork"
   280  	testBadOptions(t, methodName, func() (err error) {
   281  		_, _, err = client.SecurityAdvisories.CreateTemporaryPrivateFork(ctx, "\n", "\n", "\n")
   282  		return err
   283  	})
   284  
   285  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   286  		got, resp, err := client.SecurityAdvisories.CreateTemporaryPrivateFork(ctx, "o", "r", "ghsa_id")
   287  		if got != nil {
   288  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   289  		}
   290  		return resp, err
   291  	})
   292  }
   293  
   294  func TestSecurityAdvisoriesService_CreateTemporaryPrivateFork_deferred(t *testing.T) {
   295  	client, mux, _, teardown := setup()
   296  	defer teardown()
   297  
   298  	mux.HandleFunc("/repos/o/r/security-advisories/ghsa_id/forks", func(w http.ResponseWriter, r *http.Request) {
   299  		testMethod(t, r, "POST")
   300  		w.WriteHeader(http.StatusAccepted)
   301  		fmt.Fprint(w, `{
   302  			"id": 1,
   303  			"node_id": "R_kgDPP3c6pQ",
   304  			"owner": {
   305  				"login": "owner",
   306  				"id": 2,
   307  				"node_id": "MDQ6VXFGcjYyMjcyMTQw",
   308  				"avatar_url": "https://avatars.githubusercontent.com/u/111111?v=4",
   309  				"html_url": "https://github.com/xxxxx",
   310  				"gravatar_id": "",
   311  				"type": "User",
   312  				"site_admin": false,
   313  				"url": "https://api.github.com/users/owner",
   314  				"events_url": "https://api.github.com/users/owner/events{/privacy}",
   315  				"following_url": "https://api.github.com/users/owner/following{/other_user}",
   316  				"followers_url": "https://api.github.com/users/owner/followers",
   317  				"gists_url": "https://api.github.com/users/owner/gists{/gist_id}",
   318  				"organizations_url": "https://api.github.com/users/owner/orgs",
   319  				"received_events_url": "https://api.github.com/users/owner/received_events",
   320  				"repos_url": "https://api.github.com/users/owner/repos",
   321  				"starred_url": "https://api.github.com/users/owner/starred{/owner}{/repo}",
   322  				"subscriptions_url": "https://api.github.com/users/owner/subscriptions"
   323  			},
   324  			"name": "repo-ghsa-xxxx-xxxx-xxxx",
   325  			"full_name": "owner/repo-ghsa-xxxx-xxxx-xxxx",
   326  			"default_branch": "master",
   327  			"created_at": "2023-12-08T17:22:41Z",
   328  			"pushed_at": "2023-12-03T11:27:08Z",
   329  			"updated_at": "2023-12-08T17:22:42Z",
   330  			"html_url": "https://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx",
   331  			"clone_url": "https://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx.git",
   332  			"git_url": "git://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx.git",
   333  			"ssh_url": "git@github.com:owner/repo-ghsa-xxxx-xxxx-xxxx.git",
   334  			"svn_url": "https://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx",
   335  			"fork": false,
   336  			"forks_count": 0,
   337  			"network_count": 0,
   338  			"open_issues_count": 0,
   339  			"open_issues": 0,
   340  			"stargazers_count": 0,
   341  			"subscribers_count": 0,
   342  			"watchers_count": 0,
   343  			"watchers": 0,
   344  			"size": 0,
   345  			"permissions": {
   346  				"admin": true,
   347  				"maintain": true,
   348  				"pull": true,
   349  				"push": true,
   350  				"triage": true
   351  			},
   352  			"allow_forking": true,
   353  			"web_commit_signoff_required": false,
   354  			"archived": false,
   355  			"disabled": false,
   356  			"private": true,
   357  			"has_issues": false,
   358  			"has_wiki": false,
   359  			"has_pages": false,
   360  			"has_projects": false,
   361  			"has_downloads": false,
   362  			"has_discussions": false,
   363  			"is_template": false,
   364  			"url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx",
   365  			"archive_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/{archive_format}{/ref}",
   366  			"assignees_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/assignees{/user}",
   367  			"blobs_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/blobs{/sha}",
   368  			"branches_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/branches{/branch}",
   369  			"collaborators_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/collaborators{/collaborator}",
   370  			"comments_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/comments{/number}",
   371  			"commits_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/commits{/sha}",
   372  			"compare_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/compare/{base}...{head}",
   373  			"contents_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/contents/{+path}",
   374  			"contributors_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/contributors",
   375  			"deployments_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/deployments",
   376  			"downloads_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/downloads",
   377  			"events_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/events",
   378  			"forks_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/forks",
   379  			"git_commits_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/commits{/sha}",
   380  			"git_refs_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/refs{/sha}",
   381  			"git_tags_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/tags{/sha}",
   382  			"hooks_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/hooks",
   383  			"issue_comment_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/issues/comments{/number}",
   384  			"issue_events_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/issues/events{/number}",
   385  			"issues_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/issues{/number}",
   386  			"keys_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/keys{/key_id}",
   387  			"labels_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/labels{/name}",
   388  			"languages_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/languages",
   389  			"merges_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/merges",
   390  			"milestones_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/milestones{/number}",
   391  			"notifications_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/notifications{?since,all,participating}",
   392  			"pulls_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/pulls{/number}",
   393  			"releases_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/releases{/id}",
   394  			"stargazers_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/stargazers",
   395  			"statuses_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/statuses/{sha}",
   396  			"subscribers_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/subscribers",
   397  			"subscription_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/subscription",
   398  			"tags_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/tags",
   399  			"teams_url": "https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/teams",
   400  			"visibility": "private"
   401  		}`)
   402  	})
   403  
   404  	ctx := context.Background()
   405  	fork, _, err := client.SecurityAdvisories.CreateTemporaryPrivateFork(ctx, "o", "r", "ghsa_id")
   406  	if _, ok := err.(*AcceptedError); !ok {
   407  		t.Errorf("SecurityAdvisoriesService.CreateTemporaryPrivateFork returned error: %v (want AcceptedError)", err)
   408  	}
   409  
   410  	want := &Repository{
   411  		ID:     Int64(1),
   412  		NodeID: String("R_kgDPP3c6pQ"),
   413  		Owner: &User{
   414  			Login:             String("owner"),
   415  			ID:                Int64(2),
   416  			NodeID:            String("MDQ6VXFGcjYyMjcyMTQw"),
   417  			AvatarURL:         String("https://avatars.githubusercontent.com/u/111111?v=4"),
   418  			HTMLURL:           String("https://github.com/xxxxx"),
   419  			GravatarID:        String(""),
   420  			Type:              String("User"),
   421  			SiteAdmin:         Bool(false),
   422  			URL:               String("https://api.github.com/users/owner"),
   423  			EventsURL:         String("https://api.github.com/users/owner/events{/privacy}"),
   424  			FollowingURL:      String("https://api.github.com/users/owner/following{/other_user}"),
   425  			FollowersURL:      String("https://api.github.com/users/owner/followers"),
   426  			GistsURL:          String("https://api.github.com/users/owner/gists{/gist_id}"),
   427  			OrganizationsURL:  String("https://api.github.com/users/owner/orgs"),
   428  			ReceivedEventsURL: String("https://api.github.com/users/owner/received_events"),
   429  			ReposURL:          String("https://api.github.com/users/owner/repos"),
   430  			StarredURL:        String("https://api.github.com/users/owner/starred{/owner}{/repo}"),
   431  			SubscriptionsURL:  String("https://api.github.com/users/owner/subscriptions"),
   432  		},
   433  		Name:             String("repo-ghsa-xxxx-xxxx-xxxx"),
   434  		FullName:         String("owner/repo-ghsa-xxxx-xxxx-xxxx"),
   435  		DefaultBranch:    String("master"),
   436  		CreatedAt:        &Timestamp{time.Date(2023, time.December, 8, 17, 22, 41, 0, time.UTC)},
   437  		PushedAt:         &Timestamp{time.Date(2023, time.December, 3, 11, 27, 8, 0, time.UTC)},
   438  		UpdatedAt:        &Timestamp{time.Date(2023, time.December, 8, 17, 22, 42, 0, time.UTC)},
   439  		HTMLURL:          String("https://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx"),
   440  		CloneURL:         String("https://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx.git"),
   441  		GitURL:           String("git://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx.git"),
   442  		SSHURL:           String("git@github.com:owner/repo-ghsa-xxxx-xxxx-xxxx.git"),
   443  		SVNURL:           String("https://github.com/owner/repo-ghsa-xxxx-xxxx-xxxx"),
   444  		Fork:             Bool(false),
   445  		ForksCount:       Int(0),
   446  		NetworkCount:     Int(0),
   447  		OpenIssuesCount:  Int(0),
   448  		OpenIssues:       Int(0),
   449  		StargazersCount:  Int(0),
   450  		SubscribersCount: Int(0),
   451  		WatchersCount:    Int(0),
   452  		Watchers:         Int(0),
   453  		Size:             Int(0),
   454  		Permissions: map[string]bool{
   455  			"admin":    true,
   456  			"maintain": true,
   457  			"pull":     true,
   458  			"push":     true,
   459  			"triage":   true,
   460  		},
   461  		AllowForking:             Bool(true),
   462  		WebCommitSignoffRequired: Bool(false),
   463  		Archived:                 Bool(false),
   464  		Disabled:                 Bool(false),
   465  		Private:                  Bool(true),
   466  		HasIssues:                Bool(false),
   467  		HasWiki:                  Bool(false),
   468  		HasPages:                 Bool(false),
   469  		HasProjects:              Bool(false),
   470  		HasDownloads:             Bool(false),
   471  		HasDiscussions:           Bool(false),
   472  		IsTemplate:               Bool(false),
   473  		URL:                      String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx"),
   474  		ArchiveURL:               String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/{archive_format}{/ref}"),
   475  		AssigneesURL:             String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/assignees{/user}"),
   476  		BlobsURL:                 String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/blobs{/sha}"),
   477  		BranchesURL:              String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/branches{/branch}"),
   478  		CollaboratorsURL:         String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/collaborators{/collaborator}"),
   479  		CommentsURL:              String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/comments{/number}"),
   480  		CommitsURL:               String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/commits{/sha}"),
   481  		CompareURL:               String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/compare/{base}...{head}"),
   482  		ContentsURL:              String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/contents/{+path}"),
   483  		ContributorsURL:          String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/contributors"),
   484  		DeploymentsURL:           String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/deployments"),
   485  		DownloadsURL:             String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/downloads"),
   486  		EventsURL:                String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/events"),
   487  		ForksURL:                 String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/forks"),
   488  		GitCommitsURL:            String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/commits{/sha}"),
   489  		GitRefsURL:               String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/refs{/sha}"),
   490  		GitTagsURL:               String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/git/tags{/sha}"),
   491  		HooksURL:                 String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/hooks"),
   492  		IssueCommentURL:          String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/issues/comments{/number}"),
   493  		IssueEventsURL:           String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/issues/events{/number}"),
   494  		IssuesURL:                String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/issues{/number}"),
   495  		KeysURL:                  String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/keys{/key_id}"),
   496  		LabelsURL:                String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/labels{/name}"),
   497  		LanguagesURL:             String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/languages"),
   498  		MergesURL:                String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/merges"),
   499  		MilestonesURL:            String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/milestones{/number}"),
   500  		NotificationsURL:         String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/notifications{?since,all,participating}"),
   501  		PullsURL:                 String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/pulls{/number}"),
   502  		ReleasesURL:              String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/releases{/id}"),
   503  		StargazersURL:            String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/stargazers"),
   504  		StatusesURL:              String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/statuses/{sha}"),
   505  		SubscribersURL:           String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/subscribers"),
   506  		SubscriptionURL:          String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/subscription"),
   507  		TagsURL:                  String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/tags"),
   508  		TeamsURL:                 String("https://api.github.com/repos/owner/repo-ghsa-xxxx-xxxx-xxxx/teams"),
   509  		Visibility:               String("private"),
   510  	}
   511  	if !cmp.Equal(fork, want) {
   512  		t.Errorf("SecurityAdvisoriesService.CreateTemporaryPrivateFork returned %+v, want %+v", fork, want)
   513  	}
   514  }
   515  
   516  func TestSecurityAdvisoriesService_CreateTemporaryPrivateFork_invalidOwner(t *testing.T) {
   517  	client, _, _, teardown := setup()
   518  	defer teardown()
   519  
   520  	ctx := context.Background()
   521  	_, _, err := client.SecurityAdvisories.CreateTemporaryPrivateFork(ctx, "%", "r", "ghsa_id")
   522  	testURLParseError(t, err)
   523  }
   524  
   525  func TestSecurityAdvisoriesService_ListRepositorySecurityAdvisoriesForOrg_BadRequest(t *testing.T) {
   526  	client, mux, _, teardown := setup()
   527  	defer teardown()
   528  
   529  	mux.HandleFunc("/orgs/o/security-advisories", func(w http.ResponseWriter, r *http.Request) {
   530  		testMethod(t, r, "GET")
   531  
   532  		http.Error(w, "Bad Request", 400)
   533  	})
   534  
   535  	ctx := context.Background()
   536  	advisories, resp, err := client.SecurityAdvisories.ListRepositorySecurityAdvisoriesForOrg(ctx, "o", nil)
   537  	if err == nil {
   538  		t.Errorf("Expected HTTP 400 response")
   539  	}
   540  	if got, want := resp.Response.StatusCode, http.StatusBadRequest; got != want {
   541  		t.Errorf("ListRepositorySecurityAdvisoriesForOrg return status %d, want %d", got, want)
   542  	}
   543  	if advisories != nil {
   544  		t.Errorf("ListRepositorySecurityAdvisoriesForOrg return %+v, want nil", advisories)
   545  	}
   546  }
   547  
   548  func TestSecurityAdvisoriesService_ListRepositorySecurityAdvisoriesForOrg_NotFound(t *testing.T) {
   549  	client, mux, _, teardown := setup()
   550  	defer teardown()
   551  
   552  	mux.HandleFunc("/orgs/o/security-advisories", func(w http.ResponseWriter, r *http.Request) {
   553  		testMethod(t, r, "GET")
   554  
   555  		query := r.URL.Query()
   556  		if query.Get("state") != "draft" {
   557  			t.Errorf("ListRepositorySecurityAdvisoriesForOrg returned %+v, want %+v", query.Get("state"), "draft")
   558  		}
   559  
   560  		http.NotFound(w, r)
   561  	})
   562  
   563  	ctx := context.Background()
   564  	advisories, resp, err := client.SecurityAdvisories.ListRepositorySecurityAdvisoriesForOrg(ctx, "o", &ListRepositorySecurityAdvisoriesOptions{
   565  		State: "draft",
   566  	})
   567  	if err == nil {
   568  		t.Errorf("Expected HTTP 404 response")
   569  	}
   570  	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
   571  		t.Errorf("ListRepositorySecurityAdvisoriesForOrg return status %d, want %d", got, want)
   572  	}
   573  	if advisories != nil {
   574  		t.Errorf("ListRepositorySecurityAdvisoriesForOrg return %+v, want nil", advisories)
   575  	}
   576  }
   577  
   578  func TestSecurityAdvisoriesService_ListRepositorySecurityAdvisoriesForOrg_UnmarshalError(t *testing.T) {
   579  	client, mux, _, teardown := setup()
   580  	defer teardown()
   581  
   582  	mux.HandleFunc("/orgs/o/security-advisories", func(w http.ResponseWriter, r *http.Request) {
   583  		testMethod(t, r, "GET")
   584  
   585  		w.WriteHeader(http.StatusOK)
   586  		assertWrite(t, w, []byte(`[{"ghsa_id": 12334354}]`))
   587  	})
   588  
   589  	ctx := context.Background()
   590  	advisories, resp, err := client.SecurityAdvisories.ListRepositorySecurityAdvisoriesForOrg(ctx, "o", nil)
   591  	if err == nil {
   592  		t.Errorf("Expected unmarshal error")
   593  	} else if !strings.Contains(err.Error(), "json: cannot unmarshal number into Go struct field SecurityAdvisory.ghsa_id of type string") {
   594  		t.Errorf("ListRepositorySecurityAdvisoriesForOrg returned unexpected error: %v", err)
   595  	}
   596  	if got, want := resp.Response.StatusCode, http.StatusOK; got != want {
   597  		t.Errorf("ListRepositorySecurityAdvisoriesForOrg return status %d, want %d", got, want)
   598  	}
   599  	if advisories != nil {
   600  		t.Errorf("ListRepositorySecurityAdvisoriesForOrg return %+v, want nil", advisories)
   601  	}
   602  }
   603  
   604  func TestSecurityAdvisoriesService_ListRepositorySecurityAdvisoriesForOrg(t *testing.T) {
   605  	client, mux, _, teardown := setup()
   606  	defer teardown()
   607  
   608  	mux.HandleFunc("/orgs/o/security-advisories", func(w http.ResponseWriter, r *http.Request) {
   609  		testMethod(t, r, "GET")
   610  
   611  		w.WriteHeader(http.StatusOK)
   612  		assertWrite(t, w, []byte(`[
   613  			{
   614  				"ghsa_id": "GHSA-abcd-1234-efgh",
   615  				"cve_id": "CVE-2050-00000"
   616  			}
   617  		]`))
   618  	})
   619  
   620  	ctx := context.Background()
   621  	advisories, resp, err := client.SecurityAdvisories.ListRepositorySecurityAdvisoriesForOrg(ctx, "o", nil)
   622  	if err != nil {
   623  		t.Errorf("ListRepositorySecurityAdvisoriesForOrg returned error: %v, want nil", err)
   624  	}
   625  	if got, want := resp.Response.StatusCode, http.StatusOK; got != want {
   626  		t.Errorf("ListRepositorySecurityAdvisoriesForOrg return status %d, want %d", got, want)
   627  	}
   628  
   629  	want := []*SecurityAdvisory{
   630  		{
   631  			GHSAID: String("GHSA-abcd-1234-efgh"),
   632  			CVEID:  String("CVE-2050-00000"),
   633  		},
   634  	}
   635  	if !cmp.Equal(advisories, want) {
   636  		t.Errorf("ListRepositorySecurityAdvisoriesForOrg returned %+v, want %+v", advisories, want)
   637  	}
   638  
   639  	methodName := "ListRepositorySecurityAdvisoriesForOrg"
   640  	testBadOptions(t, methodName, func() (err error) {
   641  		_, _, err = client.SecurityAdvisories.ListRepositorySecurityAdvisoriesForOrg(ctx, "\n", &ListRepositorySecurityAdvisoriesOptions{
   642  			Sort: "\n",
   643  		})
   644  		return err
   645  	})
   646  
   647  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   648  		got, resp, err := client.SecurityAdvisories.ListRepositorySecurityAdvisoriesForOrg(ctx, "o", nil)
   649  		if got != nil {
   650  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   651  		}
   652  		return resp, err
   653  	})
   654  }
   655  
   656  func TestSecurityAdvisoriesService_ListRepositorySecurityAdvisories_BadRequest(t *testing.T) {
   657  	client, mux, _, teardown := setup()
   658  	defer teardown()
   659  
   660  	mux.HandleFunc("/repos/o/r/security-advisories", func(w http.ResponseWriter, r *http.Request) {
   661  		testMethod(t, r, "GET")
   662  
   663  		http.Error(w, "Bad Request", 400)
   664  	})
   665  
   666  	ctx := context.Background()
   667  	advisories, resp, err := client.SecurityAdvisories.ListRepositorySecurityAdvisories(ctx, "o", "r", nil)
   668  	if err == nil {
   669  		t.Errorf("Expected HTTP 400 response")
   670  	}
   671  	if got, want := resp.Response.StatusCode, http.StatusBadRequest; got != want {
   672  		t.Errorf("ListRepositorySecurityAdvisories return status %d, want %d", got, want)
   673  	}
   674  	if advisories != nil {
   675  		t.Errorf("ListRepositorySecurityAdvisories return %+v, want nil", advisories)
   676  	}
   677  }
   678  
   679  func TestSecurityAdvisoriesService_ListRepositorySecurityAdvisories_NotFound(t *testing.T) {
   680  	client, mux, _, teardown := setup()
   681  	defer teardown()
   682  
   683  	mux.HandleFunc("/repos/o/r/security-advisories", func(w http.ResponseWriter, r *http.Request) {
   684  		testMethod(t, r, "GET")
   685  
   686  		query := r.URL.Query()
   687  		if query.Get("state") != "draft" {
   688  			t.Errorf("ListRepositorySecurityAdvisories returned %+v, want %+v", query.Get("state"), "draft")
   689  		}
   690  
   691  		http.NotFound(w, r)
   692  	})
   693  
   694  	ctx := context.Background()
   695  	advisories, resp, err := client.SecurityAdvisories.ListRepositorySecurityAdvisories(ctx, "o", "r", &ListRepositorySecurityAdvisoriesOptions{
   696  		State: "draft",
   697  	})
   698  	if err == nil {
   699  		t.Errorf("Expected HTTP 404 response")
   700  	}
   701  	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
   702  		t.Errorf("ListRepositorySecurityAdvisories return status %d, want %d", got, want)
   703  	}
   704  	if advisories != nil {
   705  		t.Errorf("ListRepositorySecurityAdvisories return %+v, want nil", advisories)
   706  	}
   707  }
   708  
   709  func TestSecurityAdvisoriesService_ListRepositorySecurityAdvisories_UnmarshalError(t *testing.T) {
   710  	client, mux, _, teardown := setup()
   711  	defer teardown()
   712  
   713  	mux.HandleFunc("/repos/o/r/security-advisories", func(w http.ResponseWriter, r *http.Request) {
   714  		testMethod(t, r, "GET")
   715  
   716  		w.WriteHeader(http.StatusOK)
   717  		assertWrite(t, w, []byte(`[{"ghsa_id": 12334354}]`))
   718  	})
   719  
   720  	ctx := context.Background()
   721  	advisories, resp, err := client.SecurityAdvisories.ListRepositorySecurityAdvisories(ctx, "o", "r", nil)
   722  	if err == nil {
   723  		t.Errorf("Expected unmarshal error")
   724  	} else if !strings.Contains(err.Error(), "json: cannot unmarshal number into Go struct field SecurityAdvisory.ghsa_id of type string") {
   725  		t.Errorf("ListRepositorySecurityAdvisories returned unexpected error: %v", err)
   726  	}
   727  	if got, want := resp.Response.StatusCode, http.StatusOK; got != want {
   728  		t.Errorf("ListRepositorySecurityAdvisories return status %d, want %d", got, want)
   729  	}
   730  	if advisories != nil {
   731  		t.Errorf("ListRepositorySecurityAdvisories return %+v, want nil", advisories)
   732  	}
   733  }
   734  
   735  func TestSecurityAdvisoriesService_ListRepositorySecurityAdvisories(t *testing.T) {
   736  	client, mux, _, teardown := setup()
   737  	defer teardown()
   738  
   739  	mux.HandleFunc("/repos/o/r/security-advisories", func(w http.ResponseWriter, r *http.Request) {
   740  		testMethod(t, r, "GET")
   741  
   742  		w.WriteHeader(http.StatusOK)
   743  		assertWrite(t, w, []byte(`[
   744  			{
   745  				"ghsa_id": "GHSA-abcd-1234-efgh",
   746  				"cve_id": "CVE-2050-00000"
   747  			}
   748  		]`))
   749  	})
   750  
   751  	ctx := context.Background()
   752  	advisories, resp, err := client.SecurityAdvisories.ListRepositorySecurityAdvisories(ctx, "o", "r", nil)
   753  	if err != nil {
   754  		t.Errorf("ListRepositorySecurityAdvisories returned error: %v, want nil", err)
   755  	}
   756  	if got, want := resp.Response.StatusCode, http.StatusOK; got != want {
   757  		t.Errorf("ListRepositorySecurityAdvisories return status %d, want %d", got, want)
   758  	}
   759  
   760  	want := []*SecurityAdvisory{
   761  		{
   762  			GHSAID: String("GHSA-abcd-1234-efgh"),
   763  			CVEID:  String("CVE-2050-00000"),
   764  		},
   765  	}
   766  	if !cmp.Equal(advisories, want) {
   767  		t.Errorf("ListRepositorySecurityAdvisories returned %+v, want %+v", advisories, want)
   768  	}
   769  
   770  	methodName := "ListRepositorySecurityAdvisories"
   771  	testBadOptions(t, methodName, func() (err error) {
   772  		_, _, err = client.SecurityAdvisories.ListRepositorySecurityAdvisories(ctx, "\n", "\n", &ListRepositorySecurityAdvisoriesOptions{
   773  			Sort: "\n",
   774  		})
   775  		return err
   776  	})
   777  
   778  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   779  		got, resp, err := client.SecurityAdvisories.ListRepositorySecurityAdvisories(ctx, "o", "r", nil)
   780  		if got != nil {
   781  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   782  		}
   783  		return resp, err
   784  	})
   785  }
   786  
   787  func TestListGlobalSecurityAdvisories(t *testing.T) {
   788  	client, mux, _, teardown := setup()
   789  	defer teardown()
   790  
   791  	mux.HandleFunc("/advisories", func(w http.ResponseWriter, r *http.Request) {
   792  		testMethod(t, r, "GET")
   793  		testFormValues(t, r, values{"cve_id": "CVE-xoxo-1234"})
   794  
   795  		fmt.Fprint(w, `[{
   796  				"id": 1,
   797  				"ghsa_id": "GHSA-xoxo-1234-xoxo",
   798  				"cve_id": "CVE-xoxo-1234",
   799  				"url": "https://api.github.com/advisories/GHSA-xoxo-1234-xoxo",
   800  				"html_url": "https://github.com/advisories/GHSA-xoxo-1234-xoxo",
   801  				"repository_advisory_url": "https://api.github.com/repos/project/a-package/security-advisories/GHSA-xoxo-1234-xoxo",
   802  				"summary": "Heartbleed security advisory",
   803  				"description": "This bug allows an attacker to read portions of the affected server’s memory, potentially disclosing sensitive information.",
   804  				"type": "reviewed",
   805  				"severity": "high",
   806  				"source_code_location": "https://github.com/project/a-package",
   807  				"identifiers": [
   808  					{
   809  						"type": "GHSA",
   810  						"value": "GHSA-xoxo-1234-xoxo"
   811  					},
   812  					{
   813  						"type": "CVE",
   814  						"value": "CVE-xoxo-1234"
   815  					}
   816  				],
   817  				"references": ["https://nvd.nist.gov/vuln/detail/CVE-xoxo-1234"],
   818  				"published_at": "1996-06-20T00:00:00Z",
   819  				"updated_at": "1996-06-20T00:00:00Z",
   820  				"github_reviewed_at": "1996-06-20T00:00:00Z",
   821  				"nvd_published_at": "1996-06-20T00:00:00Z",
   822  				"withdrawn_at": null,
   823  				"vulnerabilities": [
   824  					{
   825  						"package": {
   826  							"ecosystem": "npm",
   827  							"name": "a-package"
   828  						},
   829  						"first_patched_version": "1.0.3",
   830  						"vulnerable_version_range": "<=1.0.2",
   831  						"vulnerable_functions": ["a_function"]
   832  					}
   833  				],
   834  				"cvss": {
   835  					"vector_string": "CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H",
   836  					"score": 7.6
   837  				},
   838  				"cwes": [
   839  					{
   840  						"cwe_id": "CWE-400",
   841  						"name": "Uncontrolled Resource Consumption"
   842  					}
   843  				],
   844  				"credits": [
   845  					{
   846  						"user": {
   847  							"login": "user",
   848  							"id": 1,
   849  							"node_id": "12=",
   850  							"avatar_url": "a",
   851  							"gravatar_id": "",
   852  							"url": "a",
   853  							"html_url": "b",
   854  							"followers_url": "b",
   855  							"following_url": "c",
   856  							"gists_url": "d",
   857  							"starred_url": "e",
   858  							"subscriptions_url": "f",
   859  							"organizations_url": "g",
   860  							"repos_url": "h",
   861  							"events_url": "i",
   862  							"received_events_url": "j",
   863  							"type": "User",
   864  							"site_admin": false
   865  						},
   866  						"type": "analyst"
   867  					}
   868  				]
   869  			}
   870  		]`)
   871  	})
   872  
   873  	ctx := context.Background()
   874  	opts := &ListGlobalSecurityAdvisoriesOptions{CVEID: String("CVE-xoxo-1234")}
   875  
   876  	advisories, _, err := client.SecurityAdvisories.ListGlobalSecurityAdvisories(ctx, opts)
   877  	if err != nil {
   878  		t.Errorf("SecurityAdvisories.ListGlobalSecurityAdvisories returned error: %v", err)
   879  	}
   880  
   881  	date := Timestamp{time.Date(1996, time.June, 20, 00, 00, 00, 0, time.UTC)}
   882  	want := []*GlobalSecurityAdvisory{
   883  		{
   884  			ID: Int64(1),
   885  			SecurityAdvisory: SecurityAdvisory{
   886  				GHSAID:      String("GHSA-xoxo-1234-xoxo"),
   887  				CVEID:       String("CVE-xoxo-1234"),
   888  				URL:         String("https://api.github.com/advisories/GHSA-xoxo-1234-xoxo"),
   889  				HTMLURL:     String("https://github.com/advisories/GHSA-xoxo-1234-xoxo"),
   890  				Severity:    String("high"),
   891  				Summary:     String("Heartbleed security advisory"),
   892  				Description: String("This bug allows an attacker to read portions of the affected server’s memory, potentially disclosing sensitive information."),
   893  				Identifiers: []*AdvisoryIdentifier{
   894  					{
   895  						Type:  String("GHSA"),
   896  						Value: String("GHSA-xoxo-1234-xoxo"),
   897  					},
   898  					{
   899  						Type:  String("CVE"),
   900  						Value: String("CVE-xoxo-1234"),
   901  					},
   902  				},
   903  				PublishedAt: &date,
   904  				UpdatedAt:   &date,
   905  				WithdrawnAt: nil,
   906  				CVSS: &AdvisoryCVSS{
   907  					VectorString: String("CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H"),
   908  					Score:        Float64(7.6),
   909  				},
   910  				CWEs: []*AdvisoryCWEs{
   911  					{
   912  						CWEID: String("CWE-400"),
   913  						Name:  String("Uncontrolled Resource Consumption"),
   914  					},
   915  				},
   916  			},
   917  			References: []string{"https://nvd.nist.gov/vuln/detail/CVE-xoxo-1234"},
   918  			Vulnerabilities: []*GlobalSecurityVulnerability{
   919  				{
   920  					Package: &VulnerabilityPackage{
   921  						Ecosystem: String("npm"),
   922  						Name:      String("a-package"),
   923  					},
   924  					FirstPatchedVersion:    String("1.0.3"),
   925  					VulnerableVersionRange: String("<=1.0.2"),
   926  					VulnerableFunctions:    []string{"a_function"},
   927  				},
   928  			},
   929  			RepositoryAdvisoryURL: String("https://api.github.com/repos/project/a-package/security-advisories/GHSA-xoxo-1234-xoxo"),
   930  			Type:                  String("reviewed"),
   931  			SourceCodeLocation:    String("https://github.com/project/a-package"),
   932  			GithubReviewedAt:      &date,
   933  			NVDPublishedAt:        &date,
   934  			Credits: []*Credit{
   935  				{
   936  					User: &User{
   937  						Login:             String("user"),
   938  						ID:                Int64(1),
   939  						NodeID:            String("12="),
   940  						AvatarURL:         String("a"),
   941  						GravatarID:        String(""),
   942  						URL:               String("a"),
   943  						HTMLURL:           String("b"),
   944  						FollowersURL:      String("b"),
   945  						FollowingURL:      String("c"),
   946  						GistsURL:          String("d"),
   947  						StarredURL:        String("e"),
   948  						SubscriptionsURL:  String("f"),
   949  						OrganizationsURL:  String("g"),
   950  						ReposURL:          String("h"),
   951  						EventsURL:         String("i"),
   952  						ReceivedEventsURL: String("j"),
   953  						Type:              String("User"),
   954  						SiteAdmin:         Bool(false),
   955  					},
   956  					Type: String("analyst"),
   957  				},
   958  			},
   959  		},
   960  	}
   961  
   962  	if !cmp.Equal(advisories, want) {
   963  		t.Errorf("SecurityAdvisories.ListGlobalSecurityAdvisories %+v, want %+v", advisories, want)
   964  	}
   965  
   966  	const methodName = "ListGlobalSecurityAdvisories"
   967  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   968  		_, resp, err := client.SecurityAdvisories.ListGlobalSecurityAdvisories(ctx, nil)
   969  		return resp, err
   970  	})
   971  }
   972  
   973  func TestGetGlobalSecurityAdvisories(t *testing.T) {
   974  	client, mux, _, teardown := setup()
   975  	defer teardown()
   976  
   977  	mux.HandleFunc("/advisories/GHSA-xoxo-1234-xoxo", func(w http.ResponseWriter, r *http.Request) {
   978  		testMethod(t, r, "GET")
   979  
   980  		fmt.Fprint(w, `{
   981  			"id": 1,
   982  			"ghsa_id": "GHSA-xoxo-1234-xoxo",
   983  			"cve_id": "CVE-xoxo-1234",
   984  			"url": "https://api.github.com/advisories/GHSA-xoxo-1234-xoxo",
   985  			"html_url": "https://github.com/advisories/GHSA-xoxo-1234-xoxo",
   986  			"repository_advisory_url": "https://api.github.com/repos/project/a-package/security-advisories/GHSA-xoxo-1234-xoxo",
   987  			"summary": "Heartbleed security advisory",
   988  			"description": "This bug allows an attacker to read portions of the affected server’s memory, potentially disclosing sensitive information.",
   989  			"type": "reviewed",
   990  			"severity": "high",
   991  			"source_code_location": "https://github.com/project/a-package",
   992  			"identifiers": [
   993  				{
   994  					"type": "GHSA",
   995  					"value": "GHSA-xoxo-1234-xoxo"
   996  				},
   997  				{
   998  					"type": "CVE",
   999  					"value": "CVE-xoxo-1234"
  1000  				}
  1001  			],
  1002  			"references": ["https://nvd.nist.gov/vuln/detail/CVE-xoxo-1234"],
  1003  			"published_at": "1996-06-20T00:00:00Z",
  1004  			"updated_at": "1996-06-20T00:00:00Z",
  1005  			"github_reviewed_at": "1996-06-20T00:00:00Z",
  1006  			"nvd_published_at": "1996-06-20T00:00:00Z",
  1007  			"withdrawn_at": null,
  1008  			"vulnerabilities": [
  1009  				{
  1010  					"package": {
  1011  						"ecosystem": "npm",
  1012  						"name": "a-package"
  1013  					},
  1014  					"first_patched_version": "1.0.3",
  1015  					"vulnerable_version_range": "<=1.0.2",
  1016  					"vulnerable_functions": ["a_function"]
  1017  				}
  1018  			],
  1019  			"cvss": {
  1020  				"vector_string": "CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H",
  1021  				"score": 7.6
  1022  			},
  1023  			"cwes": [
  1024  				{
  1025  					"cwe_id": "CWE-400",
  1026  					"name": "Uncontrolled Resource Consumption"
  1027  				}
  1028  			],
  1029  			"credits": [
  1030  				{
  1031  					"user": {
  1032  						"login": "user",
  1033  						"id": 1,
  1034  						"node_id": "12=",
  1035  						"avatar_url": "a",
  1036  						"gravatar_id": "",
  1037  						"url": "a",
  1038  						"html_url": "b",
  1039  						"followers_url": "b",
  1040  						"following_url": "c",
  1041  						"gists_url": "d",
  1042  						"starred_url": "e",
  1043  						"subscriptions_url": "f",
  1044  						"organizations_url": "g",
  1045  						"repos_url": "h",
  1046  						"events_url": "i",
  1047  						"received_events_url": "j",
  1048  						"type": "User",
  1049  						"site_admin": false
  1050  					},
  1051  					"type": "analyst"
  1052  				}
  1053  			]
  1054  		}`)
  1055  	})
  1056  
  1057  	ctx := context.Background()
  1058  	advisory, _, err := client.SecurityAdvisories.GetGlobalSecurityAdvisories(ctx, "GHSA-xoxo-1234-xoxo")
  1059  	if err != nil {
  1060  		t.Errorf("SecurityAdvisories.GetGlobalSecurityAdvisories returned error: %v", err)
  1061  	}
  1062  
  1063  	date := Timestamp{time.Date(1996, time.June, 20, 00, 00, 00, 0, time.UTC)}
  1064  	want := &GlobalSecurityAdvisory{
  1065  		ID: Int64(1),
  1066  		SecurityAdvisory: SecurityAdvisory{
  1067  			GHSAID:      String("GHSA-xoxo-1234-xoxo"),
  1068  			CVEID:       String("CVE-xoxo-1234"),
  1069  			URL:         String("https://api.github.com/advisories/GHSA-xoxo-1234-xoxo"),
  1070  			HTMLURL:     String("https://github.com/advisories/GHSA-xoxo-1234-xoxo"),
  1071  			Severity:    String("high"),
  1072  			Summary:     String("Heartbleed security advisory"),
  1073  			Description: String("This bug allows an attacker to read portions of the affected server’s memory, potentially disclosing sensitive information."),
  1074  			Identifiers: []*AdvisoryIdentifier{
  1075  				{
  1076  					Type:  String("GHSA"),
  1077  					Value: String("GHSA-xoxo-1234-xoxo"),
  1078  				},
  1079  				{
  1080  					Type:  String("CVE"),
  1081  					Value: String("CVE-xoxo-1234"),
  1082  				},
  1083  			},
  1084  			PublishedAt: &date,
  1085  			UpdatedAt:   &date,
  1086  			WithdrawnAt: nil,
  1087  			CVSS: &AdvisoryCVSS{
  1088  				VectorString: String("CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H"),
  1089  				Score:        Float64(7.6),
  1090  			},
  1091  			CWEs: []*AdvisoryCWEs{
  1092  				{
  1093  					CWEID: String("CWE-400"),
  1094  					Name:  String("Uncontrolled Resource Consumption"),
  1095  				},
  1096  			},
  1097  		},
  1098  		RepositoryAdvisoryURL: String("https://api.github.com/repos/project/a-package/security-advisories/GHSA-xoxo-1234-xoxo"),
  1099  		Type:                  String("reviewed"),
  1100  		SourceCodeLocation:    String("https://github.com/project/a-package"),
  1101  		References:            []string{"https://nvd.nist.gov/vuln/detail/CVE-xoxo-1234"},
  1102  		GithubReviewedAt:      &date,
  1103  		NVDPublishedAt:        &date,
  1104  
  1105  		Vulnerabilities: []*GlobalSecurityVulnerability{
  1106  			{
  1107  				Package: &VulnerabilityPackage{
  1108  					Ecosystem: String("npm"),
  1109  					Name:      String("a-package"),
  1110  				},
  1111  				FirstPatchedVersion:    String("1.0.3"),
  1112  				VulnerableVersionRange: String("<=1.0.2"),
  1113  				VulnerableFunctions:    []string{"a_function"},
  1114  			},
  1115  		},
  1116  		Credits: []*Credit{
  1117  			{
  1118  				User: &User{
  1119  					Login:             String("user"),
  1120  					ID:                Int64(1),
  1121  					NodeID:            String("12="),
  1122  					AvatarURL:         String("a"),
  1123  					GravatarID:        String(""),
  1124  					URL:               String("a"),
  1125  					HTMLURL:           String("b"),
  1126  					FollowersURL:      String("b"),
  1127  					FollowingURL:      String("c"),
  1128  					GistsURL:          String("d"),
  1129  					StarredURL:        String("e"),
  1130  					SubscriptionsURL:  String("f"),
  1131  					OrganizationsURL:  String("g"),
  1132  					ReposURL:          String("h"),
  1133  					EventsURL:         String("i"),
  1134  					ReceivedEventsURL: String("j"),
  1135  					Type:              String("User"),
  1136  					SiteAdmin:         Bool(false),
  1137  				},
  1138  				Type: String("analyst"),
  1139  			},
  1140  		},
  1141  	}
  1142  
  1143  	if !cmp.Equal(advisory, want) {
  1144  		t.Errorf("SecurityAdvisories.GetGlobalSecurityAdvisories %+v, want %+v", advisory, want)
  1145  	}
  1146  
  1147  	const methodName = "GetGlobalSecurityAdvisories"
  1148  
  1149  	testBadOptions(t, methodName, func() (err error) {
  1150  		_, _, err = client.SecurityAdvisories.GetGlobalSecurityAdvisories(ctx, "CVE-\n-1234")
  1151  		return err
  1152  	})
  1153  
  1154  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
  1155  		got, resp, err := client.SecurityAdvisories.GetGlobalSecurityAdvisories(ctx, "e")
  1156  		if got != nil {
  1157  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
  1158  		}
  1159  		return resp, err
  1160  	})
  1161  }
  1162  
  1163  func TestSecurityAdvisorySubmission_Marshal(t *testing.T) {
  1164  	testJSONMarshal(t, &SecurityAdvisorySubmission{}, `{}`)
  1165  
  1166  	u := &SecurityAdvisorySubmission{
  1167  		Accepted: Bool(true),
  1168  	}
  1169  
  1170  	w := `{
  1171  		"accepted": true
  1172  	}`
  1173  
  1174  	testJSONMarshal(t, u, w)
  1175  }
  1176  
  1177  func TestRepoAdvisoryCredit_Marshal(t *testing.T) {
  1178  	testJSONMarshal(t, &RepoAdvisoryCredit{}, `{}`)
  1179  
  1180  	u := &RepoAdvisoryCredit{
  1181  		Login: String("l"),
  1182  		Type:  String("t"),
  1183  	}
  1184  
  1185  	w := `{
  1186  		"login": "l",
  1187  		"type": "t"
  1188  	}`
  1189  
  1190  	testJSONMarshal(t, u, w)
  1191  }
  1192  
  1193  func TestRepoAdvisoryCreditDetailed_Marshal(t *testing.T) {
  1194  	testJSONMarshal(t, &RepoAdvisoryCreditDetailed{}, `{}`)
  1195  
  1196  	testDate := &Timestamp{time.Date(2019, time.August, 10, 14, 59, 22, 0, time.UTC)}
  1197  	u := &RepoAdvisoryCreditDetailed{
  1198  		Type:  String("t"),
  1199  		State: String("s"),
  1200  		User: &User{
  1201  			Name:                    String("u"),
  1202  			Company:                 String("c"),
  1203  			Blog:                    String("b"),
  1204  			Location:                String("l"),
  1205  			Email:                   String("e"),
  1206  			Hireable:                Bool(false),
  1207  			Bio:                     String("bio"),
  1208  			TwitterUsername:         String("tu"),
  1209  			PublicRepos:             Int(1),
  1210  			PublicGists:             Int(1),
  1211  			Followers:               Int(2),
  1212  			Following:               Int(2),
  1213  			CreatedAt:               testDate,
  1214  			UpdatedAt:               testDate,
  1215  			SuspendedAt:             testDate,
  1216  			Type:                    String("type"),
  1217  			SiteAdmin:               Bool(false),
  1218  			TotalPrivateRepos:       Int64(10),
  1219  			OwnedPrivateRepos:       Int64(10),
  1220  			PrivateGists:            Int(10),
  1221  			DiskUsage:               Int(10),
  1222  			Collaborators:           Int(10),
  1223  			TwoFactorAuthentication: Bool(true),
  1224  			Plan: &Plan{
  1225  				Name:          String("p"),
  1226  				Space:         Int(2),
  1227  				Collaborators: Int(2),
  1228  				PrivateRepos:  Int64(2),
  1229  				Seats:         Int(2),
  1230  				FilledSeats:   Int(1),
  1231  			},
  1232  			LdapDn:            String("l"),
  1233  			URL:               String("url"),
  1234  			EventsURL:         String("e"),
  1235  			FollowingURL:      String("f"),
  1236  			FollowersURL:      String("f"),
  1237  			GistsURL:          String("g"),
  1238  			OrganizationsURL:  String("o"),
  1239  			ReceivedEventsURL: String("r"),
  1240  			ReposURL:          String("rep"),
  1241  			StarredURL:        String("star"),
  1242  			SubscriptionsURL:  String("sub"),
  1243  			TextMatches: []*TextMatch{
  1244  				{
  1245  					ObjectURL:  String("u"),
  1246  					ObjectType: String("t"),
  1247  					Property:   String("p"),
  1248  					Fragment:   String("f"),
  1249  					Matches: []*Match{
  1250  						{
  1251  							Text:    String("t"),
  1252  							Indices: []int{1, 2},
  1253  						},
  1254  					},
  1255  				},
  1256  			},
  1257  			Permissions: map[string]bool{"p1": true},
  1258  			RoleName:    String("r"),
  1259  		},
  1260  	}
  1261  
  1262  	w := `{
  1263  		"type": "t",
  1264  		"state": "s",
  1265  		"user": {
  1266  		  "name": "u",
  1267  		  "company": "c",
  1268  		  "blog": "b",
  1269  		  "location": "l",
  1270  		  "email": "e",
  1271  		  "hireable": false,
  1272  		  "bio": "bio",
  1273  		  "twitter_username": "tu",
  1274  		  "public_repos": 1,
  1275  		  "public_gists": 1,
  1276  		  "followers": 2,
  1277  		  "following": 2,
  1278  		  "created_at": "2019-08-10T14:59:22Z",
  1279  		  "updated_at": "2019-08-10T14:59:22Z",
  1280  		  "suspended_at": "2019-08-10T14:59:22Z",
  1281  		  "type": "type",
  1282  		  "site_admin": false,
  1283  		  "total_private_repos": 10,
  1284  		  "owned_private_repos": 10,
  1285  		  "private_gists": 10,
  1286  		  "disk_usage": 10,
  1287  		  "collaborators": 10,
  1288  		  "two_factor_authentication": true,
  1289  		  "plan": {
  1290  			"name": "p",
  1291  			"space": 2,
  1292  			"collaborators": 2,
  1293  			"private_repos": 2,
  1294  			"seats": 2,
  1295  			"filled_seats": 1
  1296  		  },
  1297  		  "ldap_dn": "l",
  1298  		  "url": "url",
  1299  		  "events_url": "e",
  1300  		  "following_url": "f",
  1301  		  "followers_url": "f",
  1302  		  "gists_url": "g",
  1303  		  "organizations_url": "o",
  1304  		  "received_events_url": "r",
  1305  		  "repos_url": "rep",
  1306  		  "starred_url": "star",
  1307  		  "subscriptions_url": "sub",
  1308  		  "text_matches": [
  1309  			{
  1310  			  "object_url": "u",
  1311  			  "object_type": "t",
  1312  			  "property": "p",
  1313  			  "fragment": "f",
  1314  			  "matches": [
  1315  				{
  1316  				  "text": "t",
  1317  				  "indices": [1, 2]
  1318  				}
  1319  			  ]
  1320  			}
  1321  		  ],
  1322  		  "permissions": {
  1323  			"p1": true
  1324  		  },
  1325  		  "role_name": "r"
  1326  		}
  1327  	  }`
  1328  
  1329  	testJSONMarshal(t, u, w)
  1330  }
  1331  
  1332  func TestCredit_Marshal(t *testing.T) {
  1333  	testJSONMarshal(t, &Credit{}, `{}`)
  1334  
  1335  	testDate := &Timestamp{time.Date(2019, time.August, 10, 14, 59, 22, 0, time.UTC)}
  1336  	u := &Credit{
  1337  		Type: String("t"),
  1338  		User: &User{
  1339  			Name:                    String("u"),
  1340  			Company:                 String("c"),
  1341  			Blog:                    String("b"),
  1342  			Location:                String("l"),
  1343  			Email:                   String("e"),
  1344  			Hireable:                Bool(false),
  1345  			Bio:                     String("bio"),
  1346  			TwitterUsername:         String("tu"),
  1347  			PublicRepos:             Int(1),
  1348  			PublicGists:             Int(1),
  1349  			Followers:               Int(2),
  1350  			Following:               Int(2),
  1351  			CreatedAt:               testDate,
  1352  			UpdatedAt:               testDate,
  1353  			SuspendedAt:             testDate,
  1354  			Type:                    String("type"),
  1355  			SiteAdmin:               Bool(false),
  1356  			TotalPrivateRepos:       Int64(10),
  1357  			OwnedPrivateRepos:       Int64(10),
  1358  			PrivateGists:            Int(10),
  1359  			DiskUsage:               Int(10),
  1360  			Collaborators:           Int(10),
  1361  			TwoFactorAuthentication: Bool(true),
  1362  			Plan: &Plan{
  1363  				Name:          String("p"),
  1364  				Space:         Int(2),
  1365  				Collaborators: Int(2),
  1366  				PrivateRepos:  Int64(2),
  1367  				Seats:         Int(2),
  1368  				FilledSeats:   Int(1),
  1369  			},
  1370  			LdapDn:            String("l"),
  1371  			URL:               String("url"),
  1372  			EventsURL:         String("e"),
  1373  			FollowingURL:      String("f"),
  1374  			FollowersURL:      String("f"),
  1375  			GistsURL:          String("g"),
  1376  			OrganizationsURL:  String("o"),
  1377  			ReceivedEventsURL: String("r"),
  1378  			ReposURL:          String("rep"),
  1379  			StarredURL:        String("star"),
  1380  			SubscriptionsURL:  String("sub"),
  1381  			TextMatches: []*TextMatch{
  1382  				{
  1383  					ObjectURL:  String("u"),
  1384  					ObjectType: String("t"),
  1385  					Property:   String("p"),
  1386  					Fragment:   String("f"),
  1387  					Matches: []*Match{
  1388  						{
  1389  							Text:    String("t"),
  1390  							Indices: []int{1, 2},
  1391  						},
  1392  					},
  1393  				},
  1394  			},
  1395  			Permissions: map[string]bool{"p1": true},
  1396  			RoleName:    String("r"),
  1397  		},
  1398  	}
  1399  
  1400  	w := `{
  1401  		"type": "t",
  1402  		"user": {
  1403  			"name": "u",
  1404  			"company": "c",
  1405  			"blog": "b",
  1406  			"location": "l",
  1407  			"email": "e",
  1408  			"hireable": false,
  1409  			"bio": "bio",
  1410  			"twitter_username": "tu",
  1411  			"public_repos": 1,
  1412  			"public_gists": 1,
  1413  			"followers": 2,
  1414  			"following": 2,
  1415  			"created_at": "2019-08-10T14:59:22Z",
  1416  			"updated_at": "2019-08-10T14:59:22Z",
  1417  			"suspended_at": "2019-08-10T14:59:22Z",
  1418  			"type": "type",
  1419  			"site_admin": false,
  1420  			"total_private_repos": 10,
  1421  			"owned_private_repos": 10,
  1422  			"private_gists": 10,
  1423  			"disk_usage": 10,
  1424  			"collaborators": 10,
  1425  			"two_factor_authentication": true,
  1426  			"plan": {
  1427  			"name": "p",
  1428  			"space": 2,
  1429  			"collaborators": 2,
  1430  			"private_repos": 2,
  1431  			"seats": 2,
  1432  			"filled_seats": 1
  1433  			},
  1434  			"ldap_dn": "l",
  1435  			"url": "url",
  1436  			"events_url": "e",
  1437  			"following_url": "f",
  1438  			"followers_url": "f",
  1439  			"gists_url": "g",
  1440  			"organizations_url": "o",
  1441  			"received_events_url": "r",
  1442  			"repos_url": "rep",
  1443  			"starred_url": "star",
  1444  			"subscriptions_url": "sub",
  1445  			"text_matches": [
  1446  			{
  1447  				"object_url": "u",
  1448  				"object_type": "t",
  1449  				"property": "p",
  1450  				"fragment": "f",
  1451  				"matches": [
  1452  				{
  1453  					"text": "t",
  1454  					"indices": [1, 2]
  1455  				}
  1456  				]
  1457  			}
  1458  			],
  1459  			"permissions": {
  1460  			"p1": true
  1461  			},
  1462  			"role_name": "r"
  1463  		}
  1464  	}`
  1465  
  1466  	testJSONMarshal(t, u, w)
  1467  }
  1468  
  1469  func TestGlobalSecurityAdvisory_Marshal(t *testing.T) {
  1470  	testJSONMarshal(t, &GlobalSecurityAdvisory{}, `{}`)
  1471  
  1472  	testDate := &Timestamp{time.Date(2019, time.August, 10, 14, 59, 22, 0, time.UTC)}
  1473  	u := &GlobalSecurityAdvisory{
  1474  		ID:                    Int64(1),
  1475  		RepositoryAdvisoryURL: String("r"),
  1476  		Type:                  String("t"),
  1477  		SourceCodeLocation:    String("s"),
  1478  		References:            []string{"r"},
  1479  		Vulnerabilities: []*GlobalSecurityVulnerability{
  1480  			{
  1481  				Package: &VulnerabilityPackage{
  1482  					Ecosystem: String("npm"),
  1483  					Name:      String("a-package"),
  1484  				},
  1485  				FirstPatchedVersion:    String("1.0.3"),
  1486  				VulnerableVersionRange: String("<=1.0.2"),
  1487  				VulnerableFunctions:    []string{"a_function"},
  1488  			},
  1489  		},
  1490  		GithubReviewedAt: testDate,
  1491  		NVDPublishedAt:   testDate,
  1492  		Credits: []*Credit{
  1493  			{
  1494  				Type: String("t"),
  1495  				User: &User{
  1496  					Name:                    String("u"),
  1497  					Company:                 String("c"),
  1498  					Blog:                    String("b"),
  1499  					Location:                String("l"),
  1500  					Email:                   String("e"),
  1501  					Hireable:                Bool(false),
  1502  					Bio:                     String("bio"),
  1503  					TwitterUsername:         String("tu"),
  1504  					PublicRepos:             Int(1),
  1505  					PublicGists:             Int(1),
  1506  					Followers:               Int(2),
  1507  					Following:               Int(2),
  1508  					CreatedAt:               testDate,
  1509  					UpdatedAt:               testDate,
  1510  					SuspendedAt:             testDate,
  1511  					Type:                    String("type"),
  1512  					SiteAdmin:               Bool(false),
  1513  					TotalPrivateRepos:       Int64(10),
  1514  					OwnedPrivateRepos:       Int64(10),
  1515  					PrivateGists:            Int(10),
  1516  					DiskUsage:               Int(10),
  1517  					Collaborators:           Int(10),
  1518  					TwoFactorAuthentication: Bool(true),
  1519  					Plan: &Plan{
  1520  						Name:          String("p"),
  1521  						Space:         Int(2),
  1522  						Collaborators: Int(2),
  1523  						PrivateRepos:  Int64(2),
  1524  						Seats:         Int(2),
  1525  						FilledSeats:   Int(1),
  1526  					},
  1527  					LdapDn:            String("l"),
  1528  					URL:               String("url"),
  1529  					EventsURL:         String("e"),
  1530  					FollowingURL:      String("f"),
  1531  					FollowersURL:      String("f"),
  1532  					GistsURL:          String("g"),
  1533  					OrganizationsURL:  String("o"),
  1534  					ReceivedEventsURL: String("r"),
  1535  					ReposURL:          String("rep"),
  1536  					StarredURL:        String("star"),
  1537  					SubscriptionsURL:  String("sub"),
  1538  					TextMatches: []*TextMatch{
  1539  						{
  1540  							ObjectURL:  String("u"),
  1541  							ObjectType: String("t"),
  1542  							Property:   String("p"),
  1543  							Fragment:   String("f"),
  1544  							Matches: []*Match{
  1545  								{
  1546  									Text:    String("t"),
  1547  									Indices: []int{1, 2},
  1548  								},
  1549  							},
  1550  						},
  1551  					},
  1552  					Permissions: map[string]bool{"p1": true},
  1553  					RoleName:    String("r"),
  1554  				},
  1555  			},
  1556  		},
  1557  		SecurityAdvisory: SecurityAdvisory{
  1558  			GHSAID:      String("GHSA-xoxo-1234-xoxo"),
  1559  			CVEID:       String("CVE-xoxo-1234"),
  1560  			URL:         String("https://api.github.com/advisories/GHSA-xoxo-1234-xoxo"),
  1561  			HTMLURL:     String("https://github.com/advisories/GHSA-xoxo-1234-xoxo"),
  1562  			Severity:    String("high"),
  1563  			Summary:     String("Heartbleed security advisory"),
  1564  			Description: String("This bug allows an attacker to read portions of the affected server’s memory, potentially disclosing sensitive information."),
  1565  			Identifiers: []*AdvisoryIdentifier{
  1566  				{
  1567  					Type:  String("GHSA"),
  1568  					Value: String("GHSA-xoxo-1234-xoxo"),
  1569  				},
  1570  				{
  1571  					Type:  String("CVE"),
  1572  					Value: String("CVE-xoxo-1234"),
  1573  				},
  1574  			},
  1575  			PublishedAt: testDate,
  1576  			UpdatedAt:   testDate,
  1577  			WithdrawnAt: nil,
  1578  			CVSS: &AdvisoryCVSS{
  1579  				VectorString: String("CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H"),
  1580  				Score:        Float64(7.6),
  1581  			},
  1582  			CWEs: []*AdvisoryCWEs{
  1583  				{
  1584  					CWEID: String("CWE-400"),
  1585  					Name:  String("Uncontrolled Resource Consumption"),
  1586  				},
  1587  			},
  1588  		},
  1589  	}
  1590  
  1591  	w := `{
  1592  		"cvss": {
  1593  		  "score": 7.6,
  1594  		  "vector_string": "CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H"
  1595  		},
  1596  		"cwes": [
  1597  		  {
  1598  			"cwe_id": "CWE-400",
  1599  			"name": "Uncontrolled Resource Consumption"
  1600  		  }
  1601  		],
  1602  		"ghsa_id": "GHSA-xoxo-1234-xoxo",
  1603  		"summary": "Heartbleed security advisory",
  1604  		"description": "This bug allows an attacker to read portions of the affected server’s memory, potentially disclosing sensitive information.",
  1605  		"severity": "high",
  1606  		"identifiers": [
  1607  		  {
  1608  			"value": "GHSA-xoxo-1234-xoxo",
  1609  			"type": "GHSA"
  1610  		  },
  1611  		  {
  1612  			"value": "CVE-xoxo-1234",
  1613  			"type": "CVE"
  1614  		  }
  1615  		],
  1616  		"published_at": "2019-08-10T14:59:22Z",
  1617  		"updated_at": "2019-08-10T14:59:22Z",
  1618  		"cve_id": "CVE-xoxo-1234",
  1619  		"url": "https://api.github.com/advisories/GHSA-xoxo-1234-xoxo",
  1620  		"html_url": "https://github.com/advisories/GHSA-xoxo-1234-xoxo",
  1621  		"id": 1,
  1622  		"repository_advisory_url": "r",
  1623  		"type": "t",
  1624  		"source_code_location": "s",
  1625  		"references": [
  1626  		  "r"
  1627  		],
  1628  		"vulnerabilities": [
  1629  		  {
  1630  			"package": {
  1631  			  "ecosystem": "npm",
  1632  			  "name": "a-package"
  1633  			},
  1634  			"first_patched_version": "1.0.3",
  1635  			"vulnerable_version_range": "\u003c=1.0.2",
  1636  			"vulnerable_functions": [
  1637  			  "a_function"
  1638  			]
  1639  		  }
  1640  		],
  1641  		"github_reviewed_at": "2019-08-10T14:59:22Z",
  1642  		"nvd_published_at": "2019-08-10T14:59:22Z",
  1643  		"credits": [
  1644  		  {
  1645  			"user": {
  1646  			  "name": "u",
  1647  			  "company": "c",
  1648  			  "blog": "b",
  1649  			  "location": "l",
  1650  			  "email": "e",
  1651  			  "hireable": false,
  1652  			  "bio": "bio",
  1653  			  "twitter_username": "tu",
  1654  			  "public_repos": 1,
  1655  			  "public_gists": 1,
  1656  			  "followers": 2,
  1657  			  "following": 2,
  1658  			  "created_at": "2019-08-10T14:59:22Z",
  1659  			  "updated_at": "2019-08-10T14:59:22Z",
  1660  			  "suspended_at": "2019-08-10T14:59:22Z",
  1661  			  "type": "type",
  1662  			  "site_admin": false,
  1663  			  "total_private_repos": 10,
  1664  			  "owned_private_repos": 10,
  1665  			  "private_gists": 10,
  1666  			  "disk_usage": 10,
  1667  			  "collaborators": 10,
  1668  			  "two_factor_authentication": true,
  1669  			  "plan": {
  1670  				"name": "p",
  1671  				"space": 2,
  1672  				"collaborators": 2,
  1673  				"private_repos": 2,
  1674  				"filled_seats": 1,
  1675  				"seats": 2
  1676  			  },
  1677  			  "ldap_dn": "l",
  1678  			  "url": "url",
  1679  			  "events_url": "e",
  1680  			  "following_url": "f",
  1681  			  "followers_url": "f",
  1682  			  "gists_url": "g",
  1683  			  "organizations_url": "o",
  1684  			  "received_events_url": "r",
  1685  			  "repos_url": "rep",
  1686  			  "starred_url": "star",
  1687  			  "subscriptions_url": "sub",
  1688  			  "text_matches": [
  1689  				{
  1690  				  "object_url": "u",
  1691  				  "object_type": "t",
  1692  				  "property": "p",
  1693  				  "fragment": "f",
  1694  				  "matches": [
  1695  					{
  1696  					  "text": "t",
  1697  					  "indices": [
  1698  						1,
  1699  						2
  1700  					  ]
  1701  					}
  1702  				  ]
  1703  				}
  1704  			  ],
  1705  			  "permissions": {
  1706  				"p1": true
  1707  			  },
  1708  			  "role_name": "r"
  1709  			},
  1710  			"type": "t"
  1711  		  }
  1712  		]
  1713  	}`
  1714  
  1715  	testJSONMarshal(t, u, w)
  1716  }