From 4fd02896d25226a62681d76ee80913cba68f6c25 Mon Sep 17 00:00:00 2001 From: Owais Jamil Date: Sat, 13 Jun 2026 18:33:20 -0500 Subject: [PATCH] feat: add PLC logging and token handling --- lib/tempest/identity/plc_client.ex | 59 ++++++++++++++++++++++++++++-- scripts/src/tempest_py/main.py | 32 ++++++++++------ 2 files changed, 77 insertions(+), 14 deletions(-) diff --git a/lib/tempest/identity/plc_client.ex b/lib/tempest/identity/plc_client.ex index 1c7fac6..a4dcd8b 100644 --- a/lib/tempest/identity/plc_client.ex +++ b/lib/tempest/identity/plc_client.ex @@ -5,6 +5,8 @@ defmodule Tempest.Identity.PlcClient do The client is configurable so tests can use Req.Test or another fake service. """ + require Logger + def fetch_state(did) when is_binary(did) do url = plc_directory_url() <> "/" <> URI.encode(did) @@ -23,18 +25,69 @@ defmodule Tempest.Identity.PlcClient do def publish_operation(did, operation) when is_binary(did) and is_map(operation) do url = plc_directory_url() <> "/" <> URI.encode(did) + prev = Map.get(operation, "prev") + endpoint = get_in(operation, ["services", "atproto_pds", "endpoint"]) opts = [url: url, json: operation, retry: false] |> Keyword.merge(identity_config(:http_req_options) || []) + Logger.info("Publishing PLC operation", + did: did, + plc_url: url, + plc_prev: prev, + plc_service_endpoint: endpoint, + has_signature: is_binary(Map.get(operation, "sig")) + ) + case Req.post(opts) do - {:ok, %{status: status}} when status in 200..299 -> :ok - {:ok, %{status: status}} -> {:error, {:plc_status, status}} - {:error, reason} -> {:error, {:plc_request_failed, reason}} + {:ok, %{status: status}} when status in 200..299 -> + Logger.info("Published PLC operation", + did: did, + plc_url: url, + plc_status: status + ) + + :ok + + {:ok, %{status: status, body: body}} -> + Logger.error("PLC directory rejected operation", + did: did, + plc_url: url, + plc_status: status, + plc_response_body: response_body_snippet(body) + ) + + {:error, {:plc_status, status}} + + {:error, reason} -> + Logger.error("PLC directory request failed", + did: did, + plc_url: url, + plc_request_error: inspect(reason) + ) + + {:error, {:plc_request_failed, reason}} end end + defp response_body_snippet(body) when is_binary(body) do + body + |> String.slice(0, 500) + |> String.replace(~r/\s+/, " ") + end + + defp response_body_snippet(body) when is_map(body) do + body + |> Jason.encode() + |> case do + {:ok, encoded} -> response_body_snippet(encoded) + {:error, _reason} -> inspect(body, limit: 20, printable_limit: 500) + end + end + + defp response_body_snippet(body), do: inspect(body, limit: 20, printable_limit: 500) + defp plc_directory_url do identity_config(:plc_directory_url) || "https://plc.directory" end diff --git a/scripts/src/tempest_py/main.py b/scripts/src/tempest_py/main.py index 932b752..faf060e 100644 --- a/scripts/src/tempest_py/main.py +++ b/scripts/src/tempest_py/main.py @@ -226,9 +226,11 @@ def bearer(token: str) -> dict[str, str]: def access_from_session(settings: Settings) -> str: - explicit = env("OLD_ACCESS") - if explicit: - return explicit + if not settings.old_session_path.exists(): + explicit = env("OLD_ACCESS") + if explicit: + return explicit + raise CliError(f"{settings.old_session_path} does not exist; run login-source or set OLD_ACCESS") data = read_json(settings.old_session_path) session_host = data.get("_tempest_old_login_pds") or data.get("_tempest_old_auth_pds") @@ -265,9 +267,11 @@ def service_auth_token(settings: Settings) -> str: def tempest_access_token(settings: Settings) -> str: - explicit = env("TEMPEST_ACCESS") - if explicit: - return explicit + if not settings.create_account_path.exists(): + explicit = env("TEMPEST_ACCESS") + if explicit: + return explicit + raise CliError(f"{settings.create_account_path} does not exist; run create-account or set TEMPEST_ACCESS") data = read_json(settings.create_account_path) token = data.get("accessJwt") @@ -277,9 +281,11 @@ def tempest_access_token(settings: Settings) -> str: def tempest_refresh_token(settings: Settings) -> str: - explicit = env("TEMPEST_REFRESH") - if explicit: - return explicit + if not settings.create_account_path.exists(): + explicit = env("TEMPEST_REFRESH") + if explicit: + return explicit + raise CliError(f"{settings.create_account_path} does not exist; run create-account or set TEMPEST_REFRESH") data = read_json(settings.create_account_path) token = data.get("refreshJwt") @@ -555,12 +561,16 @@ def plc_request_token(settings: Settings) -> None: "The source session itself is valid, but this old-PDS endpoint is refusing its scope." ) - data = expect_json(status, raw, url) + if 200 <= status <= 299 and raw.strip() == b"": + data = {"requested": True, "delivery": "email"} + else: + data = expect_json(status, raw, url) + write_json(settings.plc_token_path, data) print_json_summary("saved PLC operation token response", data) log(f"wrote {settings.plc_token_path}") if "token" not in data: - log("No token field was returned. If the old PDS emails a token/code, export it as PLC_TOKEN before plc-sign.") + log("Check the source account email for the PLC token/code, then export it as PLC_TOKEN before plc-sign.") def plc_sign(settings: Settings) -> None: -- 2.51.2