# Openship Actions
URL: https://openship.io/docs/guides/actions.md

Run GitHub-compatible workflows on connected servers and temporary Cloud runners.

Actions runs repository CI and standalone automation on Openship's authorized
destinations. Workflows can be linked to projects or run independently. Jobs can
schedule an application command or invoke a saved workflow, with the same Actions
execution, topology and logs.

## Workflow sources

Select a repository and Openship discovers its workflows. The file's location
selects its integration automatically; the editor, destinations, capacity limits
and run history stay together.

- **`.github/workflows/`:** GitHub coordinates the workflow and its Checks, secrets,
  environments, artifacts and caches. Official runners on your selected Openship
  destinations execute jobs routed to them. This supports reusable workflows,
  releases, tags and protected environments.
- **`.openship/workflows/` or Standalone:** Openship schedules the YAML and runs
  jobs with act, using its scoped credentials and configured storage. The
  compatibility limits below apply to these independent workflows.

## Run only in Openship

Store the workflow in `.openship/workflows/ci.yml`. GitHub ignores this directory:
using GitHub's YAML syntax does not start GitHub Actions. Openship discovers the
file, schedules its declared triggers and executes jobs on your allowed runners.
This also works when GitHub Actions is disabled for the repository.

1. Add the file to the repository. When moving CI from GitHub, move the file out
   of `.github/workflows/`; leaving a copy there keeps its GitHub triggers active.
2. Open the project's **Actions** tab, select the repository and import the file.
3. Choose the runners, access policy and notifications, then save.
4. Run it manually or push a commit matching its `on: push` rules. Automatic GitHub
   events require a connected App subscribed to those events and a reachable webhook.

For example, this workflow checks out a private repository and runs its Node tests
on an allowed Linux runner with Git and Node available:

```yaml title=".openship/workflows/ci.yml"
name: CI
on:
  push:
    branches: [main]
  workflow_dispatch:
permissions:
  contents: read
jobs:
  test:
    runs-on: [self-hosted, openship, linux]
    steps:
      - uses: actions/checkout@v4
      - run: node --test
```

Private checkout uses a repository-scoped App token. Publishing results needs the
App's **Checks: write** permission. An Openship Check on a commit is a status report;
it does not create a GitHub Actions run. Follow execution and live logs in Openship.
The independent-workflow compatibility limits below still apply.

## Use GitHub-coordinated workflows

Files in `.github/workflows/` require runner-management access: a GitHub App with
**Actions: write** and **Administration: write**, or a suitable repository token.
Existing App installations may need to approve these permissions. Editing workflow
files also needs **Contents: write** and **Workflows: write**; new Openship App
manifests request them for the editor. Configure secrets and variables in
GitHub's repository or organization settings.

To route jobs to Openship, use explicit labels:

```yaml
runs-on: [self-hosted, openship, linux, x64]
```

For a connected Mac, use `macos` and its actual CPU architecture. A plain
`ubuntu-latest` job remains on GitHub-hosted runners. Add a Cloud size label such as
`openship-linux-2` when selecting a specific allowed profile.

A GitHub runner registration belongs to the repository and may receive any matching
job, including reusable-workflow jobs. Openship checks the actual assigned workflow,
requester and approval before starting workflow code. Configure that policy in the
**Access** step; a matching label alone does not grant permission.

## Add a runner

Open **Actions → Runners → Add runner** and choose a destination:

- **Existing server:** select a connected or managed application server. Set
  per-job CPU, memory and parallel limits to leave capacity for its applications.
  The server keeps its existing billing.
- **Dedicated server:** create a managed server through the shared server and plan
  dialog, then configure it as a runner. Its normal server subscription applies.
- **Temporary Cloud runners:** choose a disposable VM profile using your prepaid
  Actions balance. Each executed job gets a VM, which is removed after cleanup.

Openship probes the selected server's OS, architecture, Git, Node and Docker
capabilities before enabling a runtime.

- **Linux containers:** use a runner image with the tools your workflow needs.
  Docker and service-container actions require Docker on the destination.
- **Native Linux:** use the server's installed toolchain with Git and Node available.
- **Native macOS:** use a connected Mac with Git and Node installed. Native mode
  is selected by default, even when the Mac also has Docker. Jobs execute
  as the connected server user and share that user's filesystem and installed tools.
