github.com/google/go-github/v52@v52.0.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 testNewRequestAndDoFailureCategory(t, methodName, client, codeScanningUploadCategory, 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_UpdateAlert(t *testing.T) { 617 client, mux, _, teardown := setup() 618 defer teardown() 619 mux.HandleFunc("/repos/o/r/code-scanning/alerts/88", func(w http.ResponseWriter, r *http.Request) { 620 testMethod(t, r, "PATCH") 621 fmt.Fprint(w, `{"rule_id":"js/useless-expression", 622 "rule_severity":"warning", 623 "rule_description":"Expression has no effect", 624 "tool": { 625 "name": "CodeQL", 626 "guid": null, 627 "version": "1.4.0" 628 }, 629 "rule": { 630 "id": "useless expression", 631 "severity": "warning", 632 "description": "Expression has no effect", 633 "name": "useless expression", 634 "full_description": "Expression has no effect", 635 "help": "Expression has no effect" 636 }, 637 "most_recent_instance": { 638 "ref": "refs/heads/main", 639 "state": "dismissed", 640 "commit_sha": "abcdefg12345", 641 "message": { 642 "text": "This path depends on a user-provided value." 643 }, 644 "location": { 645 "path": "spec-main/api-session-spec.ts", 646 "start_line": 917, 647 "end_line": 917, 648 "start_column": 7, 649 "end_column": 18 650 }, 651 "classifications": [ 652 "test" 653 ] 654 }, 655 "created_at":"2019-01-02T15:04:05Z", 656 "state":"dismissed", 657 "dismissed_reason": "false positive", 658 "dismissed_comment": "This alert is not actually correct as sanitizer is used", 659 "closed_by":null, 660 "closed_at":null, 661 "url":"https://api.github.com/repos/o/r/code-scanning/alerts/88", 662 "html_url":"https://github.com/o/r/security/code-scanning/88"}`) 663 }) 664 665 ctx := context.Background() 666 dismissedComment := String("This alert is not actually correct as sanitizer is used") 667 dismissedReason := String("false positive") 668 state := String("dismissed") 669 stateInfo := &CodeScanningAlertState{State: *state, DismissedReason: dismissedReason, DismissedComment: dismissedComment} 670 alert, _, err := client.CodeScanning.UpdateAlert(ctx, "o", "r", 88, stateInfo) 671 if err != nil { 672 t.Errorf("CodeScanning.UpdateAlert returned error: %v", err) 673 } 674 675 date := Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)} 676 want := &Alert{ 677 RuleID: String("js/useless-expression"), 678 RuleSeverity: String("warning"), 679 RuleDescription: String("Expression has no effect"), 680 Tool: &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")}, 681 Rule: &Rule{ 682 ID: String("useless expression"), 683 Severity: String("warning"), 684 Description: String("Expression has no effect"), 685 Name: String("useless expression"), 686 FullDescription: String("Expression has no effect"), 687 Help: String("Expression has no effect"), 688 }, 689 CreatedAt: &date, 690 State: state, 691 DismissedReason: dismissedReason, 692 DismissedComment: dismissedComment, 693 ClosedBy: nil, 694 ClosedAt: nil, 695 URL: String("https://api.github.com/repos/o/r/code-scanning/alerts/88"), 696 HTMLURL: String("https://github.com/o/r/security/code-scanning/88"), 697 MostRecentInstance: &MostRecentInstance{ 698 Ref: String("refs/heads/main"), 699 State: String("dismissed"), 700 CommitSHA: String("abcdefg12345"), 701 Message: &Message{ 702 Text: String("This path depends on a user-provided value."), 703 }, 704 Location: &Location{ 705 Path: String("spec-main/api-session-spec.ts"), 706 StartLine: Int(917), 707 EndLine: Int(917), 708 StartColumn: Int(7), 709 EndColumn: Int(18), 710 }, 711 Classifications: []string{"test"}, 712 }, 713 } 714 if !cmp.Equal(alert, want) { 715 t.Errorf("CodeScanning.UpdateAlert returned %+v, want %+v", alert, want) 716 } 717 718 const methodName = "UpdateAlert" 719 testBadOptions(t, methodName, func() (err error) { 720 _, _, err = client.CodeScanning.UpdateAlert(ctx, "\n", "\n", -88, stateInfo) 721 return err 722 }) 723 724 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 725 got, resp, err := client.CodeScanning.UpdateAlert(ctx, "o", "r", 88, stateInfo) 726 if got != nil { 727 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 728 } 729 return resp, err 730 }) 731 } 732 733 func TestCodeScanningService_GetAlert(t *testing.T) { 734 client, mux, _, teardown := setup() 735 defer teardown() 736 737 mux.HandleFunc("/repos/o/r/code-scanning/alerts/88", func(w http.ResponseWriter, r *http.Request) { 738 testMethod(t, r, "GET") 739 fmt.Fprint(w, `{"rule_id":"js/useless-expression", 740 "rule_severity":"warning", 741 "rule_description":"Expression has no effect", 742 "tool": { 743 "name": "CodeQL", 744 "guid": null, 745 "version": "1.4.0" 746 }, 747 "rule": { 748 "id": "useless expression", 749 "severity": "warning", 750 "description": "Expression has no effect", 751 "name": "useless expression", 752 "full_description": "Expression has no effect", 753 "help": "Expression has no effect" 754 }, 755 "most_recent_instance": { 756 "ref": "refs/heads/main", 757 "state": "open", 758 "commit_sha": "abcdefg12345", 759 "message": { 760 "text": "This path depends on a user-provided value." 761 }, 762 "location": { 763 "path": "spec-main/api-session-spec.ts", 764 "start_line": 917, 765 "end_line": 917, 766 "start_column": 7, 767 "end_column": 18 768 }, 769 "classifications": [ 770 "test" 771 ] 772 }, 773 "created_at":"2019-01-02T15:04:05Z", 774 "state":"open", 775 "closed_by":null, 776 "closed_at":null, 777 "url":"https://api.github.com/repos/o/r/code-scanning/alerts/88", 778 "html_url":"https://github.com/o/r/security/code-scanning/88"}`) 779 }) 780 781 ctx := context.Background() 782 alert, _, err := client.CodeScanning.GetAlert(ctx, "o", "r", 88) 783 if err != nil { 784 t.Errorf("CodeScanning.GetAlert returned error: %v", err) 785 } 786 787 date := Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)} 788 want := &Alert{ 789 RuleID: String("js/useless-expression"), 790 RuleSeverity: String("warning"), 791 RuleDescription: String("Expression has no effect"), 792 Tool: &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")}, 793 Rule: &Rule{ 794 ID: String("useless expression"), 795 Severity: String("warning"), 796 Description: String("Expression has no effect"), 797 Name: String("useless expression"), 798 FullDescription: String("Expression has no effect"), 799 Help: String("Expression has no effect"), 800 }, 801 CreatedAt: &date, 802 State: String("open"), 803 ClosedBy: nil, 804 ClosedAt: nil, 805 URL: String("https://api.github.com/repos/o/r/code-scanning/alerts/88"), 806 HTMLURL: String("https://github.com/o/r/security/code-scanning/88"), 807 MostRecentInstance: &MostRecentInstance{ 808 Ref: String("refs/heads/main"), 809 State: String("open"), 810 CommitSHA: String("abcdefg12345"), 811 Message: &Message{ 812 Text: String("This path depends on a user-provided value."), 813 }, 814 Location: &Location{ 815 Path: String("spec-main/api-session-spec.ts"), 816 StartLine: Int(917), 817 EndLine: Int(917), 818 StartColumn: Int(7), 819 EndColumn: Int(18), 820 }, 821 Classifications: []string{"test"}, 822 }, 823 } 824 if !cmp.Equal(alert, want) { 825 t.Errorf("CodeScanning.GetAlert returned %+v, want %+v", alert, want) 826 } 827 828 const methodName = "GetAlert" 829 testBadOptions(t, methodName, func() (err error) { 830 _, _, err = client.CodeScanning.GetAlert(ctx, "\n", "\n", -88) 831 return err 832 }) 833 834 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 835 got, resp, err := client.CodeScanning.GetAlert(ctx, "o", "r", 88) 836 if got != nil { 837 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 838 } 839 return resp, err 840 }) 841 } 842 843 func TestAlert_Marshal(t *testing.T) { 844 testJSONMarshal(t, &Alert{}, "{}") 845 846 u := &Alert{ 847 RuleID: String("rid"), 848 RuleSeverity: String("rs"), 849 RuleDescription: String("rd"), 850 Tool: &Tool{ 851 Name: String("n"), 852 GUID: String("g"), 853 Version: String("v"), 854 }, 855 CreatedAt: &Timestamp{referenceTime}, 856 State: String("fixed"), 857 ClosedBy: &User{ 858 Login: String("l"), 859 ID: Int64(1), 860 NodeID: String("n"), 861 URL: String("u"), 862 ReposURL: String("r"), 863 EventsURL: String("e"), 864 AvatarURL: String("a"), 865 }, 866 ClosedAt: &Timestamp{referenceTime}, 867 URL: String("url"), 868 HTMLURL: String("hurl"), 869 } 870 871 want := `{ 872 "rule_id": "rid", 873 "rule_severity": "rs", 874 "rule_description": "rd", 875 "tool": { 876 "name": "n", 877 "guid": "g", 878 "version": "v" 879 }, 880 "created_at": ` + referenceTimeStr + `, 881 "state": "fixed", 882 "closed_by": { 883 "login": "l", 884 "id": 1, 885 "node_id": "n", 886 "avatar_url": "a", 887 "url": "u", 888 "events_url": "e", 889 "repos_url": "r" 890 }, 891 "closed_at": ` + referenceTimeStr + `, 892 "url": "url", 893 "html_url": "hurl" 894 }` 895 896 testJSONMarshal(t, u, want) 897 } 898 899 func TestLocation_Marshal(t *testing.T) { 900 testJSONMarshal(t, &Location{}, "{}") 901 902 u := &Location{ 903 Path: String("path"), 904 StartLine: Int(1), 905 EndLine: Int(2), 906 StartColumn: Int(3), 907 EndColumn: Int(4), 908 } 909 910 want := `{ 911 "path": "path", 912 "start_line": 1, 913 "end_line": 2, 914 "start_column": 3, 915 "end_column": 4 916 }` 917 918 testJSONMarshal(t, u, want) 919 } 920 921 func TestRule_Marshal(t *testing.T) { 922 testJSONMarshal(t, &Rule{}, "{}") 923 924 u := &Rule{ 925 ID: String("1"), 926 Severity: String("3"), 927 Description: String("description"), 928 Name: String("first"), 929 SecuritySeverityLevel: String("2"), 930 FullDescription: String("summary"), 931 Tags: []string{"tag1", "tag2"}, 932 Help: String("Help Text"), 933 } 934 935 want := `{ 936 "id": "1", 937 "severity": "3", 938 "description": "description", 939 "name": "first", 940 "security_severity_level": "2", 941 "full_description": "summary", 942 "tags": ["tag1", "tag2"], 943 "help": "Help Text" 944 }` 945 946 testJSONMarshal(t, u, want) 947 } 948 949 func TestTool_Marshal(t *testing.T) { 950 testJSONMarshal(t, &Tool{}, "{}") 951 952 u := &Tool{ 953 Name: String("name"), 954 GUID: String("guid"), 955 Version: String("ver"), 956 } 957 958 want := `{ 959 "name": "name", 960 "guid": "guid", 961 "version": "ver" 962 }` 963 964 testJSONMarshal(t, u, want) 965 } 966 967 func TestMessage_Marshal(t *testing.T) { 968 testJSONMarshal(t, &Message{}, "{}") 969 970 u := &Message{ 971 Text: String("text"), 972 } 973 974 want := `{ 975 "text": "text" 976 }` 977 978 testJSONMarshal(t, u, want) 979 } 980 981 func TestCodeScanningService_ListAnalysesForRepo(t *testing.T) { 982 client, mux, _, teardown := setup() 983 defer teardown() 984 985 mux.HandleFunc("/repos/o/r/code-scanning/analyses", func(w http.ResponseWriter, r *http.Request) { 986 testMethod(t, r, "GET") 987 testFormValues(t, r, values{"sarif_id": "8981cd8e-b078-4ac3-a3be-1dad7dbd0b582", "ref": "heads/master"}) 988 fmt.Fprint(w, `[ 989 { 990 "ref": "refs/heads/main", 991 "commit_sha": "d99612c3e1f2970085cfbaeadf8f010ef69bad83", 992 "analysis_key": ".github/workflows/codeql-analysis.yml:analyze", 993 "environment": "{\"language\":\"python\"}", 994 "error": "", 995 "category": ".github/workflows/codeql-analysis.yml:analyze/language:python", 996 "created_at": "2020-08-27T15:05:21Z", 997 "results_count": 17, 998 "rules_count": 49, 999 "id": 201, 1000 "url": "https://api.github.com/repos/o/r/code-scanning/analyses/201", 1001 "sarif_id": "8981cd8e-b078-4ac3-a3be-1dad7dbd0b582", 1002 "tool": { 1003 "name": "CodeQL", 1004 "guid": null, 1005 "version": "2.4.0" 1006 }, 1007 "deletable": true, 1008 "warning": "" 1009 }, 1010 { 1011 "ref": "refs/heads/my-branch", 1012 "commit_sha": "c8cff6510d4d084fb1b4aa13b64b97ca12b07321", 1013 "analysis_key": ".github/workflows/shiftleft.yml:build", 1014 "environment": "{}", 1015 "error": "", 1016 "category": ".github/workflows/shiftleft.yml:build/", 1017 "created_at": "2020-08-27T15:05:21Z", 1018 "results_count": 17, 1019 "rules_count": 32, 1020 "id": 200, 1021 "url": "https://api.github.com/repos/o/r/code-scanning/analyses/200", 1022 "sarif_id": "8981cd8e-b078-4ac3-a3be-1dad7dbd0b582", 1023 "tool": { 1024 "name": "Python Security ScanningAnalysis", 1025 "guid": null, 1026 "version": "1.2.0" 1027 }, 1028 "deletable": true, 1029 "warning": "" 1030 } 1031 ]`) 1032 }) 1033 1034 opts := &AnalysesListOptions{SarifID: String("8981cd8e-b078-4ac3-a3be-1dad7dbd0b582"), Ref: String("heads/master")} 1035 ctx := context.Background() 1036 analyses, _, err := client.CodeScanning.ListAnalysesForRepo(ctx, "o", "r", opts) 1037 if err != nil { 1038 t.Errorf("CodeScanning.ListAnalysesForRepo returned error: %v", err) 1039 } 1040 1041 date := &Timestamp{time.Date(2020, time.August, 27, 15, 05, 21, 0, time.UTC)} 1042 want := []*ScanningAnalysis{ 1043 { 1044 ID: Int64(201), 1045 Ref: String("refs/heads/main"), 1046 CommitSHA: String("d99612c3e1f2970085cfbaeadf8f010ef69bad83"), 1047 AnalysisKey: String(".github/workflows/codeql-analysis.yml:analyze"), 1048 Environment: String("{\"language\":\"python\"}"), 1049 Error: String(""), 1050 Category: String(".github/workflows/codeql-analysis.yml:analyze/language:python"), 1051 CreatedAt: date, 1052 ResultsCount: Int(17), 1053 RulesCount: Int(49), 1054 URL: String("https://api.github.com/repos/o/r/code-scanning/analyses/201"), 1055 SarifID: String("8981cd8e-b078-4ac3-a3be-1dad7dbd0b582"), 1056 Tool: &Tool{ 1057 Name: String("CodeQL"), 1058 GUID: nil, 1059 Version: String("2.4.0"), 1060 }, 1061 Deletable: Bool(true), 1062 Warning: String(""), 1063 }, 1064 { 1065 ID: Int64(200), 1066 Ref: String("refs/heads/my-branch"), 1067 CommitSHA: String("c8cff6510d4d084fb1b4aa13b64b97ca12b07321"), 1068 AnalysisKey: String(".github/workflows/shiftleft.yml:build"), 1069 Environment: String("{}"), 1070 Error: String(""), 1071 Category: String(".github/workflows/shiftleft.yml:build/"), 1072 CreatedAt: date, 1073 ResultsCount: Int(17), 1074 RulesCount: Int(32), 1075 URL: String("https://api.github.com/repos/o/r/code-scanning/analyses/200"), 1076 SarifID: String("8981cd8e-b078-4ac3-a3be-1dad7dbd0b582"), 1077 Tool: &Tool{ 1078 Name: String("Python Security ScanningAnalysis"), 1079 GUID: nil, 1080 Version: String("1.2.0"), 1081 }, 1082 Deletable: Bool(true), 1083 Warning: String(""), 1084 }, 1085 } 1086 if !cmp.Equal(analyses, want) { 1087 t.Errorf("CodeScanning.ListAnalysesForRepo returned %+v, want %+v", analyses, want) 1088 } 1089 1090 const methodName = "ListAnalysesForRepo" 1091 testBadOptions(t, methodName, func() (err error) { 1092 _, _, err = client.CodeScanning.ListAnalysesForRepo(ctx, "\n", "\n", opts) 1093 return err 1094 }) 1095 1096 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 1097 got, resp, err := client.CodeScanning.ListAnalysesForRepo(ctx, "o", "r", opts) 1098 if got != nil { 1099 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 1100 } 1101 return resp, err 1102 }) 1103 } 1104 1105 func TestCodeScanningService_GetAnalysis(t *testing.T) { 1106 client, mux, _, teardown := setup() 1107 defer teardown() 1108 1109 mux.HandleFunc("/repos/o/r/code-scanning/analyses/3602840", func(w http.ResponseWriter, r *http.Request) { 1110 testMethod(t, r, "GET") 1111 fmt.Fprint(w, `{ 1112 "ref": "refs/heads/main", 1113 "commit_sha": "c18c69115654ff0166991962832dc2bd7756e655", 1114 "analysis_key": ".github/workflows/codeql-analysis.yml:analyze", 1115 "environment": "{\"language\":\"javascript\"}", 1116 "error": "", 1117 "category": ".github/workflows/codeql-analysis.yml:analyze/language:javascript", 1118 "created_at": "2021-01-13T11:55:49Z", 1119 "results_count": 3, 1120 "rules_count": 67, 1121 "id": 3602840, 1122 "url": "https://api.github.com/repos/o/r/code-scanning/analyses/201", 1123 "sarif_id": "47177e22-5596-11eb-80a1-c1e54ef945c6", 1124 "tool": { 1125 "name": "CodeQL", 1126 "guid": null, 1127 "version": "2.4.0" 1128 }, 1129 "deletable": true, 1130 "warning": "" 1131 }`) 1132 }) 1133 1134 ctx := context.Background() 1135 analysis, _, err := client.CodeScanning.GetAnalysis(ctx, "o", "r", 3602840) 1136 if err != nil { 1137 t.Errorf("CodeScanning.GetAnalysis returned error: %v", err) 1138 } 1139 1140 date := &Timestamp{time.Date(2021, time.January, 13, 11, 55, 49, 0, time.UTC)} 1141 want := &ScanningAnalysis{ 1142 ID: Int64(3602840), 1143 Ref: String("refs/heads/main"), 1144 CommitSHA: String("c18c69115654ff0166991962832dc2bd7756e655"), 1145 AnalysisKey: String(".github/workflows/codeql-analysis.yml:analyze"), 1146 Environment: String("{\"language\":\"javascript\"}"), 1147 Error: String(""), 1148 Category: String(".github/workflows/codeql-analysis.yml:analyze/language:javascript"), 1149 CreatedAt: date, 1150 ResultsCount: Int(3), 1151 RulesCount: Int(67), 1152 URL: String("https://api.github.com/repos/o/r/code-scanning/analyses/201"), 1153 SarifID: String("47177e22-5596-11eb-80a1-c1e54ef945c6"), 1154 Tool: &Tool{ 1155 Name: String("CodeQL"), 1156 GUID: nil, 1157 Version: String("2.4.0"), 1158 }, 1159 Deletable: Bool(true), 1160 Warning: String(""), 1161 } 1162 if !cmp.Equal(analysis, want) { 1163 t.Errorf("CodeScanning.GetAnalysis returned %+v, want %+v", analysis, want) 1164 } 1165 1166 const methodName = "GetAnalysis" 1167 testBadOptions(t, methodName, func() (err error) { 1168 _, _, err = client.CodeScanning.GetAnalysis(ctx, "\n", "\n", -123) 1169 return err 1170 }) 1171 1172 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 1173 got, resp, err := client.CodeScanning.GetAnalysis(ctx, "o", "r", 3602840) 1174 if got != nil { 1175 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 1176 } 1177 return resp, err 1178 }) 1179 }