Add token skeleton command
This commit is contained in:
@@ -159,6 +159,7 @@ Podstawowe komendy tokenow:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
./rvctl tokens scan
|
./rvctl tokens scan
|
||||||
|
./rvctl tokens add t1
|
||||||
./rvctl tokens read
|
./rvctl tokens read
|
||||||
./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03
|
./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03
|
||||||
```
|
```
|
||||||
|
|||||||
+39
-9
@@ -291,9 +291,9 @@ Przyklady:
|
|||||||
|
|
||||||
## `tokens scan`
|
## `tokens scan`
|
||||||
|
|
||||||
Skanuje remote URL-e w repo oraz lokalny `tokens.json`, laczy wpisy w pary po
|
Czyta 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
|
endpoincie, nazwie remota, token id, wartosci tokena, org i repo, a potem
|
||||||
na token.
|
pokazuje jeden logiczny wiersz na token. Komenda jest read-only.
|
||||||
|
|
||||||
Przelaczniki:
|
Przelaczniki:
|
||||||
|
|
||||||
@@ -305,8 +305,8 @@ Typowy wynik:
|
|||||||
```text
|
```text
|
||||||
tokens
|
tokens
|
||||||
item server proto host org repo user remote token_ref token valid scope org repo
|
item server proto host org repo user remote token_ref token valid scope org repo
|
||||||
---- ------ ----- ------------------ --------- ----------- ---- ------ --------- ------------ ----- awrop- oawrc- oawr--
|
---- ------ ----- ------------------ --------- ----------- ---- ------ --------- ------------ ------------------- aAimnopru oawrc- oawr--
|
||||||
1 gitea http 77.90.8.171:3001 edu-tools rv-launcher u1 r1 t1 * e59cc...13be forever +---+ +++++ ++++
|
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
|
`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:
|
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
|
- `org` ma pozycje `oawrc`: owner, admin, write, read, create repo
|
||||||
- `repo` ma pozycje `oawr`: owner, admin, write, read
|
- `repo` ma pozycje `oawr`: owner, admin, write, read
|
||||||
- `+` oznacza wlaczone, `-` wylaczone, `?` nie wczytano, `!` blad wczytania
|
- `+` oznacza wlaczone, `-` wylaczone, `?` nie wczytano, `!` blad wczytania
|
||||||
@@ -329,6 +330,35 @@ Przyklad:
|
|||||||
./rvctl tokens scan --repo ~/dev/workspace/rv/series/inf/03
|
./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`
|
## `tokens read`
|
||||||
|
|
||||||
Pokazuje zawartosc `tokens/tokens.json` w podziale na endpointy serwerow.
|
Pokazuje zawartosc `tokens/tokens.json` w podziale na endpointy serwerow.
|
||||||
@@ -384,8 +414,8 @@ token_path<TAB>...
|
|||||||
|
|
||||||
tokens
|
tokens
|
||||||
item server proto host org repo user remote token_ref token valid scope org repo
|
item server proto host org repo user remote token_ref token valid scope org repo
|
||||||
---- ------ ----- ------------------ --------- ----------- ---- ------ --------- ------------ ----- awrop- oawrc- oawr--
|
---- ------ ----- ------------------ --------- ----------- ---- ------ --------- ------------ ------------------- aAimnopru oawrc- oawr--
|
||||||
1 gitea http 77.90.8.171:3001 edu-tools rv-launcher u1 r1 t1 * e59cc...13be forever +---+ +++++ ++++
|
1 gitea http 77.90.8.171:3001 edu-tools rv-launcher u1 r1 t1 * e59cc...13be forever -----w--- +++++ ++++
|
||||||
|
|
||||||
status
|
status
|
||||||
item<TAB>value
|
item<TAB>value
|
||||||
@@ -452,7 +482,7 @@ Przelaczniki:
|
|||||||
- `--replace`
|
- `--replace`
|
||||||
Nadpisuje inne auth przy `--from store`.
|
Nadpisuje inne auth przy `--from store`.
|
||||||
- `--dry-run`
|
- `--dry-run`
|
||||||
Pokazuje plan bez zapisu przy `--from store`.
|
Pokazuje plan bez zapisu.
|
||||||
|
|
||||||
Przyklady:
|
Przyklady:
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,19 @@ Pokazuje zawartosc `tokens.json`.
|
|||||||
./rvctl tokens read --show-secrets
|
./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`
|
### `tokens stats`
|
||||||
|
|
||||||
Pokazuje kontekst, tabele `tokens` i podsumowanie statusow endpointow.
|
Pokazuje kontekst, tabele `tokens` i podsumowanie statusow endpointow.
|
||||||
|
|||||||
@@ -77,8 +77,7 @@
|
|||||||
"minLength": 1
|
"minLength": 1
|
||||||
},
|
},
|
||||||
"value": {
|
"value": {
|
||||||
"type": "string",
|
"type": "string"
|
||||||
"minLength": 1
|
|
||||||
},
|
},
|
||||||
"server": {
|
"server": {
|
||||||
"$ref": "#/$defs/server"
|
"$ref": "#/$defs/server"
|
||||||
|
|||||||
@@ -397,10 +397,12 @@ def normalize_v3_token(config: WorkspaceConfig, raw_token: dict) -> dict | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
token_id = raw_token.get("token_id") or raw_token.get("id") or raw_token.get("token_ref")
|
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:
|
if not isinstance(token_id, str) or not token_id:
|
||||||
return None
|
return None
|
||||||
if not isinstance(token_value, str) or not token_value:
|
if not isinstance(token_value, str):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
server_record = normalize_server_record(config, raw_token.get("server", {}))
|
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", []):
|
for row in server_entry.get("tokens", []):
|
||||||
token_value = row.get("token_value", "")
|
token_value = row.get("token_value", "")
|
||||||
token_id = row.get("token_id", "")
|
token_id = row.get("token_id", "")
|
||||||
if token_value and token_id:
|
if token_id:
|
||||||
rows.append(
|
rows.append(
|
||||||
{
|
{
|
||||||
"endpoint": endpoint,
|
"endpoint": endpoint,
|
||||||
@@ -1620,6 +1622,48 @@ def run_tokens_stats(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
|||||||
print_status_counts(status_counts)
|
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:
|
def run_tokens_write(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||||
repo_path = resolve_repo_argument(args.repo)
|
repo_path = resolve_repo_argument(args.repo)
|
||||||
repo_root = git_repo_root(repo_path)
|
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)
|
server_endpoint = token_server_endpoint(token_record)
|
||||||
token_id = str(token_record.get("token_id", ""))
|
token_id = str(token_record.get("token_id", ""))
|
||||||
token_value = str(token_record.get("value", ""))
|
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)
|
final_url = credentialed_remote_url(target_url, token_id, token_value)
|
||||||
status = "added" if existing_remote_url is None else "updated"
|
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"],
|
["list-cards", "[series]", "list cards in a selected series"],
|
||||||
["tmux-container", "[series] [card]", "start tmux with container in pane 0"],
|
["tmux-container", "[series] [card]", "start tmux with container in pane 0"],
|
||||||
["submission", "[series] [card] --class K --nick N", "prepare answer repo and student branch"],
|
["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()
|
print()
|
||||||
@@ -2008,6 +2054,7 @@ def print_tokens_overview() -> None:
|
|||||||
["command", "common options", "direction", "purpose"],
|
["command", "common options", "direction", "purpose"],
|
||||||
[
|
[
|
||||||
["scan", "[--repo PATH]", "read-only", "print token table with remote/store marker and auth masks"],
|
["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"],
|
["read", "[--server ENDPOINT]", "tokens.json", "show servers, token ids and remotes"],
|
||||||
["stats", "[--repo PATH]", "repo + tokens.json", "compare remote URLs with local token store"],
|
["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"],
|
["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("--server", help="Filter output to one server endpoint.")
|
||||||
tokens_read_parser.add_argument("--show-secrets", action="store_true", help="Print full token values.")
|
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(
|
tokens_stats_parser = tokens_subparsers.add_parser(
|
||||||
"stats",
|
"stats",
|
||||||
help="Print per-server token statistics from tokens.json.",
|
help="Print per-server token statistics from tokens.json.",
|
||||||
@@ -2197,6 +2257,9 @@ def main() -> int:
|
|||||||
if args.tokens_command == "scan":
|
if args.tokens_command == "scan":
|
||||||
run_tokens_scan(config, args)
|
run_tokens_scan(config, args)
|
||||||
return 0
|
return 0
|
||||||
|
if args.tokens_command == "add":
|
||||||
|
run_tokens_add(config, args)
|
||||||
|
return 0
|
||||||
if args.tokens_command == "read":
|
if args.tokens_command == "read":
|
||||||
run_tokens_read(config, args)
|
run_tokens_read(config, args)
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
Reference in New Issue
Block a user