Skip to content

Hugging Face sign-in as a value-free native credential: status rows, guard, deny rules, per-host token policy - #268

Merged
seathatflowsinourveins merged 3 commits into
mainfrom
claude/hf-native-credential-20260925
Sep 25, 2026
Merged

seathatflowsinourveins merged 3 commits into
mainfrom
claude/hf-native-credential-20260925

Conversation

@seathatflowsinourveins

Copy link
Copy Markdown
Collaborator

Scope

  • What this PR changes: makes the Hugging Face sign-in a value-free native credential on every host, so the GPU workstation can host and qualify models (including gated ones) with our Hugging Face keys without any agent seeing the token.
  • Base commit: 3ff52117 (current origin/main).
  • Lane: lane:foundation
  • Owned paths touched:
    • adoption/credential-inventory.json: two native rows, huggingface-native (token) and huggingface-native-stored (stored_tokens), under ${HF_HOME:-${XDG_CACHE_HOME:-$HOME/.cache}/huggingface}
    • scripts/credential_status.py: the template prefix, HUGGING_FACE_HUB_TOKEN in must_not_be_set (HF_TOKEN was already there), and HF_TOKEN_PATH reported by name
    • scripts/hooks/secret_path_guard.py: both store paths, the legacy name, a block on hf auth token, and $HF_TOKEN_PATH as a pointer
    • Read deny rules in .claude/settings.json and the Claude settings template
    • .gitignore and SENSITIVE_BASENAME: stored_tokens
    • docs/secret-storage.md: a Hugging Face section
    • docs/decisions/2026-09-24-secret-storage.md: an addendum pinning the huggingface_hub v2.0.0 tag commit 97c5f5f2
    • tests

The policy it documents:

  • Each host signs in natively with hf auth login in the user's own terminal. The token is fine-grained, with read access to gated repos only, one per host so each can be revoked alone. It goes in at the hidden prompt, never with --token and never with --add-to-git-credential. Check it with hf auth whoami and python3 scripts/credential_status.py.
  • Agents may run hf download <repo> --revision <40-hex> --local-dir … and hf cache verify. hf reads the store itself, so the value never enters agent context. hf auth token is blocked.
  • New model-serving units serve from pinned local directories with HF_HUB_OFFLINE=1.
  • Workers that need no Hub access set HF_HUB_DISABLE_IMPLICIT_TOKEN=1. That behaviour was verified against the installed huggingface_hub 1.32.0 get_token_to_send.

Evidence-class table

Claim Evidence class Command
Token paths, environment variables, hf auth token printing, and the 0600 file and 0700 directory that hf writes source_review official huggingface_hub environment-variable and CLI docs, plus the installed 1.32.0 constants.py, _auth.py and _headers.py (code only; no token file read)
The rows render; the check uses lstat only (0600 → ok, missing → missing, 0644 → finding); HUGGING_FACE_HUB_TOKEN is flagged by name; the guard blocks store paths, hf auth token and pointer reads, and allows whoami, login, download and cache verify synthetic tests/test_credential_status.py, tests/test_secret_path_guard.py
This host reports both rows missing without opening any file local_integration python3 scripts/credential_status.py → missing huggingface-native, missing huggingface-native-stored, result: ok (lstat and names only; no credential file was opened)
Known guard pass-throughs (it is a heuristic): reading or copying a parent directory recursively (~, $HOME, ~/.cache, $XDG_CACHE_HOME), a relative read after cd, $HF_HOME/., an inline interpreter calling get_token() synthetic, recorded as expected pass-throughs 7 EXPECTED_PASS_THROUGH entries, also listed under "Does not stop" in the docs

Local commands run

$ uv run … -m unittest <17 modules that pin the guard, inventory, settings, template or gitignore>
Ran 917 tests … FAILED (failures=1, skipped=4)
  # the one failure is test_host_profile_copy_is_verbatim: the installed user-scope guard on this host predates this
  # branch. CI skips it (IN_CI). After merge, `tools/adoption/install_claude_profile.py --only guard` refreshes it.
$ uv run … scripts/validate.py                 # passed (5511 hashed files)
$ uv run … scripts/build_ecosystem.py --check  # passed
$ python3 scripts/credential_status.py         # huggingface-native / -stored: missing; result ok

adoption/hooks/claude/SHA256SUMS is refreshed for the new guard bytes.

Decision record

An addendum to docs/decisions/2026-09-24-secret-storage.md covers the Hugging Face row, the environment policy and the rejected alternatives: a per-provider 0600 env file, --token, a git credential, and exporting HF_TOKEN.

Review

An independent Opus reviewer returned ready with 5 low findings. A Sonnet repair round fixed all 5: the implicit-token wording, the guard pass-throughs recorded as known gaps, the $HF_TOKEN_PATH wording, stored_tokens in .gitignore and SENSITIVE_BASENAME, and the v2.0.0 SHA. A Sonnet re-check returned ready with no new defects. Codex cross-family review is unavailable until 2026-09-30.

Host evidence

None. No sign-in was performed; the user signs in natively. After merge: refresh the host guard with install_claude_profile.py --only guard, the user runs hf auth login in their own terminal, then hf auth whoami and credential_status.py should report ok.

Checklist

  • No workflow changes. [x] No secrets printed, logged or committed; no token file was opened. [x] No paid surface. [x] Peer files preserved.

🤖 Generated with Claude Code

Scout and others added 3 commits September 25, 2026 13:38
Make the Hugging Face sign-in a first-class native store on every host, so
a GPU host can fetch gated models through hf without any agent seeing the
token.

