merge: integrate repository-centered desktop workflow into dev #2707
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: | |
| - dev | |
| - feat/keiko-editor | |
| - feat/keiko-agent-native-editor-foundation-and-runtime | |
| - feat/prompt-enhancer-1307 | |
| - feat/keiko-establish-governed-end-to-end-git-delivery | |
| - feat/keiko-voice-digital-twin | |
| - feat/keiko-isolated-task-workspaces | |
| - feat/keiko-colleague-like-voice-dialogue-mode | |
| - feat/keiko-repository-centered-desktop-workflow | |
| - "release/**" | |
| pull_request: | |
| branches: | |
| - dev | |
| - feat/keiko-editor | |
| - feat/keiko-agent-native-editor-foundation-and-runtime | |
| - feat/prompt-enhancer-1307 | |
| - feat/keiko-establish-governed-end-to-end-git-delivery | |
| - feat/keiko-voice-digital-twin | |
| - feat/keiko-isolated-task-workspaces | |
| - feat/keiko-colleague-like-voice-dialogue-mode | |
| - feat/keiko-repository-centered-desktop-workflow | |
| - "release/**" | |
| workflow_dispatch: | |
| permissions: {} | |
| jobs: | |
| protected-branch-gate: | |
| name: Protected branch gate | |
| runs-on: ubuntu-latest | |
| permissions: {} | |
| steps: | |
| - name: Confirm dev branch gate | |
| run: | | |
| case "${{ github.ref }}:${{ github.base_ref }}" in | |
| refs/heads/dev: | refs/heads/feat/keiko-editor: | refs/heads/feat/keiko-agent-native-editor-foundation-and-runtime: | refs/heads/feat/prompt-enhancer-1307: | refs/heads/feat/keiko-establish-governed-end-to-end-git-delivery: | refs/heads/feat/keiko-voice-digital-twin: | refs/heads/feat/keiko-isolated-task-workspaces: | refs/heads/feat/keiko-colleague-like-voice-dialogue-mode: | refs/heads/feat/keiko-repository-centered-desktop-workflow: | refs/heads/release/*: | *:dev | *:feat/keiko-editor | *:feat/keiko-agent-native-editor-foundation-and-runtime | *:feat/prompt-enhancer-1307 | *:feat/keiko-establish-governed-end-to-end-git-delivery | *:feat/keiko-voice-digital-twin | *:feat/keiko-isolated-task-workspaces | *:feat/keiko-colleague-like-voice-dialogue-mode | *:feat/keiko-repository-centered-desktop-workflow | *:release/*) | |
| echo "Protected or integration branch gate satisfied." | |
| ;; | |
| *) | |
| echo "This gate is only valid for protected dev, integration, and release branches." | |
| exit 1 | |
| ;; | |
| esac | |
| ci: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: "22.x" | |
| cache: "npm" | |
| - run: npm ci | |
| - name: Install sandbox isolation backend (bubblewrap) | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y bubblewrap | |
| # Ubuntu 24.04 restricts unprivileged user namespaces via AppArmor; bubblewrap (and the | |
| # unshare fallback) need them to create the network namespace. Relax it for the runner so | |
| # the enforced-egress proof below actually exercises the isolation boundary (ADR-0043). | |
| sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 || true | |
| - name: Enforced sandbox egress proof (ADR-0043 / #1202) | |
| # NOT gated by the feat/keiko-editor branch skip: the assured pre-filter executes untrusted | |
| # model-generated code, so the deny-by-default egress boundary must be proven on every run. | |
| # The egress test fails the job if an outbound connection from inside network:"none" succeeds. | |
| run: npm --workspace @oscharko-dev/keiko-sandbox test | |
| - name: Verify Keiko Editor package | |
| run: | | |
| npm --workspace @oscharko-dev/keiko-editor run build | |
| npm --workspace @oscharko-dev/keiko-editor run typecheck | |
| npm --workspace @oscharko-dev/keiko-editor test | |
| - run: npm run typecheck | |
| - run: npm run check:version-consistency | |
| - run: npm run check:git-client-evidence | |
| - run: npm run lint | |
| - run: npm run arch:check | |
| - run: npm run arch:check:negative | |
| - name: Quality Intelligence supply-chain gate | |
| run: npm run check:qi-supply-chain | |
| - name: Retrieval latency gate (enterprise retrieval M3) | |
| # Runs after `npm run typecheck` (which builds packages), so the compiled keiko-workspace | |
| # dist the gate imports is present. Deterministic fixture + generous p95 ceiling. | |
| run: npm run check:retrieval-latency | |
| - name: Retrieval quality gate (enterprise retrieval M4) | |
| # Same compiled workspace surface as the latency gate; evaluates top-k quality, line-level | |
| # evidence, and generated-artifact leakage over fixed synthetic enterprise fixtures. | |
| run: npm run check:retrieval-quality | |
| - name: Context quality gate (ADR-0052, context-engineering PR1) | |
| # Runs after `npm run typecheck` (which builds packages), so the compiled keiko-contracts, | |
| # keiko-workflows, keiko-workspace, and keiko-security dist the gate imports are present — | |
| # the same build dependency the retrieval gates above rely on. Drives the deterministic lane | |
| # allocator over a fixed offline corpus and enforces context-quality invariants. | |
| run: npm run check:context-quality | |
| - name: Keiko Editor static-export bundle gate | |
| run: | | |
| npm run build:ui | |
| npm run check:editor-bundle-size -- --require-static-export | |
| - name: Package surface and installable smoke | |
| run: | | |
| npm run build | |
| npm run prepare:bin | |
| npm run prune:package-native-optionals | |
| npm run check:package-surface | |
| KEIKO_SMOKE_PACK_IGNORE_SCRIPTS=1 npm run smoke:install | |
| - name: Coverage quality gates | |
| if: ${{ github.event_name != 'pull_request' || github.base_ref != 'feat/keiko-editor' }} | |
| run: npm run test:coverage:quality | |
| actionlint: | |
| name: actionlint | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Download and verify actionlint | |
| run: | | |
| curl -sSfL "https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_amd64.tar.gz" -o actionlint.tar.gz | |
| echo "8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8 actionlint.tar.gz" | sha256sum --check | |
| tar -xzf actionlint.tar.gz actionlint | |
| chmod +x actionlint | |
| - name: Run actionlint | |
| run: ./actionlint -color .github/workflows/*.yml | |
| verify-pinned-shas: | |
| name: Verify pinned action SHAs | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Assert all action references are pinned to 40-hex SHAs | |
| run: | | |
| set -euo pipefail | |
| violations=$(grep -rnE '^\s*-?\s*uses:' .github/workflows/ \ | |
| | grep -vE 'uses:\s*\./' \ | |
| | grep -vE 'uses:\s*docker://' \ | |
| | grep -vE 'uses:\s*[A-Za-z0-9._/-]+@[0-9a-f]{40}([[:space:]]|$|#)' || true) | |
| if [ -n "$violations" ]; then | |
| echo "Unpinned action references (must pin to a full 40-hex commit SHA):" | |
| echo "$violations" | |
| exit 1 | |
| fi | |
| echo "All action references are pinned to full commit SHAs." | |
| build-scan-sbom-smoke: | |
| name: Build, scan, SBOM, smoke | |
| # Keep early feature-branch PRs fast. These release/package gates still run on merges to | |
| # feat/keiko-editor, on dev/release PRs, and on manual workflow_dispatch runs. | |
| if: ${{ github.event_name != 'pull_request' || github.base_ref != 'feat/keiko-editor' }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: "22.x" | |
| cache: "npm" | |
| - run: npm ci | |
| - name: Build | |
| run: npm run build | |
| - name: Prepare packaged CLI and UI assets | |
| run: | | |
| npm run prepare:bin | |
| npm run build:ui | |
| - name: Installable-package smoke (Issue #169 AC2) | |
| run: npm run smoke:install | |
| - name: Installable memory smoke (Issue #216) | |
| run: npm run smoke:install:memory | |
| - name: Smoke - offline evaluate exits 0 | |
| run: KEIKO_EVIDENCE_DIR="$(mktemp -d)" node dist/cli/index.js evaluate --suite all | |
| - name: Security audit (high and above) | |
| run: npm audit --audit-level=high | |
| - name: Generate CycloneDX SBOM | |
| run: npm sbom --sbom-format cyclonedx --omit dev > sbom.cdx.json | |
| - name: Workspace SBOM and license gate (Issue #169 AC4) | |
| run: npm run check:workspace-supply-chain | |
| - name: Smoke - help exits 0 | |
| run: node dist/cli/index.js --help | |
| - name: Smoke - version exits 0 | |
| run: node dist/cli/index.js --version | |
| - name: Smoke - unknown command exits 2 | |
| run: | | |
| set +e | |
| node dist/cli/index.js definitely-not-a-command | |
| code=$? | |
| if [ "$code" -ne 2 ]; then echo "expected exit 2, got $code"; exit 1; fi | |
| echo "unknown-command exit code correct: $code" | |
| - name: Upload SBOM | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: sbom-cyclonedx | |
| path: sbom.cdx.json | |
| retention-days: 90 | |
| - name: Upload workspace SBOMs (Issue #169 AC4) | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: workspace-sboms-cyclonedx | |
| path: sbom/ | |
| retention-days: 90 | |
| cross-platform-smoke: | |
| name: Cross-platform smoke (${{ matrix.os }}) | |
| if: ${{ github.event_name != 'pull_request' || github.base_ref != 'feat/keiko-editor' }} | |
| # Issue #284 AC4: the packed Keiko artifact must work on macOS, Windows, and Linux via the | |
| # normal start path. Linux is already exercised by `build-scan-sbom-smoke`; this job runs the | |
| # same installable-package smoke (pack -> install -> CLI -> packaged `keiko ui` -> health, | |
| # launch project, QI runs read route, home shell) on Windows and macOS so AC4 portability is | |
| # EXECUTED, not only portable by construction. Intentionally NOT a required/gating check yet — | |
| # the `ci` job remains the merge gate; promote this to a required check once it has proven | |
| # stable across several runs (native optional deps + the Next static export are the parts most | |
| # likely to need per-OS attention). fail-fast:false so one OS result never masks the other. | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [windows-latest, macos-latest] | |
| runs-on: ${{ matrix.os }} | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: "22.x" | |
| cache: "npm" | |
| - run: npm ci | |
| - name: Build | |
| run: npm run build | |
| # Two separate steps (not one multi-line run): on the Windows runner the default shell is | |
| # PowerShell, which only surfaces the exit code of the LAST line of a multi-line `run`; as | |
| # discrete steps each command's failure fails the job on every OS. | |
| - name: Prepare packaged CLI | |
| run: npm run prepare:bin | |
| - name: Build UI (static export) | |
| run: npm run build:ui | |
| - name: Installable-package smoke (Issue #169 AC2 / #284 AC4 cross-platform) | |
| env: | |
| # Pack the dist already built by the steps above instead of re-running the Linux-oriented | |
| # `prepack` publish gate (arch-check / package-surface / supply-chain shell out to npx/npm | |
| # in ways that are not Windows-portable — a separate concern from artifact portability). | |
| # The gating `build-scan-sbom-smoke` job keeps the full prepack pack on Linux. | |
| KEIKO_SMOKE_PACK_IGNORE_SCRIPTS: "1" | |
| run: npm run smoke:install | |
| ui: | |
| name: ui | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: "22.x" | |
| cache: "npm" | |
| - name: Install workspaces (single root lockfile after #167) | |
| run: npm ci | |
| - name: Build internal packages so contracts dist resolves for UI tsc | |
| run: npm run build:packages | |
| - name: Security audit UI dependencies (moderate and above) | |
| run: npm audit --audit-level=moderate --workspace @oscharko-dev/keiko-ui | |
| - name: Lint UI | |
| run: npm run lint --workspace @oscharko-dev/keiko-ui | |
| - name: Typecheck UI | |
| run: npm run typecheck --workspace @oscharko-dev/keiko-ui | |
| - name: Build UI (static export) | |
| run: npm run build --workspace @oscharko-dev/keiko-ui | |
| - name: Generate UI CycloneDX SBOM | |
| if: ${{ github.event_name != 'pull_request' || github.base_ref != 'feat/keiko-editor' }} | |
| run: npm sbom --sbom-format cyclonedx --omit dev --workspace @oscharko-dev/keiko-ui > ui-sbom.cdx.json | |
| - name: Test UI with coverage (jsdom + axe a11y) | |
| run: npm run test:coverage:ui | |
| - name: UI coverage ratchet | |
| run: npm run check:coverage:ui | |
| - name: Install Playwright browser | |
| if: ${{ github.event_name != 'pull_request' || github.base_ref != 'feat/keiko-editor' }} | |
| run: npx playwright install --with-deps chromium | |
| - name: Release smoke E2E | |
| if: ${{ github.event_name != 'pull_request' || github.base_ref != 'feat/keiko-editor' }} | |
| run: npm run test:e2e:smoke | |
| - name: Build package and UI assets | |
| if: ${{ github.event_name != 'pull_request' || github.base_ref != 'feat/keiko-editor' }} | |
| run: | | |
| npm run build | |
| npm run prepare:bin | |
| npm run build:ui | |
| npm run prune:package-native-optionals | |
| - name: Verify package surface | |
| if: ${{ github.event_name != 'pull_request' || github.base_ref != 'feat/keiko-editor' }} | |
| run: npm run check:package-surface | |
| - name: Smoke - keiko ui serves /api/health | |
| if: ${{ github.event_name != 'pull_request' || github.base_ref != 'feat/keiko-editor' }} | |
| run: | | |
| set -euo pipefail | |
| node dist/cli/index.js ui --port 4399 & | |
| ui_pid=$! | |
| trap 'kill "$ui_pid" 2>/dev/null || true' EXIT | |
| body=$(curl --retry 10 --retry-connrefused --retry-delay 1 -fsS http://127.0.0.1:4399/api/health) | |
| echo "health: $body" | |
| echo "$body" | grep -q '"status":"ok"' | |
| - name: Upload UI SBOM | |
| if: ${{ github.event_name != 'pull_request' || github.base_ref != 'feat/keiko-editor' }} | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: ui-sbom-cyclonedx | |
| path: ui-sbom.cdx.json | |
| retention-days: 90 |