feat: release v1.0.2 LeKiwi 语言控制与网站嵌入
web-platform-ci / Standalone decision service (no cloud credentials) (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
lekiwi-compatibility / cpu-compatibility (push) Has been cancelled
web-platform-ci / Standalone decision service (no cloud credentials) (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
lekiwi-compatibility / cpu-compatibility (push) Has been cancelled
集成服务器托管模型、自然语言移动与有界抓放、内置 LeKiwi URL 导入和双摄像头;同步部署契约与指定域名 iframe 白名单,保留原有物理安全、会话及调用预算防护。 更新 npm 包及锁文件版本、CHANGELOG 与发布文档。提交前 typecheck、120 项定向前端测试和 44 项后端测试通过(3 项可选跳过);真实 v2 云模型抓放仍待单独验收,不包含运行密钥或构建产物。
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
"""Operator-only provisioning. Never package keys, pass them in argv, or print them."""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
from decision_server.credentials import deepseek_llm, openrouter_jev # noqa: E402
|
||||
|
||||
REMOTE = r"""
|
||||
import json, os, pathlib, re, sys
|
||||
values = json.loads(sys.stdin.read(16384))
|
||||
assert set(values) == {'Deepseek_API_KEY', 'OPENROUTER_API_KEY'}
|
||||
assert all(re.fullmatch(r'[A-Za-z0-9_-]{16,4096}', v) for v in values.values())
|
||||
root = pathlib.Path('/opt/cadworld-sim')
|
||||
secrets = root / 'secrets'
|
||||
secrets.mkdir(mode=0o700, exist_ok=True)
|
||||
os.chmod(str(secrets), 0o700)
|
||||
path = secrets / 'model-keys.env'
|
||||
payload = ''.join(k+'='+v+'\n' for k,v in sorted(values.items())).encode()
|
||||
if path.exists():
|
||||
if path.is_symlink() or path.read_bytes() != payload:
|
||||
raise SystemExit('Existing credentials differ; explicit rotation required')
|
||||
else:
|
||||
fd = os.open(str(path), os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o400)
|
||||
with os.fdopen(fd, 'wb') as stream:
|
||||
stream.write(payload)
|
||||
os.chown(str(path), 10001, 10001)
|
||||
os.chmod(str(path), 0o400)
|
||||
budget = root / 'budget'
|
||||
budget.mkdir(mode=0o700, exist_ok=True)
|
||||
os.chown(str(budget), 10001, 10001)
|
||||
os.chmod(str(budget), 0o700)
|
||||
print('Server-only credentials provisioned; values not displayed.')
|
||||
"""
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--confirm-server-keys", action="store_true")
|
||||
args = parser.parse_args()
|
||||
if not args.confirm_server_keys:
|
||||
parser.error("Explicit authorization required before reading the two .env variables")
|
||||
keys = {
|
||||
"Deepseek_API_KEY": deepseek_llm(ROOT / ".env").key,
|
||||
"OPENROUTER_API_KEY": openrouter_jev(ROOT / ".env").key,
|
||||
}
|
||||
if not (ROOT / "website-dist/index.html").is_file():
|
||||
raise SystemExit("Build website before provisioning")
|
||||
for path in (ROOT / "website-dist").rglob("*"):
|
||||
if path.is_file():
|
||||
content = path.read_bytes()
|
||||
if any(value.encode() in content for value in keys.values()):
|
||||
raise SystemExit("Credential found in static build; provisioning refused")
|
||||
# The remote source contains no values. Only SSH's encrypted stdin carries keys.
|
||||
import shlex
|
||||
|
||||
result = subprocess.run(
|
||||
[
|
||||
"ssh",
|
||||
"-o",
|
||||
"BatchMode=yes",
|
||||
"-o",
|
||||
"StrictHostKeyChecking=yes",
|
||||
"-o",
|
||||
"UpdateHostKeys=no",
|
||||
"root@47.93.31.109",
|
||||
"python3 -c " + shlex.quote(REMOTE),
|
||||
],
|
||||
input=json.dumps(keys).encode(),
|
||||
capture_output=True,
|
||||
)
|
||||
if result.returncode:
|
||||
raise SystemExit("Credential provisioning failed; values/logs withheld, no automatic retry")
|
||||
print("Static secret scan passed; server-only credentials provisioned (0400, read-only mount).")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user