- Inventory: two native_store rows, huggingface-native (the active token
  file) and huggingface-native-stored (the saved tokens). The schema checks
  one path per entry and has no companion field, so the second file gets
  its own row. The path template is huggingface_hub's own default,
  ${HF_HOME:-${XDG_CACHE_HOME:-$HOME/.cache}/huggingface}, verified in the
  installed 1.32.0 constants.py and at the v2.0.0 tag. The legacy
  HUGGING_FACE_HUB_TOKEN joins HF_TOKEN in must_not_be_set. HF_TOKEN_PATH is
  listed as the rows' pointer variable.
- Checker: accept the HF_HOME template prefix, expand one nested
  ${NAME:-default} in a default (single-level templates expand as before),
  and report a native store's set path override (HF_TOKEN_PATH) by name
  under environment.native_store_path_overrides_present, with a
  store_path_overridden warning on the affected rows.
- Guard: block both token files in every spelling of their directory
  ($HF_HOME, $XDG_CACHE_HOME/huggingface, the default and the
  ${HF_HOME:-...} forms), the hf and huggingface-cli token-print commands,
  reads through $HF_TOKEN_PATH, and a reader or copy of the whole Hugging
  Face home. The legacy variable joins SECRET_NAMES. whoami, login,
  download, cache verify and cache ls still pass. SHA256SUMS refreshed with
  sha256sum from adoption/hooks/claude.
- Deny rules: Read on both default token paths and Bash on the token-print
  command, in the project settings and the user settings template.
- Docs: a Hugging Face sign-in section in docs/secret-storage.md covering
  the per-host fine-grained token, the paste login, what agents may run,
  offline serving units and workers without implicit tokens. Also corrects
  the checker's exit-status sentence, and adds a dated addendum with the
  alternatives and what would overturn it to the secret-storage decision.
- Tests: rows render as missing before sign-in, lstat-only 0600/0700 ok,
  0644 is a finding with exit 1, the template follows HF_HOME and
  XDG_CACHE_HOME, overrides and token variables are reported by name only,
  every inventory pointer variable is guarded, and the new guard block and
  pass cases.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Hot-file protocol (docs/lanes.md): the nine changed files that
manifests/evidence.json already lists are re-registered with
host_receipts.register_file. The component matrix and the new-host grand
list are unchanged (--check passes).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…guard

Independent-review repair for docs/secret-storage.md, the secret path guard's
test coverage and scripts/credential_status.py:

1. Reword the HF_HUB_DISABLE_IMPLICIT_TOKEN sentence to match installed
   huggingface_hub 1.32.0 (utils/_headers.py get_token_to_send, verified
   against the hf tool's own environment): with the variable set, the token
   is sent only when code passes it explicitly (token=True or a string);
   implicit use is off for every call, writes included, since write helpers
   default their own token parameter to None like everything else.

2. Document, rather than silently claim closed, the HF-home rule's gaps:
   recursive reads/copies of an ancestor directory (~, $HOME, ~/.cache,
   $XDG_CACHE_HOME with a trailing / or /*), a relative read after `cd` into
   the Hugging Face home, and $HF_HOME/. all bypass HF_HOME_ROOT. Closing
   these in the regex would also catch ordinary `ls`/`du`/`cp` of unrelated
   parent paths, so per the reviewer's preferred option they are recorded as
   EXPECTED_PASS_THROUGH cases (each verified to still return None from
   guard.check()) and added to the docs "Does not stop" column.

3. Stop overclaiming guard coverage of $HF_TOKEN_PATH in all three places
   that described it: it is a pointer variable, so only a reader, copy or
   input redirect on it is blocked, not every command that names it. Add an
   inline interpreter that opens $HF_TOKEN_PATH directly (never spelling a
   literal `$HF_TOKEN_PATH`) to the documented and tested bypasses.

4. Add `stored_tokens` to .gitignore and to credential_status.py's
   SENSITIVE_BASENAME (with a tracked_sensitive_names test proving both the
   catch and that a bare `token` basename is deliberately not flagged, since
   it is too generic to ignore repository-wide); qualify the threat-model
   row's overclaim about "native-store names" the same way.

5. Record the huggingface_hub v2.0.0 tag's actual commit
   (97c5f5f2030c2df01b60548f7d357970a106cd7d, dereferenced read-only from the
   annotated tag object via `gh api .../git/ref/tags/v2.0.0` then
   `git/tags/<sha>`) next to the source-review citation in the decision
   record.

scripts/hooks/secret_path_guard.py itself is unchanged (pure documentation
and test fixes per the reviewer's preferred option), so
adoption/hooks/claude/SHA256SUMS needs no refresh. Re-registered all six
touched hot files in manifests/evidence.json.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@seathatflowsinourveins seathatflowsinourveins added the lane:foundation Foundation lane: Claude/Codex setup, hosts, memory, RAG, research, workers label Sep 25, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@seathatflowsinourveins
seathatflowsinourveins merged commit 9bdce90 into main Sep 25, 2026
23 checks passed
@seathatflowsinourveins
seathatflowsinourveins deleted the claude/hf-native-credential-20260925 branch September 25, 2026 18:31
seathatflowsinourveins added a commit that referenced this pull request Sep 25, 2026
…tstrap page (#271)

#268 (Hugging Face store rules) changed the secret-path guard and its
SHA256SUMS hash after the v2026.09.25.1 re-pin, so
tests.test_adoption_docs_consistency's changed-install-input check fails on
main (ae30f94). The bootstrap unit that already notes the post-v2026.09.24.1
change now also says it changed after v2026.09.25.1 and to rerun the guard
step from a checkout that has it.

Co-authored-by: Scout <scout@local>
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lane:foundation Foundation lane: Claude/Codex setup, hosts, memory, RAG, research, workers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant