Files
pua/evals/test-release-consistency.sh
T
xsserandCodex 534b91c65f fix(upload): make contribution uploads reliable
Summary:
- Treat /contribute.html and /contribute as first-class SPA routes so
  GitHub OAuth callback and documented upload links land on the uploader.
- Switch the browser uploader from multipart/base64 to raw JSONL POSTs
  with metadata headers, while keeping JSON file_data and multipart
  compatibility on the API.
- Add static upload-flow gates and Vitest coverage for authenticated
  upload sanitization, R2 writes, and D1 metadata recording.
- Bump plugin and marketplace versions to 3.4.4.

Rationale:
- The upload path had two breakpoints: documented /contribute.html links
  rendered the homepage because routing only checked hash, and multipart
  browser uploads could be stripped by proxy/custom-domain behavior.
- Raw JSONL avoids multipart body loss and avoids base64 size/memory bloat
  for large session files.

Tests:
- bash evals/test-upload-flow.sh
- bash evals/test-release-consistency.sh
- npm --prefix landing test -- --run src/test/upload-function.test.ts
- static eval suite: governance, feedback auth, heartbeat, integrity
  guard, issue regressions, Microsoft flavor, platform compat, loop hook,
  Windows Python hooks, YAML frontmatter
- npm --prefix landing run build
- ./landing/node_modules/.bin/tsc -p pi/pua/tsconfig.json
- git diff --check

Co-authored-by: Codex <codex@openai.com>
2026-05-09 17:15:54 +08:00

