Add token skeleton command
This commit is contained in:
@@ -159,6 +159,7 @@ Podstawowe komendy tokenow:
|
||||
|
||||
```bash
|
||||
./rvctl tokens scan
|
||||
./rvctl tokens add t1
|
||||
./rvctl tokens read
|
||||
./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03
|
||||
```
|
||||
|
||||
+41
-11
@@ -291,9 +291,9 @@ Przyklady:
|
||||
|
||||
## `tokens scan`
|
||||
|
||||
Skanuje remote URL-e w repo oraz lokalny `tokens.json`, laczy wpisy w pary po
|
||||
endpoincie, userze i wartosci tokena, a potem pokazuje jeden logiczny wiersz
|
||||
na token.
|
||||
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.
|
||||
|
||||
Przelaczniki:
|
||||
|
||||
@@ -304,9 +304,9 @@ Typowy wynik:
|
||||
|
||||
```text
|
||||
tokens
|
||||
item server proto host org repo user remote token_ref token valid scope org repo
|
||||
---- ------ ----- ------------------ --------- ----------- ---- ------ --------- ------------ ----- awrop- oawrc- oawr--
|
||||
1 gitea http 77.90.8.171:3001 edu-tools rv-launcher u1 r1 t1 * e59cc...13be forever +---+ +++++ ++++
|
||||
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 t1 * e59cc...13be forever -----w--- +++++ ++++
|
||||
```
|
||||
|
||||
`token_ref` jest komorka stalej szerokosci: nazwa tokena jest po lewej, a marker
|
||||
@@ -316,7 +316,8 @@ oraz uprawnienia zostaly wczytane. Marker `R` oznacza token tylko w remote, a
|
||||
|
||||
Maski uprawnien:
|
||||
|
||||
- `scope` ma pozycje `awrop`: `all`, `write:repository`, `read:repository`, organization scope, `public-only`
|
||||
- `scope` ma pozycje `aAimnopru`: activitypub, admin, issue, misc, notification, organization, package, repository, user
|
||||
- w `scope`: `w` oznacza read/write, `r` read, `-` brak dostepu
|
||||
- `org` ma pozycje `oawrc`: owner, admin, write, read, create repo
|
||||
- `repo` ma pozycje `oawr`: owner, admin, write, read
|
||||
- `+` oznacza wlaczone, `-` wylaczone, `?` nie wczytano, `!` blad wczytania
|
||||
@@ -329,6 +330,35 @@ Przyklad:
|
||||
./rvctl tokens scan --repo ~/dev/workspace/rv/series/inf/03
|
||||
```
|
||||
|
||||
## `tokens add TOKEN_ID`
|
||||
|
||||
Dodaje pusty szkielet tokena do `tokens.json`. Pole `value` jest puste i trzeba
|
||||
je uzupelnic recznie przed uzyciem tokena.
|
||||
|
||||
Przelaczniki:
|
||||
|
||||
- `--server ENDPOINT`
|
||||
Endpoint serwera. Domyslnie `git.base_url` z `workspace.json`.
|
||||
- `--value TOKEN`
|
||||
Opcjonalna wartosc tokena. Domyslnie pusta.
|
||||
- `--user NAME`
|
||||
Opcjonalny opis usera API.
|
||||
- `--remote NAME`
|
||||
Opcjonalny remote powiazany z tokenem.
|
||||
- `--org NAME`
|
||||
Opcjonalna organizacja dla remota.
|
||||
- `--repo NAME`
|
||||
Opcjonalne repo dla remota.
|
||||
- `--dry-run`
|
||||
Pokazuje plan bez zapisu.
|
||||
|
||||
Przyklady:
|
||||
|
||||
```bash
|
||||
./rvctl tokens add r6
|
||||
./rvctl tokens add t1 --remote r1 --org edu-tools --repo rv-launcher
|
||||
```
|
||||
|
||||
## `tokens read`
|
||||
|
||||
Pokazuje zawartosc `tokens/tokens.json` w podziale na endpointy serwerow.
|
||||
@@ -383,9 +413,9 @@ repo_root<TAB>...
|
||||
token_path<TAB>...
|
||||
|
||||
tokens
|
||||
item server proto host org repo user remote token_ref token valid scope org repo
|
||||
---- ------ ----- ------------------ --------- ----------- ---- ------ --------- ------------ ----- awrop- oawrc- oawr--
|
||||
1 gitea http 77.90.8.171:3001 edu-tools rv-launcher u1 r1 t1 * e59cc...13be forever +---+ +++++ ++++
|
||||
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 t1 * e59cc...13be forever -----w--- +++++ ++++
|
||||
|
||||
status
|
||||
item<TAB>value
|
||||
@@ -452,7 +482,7 @@ Przelaczniki:
|
||||
- `--replace`
|
||||
Nadpisuje inne auth przy `--from store`.
|
||||
- `--dry-run`
|
||||
Pokazuje plan bez zapisu przy `--from store`.
|
||||
Pokazuje plan bez zapisu.
|
||||
|
||||
Przyklady:
|
||||
|
||||
|
||||
@@ -161,6 +161,19 @@ Pokazuje zawartosc `tokens.json`.
|
||||
./rvctl tokens read --show-secrets
|
||||
```
|
||||
|
||||
### `tokens add`
|
||||
|
||||
Dodaje pusty szkielet tokena do `tokens.json`. Pole `value` zostaje puste, zeby
|
||||
mozna bylo recznie wkleic sekret.
|
||||
|
||||
```bash
|
||||
./rvctl tokens add t1
|
||||
./rvctl tokens add r6 --server http://77.90.8.171:3001
|
||||
./rvctl tokens add t1 --remote r1 --org edu-tools --repo rv-launcher
|
||||
```
|
||||
|
||||
`tokens write` nie uzyje pustego tokena. Najpierw trzeba uzupelnic `value`.
|
||||
|
||||
### `tokens stats`
|
||||
|
||||
Pokazuje kontekst, tabele `tokens` i podsumowanie statusow endpointow.
|
||||
|
||||
@@ -77,8 +77,7 @@
|
||||
"minLength": 1
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
"type": "string"
|
||||
},
|
||||
"server": {
|
||||
"$ref": "#/$defs/server"
|
||||
|
||||
@@ -397,10 +397,12 @@ def normalize_v3_token(config: WorkspaceConfig, raw_token: dict) -> dict | None:
|
||||
return None
|
||||
|
||||
token_id = raw_token.get("token_id") or raw_token.get("id") or raw_token.get("token_ref")
|
||||
token_value = raw_token.get("value") or raw_token.get("token")
|
||||
token_value = raw_token.get("value")
|
||||
if token_value is None:
|
||||
token_value = raw_token.get("token")
|
||||
if not isinstance(token_id, str) or not token_id:
|
||||
return None
|
||||
if not isinstance(token_value, str) or not token_value:
|
||||
if not isinstance(token_value, str):
|
||||
return None
|
||||
|
||||
server_record = normalize_server_record(config, raw_token.get("server", {}))
|
||||
@@ -1154,7 +1156,7 @@ def token_store_rows(store_servers: dict[str, dict]) -> list[dict[str, str]]:
|
||||
for row in server_entry.get("tokens", []):
|
||||
token_value = row.get("token_value", "")
|
||||
token_id = row.get("token_id", "")
|
||||
if token_value and token_id:
|
||||
if token_id:
|
||||
rows.append(
|
||||
{
|
||||
"endpoint": endpoint,
|
||||
@@ -1620,6 +1622,48 @@ def run_tokens_stats(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||
print_status_counts(status_counts)
|
||||
|
||||
|
||||
def run_tokens_add(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||
server_url = (args.server or config.git.base_url).rstrip("/")
|
||||
server_info = server_info_from_url(config, server_url)
|
||||
if server_info is None:
|
||||
raise SystemExit(f"Only http/https server URLs are supported: {server_url}")
|
||||
|
||||
token_data = load_token_store(config)
|
||||
existing_token = find_token_record(token_data, server_info["endpoint"], args.token_id)
|
||||
if existing_token is not None:
|
||||
raise SystemExit(f"Token already exists in tokens.json: {server_info['endpoint']}:{args.token_id}")
|
||||
|
||||
token_record = {
|
||||
"token_id": args.token_id,
|
||||
"value": args.value or "",
|
||||
"server": server_record_from_info(server_info),
|
||||
"remotes": [],
|
||||
}
|
||||
if args.user:
|
||||
token_record["user"] = args.user
|
||||
if args.remote:
|
||||
token_record["remotes"].append(
|
||||
{
|
||||
"name": args.remote,
|
||||
"org": args.org or "",
|
||||
"repo": args.repo_name or "",
|
||||
}
|
||||
)
|
||||
|
||||
print(f"token_path\t{config.token_path}")
|
||||
print(f"server\t{server_info['endpoint']}")
|
||||
print(f"token_id\t{args.token_id}")
|
||||
print(f"value\t{'set' if token_record['value'] else 'empty'}")
|
||||
print(f"remote\t{args.remote or ''}")
|
||||
print(f"status\t{'dry-run' if args.dry_run else 'added'}")
|
||||
|
||||
if args.dry_run:
|
||||
return
|
||||
|
||||
token_data.setdefault("tokens", []).append(token_record)
|
||||
write_token_store(config, token_data)
|
||||
|
||||
|
||||
def run_tokens_write(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||
repo_path = resolve_repo_argument(args.repo)
|
||||
repo_root = git_repo_root(repo_path)
|
||||
@@ -1648,6 +1692,8 @@ def run_tokens_write(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||
server_endpoint = token_server_endpoint(token_record)
|
||||
token_id = str(token_record.get("token_id", ""))
|
||||
token_value = str(token_record.get("value", ""))
|
||||
if not token_value:
|
||||
raise SystemExit(f"Token value is empty in tokens.json: {server_endpoint}:{token_id}")
|
||||
|
||||
final_url = credentialed_remote_url(target_url, token_id, token_value)
|
||||
status = "added" if existing_remote_url is None else "updated"
|
||||
@@ -1971,7 +2017,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|read|stats|write|update", "manage tokens.json and Git remote credentials"],
|
||||
["tokens", "scan|add|read|stats|write|update", "manage tokens.json and Git remote credentials"],
|
||||
],
|
||||
)
|
||||
print()
|
||||
@@ -2008,6 +2054,7 @@ def print_tokens_overview() -> None:
|
||||
["command", "common options", "direction", "purpose"],
|
||||
[
|
||||
["scan", "[--repo PATH]", "read-only", "print token table with remote/store marker and auth masks"],
|
||||
["add", "TOKEN_ID", "tokens.json", "add an empty token skeleton for manual editing"],
|
||||
["read", "[--server ENDPOINT]", "tokens.json", "show servers, token ids and remotes"],
|
||||
["stats", "[--repo PATH]", "repo + tokens.json", "compare remote URLs with local token store"],
|
||||
["write", "--remote R [--replace]", "tokens.json -> repo", "write selected token into a remote URL"],
|
||||
@@ -2126,6 +2173,19 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
tokens_read_parser.add_argument("--server", help="Filter output to one server endpoint.")
|
||||
tokens_read_parser.add_argument("--show-secrets", action="store_true", help="Print full token values.")
|
||||
|
||||
tokens_add_parser = tokens_subparsers.add_parser(
|
||||
"add",
|
||||
help="Add an empty token skeleton to tokens.json.",
|
||||
)
|
||||
tokens_add_parser.add_argument("token_id", help="Token id, for example 't1' or 'r6'.")
|
||||
tokens_add_parser.add_argument("--server", help="Server endpoint. Default: git.base_url from workspace.json.")
|
||||
tokens_add_parser.add_argument("--value", default="", help="Optional token value. Default: empty for manual editing.")
|
||||
tokens_add_parser.add_argument("--user", help="Optional API user label.")
|
||||
tokens_add_parser.add_argument("--remote", help="Optional remote name to attach to this token.")
|
||||
tokens_add_parser.add_argument("--org", help="Optional remote organization.")
|
||||
tokens_add_parser.add_argument("--repo", dest="repo_name", help="Optional remote repository.")
|
||||
tokens_add_parser.add_argument("--dry-run", action="store_true", help="Print the planned token without writing it.")
|
||||
|
||||
tokens_stats_parser = tokens_subparsers.add_parser(
|
||||
"stats",
|
||||
help="Print per-server token statistics from tokens.json.",
|
||||
@@ -2197,6 +2257,9 @@ def main() -> int:
|
||||
if args.tokens_command == "scan":
|
||||
run_tokens_scan(config, args)
|
||||
return 0
|
||||
if args.tokens_command == "add":
|
||||
run_tokens_add(config, args)
|
||||
return 0
|
||||
if args.tokens_command == "read":
|
||||
run_tokens_read(config, args)
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user