Skip to main content

CI Configuration

The Agent-Up CI workflow runs on every push. This page documents the repository secrets and variables that control CI behavior. Signing and release steps degrade gracefully when their credentials are absent. Codecov uploads also skip when CODECOV_TOKEN is unavailable, which is how GitHub withholds repository secrets from Dependabot and fork pull requests. Patch coverage and the slice floor still run locally in the coverage job.

Secrets are set under Settings → Secrets and variables → Actions → Secrets. Variables are set under the Variables tab in the same location.

Code coverage

SecretValue
CODECOV_TOKENRepository upload token from Codecov. Mapped onto the coverage jobs as env.CODECOV_TOKEN because GitHub Actions cannot read secrets in if conditions. Uploads skip when that env is empty, which is how GitHub withholds the secret from Dependabot and fork runs.

The .NET coverage job uploads each test project's Cobertura output separately. Each upload has a test-project-specific Codecov flag, such as agentup-server-tests, so Codecov can filter the production-project coverage contributed by an individual test module. AgentUp.Tests combines its regular and headless E2E coverage under the agentup-tests flag.

Signing — macOS

Requires an Apple Developer Program membership ($99/year).

You need two separate certificates from the Apple Developer portal: a Developer ID Application certificate (signs the individual Mach-O binaries inside the package) and a Developer ID Installer certificate (signs the .pkg itself). Export each as a .p12 file with a password, then base64-encode it: base64 -i cert.p12 | pbcopy.

Notarization uses an app-specific password, not your Apple ID login password. Create one at appleid.apple.com under Sign-In and Security → App-Specific Passwords.

SecretValue
MACOS_APP_CERTIFICATEBase64-encoded Developer ID Application .p12
MACOS_APP_CERTIFICATE_PASSWORDPassword for the Developer ID Application .p12
MACOS_INSTALLER_CERTIFICATEBase64-encoded Developer ID Installer .p12
MACOS_INSTALLER_CERTIFICATE_PASSWORDPassword for the Developer ID Installer .p12
MACOS_NOTARIZE_APPLE_IDApple ID email associated with the developer account
MACOS_NOTARIZE_APP_SPECIFIC_PASSWORDApp-specific password from appleid.apple.com
MACOS_NOTARIZE_TEAM_IDTeam ID from the Apple Developer portal (top-right of the Certificates page)
KEYCHAIN_PASSWORDAny random string — used to protect the temporary keychain created on the runner

Enable macOS signing by setting the repository variable MACOS_SIGNING_ENABLED to true.

Signing — Windows

Requires an Azure Trusted Signing account. This is Microsoft's HSM-backed cloud signing service — no hardware token required. Identity validation (same process as a traditional OV code-signing certificate) takes 1–5 business days.

Setup steps:

  1. Create an Azure subscription and a Trusted Signing account resource (Microsoft.CodeSigning/codeSigningAccounts).
  2. Complete identity validation in the Azure portal.
  3. Create a Certificate Profile (choose Public Trust).
  4. Create a Service Principal (App Registration) and assign it the Trusted Signing Certificate Profile Signer role on the account.
  5. Generate a client secret for the service principal.
SecretValue
AZURE_TENANT_IDAzure AD directory (tenant) ID
AZURE_CLIENT_IDService principal application (client) ID
AZURE_CLIENT_SECRETService principal client secret
AZURE_TRUSTED_SIGNING_ENDPOINTAccount endpoint URL, e.g. https://eus.codesigning.azure.net/
AZURE_TRUSTED_SIGNING_ACCOUNTTrusted Signing account resource name
AZURE_TRUSTED_SIGNING_CERT_PROFILECertificate profile name

Enable Windows signing by setting the repository variable AZURE_SIGNING_ENABLED to true.

Signing — Linux

Linux packages are GPG-signed. No external account is required — generate a dedicated key pair locally.

gpg --full-gen-key # RSA 4096, set a long expiry or none
gpg --list-secret-keys --keyid-format LONG # note the key ID
gpg --export-secret-keys --armor <KEY_ID> # copy the output into the secret
gpg --export --armor <KEY_ID> > packaging/linux/agent-up-signing.asc # commit the public key
SecretValue
GPG_SIGNING_PRIVATE_KEYArmored private key (--export-secret-keys --armor)
GPG_SIGNING_PASSPHRASEGPG key passphrase

Enable Linux signing by setting the repository variable LINUX_SIGNING_ENABLED to true.

The signing step produces a detached agent-up-ubuntu-linux-x64.deb.asc signature file alongside the .deb. Users can verify with:

gpg --import agent-up-signing.asc
gpg --verify agent-up-ubuntu-linux-x64.deb.asc agent-up-ubuntu-linux-x64.deb

Release

The release job uses GITHUB_TOKEN, which GitHub provides automatically. No setup required.

Releases only run on main when semantic-release determines a new version is warranted based on Conventional Commits.

The same release publishes the Server image and agent-up-helm chart to Docker Hub. Create the public repositories themassiveone/agent-up-server and themassiveone/agent-up-helm on Docker Hub, then add a token with write access.

SecretValue
DOCKERHUB_USERNAMEDocker Hub username or organization account used to push
DOCKERHUB_TOKENDocker Hub access token with write access to those repositories

If those secrets are missing, the GitHub release still succeeds until semantic-release reaches the container and chart publish steps, which then fail.

