Skip to content

Merge branch 'local-desktop-installation-support' into main #4

Merge branch 'local-desktop-installation-support' into main

Merge branch 'local-desktop-installation-support' into main #4

Workflow file for this run

name: Installer CI
on:
push:
branches: [main]
paths:
- 'install.sh'
- 'scripts/**'
- 'acfs.manifest.yaml'
- 'checksums.yaml'
- 'packages/manifest/**'
- '.github/workflows/*.yml'
- '.shellcheckrc'
- 'tests/**/*.sh'
pull_request:
branches: [main]
paths:
- 'install.sh'
- 'scripts/**'
- 'acfs.manifest.yaml'
- 'checksums.yaml'
- 'packages/manifest/**'
- '.github/workflows/*.yml'
- '.shellcheckrc'
- 'tests/**/*.sh'
jobs:
yaml-lint:
name: Workflow YAML Lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install yamllint
run: pip install yamllint
- name: Lint workflow YAML files
run: |
# Create minimal config that catches critical YAML syntax errors
cat > /tmp/yamllint.yml << 'EOF'
extends: default
rules:
line-length:
max: 200
key-ordering: disable
comments:
min-spaces-from-content: 1
document-start: disable
document-end: disable
indentation:
spaces: 2
indent-sequences: whatever
truthy:
allowed-values: ['true', 'false', 'on', 'off']
EOF
echo "Validating YAML syntax for all workflow files..."
yamllint -c /tmp/yamllint.yml .github/workflows/*.yml
echo "✅ All workflow YAML files have valid syntax"
shellcheck:
name: ShellCheck
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install ShellCheck
run: |
sudo apt-get update
sudo apt-get install -y shellcheck
- name: Run ShellCheck
shell: bash
run: |
mapfile -t files < <(git ls-files '*.sh')
shellcheck "${files[@]}"
- name: Run declare scoping linter
run: bash scripts/tests/lint_declare_scoping.sh
- name: Run pipefail safety linter
run: bash scripts/tests/lint_pipefail_safety.sh
- name: Run TTY safety linter
run: bash scripts/tests/lint_tty_safety.sh
- name: Run library globals integration test
run: bash tests/unit/test_lib_globals.sh
- name: Run macOS bootstrap mock test
run: bash tests/vm/test_macos_bootstrap.sh
manifest-drift:
name: Manifest Drift Check
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: bun install
working-directory: packages/manifest
- name: Check manifest drift
run: bun run generate --diff
working-directory: packages/manifest
- name: Install ShellCheck
run: |
sudo apt-get update
sudo apt-get install -y shellcheck
- name: Validate generated scripts (syntax + shellcheck)
run: |
EXIT_CODE=0
echo "Checking generated scripts for syntax errors..."
for f in scripts/generated/*.sh; do
[ -f "$f" ] || continue
if ! bash -n "$f" 2>&1; then
echo "FAIL: $f has syntax errors"
EXIT_CODE=1
fi
done
echo "Running ShellCheck on generated scripts..."
for f in scripts/generated/*.sh; do
[ -f "$f" ] || continue
if ! shellcheck "$f"; then
echo "FAIL: $f has ShellCheck warnings"
EXIT_CODE=1
fi
done
if [ "$EXIT_CODE" -eq 0 ]; then
echo "All generated scripts pass syntax and ShellCheck validation"
fi
exit $EXIT_CODE
checksum-verification:
name: Verify Upstream Checksums
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Verify all checksums match upstream
id: verify
run: |
chmod +x ./scripts/lib/security.sh
echo "Verifying checksums against upstream installer scripts..."
# Run verification and capture result (stderr separate to avoid corrupting JSON)
if ./scripts/lib/security.sh --verify --json > result.json 2>verify-errors.log; then
echo "✅ All checksums match upstream"
echo "status=ok" >> $GITHUB_OUTPUT
else
echo "❌ Checksum mismatches detected!"
echo "status=mismatch" >> $GITHUB_OUTPUT
# Show what's wrong
echo ""
echo "=== Mismatched checksums ==="
jq -r '.mismatches[] | " \(.name): expected \(.expected), got \(.actual)"' result.json 2>/dev/null || true
echo ""
echo "=== To fix locally ==="
echo " ./scripts/lib/security.sh --update-checksums > checksums.yaml"
echo " git add checksums.yaml && git commit -m 'chore: update checksums'"
# Fail the job
exit 1
fi
- name: Upload verification result
if: always()
uses: actions/upload-artifact@v4
with:
name: checksum-verification
path: result.json
pinned-ref-smoke:
name: Pinned Ref Smoke (checksums from main)
runs-on: ubuntu-latest
timeout-minutes: 30
container:
image: ubuntu:24.04
env:
DEBIAN_FRONTEND: noninteractive
steps:
- name: Install container prerequisites
working-directory: /
run: |
apt-get update
apt-get install -y sudo curl git ca-certificates jq unzip tar xz-utils gnupg
- name: Checkout
uses: actions/checkout@v4
- name: Configure CI sudo
run: |
echo 'ubuntu ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/90-ci-ubuntu
chmod 440 /etc/sudoers.d/90-ci-ubuntu
- name: Run pinned-ref install (checksums from main)
run: |
ACFS_REF="$(cat VERSION)" \
ACFS_CHECKSUMS_REF=main \
bash install.sh --yes --skip-preflight --skip-ubuntu-upgrade --mode safe --only lang.uv
selection-tests:
name: Selection & Contract Tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run selection tests
run: bash scripts/lib/test_selection.sh
- name: Run contract tests
run: bash scripts/lib/test_contract.sh
- name: Run security tests
run: bash scripts/lib/test_security.sh
- name: Run install helpers tests
run: bash scripts/lib/test_install_helpers.sh
- name: Run RU integration tests
run: |
bash scripts/tests/test_ru_update.sh
bash scripts/tests/test_ru_doctor.sh
test-installer:
name: Test installer (Ubuntu ${{ matrix.ubuntu }}, mode ${{ matrix.mode }})
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- ubuntu: '24.04'
mode: vibe
- ubuntu: '25.04'
mode: vibe
- ubuntu: '24.04'
mode: safe
container:
image: ubuntu:${{ matrix.ubuntu }}
env:
DEBIAN_FRONTEND: noninteractive
steps:
- name: Install container prerequisites
working-directory: /
run: |
apt-get update
apt-get install -y sudo curl git ca-certificates jq unzip tar xz-utils gnupg
- name: Checkout
uses: actions/checkout@v4
- name: Offline bootstrap simulation
run: |
bash tests/vm/bootstrap_offline_checks.sh
- name: Configure CI sudo
run: |
# CI needs passwordless sudo for upstream scripts that use sudo internally
# This is needed for safe mode since it doesn't configure NOPASSWD
# The ubuntu user is created by install.sh, so we pre-configure sudoers
echo 'ubuntu ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/90-ci-ubuntu
chmod 440 /etc/sudoers.d/90-ci-ubuntu
- name: Run installer
run: |
# Skip preflight in CI - GitHub Actions containers have limited disk (17GB < 20GB required)
# Skip Ubuntu upgrade in CI - containers can't reboot during workflow
ACFS_CI=true bash install.sh --yes --skip-preflight --skip-ubuntu-upgrade --mode ${{ matrix.mode }}
- name: Run doctor
run: |
su - ubuntu -c "ACFS_DOCTOR_CI=true zsh -ic 'acfs doctor'"
- name: Verify key tools
run: |
su - ubuntu -c "zsh -ic 'test -f ~/.acfs/VERSION'"
su - ubuntu -c "zsh -ic 'gh --version'"
su - ubuntu -c "zsh -ic 'jq --version'"
su - ubuntu -c "zsh -ic 'sg --version'"
su - ubuntu -c "zsh -ic 'git-lfs version'"
su - ubuntu -c "zsh -ic 'rsync --version'"
su - ubuntu -c "zsh -ic 'strace --version'"
su - ubuntu -c "zsh -ic 'command -v lsof >/dev/null'"
su - ubuntu -c "zsh -ic 'command -v dig >/dev/null'"
su - ubuntu -c "zsh -ic 'command -v nc >/dev/null'"
su - ubuntu -c "zsh -ic 'ntm --help'"
su - ubuntu -c "zsh -ic 'ubs --help'"
su - ubuntu -c "zsh -ic 'bv --help'"
su - ubuntu -c "zsh -ic 'cass --help'"
su - ubuntu -c "zsh -ic 'cm --help'"
su - ubuntu -c "zsh -ic 'caam --help'"
su - ubuntu -c "zsh -ic 'slb --help'"
su - ubuntu -c "zsh -ic 'dcg --version'"
su - ubuntu -c "zsh -ic 'dcg doctor'"
su - ubuntu -c "zsh -ic 'ru --version'"
su - ubuntu -c "zsh -ic 'onboard --help'"
# beads_rust (required) - issue tracking
su - ubuntu -c "zsh -ic 'br --version'"
# New stack tools (bd-1ega)
su - ubuntu -c "zsh -ic 'ms --version'"
su - ubuntu -c "zsh -ic 'apr --help || true'"
su - ubuntu -c "zsh -ic 'jfp --version || true'"
su - ubuntu -c "zsh -ic 'pt --help || true'"
su - ubuntu -c "zsh -ic 'brenner --version || brenner --help || true'"
su - ubuntu -c "zsh -ic 'rch --version || rch --help || true'"
su - ubuntu -c "zsh -ic 'wa --version || wa --help || true'"
su - ubuntu -c "zsh -ic 'sysmoni --version || sysmoni --help || true'"
# Agents
su - ubuntu -c "zsh -ic 'claude --version'"
su - ubuntu -c "zsh -ic 'codex --version'"
su - ubuntu -c "zsh -ic 'gemini --version'"
e2e-curlbash-bootstrap:
name: E2E curl|bash Bootstrap
runs-on: ubuntu-latest
timeout-minutes: 15
container:
image: ubuntu:24.04
env:
DEBIAN_FRONTEND: noninteractive
steps:
- name: Install container prerequisites
working-directory: /
run: |
apt-get update
apt-get install -y sudo curl git ca-certificates jq python3 tar gzip bash
- name: Checkout
uses: actions/checkout@v4
- name: Configure CI sudo
run: |
echo 'ubuntu ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/90-ci-ubuntu
chmod 440 /etc/sudoers.d/90-ci-ubuntu
- name: Run curl|bash bootstrap E2E test
run: bash tests/e2e/test_curlbash_bootstrap.sh
e2e-resume-after-failure:
name: E2E Resume After Failure
runs-on: ubuntu-latest
timeout-minutes: 30
container:
image: ubuntu:24.04
env:
DEBIAN_FRONTEND: noninteractive
steps:
- name: Install container prerequisites
working-directory: /
run: |
apt-get update
apt-get install -y sudo curl git ca-certificates jq unzip tar xz-utils gnupg
- name: Checkout
uses: actions/checkout@v4
- name: Configure CI sudo
run: |
echo 'ubuntu ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/90-ci-ubuntu
chmod 440 /etc/sudoers.d/90-ci-ubuntu
- name: Run resume-after-failure E2E test
run: bash tests/e2e/test_resume_after_failure.sh