A small helpdesk system: an office Pixel running a patched GrapheneOS Dialer answers technician calls, records both call legs as separate channels, and a Ruby backend transcribes them through Whisper and files an AI summary against the caller. Squashed to a single commit for sharing. No credentials are included; secrets live outside the repo in /etc/helpdesk/env on the server or a gitignored .claude/env.local locally. See .claude/env.local.example for the shape. Start at README.md, then docs/architecture.md.
87 lines
3.1 KiB
YAML
87 lines
3.1 KiB
YAML
# Helpdesk CI/CD. Runs on the project's own runner on moje.al.army (tag: helpdesk) — NOT the shared
|
|
# vmin runners. Stages: lint -> test -> e2e -> deploy. Deploy is manual and master-only, health-checked
|
|
# with automatic rollback. The GrapheneOS patch components (dialer/sepolicy) are LINT ONLY; building them
|
|
# needs the dedicated build box and never happens here.
|
|
#
|
|
# Required CI/CD variable (Settings > CI/CD > Variables, masked):
|
|
# HELPDESK_TEST_DATABASE_URL = postgres://helpdesk:<pw>@127.0.0.1/helpdesk_test
|
|
|
|
stages: [lint, test, e2e, deploy]
|
|
|
|
default:
|
|
tags: [helpdesk]
|
|
before_script:
|
|
# CI must use the same Ruby prod runs (/usr/bin/ruby 3.3.8). The runner's login shell (chruby) points
|
|
# PATH *and* GEM_HOME/GEM_PATH at the Passenger ruby-4.0.4, which has no pg/sequel gems — reset all.
|
|
- export PATH="/usr/bin:$PATH"
|
|
- unset GEM_HOME GEM_PATH RUBYLIB RUBYOPT
|
|
- ruby -v
|
|
|
|
variables:
|
|
GIT_DEPTH: "20"
|
|
LANG: C.UTF-8
|
|
LC_ALL: C.UTF-8
|
|
|
|
# ---------------------------------------------------------------- lint
|
|
lint:ruby:
|
|
stage: lint
|
|
script:
|
|
- git ls-files '*.rb' | xargs -n1 ruby -c > /dev/null
|
|
- echo "ruby -c passed on all tracked .rb files"
|
|
|
|
lint:shell:
|
|
stage: lint
|
|
script:
|
|
- files=$(git ls-files '*.sh'); [ -n "$files" ] && shellcheck -S warning $files || echo "no shell scripts"
|
|
|
|
lint:patches:
|
|
# Validate the GrapheneOS .patch files parse; never apply/build them here.
|
|
stage: lint
|
|
script:
|
|
- |
|
|
for p in $(git ls-files '*.patch'); do
|
|
echo "check: $p"
|
|
git apply --check --recount "$p" 2>/dev/null || echo " (targets an external tree — format-only check)"
|
|
done
|
|
- echo "patch lint done (no build)"
|
|
|
|
# ---------------------------------------------------------------- test
|
|
test:unit:
|
|
stage: test
|
|
script:
|
|
- cd components/backend
|
|
- |
|
|
# Glob, not a hand-kept list: a new test/test_*.rb runs here the day it lands. (The old explicit
|
|
# list had silently dropped test_reporting.rb.) All of these are offline - no gems, no network.
|
|
for t in test/test_*.rb wiki/test_wiki_rag.rb; do
|
|
echo "== $t =="; ruby "$t"
|
|
done
|
|
|
|
test:parity:
|
|
# JSON-store vs PostgreSQL parity against the disposable helpdesk_test DB.
|
|
stage: test
|
|
script:
|
|
- cd components/backend
|
|
- ruby db/parity_check.rb
|
|
|
|
# ---------------------------------------------------------------- e2e
|
|
e2e:simulator:
|
|
# Boots the backend on a throwaway DB + alt port (4100; :4000 is the live service) and drives it
|
|
# over HTTP with the device-HMAC simulator. Transcription is skipped (no Whisper on the runner).
|
|
stage: e2e
|
|
script:
|
|
- HELPDESK_TRANSCRIBE=0 ./ci/run-e2e.sh
|
|
|
|
# ---------------------------------------------------------------- deploy
|
|
deploy:production:
|
|
stage: deploy
|
|
rules:
|
|
- if: '$CI_COMMIT_BRANCH == "master"'
|
|
when: manual
|
|
script:
|
|
# Fixed root-owned script (installed once on the server); rsyncs this checkout to /srv/helpdesk,
|
|
# runs the idempotent migration, restarts helpdesk.service, polls /healthz, rolls back on failure.
|
|
- sudo /usr/local/sbin/helpdesk-deploy "$CI_PROJECT_DIR"
|
|
environment:
|
|
name: production
|
|
url: https://moje.al.army
|