docs(deployment): deploy-space is keyless via HF Trusted Publishers - #238
Conversation
Documents the OIDC token exchange replacing HF_TOKEN in `deploy-space`, why the `id-token: write` grant is job-scoped, and why `factory_reboot=True` is load-bearing (the snippet was still showing a plain restart). Secrets table now reflects that HF_TOKEN survives only on the `staging` environment, for `deploy-pr-space` alone.
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThe deployment documentation replaces production ChangesDeployment authentication and architecture guidance
Estimated code review effort: 1 (Trivial) | ~5 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/architecture/deployment.md`:
- Around line 296-298: Update the deployment authorization explanation near the
environment scoping note to state that id-token: write only lets deploy-space
mint a GitHub OIDC token, while HF_OIDC_RESOURCE and Trusted Publisher claims
scope the exchanged Hugging Face token to the target Space; do not describe
these permissions as the production access boundary.
- Around line 419-423: The deployment documentation incorrectly limits HF_TOKEN
to deploy-pr-space and omits deploy-space. Update the section around
deploy-space and deploy-pr-space to document that build-hf-space.yml passes the
token to both consumers, that staging main dispatches use deploy-space to
restart extralit-dev/develop, and that build does not receive it; accurately
state the token’s Hugging Face scope.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: cfa4c4e9-17d6-4980-a949-794183055614
📒 Files selected for processing (1)
docs/architecture/deployment.md
| Note the environments carry **no protection rules and no branch policy**, so | ||
| `environment:` here is a scoping mechanism, not an approval gate. What actually | ||
| confines production access is the per-job `permissions:` block (§3). |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
# Inspect the documented authorization controls and the workflow paths that implement them.
set -eu
printf '%s\n' '--- deployment documentation ---'
sed -n '280,355p' docs/architecture/deployment.md
printf '%s\n' '--- workflow files and relevant controls ---'
git ls-files '.github/workflows' | sed -n '1,120p'
rg -n -C 4 'permissions:|id-token|HF_OIDC_RESOURCE|Trusted Publisher|huggingface|environment:' .github/workflows docs/architecture/deployment.mdRepository: Extralit/extralit
Length of output: 25782
🏁 Script executed:
set -eu
printf '%s\n' '--- deployment workflow ---'
sed -n '1,260p' .github/workflows/extralit-server.build-docker-images.yml
printf '%s\n' '--- remaining deployment documentation ---'
sed -n '355,430p' docs/architecture/deployment.md
printf '%s\n' '--- relevant implementation references ---'
rg -n -C 5 'get_token|HF_OIDC_RESOURCE|OIDC|restart_space|huggingface_hub|HF_TOKEN' .github/workflows docs pyproject.toml setup.cfg setup.py requirements*.txt 2>/dev/null || trueRepository: Extralit/extralit
Length of output: 22451
🏁 Script executed:
python3 - <<'PY'
from pathlib import Path
import re
doc = Path("docs/architecture/deployment.md").read_text()
workflow = Path(".github/workflows/extralit-server.build-docker-images.yml").read_text()
tracked = set(__import__("subprocess").check_output(["git", "ls-files"], text=True).splitlines())
deploy_section = doc[doc.index("### Job `deploy-space`"):doc.index("### Job `deploy-pr-space`")]
print("doc_permission_mints_oidc=", "id-token: write" in deploy_section)
print("doc_resource_scopes_space=", bool(re.search(r"HF_OIDC_RESOURCE: spaces/\\$\\{\\{ vars\\.HF_SPACE_ID \\}\\}", deploy_section)))
print("doc_trusted_publisher_exchange=", "Trusted Publishers" in deploy_section and "scoped to that one Space" in deploy_section)
print("doc_boundary_assigns_only_permissions=", "What actually\nconfines production access is the per-job `permissions:` block" in doc)
print("build_workflow_has_id_token_write=", bool(re.search(r"(?m)^\\s+id-token:\\s+write\\b", workflow)))
print("build_workflow_dispatches_companion=", "repository: extralit/extralit-hf-space" in workflow)
print("companion_workflow_tracked_here=", any(p.endswith("build-hf-space.yml") for p in tracked))
PYRepository: Extralit/extralit
Length of output: 423
🏁 Script executed:
rg -n '^## |^### ' docs/architecture/deployment.md | sed -n '1,100p'Repository: Extralit/extralit
Length of output: 1226
Security Misconfiguration (CWE-16)
Exploitability: Theoretical
State the production authorization boundary correctly.
id-token: write only allows deploy-space to mint a GitHub OIDC token. HF_OIDC_RESOURCE and the Trusted Publisher claims scope the exchanged Hugging Face token to the target Space.
Proposed wording
-What actually confines production access is the per-job `permissions:` block (§3).
+The per-job `permissions:` block (§3) allows only `deploy-space` to mint an OIDC token; `HF_OIDC_RESOURCE` and the Trusted Publisher claims (§4) scope the exchanged Hugging Face token.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Note the environments carry **no protection rules and no branch policy**, so | |
| `environment:` here is a scoping mechanism, not an approval gate. What actually | |
| confines production access is the per-job `permissions:` block (§3). | |
| Note the environments carry **no protection rules and no branch policy**, so | |
| `environment:` here is a scoping mechanism, not an approval gate. The per-job | |
| `permissions:` block (§3) allows only `deploy-space` to mint an OIDC token; | |
| `HF_OIDC_RESOURCE` and the Trusted Publisher claims (§4) scope the exchanged | |
| Hugging Face token. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/architecture/deployment.md` around lines 296 - 298, Update the
deployment authorization explanation near the environment scoping note to state
that id-token: write only lets deploy-space mint a GitHub OIDC token, while
HF_OIDC_RESOURCE and Trusted Publisher claims scope the exchanged Hugging Face
token to the target Space; do not describe these permissions as the production
access boundary.
| `HF_TOKEN` survives **only** on `staging`, and only for `deploy-pr-space`. | ||
| Trusted Publishers scope a token to an *existing* repo, so they cannot cover | ||
| `duplicate_space()`, which creates `extralit-dev/pr-N` on demand. That leaves the | ||
| remaining token's write access confined to the `extralit-dev` org — nothing can | ||
| reach `extralit/public-demo` with a stored credential. |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- workflow files ---'
git ls-files .github/workflows
printf '%s\n' '--- HF_TOKEN and staging references ---'
rg -n -C 4 'HF_TOKEN|deploy-pr-space|deploy-space|environment:\s*staging|duplicate_space|extralit/public-demo|extralit-dev/pr-' .github/workflows docs/architecture/deployment.mdRepository: Extralit/extralit
Length of output: 24628
🏁 Script executed:
#!/bin/bash
set -e
repo='extralit/extralit-hf-space'
printf '%s\n' '--- workflow listing ---'
curl -fsSL "https://api.github.com/repos/$repo/contents/.github/workflows" |
jq -r '.[] | .path' |
sort
printf '%s\n' '--- HF_TOKEN references in workflow files ---'
for path in $(curl -fsSL "https://api.github.com/repos/$repo/contents/.github/workflows" |
jq -r '.[].path'); do
body=$(curl -fsSL "https://raw.githubusercontent.com/$repo/main/$path")
if printf '%s' "$body" | rg -n -q 'HF_TOKEN|deploy-pr-space|deploy-space|environment:|repository_dispatch|workflow_dispatch'; then
printf '\n### %s\n' "$path"
printf '%s\n' "$body" | rg -n -C 5 'HF_TOKEN|deploy-pr-space|deploy-space|environment:|repository_dispatch|workflow_dispatch'
fi
doneRepository: Extralit/extralit
Length of output: 324
🏁 Script executed:
#!/bin/bash
set -e
url='https://raw.githubusercontent.com/extralit/extralit-hf-space/main/.github/workflows/build-hf-space.yml'
printf '%s\n' '--- build-hf-space.yml ---'
curl -fsSL "$url" |
rg -n -C 6 'HF_TOKEN|deploy-pr-space|deploy-space|environment:|repository_dispatch|workflow_dispatch'Repository: Extralit/extralit
Length of output: 6239
🏁 Script executed:
#!/bin/bash
set -e
url='https://raw.githubusercontent.com/extralit/extralit-hf-space/main/.github/workflows/build-hf-space.yml'
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
curl -fsSL "$url" > "$tmp"
python3 - "$tmp" <<'PY'
import re, sys
text = open(sys.argv[1]).read()
checks = {
"build_has_HF_TOKEN": bool(re.search(r"(?ms)^ build:.*?(?=^ [A-Za-z0-9_-]+:|\Z).*?HF_TOKEN", text)),
"deploy_space_environment": re.search(r"(?ms)^ deploy-space:.*?^ environment:\s*(.+)$", text),
"deploy_space_condition": re.search(r"(?ms)^ deploy-space:.*?^ if:\s*(.+)$", text),
"deploy_space_HF_TOKEN": bool(re.search(r"(?ms)^ deploy-space:.*?HF_TOKEN:\s*\$\{\{\s*secrets\.HF_TOKEN\s*\}\}", text)),
"deploy_pr_environment": re.search(r"(?ms)^ deploy-pr-space:.*?^ environment:\s*(.+)$", text),
"deploy_pr_condition": re.search(r"(?ms)^ deploy-pr-space:.*?^ if:\s*(.+)$", text),
"deploy_pr_HF_TOKEN": bool(re.search(r"(?ms)^ deploy-pr-space:.*?HF_TOKEN:\s*\$\{\{\s*secrets\.HF_TOKEN\s*\}\}", text)),
}
for key, value in checks.items():
if hasattr(value, "group"):
value = value.group(1).strip()
print(f"{key}={value!r}")
print("\n--- resolve-env and job headers ---")
for i, line in enumerate(text.splitlines(), 1):
if i <= 95 or 140 <= i <= 195:
print(f"{i}:{line}")
PYRepository: Extralit/extralit
Length of output: 21558
Sensitive Data Exposure (CWE-732): Incorrect Permission Assignment for Critical Resource
Reachability: Internal · Exploitability: Theoretical
Align the documentation with the workflow’s token boundary.
build-hf-space.yml passes secrets.HF_TOKEN to both deploy-space and deploy-pr-space. On staging main dispatches, deploy-space restarts extralit-dev/develop; build does not receive the token. Update lines 419–423 to describe both consumers and document the token’s Hugging Face scope.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/architecture/deployment.md` around lines 419 - 423, The deployment
documentation incorrectly limits HF_TOKEN to deploy-pr-space and omits
deploy-space. Update the section around deploy-space and deploy-pr-space to
document that build-hf-space.yml passes the token to both consumers, that
staging main dispatches use deploy-space to restart extralit-dev/develop, and
that build does not receive it; accurately state the token’s Hugging Face scope.
…opment workflow Replaced the Vector DB description to reflect the migration to Lancedb. Removed outdated sections on Python package management and running services, consolidating the development workflow documentation for clarity. Updated deployment and branching guidelines to enhance understanding of the release process.
…ting The restart API rejects OIDC tokens with a 401, caught by the staging smoke test. Documents the commit-to-rebuild mechanism, why a digest replaces the factory_reboot workaround, and how to tell a restart-endpoint 401 apart from a misconfigured publisher.
… [skip review] Roborev #329 (High) flagged that the doc described a deploy-space that did not exist in the submodule at any ref. The workflow has since landed on extralit-hf-space main, and the mechanism changed again (commit a digest pin rather than call the restart API, which rejects OIDC tokens with a 401). Sweeps the references the earlier commit missed: the two flowchart edges, the routing and resolve-env tables, and both walkthroughs in the pipeline section. Also sequences the HF_TOKEN deletion explicitly. Nothing on the deploy path reads secrets.HF_TOKEN anymore, so deleting early breaks nothing, but it does discard the one-commit rollback to a stored token before the keyless path has deployed to production even once.
Documents the switch of
deploy-spaceto keyless auth via HF Trusted Publishers: the OIDC token exchange that replacesHF_TOKEN, why theid-token: writegrant is scoped to that one job, and whyfactory_reboot=Trueis load-bearing (the snippet still showed a plain restart). The secrets table now reflects thatHF_TOKENsurvives only on thestagingenvironment, fordeploy-pr-spacealone.Companion PR
This documents the change implemented in the companion PR on
Extralit/extralit-hf-space(branchfeat/hf-trusted-publishers). Merge this after that one, so the docs don't describe a workflow that isn't live yet.Known drift, not fixed here
docs/architecture/deployment.mdlines ~282-288 still document thedevelopmigration alias inresolve-env, which was dropped from the hf-space workflow in commit 623d0fe. Left alone to keep this PR scoped.Summary by CodeRabbit
HF_TOKEN, while retaining restricted staging use for preview creation.