diff --git a/.github/workflows/generator-generic-ossf-slsa3-publish.yml b/.github/workflows/generator-generic-ossf-slsa3-publish.yml index 35c829b..f003244 100644 --- a/.github/workflows/generator-generic-ossf-slsa3-publish.yml +++ b/.github/workflows/generator-generic-ossf-slsa3-publish.yml @@ -14,13 +14,13 @@ name: SLSA generic generator on: workflow_dispatch: release: - types: [created] + types: [published] 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..df80189 100644 --- a/.github/workflows/google.yml +++ b/.github/workflows/google.yml @@ -36,7 +36,7 @@ name: 'Build and Deploy to GKE' on: push: branches: - - '"main"' + - 'main' env: PROJECT_ID: 'my-project' # TODO: update to your Google Cloud project ID diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 4677434..a588ab1 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -9,7 +9,7 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/first-interaction@v1 + - uses: actions/first-interaction@3c71ce730280171fd1cfb57c00c774f8998586f7 # v1.3.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} issue-message: "Message that will be displayed on users' first issue" 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/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..f4c7cee 100644 --- a/index.html +++ b/index.html @@ -1,118 +1,267 @@ - + - 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..9a101e7 --- /dev/null +++ b/scripts/smoke-test-static.mjs @@ -0,0 +1,47 @@ +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.');