# Policy CI Context

In GitHub Actions, policy rules can inspect the supplied event and allowlisted runner
metadata through `ci`. Declare `required_ci` when a rule needs complete provider data.

## Inspect your inputs

Use [`atmos ci context`](/cli/commands/ci/context) in the job where the policy runs:

```shell
# List observed field names and JSON types without values.
atmos ci context --paths

# Inspect event identity and availability.
atmos ci context --query '{"event_name": .ci.metadata.data.GITHUB_EVENT_NAME, "status": .ci.event.status}'
```

Without `--paths`, the command prints the collected snapshot under `ci`, including native event
values. Keep snapshots private: event payloads can contain sensitive user-supplied content.
Collection requires no API permissions and does not fetch live reviews. Command admission still applies.

Every [library policy](/policies/library) includes an **Inputs and examples** section. Choose an
example, search its fields, and copy a CEL or Starlark field expression. The **Input JSON** tab
shows the corresponding request. These are tested examples, not exhaustive provider schemas.

## GitHub event reference

Atmos defines the snapshot envelope; GitHub defines the keys inside `ci.event.data`.
`ci.metadata.data.GITHUB_EVENT_NAME` identifies the event. The payload is read from
`GITHUB_EVENT_PATH`, corresponding to the workflow's `github.event` object—not the entire
`github` context. See GitHub's [variables reference](https://docs.github.com/en/actions/reference/workflows-and-actions/variables)
and [context reference](https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#github-context).

| Event name | Example native fields | Provider reference |
|---|---|---|
| `pull_request` | `action`, `pull_request.head`, `pull_request.base` | [Pull request payload](https://docs.github.com/en/webhooks/webhook-events-and-payloads#pull_request) |
| `pull_request_review` | `action`, `review`, `pull_request` | [Review payload](https://docs.github.com/en/webhooks/webhook-events-and-payloads#pull_request_review) |
| `push` | `ref`, `before`, `after` | [Push payload](https://docs.github.com/en/webhooks/webhook-events-and-payloads#push) |
| `workflow_dispatch` | `ref`, `inputs` | [Manual workflow payload](https://docs.github.com/en/webhooks/webhook-events-and-payloads#workflow_dispatch) |
| `workflow_run` | `action`, `workflow_run` | [Workflow run payload](https://docs.github.com/en/webhooks/webhook-events-and-payloads#workflow_run) |

These are lookup examples, not an event allowlist. The collector preserves the supplied JSON object
without normalizing provider fields. Consult [events that trigger workflows](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows)
for Actions-specific availability, activity types, and payload differences. Check the actual snapshot
and guard optional or null fields; do not assume every webhook example is present in every Actions run.

GitHub event names are separate from Atmos lifecycle events such as `input.event == 'after.terraform.plan'`.
A triggering `pull_request_review` payload is historical event data, not proof of a current qualifying
approval. Use [approval requirements](/policies/approvals) for fresh verification.

## Snapshot schema

GitHub Actions uses provider `github-actions` and schema `github-actions/v1`.

| Path | Type | Contents |
|---|---|---|
| `ci.provider` | String | Provider identifier |
| `ci.schema` | String | Provider-owned schema version |
| `ci.metadata` | Dataset | Allowlisted environment variables; values remain strings |
| `ci.event` | Dataset | Native JSON object read from `GITHUB_EVENT_PATH` |
| `ci.facts` | Object | Empty for the supplied-event collector; no live API facts |

Each dataset has this shape:

```json
{
  "data": {"GITHUB_EVENT_NAME": "pull_request"},
  "status": "available",
  "complete": true,
  "provenance": {
    "source": "github-actions:environment",
    "collected_at": "2026-10-12T12:00:00Z",
    "revision": "<GITHUB_SHA>"
  }
}
```

| Dataset field | Meaning |
|---|---|
| `data` | Provider-native object; can be absent when collection fails |
| `status` | `available`, `unavailable`, or `incomplete` |
| `complete` | Whether collection completed successfully |
| `provenance.source` | `github-actions:environment` or `github-actions:GITHUB_EVENT_PATH` |
| `provenance.collected_at` | UTC collection timestamp, not the event timestamp |
| `provenance.revision` | `GITHUB_SHA` when supplied |
| `reason` | Explanation when data cannot be supplied |

Missing or unreadable event files are `unavailable`. Invalid JSON, non-object JSON, read failures,
or events exceeding 8 MiB are `incomplete`. Missing data is not replaced by an empty event.

Outside a detected CI provider, `ci` is `null`. A provider without snapshot support reports
unavailable datasets. Requiring GitHub data in either case blocks the command.

## Required inputs

```yaml
required_ci:
  - provider: github-actions
    schema: github-actions/v1
    dataset: event
```

- **provider**
  Required string. Exact provider identifier.
- **schema**
  Required string. Exact snapshot schema version.
- **dataset**
  Required string. Use 
  metadata
   or 
  event
   for the GitHub supplied-event collector.
  The schema also accepts 
  facts
  , but this collector supplies no facts.
- **fact**
  Required only for 
  dataset: facts
  ; invalid for other datasets.

Requirements are checked before evaluating a matching-kind rule's predicate. The provider and
schema must match, and each dataset must be `available`, complete, and contain non-null data.
`rule: false` does not bypass a missing requirement.

## Reject fork PR plans

```yaml title="policy.d/github.yaml"
apiVersion: atmos/v1
kind: Policy
metadata:
  name: github-safety
spec:
  policies:
    reject-fork-plan:
      on: terraform.plan
      action: deny
      reason: This privileged plan job does not accept fork pull requests
      required_ci:
        - provider: github-actions
          schema: github-actions/v1
          dataset: event
      rule: >-
        has(ci.event.data.pull_request) &&
        ci.event.data.pull_request.head.repo.full_name != ci.event.data.pull_request.base.repo.full_name
```

This rule is a plan gate, not a sandbox. It runs after planning and before saved-plan apply.
Do not execute untrusted pull-request code with privileged credentials and rely on this check
to make that execution safe.

## Metadata allowlist

Only variables present in the runner environment are included:

GITHUB\_ACTIONS
GITHUB\_EVENT\_NAME
GITHUB\_REPOSITORY
GITHUB\_REPOSITORY\_ID
GITHUB\_REPOSITORY\_OWNER
GITHUB\_SHA
GITHUB\_REF
GITHUB\_REF\_NAME
GITHUB\_REF\_TYPE
GITHUB\_BASE\_REF
GITHUB\_HEAD\_REF
GITHUB\_ACTOR
GITHUB\_ACTOR\_ID
GITHUB\_TRIGGERING\_ACTOR
GITHUB\_RUN\_ID
GITHUB\_RUN\_NUMBER
GITHUB\_RUN\_ATTEMPT
GITHUB\_WORKFLOW
GITHUB\_JOB
GITHUB\_SERVER\_URL
GITHUB\_API\_URL
RUNNER\_OS
RUNNER\_ARCH
RUNNER\_ENVIRONMENT

Example: `ci.metadata.data.GITHUB_EVENT_NAME == 'pull_request'`.
Tokens and arbitrary environment variables are not copied into metadata.

## GitHub permissions

| Capability | Workflow permission |
|---|---|
| Evaluate supplied event/metadata and produce local output | No additional API permission; collection makes no API calls |
| Check out repository policies/configuration | `contents: read` |
| Verify designated reviewers against current PR details and paginated reviews | `pull-requests: read` |
| Publish existing Native CI commit statuses | `statuses: write` |

Minimal permissions for a job that checks out policies and evaluates them:

```yaml
permissions:
  contents: read
```

When the job also publishes Native CI statuses:

```yaml
permissions:
  contents: read
  statuses: write
```

Use `GITHUB_TOKEN`; a PAT or GitHub App is not required for these capabilities. Configure the
checkout and policy directory using the [enforcement setup](/policies/configuration#enforcement).
See [CI authentication and permissions](/integrations/github-actions/authentication#permissions)
for the surrounding workflow.

Fork and Dependabot runs can have reduced token permissions. Keep policy failures blocking even
when status publication is unavailable. The supplied event records the triggering event, not
current review state; it must not be treated as verified approval. [Approval requirements](/policies/approvals)
fetch fresh evidence separately when selected. These policies evaluate the
current invocation, not outcomes aggregated from other component jobs.
