fix(scripts): return None from get_docx_document on missing template#2546
fix(scripts): return None from get_docx_document on missing template#2546immortal71 wants to merge 17 commits intoOWASP:masterfrom
Conversation
When the template .docx file does not exist, get_docx_document() was returning a blank docx.Document() which is always truthy in Python. This caused create_edition_from_template() to silently write an empty output file because the if doc: guard always evaluated to True. Changes: - get_docx_document(): return None instead of docx.Document() on missing file; update docstring accordingly - create_edition_from_template(): change if doc: to if doc is not None: for explicitness; add else branch that logs an error and returns early to prevent writing empty output files - test_get_docx_document_failure: update assertion to assertIsNone - Add test_create_edition_from_template_docx_none_doc_returns_early to cover the new else branch and ensure no file is saved Fixes OWASP#2490
- Apply black --line-length=120 formatting to convert_utest.py - Update get_docx_document() return type from Any to Optional[Any] to accurately reflect that None is returned on missing file - Add Optional to typing imports
Add targeted tests covering previously uncovered branches in convert.py: - TestValidateFilePaths: source not found, output dir not found, source/output outside base path, valid paths (lines 62, 69-86) - TestValidateCommandArgs: dangerous chars trigger warning + False, pipe char, valid args (lines 116-121) - TestConvertWithLibreOffice: libreoffice not found, invalid paths, subprocess.TimeoutExpired, generic exception (lines 134-174) - TestConvertWithDocx2pdf: not docx, can_convert=False, exception path with warning (lines 179-186) - TestCleanupTempFile: file removed, debug skip, OSError swallowed (lines 214-219) - TestRenameLibreofficeOutput: same path, different path rename (lines 234-236) - TestConvertToPdfDocx2pdfPath: covers convert_to_pdf docx2pdf success branch calling _cleanup_temp_file (lines 240-241) - TestIsValidStringArgumentErrors: too-long arg, invalid chars (lines 525, 530) - TestGetDocumentParagraphsEmpty: empty doc logs error (line 551) - TestGetMetaData.test_get_meta_data_meta_not_dict: meta not dict (lines 694-695) - TestMapLanguageDataToTemplate: exception fallback + debug mode debug log output (lines 782-792) - TestGetLanguageDataErrors: yaml parse error, missing meta key (lines 742-748) - TestGetMappingForEditionException: build_template_dict exception logs warning (lines 613-614) Result: scripts/convert.py 81% -> 92%, total 85% -> 91%
- player_live_test: add :index action test (apply_action :index path) - create_game_form_test: add submit-with-empty-name test to cover save_game(:new) changeset error branch - game_live/show_test: add last_version/display_game_session fallback cases to cover mlsec, eop, cumulus, masvs, unknown branches - player_live/show_test: add last_round? true/false unit assertions - form_component_test: add FormComponent.topic/1 unit test
…layer-not-found tests to close coverage gap
There was a problem hiding this comment.
Pull request overview
This PR fixes a bug in get_docx_document() where a blank docx.Document() was returned instead of None when a template file was not found, causing create_edition_from_template() to silently write empty output files. The fix also adds an explicit else branch with error logging and early return. Beyond the core fix, the PR includes substantial additional test coverage across both the Python and Elixir codebases, and minor CI workflow adjustments.
Changes:
- Fixed
get_docx_document()to returnNoneon missing template and updatedcreate_edition_from_template()to handleNonewith error logging and early return - Added extensive test coverage: new Python test classes for file path validation, command args validation, LibreOffice/docx2pdf conversion, cleanup, and various edge cases; new Elixir tests for game logic, player interactions, rate limiting, IP handling, and controller endpoints
- Modified CI workflow to remove unnecessary
repositoryparameter and redundant checkout step
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
scripts/convert.py |
Core fix: return None from get_docx_document(), add if doc is not None: guard with error logging, add Optional import |
tests/scripts/convert_utest.py |
Updated failure test to assert None, added new test for early return path, plus many new test classes for other functions |
.github/workflows/run-tests-generate-output.yaml |
Removed repository: param (defaults to base repo), added fetch-depth: 0, removed unnecessary checkout in commentpr job |
copi.owasp.org/test/copi_web/live/player_live/show_test.exs |
Added tests for last_round?, player_first/2, get_vote/2, next_round, and voting events |
copi.owasp.org/test/copi_web/live/player_live/form_component_test.exs |
Added FormComponent.topic/1 test, whitespace cleanup |
copi.owasp.org/test/copi_web/live/game_live/show_test.exs |
Added tests for card_played_in_round/2, game redirect, handle_params, handle_info, version helpers |
copi.owasp.org/test/copi_web/live/game_live/create_game_form_test.exs |
Added test for invalid name changeset error path |
copi.owasp.org/test/copi_web/controllers/card_controller_test.exs |
Added format_capec/1 tests |
copi.owasp.org/test/copi_web/controllers/api_controller_test.exs |
Added play_card 404 test |
copi.owasp.org/test/copi_web/plugs/rate_limiter_plug_test.exs |
Added test for nil remote_ip bypass |
copi.owasp.org/test/copi/rate_limiter_test.exs |
Added tests for localhost bypass, normalize_ip fallback, cleanup handler |
copi.owasp.org/test/copi/ip_helper_test.exs |
Added tests for various IP extraction paths |
copi.owasp.org/test/copi/cornucopia_test.exs |
Added tests for Game.find/1, continue vote count, majority votes |
copi.owasp.org/test/copi/cornucopia_logic_test.exs |
Added tests for scoring edge cases, lead suit logic, whitespace cleanup |
| if doc is not None: | ||
| doc = replace_docx_inline_text(doc, language_dict) | ||
| doc.save(output_file) | ||
| else: | ||
| logging.error("Cannot create output file: template document not found at %s", template_doc) | ||
| return |
There was a problem hiding this comment.
The PR description lists only the changes to scripts/convert.py and tests/scripts/convert_utest.py, but the actual diff includes substantial additional changes: ~10 Elixir test files with new test coverage, CI workflow modifications (.github/workflows/run-tests-generate-output.yaml), and several new Python test classes beyond what's described (e.g., TestValidateFilePaths, TestValidateCommandArgs, TestConvertWithLibreOffice, TestConvertWithDocx2pdf, TestCleanupTempFile, etc.). Consider updating the PR description to reflect the full scope of changes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
The Root cause: The What we can do: Apply this one-line fix directly to In the ref: ${{ github.event.pull_request.head.ref }}to: ref: ${{ github.event.pull_request.head.sha }}This will make the checkout use the commit SHA instead of the branch name, which is both more reliable and avoids the truncation issue with long branch names. This fix will benefit all future fork PRs. All other required checks pass (hardening , runtests , Upload Output Files ). This PR is ready for review. |
|
The Comment on PR with build artifacts check is failing due to a pre-existing issue in the upstream pull_request_target workflow — it runs from OWASP/cornucopia's master branch rather than the PR branch, so changes made in this PR to the workflow file have no effect on it. All other required checks pass (hardening, runtests, upload output files). This appears to affect all fork PRs and is unrelated to the changes in this PR. @sydseter @rewtd @cw-owasp What to do with this should i create pr to solve this issue...... |
|
@sydseter just following up ....is this good to go ?? |
|
@immortal71 Could you please resolve the conflict? The rest is good to go. |
# Conflicts: # .github/workflows/run-tests-generate-output.yaml # copi.owasp.org/test/copi_web/live/game_live/show_test.exs
…rnucopia into fix/2490-docx-none
Build artifacts:
Translation Check ReportThe following sentences/tags have issues in the translations: SpanishFile: Untranslated TagsThe following tags have identical text to English (not translated): T00105, T00140 RussianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00001, T00003, T00004, T00090, T00100, T00105, T00210, T00220, T00230, T00240, T00250, T00260, T00270, T00280, T00290, T00300, T00310, T00320, T00330, T00340, T00350, T00360, T00370, T00380, T00390, T00400, T00410, T00420, T00430, T00440, T00450, T00460, T00470, T00480 RussianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00020, T00120, T00130, T00220, T00240, T00310, T00311, T00320, T00330, T00340, T00350, T00360, T00370, T00380, T00390, T00400, T00510, T00520, T00530, T00610, T01010, T01070, T01160, T01170, T01180, T01200, T01210, T01220, T01301, T01411, T02680, T02690, T02700, T02710, T02720, T02730, T02780, T03010 RussianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00020, T00120, T00130, T00220, T00240, T00310, T00311, T00320, T00330, T00340, T00350, T00360, T00370, T00380, T00390, T00400, T00510, T00520, T00530, T00610, T01010, T01070, T01160, T01170, T01180, T01200, T01210, T01220, T01301, T01411, T02680, T02690, T02700, T02710, T02720, T02730, T02780, T03010 SpanishFile: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00020, T00030, T00380, T01590, T02940, T03140, T03160, T03180, T03200, T03210, T03220, T03230, T03250, T03270, T03280, T03290, T03300, T03310, T03320, T03330, T03340, T03360, T03370, T03380, T03390, T03400, T03410, T03430, T03440, T03450, T03460, T03480, T03500, T03510, T03520, T03530, T03550, T03560, T03570, T03590, T03600, T03610, T03620, T03630, T03640, T03650, T03660, T03670, T03680, T03690, T03700, T03720, T03771, T03773, T03775, T03800, T03810, T03820, T03830, T03840, T03850, T03860, T03870, T03900, T03940, T03950 FrenchFile: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00200, T01100, T03110, T03120, T03771, T03773, T03775 HungarianFile: Missing TagsThe following tags are present in the English version but missing in this translation: T00005, T00161, T00162, T01301, T01311, T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00020, T00030, T00140, T00145, T00200, T00210, T00220, T00230, T00240, T00300, T00320, T00340, T00350, T00360, T00370, T00380, T00390, T00400, T00500, T00510, T00520, T00600, T00610, T00700, T00710, T00720, T00730, T00740, T00750, T00760, T00770, T00780, T00790, T00800, T00810, T00830, T00840, T00900, T00910, T00920, T01000, T01020, T01060, T01100, T01110, T01120, T01130, T01140, T01150, T01160, T01170, T01190, T01200, T01240, T01250, T01260, T01270, T01280, T01290, T01300, T01400, T01410, T01420, T01430, T01431, T01440, T01450, T01500, T01510, T01520, T01530, T01540, T01550, T01560, T01570, T01571, T01580, T01590, T01600, T01610, T01700, T01710, T01720, T01730, T01740, T01800, T01810, T01811, T01820, T01900, T01910, T01920, T01930, T01940, T01960, T01970, T01980, T02000, T02010, T02020, T02030, T02040, T02100, T02120, T02140, T02200, T02220, T02240, T02250, T02260, T02280, T02290, T02300, T02310, T02320, T02340, T02400, T02410, T02420, T02440, T02450, T02460, T02480, T02490, T02500, T02510, T02520, T02540, T02600, T02610, T02620, T02630, T02650, T02680, T02690, T02700, T02710, T02720, T02730, T02760, T02770, T02790, T02800, T02810, T02820, T02840, T02850, T02860, T02870, T02880, T02890, T02900, T02910, T02920, T02930, T02940, T02950, T02960, T02970, T02980, T02990, T03000, T03020, T03100, T03110, T03120, T03140, T03160, T03200, T03210, T03220, T03230, T03250, T03270, T03280, T03290, T03300, T03310, T03320, T03330, T03340, T03360, T03370, T03380, T03390, T03400, T03410, T03430, T03450, T03460, T03480, T03500, T03510, T03520, T03530, T03550, T03560, T03570, T03590, T03600, T03610, T03620, T03630, T03640, T03650, T03660, T03670, T03680, T03690, T03700, T03720, T03740, T03760, T03771, T03773, T03775, T03800, T03810, T03820, T03830, T03840, T03900, T03920, T03950 ItalianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00380, T02940, T03250, T03771, T03773, T03775 DutchFile: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00500, T03771, T03773, T03775 NorwegianFile: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00380, T01700, T03140, T03160, T03180, T03200, T03210, T03220, T03230, T03250, T03270, T03280, T03290, T03300, T03310, T03320, T03330, T03340, T03360, T03370, T03380, T03390, T03400, T03410, T03430, T03440, T03450, T03460, T03480, T03500, T03510, T03520, T03530, T03550, T03560, T03570, T03590, T03600, T03610, T03620, T03630, T03640, T03650, T03660, T03670, T03680, T03690, T03700, T03771, T03773, T03775 Portuguese (Brazil)File: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00380, T02250, T02290, T02310, T02450, T02490, T02510, T03100, T03110, T03120, T03140, T03160, T03180, T03200, T03210, T03220, T03230, T03250, T03270, T03280, T03290, T03300, T03310, T03320, T03330, T03340, T03360, T03370, T03380, T03390, T03400, T03410, T03430, T03440, T03450, T03460, T03480, T03500, T03510, T03520, T03530, T03550, T03560, T03570, T03590, T03600, T03610, T03620, T03630, T03640, T03650, T03660, T03670, T03680, T03690, T03700, T03720, T03771, T03773, T03775 Portuguese (Portugal)File: Untranslated TagsThe following tags have identical text to English (not translated): T00380, T03771, T03773, T03775 RussianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00380, T01411, T03771, T03773, T03775 FrenchFile: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00200, T01100, T03110, T03120 hiFile: Missing TagsThe following tags are present in the English version but missing in this translation: T03390, T03400, T03410, T03560, T03570, T03610, T03620, T03630, T03640, T03650, T03670, T03680, T03690, T03700 ItalianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00380, T02940, T03250 DutchFile: Untranslated TagsThe following tags have identical text to English (not translated): T00380, T02270, T02290, T03250 NorwegianFile: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00380, T01700, T03140, T03160, T03180, T03200, T03210, T03220, T03230, T03250, T03270, T03280, T03290, T03300, T03310, T03320, T03330, T03340, T03360, T03370, T03380, T03390, T03400, T03410, T03430, T03440, T03450, T03460, T03480, T03500, T03510, T03520, T03530, T03550, T03560, T03570, T03590, T03600, T03610, T03620, T03630, T03640, T03650, T03660, T03670, T03680, T03690, T03700 Portuguese (Brazil)File: Untranslated TagsThe following tags have identical text to English (not translated): T00330, T00340, T00350, T00360, T00370, T00380, T02240, T02260, T02280, T02300, T02320, T02340, T02440, T02460, T02480, T02500, T02520, T02540 Portuguese (Portugal)File: Untranslated TagsThe following tags have identical text to English (not translated): T00380 RussianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00380 |
Build artifacts:
Translation Check ReportThe following sentences/tags have issues in the translations: SpanishFile: Untranslated TagsThe following tags have identical text to English (not translated): T00105, T00140 RussianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00001, T00003, T00004, T00090, T00100, T00105, T00210, T00220, T00230, T00240, T00250, T00260, T00270, T00280, T00290, T00300, T00310, T00320, T00330, T00340, T00350, T00360, T00370, T00380, T00390, T00400, T00410, T00420, T00430, T00440, T00450, T00460, T00470, T00480 RussianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00020, T00120, T00130, T00220, T00240, T00310, T00311, T00320, T00330, T00340, T00350, T00360, T00370, T00380, T00390, T00400, T00510, T00520, T00530, T00610, T01010, T01070, T01160, T01170, T01180, T01200, T01210, T01220, T01301, T01411, T02680, T02690, T02700, T02710, T02720, T02730, T02780, T03010 RussianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00020, T00120, T00130, T00220, T00240, T00310, T00311, T00320, T00330, T00340, T00350, T00360, T00370, T00380, T00390, T00400, T00510, T00520, T00530, T00610, T01010, T01070, T01160, T01170, T01180, T01200, T01210, T01220, T01301, T01411, T02680, T02690, T02700, T02710, T02720, T02730, T02780, T03010 SpanishFile: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00020, T00030, T00380, T01590, T02940, T03140, T03160, T03180, T03200, T03210, T03220, T03230, T03250, T03270, T03280, T03290, T03300, T03310, T03320, T03330, T03340, T03360, T03370, T03380, T03390, T03400, T03410, T03430, T03440, T03450, T03460, T03480, T03500, T03510, T03520, T03530, T03550, T03560, T03570, T03590, T03600, T03610, T03620, T03630, T03640, T03650, T03660, T03670, T03680, T03690, T03700, T03720, T03771, T03773, T03775, T03800, T03810, T03820, T03830, T03840, T03850, T03860, T03870, T03900, T03940, T03950 FrenchFile: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00200, T01100, T03110, T03120, T03771, T03773, T03775 HungarianFile: Missing TagsThe following tags are present in the English version but missing in this translation: T00005, T00161, T00162, T01301, T01311, T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00020, T00030, T00140, T00145, T00200, T00210, T00220, T00230, T00240, T00300, T00320, T00340, T00350, T00360, T00370, T00380, T00390, T00400, T00500, T00510, T00520, T00600, T00610, T00700, T00710, T00720, T00730, T00740, T00750, T00760, T00770, T00780, T00790, T00800, T00810, T00830, T00840, T00900, T00910, T00920, T01000, T01020, T01060, T01100, T01110, T01120, T01130, T01140, T01150, T01160, T01170, T01190, T01200, T01240, T01250, T01260, T01270, T01280, T01290, T01300, T01400, T01410, T01420, T01430, T01431, T01440, T01450, T01500, T01510, T01520, T01530, T01540, T01550, T01560, T01570, T01571, T01580, T01590, T01600, T01610, T01700, T01710, T01720, T01730, T01740, T01800, T01810, T01811, T01820, T01900, T01910, T01920, T01930, T01940, T01960, T01970, T01980, T02000, T02010, T02020, T02030, T02040, T02100, T02120, T02140, T02200, T02220, T02240, T02250, T02260, T02280, T02290, T02300, T02310, T02320, T02340, T02400, T02410, T02420, T02440, T02450, T02460, T02480, T02490, T02500, T02510, T02520, T02540, T02600, T02610, T02620, T02630, T02650, T02680, T02690, T02700, T02710, T02720, T02730, T02760, T02770, T02790, T02800, T02810, T02820, T02840, T02850, T02860, T02870, T02880, T02890, T02900, T02910, T02920, T02930, T02940, T02950, T02960, T02970, T02980, T02990, T03000, T03020, T03100, T03110, T03120, T03140, T03160, T03200, T03210, T03220, T03230, T03250, T03270, T03280, T03290, T03300, T03310, T03320, T03330, T03340, T03360, T03370, T03380, T03390, T03400, T03410, T03430, T03450, T03460, T03480, T03500, T03510, T03520, T03530, T03550, T03560, T03570, T03590, T03600, T03610, T03620, T03630, T03640, T03650, T03660, T03670, T03680, T03690, T03700, T03720, T03740, T03760, T03771, T03773, T03775, T03800, T03810, T03820, T03830, T03840, T03900, T03920, T03950 ItalianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00380, T02940, T03250, T03771, T03773, T03775 DutchFile: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00500, T03771, T03773, T03775 NorwegianFile: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00380, T01700, T03140, T03160, T03180, T03200, T03210, T03220, T03230, T03250, T03270, T03280, T03290, T03300, T03310, T03320, T03330, T03340, T03360, T03370, T03380, T03390, T03400, T03410, T03430, T03440, T03450, T03460, T03480, T03500, T03510, T03520, T03530, T03550, T03560, T03570, T03590, T03600, T03610, T03620, T03630, T03640, T03650, T03660, T03670, T03680, T03690, T03700, T03771, T03773, T03775 Portuguese (Brazil)File: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00380, T02250, T02290, T02310, T02450, T02490, T02510, T03100, T03110, T03120, T03140, T03160, T03180, T03200, T03210, T03220, T03230, T03250, T03270, T03280, T03290, T03300, T03310, T03320, T03330, T03340, T03360, T03370, T03380, T03390, T03400, T03410, T03430, T03440, T03450, T03460, T03480, T03500, T03510, T03520, T03530, T03550, T03560, T03570, T03590, T03600, T03610, T03620, T03630, T03640, T03650, T03660, T03670, T03680, T03690, T03700, T03720, T03771, T03773, T03775 Portuguese (Portugal)File: Untranslated TagsThe following tags have identical text to English (not translated): T00380, T03771, T03773, T03775 RussianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00380, T01411, T03771, T03773, T03775 FrenchFile: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00200, T01100, T03110, T03120 hiFile: Missing TagsThe following tags are present in the English version but missing in this translation: T03390, T03400, T03410, T03560, T03570, T03610, T03620, T03630, T03640, T03650, T03670, T03680, T03690, T03700 ItalianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00380, T02940, T03250 DutchFile: Untranslated TagsThe following tags have identical text to English (not translated): T00380, T02270, T02290, T03250 NorwegianFile: Missing TagsThe following tags are present in the English version but missing in this translation: T01411 Untranslated TagsThe following tags have identical text to English (not translated): T00380, T01700, T03140, T03160, T03180, T03200, T03210, T03220, T03230, T03250, T03270, T03280, T03290, T03300, T03310, T03320, T03330, T03340, T03360, T03370, T03380, T03390, T03400, T03410, T03430, T03440, T03450, T03460, T03480, T03500, T03510, T03520, T03530, T03550, T03560, T03570, T03590, T03600, T03610, T03620, T03630, T03640, T03650, T03660, T03670, T03680, T03690, T03700 Portuguese (Brazil)File: Untranslated TagsThe following tags have identical text to English (not translated): T00330, T00340, T00350, T00360, T00370, T00380, T02240, T02260, T02280, T02300, T02320, T02340, T02440, T02460, T02480, T02500, T02520, T02540 Portuguese (Portugal)File: Untranslated TagsThe following tags have identical text to English (not translated): T00380 RussianFile: Untranslated TagsThe following tags have identical text to English (not translated): T00380 |
Summary
Resolves #2490
Problem
get_docx_document()returned a blankdocx.Document()when the template file was not found. Because a blankdocx.Document()is always truthy in Python, the caller'sif doc:guard always passed — causingcreate_edition_from_template()to silently write an empty output file with no further error.Changes
scripts/convert.pyget_docx_document(): returnNoneinstead ofdocx.Document()when the template file does not exist; update return type annotation toOptional[Any]; update docstring to reflect thiscreate_edition_from_template(): changeif doc:toif doc is not None:for semantic clarity; addelsebranch that logs a descriptive error and returns early, preventing any empty output file from being writtentests/scripts/convert_utest.pytest_get_docx_document_failure: updated to assertassertIsNone(got_file)instead of asserting a blank-document type/lengthtest_create_edition_from_template_docx_none_doc_returns_early: covers the newelsepathTestValidateFilePaths,TestValidateCommandArgs,TestConvertWithLibreOffice,TestConvertWithDocx2pdf,TestCleanupTempFile, and others covering previously untested branches inconvert.pyllandresult)blackformatting (--line-length=120)copi.owasp.org/test/— ~10 Elixir test files updated/added to push COPI coverage above 90%:test/copi_web/live/game_live/show_test.exs: redirect on invalid game_id, finished game path,card_played_in_round,display_game_session,latest_version, handle_info non-matching topictest/copi_web/live/player_live/show_test.exs:last_round?true/false,player_first,get_vote,next_round(closed/open),toggle_vote,toggle_continue_vote,proceed_to_next_roundtest/copi_web/live/player_live/form_component_test.exs: rate limiting paths,FormComponent.topic/1test/copi_web/live/game_live/create_game_form_test.exs: rate limiting, validation,save_gameerror branchtest/copi_web/controllers/api_controller_test.exs: game not found, card already played, player already played in roundtest/copi_web/controllers/card_controller_test.exs:format_capec/1test/copi/cornucopia_logic_test.exs,test/copi/cornucopia_test.exs,test/copi/rate_limiter_test.exs,test/copi/ip_helper_test.exs,test/copi_web/plugs/rate_limiter_plug_test.exs.github/workflows/run-tests-generate-output.yamluploadoutputfilesjob: switched checkoutreffrom branch name togithub.event.pull_request.head.shawithfetch-depth: 0to avoid git refspec truncation on long branch names inpull_request_targetworkflowscommentprjob: removed unnecessary checkout step (job only downloads an artifact and posts a comment)Testing