Bot authentication
Workflows that need elevated, cross-repo, or branch-protection-bypassing access authenticate as a GitHub App,
minting a short-lived installation token at runtime via
actions/create-github-app-token. Each workflow exposes two
optional workflow_call secrets, APP_ID and APP_PRIVATE_KEY, that the caller wires to the relevant App.
To avoid breaking repositories that have not yet been migrated, each workflow resolves its token with a fallback chain:
App token (if APP_ID + APP_PRIVATE_KEY are set) → legacy bot PAT (if set) → github.tokengithub.token is a viable last resort only for the module release checkouts, backend and frontend alike, which are
repo-local operations. The remaining operations cannot work under it (cross-repo dispatch/push for the distro and
dashboard workflows, and a CI-triggering, self-approvable PR for translations), so those jobs omit it and fail fast
with a clear error when neither App credentials nor the legacy PAT are supplied.
So a repo that passes the App credentials uses the App; a repo still passing the old PAT keeps working unchanged. Once
every consuming repo has migrated, the legacy PAT secrets and the || secrets.<PAT> fallback can be removed.
These five functions are backed by four Apps, each installed only where it is needed and granted the minimum permissions:
| Function | Workflow | App permissions | Installed on |
|---|---|---|---|
| Translation updates | tx-pull.yml | contents: write, pull-requests: write | repos with Transifex automation |
| Backend module release | release-backend-module.yml | contents: write (+ ruleset bypass) | released backend module repos |
| Frontend module release | release-frontend-module.yml | contents: write (+ ruleset bypass) | released frontend module repos |
| Distro build trigger | release-frontend-module.yml | actions: write | openmrs-distro-referenceapplication |
| Security dashboard | owasp-dependency-check.yml | contents: write | openmrs-contrib-dependency-vulnerability-dashboard |
release-frontend-module.yml accounts for two of those rows and exposes only one APP_ID / APP_PRIVATE_KEY pair, so a
single App covers both: it pushes the release commit and tag to the calling repo, and dispatches the build on the
distro repo. Install it in both places, with the permissions each row lists.
Recommended org-secret names for the App credentials: OMRS_TRANSLATION, OMRS_MODULE_RELEASE, OMRS_ESM_RELEASE, and
OMRS_SEC_DASHBOARD (each with an _APP_ID / _APP_PRIVATE_KEY pair). A caller wires them to the generic inputs, e.g.:
jobs:
pull-translations:
uses: openmrs/openmrs-contrib-gha-workflows/.github/workflows/tx-pull.yml@main
secrets:
TRANSIFEX_TOKEN: ${{ secrets.TRANSIFEX_TOKEN }}
APP_ID: ${{ secrets.OMRS_TRANSLATION_APP_ID }}
APP_PRIVATE_KEY: ${{ secrets.OMRS_TRANSLATION_APP_PRIVATE_KEY }}Setup notes
- Branch-protection bypass: unlike an admin PAT, a GitHub App token does not bypass branch protection / rulesets implicitly. The module release Apps, backend and frontend, must each be added to their target repos’ ruleset bypass list: the frontend one pushes a release commit and tag straight to the default branch.
- App credentials are all-or-nothing: supply both
APP_IDandAPP_PRIVATE_KEYor neither. Supplying only one (e.g. a typo in a secret name) fails the run, rather than silently falling back to the PAT. - Cross-repo scope: the distro and dashboard tokens are minted scoped to the target repo (
owner+repositories), so those Apps must be installed on the target repo even when the workflow runs elsewhere. Both module release tokens are minted unscoped instead, against the calling repo’s own installation. github.tokenis a repo-local safety net only: it cannot bypass branch protection or act across repositories. Both module release checkouts fall back to it (a push only fails later if the branch is protected), but the distro-dispatch, dashboard-sync, and translation workflows omit it from the fallback and fail fast with a clear error when neither App credentials nor the legacy PAT are provided.- Dashboard sync is org-scoped:
owasp-dependency-checkonly syncs the report to the dashboard repo onpush/workflow_dispatchevents in theopenmrsorg, so forks run the scan without needing dashboard credentials. - Token lifetime: App installation tokens expire after one hour. A backend release pushes its commit/tag during
release:prepare, well before the longerrelease:performdeploy, so the token is normally used long before it expires. For an unusually long pre-push build, use the legacy PAT, which does not expire.