Example #1
0
def test_legacy_swhid_browse(archive_data, client, origin):
    snapshot = archive_data.snapshot_get_latest(origin["url"])
    revision = archive_data.snapshot_get_head(snapshot)
    directory = archive_data.revision_get(revision)["directory"]
    directory_content = archive_data.directory_ls(directory)
    directory_file = random.choice(
        [e for e in directory_content if e["type"] == "file"])
    legacy_swhid = gen_swhid(
        CONTENT,
        directory_file["checksums"]["sha1_git"],
        metadata={"origin": origin["url"]},
    )

    url = reverse("browse-swhid", url_args={"swhid": legacy_swhid})

    resp = check_html_get_response(client, url, status_code=302)
    resp = check_html_get_response(client,
                                   resp["location"],
                                   status_code=200,
                                   template_used="browse/content.html")

    swhid = gen_swhid(
        CONTENT,
        directory_file["checksums"]["sha1_git"],
        metadata={
            "origin": origin["url"],
            "visit": gen_swhid(SNAPSHOT, snapshot["id"]),
            "anchor": gen_swhid(REVISION, revision),
        },
    )

    assert_contains(resp, swhid)
Example #2
0
def test_origin_snapshot_invalid_branch(
    client, archive_data, new_origin, new_snapshot, visit_dates, revisions
):
    snp_dict = new_snapshot.to_dict()
    archive_data.origin_add([new_origin])
    for i, branch in enumerate(snp_dict["branches"].keys()):
        snp_dict["branches"][branch] = {
            "target_type": "revision",
            "target": hash_to_bytes(revisions[i]),
        }

    archive_data.snapshot_add([Snapshot.from_dict(snp_dict)])
    visit = archive_data.origin_visit_add(
        [OriginVisit(origin=new_origin.url, date=visit_dates[0], type="git",)]
    )[0]
    visit_status = OriginVisitStatus(
        origin=new_origin.url,
        visit=visit.visit,
        date=now(),
        status="full",
        snapshot=snp_dict["id"],
    )
    archive_data.origin_visit_status_add([visit_status])

    url = reverse(
        "browse-origin-directory",
        query_params={"origin_url": new_origin.url, "branch": "invalid_branch"},
    )

    check_html_get_response(client, url, status_code=404, template_used="error.html")
Example #3
0
def test_revision_request_errors(client, revision, unknown_revision,
                                 new_origin):
    url = reverse("browse-revision", url_args={"sha1_git": unknown_revision})

    resp = check_html_get_response(client,
                                   url,
                                   status_code=404,
                                   template_used="error.html")
    assert_contains(resp,
                    "Revision with sha1_git %s not found" % unknown_revision,
                    status_code=404)

    url = reverse(
        "browse-revision",
        url_args={"sha1_git": revision},
        query_params={"origin_url": new_origin.url},
    )

    resp = check_html_get_response(client,
                                   url,
                                   status_code=404,
                                   template_used="error.html")
    assert_contains(resp, "the origin mentioned in your request"
                    " appears broken",
                    status_code=404)
Example #4
0
def test_apidoc_post_only(client):
    # a dedicated view accepting GET requests should have
    # been created to display the HTML documentation
    url = reverse("api-1-test-post-only-doc")
    check_html_get_response(client,
                            url,
                            status_code=200,
                            template_used="api/apidoc.html")
