============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-9.1.1, pluggy-1.6.0 -- /venv/bin/python3
cachedir: .pytest_cache
rootdir: /builds/keystone/python/pjdev-feedback
configfile: pyproject.toml
plugins: anyio-4.15.1
collecting ... collected 130 items

tests/test_feedback.py::test_mode_a_without_require_user_refuses_to_mount PASSED [  0%]
tests/test_feedback.py::test_mode_a_unauthenticated_user_returns_401 PASSED [  1%]
tests/test_feedback.py::test_missing_project_token_returns_503 PASSED    [  2%]
tests/test_feedback.py::test_bad_cid_map_returns_400[not-json] PASSED    [  3%]
tests/test_feedback.py::test_bad_cid_map_returns_400[json-array] PASSED  [  3%]
tests/test_feedback.py::test_bad_cid_map_returns_400[json-number] PASSED [  4%]
tests/test_feedback.py::test_bad_cid_map_returns_400[json-null] PASSED   [  5%]
tests/test_feedback.py::test_bad_cid_map_returns_400[json-string] PASSED [  6%]
tests/test_feedback.py::test_non_integer_cid_map_values_return_400[numeric-string] PASSED [  6%]
tests/test_feedback.py::test_non_integer_cid_map_values_return_400[old-filename-contract] PASSED [  7%]
tests/test_feedback.py::test_non_integer_cid_map_values_return_400[json-true] PASSED [  8%]
tests/test_feedback.py::test_non_integer_cid_map_values_return_400[json-false] PASSED [  9%]
tests/test_feedback.py::test_non_integer_cid_map_values_return_400[json-float] PASSED [ 10%]
tests/test_feedback.py::test_non_integer_cid_map_values_return_400[json-null] PASSED [ 10%]
tests/test_feedback.py::test_non_integer_cid_map_values_return_400[json-array] PASSED [ 11%]
tests/test_feedback.py::test_non_integer_cid_map_values_return_400[json-object] PASSED [ 12%]
tests/test_feedback.py::test_out_of_range_cid_map_index_returns_400[-1] PASSED [ 13%]
tests/test_feedback.py::test_out_of_range_cid_map_index_returns_400[1] PASSED [ 13%]
tests/test_feedback.py::test_out_of_range_cid_map_index_returns_400[2] PASSED [ 14%]
tests/test_feedback.py::test_out_of_range_cid_map_index_returns_400[99] PASSED [ 15%]
tests/test_feedback.py::test_cid_map_with_no_files_returns_400 PASSED    [ 16%]
tests/test_feedback.py::test_malformed_cid_keys_return_400[empty] PASSED [ 16%]
tests/test_feedback.py::test_malformed_cid_keys_return_400[over-64-chars] PASSED [ 17%]
tests/test_feedback.py::test_malformed_cid_keys_return_400[space] PASSED [ 18%]
tests/test_feedback.py::test_malformed_cid_keys_return_400[slash] PASSED [ 19%]
tests/test_feedback.py::test_malformed_cid_keys_return_400[non-ascii] PASSED [ 20%]
tests/test_feedback.py::test_a_cid_of_exactly_64_characters_is_accepted PASSED [ 20%]
tests/test_feedback.py::test_a_part_with_no_filename_returns_400 PASSED  [ 21%]
tests/test_feedback.py::test_a_stale_client_is_told_to_reload_not_told_its_values_are_wrong PASSED [ 22%]
tests/test_feedback.py::test_request_type_is_off_by_default PASSED       [ 23%]
tests/test_feedback.py::test_missing_request_type_returns_400_once_configured PASSED [ 23%]
tests/test_feedback.py::test_unknown_request_type_returns_400 PASSED     [ 24%]
tests/test_feedback.py::test_each_default_request_type_labels_and_heads_the_issue[bug-request::bug-Something isn't working] PASSED [ 25%]
tests/test_feedback.py::test_each_default_request_type_labels_and_heads_the_issue[how-to-request::how-to-I need help using the app] PASSED [ 26%]
tests/test_feedback.py::test_each_default_request_type_labels_and_heads_the_issue[access-request::access-I need access to a system] PASSED [ 26%]
tests/test_feedback.py::test_each_default_request_type_labels_and_heads_the_issue[idea-request::idea-I have an idea or suggestion] PASSED [ 27%]
tests/test_feedback.py::test_custom_request_types_replace_the_defaults PASSED [ 28%]
tests/test_feedback.py::test_request_type_can_be_offered_without_being_required PASSED [ 29%]
tests/test_feedback.py::test_duplicate_request_type_values_refuse_to_mount PASSED [ 30%]
tests/test_feedback.py::test_request_type_label_is_not_duplicated PASSED [ 30%]
tests/test_feedback.py::test_request_type_heading_precedes_an_escaped_body PASSED [ 31%]
tests/test_feedback.py::test_too_many_file_parts_returns_400 PASSED      [ 32%]
tests/test_feedback.py::test_too_many_cid_references_returns_400 PASSED  [ 33%]
tests/test_feedback.py::test_over_cap_is_a_400_not_a_413 PASSED          [ 33%]
tests/test_feedback.py::test_an_unreferenced_part_still_counts_toward_the_file_cap PASSED [ 34%]
tests/test_feedback.py::test_count_caps_run_before_per_entry_validation PASSED [ 35%]
tests/test_feedback.py::test_total_bytes_cap_returns_413 PASSED          [ 36%]
tests/test_feedback.py::test_gitlab_413_passthrough PASSED               [ 36%]
tests/test_feedback.py::test_non_413_gitlab_errors_map_to_502[401] PASSED [ 37%]
tests/test_feedback.py::test_non_413_gitlab_errors_map_to_502[403] PASSED [ 38%]
tests/test_feedback.py::test_non_413_gitlab_errors_map_to_502[404] PASSED [ 39%]
tests/test_feedback.py::test_non_413_gitlab_errors_map_to_502[500] PASSED [ 40%]
tests/test_feedback.py::test_http_error_message_wording[401-GitLab rejected the request (401)] PASSED [ 40%]
tests/test_feedback.py::test_http_error_message_wording[403-GitLab rejected the request (403)] PASSED [ 41%]
tests/test_feedback.py::test_http_error_message_wording[404-GitLab project not found] PASSED [ 42%]
tests/test_feedback.py::test_http_error_message_wording[413-too large] PASSED [ 43%]
tests/test_feedback.py::test_http_error_message_wording[500-GitLab returned 500] PASSED [ 43%]
tests/test_feedback.py::test_happy_path_substitutes_cid PASSED           [ 44%]
tests/test_feedback.py::test_duplicate_display_filenames_upload_distinct_content PASSED [ 45%]
tests/test_feedback.py::test_one_file_embedded_twice_is_uploaded_once_and_every_cid_resolves PASSED [ 46%]
tests/test_feedback.py::test_one_file_embedded_twice_is_charged_once_against_the_byte_cap PASSED [ 46%]
tests/test_feedback.py::test_an_unreferenced_part_is_accepted_and_not_uploaded PASSED [ 47%]
tests/test_feedback.py::test_multiple_referenced_files_upload_with_their_display_names PASSED [ 48%]
tests/test_feedback.py::test_mode_b_injects_bearer_client PASSED         [ 49%]
tests/test_feedback.py::test_mode_b_unresolved_token_returns_401 PASSED  [ 50%]
tests/test_feedback.py::test_turnkey_oauth_full_flow PASSED              [ 50%]
tests/test_feedback.py::test_cross_site_requests_rejected PASSED         [ 51%]
tests/test_feedback.py::test_app_csrf_dependency_is_enforced PASSED      [ 52%]
tests/test_feedback.py::test_turnkey_oauth_callback_bad_state_returns_400 PASSED [ 53%]
tests/test_feedback.py::test_mounting_initializes_the_gitlab_sdk_global PASSED [ 53%]
tests/test_feedback.py::test_existing_sdk_config_is_not_clobbered PASSED [ 54%]
tests/test_feedback.py::test_reporter_footer_falls_back_to_username PASSED [ 55%]
tests/test_feedback.py::test_display_name_still_wins_over_username PASSED [ 56%]
tests/test_feedback.py::test_reporter_identity_cannot_inject_markdown PASSED [ 56%]
tests/test_feedback.py::test_ordinary_identities_are_left_readable PASSED [ 57%]
tests/test_feedback.py::test_escape_quick_actions[/close-\\/close] PASSED [ 58%]
tests/test_feedback.py::test_escape_quick_actions[/confidential-\\/confidential] PASSED [ 59%]
tests/test_feedback.py::test_escape_quick_actions[/move group/other-\\/move group/other] PASSED [ 60%]
tests/test_feedback.py::test_escape_quick_actions[/create_merge_request evil-branch-\\/create_merge_request evil-branch] PASSED [ 60%]
tests/test_feedback.py::test_escape_quick_actions[Search is broken.\n/close\nThanks!-Search is broken.\n\\/close\nThanks!] PASSED [ 61%]
tests/test_feedback.py::test_escape_quick_actions[Broken.\r\n/close\r\n-Broken.\r\n\\/close\r\n] PASSED [ 62%]
tests/test_feedback.py::test_escape_quick_actions[  /close-  /close] PASSED [ 63%]
tests/test_feedback.py::test_escape_quick_actions[see /docs/setup for repro-see /docs/setup for repro] PASSED [ 63%]
tests/test_feedback.py::test_escape_quick_actions[/ 2 of the pages-/ 2 of the pages] PASSED [ 64%]
tests/test_feedback.py::test_escape_quick_actions[-] PASSED              [ 65%]
tests/test_feedback.py::test_escape_quick_actions_leaves_fenced_code_alone PASSED [ 66%]
tests/test_feedback.py::test_quick_actions_in_description_are_neutralized PASSED [ 66%]
tests/test_feedback.py::test_app_version_is_recorded_in_the_footer PASSED [ 67%]
tests/test_feedback.py::test_app_version_is_recorded_without_a_reporter PASSED [ 68%]
tests/test_feedback.py::test_no_footer_at_all_when_there_is_nothing_to_say PASSED [ 69%]
tests/test_feedback.py::test_page_url_is_ignored_unless_the_app_asks_for_it PASSED [ 70%]
tests/test_feedback.py::test_page_url_lands_in_the_footer_when_enabled PASSED [ 70%]
tests/test_feedback.py::test_hostile_page_urls_are_dropped[javascript:alert(document.cookie)] PASSED [ 71%]
tests/test_feedback.py::test_hostile_page_urls_are_dropped[JavaScript:alert(1)] PASSED [ 72%]
tests/test_feedback.py::test_hostile_page_urls_are_dropped[data:text/html;base64,PHNjcmlwdD4=] PASSED [ 73%]
tests/test_feedback.py::test_hostile_page_urls_are_dropped[not a url] PASSED [ 73%]
tests/test_feedback.py::test_hostile_page_urls_are_dropped[] PASSED      [ 74%]
tests/test_feedback.py::test_hostile_page_urls_are_dropped[https://app.example.com/>](http://evil.test)] PASSED [ 75%]
tests/test_feedback.py::test_hostile_page_urls_are_dropped[https://app.example.com/<script>] PASSED [ 76%]
tests/test_feedback.py::test_hostile_page_urls_are_dropped[https://app.example.com/`x`] PASSED [ 76%]
tests/test_feedback.py::test_page_url_cannot_inject_markdown_lines PASSED [ 77%]
tests/test_feedback.py::test_an_over_long_page_url_is_refused_by_the_form_field PASSED [ 78%]
tests/test_feedback.py::test_a_sha_like_version_is_not_left_for_gitlab_to_autolink PASSED [ 79%]
tests/test_feedback.py::test_append_footer_shapes[None-None-Body] PASSED [ 80%]
tests/test_feedback.py::test_append_footer_shapes[None-2.0.6-Body\n\n---\nApp version: `2.0.6`\n] PASSED [ 80%]
tests/test_feedback.py::test_append_footer_shapes[None--Body] PASSED     [ 81%]
tests/test_feedback.py::test_reporter_footer_cannot_be_escaped_into_a_command PASSED [ 82%]
tests/test_feedback.py::test_misconfiguration_message_names_the_missing_field[overrides0-project_token-project_id] PASSED [ 83%]
tests/test_feedback.py::test_misconfiguration_message_names_the_missing_field[overrides1-project_id-project_token] PASSED [ 83%]
tests/test_feedback.py::test_a_configured_sink_receives_the_parsed_submission PASSED [ 84%]
tests/test_feedback.py::test_a_configured_sink_answers_202_with_its_own_id PASSED [ 85%]
tests/test_feedback.py::test_without_a_sink_the_inline_path_still_answers_201 PASSED [ 86%]
tests/test_feedback.py::test_validation_rejections_never_reach_the_sink[malformed-cid-map] PASSED [ 86%]
tests/test_feedback.py::test_validation_rejections_never_reach_the_sink[out-of-range-index] PASSED [ 87%]
tests/test_feedback.py::test_validation_rejections_never_reach_the_sink[stale-client] PASSED [ 88%]
tests/test_feedback.py::test_validation_rejections_never_reach_the_sink[unknown-request-type] PASSED [ 89%]
tests/test_feedback.py::test_validation_rejections_never_reach_the_sink[over-the-file-cap] PASSED [ 90%]
tests/test_feedback.py::test_the_sink_receives_the_raw_auth_user_not_just_the_reporter PASSED [ 90%]
tests/test_feedback.py::test_the_sink_receives_a_quick_action_escaped_body PASSED [ 91%]
tests/test_feedback.py::test_escaping_a_body_twice_changes_nothing[leading-quick-action] PASSED [ 92%]
tests/test_feedback.py::test_escaping_a_body_twice_changes_nothing[nothing-to-escape] PASSED [ 93%]
tests/test_feedback.py::test_escaping_a_body_twice_changes_nothing[fenced-code] PASSED [ 93%]
tests/test_feedback.py::test_openapi_advertises_202_and_the_queued_model_when_a_sink_is_set PASSED [ 94%]
tests/test_feedback.py::test_openapi_advertises_201_and_the_issue_model_without_a_sink PASSED [ 95%]
tests/test_feedback.py::test_a_sink_deployment_never_calls_gitlab PASSED [ 96%]
tests/test_feedback.py::test_the_sinks_http_exception_reaches_the_client_unchanged PASSED [ 96%]
tests/test_feedback.py::test_a_sink_is_refused_in_oauth_mode PASSED      [ 97%]
tests/test_feedback.py::test_a_sink_sees_no_page_url_unless_the_app_asks_for_it PASSED [ 98%]
tests/test_feedback.py::test_mounting_with_a_sink_does_not_initialize_the_gitlab_sdk_global PASSED [ 99%]
tests/test_feedback.py::test_an_unreferenced_part_still_reaches_the_sink_in_wire_order PASSED [100%]

============================= 130 passed in 1.81s ==============================
