davidtran999 commited on
Commit
2e00b5b
·
verified ·
1 Parent(s): 23f9cd1

Upload backend/scripts/update_hf_space_secrets.py with huggingface_hub

Browse files
backend/scripts/update_hf_space_secrets.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Utility to push Hugging Face Space secrets from a local env file.
4
+
5
+ Usage:
6
+ export HF_TOKEN=hf_xxx # token with write access to the Space
7
+ python backend/scripts/update_hf_space_secrets.py \
8
+ --space davidttran999/hue-portal-backendDocker \
9
+ --secrets-file ops/hf.secrets.env
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import argparse
15
+ import os
16
+ import sys
17
+ from pathlib import Path
18
+ from typing import Dict
19
+
20
+ import requests
21
+
22
+
23
+ def parse_env_file(path: Path) -> Dict[str, str]:
24
+ """
25
+ Load KEY=VALUE pairs from the provided file.
26
+
27
+ Blank lines and comments starting with `#` are ignored.
28
+ """
29
+ if not path.exists():
30
+ raise FileNotFoundError(f"Secrets file not found: {path}")
31
+
32
+ secrets: Dict[str, str] = {}
33
+ for raw_line in path.read_text(encoding="utf-8").splitlines():
34
+ line = raw_line.strip()
35
+ if not line or line.startswith("#"):
36
+ continue
37
+ if "=" not in line:
38
+ raise ValueError(f"Invalid secret line (missing '='): {raw_line}")
39
+ key, value = line.split("=", 1)
40
+ secrets[key.strip()] = value.strip()
41
+
42
+ if not secrets:
43
+ raise ValueError(f"No secrets detected in {path}")
44
+ return secrets
45
+
46
+
47
+ def upsert_secret(space_id: str, token: str, key: str, value: str) -> None:
48
+ """Create or update a secret for the given Hugging Face Space."""
49
+ url = f"https://huggingface.co/api/spaces/{space_id}/secrets"
50
+ headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
51
+ response = requests.post(url, headers=headers, json={"key": key, "value": value}, timeout=30)
52
+ if response.status_code != 200:
53
+ raise RuntimeError(
54
+ f"Failed to upsert secret '{key}'. "
55
+ f"Status {response.status_code}: {response.text}"
56
+ )
57
+
58
+
59
+ def build_parser() -> argparse.ArgumentParser:
60
+ """Configure CLI options."""
61
+ parser = argparse.ArgumentParser(description="Sync secrets to a Hugging Face Space.")
62
+ parser.add_argument(
63
+ "--space",
64
+ required=True,
65
+ help="Space identifier in the form owner/space (e.g. davidttran999/hue-portal-backendDocker).",
66
+ )
67
+ parser.add_argument(
68
+ "--secrets-file",
69
+ default="ops/hf.secrets.env",
70
+ help="Path to file containing KEY=VALUE entries (default: %(default)s).",
71
+ )
72
+ parser.add_argument(
73
+ "--token-env",
74
+ default="HF_TOKEN",
75
+ help="Environment variable that stores the Hugging Face access token (default: %(default)s).",
76
+ )
77
+ return parser
78
+
79
+
80
+ def main() -> None:
81
+ """CLI entry point."""
82
+ parser = build_parser()
83
+ args = parser.parse_args()
84
+
85
+ token = os.environ.get(args.token_env)
86
+ if not token:
87
+ parser.error(f"Environment variable {args.token_env} is not set.")
88
+
89
+ secrets = parse_env_file(Path(args.secrets_file).expanduser())
90
+ for key, value in secrets.items():
91
+ upsert_secret(args.space, token, key, value)
92
+ print(f"✅ Synced secret '{key}' to {args.space}")
93
+
94
+
95
+ if __name__ == "__main__":
96
+ try:
97
+ main()
98
+ except Exception as exc: # pylint: disable=broad-except
99
+ print(f"❌ {exc}", file=sys.stderr)
100
+ sys.exit(1)
101
+