- **Temporary Cloud runners:** each job receives a disposable Linux VM. Its funding
  is separate from managed application-server subscriptions.

The runner picker shows its execution OS, Docker/native mode and verified CPU
architectures. Expand **Environment & labels** to see the host version, default image,
per-job limits and routing labels. For example, an Ubuntu 24.04 host can use an
Ubuntu 22.04 default container image; these are separate environments.

New connected runners use their verified OS and architecture labels. The Ubuntu
image preset does not add `ubuntu-latest` or a version alias. Existing saved labels
remain intact. Add a custom routing label only when your workflow needs it; a label
does not select a different image or install tools.

Only run trusted code on persistent destinations. Enabling a native runner gives
its workflows the same host access as the connected user. Runner labels select
compatible capabilities; adding `macos` to a Linux runner does not make it a Mac.

The runner image is a default. Each job can use its own compatible Linux image with
`jobs.<job>.container`, including Debian, Alpine and language images. The image must
provide the shell and tools used by its steps; a minimal image does not include the
full GitHub-hosted toolchain. Container image options and registry credentials remain
available in YAML.

For container runners, **Enable CPU emulation** installs the missing QEMU/binfmt
support on the selected Docker host and verifies it by executing a foreign binary.
It requires server administration access. Existing working emulators are reused.
Normal capability checks do not install packages or register emulators. Use the
standard `x64` or `arm64` runner label to select a CPU; use a matrix for both:

```yaml
jobs:
  test:
    strategy:
      matrix:
        arch: [x64, arm64]
    runs-on: [self-hosted, openship, linux, "${{ matrix.arch }}"]
    container: alpine:3.22
    steps:
      - shell: sh
        run: uname -m
```

The selected image needs a build for that architecture. QEMU can be slower than
native execution. `runner.arch` and `RUNNER_ARCH` describe the selected execution
architecture; native macOS jobs still need a real Mac.

**Allow Docker access** enables Docker build actions on a connected container runner;
enable it only for trusted workflows because it grants access to that server's Docker
daemon. Cloud job containers use the Docker daemon of their own private disposable VM.
They receive no provider credentials or access to other customers' machines.

## Connect a workflow

Open **Actions → Add workflow**, **Project → Actions**, or the Actions section in
the deployment wizard. These entry points share the same setup:

1. Select a repository and branch. Openship discovers files in `.github/workflows/`
   and `.openship/workflows/` and previews their job dependencies as a topology.
   Check several files or choose **Select all** to add them together. Select a
   filename to preview it; each file keeps its own draft and undo history.
2. The canvas stays visible while you edit. Select a job to open its settings in the
   right panel. Expand its canvas node to reveal a grid of step cards connected by
   execution-order arrows; selecting a step opens its editor. **List** edits those
   same steps inline on the left, without
   duplicating them in the right panel. Jobs and steps expand independently, and
   open steps stay open when switching views. Connect jobs to set dependencies
   and select a connection to remove it. **List** and **YAML** show the same draft; undo and redo work across
   views. **Job YAML** exposes matrix, services, conditions, permissions and step
   inputs. Dependency cycles and deletion of referenced job outputs are rejected.
3. Use **Run settings** on the right to choose the required runners and configure
   triggers. If no runner exists, the selector opens runner setup in a modal;
   saving selects the new runner without leaving your draft. The current project
   is linked automatically. The generic editor keeps extra project links under a
   disclosure. Independent workflows also configure variables, secrets and artifact
   storage here; GitHub workflows use their repository settings.
   Runner destinations, enabled state and project links apply to the selected
   files. Trigger edits apply to the file being previewed.
4. In **Access**, choose who can run and whether each run needs approval. Defaults
   allow only your connected account, require approval for each run and block forks.
   Choose specific GitHub users or repository collaborators with write access to
   extend access. These settings apply to the selected files.