Example #5
0
def test_oidc_login_views_success(client, keycloak_mock):
    """
    Simulate a successful login authentication with OpenID Connect
    authorization code flow with PKCE.
    """
    # user initiates login process
    login_url = reverse("oidc-login")

    # should redirect to Keycloak authentication page in order
    # for a user to login with its username / password
    response = check_html_get_response(client, login_url, status_code=302)
    request = response.wsgi_request

    assert isinstance(request.user, AnonymousUser)

    login_data = _check_oidc_login_code_flow_data(
        request,
        response,
        keycloak_mock,
        redirect_uri=reverse("oidc-login-complete", request=request),
    )

    # once a user has identified himself in Keycloak, he is
    # redirected to the 'oidc-login-complete' view to
    # login in Django.

    # generate authorization code / session state in the same
    # manner as Keycloak
    code = f"{str(uuid.uuid4())}.{str(uuid.uuid4())}.{str(uuid.uuid4())}"
    session_state = str(uuid.uuid4())

    login_complete_url = reverse(
        "oidc-login-complete",
        query_params={
            "code": code,
            "state": login_data["state"],
            "session_state": session_state,
        },
    )

    # login process finalization, should redirect to root url by default
    response = check_html_get_response(client,
                                       login_complete_url,
                                       status_code=302)
    request = response.wsgi_request

    assert response["location"] == request.build_absolute_uri("/")

    # user should be authenticated
    assert isinstance(request.user, OIDCUser)

    # check remote user has not been saved to Django database
    with pytest.raises(User.DoesNotExist):
        User.objects.get(username=request.user.username)
Example #6
0
def test_content_request_errors(client, invalid_sha1, unknown_content):
    url = reverse("browse-content", url_args={"query_string": invalid_sha1})
    check_html_get_response(client,
                            url,
                            status_code=400,
                            template_used="error.html")

    url = reverse("browse-content",
                  url_args={"query_string": unknown_content["sha1"]})
    check_html_get_response(client,
                            url,
                            status_code=404,
                            template_used="browse/content.html")
Example #7
0
def test_pull_request_branches_filtering(client, origin):
    # check no pull request branches are displayed in the Branches / Releases dropdown
    url = reverse("browse-origin-directory", query_params={"origin_url": origin.url})
    resp = check_html_get_response(
        client, url, status_code=200, template_used="browse/directory.html"
    )
    assert_not_contains(resp, "refs/pull/")

    # check no pull request branches are displayed in the branches view
    url = reverse("browse-origin-branches", query_params={"origin_url": origin.url})
    resp = check_html_get_response(
        client, url, status_code=200, template_used="browse/branches.html"
    )
    assert_not_contains(resp, "refs/pull/")
Example #8
0
def test_directory_request_errors(client, invalid_sha1, unknown_directory):
    dir_url = reverse("browse-directory", url_args={"sha1_git": invalid_sha1})

    check_html_get_response(client,
                            dir_url,
                            status_code=400,
                            template_used="error.html")

    dir_url = reverse("browse-directory",
                      url_args={"sha1_git": unknown_directory})

    check_html_get_response(client,
                            dir_url,
                            status_code=404,
                            template_used="error.html")
Example #9
0
def test_content_bytes_missing(client, archive_data, mocker, content):
    mock_archive = mocker.patch("swh.web.browse.utils.archive")
    content_data = archive_data.content_get(content["sha1"])

    mock_archive.lookup_content.return_value = content_data
    mock_archive.lookup_content_filetype.side_effect = Exception()
    mock_archive.lookup_content_raw.side_effect = NotFoundExc(
        "Content bytes not available!")

    url = reverse("browse-content", url_args={"query_string": content["sha1"]})

    check_html_get_response(client,
                            url,
                            status_code=404,
                            template_used="browse/content.html")
Example #10
0
def test_apidoc_with_links(client):
    url = reverse("api-1-endpoint-links-in-doc")
    rv = check_html_get_response(client,
                                 url,
                                 status_code=200,
                                 template_used="api/apidoc.html")

    html = prettify_html(rv.content)

    first_link = textwrap.indent(
        ('<a class="reference external" href="/api/1/content/doc/">\n'
         " /api/1/content/\n"
         "</a>"),
        " " * 9,
    )

    second_link = textwrap.indent(
        ('<a class="reference external" href="/api/1/directory/doc/">\n'
         " /api/1/directory/\n"
         "</a>"),
        " " * 9,
    )

    third_link = textwrap.indent(
        ('<a class="reference external" '
         'href="https://archive.softwareheritage.org">\n'
         " archive\n"
         "</a>"),
        " " * 9,
    )

    assert first_link in html
    assert second_link in html
    assert third_link in html
