Skip to content

About

Appcircle.io self-hosted scripts repository that has helper scripts for installation, upgrade, or runtime.

Resources

Stars

1 star

Watchers

6 watching

Forks

Repository files navigation

appcircle-self-hosted-scripts

Appcircle.io self-hosted scripts repository that has helper scripts for installation, upgrade, or runtime.

Script Overviews

download-runner.sh

This script was made for downloading, validating and extracting the Appcircle runner VM image and Xcode image tar.gz files in the background.

The curl command under the Download MacOS VM can exit if user closes the SSH session.

The download and unzip takes so much time. So this script handles manual tasks for the user.

For detailed usage, check the docs.

By default the images are downloaded from https://storage.googleapis.com/appcircle-dev-common/self-hosted. To download them through a mirror of that location, such as an artifact proxy on a host without internet access, set AC_RUNNER_IMAGE_BASE_URL:

AC_RUNNER_IMAGE_BASE_URL="https://nexus.example.com/repository/appcircle-gcs" ./download-runner.sh 260914
  • The image version is required with a mirror, because the latest image is found through the Google Cloud Storage API.
  • Credentials for the mirror are read from ~/.netrc when it has an entry for the mirror host.
  • Each image is verified with the MD5 checksum in the <file>.md5 file next to it. With the default location the script falls back to the MD5 checksum in the object's ETag while the .md5 files are not published. With a mirror there is no fallback, because a mirror serves its own ETag.

download-server.sh

You can use that script to download the latest Appcircle server package.

Save the script to a directory. Save the cred.json file to the same directory.

Run the script with no argument.

./download-server.sh

This will download the latest and licensed Appcircle server for your cred.json file.

harden-host.sh

Applies a security baseline to the physical macOS host that runs the Tart VMs, based on a subset of the CIS macOS Level 1 benchmark. Audit-only and dry-run modes are available. Published as harden-macos-host.sh (see Publishing).

For detailed usage, check the docs.

run.sh

The ephemeral runner loop for a Tart macOS VM. Clones the base VM, runs the clone until the build finishes, deletes the clone and repeats. Started either manually or, preferably, by runner-service.sh.

Beyond the loop it prepares the host for an unattended start: waits for tart and for outbound networking to become usable at boot, removes clones orphaned by a crash or a hard stop, and unlocks the login keychain.

That last step is what lets a runner survive a host reboot with nobody logged in. On macOS 15 and newer, tart cannot read the Virtualization.framework HostKey unless the runner account's login keychain is unlocked, and fails with VZErrorDomain Code=-9 otherwise. Put the keychain password in a mode-600 file owned by the runner account and run.sh performs the unlock itself:

mkdir -p ~/.appcircle && chmod 700 ~/.appcircle
printf '%s' '<keychain-password>' > ~/.appcircle/runner-keychain.pw
chmod 600 ~/.appcircle/runner-keychain.pw

Override the path, never the secret, with KEYCHAIN_PW_FILE. Without the file the unlock is skipped, which is correct on macOS 13 and when a desktop session has already unlocked the keychain.

runner-service.sh

Installs run.sh as a per-runner launchd system daemon so the runners start at boot and are unaffected by an SSH session being closed. The service label is derived from the runner folder name, so $HOME/runner1 becomes io.appcircle.runner1 and several runners on one host get independent services.

sudo ./runner-service.sh install <vm-name>
sudo ./runner-service.sh stop [--now] [--disable]
./runner-service.sh status
./runner-service.sh logs

check-runner-host.sh

Read-only readiness check for a runner host. Reports PASS, WARN or FAIL per item and exits non-zero on any failure. Covers sizing, MDM policy and password rotation, desktop session and keychain state, auto-login and FileVault, power settings, automatic updates, security posture, corporate root CA trust and TLS interception, egress reachability, Tart and VM images, and runner supervision.

Run it before opening a support ticket about a runner that will not start.

Publishing

The scripts are served to customers from https://cdn.appcircle.io/self-hosted/ and the documentation links to that URL. Publishing is manual, so the mapping below is the only record of which repository file becomes which public file. Keep it accurate.

Repository file Published as
download-runner.sh https://cdn.appcircle.io/self-hosted/download-runner.sh, and the same file as download-runner-beta.sh while older docs and customer automation still use that name
harden-host.sh https://cdn.appcircle.io/self-hosted/harden-macos-host.sh
run.sh https://cdn.appcircle.io/self-hosted/run-<VERSION>.sh
runner-service.sh https://cdn.appcircle.io/self-hosted/runner-service.sh
check-runner-host.sh https://cdn.appcircle.io/self-hosted/check-runner-host.sh
download-server.sh https://cdn.appcircle.io/self-hosted/download-server.sh