5. In **Checks**, review the connected GitHub account and the selected repository's
   access. **Connect GitHub** or **Review access** opens setup without leaving your
   draft; unavailable checks can be retried. GitHub workflows retain their original
   Checks. Independent repository workflows need a GitHub App with **Checks: write**.
   For notifications, choose **Add channel**, enter its destination and select
   **Send test & use**. Failed verification stays retryable in the same dialog.
   Select failures, successes or cancellations; notifications remain optional.
   Choose required workflows in the project's **Deployment automation** tab.
6. Save the workflow. Canvas and trigger edits preserve unrelated YAML and
   expressions. Before writing back to GitHub, review the changes and choose
   **Commit and save**. `.openship/workflows` also offers **Save Openship copy**.
   `.github/workflows` always runs committed YAML. A changed file on GitHub rejects
   the commit instead of overwriting someone else's changes.

GitHub workflow management uses the instance's existing credential resolver: an
authorized local CLI login, personal token, or repository-scoped GitHub App
(including an App connected through Openship Cloud). A detected CLI login can
read repository information before you authorize it for management. Choose
**Review access → Change method → Use gh CLI** to select it explicitly.
Repository Actions and runner-management permissions still apply; signing into
GitHub alone does not grant them. Cloud uses the connected user's credentials or
App installation and never the Cloud host's CLI login. Independent Checks use a
GitHub App with Checks write access. Actions currently supports github.com, not
GitHub Enterprise destinations.

All selected files are validated before their workflow records and project links
are saved in one transaction. Retrying an import reuses existing records, retains
their settings and adds any new project links; it does not duplicate workflows or
start a run. Edit an already connected workflow from its Actions page to change
its saved configuration. Reviewed repository commits can trigger the repository's
normal automation, and are separate from the database transaction.

## Access and approvals

Access policies apply on both connected servers and Cloud destinations. **Only my
account** uses your connected GitHub identity for repository workflows and your
Openship identity for standalone workflows. Selected GitHub users are verified by
account ID; the original requester and anyone retrying a run must both be eligible.

With **Approve each run**, an Actions administrator with access to its destinations
reviews the commit, attempt and runners before any runner is allocated. Changing
the policy, destinations or execution settings requires a new review. A retry does
not inherit the previous attempt's approval. Open the run's **Approvals** tab to
review it; a yellow icon marks pending or blocked access. The tab explains blocked
access and links back to workflow settings without covering the job list or logs.

**Automatically allow eligible users** skips Openship's review for trusted runs.
GitHub's fork and protected-environment approvals still apply; the editor links
to repository settings. GitHub does not require approval for every collaborator
push by default. Choose per-run approval when you need that control. Eligible
fork runs always need Openship approval and a disposable Cloud runner.

Existing independent workflows keep their previous behavior until their access
settings are saved. Existing GitHub workflows without a policy require review
before Openship starts new runners. The official runner adapter verifies the actual
assignment through GitHub's local IPC protocol and fails closed if that protocol
becomes incompatible; it does not fall back to unchecked execution.

Workflow notifications use the existing notification queue, alongside account-wide
Actions subscriptions. A channel selected by both rules gets one queued notification
per run. Jobs that invoke a workflow share that identity. Failed enqueues are retried
before completion is settled, and delivery rechecks channel verification and resource
access. Notification choices are captured when the run is created; importing old GitHub
history does not send a backlog of alerts. No workflow commands, secrets or raw logs
are included in these notifications.

Choose **Standalone** for YAML without a repository. It supports manual runs,
schedules and authenticated webhooks without GitHub credentials. `actions/checkout`
in a standalone workflow needs an explicit `with.repository`.

**Repository updates** for `.openship/workflows` controls which definition future runs use.
Files in `.github/workflows` always use the definition from GitHub for that run:

- **Automatic:** use the workflow from the run's repository commit. Changes in Git
  apply automatically.
- **Review first:** keep the YAML saved in Openship. **Check repository** loads the
  latest file without replacing your saved definition or edited draft. Review the
  differences, choose **Use repository version**, then save to approve it. Until
  then, runs continue using the previously saved YAML.

Saving an Openship copy selects **Review first**. Changing the definition affects
future runs; existing runs retain their immutable snapshots.

```yaml
name: CI
on:
  push:
    branches: [main]
  workflow_dispatch:
permissions:
  contents: read
jobs:
  build:
    runs-on: [self-hosted, openship, linux]
    strategy:
      matrix:
        node: [20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci
      - run: npm test
  complete:
    needs: build
    runs-on: [self-hosted, openship, linux]
    steps:
      - run: echo "All matrix jobs passed"
```