Example #11
0
def test_content_id_optional_parts_browse(client, archive_data, content):
    cnt_sha1_git = content["sha1_git"]
    origin_url = "https://github.com/user/repo"

    archive_data.origin_add([Origin(url=origin_url)])

    swhid = gen_swhid(
        CONTENT,
        cnt_sha1_git,
        metadata={
            "lines": "4-20",
            "origin": origin_url
        },
    )
    url = reverse("browse-swhid", url_args={"swhid": swhid})

    query_string = "sha1_git:" + cnt_sha1_git
    content_browse_url = reverse(
        "browse-content",
        url_args={"query_string": query_string},
        query_params={"origin_url": origin_url},
    )
    content_browse_url += "#L4-L20"

    resp = check_html_get_response(client, url, status_code=302)
    assert resp["location"] == content_browse_url
Example #12
0
def test_oidc_login_complete_wrong_code_verifier(client, keycloak_mock):
    keycloak_mock.set_auth_success(False)

    # simulate login process has been initialized
    session = client.session
    session["login_data"] = {
        "code_verifier": "",
        "state": str(uuid.uuid4()),
        "redirect_uri": "",
        "next_path": "",
    }
    session.save()

    # check authentication error is reported
    login_url = reverse(
        "oidc-login-complete",
        query_params={
            "code": "some-code",
            "state": session["login_data"]["state"]
        },
    )

    # should render an error page
    response = check_html_get_response(client,
                                       login_url,
                                       status_code=500,
                                       template_used="error.html")
    request = response.wsgi_request
    assert_contains(response, "User authentication failed.", status_code=500)

    # no user should be logged in
    assert isinstance(request.user, AnonymousUser)
Example #13
0
def test_oidc_login_complete_wrong_csrf_token(client, keycloak_mock):
    # simulate login process has been initialized
    session = client.session
    session["login_data"] = {
        "code_verifier": "",
        "state": str(uuid.uuid4()),
        "redirect_uri": "",
        "next_path": "",
    }
    session.save()

    # user initiates login process
    login_url = reverse("oidc-login-complete",
                        query_params={
                            "code": "some-code",
                            "state": "some-state"
                        })

    # should render an error page
    response = check_html_get_response(client,
                                       login_url,
                                       status_code=400,
                                       template_used="error.html")
    request = response.wsgi_request
    assert_contains(response,
                    "Wrong CSRF token, aborting login process.",
                    status_code=400)

    # no user should be logged in
    assert isinstance(request.user, AnonymousUser)
Example #14
0
def test_oidc_login_complete_view_missing_parameters(client, mocker):
    # simulate login process has been initialized
    session = client.session
    session["login_data"] = {
        "code_verifier": "",
        "state": str(uuid.uuid4()),
        "redirect_uri": "",
        "next_path": "",
    }
    session.save()

    # user initiates login process
    login_url = reverse("oidc-login-complete")
    # should render an error page
    response = check_html_get_response(client,
                                       login_url,
                                       status_code=400,
                                       template_used="error.html")
    request = response.wsgi_request
    assert_contains(response,
                    "Missing query parameters for authentication.",
                    status_code=400)

    # no user should be logged in
    assert isinstance(request.user, AnonymousUser)
