davidtran999 commited on
Commit
2e60707
·
verified ·
1 Parent(s): b0efede

Upload backend/scripts/list_hf_space_config.py with huggingface_hub

Browse files
backend/scripts/list_hf_space_config.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ List all variables and secrets for a Hugging Face Space.
4
+
5
+ Usage:
6
+ export HF_TOKEN=hf_xxx
7
+ python backend/scripts/list_hf_space_config.py --space davidtran999/hue-portal-backend
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import argparse
13
+ import os
14
+ import sys
15
+ from typing import Dict, List, Optional
16
+
17
+ import requests
18
+
19
+
20
+ def get_space_variables(space_id: str, token: str) -> Dict[str, str]:
21
+ """Fetch all environment variables for a Space."""
22
+ url = f"https://huggingface.co/api/spaces/{space_id}/variables"
23
+ headers = {"Authorization": f"Bearer {token}"}
24
+ try:
25
+ response = requests.get(url, headers=headers, timeout=30)
26
+ if response.status_code == 200:
27
+ data = response.json()
28
+ # Handle both list and dict responses
29
+ if isinstance(data, list):
30
+ return {item["key"]: item.get("value", "") for item in data}
31
+ elif isinstance(data, dict):
32
+ return {k: v.get("value", "") if isinstance(v, dict) else v for k, v in data.items()}
33
+ else:
34
+ return {}
35
+ elif response.status_code == 404:
36
+ return {}
37
+ else:
38
+ print(f"⚠️ Failed to fetch variables: {response.status_code} - {response.text}", file=sys.stderr)
39
+ return {}
40
+ except Exception as e:
41
+ print(f"⚠️ Error fetching variables: {e}", file=sys.stderr)
42
+ return {}
43
+
44
+
45
+ def get_space_secrets(space_id: str, token: str) -> List[str]:
46
+ """Fetch all secret keys (values are hidden) for a Space."""
47
+ url = f"https://huggingface.co/api/spaces/{space_id}/secrets"
48
+ headers = {"Authorization": f"Bearer {token}"}
49
+ try:
50
+ response = requests.get(url, headers=headers, timeout=30)
51
+ if response.status_code == 200:
52
+ data = response.json()
53
+ # Handle both list and dict responses
54
+ if isinstance(data, list):
55
+ return [item["key"] for item in data]
56
+ elif isinstance(data, dict):
57
+ return list(data.keys())
58
+ else:
59
+ return []
60
+ elif response.status_code == 404:
61
+ return []
62
+ else:
63
+ print(f"⚠️ Failed to fetch secrets: {response.status_code} - {response.text}", file=sys.stderr)
64
+ return []
65
+ except Exception as e:
66
+ print(f"⚠️ Error fetching secrets: {e}", file=sys.stderr)
67
+ return []
68
+
69
+
70
+ def build_parser() -> argparse.ArgumentParser:
71
+ """Configure CLI options."""
72
+ parser = argparse.ArgumentParser(description="List variables and secrets for a Hugging Face Space.")
73
+ parser.add_argument(
74
+ "--space",
75
+ required=True,
76
+ help="Space identifier in the form owner/space (e.g. davidtran999/hue-portal-backend).",
77
+ )
78
+ parser.add_argument(
79
+ "--token-env",
80
+ default="HF_TOKEN",
81
+ help="Environment variable that stores the Hugging Face access token (default: %(default)s).",
82
+ )
83
+ return parser
84
+
85
+
86
+ def main() -> None:
87
+ """CLI entry point."""
88
+ parser = build_parser()
89
+ args = parser.parse_args()
90
+
91
+ token = os.environ.get(args.token_env)
92
+ if not token:
93
+ parser.error(f"Environment variable {args.token_env} is not set.")
94
+
95
+ print(f"📋 Listing configuration for: {args.space}\n")
96
+
97
+ # Fetch variables
98
+ variables = get_space_variables(args.space, token)
99
+ print("🔧 Environment Variables:")
100
+ if variables:
101
+ for key, value in sorted(variables.items()):
102
+ # Mask sensitive values
103
+ if "password" in key.lower() or "secret" in key.lower() or "token" in key.lower() or "key" in key.lower():
104
+ masked = value[:4] + "***" if len(value) > 4 else "***"
105
+ print(f" {key} = {masked}")
106
+ else:
107
+ print(f" {key} = {value}")
108
+ else:
109
+ print(" (none)")
110
+
111
+ print()
112
+
113
+ # Fetch secrets
114
+ secrets = get_space_secrets(args.space, token)
115
+ print("🔐 Secrets:")
116
+ if secrets:
117
+ for key in sorted(secrets):
118
+ print(f" {key} = <hidden>")
119
+ else:
120
+ print(" (none)")
121
+
122
+ print()
123
+
124
+ # Check for collisions
125
+ var_keys = set(variables.keys())
126
+ secret_keys = set(secrets)
127
+ collisions = var_keys & secret_keys
128
+
129
+ if collisions:
130
+ print("❌ COLLISIONS DETECTED (same name in both Variables and Secrets):")
131
+ for key in sorted(collisions):
132
+ print(f" ⚠️ {key}")
133
+ print("\n💡 Fix: Remove from Variables (keep only in Secrets)")
134
+ sys.exit(1)
135
+ else:
136
+ print("✅ No collisions detected")
137
+
138
+
139
+ if __name__ == "__main__":
140
+ try:
141
+ main()
142
+ except Exception as exc: # pylint: disable=broad-except
143
+ print(f"❌ {exc}", file=sys.stderr)
144
+ sys.exit(1)
145
+