LocalInstaller NuGet publishing is optional. Add NUGET_API_KEY to publish LocalInstaller.Core, LocalInstaller.App, LocalInstaller.Packaging, and LocalInstaller.Smoke packages from the localinstaller.yml release job; when the secret is absent, the GitHub release still publishes the NuGet package files and separately labeled sample installer assets.

Mobile store release

Native mobile binaries are built by .github/workflows/mobile-ci.yaml. Path-filtered pushes run the shared Mobile test job before they smoke-build and sign. After validation, the signed AAB and IPA are uploaded to GitHub Actions artifacts with 1-day retention, before any store submit. Store upload and android-v* / ios-v* GitHub releases run only on workflow_dispatch. The desktop ci.yml signing and release steps skip when credentials are absent; the mobile store workflow is an exception and fails instead. Play upload secrets are required only on dispatch. The same Apple Match secret names as other MassiveCreationLab iOS apps can be copied onto this repository. Full flow: Mobile store release.

SecretValue
MATCH_REPOSITORYMatch git store as org/repo, typically MassiveCreationLab/certificates
MATCH_PASSWORDOpenSSL passphrase for encrypted Match files
MATCH_DEPLOY_KEYSSH deploy key for the certificates repository
APPSTORE_KEY_IDApp Store Connect API key id
APPSTORE_ISSUER_IDApp Store Connect API issuer id
APPSTORE_P8App Store Connect API private key contents
GH_PATGitHub token used only by Mobile iOS certificates init_ci
ANDROID_KEYSTORE_BASE64Base64-encoded Play upload keystore
ANDROID_KEYSTORE_PASSUpload keystore password
ANDROID_KEYALIAS_NAMEUpload key alias
ANDROID_KEYALIAS_PASSUpload key password
GOOGLE_PLAY_SERVICE_ACCOUNT_JSONPlay Developer API service-account JSON
SENTRY_DSN_MOBILEOptional agent-up-mobile DSN baked into native store builds

Sentry product telemetry

The GitOps sentry-configurator Job creates agent-up-server, agent-up-desktop, agent-up-cli, and agent-up-mobile on the self-hosted Sentry and writes their DSNs to Secret agent-up-sentry-dsn. Copy the packaged Desktop, CLI, and Server keys into GitHub Actions secrets. Cluster Helm Server does not use a GitHub secret: it reads SENTRY_DSN from that generated Secret. Mobile production web builds read SENTRY_DSN_MOBILE from Cloudflare Pages, not GitHub Actions. Native store builds also read the GitHub Actions secret SENTRY_DSN_MOBILE when it is set.

CI passes SENTRY_DSN_DESKTOP and SENTRY_DSN_CLI into .NET publish, and SENTRY_DSN_SERVER into native packaging. Unset secrets leave those binaries as SDK no-ops.

SecretValue
SENTRY_DSN_SERVERagent-up-server DSN for packaged Server service env at package time
SENTRY_DSN_DESKTOPagent-up-desktop DSN for native Desktop publish (/p:SentryDsn=...)
SENTRY_DSN_CLIagent-up-cli DSN for native CLI publish (/p:SentryDsn=...)
SENTRY_AUTH_TOKENOptional org auth token for later sentry-cli debug-file or source-map upload; not used by apps or the cluster

Do not put a DSN in Helm values or in Docker images. Unset DSN means the SDK is a no-op. Inbound filters and rate limits on the public Desktop, CLI, and Mobile projects mitigate DSN spam.

Event tags, error-only SDK policy, and injection paths are documented in Product telemetry.

JetBrains Marketplace

JetBrains Marketplace publishing is optional. Create the Agent-Up plugin entry in JetBrains Marketplace once, then add a Marketplace token from the vendor profile. The release job publishes Plugins/Jetbrains through Gradle after the GitHub release succeeds, using the same planned release version that was injected into the release ZIP.

SecretValue
JETBRAINS_MARKETPLACE_TOKENJetBrains Marketplace publishing token
JETBRAINS_PLUGIN_CERTIFICATE_CHAINOptional Base64-encoded plugin signing certificate chain
JETBRAINS_PLUGIN_PRIVATE_KEYOptional Base64-encoded plugin signing private key
JETBRAINS_PLUGIN_PRIVATE_KEY_PASSWORDOptional private-key password

If JETBRAINS_MARKETPLACE_TOKEN is not configured, CI still builds the plugin ZIP and attaches it to the GitHub release, but skips Marketplace publishing.

Repository Variables

Variables control which signing steps run. They are not secrets and can be read freely in workflow if: conditions.

VariableEffect when set to true
MACOS_SIGNING_ENABLEDEnables real macOS signing (requires the macOS secrets above)
AZURE_SIGNING_ENABLEDEnables real Windows signing via Azure Trusted Signing (requires the Azure secrets above)
LINUX_SIGNING_ENABLEDEnables real Linux GPG signing (requires the GPG secrets above)
SIGNING_SMOKE_TESTRuns a credential-free signing dry run on all platforms: ad-hoc codesign on macOS, self-signed certificate via signtool on Windows, throwaway GPG key on Linux. Useful for validating the signing pipeline before real credentials are available.

SIGNING_SMOKE_TEST and the platform-specific *_SIGNING_ENABLED variables are mutually exclusive in intent. Setting both at the same time would sign files twice.