Example #15
0
def test_oidc_logout_view_success(client, keycloak_mock):
    """
    Simulate a successful logout operation with OpenID Connect.
    """
    # login our test user
    client.login(code="", code_verifier="", redirect_uri="")
    keycloak_mock.authorization_code.assert_called()

    # user initiates logout
    oidc_logout_url = reverse("oidc-logout")

    # should redirect to logout page
    response = check_html_get_response(client,
                                       oidc_logout_url,
                                       status_code=302)
    request = response.wsgi_request

    logout_url = reverse("logout", query_params={"remote_user": 1})
    assert response["location"] == request.build_absolute_uri(logout_url)

    # should have been logged out in Keycloak
    oidc_profile = keycloak_mock.login()
    keycloak_mock.logout.assert_called_with(oidc_profile["refresh_token"])

    # check effective logout in Django
    assert isinstance(request.user, AnonymousUser)
Example #16
0
def test_content_view_text(client, archive_data, content):
    sha1_git = content["sha1_git"]

    url = reverse(
        "browse-content",
        url_args={"query_string": content["sha1"]},
        query_params={"path": content["path"]},
    )

    url_raw = reverse("browse-content-raw",
                      url_args={"query_string": content["sha1"]})

    resp = check_html_get_response(client,
                                   url,
                                   status_code=200,
                                   template_used="browse/content.html")

    content_display = _process_content_for_display(archive_data, content)
    mimetype = content_display["mimetype"]

    if mimetype.startswith("text/"):
        assert_contains(resp,
                        '<code class="%s">' % content_display["language"])
        assert_contains(resp, escape(content_display["content_data"]))
    assert_contains(resp, url_raw)

    swh_cnt_id = gen_swhid(CONTENT, sha1_git)
    swh_cnt_id_url = reverse("browse-swhid", url_args={"swhid": swh_cnt_id})
    assert_contains(resp, swh_cnt_id)
    assert_contains(resp, swh_cnt_id_url)
    assert_not_contains(resp, "swh-metadata-popover")
Example #17
0
def test_origin_empty_snapshot_null_revision(client, archive_data, new_origin):
    snapshot = Snapshot(
        branches={
            b"HEAD": SnapshotBranch(
                target="refs/head/master".encode(), target_type=TargetType.ALIAS,
            ),
            b"refs/head/master": None,
        }
    )
    archive_data.origin_add([new_origin])
    archive_data.snapshot_add([snapshot])
    visit = archive_data.origin_visit_add(
        [OriginVisit(origin=new_origin.url, date=now(), type="git",)]
    )[0]
    visit_status = OriginVisitStatus(
        origin=new_origin.url,
        visit=visit.visit,
        date=now(),
        status="partial",
        snapshot=snapshot.id,
    )
    archive_data.origin_visit_status_add([visit_status])

    url = reverse(
        "browse-origin-directory", query_params={"origin_url": new_origin.url},
    )

    resp = check_html_get_response(
        client, url, status_code=200, template_used="browse/directory.html"
    )
    resp_content = resp.content.decode("utf-8")
    assert re.search("snapshot.*is empty", resp_content)
    assert not re.search("swh-tr-link", resp_content)
Example #18
0
def test_oidc_session_expired_middleware_disabled(client, keycloak_mock):
    # authenticate user

    client.login(code="", code_verifier="", redirect_uri="")
    keycloak_mock.authorization_code.assert_called()

    url = reverse("swh-web-homepage")

    # visit url first to get user from response
    response = check_html_get_response(client, url, status_code=200)

    # simulate OIDC session expiration
    cache.delete(f"oidc_user_{response.wsgi_request.user.id}")

    # no redirection when session has expired
    check_html_get_response(client, url, status_code=200)
