AI Router · CLI · MCPCheapest eligible quotes before you create
task · activation

Use OfflineCreator CLI in CI without leaking secrets

Scope keys, mask output, constrain uploads, and avoid unattended purchasing.

Connect OfflineCreator with OAuth
Freshness marker

Split untrusted checks from the credentialed generation job

Use two CI boundaries. Let pull-request validation install, lint, type-check, and test without an OfflineCreator credential. Put the generation step in a separate job that runs only from a trusted branch, manual dispatch, or protected environment after review. GitHub does not pass ordinary Actions secrets to workflows triggered from forks, and its secure-use guidance warns that privileged `pull_request_target` or `workflow_run` jobs must not check out untrusted pull-request code. Do not work around that boundary merely to make preview generation available.

The credentialed job should check out only the trusted revision it intends to run. Pin third-party actions to full commit SHAs, give `GITHUB_TOKEN` read-only contents permission unless a step demonstrably needs more, and keep pull-request titles, branch names, and other attacker-controlled context out of generated shell source. GitHub documents those context values as potentially untrusted and recommends passing them through an intermediate environment variable when an inline script must consume them.

Evidence rail

Inject one scoped key without putting it on the command line

At repository commit `4a7d1ed`, local configuration reads `OFFLINECREATOR_API_KEY` from the process environment, requires an `oc_live_` or `oc_test_` prefix, and adds the key as a Bearer authorization header to `/api/v1/*` requests. Map a protected CI secret to that environment variable only on the step that invokes the pinned package. Do not place the value in a command argument, workflow file, generated config artifact, cache key, or copied diagnostic bundle.

GitHub recommends secrets or environment variables instead of command-line arguments, masks registered Actions secrets in logs, and requires `::add-mask::VALUE` for other sensitive values. Masking is a backstop rather than permission to print: automatic redaction can fail after values are transformed or embedded in structured data. Keep shell tracing off for the credentialed step, retain only sanitized stderr, and rotate the key if an unredacted value reaches a run log.

Tool rack

Pin the package and test the command surface you actually receive

Do not let an unqualified `npx` fetch decide the executable during a privileged run. The immutable npm record shows published version `0.1.1`, while the inspected repository commit declares package version `0.1.2` and Node.js 20 or newer. Those are different evidence surfaces. Pin the registry version or lockfile-resolved artifact, record its integrity, and test its help and exit behavior before admitting it to a secret-bearing job.

The difference matters for purchasing controls. The npm `0.1.1` README advertises `topups` and `topup --id`, while saying checkout creation returns a URL for a human browser action and agents do not charge a payment method directly. The later pinned repository parser exposes only `models`, `balance` or `credits`, `generate`, and help. A CI policy must therefore inspect the installed artifact instead of assuming either source describes every version.

Failure trace

Make read-only preflight separate from paid generation

Run model discovery and the credit-balance check before the generation step, then require a deliberate policy decision before calling `generate`. At the pinned repository commit, the CLI parser sends `models` to the model-list request, `balance` or `credits` to the balance request, and `generate` to a POST that starts work. The public MCP registry separately maps model listing to the `models` scope, balance and status tools to `read`, and generation or upload tools to `generate`; that tool map does not by itself prove how every CLI API key is enforced by the proprietary backend.

Use the narrowest key the Settings UI currently offers and verify it against the pinned artifact with a non-production test account before relying on it. Keep purchasing outside the automation even if an installed release exposes top-up discovery: accept only a checkout URL as an artifact for an authorized human, never open it automatically, never follow redirects from job output, and never store payment details in CI. Set an explicit maximum expected credit cost from the model data and fail closed when the model, cost, or balance response is missing or malformed.

Error code index

Constrain files and network destination before adding media inputs

At the pinned commit, `OFFLINECREATOR_API_BASE` defaults to `https://offlinecreatorstudio.com`; configuration rejects embedded credentials, non-HTTP protocols, non-HTTPS remote origins, and remote hosts outside its trusted set. Leave that default in production CI rather than accepting an API origin from pull-request input. If a test job uses localhost, keep that job credential-free or use a dedicated test key and prevent its artifacts from flowing into the protected generation job.

`OFFLINECREATOR_UPLOAD_ROOT` is a local stdio upload boundary, not a general permission for the CLI `generate` command. The local reader restricts selected files to a configured root, supported image extensions, regular non-empty files, a byte limit, and recognized image signatures. If a future pinned workflow invokes local `upload_input`, stage only approved assets in a fresh directory and set that directory as the root. Do not mount the repository parent, home directory, cloud credential directories, or runner socket into that step.

Related circuit

Parse stdout only as the JSON contract expected from the pinned command and keep stderr as a sanitized diagnostic channel. Do not evaluate a prompt, model label, output URL, error body, pull-request title, or branch name as shell code. The public client refuses non-`/api/v1/` paths, uses manual redirect handling, and omits output URLs that cannot be normalized to the configured Studio origin. Preserve those checks by consuming fields as data and by refusing unexpected redirects or origins in any downloader wrapper.

A safe failure leaves enough metadata to reconcile without leaking the prompt or key: pinned package version, trusted commit, workflow run ID, process status, generation UUID when returned, and a redacted error category. Do not dump the full environment or use broad debug modes after a failure. If a generation call may have reached the service, reconcile the known UUID before retrying; an empty local stdout is not evidence that no paid work started.