Every run records the resolved commit and workflow definition. Rerunning creates a
new attempt of that recorded revision. A controller restart resumes inspection of
the same worker; it does not replay a job whose start was already accepted.

The run page opens with a collapsible job-and-step list on the left and logs on the
right. Select a job for all its output, or a step for its recorded output. Jobs
expand independently. Switching to **Topology** keeps the same selection and logs;
use **Expand all**, **Collapse all**, zoom, fit or **Arrange workflow** to inspect
the connected steps. Independent jobs wrap across the graph rather than forming
one long column. A single job shows its step nodes immediately. The selected job,
step and view are preserved in the URL when you refresh or share the page.
Queued and waiting jobs keep their own status labels and use a yellow loading
indicator. Opening **Approvals** preserves the current job, step and log cursor.

Independent logs resume from their persisted cursor. For GitHub workflows, step
state is synchronized from GitHub, live logs open in GitHub, and completed logs and
artifacts are available in Openship. GitHub supplies a complete job log, so selecting
a step keeps that full output visible with a scope label.
GitHub owns the Check IDs and conclusions; Openship does not publish duplicate Checks.

## Triggers and Jobs

**When to run** edits the workflow's own `on` rules. It supports manual inputs,
push and pull-request branch/path filters, UTC Cron schedules and authenticated
webhooks. Expand a trigger to configure it. Branches and paths use removable
patterns: type a pattern and press **Enter** or **+** to add it. Choose **Only
matching** or **Except matching**; Openship preserves commas inside glob patterns.
**Paths & more filters** includes tags and pull-request event types. Each Cron
schedule has its own UTC input. Other events, including `workflow_call`, remain
visible and open the YAML editor without changing their definitions.

**Manual & Jobs** enables `workflow_dispatch`. Add string, number, boolean or choice
inputs with defaults and required values. The manual-run form and **Jobs → Run
workflow** use those same declared inputs. Jobs can run a workflow on a Cron
schedule, once, after another job succeeds or on a supported platform event.
Allowed runners and secrets remain configured on the workflow. Job history opens
the original Actions execution rather than a second copy of its logs or status.

For an independent workflow's authenticated webhook, enable `repository_dispatch` and optionally restrict
event types. The workflow details show its dispatch endpoint. Call it with an
Openship API token authorized to run that workflow:

```http
POST /api/actions/workflows/WORKFLOW_ID/dispatch
Authorization: Bearer YOUR_OPENSHIP_TOKEN
Content-Type: application/json

{
  "eventType": "release",
  "clientPayload": { "version": "1.2.3" },
  "idempotencyKey": "release-1.2.3"
}
```

The workflow receives these values in `github.event.action` and
`github.event.client_payload`. Keep the token in the caller's secret store and
reuse the same idempotency key when retrying one delivery. This is Openship's
authenticated dispatch API; it does not subscribe to GitHub App
`repository_dispatch` deliveries. The caller must be able to reach the instance. For `.github/workflows`, send
`repository_dispatch` events to GitHub's repository dispatch API instead. Openship's Run button and Jobs schedules use GitHub's `workflow_dispatch` endpoint.

## Project deployment rules

In **Project → Actions**, create a workflow or open **Deployment automation** to link
existing workflows and select:

- **Manual deployments:** workflows run independently; deployment starts when requested.
- **Deploy on push:** use the project's existing automatic deployment pipeline.
- **Deploy after Actions pass:** require all selected workflows to pass for the
  exact pushed commit before entering that same deployment pipeline.

Required workflows must be enabled, belong to the project's repository and run
on every push to its deployment branch. Path-filtered workflows can be linked as
optional checks. Required checks need a reachable control plane and an authenticated
repository push webhook. Independent Checks additionally require a connected GitHub
App to publish results. GitHub-mode deployment gates wait for the original GitHub
push run; they do not dispatch another run. Manual deployments remain available.

