This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git
The following commit(s) were added to refs/heads/main by this push:
new adabecd Add a command to fetch a JWT
adabecd is described below
commit adabecdab98ba591d4d985f49e9602e9c84bfffa
Author: Sean B. Palmer <[email protected]>
AuthorDate: Fri Jul 4 16:52:23 2025 +0100
Add a command to fetch a JWT
---
client/atr | 43 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/client/atr b/client/atr
index 7cb7d5f..c53f662 100755
--- a/client/atr
+++ b/client/atr
@@ -20,6 +20,7 @@
# /// script
# requires-python = ">=3.13"
# dependencies = [
+# "aiohttp",
# "cyclopts",
# "filelock",
# "platformdirs",
@@ -44,6 +45,7 @@
from __future__ import annotations
+import asyncio
import contextlib
import logging
import os
@@ -52,6 +54,7 @@ import sys
import tempfile
from typing import Any, Literal
+import aiohttp # type: ignore[import-not-found]
import cyclopts # type: ignore[import-not-found]
import filelock # type: ignore[import-not-found]
import platformdirs # type: ignore[import-not-found]
@@ -66,7 +69,7 @@ YAML_DEFAULTS: dict[str, Any] = {"atr": {}, "tokens": {}}
YAML_SCHEMA: strictyaml.Map = strictyaml.Map(
{
strictyaml.Optional("atr"):
strictyaml.Map({strictyaml.Optional("host"): strictyaml.Str()}),
- "tokens": strictyaml.Map({strictyaml.Optional("pat"):
strictyaml.Str()}),
+ strictyaml.Optional("tokens"):
strictyaml.Map({strictyaml.Optional("pat"): strictyaml.Str()}),
}
)
@@ -170,6 +173,28 @@ def app_pat_show() -> None:
sys.exit(1)
[email protected](name="jwt", help="Fetch a JWT using the stored PAT.")
+def app_pat_jwt(asf_uid: str | None = None) -> None:
+ with config_lock():
+ cfg = config_read()
+
+ pat_token = cfg.get("tokens", {}).get("pat")
+ if pat_token is None:
+ LOGGER.error("No Personal Access Token stored.")
+ sys.exit(1)
+
+ host = cfg.get("atr", {}).get("host", "release-test.apache.org")
+ url = f"https://{host}/api/jwt"
+
+ if asf_uid is None:
+ LOGGER.error("No ASF UID provided.")
+ sys.exit(1)
+
+ verify_ssl = not host.startswith("127.0.0.1")
+ jwt = asyncio.run(web_fetch(url, asf_uid, pat_token, verify_ssl))
+ print(jwt)
+
+
@RELEASE.command(name="add", help="Add a release.")
def app_release_add(project: str, version: str) -> None:
print(project, version)
@@ -224,5 +249,21 @@ def main() -> None:
APP()
+async def web_fetch(url: str, asfuid: str, pat_token: str, verify_ssl: bool =
True) -> str:
+ connector = aiohttp.TCPConnector(ssl=verify_ssl) if not verify_ssl else
None
+ async with aiohttp.ClientSession(connector=connector) as session:
+ payload = {"asfuid": asfuid, "pat": pat_token}
+ async with session.post(url, json=payload) as resp:
+ if resp.status != 200:
+ text = await resp.text()
+ LOGGER.error(f"JWT fetch failed: {resp.status} {text}")
+ sys.exit(1)
+
+ data: dict[str, Any] = await resp.json()
+ if "jwt" in data:
+ return data["jwt"]
+ raise RuntimeError(f"Unexpected response: {data}")
+
+
if __name__ == "__main__":
main()
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]