From 147468c48d65d7f351cbfbdadc4128b980f28253 Mon Sep 17 00:00:00 2001 From: mpabi Date: Mon, 27 Apr 2026 20:23:04 +0200 Subject: [PATCH] Split token scan and compare commands --- README.md | 7 +++-- doc/rvctl.md | 38 ++++++++++++++++++++++--- doc/tokens.md | 35 +++++++++++++++-------- rvctl.py | 79 +++++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 135 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 98afb98..42ab55e 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,7 @@ Podstawowe komendy tokenow: ```bash ./rvctl tokens scan +./rvctl tokens compare ./rvctl tokens list store ./rvctl tokens list remote ./rvctl tokens sync remote r1 @@ -168,8 +169,10 @@ Podstawowe komendy tokenow: ./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03 ``` -`tokens scan` wypisuje tabele `tokens` i niczego nie zapisuje: jeden wiersz na -logiczny remote tokena. +`tokens scan` wypisuje diagnostyczny skan git remotes i niczego nie zapisuje: +pokazuje URL-e typu `auth`, `plain` i `unsupported`. +`tokens compare` wypisuje tabele `tokens` i niczego nie zapisuje: jeden wiersz +na logiczny remote tokena. `tokens list store|remote|both` wypisuje jedno zrodlo bez porownywania. `tokens.json` synchronizujemy z repo `rv-launcher`; remotes kart pracy i odpowiedzi sa generowane jako pochodne tego ustawienia. diff --git a/doc/rvctl.md b/doc/rvctl.md index 9bb8694..5f17805 100644 --- a/doc/rvctl.md +++ b/doc/rvctl.md @@ -206,6 +206,7 @@ Komendy: - `list-series` - `list-cards [series]` - `tokens scan` +- `tokens compare` - `tokens read` - `tokens stats` - `tokens write` @@ -292,6 +293,35 @@ Przyklady: ## `tokens scan` +Czyta remote URL-e w repo i pokazuje diagnostyczna tabele git remotes: +`auth`, `plain` i `unsupported`. Nie porownuje ich z `tokens.json`. Komenda +jest read-only. + +Przelaczniki: + +- `--repo PATH` + Sciezka wewnatrz docelowego repo. Domyslnie repo zawierajace `rvctl`. +- `--server ENDPOINT` + Pokazuje tylko wpisy z danego endpointu. + +Typowy wynik: + +```text +remotes +item remote kind server proto host org repo user token result url +---- ------ ----------- ------ ----- ------------------ --------- ----------- ---- ------------ -------------- -------------------------------------- +1 r1 auth gitea http 77.90.8.171:3001 edu-tools rv-launcher u1 e59cc...13be found http://77.90.8.171:3001/edu-tools/... +``` + +Przyklad: + +```bash +./rvctl tokens scan +./rvctl tokens scan --repo ~/dev/workspace/rv/series/inf/03 +``` + +## `tokens compare` + Czyta remote URL-e w repo oraz lokalny `tokens.json`, laczy wpisy w pary po endpoincie, nazwie remota, token id, wartosci tokena, org i repo, a potem pokazuje jeden logiczny wiersz na token. Komenda jest read-only. @@ -307,7 +337,7 @@ Typowy wynik: tokens item server proto host org repo user remote token_ref token valid scope org repo ---- ------ ----- ------------------ --------- ----------- ---- ------ --------- ------------ ------------------- aAimnopru oawrc- oawr-- -1 gitea http 77.90.8.171:3001 edu-tools rv-launcher u1 r1 r1 * e59cc...13be forever -----w--- +++++ ++++ +1 gitea http 77.90.8.171:3001 edu-tools rv-launcher u1 r1 r1 * e59cc...13be forever wwwwwwwww +++++ ++++ ``` `token_ref` jest komorka stalej szerokosci: nazwa tokena jest po lewej, a marker @@ -327,15 +357,15 @@ Maski uprawnien: Przyklad: ```bash -./rvctl tokens scan -./rvctl tokens scan --repo ~/dev/workspace/rv/series/inf/03 +./rvctl tokens compare +./rvctl tokens compare --repo ~/dev/workspace/rv/series/inf/03 ``` ## `tokens list store|remote|both` Wypisuje jedno zrodlo bez porownywania go z drugim. `list` jest read-only: pokazuje co jest w `tokens.json`, co jest w git remote albo oba zrodla jako -osobne wiersze. `scan` sluzy do porownania zgodnosci. +osobne wiersze. `compare` sluzy do porownania zgodnosci. Przelaczniki: diff --git a/doc/tokens.md b/doc/tokens.md index ea62e4e..d647634 100644 --- a/doc/tokens.md +++ b/doc/tokens.md @@ -13,7 +13,7 @@ W praktyce oznacza to: - `r1` w repo `rv-launcher` jest miejscem startowym do pobrania tokena z remote - `tokens.json` jest lokalnym store sekretow i metadanych tokenow - karty pracy dostaja remote na podstawie ustawien launchera i komend typu `submission` -- `tokens scan` jest read-only i niczego nie zapisuje +- `tokens scan` i `tokens compare` sa read-only i niczego nie zapisuja ## Zrodlo Prawdy @@ -109,7 +109,7 @@ Pola pobierane z API przez `tokens update r1`: ## Porownanie -`tokens scan` porownuje git remote i `tokens.json` po: +`tokens compare` porownuje git remote i `tokens.json` po: ```text server.endpoint + id + user + value + org + repo @@ -189,9 +189,10 @@ W repo `rv-launcher`: ```bash git remote add r1 http://u1:TOKEN@77.90.8.171:3001/edu-tools/rv-launcher.git ./rvctl tokens scan +./rvctl tokens compare ./rvctl tokens sync remote r1 ./rvctl tokens update r1 -./rvctl tokens scan +./rvctl tokens compare ``` Po `sync remote` sekret jest w `tokens.json`. Po `update` `rvctl` dopisuje @@ -205,37 +206,47 @@ Jesli chcesz tylko zobaczyc jedno zrodlo, bez porownywania: ./rvctl tokens list both ``` -Jesli remote ma byc bez sekretu, a token ma zostac tylko w `tokens.json`: +Jesli token ma zostac tylko w `tokens.json`, usun git remote: ```bash ./rvctl tokens remove remote r1 -git remote add r1 http://77.90.8.171:3001/edu-tools/rv-launcher.git ``` -Jesli trzeba ponownie wpisac sekret ze store do remota: +Jesli trzeba ponownie utworzyc remote z sekretem ze store: ```bash -./rvctl tokens sync store r1 +./rvctl tokens sync store r1 --url http://77.90.8.171:3001/edu-tools/rv-launcher.git ``` ## Komendy ### `tokens scan` -Read-only. Czyta git remote i `tokens.json`, laczy wpisy w pary i wypisuje -tabele `tokens`. Nie tworzy i nie modyfikuje `tokens.json`. Bez `--repo` -czyta repo zawierajace `rvctl`. +Read-only. Czyta git remotes i wypisuje diagnostyczna tabele URL-i: +`auth`, `plain` i `unsupported`. Nie porownuje ich z `tokens.json`. Bez +`--repo` czyta repo zawierajace `rvctl`. ```bash ./rvctl tokens scan ./rvctl tokens scan --repo ~/dev/workspace/rv/tools/rv-launcher ``` +### `tokens compare` + +Read-only. Czyta git remote i `tokens.json`, laczy wpisy w pary i wypisuje +tabele `tokens`. Nie tworzy i nie modyfikuje `tokens.json`. Bez `--repo` +czyta repo zawierajace `rvctl`. + +```bash +./rvctl tokens compare +./rvctl tokens compare --repo ~/dev/workspace/rv/tools/rv-launcher +``` + ### `tokens list store|remote|both` Read-only. Wypisuje jedno zrodlo bez porownywania go z drugim. To odroznia -`list` od `scan`: `list` odpowiada na pytanie "co jest zapisane tutaj", a -`scan` odpowiada na pytanie "czy store i remote sa zgodne". +`list` od `compare`: `list` odpowiada na pytanie "co jest zapisane tutaj", a +`compare` odpowiada na pytanie "czy store i remote sa zgodne". ```bash ./rvctl tokens list store diff --git a/rvctl.py b/rvctl.py index 53347c2..19a20d8 100644 --- a/rvctl.py +++ b/rvctl.py @@ -915,6 +915,7 @@ def scan_repo_remotes(config: WorkspaceConfig, repo_path: Path) -> dict: "org": "", "repo": "", "url_kind": "unsupported", + "url": safe_remote_url_label(remote_url), "token_id": "", "token_value": "", "result": "ignored", @@ -934,6 +935,7 @@ def scan_repo_remotes(config: WorkspaceConfig, repo_path: Path) -> dict: "org": server_info["org"], "repo": server_info["repo"], "url_kind": "plain", + "url": safe_remote_url_label(remote_url), "token_id": "", "token_value": "", "result": "no_credentials", @@ -952,6 +954,7 @@ def scan_repo_remotes(config: WorkspaceConfig, repo_path: Path) -> dict: "org": server_info["org"], "repo": server_info["repo"], "url_kind": "auth", + "url": safe_remote_url_label(remote_url), "token_id": remote_name, "user": user_name, "token_value": token_value, @@ -1300,6 +1303,21 @@ TOKEN_LIST_COLUMNS = [ ("repo_mask", "repo", 6), ] +TOKEN_SCAN_COLUMNS = [ + ("item", "item", 4), + ("remote", "remote", 6), + ("kind", "kind", 11), + ("server", "server", 6), + ("proto", "proto", 5), + ("host", "host", 18), + ("owner", "org", 9), + ("repo_name", "repo", 11), + ("user", "user", 4), + ("token", "token", 12), + ("result", "result", 14), + ("url", "url", 38), +] + TOKEN_SEPARATOR_OVERRIDES = { "scope_mask": "aAimnopru", "org_mask": "oawrc-", @@ -1520,6 +1538,33 @@ def list_remote_rows(repo_servers: dict[str, dict], server_filter: str | None = return rows +def scan_remote_rows(report: dict, server_filter: str | None = None) -> list[dict[str, str]]: + rows: list[dict[str, str]] = [] + for row in report.get("remote_rows", []): + endpoint = str(row.get("endpoint", "")) + if server_filter and endpoint != server_filter: + continue + endpoint_values = endpoint_column_values(endpoint, None, None) if endpoint else {} + token_value = str(row.get("token_value", "")) + rows.append( + { + "item": str(len(rows) + 1), + "remote": str(row.get("remote", "")), + "kind": str(row.get("url_kind", "")), + "server": str(row.get("type", "")), + "proto": endpoint_values.get("scheme", ""), + "host": endpoint_values.get("host", ""), + "owner": str(row.get("org", "")), + "repo_name": str(row.get("repo", "")), + "user": str(row.get("user", "")), + "token": short_secret(token_value) if token_value else "", + "result": str(row.get("result", "")), + "url": str(row.get("url", "")), + } + ) + return rows + + def fallback_project_by_endpoint( endpoint_names: list[str], repo_servers: dict[str, dict], @@ -1864,6 +1909,12 @@ def safe_remote_url_label(remote_url: str | None) -> str: def run_tokens_scan(config: WorkspaceConfig, args: argparse.Namespace) -> None: + repo_path = resolve_launcher_repo_argument(args.repo) + report = scan_repo_remotes(config, repo_path) + print_fixed_table("remotes", TOKEN_SCAN_COLUMNS, scan_remote_rows(report, args.server)) + + +def run_tokens_compare(config: WorkspaceConfig, args: argparse.Namespace) -> None: repo_path = resolve_launcher_repo_argument(args.repo) token_data = load_token_store(config, write_normalized=False) store_servers = store_servers_from_tokens(token_data) @@ -2477,7 +2528,7 @@ def print_main_overview(config_path: Path) -> None: ["list-cards", "[series]", "list cards in a selected series"], ["tmux-container", "[series] [card]", "start tmux with container in pane 0"], ["submission", "[series] [card] --class K --nick N", "prepare answer repo and student branch"], - ["tokens", "scan|list|sync|update|remove|add|read|stats|write", "manage tokens.json and Git remote credentials"], + ["tokens", "list|scan|compare|sync|update|remove|add|read|stats|write", "manage tokens.json and Git remote credentials"], ], ) print() @@ -2485,7 +2536,7 @@ def print_main_overview(config_path: Path) -> None: print_table( ["step", "command", "result"], [ - ["1", "./rvctl tokens scan", "print token table from repo remotes and tokens.json"], + ["1", "./rvctl tokens compare", "compare repo remotes with tokens.json"], ["2", "./rvctl list-series", "choose a series"], ["3", "./rvctl list-cards inf", "choose a card"], ["4", "./rvctl tmux-container inf ", "start the working container"], @@ -2513,8 +2564,9 @@ def print_tokens_overview() -> None: print_table( ["command", "common options", "direction", "purpose"], [ - ["scan", "[--repo PATH]", "read-only", "print token table with remote/store marker and auth masks"], ["list", "store|remote|both", "read-only", "list one source without comparing it"], + ["scan", "[--repo PATH]", "read-only", "diagnose Git remotes as auth/plain/unsupported"], + ["compare", "[--repo PATH]", "read-only", "compare remote/store with marker and auth masks"], ["add", "REMOTE_ID", "tokens.json", "add an empty token skeleton for manual editing"], ["read", "[--server ENDPOINT]", "tokens.json", "show servers, remote ids and tokens"], ["stats", "[--repo PATH]", "repo + tokens.json", "compare remote URLs with local token store"], @@ -2530,16 +2582,18 @@ def print_tokens_overview() -> None: print_table( ["case", "command"], [ - ["scan launcher repo", "./rvctl tokens scan"], ["list token store", "./rvctl tokens list store"], ["list launcher remotes", "./rvctl tokens list remote"], + ["scan launcher remotes", "./rvctl tokens scan"], + ["compare launcher state", "./rvctl tokens compare"], ["read remote r1 into store", "./rvctl tokens sync remote r1"], ["refresh r1 metadata", "./rvctl tokens update r1"], ["write store r1 to remote", "./rvctl tokens sync store r1 --repo PATH"], ["remove r1 from store", "./rvctl tokens remove store r1"], ["remove Git remote r1", "./rvctl tokens remove remote r1"], ["scan selected card", "./rvctl tokens scan --repo ~/dev/workspace/rv/series/inf/03"], - ["compare state", "./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03"], + ["compare selected card", "./rvctl tokens compare --repo ~/dev/workspace/rv/series/inf/03"], + ["stats selected card", "./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03"], ["write auth to r1", "./rvctl tokens write --repo PATH --remote r1 --server URL"], ], ) @@ -2633,12 +2687,22 @@ def build_parser() -> argparse.ArgumentParser: tokens_scan_parser = tokens_subparsers.add_parser( "scan", - help="Read repo remotes and tokens.json, then print paired token rows.", + help="Scan Git remotes and print auth/plain/unsupported URL diagnostics.", ) tokens_scan_parser.add_argument( "--repo", help="Path inside a target git repo. Default: repo containing rvctl.", ) + tokens_scan_parser.add_argument("--server", help="Filter output to one server endpoint.") + + tokens_compare_parser = tokens_subparsers.add_parser( + "compare", + help="Compare repo remotes with tokens.json and print paired token rows.", + ) + tokens_compare_parser.add_argument( + "--repo", + help="Path inside a target git repo. Default: repo containing rvctl.", + ) tokens_list_parser = tokens_subparsers.add_parser( "list", @@ -2773,6 +2837,9 @@ def main() -> int: if args.tokens_command == "scan": run_tokens_scan(config, args) return 0 + if args.tokens_command == "compare": + run_tokens_compare(config, args) + return 0 if args.tokens_command == "list": run_tokens_list(config, args) return 0