Cion-lab commited on
Commit
90c1cde
·
verified ·
1 Parent(s): 0e945ba

add p1_secret_verify: mounted-credential end-to-end auth test

Browse files
Files changed (1) hide show
  1. probes/p1_secret_verify.py +129 -0
probes/p1_secret_verify.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Phase 1 verification: does the Kaggle-mounted secret store actually work end to end, and can a job
2
+ # write to the Hub with it?
3
+ #
4
+ # This is the decisive test for D-002. It carries NO token in its source: the credential arrives via
5
+ # the mounted private dataset dodosoomro/ounce100m-secret-store, which is the whole point of the store.
6
+ #
7
+ # Checks, in order:
8
+ # 1. the mount exists and parses,
9
+ # 2. token integrity -- length + a truncated sha256 compared against the value the bootstrap
10
+ # recorded, which proves the right credential without ever printing it,
11
+ # 3. HF read auth (whoami),
12
+ # 4. HF WRITE auth, the thing §3.13 needs: create a throwaway repo, commit a file, verify it is
13
+ # listed on the Hub from outside, delete it.
14
+ #
15
+ # Every optional diagnostic is wrapped: the bootstrap job died because one unwrapped cross-check
16
+ # raised AFTER the real work had succeeded, so the run produced no report at all (E-012). A probe that
17
+ # cannot survive its own instrumentation is not a probe.
18
+ #
19
+ # Zero GPU quota (CPU session).
20
+
21
+ import hashlib
22
+ import json
23
+ import os
24
+ import time
25
+ import urllib.error
26
+ import urllib.request
27
+
28
+ R = {}
29
+ MOUNT = "/kaggle/input/ounce100m-secret-store/credentials.json"
30
+ DS_ID = "dodosoomro/ounce100m-secret-store"
31
+ EXPECTED_SHA12 = "076ca223fcf6" # recorded by p1_secret_bootstrap v1, value-free
32
+ TEST_REPO = "Cion-lab/ounce100m-authtest-DELETEME"
33
+
34
+
35
+ def guard(name, fn):
36
+ try:
37
+ R[name] = fn()
38
+ except Exception as e:
39
+ R[name] = {"error": f"{type(e).__name__}: {e}"[:300]}
40
+
41
+
42
+ # ---- 1 + 2: the mount, checked without echoing anything secret
43
+ def read_mount():
44
+ if not os.path.exists(MOUNT):
45
+ siblings = sorted(os.listdir("/kaggle/input")) if os.path.isdir("/kaggle/input") else None
46
+ return {"mounted": False, "kaggle_input_listing": siblings,
47
+ "note": "the private dataset did not mount -- creation probably never succeeded"}
48
+ with open(MOUNT) as f:
49
+ blob = json.load(f)
50
+ tok = blob.get("HF_TOKEN", "")
51
+ return {"mounted": True, "keys": sorted(blob.keys()), "token_length": len(tok),
52
+ "token_sha256_prefix": hashlib.sha256(tok.encode()).hexdigest()[:12],
53
+ "matches_bootstrap_record": hashlib.sha256(tok.encode()).hexdigest()[:12] == EXPECTED_SHA12,
54
+ "mode": oct(os.stat(MOUNT).st_mode & 0o777)}
55
+
56
+
57
+ guard("mount", read_mount)
58
+
59
+ tok = ""
60
+ if isinstance(R.get("mount"), dict) and R["mount"].get("mounted"):
61
+ with open(MOUNT) as f:
62
+ tok = json.load(f).get("HF_TOKEN", "")
63
+
64
+ # ---- privacy, re-proved from the outside: an anonymous download must NOT work
65
+ def privacy():
66
+ url = f"https://www.kaggle.com/api/v1/datasets/download/{DS_ID}"
67
+ try:
68
+ with urllib.request.urlopen(url, timeout=60) as r:
69
+ return {"status": r.status, "verdict": "PUBLIC_LEAK"}
70
+ except urllib.error.HTTPError as e:
71
+ return {"status": e.code, "verdict": "PRIVATE" if e.code in (401, 403) else f"HTTP_{e.code}"}
72
+
73
+
74
+ guard("privacy_anonymous", privacy)
75
+
76
+ # ---- 3: HF read auth, using the mounted credential only in memory
77
+ def hf_read():
78
+ from huggingface_hub import HfApi
79
+
80
+ api = HfApi(token=tok)
81
+ me = api.whoami()
82
+ return {"name": me.get("name"), "type": me.get("type"),
83
+ "can_be_org": bool(me.get("orgs")), "token_kind": me.get("full", {}).get("fullname")}
84
+
85
+
86
+ guard("hf_whoami", hf_read)
87
+
88
+ # ---- 4: HF write auth -- the capability the checkpoint cycle depends on
89
+ def hf_write():
90
+ from huggingface_hub import HfApi, create_repo, delete_repo
91
+
92
+ api = HfApi(token=tok)
93
+ t0 = time.monotonic()
94
+ create_repo(TEST_REPO.split("/")[1], token=tok, repo_type="model",
95
+ namespace=TEST_REPO.split("/")[0], private=False, exist_ok=True)
96
+ api.upload_file(path_or_fileobj=b"ounce100m auth round-trip probe\n",
97
+ path_in_repo="authcheck.txt", repo_id=TEST_REPO, repo_type="model",
98
+ commit_message="auth write check")
99
+ # Independent verification: read it back over plain anonymous HTTPS, not through the client that
100
+ # wrote it, so a fake success in the library cannot be mistaken for a working upload path.
101
+ url = f"https://huggingface.co/{TEST_REPO}/resolve/main/authcheck.txt"
102
+ with urllib.request.urlopen(url, timeout=60) as r:
103
+ body = r.read()
104
+ verified = body.strip() == b"ounce100m auth round-trip probe"
105
+ delete_repo(TEST_REPO, repo_type="model", token=tok)
106
+ gone = False
107
+ try:
108
+ urllib.request.urlopen(url, timeout=30)
109
+ except urllib.error.HTTPError as e:
110
+ gone = e.code in (404, 401, 403)
111
+ except Exception:
112
+ pass
113
+ return {"created": True, "readback_verified": verified, "seconds": round(time.monotonic() - t0, 1),
114
+ "deleted": True, "delete_confirmed_gone": gone}
115
+
116
+
117
+ guard("hf_write_roundtrip", hf_write)
118
+
119
+ # ---- how a training job should use this, for the record
120
+ R["usage_pattern"] = {
121
+ "save_notebook_datasetDataSources": [DS_ID],
122
+ "read": f"json.load(open({MOUNT!r}))['HF_TOKEN']",
123
+ "rule": "set os.environ['HF_TOKEN'] in-process; never print the value; never copy the file into "
124
+ "/kaggle/working, because working-dir files become kernel output artifacts",
125
+ }
126
+
127
+ print("PROBE_JSON_BEGIN")
128
+ print(json.dumps(R, indent=1, default=str))
129
+ print("PROBE_JSON_END")