Secret files in CI

Materialise keystores, certificates and service-account JSON on the runner, at the paths your build already expects.

Secret files in CI

A release build usually needs more than variables: a signing keystore, a .p12, a service-account JSON. files: true writes them onto the runner at their recorded paths, with their recorded modes.

yaml
- uses: rafay99-epic/envpilot-action@v1
  with:
    token: ${{ secrets.ENVPILOT_TOKEN }}
    environment: production
    project: mobile-app # required when files: true
    files: true

After that step, android/app/upload.jks (or whatever path the file records) exists, mode 0600, ready for the build.

Requirements#

RequirementWhy
files: trueOff by default — no workflow pulls file contents unless it asks
project: <slug>The files endpoint is project-scoped, unlike variables
files resource on the keyNever granted by default; select it when minting the key

Without the resource the request is refused — the key is not "partially allowed".

Where files land#

files-dir sets the root that destination paths resolve against; it defaults to the workspace. The directory is created if missing, then resolved to a real path.

yaml
with:
  files: true
  project: mobile-app
  files-dir: build/secrets

How the write is protected#

The server validates every path, and the Action re-validates on the runner, because it is the process actually creating files. A server bug or a tampered response must not be able to write outside the workspace:

  • absolute paths are refused
  • paths that escape the root are refused, including through a symlinked intermediate directory
  • writing through a symlink is refused
  • content is staged into a fresh exclusive temp file at the restrictive mode and renamed over the target, so a pre-existing world-readable file never holds new secret contents at its old mode

Batching and the 8 MiB rule#

Files are fetched in batches sized under the server's per-request ceiling of 8 MiB, so a project with many files still pulls in one step. A single file larger than 8 MiB cannot be fetched at all — the Pro per-file limit is 8 MB precisely so this cannot happen through the product.

The step logs name, path and size only. Contents never reach the log: masking a multi-megabyte binary is not meaningful, so the rule is that it never gets there.

Output#

files-count holds the number of files written — zero when files is false.

yaml
- id: envpilot
  uses: rafay99-epic/envpilot-action@v1
  with:
    token: ${{ secrets.ENVPILOT_TOKEN }}
    environment: production
    project: mobile-app
    files: true
 
- run: echo "wrote ${{ steps.envpilot.outputs.files-count }} files"

Limits#

  • Every file fetch is audited against the API key. A workflow that pulls on every push produces an audit entry per run — by design.
  • Content reads are rate limited: refill 60/min, burst 1000. A cold pull of any legal project fits in one burst.
  • The Action overwrites whatever is at the destination path. Unlike envpilot files pull, there is no conflict check — a runner is expected to be empty.
  • No upload path. CI writes to disk, never to Envpilot.

Next#