Skip to content

Commit c1137e0

Browse files
authored
v1 release infrastructure: UI overhaul, README, CI, release pipeline (#1)
* Overhaul dashboard UI to match Android Replace the flat list/text dashboard with Android-parity device cards: each peer renders as a Material-3 card containing a tile grid (hero/wide + paired narrow tiles), with quick actions, overflow menu, and a per-tile bottom-sheet detail view. Tile layouts persist per-device in IndexedDB. Self device pins to the top-left of a responsive multi-column grid that scales to ultrawide displays. Read-only modules (Apps, Power, WiFi, Connectivity) join Clipboard/Files/Meta via a central module registry with ETag-cached payload decoding. Adds a sticky nav header (title + identity subtitle + version pill + last-sync pill + Refresh + Settings + overflow), Settings sheet (editable device label with republish + read-only diagnostics + SHA-256 keyset fingerprint), and route-level width classes (onboarding stays narrow, dashboard fills viewport up to header cap at 1400px). * Add P0+P1 unit tests and smoke harness P0 (correctness-critical): base64 ↔ bytes roundtrip, HKDF-SHA256 against RFC 5869 vectors, blob-cipher roundtrip + AAD format pinning. P1 (high-value): mocked-fetch coverage of the octi-api surface (auth header, deviceHeaders propagation including label, URL encoding, ETag passthrough, 412 mapping), blob-session lifecycle (create → multi-chunk PATCH with Upload-Offset progression → finalize → returns blobId), including the dangerous-server failure modes the implementation could previously hang on (non-progressing offset → infinite loop, offset past ciphertext length); poll-loop fake-timer coverage (interval, visibility pause + immediate-on-focus, re-entrancy dedup, error survival, stop); credentials-repo IndexedDB roundtrip via fake-indexeddb (stale-pointer scrub, multi-account list, wipe). Adds blob-session offset-progress guards to fix the infinite-loop on a misbehaving server (Codex flagged during plan review). Adds src/__smoke__/smoke.test.ts: full account-create → encrypted meta publish + read against a real sync-server. Skipped by default; CI smoke job runs it explicitly via SMOKE_SERVER_URL. Adds jsdom devDep for the localStorage + document tests. * Add app icon, manifest, custom-domain hosting Vendors the Octi.png master from app-desktop's resources (512×512) into public/icons/, plus ImageMagick-downscaled 192 (PWA + Apple touch + nav header) and 32 (favicon) variants. Adds a webmanifest declaring name/short_name/standalone-display/theme + the two PWA icon sizes. Adds public/CNAME for the custom-domain Pages hosting at web.octi.darken.eu (must be DNS-pointed at GitHub Pages before the first release). Wires <link rel="icon|apple-touch-icon|manifest"> + <meta name="theme-color"> into index.html (CSP already allows img-src 'self' data: and manifest-src 'self'). Adds inline boot-flash style so the tab background matches the dark theme between document parse and Svelte mount. Renders the 36×36 brand icon next to the title in NavBar (restructures .identity into a flex row), and re-cases the title to "Octi Web" to match the wordmark. * Rewrite README for v1 release Drops the Status/Stack/Storage sections (internal churn / not user-facing) and leads with the Octi banner + badges (release version, CI status, license, Discord) above an Install section pointing at the hosted instance, the static-host tarball, and the Docker image. Keeps the sync-server CORS guide (still relevant to self-hosters), compatibility notes (shortened), and the Develop block (with the new pnpm test:smoke target) at the bottom. Adds an explicit mixed-content caveat for users with HTTP-only LAN sync-servers. * Add CI: type-check, test, build, smoke, release-tooling Five parallel jobs on every PR/push to main: svelte-check (types), vitest (unit tests), Vite production build (with dist upload as a 7-day artifact for reviewer spot-checks), a real-server smoke job against a digest-pinned sync-server Docker service (account create + encrypted-meta roundtrip), and the release-tooling validator (shellcheck + bats on bump.sh, consistency check). Composite action .github/actions/common-setup installs pnpm + Node 24 with pnpm-cache enabled so every job warms in seconds. Actions pinned by SHA + version comment, matching the Android repo's pattern. Release-tooling job runs even though bump.sh isn't committed yet — the next commit adds it; CI on this branch's first push will show that job red until the release pipeline commit lands. * Add release pipeline (prepare + tag + Pages + Docker) Ports the Android dispatch UX (Actions tab → Release prepare → version inputs → optional dry-run → atomic commit + tag push) to a Node/Vite SPA. Source of truth is package.json#version (no version.properties / versionCode — web has no app-store gating). tools/release/bump.sh mirrors the Android bump.sh CLI (--mode={check,plan,write}, --bump-kind, --version-type, --version-override, --expected-current) and refuses to bump from the placeholder 0.0.0 without an explicit override. 16-case bats suite + shellcheck-clean. release-prepare.yml gates Job 2 with the web-production environment so the bump commit + tag push happen only after operator approval — diverges from Android's pattern (rationale documented in RELEASE.md and inline). Job 1 also asserts the named required checks (check/test/build/smoke/release-tooling) are present + green on the candidate commit so a path-ignored push can't sneak through. release-tag.yml fans out three publish jobs after a single validate-tag (regex, on-main, name matches): release-github (tarball + softprops/action-gh-release with pre-release flag for -rc/-beta), release-pages (configure-pages → upload-pages-artifact → deploy-pages, environment github-pages, pages:write + id-token:write), release-docker (login-action + buildx + multi-arch amd64+arm64, :latest only on suffix-free vM.m.p). pages.yml standalone manual deploy mirrors Android. Dockerfile is a two-stage node:24-alpine → nginx:alpine static serve; the strict CSP travels with index.html's meta tag. .dockerignore keeps the image lean. RELEASE.md walks the one-time setup (App install, ruleset bypass, GH Pages enable, environment, DNS, sync-server digest refresh) and the first-release dispatch flow. * Fix test:smoke filter — pass path positionally instead of --dir vitest's --dir changes the project root, so 'src/**/*.test.ts' (relative to the new root) finds nothing inside the directory we wanted to filter. Pass the test path positionally so vitest uses it as a name filter against the configured include pattern.
1 parent 133bfb6 commit c1137e0

81 files changed

Lines changed: 8479 additions & 476 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
node_modules
2+
dist
3+
.git
4+
.github
5+
*.md
6+
.dockerignore
7+
Dockerfile
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Common setup
2+
description: Install Node + pnpm with cached dependencies.
3+
4+
runs:
5+
using: composite
6+
steps:
7+
- name: Install pnpm
8+
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
9+
with:
10+
version: 10.12.3
11+
12+
- name: Install Node.js
13+
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
14+
with:
15+
node-version: 24
16+
cache: pnpm
17+
18+
- name: Install dependencies
19+
shell: bash
20+
run: pnpm install --frozen-lockfile

.github/featureGraphic.jpg

45.1 KB
Loading

.github/workflows/code-checks.yml

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
name: Code tests & eval
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
check:
14+
name: Type check
15+
runs-on: ubuntu-22.04
16+
steps:
17+
- name: Checkout source
18+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6.0.2
19+
with: { persist-credentials: false }
20+
- name: Setup environment
21+
uses: ./.github/actions/common-setup
22+
- name: svelte-check
23+
run: pnpm check
24+
25+
test:
26+
name: Unit tests
27+
runs-on: ubuntu-22.04
28+
steps:
29+
- name: Checkout source
30+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6.0.2
31+
with: { persist-credentials: false }
32+
- name: Setup environment
33+
uses: ./.github/actions/common-setup
34+
- name: vitest
35+
run: pnpm test
36+
37+
build:
38+
name: Production build
39+
runs-on: ubuntu-22.04
40+
steps:
41+
- name: Checkout source
42+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6.0.2
43+
with: { persist-credentials: false }
44+
- name: Setup environment
45+
uses: ./.github/actions/common-setup
46+
- name: Build production bundle
47+
run: pnpm build
48+
- name: Upload dist artifact
49+
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.6.0
50+
with:
51+
name: dist-${{ github.sha }}
52+
path: dist/
53+
retention-days: 7
54+
55+
smoke:
56+
name: Smoke (real sync-server)
57+
runs-on: ubuntu-22.04
58+
timeout-minutes: 10
59+
# Pin sync-server by digest so this test can never silently shift if `latest`
60+
# is republished. Refresh intentionally when targeting a different release.
61+
services:
62+
sync-server:
63+
image: ghcr.io/d4rken-org/octi-server@sha256:bdb7a647a4d74ad39d17170080d9aacc94159f412b147372825c23e7067fa0b7
64+
ports:
65+
- 18080:8080
66+
env:
67+
OCTI_CORS_ALLOWED_ORIGINS: 'http://127.0.0.1:5173,http://localhost:5173'
68+
steps:
69+
- name: Checkout source
70+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6.0.2
71+
with: { persist-credentials: false }
72+
- name: Setup environment
73+
uses: ./.github/actions/common-setup
74+
- name: Wait for sync-server
75+
run: |
76+
set -euo pipefail
77+
for attempt in $(seq 1 30); do
78+
if curl -sf http://127.0.0.1:18080/v1/status > /dev/null; then
79+
echo "sync-server up after ${attempt}s"
80+
exit 0
81+
fi
82+
sleep 1
83+
done
84+
echo "sync-server did not respond within 30s" >&2
85+
docker logs ${{ job.services.sync-server.id }} || true
86+
exit 1
87+
- name: Run smoke suite
88+
env:
89+
SMOKE_SERVER_URL: http://127.0.0.1:18080
90+
run: pnpm test:smoke
91+
- name: Dump sync-server logs on failure
92+
if: failure()
93+
run: docker logs ${{ job.services.sync-server.id }} || true
94+
95+
release-tooling:
96+
name: Release tooling
97+
runs-on: ubuntu-22.04
98+
steps:
99+
- name: Checkout source
100+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6.0.2
101+
with: { persist-credentials: false }
102+
- name: Install bats + shellcheck
103+
run: |
104+
sudo apt-get update
105+
sudo apt-get install -y bats shellcheck
106+
- name: Shellcheck bump.sh
107+
run: shellcheck tools/release/bump.sh
108+
- name: Run bump.sh unit tests
109+
run: bats tools/release/bump.bats
110+
- name: Verify package.json + bump.sh are consistent
111+
run: tools/release/bump.sh --mode=check

.github/workflows/pages.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Deploy Pages (manual)
2+
3+
# Standalone manual deploy of the current main to GitHub Pages. The normal
4+
# release flow auto-deploys via release-tag.yml; this workflow is for testing
5+
# a Pages-affecting change without cutting a tag.
6+
7+
on:
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
pages: write
13+
id-token: write
14+
15+
concurrency:
16+
group: pages
17+
cancel-in-progress: false
18+
19+
jobs:
20+
deploy:
21+
name: Build & deploy
22+
runs-on: ubuntu-22.04
23+
environment:
24+
name: github-pages
25+
url: ${{ steps.deploy.outputs.page_url }}
26+
steps:
27+
- name: Checkout source code
28+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6.0.2
29+
with:
30+
ref: main
31+
persist-credentials: false
32+
33+
- name: Setup environment
34+
uses: ./.github/actions/common-setup
35+
36+
- name: Build production bundle
37+
run: pnpm build
38+
39+
- name: Configure Pages
40+
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0
41+
42+
- name: Upload Pages artifact
43+
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1
44+
with:
45+
path: dist/
46+
47+
- name: Deploy to Pages
48+
id: deploy
49+
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5

0 commit comments

Comments
 (0)