download-server.sh is the script the server installation and update docs run with curl ... | bash. It must keep working with the stock tools of Linux and macOS (no grep -P, no tac, bash 3.2 syntax); ./tests/download-server-tests.sh checks that on both.

Two of these rows are renames rather than plain copies, and nothing enforces either one, so verify the published URL after every upload.

harden-host.sh is published under a different name than it has here. This was recorded nowhere before, and cdn.appcircle.io/self-hosted/harden-host.sh returns 404 while harden-macos-host.sh serves the file.

run.sh is published per version, not under a fixed name, because a given run.sh is only guaranteed to work with the macOS VM image it shipped with. Take VERSION from the top of the script, so 1.9.0 is published as run-1.9.0.sh, and add a tab for it in the macOS VM setup page next to the image version it belongs to. A bare run.sh also exists on the old storage bucket, pinned at 1.0.2 and reachable by hosts installed before this convention; leave it in place, it is not the current download path.

macOS VM and Xcode images

The images are not built from this repository, but download-runner.sh depends on how they are published. Upload an MD5 checksum file next to every macOS_<version>.tar.gz and xcodes_<version>.tar.gz in gs://appcircle-dev-common/self-hosted/, in the format md5sum prints (<checksum> <file name>). The latest-image lookup (no image version given) matches only macOS_*.tar.gz and xcodes_*.tar.gz since 1.2.1; up to 1.2.0 it matched every name starting with macOS or xcodes and picked a .md5 file once they were published. Cloud Storage already keeps the MD5 of each object, so the file can be written from the object metadata without downloading the image:

B=gs://appcircle-dev-common/self-hosted
f=macOS_260914.tar.gz
printf '%s  %s\n' "$(gcloud storage objects describe "$B/$f" --format='value(md5_hash)' | base64 -d | xxd -p)" "$f" > "$f.md5"
gcloud storage cp --no-clobber --content-type=text/plain "$f.md5" "$B/"

Without these files the script cannot verify downloads made through a mirror (AC_RUNNER_IMAGE_BASE_URL), and it stops.

Testing

Environment Information

  • The tests should run in a clean environment.
  • You can test overall functionality with bash script tests.
  • You can see all the tests inside the tests folder.
  • The ones with names ending with *Test.sh files are the test cases that are waiting to run.
  • For example, to run tests for the download-runner.sh, you can simply call it:
./tests/download-runner-tests.sh

⚠️ Warning: The test scripts must be executed from the repo's root directory. For instance, ./tests/download-runner-tests.sh. The command running inside the tests folder as ./download-runner-tests.sh will not work.

  • You should see an output like:
You can see the outputs in ./tests/reports/test-6514-23621 folder
testRunnerDownload
test-6514-23621 test starting
Tests finished.

Ran 1 test.

OK
  • If you face any errors while testing and want to see the outputs, please check the ./tests/reports folder.
  • Test outputs are written to that directory with the name of test id.

Test Cases

  • download-runner-mirror-tests.sh runs download-runner.sh against a local mirror (tests/mirror-server.py) and needs no internet access, only macOS and python3:
    • testMirrorDownloadWithChecksum: downloads, verifies with the .md5 files and extracts through the mirror; a trailing slash in the URL is accepted.
    • testMirrorRequiresVersion: fails before downloading when no version is given.
    • testMirrorChecksumMismatch: fails when the checksum does not match.
    • testMirrorMissingChecksumFile: fails when the mirror does not serve the .md5 file.
    • testMirrorWithNetrcCredentials: fails without credentials and succeeds with them in ~/.netrc.
    • testMirrorUrlHidesCredentials: credentials in the URL work and are not printed.
  • download-runner-tests.sh
    • testRunnerDownload
      • Valid remote MD5 for macOS images should be found.
      • MD5 check for macOS image should be successful.
      • Valid remote MD5 for Xcode images should be found.
      • MD5 check for Xcodes image should be successful.
      • MacOS image should be extracted successfully.
      • MacOS image directory should be found in the "$HOME/.tart/vms" directory.
      • Xcode images should be extracted successfully.
      • Xcode images directory should be found in the "$HOME" directory.
      • Xcode images directory should contain some dmg files.
      • Script output should container success log.
    • testRunnerDownloadWithNonExistingVersion
      • Script output should contain 404 logs 6 times.
      • Script output should contain fail log.

About

Appcircle.io self-hosted scripts repository that has helper scripts for installation, upgrade, or runtime.

Resources

Stars

1 star

Watchers

6 watching

Forks

Releases

Packages

Used by

Contributors

Languages