|
11 | 11 |
|
12 | 12 | from webob.multidict import MultiDict
|
13 | 13 |
|
14 |
| -from tests.common.db.oidc import GitHubPublisherFactory |
| 14 | +from tests.common.db.oidc import ( |
| 15 | + ActiveStatePublisherFactory, |
| 16 | + GitHubPublisherFactory, |
| 17 | + GitLabPublisherFactory, |
| 18 | + GooglePublisherFactory, |
| 19 | +) |
15 | 20 | from tests.common.db.packaging import ProjectFactory, RoleFactory
|
16 | 21 | from warehouse.macaroons import caveats
|
17 | 22 |
|
| 23 | +from ...common.constants import ( |
| 24 | + DUMMY_ACTIVESTATE_OIDC_JWT, |
| 25 | + DUMMY_GITHUB_OIDC_JWT, |
| 26 | + DUMMY_GITLAB_OIDC_JWT, |
| 27 | + DUMMY_GOOGLE_OIDC_JWT, |
| 28 | +) |
18 | 29 | from ...common.db.accounts import UserFactory
|
19 | 30 | from ...common.db.macaroons import MacaroonFactory
|
20 | 31 |
|
@@ -397,3 +408,173 @@ def test_provenance_upload(webtest):
|
397 | 408 | status=HTTPStatus.OK,
|
398 | 409 | )
|
399 | 410 | assert response.json == project.releases[0].files[0].provenance.provenance
|
| 411 | + |
| 412 | + |
| 413 | +@pytest.mark.parametrize( |
| 414 | + ("publisher_factory", "publisher_data", "oidc_jwt"), |
| 415 | + [ |
| 416 | + ( |
| 417 | + GitHubPublisherFactory, |
| 418 | + { |
| 419 | + "repository_name": "bar", |
| 420 | + "repository_owner": "foo", |
| 421 | + "repository_owner_id": "123", |
| 422 | + "workflow_filename": "example.yml", |
| 423 | + "environment": "fake", |
| 424 | + }, |
| 425 | + DUMMY_GITHUB_OIDC_JWT, |
| 426 | + ), |
| 427 | + ( |
| 428 | + ActiveStatePublisherFactory, |
| 429 | + { |
| 430 | + "organization": "fakeorg", |
| 431 | + "activestate_project_name": "fakeproject", |
| 432 | + "actor": "foo", |
| 433 | + "actor_id": "fake", |
| 434 | + }, |
| 435 | + DUMMY_ACTIVESTATE_OIDC_JWT, |
| 436 | + ), |
| 437 | + ( |
| 438 | + GitLabPublisherFactory, |
| 439 | + { |
| 440 | + "namespace": "foo", |
| 441 | + "project": "bar", |
| 442 | + "workflow_filepath": ".gitlab-ci.yml", |
| 443 | + "environment": "", |
| 444 | + }, |
| 445 | + DUMMY_GITLAB_OIDC_JWT, |
| 446 | + ), |
| 447 | + ( |
| 448 | + GooglePublisherFactory, |
| 449 | + { |
| 450 | + |
| 451 | + "sub": "111260650121185072906", |
| 452 | + }, |
| 453 | + DUMMY_GOOGLE_OIDC_JWT, |
| 454 | + ), |
| 455 | + ], |
| 456 | +) |
| 457 | +@pytest.mark.usefixtures("_enable_all_oidc_providers") |
| 458 | +def test_trusted_publisher_upload_ok( |
| 459 | + webtest, publisher_factory, publisher_data, oidc_jwt |
| 460 | +): |
| 461 | + user = UserFactory.create(with_verified_primary_email=True, clear_pwd="password") |
| 462 | + project = ProjectFactory.create(name="sampleproject") |
| 463 | + RoleFactory.create(user=user, project=project, role_name="Owner") |
| 464 | + publisher_factory.create( |
| 465 | + projects=[project], |
| 466 | + **publisher_data, |
| 467 | + ) |
| 468 | + |
| 469 | + response = webtest.post_json( |
| 470 | + "/_/oidc/mint-token", |
| 471 | + params={ |
| 472 | + "token": oidc_jwt, |
| 473 | + }, |
| 474 | + status=HTTPStatus.OK, |
| 475 | + ) |
| 476 | + |
| 477 | + assert "success" in response.json |
| 478 | + assert response.json["success"] |
| 479 | + assert "token" in response.json |
| 480 | + pypi_token = response.json["token"] |
| 481 | + assert pypi_token.startswith("pypi-") |
| 482 | + |
| 483 | + with open(_ASSETS / "sampleproject-3.0.0.tar.gz", "rb") as f: |
| 484 | + content = f.read() |
| 485 | + |
| 486 | + webtest.set_authorization(("Basic", ("__token__", pypi_token))) |
| 487 | + webtest.post( |
| 488 | + "/legacy/?:action=file_upload", |
| 489 | + params={ |
| 490 | + "name": "sampleproject", |
| 491 | + "sha256_digest": ( |
| 492 | + "117ed88e5db073bb92969a7545745fd977ee85b7019706dd256a64058f70963d" |
| 493 | + ), |
| 494 | + "filetype": "sdist", |
| 495 | + "metadata_version": "2.1", |
| 496 | + "version": "3.0.0", |
| 497 | + }, |
| 498 | + upload_files=[("content", "sampleproject-3.0.0.tar.gz", content)], |
| 499 | + status=HTTPStatus.OK, |
| 500 | + ) |
| 501 | + |
| 502 | + assert len(project.releases) == 1 |
| 503 | + release = project.releases[0] |
| 504 | + assert release.files.count() == 1 |
| 505 | + |
| 506 | + |
| 507 | +@pytest.mark.parametrize( |
| 508 | + ("publisher_factory", "publisher_data", "oidc_jwt"), |
| 509 | + [ |
| 510 | + ( |
| 511 | + GitHubPublisherFactory, |
| 512 | + { |
| 513 | + "repository_name": "wrong", |
| 514 | + "repository_owner": "foo", |
| 515 | + "repository_owner_id": "123", |
| 516 | + "workflow_filename": "example.yml", |
| 517 | + "environment": "fake", |
| 518 | + }, |
| 519 | + DUMMY_GITHUB_OIDC_JWT, |
| 520 | + ), |
| 521 | + ( |
| 522 | + ActiveStatePublisherFactory, |
| 523 | + { |
| 524 | + "organization": "wrong", |
| 525 | + "activestate_project_name": "fakeproject", |
| 526 | + "actor": "foo", |
| 527 | + "actor_id": "fake", |
| 528 | + }, |
| 529 | + DUMMY_ACTIVESTATE_OIDC_JWT, |
| 530 | + ), |
| 531 | + ( |
| 532 | + GitLabPublisherFactory, |
| 533 | + { |
| 534 | + "namespace": "wrong", |
| 535 | + "project": "bar", |
| 536 | + "workflow_filepath": ".gitlab-ci.yml", |
| 537 | + "environment": "fake", |
| 538 | + }, |
| 539 | + DUMMY_GITLAB_OIDC_JWT, |
| 540 | + ), |
| 541 | + ( |
| 542 | + GooglePublisherFactory, |
| 543 | + { |
| 544 | + |
| 545 | + "sub": "111260650121185072906", |
| 546 | + }, |
| 547 | + DUMMY_GOOGLE_OIDC_JWT, |
| 548 | + ), |
| 549 | + ], |
| 550 | +) |
| 551 | +@pytest.mark.usefixtures("_enable_all_oidc_providers") |
| 552 | +def test_trusted_publisher_upload_fails_wrong_publisher( |
| 553 | + webtest, publisher_factory, publisher_data, oidc_jwt |
| 554 | +): |
| 555 | + user = UserFactory.create(with_verified_primary_email=True, clear_pwd="password") |
| 556 | + project = ProjectFactory.create(name="sampleproject") |
| 557 | + RoleFactory.create(user=user, project=project, role_name="Owner") |
| 558 | + publisher_factory.create( |
| 559 | + projects=[project], |
| 560 | + **publisher_data, |
| 561 | + ) |
| 562 | + response = webtest.post_json( |
| 563 | + "/_/oidc/mint-token", |
| 564 | + params={ |
| 565 | + "token": oidc_jwt, |
| 566 | + }, |
| 567 | + status=HTTPStatus.UNPROCESSABLE_CONTENT, |
| 568 | + ) |
| 569 | + |
| 570 | + assert "token" not in response.json |
| 571 | + assert "message" in response.json |
| 572 | + assert response.json["message"] == "Token request failed" |
| 573 | + assert "errors" in response.json |
| 574 | + assert response.json["errors"] == [ |
| 575 | + { |
| 576 | + "code": "invalid-publisher", |
| 577 | + "description": "valid token, but no corresponding publisher " |
| 578 | + "(Publisher with matching claims was not found)", |
| 579 | + } |
| 580 | + ] |
0 commit comments