🔍 Running security validation on staged changes... Log file: /root/liveserver2024/data/www/official-en-aia/.claude/skills/safe-commit/scripts/../logs/validate_20260202_113842.log AI Validation: enabled (codex) ✓ Found staged changes Checking for sensitive data patterns... - API keys/tokens/secrets... [0;32mOK[0m - Absolute file paths... [0;32mOK[0m - Private domains/IPs... [0;32mOK[0m - .env variable values... [0;32mOK[0m - Database credentials... [0;32mOK[0m [0;32m✓ Regex-based security checks passed![0m [0;34m🤖 Running AI-powered validation...[0m - AI sensitive data scan (codex)... OpenAI Codex v0.84.0 (research preview) -------- workdir: /root/liveserver2024/data/www/official-en-aia model: gpt-5.2 provider: openai approval: never sandbox: read-only reasoning effort: medium reasoning summaries: auto session id: 019c1e25-dce6-7fc0-a162-2cdc14156e45 -------- user You are a security auditor reviewing a git diff for sensitive information before commit. Analyze this git diff and check for: 1. API keys, tokens, secrets, passwords (real values, not placeholders) 2. Absolute file paths that reveal server infrastructure (e.g., /root/..., /home/user/..., /var/www/...) 3. Internal/private domain names or IP addresses 4. Database credentials or connection strings with passwords 5. Personal information (emails, phone numbers, addresses) 6. Cloud credentials (AWS keys, GCP keys, Azure keys) IMPORTANT: Documentation examples with placeholder paths like '/home/username/...' are OK. Only flag REAL sensitive data that would be a security risk if committed. Respond with EXACTLY one of these formats: - If SAFE: 'SAFE: No sensitive data found' - If ISSUES: 'ISSUES: [brief description of what was found]' Do NOT output anything else. Be concise. Here is the git diff to analyze: diff --git a/laravel/app/Services/KpiService.php b/laravel/app/Services/KpiService.php index 1ccd8be..0b96662 100644 --- a/laravel/app/Services/KpiService.php +++ b/laravel/app/Services/KpiService.php @@ -131,9 +131,24 @@ private function parseTsvContent(string $content): array return $result; } + /** + * Key mapping from Google Sheets to internal keys + * Google Sheets key (lowercase) => internal key + */ + private const KEY_MAPPING = [ + 'annual_conferences' => 'annual_conferences', + 'lecturers' => 'lectures', + 'programs' => 'programs', + 'trainee_companies' => 'trainee_companies', + 'industrial_cases' => 'industry_user_cases', + 'trainees' => 'trainee', + 'technical_cases' => 'technical_study_cases', + ]; + /** * Normalize key from TSV to match our expected keys * "Annual Conferences" -> "annual_conferences" + * Also maps Google Sheets keys to internal keys * * @param string $key * @return string @@ -146,7 +161,8 @@ private function normalizeKey(string $key): string // Remove "_count" suffix if present (from original PHP) $key = preg_replace('/_count$/', '', $key); - return $key; + // Map Google Sheets key to internal key + return self::KEY_MAPPING[$key] ?? $key; } /** diff --git a/laravel/resources/js/pages/ai-in-taiwan.tsx b/laravel/resources/js/pages/ai-in-taiwan.tsx index 9e164d5..bef646e 100644 --- a/laravel/resources/js/pages/ai-in-taiwan.tsx +++ b/laravel/resources/js/pages/ai-in-taiwan.tsx @@ -6,7 +6,31 @@ import HeroContent from '@/components/aia/hero-content'; import Discover from '@/components/aia/discover'; import AIAForAll from '@/components/aia/aia-for-all'; -export default function PartnerWithUs() { +type KpiItem = { + value: number; + formatted: string; +}; + +type KpiData = { + kpi: { + annual_conferences: KpiItem; + programs: KpiItem; + technical_study_cases: KpiItem; + trainee_companies: KpiItem; + trainee: KpiItem; + industry_user_cases: KpiItem; + lectures: KpiItem; + industry_involved: KpiItem; + }; + updated_at: string | null; +}; + +type AiInTaiwanProps = { + kpiData: KpiData; +}; + +export default function PartnerWithUs({ kpiData }: AiInTaiwanProps) { + const kpi = kpiData?.kpi; const partnerDashboardNums = { @@ -119,38 +143,38 @@ We shape policy by turning projects into impact. By working with government and