Pending requests and failed checks appear in the project's Actions tab. Retrying
uses the saved commit and one deployment receipt; duplicate deliveries or a
controller restart do not create another accepted deployment. Newer commits,
changed rules and a new manual deployment supersede pending approvals. Pull-request
runs and manual workflow runs do not approve automatic push deployments.

The deployment wizard saves its selected workflow links and rules before starting
the initial deployment. If rule setup fails, it keeps the draft for retry. The
initial deployment remains an explicit manual deployment; the selected automatic
policy applies to subsequent pushes.

## GitHub events and checks

For independent workflows, a connected GitHub App receives signed push and pull-request events and publishes
Checks on the commit. Each job uses a token scoped to its repository and declared
permissions. Stored personal credentials are not substituted for an unavailable
App token. GitHub installation tokens normally expire after one hour; token refresh
inside a running job is not currently supported.

Independent scheduled workflows run while the controller is online, at intervals of at least
five minutes. Missed schedules are not replayed after downtime. For Desktop, keep
it running or [move the control plane to a server](/docs/guides/migrate-control-plane).

Schedules in `.github/workflows` are managed by GitHub. Openship must be online to provision
and register its runners. Signed `workflow_run`/`workflow_job` events request a fresh
API read; periodic reconciliation also recovers missed events. Event payloads alone
cannot mark a run successful.

Use `.openship/workflows/` when you want scheduling independent of GitHub. If a workflow script deploys the application
itself, use manual project deployment mode to avoid also requesting an automatic
deployment after its checks pass.

Independent fork runs require explicit approval and disposable runners. Their workflow comes
from the trusted base revision, while checkout can use the pull-request merge
commit. They receive no stored secrets, write credential or shared cache access.
Authorization is rechecked during execution; revoking the originating user's
access prevents further authorized work.

Fork approvals and protected-environment approvals for `.github/workflows` still
follow GitHub repository policy. Openship also requires its own approval and a
disposable Cloud runner for eligible fork runs. Forks never run on connected
persistent servers, including Macs. `pull_request_target` is also treated as untrusted.

## Artifacts and cache

Files in `.github/workflows` use GitHub's artifact/cache service, retention and storage billing.
Download links are fetched with repository authorization and returned as short-lived
signed links; credentials are never forwarded to the download host.

For independent workflows, select an existing backup destination for artifacts and cache. Cloud requires an
S3-compatible destination; self-hosted instances can also use a local destination.
Workflow code never receives the destination's storage credentials.

The API implements the protocols used by `actions/upload-artifact@v4`,
`actions/download-artifact@v4` and `actions/cache@v4`. One object is limited to
1 GiB, with 20 GiB of reserved and retained objects per organization. Artifact
retention defaults to seven days and can be set up to 30 days. Expired objects are
removed by the controller's cleanup loop.

Runners must be able to reach the instance's public API. Set
`OPENSHIP_ACTIONS_RUNTIME_URL` when it differs from `OPENSHIP_PUBLIC_URL`; preserve
the artifact API and `/twirp` proxy routes. Runtime URLs use short-lived tokens
scoped to one organization, run and job.

## Independent reusable workflows

Use `jobs.<job>.uses` to call a YAML file in `.openship/workflows/` or
`.github/workflows/`. Local calls use the caller's immutable commit. Remote calls
use `owner/repository/path@ref`; Openship resolves the ref and saves every called
source before approval. A later tag change cannot alter an approved attempt.

```yaml
jobs:
  gate:
    uses: ./.openship/workflows/test.yml
    with:
      enabled: false
      version: 22
    secrets:
      registry_token: ${{ secrets.REGISTRY_TOKEN }}
```

The called file declares `on: workflow_call`, typed inputs, accepted secrets and
outputs. Its jobs select their own allowed runners and appear in the same run,
with logs, Checks and cancellation. Boolean and number inputs retain their types.
Permissions can stay the same or narrow at each call. Secrets must be forwarded
explicitly; `secrets: inherit` is permitted only within the same owner.
Nesting is limited to 10 workflow levels, 50 called files, 2 MiB of combined source
and 256 total concrete jobs. Protected environment settings remain unsupported
in independent mode.

## Openship OIDC

