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.
- uses: rafay99-epic/envpilot-action@v1
with:
token: ${{ secrets.ENVPILOT_TOKEN }}
environment: production
project: mobile-app # required when files: true
files: trueAfter that step, android/app/upload.jks (or whatever path the file records) exists, mode 0600, ready for the build.
Requirements#
| Requirement | Why |
|---|---|
files: true | Off by default — no workflow pulls file contents unless it asks |
project: <slug> | The files endpoint is project-scoped, unlike variables |
files resource on the key | Never 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.
with:
files: true
project: mobile-app
files-dir: build/secretsHow 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.
- 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#
- Android keystore in CI — the full workflow
- Secret files — the object model