Deployment operations
AncestryLLM is local-first software. This document covers the hosted controls used to build and publish its desktop installers; it does not describe a hosted application deployment.
Deployment-profile status
ADR-0026 accepts a future Local Desktop container profile plus explicit Connect Remote and Host Remote profiles. Unreleased 0.6 source now implements the shared profile control plane, not those future runtimes. Local Desktop is the preselected, recommended mode. An omitted profile migrates to that safe local default; an unknown schema, malformed topology, stale revision, or substituted endpoint fails closed.
Headless tooling can list the reviewed choices, inspect the stored profile, preview an exact transition, diagnose a profile/runtime mismatch, recover to Local Desktop, and emit redacted backup or support metadata:
ancestry --json deployment modes
ancestry --json deployment status
ancestry --json deployment diagnose
ancestry --json deployment metadata --purpose support
Every unattended transition requires the current schema and configuration
revision, the exact confirmation returned by a separate preview, and the
literal --unattended flag. Only Local Desktop can currently be activated.
Connect Remote activation is reserved for authenticated enrollment in #357;
Host Remote activation is reserved for the reviewed runtime integration in
#348. The host-only container-control foundation in #363 does not activate a
profile.
Profile selection never starts a listener, container, supervisor, or remote
session, and never copies, exports, imports, or uploads a family tree.
The stored endpoint origin and endpoint-identity digest are non-secret
configuration, while enrollment credentials remain in the secret store. No
mode is inferred from environment variables, Docker context, port state,
hostname, or service discovery. provider=none continues to require the local,
network-free path. A valid non-local profile without its separately authorized
runtime blocks ordinary commands but leaves deployment status, diagnose,
and Local Desktop recovery available.
This guide does not authorize using the current private sidecar as a network service or provide a current Host Remote runbook.
Host container-control foundation
Unreleased 0.6 source contains a deliberately unwired, Electron-Main-only control foundation for #348 and #349. It is not reachable from the renderer, preload bridge, shared renderer types, deployment-profile executor, CLI, or application containers, and it does not start a container during ordinary application execution. No public or supported container runtime is introduced.
The closed schema-v1 policy and plan currently accept only native Darwin arm64
with an app-owned runtime profile, Docker context, Unix socket, Docker
configuration directory, working directory, exact Engine identity and
compatibility, and exact Compose project labels. Before and after every
lifecycle action, the supervisor verifies the canonical socket path, owner,
mode, device and inode, endpoint, runtime profile, context, Engine ID, server
and API versions, operating system, architecture, and required security
options. Ambient DOCKER_HOST, DOCKER_CONTEXT, DOCKER_CONFIG, PATH
selection, and alternate endpoints are not authority. Docker and Compose run
by absolute executable path with a minimal environment, fixed arguments,
bounded input, output, and time, no shell, process-tree termination, and
redacted stable failures.
Validated plans require digest-pinned images, a numeric non-root user,
read-only roots, cap_drop: [ALL], no-new-privileges, init, app-owned named
volumes, internal networks, and loopback-only TCP publication. Host paths,
devices, host namespaces, privileged execution, writable roots, extra
capabilities, unowned labels, and ambiguous or colliding resources fail
closed. Discovery and reconciliation use the exact project identity and three
app-owned labels; conflicting resources are reported and never adopted.
Start, repair, and preserve/delete uninstall require a short-lived token bound
to that exact operation. Stop is bounded but does not delete resources.
Stable control failures are INVALID_POLICY, INVALID_PLAN,
ENDPOINT_UNTRUSTED, ENDPOINT_CHANGED, ENGINE_UNTRUSTED,
RESOURCE_CONFLICT, AUTHORIZATION_REQUIRED, and CONTROL_FAILED. Stable
process failures are PROCESS_REQUEST_INVALID, PROCESS_INPUT_LIMIT,
PROCESS_OUTPUT_LIMIT, PROCESS_TIMEOUT, PROCESS_EXIT, and
PROCESS_RESPONSE_INVALID. These codes are developer evidence, not an
end-user Host Remote troubleshooting interface.
The sanitized
issue-363-macos-arm64-container-supervisor.json
record verifies this control subset against an isolated, app-owned Colima
profile. It exercises start, stop, repair, preserve/delete uninstall, exact
inventory, hardening inspection, ambient-selection rejection, and complete
owned-resource cleanup while leaving the default Docker context and engine
unchanged. It proves neither an application image nor a supported runtime.
Remaining work includes runtime acquisition and selection, application images,
the host secret broker, profile activation, grant-authorized read-only family
tree mounts, authenticated workloads, storage migration and backup, upgrade
and rollback, interruption recovery, resource/readiness/listener budgets, the
full G5/G7 evidence set, and every additional OS, architecture, Engine, and
Compose row claimed by a future release.
Before any profile release, a separate operator runbook must cover every claimed native host and architecture, Docker Engine API and Compose compatibility, Colima/Lima as the open-source macOS default, and Docker Desktop as an optional separately licensed runtime. It must also cover explicit profile intent, identity and enrollment, immutable image digests, TLS, authentication, firewalls and listeners, the narrow host-secret broker, backups, upgrades, uninstall, monitoring, recovery, and ownership. Host Remote is limited to one trusted household, is self-supported, and has no project-operated SLA.
Release evidence must meet ADR-0026’s quantitative startup, shutdown, memory,
image-size, listener, and zero-egress budgets and the threat model’s G5-G7
gates. Emulated execution must be labeled as emulation and cannot establish
native platform or architecture support.
Full production/trusted binary signing is intentionally deferred until the
first full version release, v1.0.0. Official 0.x releases default to unsigned
binaries, so none of the signing credentials below are required to build or
publish them. This procedure prepares the mandatory v1.0.0-and-later trusted
signing environment. Signed annotated release tags are likewise deferred until
v1.0.0; protected-branch signed-commit requirements are unchanged.
Reconfigure desktop signing from macOS
The repository helper searches the current macOS user’s keychain for exactly
one valid Developer ID Application identity, exports only that identity,
generates a strong one-time PKCS#12 password, and derives the Apple Team ID.
It ignores Xcode’s Apple Development and Apple Distribution identities because
they cannot sign a Developer ID release distributed through GitHub. The helper
then creates and validates all five required Base64 payloads, securely collects
the remaining values, uploads all nine private environment secrets and four
public repository variables, and verifies the result.
The helper does not issue Apple or Windows certificates, create an Apple notary API key, create GPG keys, or provision a Windows virtual machine. The Developer ID identity, notary API key, Windows identity, and GPG keys must exist before it runs. The Apple notary credentials are used only to notarize a GitHub-distributed application; this flow does not upload to the App Store.
Destination and exact configuration
- Repository:
sodejm/AncestryLLM - GitHub Actions environment for private secrets:
desktop-signing - Repository-level public variables:
sodejm/AncestryLLM
The nine private environment secrets are:
APPLE_CERTIFICATE_BASE64APPLE_CERTIFICATE_PASSWORDAPPLE_API_KEY_BASE64APPLE_API_KEY_IDAPPLE_API_ISSUERWINDOWS_CERTIFICATE_BASE64WINDOWS_CERTIFICATE_PASSWORDLINUX_GPG_PRIVATE_KEY_BASE64LINUX_GPG_PASSPHRASE
The four public repository variables are:
APPLE_TEAM_IDWINDOWS_SIGNING_CERTIFICATE_THUMBPRINTLINUX_GPG_SIGNING_FINGERPRINTLINUX_GPG_PUBLIC_KEY_BASE64
Missing information and required inputs
The following values and procedures are intentionally not stored in this repository. Obtain them through the project’s approved credential-management process before reconfiguration:
- One valid
Developer ID Applicationcertificate and private key in the current macOS user’s unlocked keychain. Xcode or the Apple developer profile may install this identity. The helper derivesAPPLE_TEAM_ID, exports the identity into its private temporary directory, and generatesAPPLE_CERTIFICATE_PASSWORD; neither value needs to be supplied manually. [APPLE_API_KEY_SOURCE_FILE]: the original Apple notary API private-key payload, plusAPPLE_API_KEY_IDandAPPLE_API_ISSUER.[WINDOWS_CERTIFICATE_SOURCE_FILE]: the original Authenticode certificate payload and itsWINDOWS_CERTIFICATE_PASSWORD.[LINUX_GPG_PRIVATE_KEY_SOURCE_FILE]and[LINUX_GPG_PUBLIC_KEY_SOURCE_FILE]: matching exported GPG key payloads, plusLINUX_GPG_PASSPHRASE.- The complete
WINDOWS_SIGNING_CERTIFICATE_THUMBPRINTand the completeLINUX_GPG_SIGNING_FINGERPRINT. [GH_INSTALL_COMMAND]if GitHub CLI is not already installed, and the project’s approved[GH_AUTHENTICATION_METHOD]. The repository does not prescribe either one.- Access to GitHub’s hosted
windows-11-armrunner for Windows 11 validation. No repository runner registration token, provider, provisioning command, or destroy command is required.
No environment variables are required by the helper. All remaining paths and values are entered interactively so private values do not appear in command arguments or shell history. The helper generates only the temporary Apple PKCS#12 export, its password, and temporary Base64 representations. It never generates, replaces, or removes the keychain identity or any user-supplied source file.
If the correct identity cannot be made available in the current keychain, the
explicit fallback --apple-certificate-file [APPLE_CERTIFICATE_SOURCE_FILE]
accepts an existing PKCS#12 file outside the repository. That mode also prompts
for its password and APPLE_TEAM_ID.
macOS prerequisites and secure preparation
- Use a trusted macOS account and terminal. Disable shell tracing before any
credential work with
set +x. -
Unlock the current user’s login keychain. Confirm that Keychain Access shows a
Developer ID Applicationcertificate with its private key, or run this read-only check:security find-identity -v -p codesigningExactly one valid line beginning with
Developer ID Application:must be present. Apple Development and Apple Distribution lines do not count. If macOS asks whether the helper may access the private key during export, verify the selected identity and allow access for that run. - Store the Apple notary API key, Windows certificate, and GPG source files in a private location outside the AncestryLLM checkout. The helper rejects repository-local sources, including paths reached through symbolic links. Repository ignore rules cover common signing formats as a second line of defense, and the repository-safety gate rejects them even if force-added.
-
Confirm
/bin/bash,/usr/bin/base64,/usr/bin/python3,/usr/bin/security,awk,chmod,cmp,grep,mktemp,openssl,realpath,rm,tr, andunameare available. Install Xcode Command Line Tools ifxcrunand Swift are not already available:xcode-select --installThe exporter uses Apple’s Security framework and sends the generated PKCS#12 password through standard input, not a command argument.
- Install GitHub CLI with the approved
[GH_INSTALL_COMMAND]ifghis not present. Authenticatesodejmongithub.comusing[GH_AUTHENTICATION_METHOD]; that exact account must be authorized to readsodejm/AncestryLLM, update its Actions environment secrets, and update repository Actions variables. The helper rejects an inheritedGH_HOSTother thangithub.com, binds every CLI call to that host, and verifies the authenticated account and repository identity before collecting any credentials. It never resolvesghfromPATH. It checks fixed installation locations and executes the canonical file with a minimalPATH. If the reviewed CLI is elsewhere, pass its absolute, canonical, non-symlink path with--gh-executable. The executable and every canonical parent must be owned by root or the current user and must not be group- or world-writable. - Confirm
desktop-signingalready exists and has the protections required by the release runbook. The helper does not create or alter environment protection rules. -
Put the four remaining original signing payloads outside the repository in a secure directory. Restrict each file before use, for example:
chmod 600 [APPLE_API_KEY_SOURCE_FILE] \ [WINDOWS_CERTIFICATE_SOURCE_FILE] \ [LINUX_GPG_PRIVATE_KEY_SOURCE_FILE] \ [LINUX_GPG_PUBLIC_KEY_SOURCE_FILE]Each source must be a non-empty regular file owned by root or the current user, with exact mode
0400or0600; the final source path must not be a symbolic link. Do not place these files, their Base64 encodings, passwords, key IDs, issuer IDs, or passphrases in this repository, a shell command, a log, or a clipboard manager. The script disables shell tracing, masks private text entry, and uses a mode-0700temporary directory. It securely opens each user-supplied path exactly once with no-follow semantics, validates the open descriptor, copies it directly into a mode-0600snapshot, and then uses only that snapshot. If the open file changes while it is copied, the helper aborts and removes the incomplete snapshot. All generated material is removed on exit.
Generate and validate without uploading
From the repository root:
chmod 700 scripts/ancestryll-runner-secrets-helper.sh
./scripts/ancestryll-runner-secrets-helper.sh --dry-run
If the approved GitHub CLI is outside a fixed installation location, use the canonical path that you reviewed:
./scripts/ancestryll-runner-secrets-helper.sh --dry-run \
--gh-executable /reviewed/canonical/path/to/gh
The default run discovers and exports the Apple identity first. Supply four
remaining source paths, four private text values, and the Windows and Linux
public identity values when prompted. The helper asks for every user-supplied
private text value twice. A dry run checks the fixed github.com host, the
exact authenticated sodejm account, the canonical repository identity,
keychain discovery and export, descriptor-bound credential snapshots, non-empty
values, Base64 round trips, and public-identity formats, then exits without
changing GitHub.
For the explicit manual fallback, run:
./scripts/ancestryll-runner-secrets-helper.sh --dry-run \
--apple-certificate-file [APPLE_CERTIFICATE_SOURCE_FILE]
This fallback prompts for the PKCS#12 password and Apple Team ID in addition to the remaining values. The certificate file must remain outside the repository.
Upload and verify
After a successful dry run, repeat the prompts in upload mode:
./scripts/ancestryll-runner-secrets-helper.sh --upload
Review the destination summary and type the exact confirmation
UPLOAD github.com/sodejm/AncestryLLM desktop-signing AS sodejm only when
ready. Existing values with the same names will be replaced. The helper prints
the fixed host, approved authenticated account, canonical GitHub CLI path, and
version before authentication, then uses that exact executable for the
following operations:
gh secret set [SECRET_NAME] -R sodejm/AncestryLLM -e desktop-signing
gh variable set [VARIABLE_NAME] -R sodejm/AncestryLLM
Private text is supplied through standard input, never as a command argument. After all commands succeed, the helper lists the configured names, confirms all nine secret names and all four variable names exist, and reads back the four public variables to compare their complete values. GitHub deliberately does not expose Actions secret values after creation, so secret verification is limited to successful upload responses and presence of each expected name.
Independent verification and cleanup
Without displaying secret values, verify the configured names:
gh secret list -R sodejm/AncestryLLM -e desktop-signing
gh variable list -R sodejm/AncestryLLM
Confirm that every name listed above is present. Review the
desktop-signing environment in GitHub and confirm its required reviewer and
protected-branch policy remain intact. Then close the terminal, remove any
unneeded local copies using the project’s approved secure-deletion process,
and clear clipboard history if it was used. The helper removes only its own
temporary directory; it never removes user-supplied source files.
If setup fails:
Required command is missing: install that prerequisite, then rerun dry run.- host, account, authentication, or repository-identity failure: unset an
alternate
GH_HOST, reauthenticatesodejmongithub.comusing[GH_AUTHENTICATION_METHOD], and confirm that account’s repository, environment-secret, and variable permissions. - rejected credential source: use a non-empty regular file outside the
repository, owned by root or the current user, with exact mode
0400or0600; do not use a symbolic link. If the source changed during its descriptor-bound copy, stop other writers before retrying. - no valid Developer ID identity: use Xcode or the Apple developer profile to
install a
Developer ID Applicationcertificate and its private key in the current user’s keychain, then repeat the read-only identity check. - multiple valid Developer ID identities: remove or archive obsolete identities through the approved keychain process, or use the explicit PKCS#12 fallback.
- keychain export failure: unlock the login keychain, confirm the certificate has its private key, and allow private-key access when macOS prompts. The helper stops without uploading if export fails.
- Base64 round-trip failure: stop and replace the affected source file from the approved issuer or backup.
- upload failure: the script stops immediately. Rerun
--upload; successful earlier items may already have been replaced, and repeating the complete set restores a consistent configuration. - verification mismatch: do not run a release. Check repository/environment scope and authorization, then rerun the complete upload.
GitHub-hosted Windows 11 validation
The Windows ARM64 installer is built, installed, and launched natively on
GitHub’s hosted windows-11-arm image. Workflows assert Windows 11 and the
ARM64 host architecture before accepting validation evidence, then explicitly
select and probe ARM64 Python and Node.js so dependency installation,
packaging, and exercise stay on the shipped win32-arm64 boundary. The locked
desktop environment installs only the base runtime and the desktop-build
extra, which contains the sidecar packager. Third-party packages must resolve
to prebuilt wheels; uv --no-build fails the job instead of invoking a compiler
or external library toolchain. The workflow then installs and packages only the
local AncestryLLM application code. Optional remote-provider SDKs are not part
of the provider-none desktop sidecar. Evidence records ARM64 for both host and
artifact architecture.
GitHub supplies a fresh hosted VM for each job, so the repository has no
self-hosted runner registration, provider, runner group, provisioning, or
teardown procedure to maintain. If windows-11-arm is unavailable to the
repository, the Windows row remains queued or fails and the aggregate desktop
gate cannot pass; do not substitute a Windows Server image for this validation
boundary.