github.com/google/go-github/v49@v49.1.0/github/code-scanning_test.go (about) 1 // Copyright 2020 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 "encoding/json" 11 "fmt" 12 "net/http" 13 "testing" 14 "time" 15 16 "github.com/google/go-cmp/cmp" 17 ) 18 19 func TestCodeScanningService_Alert_ID(t *testing.T) { 20 // Test: nil Alert ID == 0 21 var a *Alert 22 id := a.ID() 23 var want int64 24 if id != want { 25 t.Errorf("Alert.ID error returned %+v, want %+v", id, want) 26 } 27 28 // Test: Valid HTMLURL 29 a = &Alert{ 30 HTMLURL: String("https://github.com/o/r/security/code-scanning/88"), 31 } 32 id = a.ID() 33 want = 88 34 if !cmp.Equal(id, want) { 35 t.Errorf("Alert.ID error returned %+v, want %+v", id, want) 36 } 37 38 // Test: HTMLURL is nil 39 a = &Alert{} 40 id = a.ID() 41 want = 0 42 if !cmp.Equal(id, want) { 43 t.Errorf("Alert.ID error returned %+v, want %+v", id, want) 44 } 45 46 // Test: ID can't be parsed as an int 47 a = &Alert{ 48 HTMLURL: String("https://github.com/o/r/security/code-scanning/bad88"), 49 } 50 id = a.ID() 51 want = 0 52 if !cmp.Equal(id, want) { 53 t.Errorf("Alert.ID error returned %+v, want %+v", id, want) 54 } 55 } 56 57 func TestCodeScanningService_UploadSarif(t *testing.T) { 58 client, mux, _, teardown := setup() 59 defer teardown() 60 61 mux.HandleFunc("/repos/o/r/code-scanning/sarifs", func(w http.ResponseWriter, r *http.Request) { 62 v := new(SarifAnalysis) 63 json.NewDecoder(r.Body).Decode(v) 64 testMethod(t, r, "POST") 65 want := &SarifAnalysis{CommitSHA: String("abc"), Ref: String("ref/head/main"), Sarif: String("abc"), CheckoutURI: String("uri"), StartedAt: &Timestamp{time.Date(2006, time.January, 02, 15, 04, 05, 0, time.UTC)}, ToolName: String("codeql-cli")} 66 if !cmp.Equal(v, want) { 67 t.Errorf("Request body = %+v, want %+v", v, want) 68 } 69 70 fmt.Fprint(w, `{"commit_sha":"abc","ref":"ref/head/main","sarif":"abc"}`) 71 }) 72 73 ctx := context.Background() 74 sarifAnalysis := &SarifAnalysis{CommitSHA: String("abc"), Ref: String("ref/head/main"), Sarif: String("abc"), CheckoutURI: String("uri"), StartedAt: &Timestamp{time.Date(2006, time.January, 02, 15, 04, 05, 0, time.UTC)}, ToolName: String("codeql-cli")} 75 _, _, err := client.CodeScanning.UploadSarif(ctx, "o", "r", sarifAnalysis) 76 if err != nil { 77 t.Errorf("CodeScanning.UploadSarif returned error: %v", err) 78 } 79 80 const methodName = "UploadSarif" 81 testBadOptions(t, methodName, func() (err error) { 82 _, _, err = client.CodeScanning.UploadSarif(ctx, "\n", "\n", sarifAnalysis) 83 return err 84 }) 85 86 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 87 _, resp, err := client.CodeScanning.UploadSarif(ctx, "o", "r", sarifAnalysis) 88 return resp, err 89 }) 90 } 91 92 func TestCodeScanningService_ListAlertsForOrg(t *testing.T) { 93 client, mux, _, teardown := setup() 94 defer teardown() 95 96 mux.HandleFunc("/orgs/o/code-scanning/alerts", func(w http.ResponseWriter, r *http.Request) { 97 testMethod(t, r, "GET") 98 testFormValues(t, r, values{"state": "open", "ref": "heads/master"}) 99 fmt.Fprint(w, `[{ 100 "repository": { 101 "id": 1, 102 "name": "n", 103 "url": "url" 104 }, 105 "rule_id":"js/trivial-conditional", 106 "rule_severity":"warning", 107 "rule_description":"Useless conditional", 108 "tool": { 109 "name": "CodeQL", 110 "guid": null, 111 "version": "1.4.0" 112 }, 113 "rule": { 114 "id": "js/trivial-conditional", 115 "severity": "warning", 116 "description": "Useless conditional", 117 "name": "js/trivial-conditional", 118 "full_description": "Expression has no effect", 119 "help": "Expression has no effect" 120 }, 121 "most_recent_instance": { 122 "ref": "refs/heads/main", 123 "state": "open", 124 "commit_sha": "abcdefg12345", 125 "message": { 126 "text": "This path depends on a user-provided value." 127 }, 128 "location": { 129 "path": "spec-main/api-session-spec.ts", 130 "start_line": 917, 131 "end_line": 917, 132 "start_column": 7, 133 "end_column": 18 134 }, 135 "classifications": [ 136 "test" 137 ] 138 }, 139 "created_at":"2020-05-06T12:00:00Z", 140 "state":"open", 141 "closed_by":null, 142 "closed_at":null, 143 "url":"https://api.github.com/repos/o/r/code-scanning/alerts/25", 144 "html_url":"https://github.com/o/r/security/code-scanning/25" 145 }, 146 { 147 "rule_id":"js/useless-expression", 148 "rule_severity":"warning", 149 "rule_description":"Expression has no effect", 150 "tool": { 151 "name": "CodeQL", 152 "guid": null, 153 "version": "1.4.0" 154 }, 155 "rule": { 156 "id": "js/useless-expression", 157 "severity": "warning", 158 "description": "Expression has no effect", 159 "name": "js/useless-expression", 160 "full_description": "Expression has no effect", 161 "help": "Expression has no effect" 162 }, 163 "most_recent_instance": { 164 "ref": "refs/heads/main", 165 "state": "open", 166 "commit_sha": "abcdefg12345", 167 "message": { 168 "text": "This path depends on a user-provided value." 169 }, 170 "location": { 171 "path": "spec-main/api-session-spec.ts", 172 "start_line": 917, 173 "end_line": 917, 174 "start_column": 7, 175 "end_column": 18 176 }, 177 "classifications": [ 178 "test" 179 ] 180 }, 181 "created_at":"2020-05-06T12:00:00Z", 182 "state":"open", 183 "closed_by":null, 184 "closed_at":null, 185 "url":"https://api.github.com/repos/o/r/code-scanning/alerts/88", 186 "html_url":"https://github.com/o/r/security/code-scanning/88" 187 }]`) 188 }) 189 190 opts := &AlertListOptions{State: "open", Ref: "heads/master"} 191 ctx := context.Background() 192 alerts, _, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts) 193 if err != nil { 194 t.Errorf("CodeScanning.ListAlertsForOrg returned error: %v", err) 195 } 196 197 date := Timestamp{time.Date(2020, time.May, 06, 12, 00, 00, 0, time.UTC)} 198 want := []*Alert{ 199 { 200 Repository: &Repository{ 201 ID: Int64(1), 202 URL: String("url"), 203 Name: String("n"), 204 }, 205 RuleID: String("js/trivial-conditional"), 206 RuleSeverity: String("warning"), 207 RuleDescription: String("Useless conditional"), 208 Tool: &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")}, 209 Rule: &Rule{ 210 ID: String("js/trivial-conditional"), 211 Severity: String("warning"), 212 Description: String("Useless conditional"), 213 Name: String("js/trivial-conditional"), 214 FullDescription: String("Expression has no effect"), 215 Help: String("Expression has no effect"), 216 }, 217 CreatedAt: &date, 218 State: String("open"), 219 ClosedBy: nil, 220 ClosedAt: nil, 221 URL: String("https://api.github.com/repos/o/r/code-scanning/alerts/25"), 222 HTMLURL: String("https://github.com/o/r/security/code-scanning/25"), 223 MostRecentInstance: &MostRecentInstance{ 224 Ref: String("refs/heads/main"), 225 State: String("open"), 226 CommitSHA: String("abcdefg12345"), 227 Message: &Message{ 228 Text: String("This path depends on a user-provided value."), 229 }, 230 Location: &Location{ 231 Path: String("spec-main/api-session-spec.ts"), 232 StartLine: Int(917), 233 EndLine: Int(917), 234 StartColumn: Int(7), 235 EndColumn: Int(18), 236 }, 237 Classifications: []string{"test"}, 238 }, 239 }, 240 { 241 RuleID: String("js/useless-expression"), 242 RuleSeverity: String("warning"), 243 RuleDescription: String("Expression has no effect"), 244 Tool: &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")}, 245 Rule: &Rule{ 246 ID: String("js/useless-expression"), 247 Severity: String("warning"), 248 Description: String("Expression has no effect"), 249 Name: String("js/useless-expression"), 250 FullDescription: String("Expression has no effect"), 251 Help: String("Expression has no effect"), 252 }, 253 CreatedAt: &date, 254 State: String("open"), 255 ClosedBy: nil, 256 ClosedAt: nil, 257 URL: String("https://api.github.com/repos/o/r/code-scanning/alerts/88"), 258 HTMLURL: String("https://github.com/o/r/security/code-scanning/88"), 259 MostRecentInstance: &MostRecentInstance{ 260 Ref: String("refs/heads/main"), 261 State: String("open"), 262 CommitSHA: String("abcdefg12345"), 263 Message: &Message{ 264 Text: String("This path depends on a user-provided value."), 265 }, 266 Location: &Location{ 267 Path: String("spec-main/api-session-spec.ts"), 268 StartLine: Int(917), 269 EndLine: Int(917), 270 StartColumn: Int(7), 271 EndColumn: Int(18), 272 }, 273 Classifications: []string{"test"}, 274 }, 275 }, 276 } 277 if !cmp.Equal(alerts, want) { 278 t.Errorf("CodeScanning.ListAlertsForOrg returned %+v, want %+v", *&alerts, *&want) 279 } 280 281 const methodName = "ListAlertsForOrg" 282 testBadOptions(t, methodName, func() (err error) { 283 _, _, err = client.CodeScanning.ListAlertsForOrg(ctx, "\n", opts) 284 return err 285 }) 286 287 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 288 got, resp, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts) 289 if got != nil { 290 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 291 } 292 return resp, err 293 }) 294 } 295 296 func TestCodeScanningService_ListAlertsForOrgLisCursorOptions(t *testing.T) { 297 client, mux, _, teardown := setup() 298 defer teardown() 299 300 mux.HandleFunc("/orgs/o/code-scanning/alerts", func(w http.ResponseWriter, r *http.Request) { 301 testMethod(t, r, "GET") 302 testFormValues(t, r, values{"state": "open", "ref": "heads/master", "per_page": "1", "before": "deadbeefb", "after": "deadbeefa"}) 303 fmt.Fprint(w, `[{ 304 "repository": { 305 "id": 1, 306 "name": "n", 307 "url": "url" 308 }, 309 "rule_id":"js/trivial-conditional", 310 "rule_severity":"warning", 311 "rule_description":"Useless conditional", 312 "tool": { 313 "name": "CodeQL", 314 "guid": null, 315 "version": "1.4.0" 316 }, 317 "rule": { 318 "id": "js/trivial-conditional", 319 "severity": "warning", 320 "description": "Useless conditional", 321 "name": "js/trivial-conditional", 322 "full_description": "Expression has no effect", 323 "help": "Expression has no effect" 324 }, 325 "most_recent_instance": { 326 "ref": "refs/heads/main", 327 "state": "open", 328 "commit_sha": "abcdefg12345", 329 "message": { 330 "text": "This path depends on a user-provided value." 331 }, 332 "location": { 333 "path": "spec-main/api-session-spec.ts", 334 "start_line": 917, 335 "end_line": 917, 336 "start_column": 7, 337 "end_column": 18 338 }, 339 "classifications": [ 340 "test" 341 ] 342 }, 343 "created_at":"2020-05-06T12:00:00Z", 344 "state":"open", 345 "closed_by":null, 346 "closed_at":null, 347 "url":"https://api.github.com/repos/o/r/code-scanning/alerts/25", 348 "html_url":"https://github.com/o/r/security/code-scanning/25" 349 }]`) 350 }) 351 352 opts := &AlertListOptions{State: "open", Ref: "heads/master", ListCursorOptions: ListCursorOptions{PerPage: 1, Before: "deadbeefb", After: "deadbeefa"}} 353 ctx := context.Background() 354 alerts, _, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts) 355 if err != nil { 356 t.Errorf("CodeScanning.ListAlertsForOrg returned error: %v", err) 357 } 358 359 date := Timestamp{time.Date(2020, time.May, 06, 12, 00, 00, 0, time.UTC)} 360 want := []*Alert{ 361 { 362 Repository: &Repository{ 363 ID: Int64(1), 364 URL: String("url"), 365 Name: String("n"), 366 }, 367 RuleID: String("js/trivial-conditional"), 368 RuleSeverity: String("warning"), 369 RuleDescription: String("Useless conditional"), 370 Tool: &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")}, 371 Rule: &Rule{ 372 ID: String("js/trivial-conditional"), 373 Severity: String("warning"), 374 Description: String("Useless conditional"), 375 Name: String("js/trivial-conditional"), 376 FullDescription: String("Expression has no effect"), 377 Help: String("Expression has no effect"), 378 }, 379 CreatedAt: &date, 380 State: String("open"), 381 ClosedBy: nil, 382 ClosedAt: nil, 383 URL: String("https://api.github.com/repos/o/r/code-scanning/alerts/25"), 384 HTMLURL: String("https://github.com/o/r/security/code-scanning/25"), 385 MostRecentInstance: &MostRecentInstance{ 386 Ref: String("refs/heads/main"), 387 State: String("open"), 388 CommitSHA: String("abcdefg12345"), 389 Message: &Message{ 390 Text: String("This path depends on a user-provided value."), 391 }, 392 Location: &Location{ 393 Path: String("spec-main/api-session-spec.ts"), 394 StartLine: Int(917), 395 EndLine: Int(917), 396 StartColumn: Int(7), 397 EndColumn: Int(18), 398 }, 399 Classifications: []string{"test"}, 400 }, 401 }, 402 } 403 if !cmp.Equal(alerts, want) { 404 t.Errorf("CodeScanning.ListAlertsForOrg returned %+v, want %+v", *&alerts, *&want) 405 } 406 407 const methodName = "ListAlertsForOrg" 408 testBadOptions(t, methodName, func() (err error) { 409 _, _, err = client.CodeScanning.ListAlertsForOrg(ctx, "\n", opts) 410 return err 411 }) 412 413 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 414 got, resp, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts) 415 if got != nil { 416 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 417 } 418 return resp, err 419 }) 420 } 421 422 func TestCodeScanningService_ListAlertsForRepo(t *testing.T) { 423 client, mux, _, teardown := setup() 424 defer teardown() 425 426 mux.HandleFunc("/repos/o/r/code-scanning/alerts", func(w http.ResponseWriter, r *http.Request) { 427 testMethod(t, r, "GET") 428 testFormValues(t, r, values{"state": "open", "ref": "heads/master"}) 429 fmt.Fprint(w, `[{ 430 "rule_id":"js/trivial-conditional", 431 "rule_severity":"warning", 432 "rule_description":"Useless conditional", 433 "tool": { 434 "name": "CodeQL", 435 "guid": null, 436 "version": "1.4.0" 437 }, 438 "rule": { 439 "id": "js/trivial-conditional", 440 "severity": "warning", 441 "description": "Useless conditional", 442 "name": "js/trivial-conditional", 443 "full_description": "Expression has no effect", 444 "help": "Expression has no effect" 445 }, 446 "most_recent_instance": { 447 "ref": "refs/heads/main", 448 "state": "open", 449 "commit_sha": "abcdefg12345", 450 "message": { 451 "text": "This path depends on a user-provided value." 452 }, 453 "location": { 454 "path": "spec-main/api-session-spec.ts", 455 "start_line": 917, 456 "end_line": 917, 457 "start_column": 7, 458 "end_column": 18 459 }, 460 "classifications": [ 461 "test" 462 ] 463 }, 464 "created_at":"2020-05-06T12:00:00Z", 465 "state":"open", 466 "closed_by":null, 467 "closed_at":null, 468 "url":"https://api.github.com/repos/o/r/code-scanning/alerts/25", 469 "html_url":"https://github.com/o/r/security/code-scanning/25" 470 }, 471 { 472 "rule_id":"js/useless-expression", 473 "rule_severity":"warning", 474 "rule_description":"Expression has no effect", 475 "tool": { 476 "name": "CodeQL", 477 "guid": null, 478 "version": "1.4.0" 479 }, 480 "rule": { 481 "id": "js/useless-expression", 482 "severity": "warning", 483 "description": "Expression has no effect", 484 "name": "js/useless-expression", 485 "full_description": "Expression has no effect", 486 "help": "Expression has no effect" 487 }, 488 "most_recent_instance": { 489 "ref": "refs/heads/main", 490 "state": "open", 491 "commit_sha": "abcdefg12345", 492 "message": { 493 "text": "This path depends on a user-provided value." 494 }, 495 "location": { 496 "path": "spec-main/api-session-spec.ts", 497 "start_line": 917, 498 "end_line": 917, 499 "start_column": 7, 500 "end_column": 18 501 }, 502 "classifications": [ 503 "test" 504 ] 505 }, 506 "created_at":"2020-05-06T12:00:00Z", 507 "state":"open", 508 "closed_by":null, 509 "closed_at":null, 510 "url":"https://api.github.com/repos/o/r/code-scanning/alerts/88", 511 "html_url":"https://github.com/o/r/security/code-scanning/88" 512 }]`) 513 }) 514 515 opts := &AlertListOptions{State: "open", Ref: "heads/master"} 516 ctx := context.Background() 517 alerts, _, err := client.CodeScanning.ListAlertsForRepo(ctx, "o", "r", opts) 518 if err != nil { 519 t.Errorf("CodeScanning.ListAlertsForRepo returned error: %v", err) 520 } 521 522 date := Timestamp{time.Date(2020, time.May, 06, 12, 00, 00, 0, time.UTC)} 523 want := []*Alert{ 524 { 525 RuleID: String("js/trivial-conditional"), 526 RuleSeverity: String("warning"), 527 RuleDescription: String("Useless conditional"), 528 Tool: &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")}, 529 Rule: &Rule{ 530 ID: String("js/trivial-conditional"), 531 Severity: String("warning"), 532 Description: String("Useless conditional"), 533 Name: String("js/trivial-conditional"), 534 FullDescription: String("Expression has no effect"), 535 Help: String("Expression has no effect"), 536 }, 537 CreatedAt: &date, 538 State: String("open"), 539 ClosedBy: nil, 540 ClosedAt: nil, 541 URL: String("https://api.github.com/repos/o/r/code-scanning/alerts/25"), 542 HTMLURL: String("https://github.com/o/r/security/code-scanning/25"), 543 MostRecentInstance: &MostRecentInstance{ 544 Ref: String("refs/heads/main"), 545 State: String("open"), 546 CommitSHA: String("abcdefg12345"), 547 Message: &Message{ 548 Text: String("This path depends on a user-provided value."), 549 }, 550 Location: &Location{ 551 Path: String("spec-main/api-session-spec.ts"), 552 StartLine: Int(917), 553 EndLine: Int(917), 554 StartColumn: Int(7), 555 EndColumn: Int(18), 556 }, 557 Classifications: []string{"test"}, 558 }, 559 }, 560 { 561 RuleID: String("js/useless-expression"), 562 RuleSeverity: String("warning"), 563 RuleDescription: String("Expression has no effect"), 564 Tool: &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")}, 565 Rule: &Rule{ 566 ID: String("js/useless-expression"), 567 Severity: String("warning"), 568 Description: String("Expression has no effect"), 569 Name: String("js/useless-expression"), 570 FullDescription: String("Expression has no effect"), 571 Help: String("Expression has no effect"), 572 }, 573 CreatedAt: &date, 574 State: String("open"), 575 ClosedBy: nil, 576 ClosedAt: nil, 577 URL: String("https://api.github.com/repos/o/r/code-scanning/alerts/88"), 578 HTMLURL: String("https://github.com/o/r/security/code-scanning/88"), 579 MostRecentInstance: &MostRecentInstance{ 580 Ref: String("refs/heads/main"), 581 State: String("open"), 582 CommitSHA: String("abcdefg12345"), 583 Message: &Message{ 584 Text: String("This path depends on a user-provided value."), 585 }, 586 Location: &Location{ 587 Path: String("spec-main/api-session-spec.ts"), 588 StartLine: Int(917), 589 EndLine: Int(917), 590 StartColumn: Int(7), 591 EndColumn: Int(18), 592 }, 593 Classifications: []string{"test"}, 594 }, 595 }, 596 } 597 if !cmp.Equal(alerts, want) { 598 t.Errorf("CodeScanning.ListAlertsForRepo returned %+v, want %+v", alerts, want) 599 } 600 601 const methodName = "ListAlertsForRepo" 602 testBadOptions(t, methodName, func() (err error) { 603 _, _, err = client.CodeScanning.ListAlertsForRepo(ctx, "\n", "\n", opts) 604 return err 605 }) 606 607 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 608 got, resp, err := client.CodeScanning.ListAlertsForRepo(ctx, "o", "r", opts) 609 if got != nil { 610 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 611 } 612 return resp, err 613 }) 614 } 615 616 func TestCodeScanningService_GetAlert(t *testing.T) { 617 client, mux, _, teardown := setup() 618 defer teardown() 619 620 mux.HandleFunc("/repos/o/r/code-scanning/alerts/88", func(w http.ResponseWriter, r *http.Request) { 621 testMethod(t, r, "GET") 622 fmt.Fprint(w, `{"rule_id":"js/useless-expression", 623 "rule_severity":"warning", 624 "rule_description":"Expression has no effect", 625 "tool": { 626 "name": "CodeQL", 627 "guid": null, 628 "version": "1.4.0" 629 }, 630 "rule": { 631 "id": "useless expression", 632 "severity": "warning", 633 "description": "Expression has no effect", 634 "name": "useless expression", 635 "full_description": "Expression has no effect", 636 "help": "Expression has no effect" 637 }, 638 "most_recent_instance": { 639 "ref": "refs/heads/main", 640 "state": "open", 641 "commit_sha": "abcdefg12345", 642 "message": { 643 "text": "This path depends on a user-provided value." 644 }, 645 "location": { 646 "path": "spec-main/api-session-spec.ts", 647 "start_line": 917, 648 "end_line": 917, 649 "start_column": 7, 650 "end_column": 18 651 }, 652 "classifications": [ 653 "test" 654 ] 655 }, 656 "created_at":"2019-01-02T15:04:05Z", 657 "state":"open", 658 "closed_by":null, 659 "closed_at":null, 660 "url":"https://api.github.com/repos/o/r/code-scanning/alerts/88", 661 "html_url":"https://github.com/o/r/security/code-scanning/88"}`) 662 }) 663 664 ctx := context.Background() 665 alert, _, err := client.CodeScanning.GetAlert(ctx, "o", "r", 88) 666 if err != nil { 667 t.Errorf("CodeScanning.GetAlert returned error: %v", err) 668 } 669 670 date := Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)} 671 want := &Alert{ 672 RuleID: String("js/useless-expression"), 673 RuleSeverity: String("warning"), 674 RuleDescription: String("Expression has no effect"), 675 Tool: &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")}, 676 Rule: &Rule{ 677 ID: String("useless expression"), 678 Severity: String("warning"), 679 Description: String("Expression has no effect"), 680 Name: String("useless expression"), 681 FullDescription: String("Expression has no effect"), 682 Help: String("Expression has no effect"), 683 }, 684 CreatedAt: &date, 685 State: String("open"), 686 ClosedBy: nil, 687 ClosedAt: nil, 688 URL: String("https://api.github.com/repos/o/r/code-scanning/alerts/88"), 689 HTMLURL: String("https://github.com/o/r/security/code-scanning/88"), 690 MostRecentInstance: &MostRecentInstance{ 691 Ref: String("refs/heads/main"), 692 State: String("open"), 693 CommitSHA: String("abcdefg12345"), 694 Message: &Message{ 695 Text: String("This path depends on a user-provided value."), 696 }, 697 Location: &Location{ 698 Path: String("spec-main/api-session-spec.ts"), 699 StartLine: Int(917), 700 EndLine: Int(917), 701 StartColumn: Int(7), 702 EndColumn: Int(18), 703 }, 704 Classifications: []string{"test"}, 705 }, 706 } 707 if !cmp.Equal(alert, want) { 708 t.Errorf("CodeScanning.GetAlert returned %+v, want %+v", alert, want) 709 } 710 711 const methodName = "GetAlert" 712 testBadOptions(t, methodName, func() (err error) { 713 _, _, err = client.CodeScanning.GetAlert(ctx, "\n", "\n", -88) 714 return err 715 }) 716 717 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 718 got, resp, err := client.CodeScanning.GetAlert(ctx, "o", "r", 88) 719 if got != nil { 720 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 721 } 722 return resp, err 723 }) 724 } 725 726 func TestAlert_Marshal(t *testing.T) { 727 testJSONMarshal(t, &Alert{}, "{}") 728 729 u := &Alert{ 730 RuleID: String("rid"), 731 RuleSeverity: String("rs"), 732 RuleDescription: String("rd"), 733 Tool: &Tool{ 734 Name: String("n"), 735 GUID: String("g"), 736 Version: String("v"), 737 }, 738 CreatedAt: &Timestamp{referenceTime}, 739 State: String("fixed"), 740 ClosedBy: &User{ 741 Login: String("l"), 742 ID: Int64(1), 743 NodeID: String("n"), 744 URL: String("u"), 745 ReposURL: String("r"), 746 EventsURL: String("e"), 747 AvatarURL: String("a"), 748 }, 749 ClosedAt: &Timestamp{referenceTime}, 750 URL: String("url"), 751 HTMLURL: String("hurl"), 752 } 753 754 want := `{ 755 "rule_id": "rid", 756 "rule_severity": "rs", 757 "rule_description": "rd", 758 "tool": { 759 "name": "n", 760 "guid": "g", 761 "version": "v" 762 }, 763 "created_at": ` + referenceTimeStr + `, 764 "state": "fixed", 765 "closed_by": { 766 "login": "l", 767 "id": 1, 768 "node_id": "n", 769 "avatar_url": "a", 770 "url": "u", 771 "events_url": "e", 772 "repos_url": "r" 773 }, 774 "closed_at": ` + referenceTimeStr + `, 775 "url": "url", 776 "html_url": "hurl" 777 }` 778 779 testJSONMarshal(t, u, want) 780 } 781 782 func TestLocation_Marshal(t *testing.T) { 783 testJSONMarshal(t, &Location{}, "{}") 784 785 u := &Location{ 786 Path: String("path"), 787 StartLine: Int(1), 788 EndLine: Int(2), 789 StartColumn: Int(3), 790 EndColumn: Int(4), 791 } 792 793 want := `{ 794 "path": "path", 795 "start_line": 1, 796 "end_line": 2, 797 "start_column": 3, 798 "end_column": 4 799 }` 800 801 testJSONMarshal(t, u, want) 802 } 803 804 func TestRule_Marshal(t *testing.T) { 805 testJSONMarshal(t, &Rule{}, "{}") 806 807 u := &Rule{ 808 ID: String("1"), 809 Severity: String("3"), 810 Description: String("description"), 811 Name: String("first"), 812 SecuritySeverityLevel: String("2"), 813 FullDescription: String("summary"), 814 Tags: []string{"tag1", "tag2"}, 815 Help: String("Help Text"), 816 } 817 818 want := `{ 819 "id": "1", 820 "severity": "3", 821 "description": "description", 822 "name": "first", 823 "security_severity_level": "2", 824 "full_description": "summary", 825 "tags": ["tag1", "tag2"], 826 "help": "Help Text" 827 }` 828 829 testJSONMarshal(t, u, want) 830 } 831 832 func TestTool_Marshal(t *testing.T) { 833 testJSONMarshal(t, &Tool{}, "{}") 834 835 u := &Tool{ 836 Name: String("name"), 837 GUID: String("guid"), 838 Version: String("ver"), 839 } 840 841 want := `{ 842 "name": "name", 843 "guid": "guid", 844 "version": "ver" 845 }` 846 847 testJSONMarshal(t, u, want) 848 } 849 850 func TestMessage_Marshal(t *testing.T) { 851 testJSONMarshal(t, &Message{}, "{}") 852 853 u := &Message{ 854 Text: String("text"), 855 } 856 857 want := `{ 858 "text": "text" 859 }` 860 861 testJSONMarshal(t, u, want) 862 } 863 864 func TestCodeScanningService_ListAnalysesForRepo(t *testing.T) { 865 client, mux, _, teardown := setup() 866 defer teardown() 867 868 mux.HandleFunc("/repos/o/r/code-scanning/analyses", func(w http.ResponseWriter, r *http.Request) { 869 testMethod(t, r, "GET") 870 testFormValues(t, r, values{"sarif_id": "8981cd8e-b078-4ac3-a3be-1dad7dbd0b582", "ref": "heads/master"}) 871 fmt.Fprint(w, `[ 872 { 873 "ref": "refs/heads/main", 874 "commit_sha": "d99612c3e1f2970085cfbaeadf8f010ef69bad83", 875 "analysis_key": ".github/workflows/codeql-analysis.yml:analyze", 876 "environment": "{\"language\":\"python\"}", 877 "error": "", 878 "category": ".github/workflows/codeql-analysis.yml:analyze/language:python", 879 "created_at": "2020-08-27T15:05:21Z", 880 "results_count": 17, 881 "rules_count": 49, 882 "id": 201, 883 "url": "https://api.github.com/repos/o/r/code-scanning/analyses/201", 884 "sarif_id": "8981cd8e-b078-4ac3-a3be-1dad7dbd0b582", 885 "tool": { 886 "name": "CodeQL", 887 "guid": null, 888 "version": "2.4.0" 889 }, 890 "deletable": true, 891 "warning": "" 892 }, 893 { 894 "ref": "refs/heads/my-branch", 895 "commit_sha": "c8cff6510d4d084fb1b4aa13b64b97ca12b07321", 896 "analysis_key": ".github/workflows/shiftleft.yml:build", 897 "environment": "{}", 898 "error": "", 899 "category": ".github/workflows/shiftleft.yml:build/", 900 "created_at": "2020-08-27T15:05:21Z", 901 "results_count": 17, 902 "rules_count": 32, 903 "id": 200, 904 "url": "https://api.github.com/repos/o/r/code-scanning/analyses/200", 905 "sarif_id": "8981cd8e-b078-4ac3-a3be-1dad7dbd0b582", 906 "tool": { 907 "name": "Python Security ScanningAnalysis", 908 "guid": null, 909 "version": "1.2.0" 910 }, 911 "deletable": true, 912 "warning": "" 913 } 914 ]`) 915 }) 916 917 opts := &AnalysesListOptions{SarifID: String("8981cd8e-b078-4ac3-a3be-1dad7dbd0b582"), Ref: String("heads/master")} 918 ctx := context.Background() 919 analyses, _, err := client.CodeScanning.ListAnalysesForRepo(ctx, "o", "r", opts) 920 if err != nil { 921 t.Errorf("CodeScanning.ListAnalysesForRepo returned error: %v", err) 922 } 923 924 date := &Timestamp{time.Date(2020, time.August, 27, 15, 05, 21, 0, time.UTC)} 925 want := []*ScanningAnalysis{ 926 { 927 ID: Int64(201), 928 Ref: String("refs/heads/main"), 929 CommitSHA: String("d99612c3e1f2970085cfbaeadf8f010ef69bad83"), 930 AnalysisKey: String(".github/workflows/codeql-analysis.yml:analyze"), 931 Environment: String("{\"language\":\"python\"}"), 932 Error: String(""), 933 Category: String(".github/workflows/codeql-analysis.yml:analyze/language:python"), 934 CreatedAt: date, 935 ResultsCount: Int(17), 936 RulesCount: Int(49), 937 URL: String("https://api.github.com/repos/o/r/code-scanning/analyses/201"), 938 SarifID: String("8981cd8e-b078-4ac3-a3be-1dad7dbd0b582"), 939 Tool: &Tool{ 940 Name: String("CodeQL"), 941 GUID: nil, 942 Version: String("2.4.0"), 943 }, 944 Deletable: Bool(true), 945 Warning: String(""), 946 }, 947 { 948 ID: Int64(200), 949 Ref: String("refs/heads/my-branch"), 950 CommitSHA: String("c8cff6510d4d084fb1b4aa13b64b97ca12b07321"), 951 AnalysisKey: String(".github/workflows/shiftleft.yml:build"), 952 Environment: String("{}"), 953 Error: String(""), 954 Category: String(".github/workflows/shiftleft.yml:build/"), 955 CreatedAt: date, 956 ResultsCount: Int(17), 957 RulesCount: Int(32), 958 URL: String("https://api.github.com/repos/o/r/code-scanning/analyses/200"), 959 SarifID: String("8981cd8e-b078-4ac3-a3be-1dad7dbd0b582"), 960 Tool: &Tool{ 961 Name: String("Python Security ScanningAnalysis"), 962 GUID: nil, 963 Version: String("1.2.0"), 964 }, 965 Deletable: Bool(true), 966 Warning: String(""), 967 }, 968 } 969 if !cmp.Equal(analyses, want) { 970 t.Errorf("CodeScanning.ListAnalysesForRepo returned %+v, want %+v", analyses, want) 971 } 972 973 const methodName = "ListAnalysesForRepo" 974 testBadOptions(t, methodName, func() (err error) { 975 _, _, err = client.CodeScanning.ListAnalysesForRepo(ctx, "\n", "\n", opts) 976 return err 977 }) 978 979 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 980 got, resp, err := client.CodeScanning.ListAnalysesForRepo(ctx, "o", "r", opts) 981 if got != nil { 982 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 983 } 984 return resp, err 985 }) 986 } 987 988 func TestCodeScanningService_GetAnalysis(t *testing.T) { 989 client, mux, _, teardown := setup() 990 defer teardown() 991 992 mux.HandleFunc("/repos/o/r/code-scanning/analyses/3602840", func(w http.ResponseWriter, r *http.Request) { 993 testMethod(t, r, "GET") 994 fmt.Fprint(w, `{ 995 "ref": "refs/heads/main", 996 "commit_sha": "c18c69115654ff0166991962832dc2bd7756e655", 997 "analysis_key": ".github/workflows/codeql-analysis.yml:analyze", 998 "environment": "{\"language\":\"javascript\"}", 999 "error": "", 1000 "category": ".github/workflows/codeql-analysis.yml:analyze/language:javascript", 1001 "created_at": "2021-01-13T11:55:49Z", 1002 "results_count": 3, 1003 "rules_count": 67, 1004 "id": 3602840, 1005 "url": "https://api.github.com/repos/o/r/code-scanning/analyses/201", 1006 "sarif_id": "47177e22-5596-11eb-80a1-c1e54ef945c6", 1007 "tool": { 1008 "name": "CodeQL", 1009 "guid": null, 1010 "version": "2.4.0" 1011 }, 1012 "deletable": true, 1013 "warning": "" 1014 }`) 1015 }) 1016 1017 ctx := context.Background() 1018 analysis, _, err := client.CodeScanning.GetAnalysis(ctx, "o", "r", 3602840) 1019 if err != nil { 1020 t.Errorf("CodeScanning.GetAnalysis returned error: %v", err) 1021 } 1022 1023 date := &Timestamp{time.Date(2021, time.January, 13, 11, 55, 49, 0, time.UTC)} 1024 want := &ScanningAnalysis{ 1025 ID: Int64(3602840), 1026 Ref: String("refs/heads/main"), 1027 CommitSHA: String("c18c69115654ff0166991962832dc2bd7756e655"), 1028 AnalysisKey: String(".github/workflows/codeql-analysis.yml:analyze"), 1029 Environment: String("{\"language\":\"javascript\"}"), 1030 Error: String(""), 1031 Category: String(".github/workflows/codeql-analysis.yml:analyze/language:javascript"), 1032 CreatedAt: date, 1033 ResultsCount: Int(3), 1034 RulesCount: Int(67), 1035 URL: String("https://api.github.com/repos/o/r/code-scanning/analyses/201"), 1036 SarifID: String("47177e22-5596-11eb-80a1-c1e54ef945c6"), 1037 Tool: &Tool{ 1038 Name: String("CodeQL"), 1039 GUID: nil, 1040 Version: String("2.4.0"), 1041 }, 1042 Deletable: Bool(true), 1043 Warning: String(""), 1044 } 1045 if !cmp.Equal(analysis, want) { 1046 t.Errorf("CodeScanning.GetAnalysis returned %+v, want %+v", analysis, want) 1047 } 1048 1049 const methodName = "GetAnalysis" 1050 testBadOptions(t, methodName, func() (err error) { 1051 _, _, err = client.CodeScanning.GetAnalysis(ctx, "\n", "\n", -123) 1052 return err 1053 }) 1054 1055 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 1056 got, resp, err := client.CodeScanning.GetAnalysis(ctx, "o", "r", 3602840) 1057 if got != nil { 1058 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 1059 } 1060 return resp, err 1061 }) 1062 }