From cf0bc497320159de4c7920da26db1ce76d5b8f45 Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Wed, 4 Nov 2026 17:32:36 +0800 Subject: [PATCH] Verify workspace membership on dev with isolated accounts --- .gitea/workflows/preview.yml | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/.gitea/workflows/preview.yml b/.gitea/workflows/preview.yml index 3a060ee..6120763 100644 --- a/.gitea/workflows/preview.yml +++ b/.gitea/workflows/preview.yml @@ -58,3 +58,40 @@ jobs: bash scripts/preview/init.sh "$PWD" waterfall-wiki-tests:6654a1456bdcef77d83ca84373dc36188e15bd12 fi bash scripts/preview/sync.sh "$PWD" "$SOURCE_SHA" "$SOURCE_BRANCH" + - name: Verify Workspace with two temporary dev accounts + if: gitea.ref == 'refs/heads/dev' + run: | + python3 - <<'PY' + import hashlib,json,secrets,subprocess,urllib.request,urllib.error,uuid + container=subprocess.check_output(['docker','ps','-q','--filter','label=com.docker.compose.project=prompt-preview','--filter','label=com.docker.compose.service=postgres'],text=True).strip() + assert len(container)==12 + ids=[str(uuid.uuid4()),str(uuid.uuid4())] + tokens=[secrets.token_hex(32),secrets.token_hex(32)] + def sql(command): + subprocess.run(['docker','exec','-i',container,'psql','-Xq','-v','ON_ERROR_STOP=1','-U','prompt','-d','prompt'],input=command,text=True,check=True) + origin='http://8.211.154.134:18136' + def api(index,payload=None,expected=200): + req=urllib.request.Request('http://127.0.0.1:18136/api/account/workspaces',data=None if payload is None else json.dumps(payload).encode(),headers={'Origin':origin,'Content-Type':'application/json','Cookie':'preview_wiki_account='+tokens[index]}) + try: + response=urllib.request.build_opener(urllib.request.ProxyHandler({})).open(req,timeout=30) + except urllib.error.HTTPError as error: + response=error + with response: + assert response.code==expected, (payload and payload['action'],response.code,expected) + return json.load(response) + try: + for uid,token in zip(ids,tokens): + digest=hashlib.sha256(token.encode()).hexdigest() + sql(f"INSERT INTO account_users(id,email,password_hash,verified_at) VALUES('{uid}','{uid}@example.test','invalid',now()); INSERT INTO account_tokens(digest,user_id,kind,expires_at) VALUES('{digest}','{uid}','session',now()+interval '5 minutes');") + space=api(0,{'action':'create','name':'Workspace smoke check','purpose':'个人创作'},201)['space'] + assert space['owner'] and not api(1)['spaces'] + api(1,{'action':'invite','workspaceId':space['id']},404) + invite=api(0,{'action':'invite','workspaceId':space['id']})['code'] + assert api(1,{'action':'join','code':invite})['space']['id']==space['id'] + api(1,{'action':'join','code':invite}) + assert api(1)['spaces']==[{**space,'owner':False}] + print('PASS create, owner-only invite, join, repeat join, and membership isolation') + finally: + a,b=ids + sql(f"DELETE FROM workspaces WHERE owner_id IN ('{a}','{b}'); DELETE FROM account_users WHERE id IN ('{a}','{b}');") + PY