Sean Yu commited on
Commit
1622ebb
·
1 Parent(s): 2850a82

Derive submission model name from verified repository URL

Browse files
README.md CHANGED
@@ -58,3 +58,5 @@ Limits: ZIP ≤8 GiB, expanded contents ≤24 GiB, each member ≤128 MiB, ≤40
58
  Local development of storage only: set `INTREAL_LOCAL_STORAGE=1` and `SUBMISSIONS_DIR` to a scratch directory. This never enables a fake sign-in and is ignored in a Space. Production OAuth must be tested on the Space before enabling real submissions. Use `python -m pytest tests` for backend checks.
59
 
60
  Storage admission checks account for the configured 32 GiB intake quota, existing files, pending reservations, and filesystem free space before receiving a ZIP. Disk-full/quota errors during upload are rejected and incomplete files removed. The form disables submission when full and directs users to `shaohanyu628@gmail.com` to request storage management and retry later. Filesystem capacity is not a direct measurement of the HF account-wide Hub storage quota; remote quota write failures are also handled.
 
 
 
58
  Local development of storage only: set `INTREAL_LOCAL_STORAGE=1` and `SUBMISSIONS_DIR` to a scratch directory. This never enables a fake sign-in and is ignored in a Space. Production OAuth must be tested on the Space before enabling real submissions. Use `python -m pytest tests` for backend checks.
59
 
60
  Storage admission checks account for the configured 32 GiB intake quota, existing files, pending reservations, and filesystem free space before receiving a ZIP. Disk-full/quota errors during upload are rejected and incomplete files removed. The form disables submission when full and directs users to `shaohanyu628@gmail.com` to request storage management and retry later. Filesystem capacity is not a direct measurement of the HF account-wide Hub storage quota; remote quota write failures are also handled.
61
+
62
+ Submission model names are derived server-side from the verified HF repository URL; submitters do not enter a separate name.
static/submit.html CHANGED
@@ -20,7 +20,6 @@
20
  <form id="submission-form">
21
  <fieldset id="submission-fields" disabled>
22
  <div class="form-grid">
23
- <label class="field full"><span>Model name *</span><input name="model_name" required maxlength="160" placeholder="Your model name"></label>
24
  <label class="field full"><span>Hugging Face model URL *</span><input name="model_url" type="url" required maxlength="240" placeholder="https://huggingface.co/your-username/model-name"><small>Public, ungated, with weights and an open license. The owner must match your signed-in account.</small></label>
25
  <label class="field"><span>Hugging Face username *</span><input id="hf-username" name="username" readonly required autocomplete="off"><small>Automatically verified through Hugging Face sign-in.</small></label>
26
  <label class="field"><span>Contact email *</span><input name="email" type="email" required maxlength="254" autocomplete="email" placeholder="you@example.com"></label>
 
20
  <form id="submission-form">
21
  <fieldset id="submission-fields" disabled>
22
  <div class="form-grid">
 
23
  <label class="field full"><span>Hugging Face model URL *</span><input name="model_url" type="url" required maxlength="240" placeholder="https://huggingface.co/your-username/model-name"><small>Public, ungated, with weights and an open license. The owner must match your signed-in account.</small></label>
24
  <label class="field"><span>Hugging Face username *</span><input id="hf-username" name="username" readonly required autocomplete="off"><small>Automatically verified through Hugging Face sign-in.</small></label>
25
  <label class="field"><span>Contact email *</span><input name="email" type="email" required maxlength="254" autocomplete="email" placeholder="you@example.com"></label>
submission_backend.py CHANGED
@@ -302,13 +302,11 @@ def install_submissions(app):
302
  raise HTTPException(413, "Form data is too large.")
303
  try:
304
  body = json.loads(body_bytes)
305
- name = body.get("model_name", "").strip()
306
- if not 1 <= len(name) <= 160:
307
- raise ValueError("Model name is required (maximum 160 characters).")
308
  email = validate_email(body.get("email", ""), check_deliverability=False).normalized
309
  if body.get("username") != user["username"]:
310
  raise ValueError("Submitted HF username must match your signed-in account.")
311
  repo_id = model_id_from_url(body.get("model_url", ""), user["username"])
 
312
  filename = body.get("filename", "")
313
  if not filename.lower().endswith(".zip") or "/" in filename or "\\" in filename or len(filename) > 200:
314
  raise ValueError("Choose a .zip archive.")
 
302
  raise HTTPException(413, "Form data is too large.")
303
  try:
304
  body = json.loads(body_bytes)
 
 
 
305
  email = validate_email(body.get("email", ""), check_deliverability=False).normalized
306
  if body.get("username") != user["username"]:
307
  raise ValueError("Submitted HF username must match your signed-in account.")
308
  repo_id = model_id_from_url(body.get("model_url", ""), user["username"])
309
+ name = repo_id.split("/", 1)[1]
310
  filename = body.get("filename", "")
311
  if not filename.lower().endswith(".zip") or "/" in filename or "\\" in filename or len(filename) > 200:
312
  raise ValueError("Choose a .zip archive.")
tests/test_submissions.py CHANGED
@@ -116,7 +116,7 @@ def service(tmp_path, monkeypatch):
116
 
117
 
118
  def form(data):
119
- return {'model_name': 'My model', 'model_url': 'https://huggingface.co/alice/model', 'username': 'alice', 'email': 'alice@example.com', 'filename': 'outputs.zip', 'size': len(data)}
120
 
121
 
122
  def sign_in(client, username='alice'):
@@ -289,3 +289,13 @@ def test_disk_fills_during_upload_cleans_partial(service, monkeypatch):
289
  assert 'shaohanyu628@gmail.com' in response.json()['detail']
290
  assert not (root/sid/'outputs.zip.part').exists()
291
  assert not (root/sid/'outputs.zip').exists()
 
 
 
 
 
 
 
 
 
 
 
116
 
117
 
118
  def form(data):
119
+ return {'model_url': 'https://huggingface.co/alice/model', 'username': 'alice', 'email': 'alice@example.com', 'filename': 'outputs.zip', 'size': len(data)}
120
 
121
 
122
  def sign_in(client, username='alice'):
 
289
  assert 'shaohanyu628@gmail.com' in response.json()['detail']
290
  assert not (root/sid/'outputs.zip.part').exists()
291
  assert not (root/sid/'outputs.zip').exists()
292
+
293
+
294
+ def test_model_name_is_derived_and_not_user_controlled(service):
295
+ client, root = service
296
+ sign_in(client)
297
+ payload = form(archive_bytes()) | {'model_name': 'forged display name'}
298
+ response = client.post('/api/submissions', json=payload, headers={'X-CSRF-Token':'csrf-test'})
299
+ assert response.status_code == 200
300
+ record = json.loads((root / response.json()['id'] / 'metadata.json').read_text())
301
+ assert record['model_name'] == 'model'