Skip to content

Fix manage API gaps found migrating LexBox: hgrc strip, backup under Kestrel - #32

Open
hahn-kev-bot wants to merge 2 commits into
masterfrom
claude/hgresume-manage-api-migration-b69787
Open

hahn-kev-bot wants to merge 2 commits into
masterfrom
claude/hgresume-manage-api-migration-b69787

Conversation

@hahn-kev-bot

@hahn-kev-bot hahn-kev-bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

AI summary

Two bugs in /api/manage, both found while moving LexBox's HgService onto it (sillsdev/languageforge-lexbox#2821).

Uploaded .hg/hgrc survived FinishReset. Mercurial trusts a repo-level hgrc (hooks, extensions), so a user-uploaded one shouldn't land on the server. LexBox already stripped it; the port in #24 didn't. FinishReset now deletes it.

GET /repos/{code}/backup failed under Kestrel with a 409. It zipped with ZipFile.CreateFromDirectory straight into the response body. Kestrel rejects synchronous writes, and ApiExceptionHandler turned the resulting InvalidOperationException into a "Conflict". The unit tests wrote into a MemoryStream, so they never saw it.

  • Backup now uses ZipFile.CreateFromDirectoryAsync. .NET still flushes each entry's DeflateStream synchronously on dispose, so the endpoint also sets AllowSynchronousIO for that one response. The bulk of the zip is still written asynchronously.
  • InvalidOperationException no longer maps to 409. CopyRepo's "destination not empty" throws AlreadyExistsException, which still does, so other bugs surface as 500s instead of a misleading 409.

Image: LexBox needs an image with this before #2821 merges. Once this merges to master the workflow publishes v<merge date>; until then there's pr-32.

Test plan

  • FinishResetDropsUploadedHgrc theory (.hg at zip root and nested)
  • ManageEndpointTests runs backup through WebApplicationFactory, whose TestServer rejects sync IO like Kestrel. It failed with the CI error before the fix and passes after.
  • HgResume.Api.Tests 19/19 locally
  • ManageFacts.Backup_RestoresTheSameRepo (backup → finish-reset round trip against the container) in CI; Docker wasn't available locally

🤖 Generated with Claude Code

Mercurial trusts a repo's hgrc (hooks, extensions) on the server, and an
uploaded reset zip can carry one. LexBox's HgService already strips it;
the manage API port didn't, so LexBox moving onto /api/manage would lose
that protection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /api/manage/repos/{code}/backup zipped synchronously into the response
body, which Kestrel rejects, and the exception handler turned the resulting
InvalidOperationException into a 409. Write the zip with
CreateFromDirectoryAsync and allow synchronous IO on that one response,
since .NET still flushes each entry's DeflateStream synchronously on dispose.

Stop mapping every InvalidOperationException to 409: CopyRepo's "destination
not empty" now throws AlreadyExistsException, so other bugs surface as 500s.

Tests: backup through WebApplicationFactory (TestServer rejects sync IO like
Kestrel) and a backup/restore round trip against the container.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hahn-kev-bot hahn-kev-bot changed the title Drop uploaded .hg/hgrc in FinishReset Fix manage API gaps found migrating LexBox: hgrc strip, backup under Kestrel Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants