diff --git a/service/shale/prepare.py b/service/shale/prepare.py index 897e58d82f5ca57480010c71529ea694de3a35bd..29f817a05e536bf679dd13eab10f1b111c69860f 100644 --- a/service/shale/prepare.py +++ b/service/shale/prepare.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Keep Shale identities attached to their existing accounts when the issuer moves.""" +"""Prepare owned Git repositories and preserve Shale account bindings.""" import json import os from pathlib import Path diff --git a/tools/router.py b/tools/router.py index b6311bd108befa91145a9dead59db0a925a187b1..9ae855b0c80be1e5a7b117f5b441160d7104d369 100644 --- a/tools/router.py +++ b/tools/router.py @@ -87,7 +87,7 @@ def shale_git_routes(upstreams): lines = [" @shale_git path */info/refs */git-upload-pack */git-receive-pack", " handle @shale_git {", f" reverse_proxy {upstreams} {{"] # Shale forwards CGI Status as a header instead of the HTTP status. - for status in (403, 404, 500): + for status in (400, 403, 404, 405, 415, 500): lines += [f' @cgi_{status} header Status "{status} *"', f" handle_response @cgi_{status} {{", " header {", " -Status", " defer", " }", diff --git a/tools/shale-migration.md b/tools/shale-migration.md index 430984990182f70e039d7930f6164e122406c2e3..0def154de3ccdb15fa7fb97f45628a75196aff50 100644 --- a/tools/shale-migration.md +++ b/tools/shale-migration.md @@ -67,3 +67,9 @@ Zenith's Shale app directory contains a small SQLite database and 419 MB of owne For the production copy, stop Zenith's Shale container and the Snow Globe Shale job, set `STUDIO_DEPLOY_HOST` and `STUDIO_DEPLOY_PORT` for the new host, then run `bash tools/import-shale.sh shale`. The importer checks both jobs remain stopped, snapshots the destination dataset, verifies all three copied directories, and leaves Snow Globe stopped. Start the new job after the copy, check the SQLite state and a known login through the new Keycloak client, then switch the public route. The destination snapshot printed by the importer remains available for recovery. After a same-machine OS replacement, set `STUDIO_LEGACY_HANDOFF` to the [offline handoff](legacy-handoff.md) directory as well. The importer then reads the retained Shale directory from the new host's mounted old apps dataset, with no old Docker dependency. + +## Imported repository HTTP pushes + +The Forgejo importer originally omitted `http.receivepack=true`, which Shale sets when it creates an owned repository. Shale checks its push ACL before invoking `git-http-backend`, but does not set `REMOTE_USER`; Git's default therefore rejected authorized pushes to imported repositories. The importer now writes the setting, and Shale's prepare step repairs missing settings without replacing an explicit disable. Production `config` remains owner-only for pushes. + +Shale also forwards CGI `Status` as an ordinary header on HTTP 200. The Git-specific Caddy handler translates Git's error statuses into HTTP statuses and removes the CGI header. A disposable production database/repository copy verified anonymous and invalid credentials return 401, authenticated non-owners return 403, owner discovery advertises `main=37665e69e1aa954f0dec06b1cafa1612f44dc907`, and an actual `jj git push --bookmark main` advances the clone to `b8e734ce6aabd94a7e1aacfc989467662ca27dbe`. Disabled receive-pack returns actual HTTP 403; invalid method/content type return 400/415 without a `Status` header. No production token was added.