Independent jobs can request an identity with `permissions: {id-token: write}`.
Publish the controller at a stable HTTPS origin reachable from runners and the
external service. Configure that service to trust
`https://your-controller/api/actions/oidc` as its issuer. Discovery is available at
`/api/actions/oidc/.well-known/openid-configuration`; RSA verification keys are at
`/api/actions/oidc/jwks`.

The job receives the standard `ACTIONS_ID_TOKEN_REQUEST_URL` and
`ACTIONS_ID_TOKEN_REQUEST_TOKEN` environment variables. Actions using the standard
OIDC toolkit can request a token with their required audience. Credentials such as
AWS or Azure trust policies must allow this Openship issuer; GitHub-specific
issuer policies do not grant access automatically.

Restrict the provider's trust to the organization, repository, ref and workflow
identity. A normal repository subject is
`openship:organization:<org-id>:repo:<owner>/<repo>:ref:refs/heads/main`.
A workflow edited in Openship includes `:source:override` in its subject and sets
`openship_workflow_modified`, so it cannot impersonate the repository's committed
workflow. Claims also identify the run, job, destination and immutable called
workflow source (`job_workflow_ref`, `job_workflow_sha`).

Tokens expire within five minutes. Issuance rechecks approval, actor access,
runner access and cancellation; fork jobs receive no OIDC capability. The
instance's signing key is encrypted in its database and included only in a full
instance transfer, preserving its key when credentials are transferred securely.
Keep the issuer address stable when moving a control plane. An archive that omits
credentials retains public verification metadata but cannot issue new tokens;
restore an archive containing the signing credentials to use that issuer.

## Cancellation and limits

Cancel stops the remote execution and then cleans its resources. A runner remains
busy until cleanup succeeds. Cloud workers also have a provider TTL as a fallback;
an unreachable controller does not leave a VM running indefinitely.

Independent workflows support up to 256 concrete jobs after matrix expansion. A job defaults
to a 60-minute timeout and can request up to 360 minutes. Logs are bounded at
8 MiB per job. Settled run history is retained for 30 days, with runs referenced
by retained artifacts or retry attempts protected from early removal.

Independent workflows support reusable workflows and Openship-issued OIDC.
Protected environments and attestations require GitHub-coordinated workflows;
independent mode rejects those features before dispatch. Openship-managed destinations
currently support Linux and macOS; Windows and GitHub Enterprise Server are not
available. Official runner registrations execute one job and expire after six hours;
idle registrations are removed after ten minutes. Choose a runner image with the
official runner's dependencies, or use the Ubuntu preset.

GitHub dispatch and rerun POSTs have durable command receipts. If GitHub accepts a
request but its response is lost, Openship does not send the POST twice. Refresh
Runs or open GitHub before deliberately starting another run.

## Cloud Actions funding

**Actions → Budget** provides a separate prepaid balance for temporary VMs and
transfer. Add $5, $20, $50 or $100, complete the hosted payment, and return to see
its verified status. Runner setup retries automatically if the provider is
unavailable; it does not buy another deposit. Once ready, choose the Cloud runners
in your workflow's allowed destinations.

| Runner | RAM    | Temporary disk |
| ------ | ------ | -------------- |
| 2 vCPU | 4 GiB  | 40 GiB         |
| 4 vCPU | 8 GiB  | 80 GiB         |
| 8 vCPU | 16 GiB | 160 GiB        |

All sizes share two concurrent Cloud jobs per organization. You can select a size
with `runs-on: [self-hosted, openship, linux, openship-linux-2]`, `openship-linux-4` or
`openship-linux-8`, provided that profile is allowed for the workflow.

The page shows live provider rates and estimated VM minutes for your deposit.
Estimates assume full CPU and memory use, before transfer or disk I/O. Actual
charges follow measured CPU time, memory and combined uploads/downloads. VM
preparation, failed steps and cleanup can consume credits; queued jobs use no VM.
This is prepaid usage, not a fixed number of execution minutes or a subscription.

Your displayed balance comes from Oblien. Recent usage may appear with a delay.
Workers stop when the provider marks the balance exhausted. Add funds and rerun
the workflow to try again; an interrupted attempt is not silently restarted.
Independent artifacts and caches use your configured storage destination; GitHub
mode uses GitHub storage. Connected servers
run workflows without spending this Cloud Actions balance.