Example #19
0
def test_origin_release_browse(client, archive_data, origin):
    snapshot = archive_data.snapshot_get_latest(origin["url"])
    release = [
        b for b in snapshot["branches"].values() if b["target_type"] == "release"
    ][-1]
    release_data = archive_data.release_get(release["target"])
    revision_data = archive_data.revision_get(release_data["target"])
    url = reverse(
        "browse-origin-directory",
        query_params={"origin_url": origin["url"], "release": release_data["name"]},
    )

    resp = check_html_get_response(
        client, url, status_code=200, template_used="browse/directory.html"
    )
    assert_contains(resp, release_data["name"])
    assert_contains(resp, release["target"])

    swhid_context = {
        "origin": origin["url"],
        "visit": gen_swhid(SNAPSHOT, snapshot["id"]),
        "anchor": gen_swhid(RELEASE, release_data["id"]),
    }

    swh_dir_id = gen_swhid(
        DIRECTORY, revision_data["directory"], metadata=swhid_context
    )
    swh_dir_id_url = reverse("browse-swhid", url_args={"swhid": swh_dir_id})
    assert_contains(resp, swh_dir_id)
    assert_contains(resp, swh_dir_id_url)
Example #20
0
def test_browse_origin_content_directory_empty_snapshot(client, mocker, origin):
    mock_snapshot_archive = mocker.patch("swh.web.browse.snapshot_context.archive")
    mock_get_origin_visit_snapshot = mocker.patch(
        "swh.web.browse.snapshot_context.get_origin_visit_snapshot"
    )
    mock_get_origin_visit_snapshot.return_value = ([], [], {})
    mock_snapshot_archive.lookup_origin.return_value = origin
    mock_snapshot_archive.lookup_snapshot_sizes.return_value = {
        "alias": 0,
        "revision": 0,
        "release": 0,
    }

    for browse_context in ("content", "directory"):
        url = reverse(
            f"browse-origin-{browse_context}",
            query_params={"origin_url": origin["url"], "path": "baz"},
        )

        resp = check_html_get_response(
            client, url, status_code=200, template_used=f"browse/{browse_context}.html"
        )
        assert re.search("snapshot.*is empty", resp.content.decode("utf-8"))
        assert mock_get_origin_visit_snapshot.called
        assert mock_snapshot_archive.lookup_origin.called
        assert mock_snapshot_archive.lookup_snapshot_sizes.called
Example #21
0
def test_revision_metadata_display(archive_data, client, directory, person,
                                   date):
    metadata = {"foo": "bar"}
    revision = Revision(
        directory=hash_to_bytes(directory),
        author=person,
        committer=person,
        message=b"commit message",
        date=TimestampWithTimezone.from_datetime(date),
        committer_date=TimestampWithTimezone.from_datetime(date),
        synthetic=False,
        type=RevisionType.GIT,
        metadata=metadata,
    )
    archive_data.revision_add([revision])

    url = reverse("browse-revision",
                  url_args={"sha1_git": hash_to_hex(revision.id)})

    resp = check_html_get_response(client,
                                   url,
                                   status_code=200,
                                   template_used="browse/revision.html")
    assert_contains(resp, "swh-metadata-popover")
    assert_contains(resp, escape(json.dumps(metadata, indent=4)))
Example #22
0
def test_release_browse_not_found(client, archive_data, unknown_release):
    url = reverse("browse-release", url_args={"sha1_git": unknown_release})

    resp = check_html_get_response(
        client, url, status_code=404, template_used="error.html"
    )
    err_msg = "Release with sha1_git %s not found" % unknown_release
    assert_contains(resp, err_msg, status_code=404)
