From ffd12c99055a26708d22df49c205d3910e9e0c10 Mon Sep 17 00:00:00 2001 From: mpabi Date: Mon, 27 Apr 2026 19:59:45 +0200 Subject: [PATCH] Strip remote credentials without deleting remotes --- README.md | 4 ++-- doc/rvctl.md | 8 +++++--- doc/tokens.md | 4 +++- rvctl.py | 33 +++++++++++++++++++++------------ 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 98afb98..324e20f 100644 --- a/README.md +++ b/README.md @@ -180,8 +180,8 @@ uprawnien; bez zgodnego wpisu maja wartosc `?????????`, `?????` albo `????`. Zapis z remote do `tokens.json` robi `tokens sync remote r1`. Odczyt `valid` i uprawnien z API robi `tokens update r1`. Zapis z `tokens.json` do remota robi `tokens sync store r1`. -Usuniecie wpisu robi `tokens remove store r1`, a usuniecie git remota -`tokens remove remote r1`. +Usuniecie wpisu robi `tokens remove store r1`, a usuniecie poswiadczen z URL-a +git remota robi `tokens remove remote r1`. Kolumna `valid` oznacza, czy token zostal zaakceptowany przez API teraz. Jesli przy tokenie w `tokens.json` zapiszesz `expires_at`, `valid` moze pokazac date wygasniecia; bez daty poprawny token pokazuje `forever`. diff --git a/doc/rvctl.md b/doc/rvctl.md index 9bb8694..13f63be 100644 --- a/doc/rvctl.md +++ b/doc/rvctl.md @@ -437,15 +437,17 @@ Przyklad: ## `tokens remove store|remote|both REMOTE_ID` -Usuwa rekord z `tokens.json`, git remote albo oba miejsca. +Usuwa rekord z `tokens.json`, poswiadczenia z URL-a git remota albo oba +miejsca. `tokens remove remote` zostawia sam git remote, ale zapisuje jego URL +bez `LOGIN:TOKEN@`. Domyslnym repo dla `remote` i `both` jest repo, w ktorym lezy `rvctl`. Inne repo mozna wskazac przez `--repo PATH`. Przelaczniki: - `--repo PATH` - Repo, z ktorego ma byc usuniety git remote. Domyslnie repo zawierajace - `rvctl`. + Repo, w ktorym ma byc wyczyszczony URL git remota. Domyslnie repo + zawierajace `rvctl`. - `--server ENDPOINT` Endpoint serwera, jesli `tokens.json` ma kilka rekordow o tym samym `id`. - `--dry-run` diff --git a/doc/tokens.md b/doc/tokens.md index 383b018..9d85276 100644 --- a/doc/tokens.md +++ b/doc/tokens.md @@ -29,7 +29,9 @@ Kierunek jest jawny: - `tokens sync remote r1` czyta git remote `r1` i zapisuje rekord do `tokens.json` - `tokens sync store r1` czyta `tokens.json` i zapisuje auth do git remote `r1` - `tokens update r1` nie synchronizuje sekretu, tylko pobiera metadane z API -- `tokens remove ... r1` usuwa rekord ze store, git remote albo oba miejsca +- `tokens remove store r1` usuwa rekord z `tokens.json` +- `tokens remove remote r1` usuwa poswiadczenia z URL-a git remota, ale zostawia remote +- `tokens remove both r1` usuwa rekord ze store i poswiadczenia z URL-a git remota ## Format `tokens.json` diff --git a/rvctl.py b/rvctl.py index 9af7734..0afeb54 100644 --- a/rvctl.py +++ b/rvctl.py @@ -1511,10 +1511,10 @@ def list_remote_rows(repo_servers: dict[str, dict], server_filter: str | None = "user": str(row.get("user", "")), "remote": str(row.get("remote", "")), "token": short_secret(token_value) if token_value else "", - "valid": "", - "scope_mask": "", - "org_mask": "", - "repo_mask": "", + "valid": "?", + "scope_mask": "?????????", + "org_mask": "?????", + "repo_mask": "????", } ) return rows @@ -2008,7 +2008,7 @@ def remove_token_from_store( } -def remove_git_remote(repo_path: Path, remote_id: str, dry_run: bool = False) -> dict[str, str]: +def remove_git_remote_credentials(repo_path: Path, remote_id: str, dry_run: bool = False) -> dict[str, str]: repo_root = git_repo_root(repo_path) if repo_root is None: raise SystemExit(f"Missing git repo at path: {repo_path}") @@ -2021,17 +2021,26 @@ def remove_git_remote(repo_path: Path, remote_id: str, dry_run: bool = False) -> "removed": "0", "status": "missing", } + sanitized_url, had_credentials = sanitize_remote_url(remote_url) + if not had_credentials: + return { + "repo_root": str(repo_root), + "remote": remote_id, + "url": sanitized_url, + "removed": "0", + "status": "no_credentials", + } if not dry_run: subprocess.run( - ["git", "-C", str(repo_root), "remote", "remove", remote_id], + ["git", "-C", str(repo_root), "remote", "set-url", remote_id, sanitized_url], check=True, ) return { "repo_root": str(repo_root), "remote": remote_id, - "url": safe_remote_url_label(remote_url), + "url": sanitized_url, "removed": "1", "status": "dry-run" if dry_run else "removed", } @@ -2044,7 +2053,7 @@ def run_tokens_remove(config: WorkspaceConfig, args: argparse.Namespace) -> None return if args.target == "remote": - result = remove_git_remote(resolve_launcher_repo_argument(args.repo), args.remote_id, args.dry_run) + result = remove_git_remote_credentials(resolve_launcher_repo_argument(args.repo), args.remote_id, args.dry_run) print_token_action_result(result) return @@ -2052,7 +2061,7 @@ def run_tokens_remove(config: WorkspaceConfig, args: argparse.Namespace) -> None repo_path = resolve_launcher_repo_argument(args.repo) if not args.dry_run: remove_token_from_store(config, args.remote_id, args.server, dry_run=True) - remote_result = remove_git_remote(repo_path, args.remote_id, args.dry_run) + remote_result = remove_git_remote_credentials(repo_path, args.remote_id, args.dry_run) print_token_action_result(remote_result) print() store_result = remove_token_from_store(config, args.remote_id, args.server, args.dry_run) @@ -2520,7 +2529,7 @@ def print_tokens_overview() -> None: ["stats", "[--repo PATH]", "repo + tokens.json", "compare remote URLs with local token store"], ["sync remote", "REMOTE_ID [--repo PATH]", "repo -> tokens.json", "copy one remote URL into the store"], ["sync store", "REMOTE_ID [--repo PATH]", "tokens.json -> repo", "write one store record into a remote URL"], - ["remove", "store|remote|both REMOTE_ID", "selected", "remove token store record or Git remote"], + ["remove", "store|remote|both REMOTE_ID", "selected", "remove store record or remote credentials"], ["write", "--remote R [--replace]", "tokens.json -> repo", "write selected token into a remote URL"], ["update", "REMOTE_ID", "API -> tokens.json", "refresh valid/scope/org/repo metadata"], ], @@ -2537,7 +2546,7 @@ def print_tokens_overview() -> None: ["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"], + ["remove auth from 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"], ["write auth to r1", "./rvctl tokens write --repo PATH --remote r1 --server URL"], @@ -2698,7 +2707,7 @@ def build_parser() -> argparse.ArgumentParser: tokens_remove_parser = tokens_subparsers.add_parser( "remove", - help="Remove a token store record, a Git remote, or both.", + help="Remove a token store record, Git remote credentials, or both.", ) tokens_remove_parser.add_argument("target", choices=["store", "remote", "both"], help="Where to remove REMOTE_ID from.") tokens_remove_parser.add_argument("remote_id", help="Remote id, for example 'r1' or 'r1a'.")