diff --git a/.github/workflows/generator-generic-ossf-slsa3-publish.yml b/.github/workflows/generator-generic-ossf-slsa3-publish.yml index 35c829b..945c409 100644 --- a/.github/workflows/generator-generic-ossf-slsa3-publish.yml +++ b/.github/workflows/generator-generic-ossf-slsa3-publish.yml @@ -20,7 +20,7 @@ jobs: build: runs-on: ubuntu-latest outputs: - digests: ${{ steps.hash.outputs.digests }} + digests: ${{ steps.hash.outputs.hashes }} steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/google.yml b/.github/workflows/google.yml index 0b5c7d1..5c618df 100644 --- a/.github/workflows/google.yml +++ b/.github/workflows/google.yml @@ -103,7 +103,7 @@ jobs: # Set up kustomize - name: 'Set up Kustomize' run: |- - curl -sfLo kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.4.3/kustomize_v5.4.3_linux_amd64.tar.gz + curl -sSfL https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.4.3/kustomize_v5.4.3_linux_amd64.tar.gz | tar -xz chmod u+x ./kustomize # Deploy the Docker image to the GKE cluster diff --git a/.github/workflows/hadolint.yml b/.github/workflows/hadolint.yml index dc73566..a264df3 100644 --- a/.github/workflows/hadolint.yml +++ b/.github/workflows/hadolint.yml @@ -2,7 +2,7 @@ # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support # documentation. -# hadoint is a Dockerfile linter written in Haskell +# hadolint is a Dockerfile linter written in Haskell # that helps you build best practice Docker images. # More details at https://github.com/hadolint/hadolint diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index 09631a2..8e55f57 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -22,6 +22,9 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Smoke test static app + run: node scripts/smoke-test-static.mjs + - name: Prepare static site shell: bash run: | diff --git a/CNAME b/CNAME index 2037010..2c40239 100644 --- a/CNAME +++ b/CNAME @@ -1 +1 @@ -app.github.rkix \ No newline at end of file +app.rkix.com \ No newline at end of file diff --git a/README.md b/README.md index 91f1766..66293ea 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ RKIX3/ ├─ index.html # Single-file AI Studio UI ├─ README.md # Trang giới thiệu chuyên nghiệp trên GitHub +├─ scripts/smoke-test-static.mjs # Smoke test HTML/JS trước khi deploy ├─ 1780136894650-Photoroom.png # Logo chính └─ .github/workflows/static.yml # Build _site + deploy GitHub Pages ``` @@ -66,17 +67,26 @@ python3 -m http.server 4173 # mở http://127.0.0.1:4173 ``` +## 🧪 Kiểm thử + +```bash +node scripts/smoke-test-static.mjs +``` + +Smoke test sẽ kiểm tra cấu trúc route chính, sự tồn tại của chat input/send button, cú pháp JavaScript inline và guard chống render raw user message vào `innerHTML`. + ## 🚀 Deploy GitHub Pages -Workflow `.github/workflows/static.yml` sẽ: +Workflow chính `.github/workflows/static.yml` sẽ: 1. Checkout source. -2. Setup GitHub Pages. -3. Tạo `_site` chứa `index.html`, ảnh và file đánh dấu static site. -4. Upload artifact Pages. -5. Deploy bằng `actions/deploy-pages`. +2. Chạy smoke test static app bằng `node scripts/smoke-test-static.mjs`. +3. Setup GitHub Pages. +4. Tạo `_site` chứa `index.html`, ảnh và file đánh dấu static site. +5. Upload artifact Pages. +6. Deploy bằng `actions/deploy-pages`. -> Nếu GitHub vẫn báo lỗi deploy, hãy vào **Settings → Pages → Build and deployment** và chọn **Source: GitHub Actions** cho repository. +> Nếu GitHub vẫn báo lỗi deploy, hãy vào **Settings → Pages → Build and deployment** và chọn **Source: GitHub Actions** cho repository. Các workflow mẫu khác trong `.github/workflows/` chỉ nên được bật khi dự án thật sự dùng stack tương ứng. ## 🏅 Huy hiệu dự án @@ -121,13 +131,13 @@ Workflow `.github/workflows/static.yml` sẽ: ## ✅ Ba xung đột đã được chốt -- **Workflow Pages**: chỉ giữ một pipeline static ở `.github/workflows/static.yml`, dùng `_site` làm artifact triển khai. +- **Workflow Pages**: `.github/workflows/static.yml` là pipeline deploy chính, chạy smoke test rồi dùng `_site` làm artifact triển khai. - **Tài liệu GitHub**: README là trang giới thiệu chính thức của RKIX3, không còn nội dung cũ trùng lặp. - **Web app RKIX3**: `index.html` tiếp tục là nguồn giao diện single-file được workflow copy trực tiếp khi deploy. ## 🗺️ Roadmap -- [x] Giao diện RKIX3 Studio single-file. +- [x] Giao diện RKIX3 Studio single-file, ưu tiên mobile web với shell giống app gốc. - [x] Command Center cho CLI/mobile workflow. - [x] Demo Offline để sinh blueprint khi chưa có API key. - [x] GitHub Pages static deploy workflow. diff --git a/index.html b/index.html index 12bb580..245ecd2 100644 --- a/index.html +++ b/index.html @@ -1,118 +1,262 @@ - + - RKIX3 — Developer Workspace Platform - + RKIX3 — Mobile AI Workspace +
- -

RKIX3 Command Layer

Dashboard

main · healthy
-
RKIX3
+ + +
+
+ + + +
+ +
+
+
+
+
+
+ + +
+ diff --git a/scripts/smoke-test-static.mjs b/scripts/smoke-test-static.mjs new file mode 100644 index 0000000..8a14429 --- /dev/null +++ b/scripts/smoke-test-static.mjs @@ -0,0 +1,45 @@ +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { spawnSync } from 'node:child_process'; + +const html = readFileSync('index.html', 'utf8'); +const failures = []; + +function assert(condition, message) { + if (!condition) failures.push(message); +} + +assert(html.includes(''), 'index.html must declare an HTML doctype.'); +assert(html.includes('
${m.text}

'), 'Chat messages must not render raw user text into innerHTML.'); + +const scripts = [...html.matchAll(/]*)?>([\s\S]*?)<\/script>/gi)].map((match) => match[1]); +assert(scripts.length > 0, 'index.html must include an inline script to validate.'); + +if (scripts.length > 0) { + const workDir = mkdtempSync(join(tmpdir(), 'rkix3-smoke-')); + const scriptPath = join(workDir, 'index-inline-script.js'); + writeFileSync(scriptPath, scripts.join('\n'), 'utf8'); + const result = spawnSync(process.execPath, ['--check', scriptPath], { encoding: 'utf8' }); + if (result.status !== 0) { + failures.push(`Inline JavaScript failed syntax check:\n${result.stderr || result.stdout}`); + } + rmSync(workDir, { recursive: true, force: true }); +} + +if (failures.length > 0) { + console.error('Static smoke test failed:'); + for (const failure of failures) console.error(`- ${failure}`); + process.exit(1); +} + +console.log('Static smoke test passed.');