Example #23
0
def _generate_and_test_bearer_token(client, kc_oidc_mock):
    # user authenticates
    client.login(code="code",
                 code_verifier="code-verifier",
                 redirect_uri="redirect-uri")
    # user initiates bearer token generation flow
    url = reverse("oidc-generate-bearer-token")
    response = check_http_get_response(client, url, status_code=302)
    request = response.wsgi_request
    redirect_uri = reverse("oidc-generate-bearer-token-complete",
                           request=request)
    # check login data and redirection to Keycloak is valid
    login_data = _check_oidc_login_code_flow_data(
        request,
        response,
        kc_oidc_mock,
        redirect_uri=redirect_uri,
        scope="openid offline_access",
    )

    # once a user has identified himself in Keycloak, he is
    # redirected to the 'oidc-generate-bearer-token-complete' view
    # to get and save bearer token

    # generate authorization code / session state in the same
    # manner as Keycloak
    code = f"{str(uuid.uuid4())}.{str(uuid.uuid4())}.{str(uuid.uuid4())}"
    session_state = str(uuid.uuid4())

    token_complete_url = reverse(
        "oidc-generate-bearer-token-complete",
        query_params={
            "code": code,
            "state": login_data["state"],
            "session_state": session_state,
        },
    )

    nb_tokens = len(OIDCUserOfflineTokens.objects.all())
    response = check_html_get_response(client,
                                       token_complete_url,
                                       status_code=302)
    request = response.wsgi_request

    # check token has been generated and saved encrypted to database
    assert len(OIDCUserOfflineTokens.objects.all()) == nb_tokens + 1
    encrypted_token = OIDCUserOfflineTokens.objects.last().offline_token
    secret = get_config()["secret_key"].encode()
    salt = request.user.sub.encode()
    decrypted_token = decrypt_data(encrypted_token, secret, salt)
    oidc_profile = kc_oidc_mock.authorization_code(code=code,
                                                   redirect_uri=redirect_uri)
    assert decrypted_token.decode("ascii") == oidc_profile["refresh_token"]

    # should redirect to tokens management Web UI
    assert response["location"] == reverse("oidc-profile") + "#tokens"

    return decrypted_token
Example #24
0
def test_oidc_profile_view_anonymous_user(client):
    """
    Non authenticated users should be redirected to login page when
    requesting profile view.
    """
    url = reverse("oidc-profile")
    login_url = reverse("oidc-login", query_params={"next_path": url})
    resp = check_html_get_response(client, url, status_code=302)
    assert resp["location"] == login_url
Example #25
0
def test_origin_content_no_path(client, origin):
    url = reverse("browse-origin-content", query_params={"origin_url": origin["url"]})

    resp = check_html_get_response(
        client, url, status_code=400, template_used="error.html"
    )
    assert_contains(
        resp, "The path of a content must be given as query parameter.", status_code=400
    )
Example #26
0
def test_browse_visits_origin_not_found(client, new_origin):
    url = reverse("browse-origin-visits", query_params={"origin_url": new_origin.url})

    resp = check_html_get_response(
        client, url, status_code=404, template_used="error.html"
    )
    assert_contains(
        resp, f"Origin with url {new_origin.url} not found", status_code=404
    )
Example #27
0
def test_directory_id_browse(client, directory):
    swhid = gen_swhid(DIRECTORY, directory)
    url = reverse("browse-swhid", url_args={"swhid": swhid})

    directory_browse_url = reverse("browse-directory",
                                   url_args={"sha1_git": directory})

    resp = check_html_get_response(client, url, status_code=302)
    assert resp["location"] == directory_browse_url
Example #28
0
def test_revision_uppercase(client, revision):
    url = reverse("browse-revision-uppercase-checksum",
                  url_args={"sha1_git": revision.upper()})

    resp = check_html_get_response(client, url, status_code=302)

    redirect_url = reverse("browse-revision", url_args={"sha1_git": revision})

    assert resp["location"] == redirect_url
Example #29
0
def test_browse_origin_content_not_found(client, origin):
    url = reverse(
        "browse-origin-content",
        query_params={"origin_url": origin["url"], "path": "/invalid/file/path"},
    )

    resp = check_html_get_response(
        client, url, status_code=404, template_used="browse/content.html"
    )
    assert re.search("Directory entry.*not found", resp.content.decode("utf-8"))
Example #30
0
def test_directory_uppercase(client, directory):
    url = reverse("browse-directory-uppercase-checksum",
                  url_args={"sha1_git": directory.upper()})

    resp = check_html_get_response(client, url, status_code=302)

    redirect_url = reverse("browse-directory",
                           url_args={"sha1_git": directory})

    assert resp["location"] == redirect_url