the document comes from the forge, where the document is

`generate.py`'s fetch — the path every SDK takes when hanzoai/ci does not hand it
the document by value — asked api.github.com for hanzoai/cloud's openapi.yaml.
That is a mirror. It trails cloud by thousands of commits and carries no
openapi.yaml at its root at all, so the request could only 404, and the code read
that 404 as a private repo refusing an anonymous caller: it printed "is private
and no SPEC_TOKEN / GH_TOKEN / GITHUB_TOKEN is set", which sent every reader
looking for a credential to fix a host that has no file to serve. Measured with a
valid GitHub token on the exact address: 404, and the ref v1.801.495 is 404 there
too. The same request against git.hanzo.ai returns 4,073,309 bytes.

So one host and one credential. git.hanzo.ai is where hanzoai/cloud lives,
FORGE_TOKEN is what reads it, and the three-name credential ladder goes with the
mirror it was reaching for — a fallback chain across hosts that hold different
documents cannot be a fallback, only a coin flip about which document you get.

The forge serves its API at /v1/, not /api/v1/, and /api/v1 answers with a 404
indistinguishable from a rejected credential. Same route hanzoai/ci's client lane
and the CLI's Makefile take, because there is one document at one address.
This commit is contained in:
2026-08-08 06:19:41 -07:00
parent ca63495175
commit 067fc8dba3
+19 -16
View File
@@ -161,26 +161,29 @@ def lock(repo):
return out
def fetch(spec, dest):
"""The document at the locked ref, from GitHub, digest-checked.
FORGE = "https://git.hanzo.ai/v1"
hanzoai/cloud is private, so raw.githubusercontent.com answers 404 rather
than 403 and an anonymous miss is indistinguishable from a deleted file. The
contents API with a token says which case it is. Same credential names every
SDK call site already takes.
def fetch(spec, dest):
"""The document at the locked ref, from the forge, digest-checked.
git.hanzo.ai is where hanzoai/cloud lives. This asked api.github.com, which
holds a mirror thousands of commits behind and no openapi.yaml at its root at
all — so the fetch could only 404, and the 404 read as "your token is wrong".
A mirror is not a slower source; it answers a different question.
The forge serves its API at /v1/, NOT /api/v1/, and /api/v1 returns a 404 that
is indistinguishable from a rejected credential. Same route hanzoai/ci's
client lane and the CLI's Makefile take, because there is one document at one
address.
"""
token = (os.environ.get("SPEC_TOKEN") or os.environ.get("GH_TOKEN")
or os.environ.get("GITHUB_TOKEN")
or subprocess.run(["gh", "auth", "token"], capture_output=True,
text=True).stdout.strip())
token = os.environ.get("FORGE_TOKEN", "")
if not token:
sys.exit(f"generate: {spec['repo']} is private and no SPEC_TOKEN / GH_TOKEN /"
f" GITHUB_TOKEN is set (nor `gh auth login`). Pass --spec instead.")
sys.exit(f"generate: reading {spec['repo']}@{spec['ref']} from git.hanzo.ai"
f" needs FORGE_TOKEN (contents:read). Pass --spec instead.")
req = urllib.request.Request(
f"https://api.github.com/repos/{spec['repo']}/contents/{spec['path']}"
f"?ref={spec['ref']}",
headers={"Authorization": f"Bearer {token}",
"Accept": "application/vnd.github.raw"})
f"{FORGE}/repos/{spec['repo']}/raw/{spec['path']}?ref={spec['ref']}",
headers={"Authorization": f"token {token}"})
with urllib.request.urlopen(req) as r, open(dest, "wb") as f:
shutil.copyfileobj(r, f)
got = hashlib.sha256(open(dest, "rb").read()).hexdigest()