bacpilot-backend / scripts /deploy_hf_space_api.py
debpc
Add Hugging Face API deployment script
f6352f9
Raw
History Blame Contribute Delete
5.25 kB
from __future__ import annotations
import argparse
import shutil
import sys
import time
from pathlib import Path
DEFAULT_REPO_ID = "shazhass/bacpilot-backend"
DEFAULT_DEPLOY_DIR = Path("/tmp/bacpilot_hf_deploy")
PATHS_TO_COPY = (
"app",
"Dockerfile",
"README.md",
"requirements.txt",
"pyproject.toml",
"Procfile",
"runtime.txt",
)
SECRET_PATH_PATTERNS = (
".env",
".env.",
".secrets",
"quality/private",
".git",
".venv",
"__pycache__",
)
SECRET_CONTENT_PATTERNS = (
"OPENROUTER_API_KEY=",
"SUPABASE_SERVICE_ROLE_KEY=",
"INTERNAL_GATEWAY_SECRET=",
"HF_TOKEN=",
"HUGGINGFACE_TOKEN=",
)
def build_deploy_folder(source_root: Path, deploy_root: Path) -> list[str]:
if deploy_root.exists():
shutil.rmtree(deploy_root)
deploy_root.mkdir(parents=True)
copied: list[str] = []
for relative_path in PATHS_TO_COPY:
src = source_root / relative_path
dst = deploy_root / relative_path
if not src.exists():
print(f"skip_missing={relative_path}")
continue
if src.is_dir():
shutil.copytree(
src,
dst,
ignore=shutil.ignore_patterns("__pycache__", "*.pyc", ".pytest_cache"),
)
else:
shutil.copy2(src, dst)
copied.append(relative_path)
return copied
def scan_for_sensitive_paths(deploy_root: Path) -> list[str]:
findings: list[str] = []
for path in deploy_root.rglob("*"):
relative = path.relative_to(deploy_root).as_posix()
lower_relative = relative.lower()
for pattern in SECRET_PATH_PATTERNS:
if pattern.lower() in lower_relative:
findings.append(relative)
break
return sorted(set(findings))
def scan_for_sensitive_contents(deploy_root: Path) -> list[str]:
findings: list[str] = []
for path in deploy_root.rglob("*"):
if not path.is_file():
continue
relative = path.relative_to(deploy_root).as_posix()
try:
text = path.read_text(encoding="utf-8")
except UnicodeDecodeError:
continue
for pattern in SECRET_CONTENT_PATTERNS:
if pattern in text:
findings.append(relative)
break
return sorted(set(findings))
def upload_to_hugging_face(repo_id: str, deploy_root: Path, commit_message: str) -> None:
try:
from huggingface_hub import HfApi, get_token
except ImportError as exc:
raise RuntimeError(
"huggingface_hub manquant. Installe-le avec : "
"python -m pip install 'huggingface_hub>=1.21.0'"
) from exc
token = get_token()
if not token:
raise RuntimeError("HF_TOKEN_LOCAL=MISSING. Lance : hf auth login")
api = HfApi(token=token)
api.upload_folder(
repo_id=repo_id,
repo_type="space",
folder_path=str(deploy_root),
path_in_repo=".",
commit_message=commit_message,
ignore_patterns=[
".git/*",
".env",
".env.*",
".venv/*",
".secrets/*",
"quality/private/*",
"__pycache__/*",
"*.pyc",
],
)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Déployer le backend BacPilot vers Hugging Face Space via API."
)
parser.add_argument("--repo-id", default=DEFAULT_REPO_ID)
parser.add_argument("--deploy-dir", default=str(DEFAULT_DEPLOY_DIR))
parser.add_argument("--commit-message", default="Deploy BacPilot backend via API")
parser.add_argument("--dry-run", action="store_true")
parser.add_argument("--wait-seconds", type=int, default=90)
return parser.parse_args()
def main() -> int:
args = parse_args()
source_root = Path.cwd()
deploy_root = Path(args.deploy_dir)
copied = build_deploy_folder(source_root=source_root, deploy_root=deploy_root)
path_findings = scan_for_sensitive_paths(deploy_root)
content_findings = scan_for_sensitive_contents(deploy_root)
print(f"HF_DEPLOY_FOLDER={deploy_root}")
print("HF_DEPLOY_COPIED=" + ",".join(copied))
if path_findings or content_findings:
print("HF_DEPLOY_SECRET_SCAN=FAILED")
for finding in path_findings:
print(f"sensitive_path={finding}")
for finding in content_findings:
print(f"sensitive_content_file={finding}")
return 1
print("HF_DEPLOY_SECRET_SCAN=OK")
if args.dry_run:
print("HF_UPLOAD_FOLDER=SKIPPED_DRY_RUN")
return 0
upload_to_hugging_face(
repo_id=args.repo_id,
deploy_root=deploy_root,
commit_message=args.commit_message,
)
print("HF_UPLOAD_FOLDER=OK")
print(f"HF_COMMIT_MESSAGE={args.commit_message}")
if args.wait_seconds > 0:
print(f"HF_REBUILD_WAIT_SECONDS={args.wait_seconds}")
time.sleep(args.wait_seconds)
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except Exception as exc:
print(f"HF_DEPLOY_ERROR={exc}", file=sys.stderr)
raise SystemExit(1)