ComfyUI-Ranking-API / github_archive.py
ZHIWEI666's picture
Upload 14 files
9bc3427 verified
Raw History Blame Contribute Delete
4.74 kB
"""固定Git commit归档与缓存来源证明;不把旧缓存当作已核实安装包。"""
import datetime
import hashlib
import json
import re
from github_source import canonical_resource_source
ARCHIVE_SCHEMA = 3
ARCHIVE_MAX_BYTES = 500 * 1024 * 1024
def archive_repository(value):
"""仅接收明确的owner/name标识,不能用元数据构造额外URL路径。"""
if (not isinstance(value, str) or len(value) > 193
or not re.fullmatch(r'[A-Za-z0-9](?:[A-Za-z0-9_.-]{0,94}[A-Za-z0-9])?/[A-Za-z0-9](?:[A-Za-z0-9_.-]{0,94}[A-Za-z0-9])?', value)
or '..' in value or '--' in value):
raise ValueError('invalid archive storage identity')
return value
def commit_sha(value):
if not isinstance(value, str) or not re.fullmatch(r'[0-9a-fA-F]{40}', value):
raise ValueError('invalid commit identity')
return value.lower()
def commit_ref(value):
if not isinstance(value, str) or not re.fullmatch(r'(?:[0-9a-fA-F]{7}|[0-9a-fA-F]{40})', value):
raise ValueError('invalid commit reference')
return value.lower()
def source_signature(item, token):
author = item.get('author')
if not isinstance(author, str) or not author.strip():
raise ValueError('invalid archive author')
source = [canonical_resource_source(item), author, token or '']
# 元数据只保存摘要,不保存或输出凭据。
return hashlib.sha256(json.dumps(source, ensure_ascii=True, separators=(',', ':')).encode()).hexdigest()
def archive_path(item_id, sha, signature):
if not isinstance(item_id, str) or not re.fullmatch(r'[A-Za-z0-9_-]{1,100}', item_id):
raise ValueError('invalid archive item')
if not isinstance(signature, str) or not re.fullmatch(r'[0-9a-f]{64}', signature):
raise ValueError('invalid archive source')
return f'zips/{item_id}_{commit_sha(sha)}_{signature[:16]}.zip'
def cached_archive(item, token, entry, *, repo_id, now=None):
"""只有完整来源、commit、HF不可变提交及未过期元数据才允许命中。"""
try:
if not isinstance(entry, dict) or type(entry.get('archive_schema')) is not int or entry['archive_schema'] != ARCHIVE_SCHEMA:
return None
repository = archive_repository(repo_id)
if entry.get('archive_repo_id') != repository:
return None
if entry.get('archive_storage_private') is not True:
return None
sha = commit_sha(entry.get('archive_commit'))
if entry.get('version_commit') not in (None, sha):
return None
if entry.get('hash') != sha[:7]:
return None
signature = source_signature(item, token)
if entry.get('archive_source') != signature:
return None
path = archive_path(item.get('id'), sha, signature)
if entry.get('archive_path') != path:
return None
hf_commit = commit_sha(entry.get('archive_hf_commit'))
size = entry.get('zip_size')
if type(size) is not int or not 0 < size <= ARCHIVE_MAX_BYTES:
return None
cached_at = datetime.datetime.fromisoformat(entry['cached_at'].replace('Z', '+00:00'))
if cached_at.tzinfo is None:
return None
elapsed = (now or datetime.datetime.now(datetime.timezone.utc)) - cached_at
if not datetime.timedelta(minutes=-5) <= elapsed <= datetime.timedelta(days=30):
return None
return dict(commit=sha, path=path, hf_commit=hf_commit, size=size, repo_id=repository)
except (ValueError, TypeError, KeyError, AttributeError):
return None
def publish_archive_metadata(versions, item_id, expected_hash, metadata):
"""锁内只更新目标缓存字段;晚到下载不能改变当前版本或其它资源。"""
if not isinstance(versions, dict):
raise ValueError('invalid version source')
entry = versions.get(item_id)
if isinstance(entry, str):
entry = {'hash': entry}
if not isinstance(entry, dict) or entry.get('hash') != commit_ref(expected_hash)[:7]:
return False
if (entry.get('version_commit') not in (None, metadata.get('archive_commit'))
or entry.get('version_source') not in (None, metadata.get('archive_source'))):
return False
keys = ('archive_schema', 'archive_commit', 'archive_source', 'archive_path',
'archive_hf_commit', 'archive_storage_private', 'archive_repo_id', 'zip_size', 'cached_at')
archive_repository(metadata['archive_repo_id'])
entry = {**entry, **{key: metadata[key] for key in keys}}
versions[item_id] = entry
return True