File size: 4,748 Bytes
2e60707
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/env python3
"""
List all variables and secrets for a Hugging Face Space.

Usage:
    export HF_TOKEN=hf_xxx
    python backend/scripts/list_hf_space_config.py --space davidtran999/hue-portal-backend
"""

from __future__ import annotations

import argparse
import os
import sys
from typing import Dict, List, Optional

import requests


def get_space_variables(space_id: str, token: str) -> Dict[str, str]:
    """Fetch all environment variables for a Space."""
    url = f"https://huggingface.co/api/spaces/{space_id}/variables"
    headers = {"Authorization": f"Bearer {token}"}
    try:
        response = requests.get(url, headers=headers, timeout=30)
        if response.status_code == 200:
            data = response.json()
            # Handle both list and dict responses
            if isinstance(data, list):
                return {item["key"]: item.get("value", "") for item in data}
            elif isinstance(data, dict):
                return {k: v.get("value", "") if isinstance(v, dict) else v for k, v in data.items()}
            else:
                return {}
        elif response.status_code == 404:
            return {}
        else:
            print(f"⚠️  Failed to fetch variables: {response.status_code} - {response.text}", file=sys.stderr)
            return {}
    except Exception as e:
        print(f"⚠️  Error fetching variables: {e}", file=sys.stderr)
        return {}


def get_space_secrets(space_id: str, token: str) -> List[str]:
    """Fetch all secret keys (values are hidden) for a Space."""
    url = f"https://huggingface.co/api/spaces/{space_id}/secrets"
    headers = {"Authorization": f"Bearer {token}"}
    try:
        response = requests.get(url, headers=headers, timeout=30)
        if response.status_code == 200:
            data = response.json()
            # Handle both list and dict responses
            if isinstance(data, list):
                return [item["key"] for item in data]
            elif isinstance(data, dict):
                return list(data.keys())
            else:
                return []
        elif response.status_code == 404:
            return []
        else:
            print(f"⚠️  Failed to fetch secrets: {response.status_code} - {response.text}", file=sys.stderr)
            return []
    except Exception as e:
        print(f"⚠️  Error fetching secrets: {e}", file=sys.stderr)
        return []


def build_parser() -> argparse.ArgumentParser:
    """Configure CLI options."""
    parser = argparse.ArgumentParser(description="List variables and secrets for a Hugging Face Space.")
    parser.add_argument(
        "--space",
        required=True,
        help="Space identifier in the form owner/space (e.g. davidtran999/hue-portal-backend).",
    )
    parser.add_argument(
        "--token-env",
        default="HF_TOKEN",
        help="Environment variable that stores the Hugging Face access token (default: %(default)s).",
    )
    return parser


def main() -> None:
    """CLI entry point."""
    parser = build_parser()
    args = parser.parse_args()

    token = os.environ.get(args.token_env)
    if not token:
        parser.error(f"Environment variable {args.token_env} is not set.")

    print(f"📋 Listing configuration for: {args.space}\n")

    # Fetch variables
    variables = get_space_variables(args.space, token)
    print("🔧 Environment Variables:")
    if variables:
        for key, value in sorted(variables.items()):
            # Mask sensitive values
            if "password" in key.lower() or "secret" in key.lower() or "token" in key.lower() or "key" in key.lower():
                masked = value[:4] + "***" if len(value) > 4 else "***"
                print(f"  {key} = {masked}")
            else:
                print(f"  {key} = {value}")
    else:
        print("  (none)")

    print()

    # Fetch secrets
    secrets = get_space_secrets(args.space, token)
    print("🔐 Secrets:")
    if secrets:
        for key in sorted(secrets):
            print(f"  {key} = <hidden>")
    else:
        print("  (none)")

    print()

    # Check for collisions
    var_keys = set(variables.keys())
    secret_keys = set(secrets)
    collisions = var_keys & secret_keys

    if collisions:
        print("❌ COLLISIONS DETECTED (same name in both Variables and Secrets):")
        for key in sorted(collisions):
            print(f"  ⚠️  {key}")
        print("\n💡 Fix: Remove from Variables (keep only in Secrets)")
        sys.exit(1)
    else:
        print("✅ No collisions detected")


if __name__ == "__main__":
    try:
        main()
    except Exception as exc:  # pylint: disable=broad-except
        print(f"❌ {exc}", file=sys.stderr)
        sys.exit(1)