259 lines
14 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Static release gates: manifest version sync + confidence gate hardening.
set -euo pipefail
PLUGIN_DIR="${PLUGIN_DIR:-$(cd "$(dirname "$0")/.." && pwd)}"
python3 - "$PLUGIN_DIR" <<'PY'
import json, pathlib, sys
root = pathlib.Path(sys.argv[1])
manifest_files = [
'plugin.json',
'.claude-plugin/plugin.json',
'.claude-plugin/marketplace.json',
'.codebuddy-plugin/plugin.json',
'.codebuddy-plugin/marketplace.json',
]
versions = []
errors = []
for rel in manifest_files:
path = root / rel
data = json.loads(path.read_text(encoding='utf-8'))
if 'version' in data:
versions.append((rel, data['version']))
for idx, plugin in enumerate(data.get('plugins', []) or []):
if plugin.get('name') == 'pua':
versions.append((f'{rel}:plugins[{idx}]', plugin.get('version')))
unique = {v for _, v in versions}
if len(unique) != 1:
errors.append('version mismatch: ' + repr(versions))
version = next(iter(unique)) if unique else None
if not version:
errors.append('no version detected')
claude_market = json.loads((root / '.claude-plugin/marketplace.json').read_text(encoding='utf-8'))
plugin_desc = claude_market['plugins'][0].get('description', '')
if version and f'v{version}:' not in plugin_desc:
errors.append(f'.claude-plugin/marketplace.json plugin description missing changelog marker v{version}:')
skill = (root / 'skills/pua/SKILL.md').read_text(encoding='utf-8')
required_terms = [
'信心门控(Confidence Gate',
'列声明',
'找漏洞',
'P0/P1',
'跑证据',
'循环判定',
'事实上的 100%',
'缓存/发布链路',
'hook smoke test',
'Harness 防作弊治理(权责分离)',
'行动权 / 自我评价权 / 评分权 / 环境修改权',
'verifier_status',
'四代理拓扑',
'pua-policy-guardian',
'pua-action-executor',
'pua-self-reviewer',
'pua-verifier',
'文化叙事绑定',
]
for term in required_terms:
if term not in skill:
errors.append(f'confidence gate missing required term: {term}')
reference = root / 'skills/pua/references/harness-governance.md'
if not reference.exists():
errors.append('missing harness governance reference file')
else:
ref_text = reference.read_text(encoding='utf-8')
for term in ['把四类权力分开', 'Grader gaming', 'Solution contamination', 'Task Contract', 'Memory 权限模型', '事实上的 100%', '四代理上下文隔离拓扑(v3.2.7', 'pua-action-executor', 'pua-policy-guardian', '上下文隔离降低叙事污染']:
if term not in ref_text:
errors.append(f'harness governance reference missing required term: {term}')
hooks_json = json.loads((root / 'hooks/hooks.json').read_text(encoding='utf-8'))
pre_hooks = hooks_json.get('hooks', {}).get('PreToolUse', [])
if not any(any('integrity-guard.sh' in hook.get('command', '') for hook in item.get('hooks', [])) for item in pre_hooks):
errors.append('hooks/hooks.json missing PreToolUse integrity-guard.sh registration')
if not (root / 'hooks/integrity-guard.sh').exists():
errors.append('missing hooks/integrity-guard.sh')
if not (root / 'evals/test-integrity-guard.sh').exists():
errors.append('missing evals/test-integrity-guard.sh')
if not (root / 'evals/test-windows-python-hooks.sh').exists():
errors.append('missing evals/test-windows-python-hooks.sh')
if not (root / 'evals/test-issue-regressions.sh').exists():
errors.append('missing evals/test-issue-regressions.sh')
if not (root / 'evals/test-agent-governance.sh').exists():
errors.append('missing evals/test-agent-governance.sh')
for agent_file in ['agents/pua-action-executor.md', 'agents/pua-self-reviewer.md', 'agents/pua-verifier.md', 'agents/pua-policy-guardian.md']:
if not (root / agent_file).exists():
errors.append(f'missing governance agent: {agent_file}')
integrity_guard = (root / 'hooks/integrity-guard.sh').read_text(encoding='utf-8') if (root / 'hooks/integrity-guard.sh').exists() else ''
for term in ['permissionDecision', 'Grader gaming risk', 'Solution contamination risk', 'Capability-abuse risk', 'PUA_INTEGRITY_FORCE', 'hookEventName']:
if term not in integrity_guard:
errors.append(f'integrity guard missing required term: {term}')
flavor_helper = (root / 'hooks/flavor-helper.sh').read_text(encoding='utf-8')
for term in ['pua_python_cmd()', 'pua_to_python_path()', 'pua_json_get()', 'cygpath -w']:
if term not in flavor_helper:
errors.append(f'flavor-helper missing Windows/Python compatibility helper: {term}')
for hook_file in ['hooks/frustration-trigger.sh', 'hooks/failure-detector.sh', 'hooks/session-restore.sh', 'hooks/stop-feedback.sh']:
hook_text = (root / hook_file).read_text(encoding='utf-8')
if 'pua_json_get' not in hook_text:
errors.append(f'{hook_file} must read config through pua_json_get')
# Open issue regression guards
required_paths = [
'commands/offline.md',
'codex/pua-on/SKILL.md',
'codex/pua-off/SKILL.md',
'codex/pua-p7/SKILL.md',
'codex/pua-p9/SKILL.md',
'codex/pua-p10/SKILL.md',
'pi/pua/index.ts',
'pi/pua/INSTALL.md',
'pi/package/package.json',
'pi/package/extensions/pua/index.ts',
'pi/package/skills/pua/SKILL.md',
'trae/INSTALL.md',
'trae/DIFF.md',
'trae/pua.md',
'.trae/skills/pua/SKILL.md',
'.trae/skills/pua-en/SKILL.md',
'.trae/skills/pua-trae/SKILL.md',
'docs/FAQ.md',
'landing/migrations/0003_feedback_rate_limits.sql',
'evals/test-platform-compat.sh',
'evals/test-feedback-auth.sh',
'evals/test-microsoft-flavor.sh',
'evals/test-heartbeat.sh',
'evals/test-upload-flow.sh',
'hooks/heartbeat.sh',
'landing/functions/api/heartbeat.ts',
'landing/migrations/0004_heartbeat.sql',
'landing/src/pages/AdminStats.tsx',
'skills/pua/references/methodology-microsoft.md',
]
for rel in required_paths:
if not (root / rel).exists():
errors.append(f'missing issue-sweep asset: {rel}')
# D1 migrations must be idempotent because existing production DBs may predate
# Wrangler's migration journal. A non-idempotent CREATE INDEX previously made
# `wrangler d1 migrations apply --remote` fail on 0001 before newer migrations.
for migration in sorted((root / 'landing/migrations').glob('*.sql')):
text_sql = migration.read_text(encoding='utf-8')
if 'CREATE INDEX ' in text_sql:
for line in text_sql.splitlines():
stripped = line.strip().upper()
if stripped.startswith('CREATE INDEX ') and not stripped.startswith('CREATE INDEX IF NOT EXISTS '):
errors.append(f'D1 migration has non-idempotent index creation: {migration.relative_to(root)}')
frustration = (root / 'hooks/frustration-trigger.sh').read_text(encoding='utf-8')
for term in ['TRIGGER_RE', 'PUA Skill Context']:
if term not in frustration:
errors.append(f'frustration trigger missing internal filter/context term: {term}')
if 'MUST invoke' in frustration or 'PUA behavioral enforcement' in frustration:
errors.append('frustration trigger still contains coercive injection wording')
stop_feedback = (root / 'hooks/stop-feedback.sh').read_text(encoding='utf-8')
if '/tmp/pua-plugin-root' in stop_feedback:
errors.append('stop-feedback must not use /tmp/pua-plugin-root')
if 'offline' not in stop_feedback:
errors.append('stop-feedback must honor offline config')
feedback_api = (root / 'landing/functions/api/feedback.ts').read_text(encoding='utf-8')
for term in ['MAX_BODY_BYTES', 'MAX_SESSION_DATA_BYTES', 'RATE_LIMIT_MAX_WRITES', 'ALLOWED_ORIGINS', 'getSession(request, env.SESSION_SECRET)', 'Login required for session upload']:
if term not in feedback_api:
errors.append(f'feedback endpoint missing abuse-control term: {term}')
stop_feedback = (root / 'hooks/stop-feedback.sh').read_text(encoding='utf-8')
if "json.dumps({'rating': 'session_upload', 'session_data': data})" in stop_feedback:
errors.append('stop-feedback must not anonymously post session_data to feedback endpoint')
for term in ['GitHub login', 'contribute.html', '/api/upload']:
if term not in stop_feedback:
errors.append(f'stop-feedback missing authenticated upload guidance: {term}')
if '[PUA-DIAGNOSIS]' not in (root / 'skills/pua/SKILL.md').read_text(encoding='utf-8'):
errors.append('pua skill missing diagnosis-first rule')
if '军令状' not in (root / 'skills/pua/references/methodology-huawei.md').read_text(encoding='utf-8'):
errors.append('Huawei methodology missing military-order mode')
for scan_rel in ['agents', 'commands', 'skills/pua/references']:
for path in (root / scan_rel).rglob('*'):
if path.is_file() and '下场' in path.read_text(encoding='utf-8', errors='ignore'):
errors.append(f'ambiguous 下场 wording remains in {path.relative_to(root)}')
session_restore = (root / 'hooks/session-restore.sh').read_text(encoding='utf-8')
if 'Harness Integrity (anti-cheating governance)' not in session_restore:
errors.append('SessionStart protocol missing Harness Integrity governance injection')
if 'Multi-Agent Governance Topology' not in session_restore:
errors.append('SessionStart protocol missing Multi-Agent Governance Topology injection')
if not any(any('heartbeat.sh' in hook.get('command', '') for hook in item.get('hooks', [])) for item in hooks_json.get('hooks', {}).get('SessionStart', [])):
errors.append('SessionStart missing silent heartbeat.sh registration')
heartbeat_hook = (root / 'hooks/heartbeat.sh').read_text(encoding='utf-8') if (root / 'hooks/heartbeat.sh').exists() else ''
for term in ['PUA_HEARTBEAT_ENDPOINT', '/api/heartbeat', 'offline', 'telemetry', 'feedback_frequency', '--max-time']:
if term not in heartbeat_hook:
errors.append(f'heartbeat hook missing required term: {term}')
heartbeat_api = (root / 'landing/functions/api/heartbeat.ts').read_text(encoding='utf-8') if (root / 'landing/functions/api/heartbeat.ts').exists() else ''
for term in ['ADMIN_GITHUB_LOGINS', 'getSession(request, env.SESSION_SECRET)', 'heartbeat_installs', 'heartbeat_events', 'COUNT(DISTINCT install_id_hash)', 'sha256Hex']:
if term not in heartbeat_api:
errors.append(f'heartbeat endpoint missing required term: {term}')
app_tsx = (root / 'landing/src/App.tsx').read_text(encoding='utf-8')
contribute_tsx = (root / 'landing/src/pages/Contribute.tsx').read_text(encoding='utf-8')
for term in ['pathname', '/contribute.html', '#/contribute']:
if term not in app_tsx:
errors.append(f'upload flow missing required term in App.tsx: {term}')
for term in ['file.text()', 'application/jsonl', 'X-PUA-File-Name', 'X-PUA-Wechat-Id']:
if term not in contribute_tsx:
errors.append(f'upload flow missing required term in Contribute.tsx: {term}')
for forbidden_upload_term in ['new FormData()', 'readFileAsBase64', 'file_data: fileData']:
if forbidden_upload_term in contribute_tsx:
errors.append(f'upload flow must not rely on bloated/multipart browser upload path: {forbidden_upload_term}')
for forbidden in ['Applies to ALL task types', 'All task types', 'code, config, debug, deploy, research']:
if forbidden in skill.split('---', 2)[1]:
errors.append(f'pua skill description is too broad and may false-trigger: {forbidden}')
if 'Do not trigger for normal first-attempt coding or information requests.' not in skill.split('---', 2)[1]:
errors.append('pua skill description must explicitly exclude normal first-attempt requests')
command = (root / 'commands/pua.md').read_text(encoding='utf-8')
command_frontmatter = command.split('---', 2)[1]
if 'Use only when the user explicitly invokes /pua' not in command_frontmatter:
errors.append('pua slash command description must be explicit-invocation only')
if '任务描述]' in command_frontmatter or '任意任务描述' in command_frontmatter:
errors.append('pua slash command frontmatter is too broad and may false-trigger')
hook = (root / 'hooks/pua-loop-hook.sh').read_text(encoding='utf-8')
if 'run_with_timeout 120 bash -c "$VERIFY_CMD"' not in hook:
errors.append('pua-loop hook does not use portable run_with_timeout for verify_command')
if 'VERIFY_OUTPUT=$(timeout 120 bash -c "$VERIFY_CMD"' in hook:
errors.append('pua-loop hook still calls GNU timeout directly')
helpers = (root / 'evals/test-helpers.sh').read_text(encoding='utf-8')
trigger = (root / 'evals/run-trigger-test.sh').read_text(encoding='utf-8')
if 'run_with_timeout()' not in helpers:
errors.append('eval helper missing portable run_with_timeout')
if ' timeout 120 claude' in trigger or ' timeout 90 claude' in helpers:
errors.append('eval scripts still call GNU timeout directly')
if '--output-format stream-json' in trigger and '--verbose' not in trigger:
errors.append('trigger eval uses stream-json without --verbose')
if 'PUA_CONFIG="$EVAL_PUA_CONFIG" run_with_timeout 120 claude' not in trigger:
errors.append('trigger eval must use isolated PUA_CONFIG to avoid user ~/.pua/config.json')
if 'observable PUA behavior as triggered' not in trigger:
errors.append('trigger eval must accept observable PUA behavior fallback to reduce Skill-tool flake')
if 'EVAL_WORKSPACE="$RESULTS_DIR/workspace"' not in trigger or 'cd "$EVAL_WORKSPACE"' not in trigger:
errors.append('trigger eval must run in a neutral workspace, not the pua plugin repo')
if 'PUA_CONFIG="$eval_config" run_with_timeout 90 claude' not in helpers:
errors.append('behavior eval must use isolated PUA_CONFIG to avoid user ~/.pua/config.json')
if errors:
print('=== Release consistency FAILED ===')
for e in errors:
print(' -', e)
sys.exit(1)
print('=== Release consistency OK ===')
print('version =', version)
print('manifests checked =', len(manifest_files))
print('confidence/harness/agent terms checked =', len(required_terms))
PY