fix devpi gateway auth
This commit is contained in:
@@ -12,11 +12,12 @@ On every ``get`` the helper:
|
||||
1. Reads the auth file (same path the gateway uses:
|
||||
``~/.forge-stack-devpi-gateway-gitea/client-auth.json`` by default,
|
||||
or whatever ``FSDGG_AUTH_STORE_PATH`` / ``FSDGG_RUNTIME_DIR`` point
|
||||
at). If the file is missing, the helper passes git's input through
|
||||
unchanged so the normal prompt chain continues.
|
||||
at). If the file is missing, the helper emits no output so the next
|
||||
helper in Git's chain can answer without receiving echoed fields from
|
||||
this helper.
|
||||
2. Checks that the git request host matches the host recorded in
|
||||
``_forge_gitea_base_url`` (or ``FORGE_GITEA_URL``). If not, passes
|
||||
through. This prevents OAuth token disclosure to unrelated
|
||||
``_forge_gitea_base_url`` (or ``FORGE_GITEA_URL``). If not, emits no
|
||||
output. This prevents OAuth token disclosure to unrelated
|
||||
hosts even if git mis-scopes its lookup.
|
||||
3. If ``gitea_access_token`` is live, emits
|
||||
``username=<stored-user>`` and ``password=<gitea_access_token>``.
|
||||
@@ -29,7 +30,7 @@ Security notes
|
||||
--------------
|
||||
* The helper never writes to stdout except the credential key=value
|
||||
block. Logs go to stderr.
|
||||
* On OAuth refresh failure the helper exits **non-zero** rather than silently
|
||||
* On OAuth refresh failure the helper emits no credentials rather than
|
||||
returning stale credentials.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
@@ -82,6 +83,10 @@ def emit(fields: dict[str, str]) -> None:
|
||||
sys.stdout.write(f"{key}={value}\n")
|
||||
|
||||
|
||||
def emit_no_credentials() -> None:
|
||||
return
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Host matching
|
||||
# --------------------------------------------------------------------
|
||||
@@ -150,10 +155,10 @@ def _request_matches(
|
||||
def cmd_get(fields: dict[str, str]) -> int:
|
||||
configured = _configured_host()
|
||||
if configured is None:
|
||||
emit(fields) # pass-through: helper scope is unknown
|
||||
emit_no_credentials()
|
||||
return 0
|
||||
if not _request_matches(fields, configured):
|
||||
emit(fields) # pass-through: request targets a different host
|
||||
emit_no_credentials()
|
||||
return 0
|
||||
|
||||
state = forge_auth.AuthFile.read(forge_auth.auth_store_path())
|
||||
@@ -172,7 +177,7 @@ def cmd_get(fields: dict[str, str]) -> int:
|
||||
"FSDGG_CLI_CLIENT_ID are not set in the environment; "
|
||||
"cannot refresh. Run 'just login' to re-authenticate."
|
||||
)
|
||||
emit(fields)
|
||||
emit_no_credentials()
|
||||
return 0
|
||||
try:
|
||||
refreshed = forge_auth.run_refresh(config, must_refresh=True)
|
||||
@@ -181,7 +186,7 @@ def cmd_get(fields: dict[str, str]) -> int:
|
||||
f"token refresh failed: {exc}. "
|
||||
f"Run 'just login' to re-authenticate."
|
||||
)
|
||||
emit(fields)
|
||||
emit_no_credentials()
|
||||
return 0
|
||||
_emit_credentials(fields, refreshed)
|
||||
return 0
|
||||
@@ -190,7 +195,7 @@ def cmd_get(fields: dict[str, str]) -> int:
|
||||
def _emit_credentials(fields: dict[str, str], state: forge_auth.AuthFile) -> None:
|
||||
token = state.gitea_access_token
|
||||
if not token:
|
||||
emit(fields)
|
||||
emit_no_credentials()
|
||||
return
|
||||
out = dict(fields)
|
||||
out["username"] = state.username or fields.get("username") or "oauth"
|
||||
|
||||
@@ -177,16 +177,16 @@ class CmdGetTests(unittest.TestCase):
|
||||
self.assertEqual(parsed["password"], "LIVETOKEN")
|
||||
self.assertEqual(parsed["host"], "g.example:8443")
|
||||
|
||||
def test_no_store_passes_through(self) -> None:
|
||||
def test_no_store_emits_no_credentials(self) -> None:
|
||||
rc, out, _ = self._run(
|
||||
store_payload=None,
|
||||
stdin_text="protocol=https\nhost=g.example:8443\n\n",
|
||||
)
|
||||
self.assertEqual(rc, 0)
|
||||
self.assertEqual(out, "")
|
||||
self.assertNotIn("password=", out)
|
||||
self.assertIn("host=g.example:8443", out)
|
||||
|
||||
def test_non_matching_host_passes_through(self) -> None:
|
||||
def test_non_matching_host_emits_no_credentials(self) -> None:
|
||||
payload = {
|
||||
"username": "alice",
|
||||
"gitea_access_token": "LIVETOKEN",
|
||||
@@ -198,10 +198,10 @@ class CmdGetTests(unittest.TestCase):
|
||||
stdin_text="protocol=https\nhost=github.com\n\n",
|
||||
)
|
||||
self.assertEqual(rc, 0)
|
||||
self.assertEqual(out, "")
|
||||
self.assertNotIn("password=", out)
|
||||
self.assertIn("host=github.com", out)
|
||||
|
||||
def test_match_but_no_token_passes_through(self) -> None:
|
||||
def test_match_but_no_token_emits_no_credentials(self) -> None:
|
||||
payload = {
|
||||
"username": "alice",
|
||||
"gitea_access_token": "",
|
||||
@@ -212,6 +212,7 @@ class CmdGetTests(unittest.TestCase):
|
||||
stdin_text="protocol=https\nhost=g.example:8443\n\n",
|
||||
)
|
||||
self.assertEqual(rc, 0)
|
||||
self.assertEqual(out, "")
|
||||
self.assertNotIn("password=", out)
|
||||
|
||||
# --- expired token + refresh -------------------------------------
|
||||
@@ -263,6 +264,7 @@ class CmdGetTests(unittest.TestCase):
|
||||
stdin_text="protocol=https\nhost=g.example:8443\n\n",
|
||||
)
|
||||
self.assertEqual(rc, 0)
|
||||
self.assertEqual(out, "")
|
||||
self.assertNotIn("password=", out)
|
||||
self.assertIn("token refresh failed", err)
|
||||
self.assertIn("just login", err)
|
||||
|
||||
@@ -24,13 +24,15 @@ assert() {
|
||||
|
||||
assert 'setup.sh parses as valid bash' bash -n "$root/scripts/setup.sh"
|
||||
|
||||
help_out="$(bash "$root/scripts/setup.sh" --help 2>&1)"
|
||||
help_file="$(mktemp)"
|
||||
bash "$root/scripts/setup.sh" --help >"$help_file" 2>&1
|
||||
assert '--help prints the Usage header' \
|
||||
bash -c "printf '%s' \"$help_out\" | grep -q '^Usage: just setup'"
|
||||
grep -q '^Usage: just setup' "$help_file"
|
||||
assert '--help documents --headless' \
|
||||
bash -c "printf '%s' \"$help_out\" | grep -q -- '--headless'"
|
||||
grep -q -- '--headless' "$help_file"
|
||||
assert '--help documents FORGE_SETUP_YES' \
|
||||
bash -c "printf '%s' \"$help_out\" | grep -q 'FORGE_SETUP_YES'"
|
||||
grep -q 'FORGE_SETUP_YES' "$help_file"
|
||||
rm -f "$help_file"
|
||||
|
||||
set +e
|
||||
bash "$root/scripts/setup.sh" --not-a-flag >/dev/null 2>"$here/.bad.err"
|
||||
|
||||
Reference in New Issue
Block a user