Skip to content

Automation and AI

Headless runs and CI

Record, check and replay API traffic in CI with cloakctl run, and run API-client collections like Newman with JUnit, JSON and HTML reports.

Cloak Proxy works without its window. cloakctl can wrap your test command in a capture proxy, record everything it sends, write a report, and fail the build on server errors, leaked secrets or schema changes. It can also run your API client collections with their tests, like Newman or the Postman CLI. Use this page to set up both on your Mac or on a macOS CI runner.

Goal Command
Record every API call your tests make, as HAR cloakctl run --ssl '*' --record run.har -- npm test
Fail the build on server errors or leaked secrets cloakctl run --ssl '*' --fail-on-5xx --fail-on-secrets -- npm test
Get a Markdown report for a pull request cloakctl run --ssl '*' --report report.md -- npm test
Run tests offline against a recording cloakctl run --mock run.har -- npm test
Run a collection’s tests with JUnit output cloakctl collection run "Shop API" -r cli,junit
Load test a collection cloakctl perf "Shop API" --vus 20 --duration 60
Lint an OpenAPI spec cloakctl spec lint openapi.yaml
  • macOS 14 Sonoma or later, Apple silicon or Intel. cloakctl is a Mac program, so CI jobs need a macOS runner.
  • Cloak Proxy installed, because cloakctl ships inside it at /Applications/Cloak Proxy.app/Contents/Resources/cloakctl. See Install and Put cloakctl on your PATH.
  • No account and no license key. cloakctl is free for life, like the app.

cloakctl run creates the root certificate in ~/Library/Application Support/CloakProxy/ the first time it needs one. It doesn’t need the certificate to be trusted in the macOS keychain, because it hands the certificate to the wrapped command through environment variables.

Put your test command after --. cloakctl run starts the proxy, runs the command with the proxy and certificate already set, and stops when the command exits.

  1. Choose which HTTPS traffic to decrypt. --ssl '*' decrypts every host. To be narrower, repeat --ssl with host patterns such as api.example.com or *.example.com. Without --ssl, HTTPS shows only as encrypted tunnels.

  2. Add what you want out of the run: --record for the traffic, --report for a summary, and any --fail-on-… checks.

  3. Run it:

    Terminal
    cloakctl run --port 9091 --ssl '*' \
    --record run.har --redact --report report.md \
    --fail-on-5xx --fail-on-secrets \
    -- npm test
  4. Read the summary on standard error and check the exit code:

    Recorded 42 requests to run.har
    Report written to report.md
    42 requests, 9 endpoints, 0 errors, 0 possible secrets, 0 schema changes

The wrapped command is started through /usr/bin/env with these variables added to your current environment:

Variable Value Who reads it
HTTP_PROXY, HTTPS_PROXY, http_proxy, https_proxy http://127.0.0.1:PORT curl, Python, Ruby, Go, git, Deno and most HTTP libraries
NODE_USE_ENV_PROXY 1 Node.js 24 and later, so its built-in fetch and http use the proxy
NODE_EXTRA_CA_CERTS Path of the root certificate Node.js
SSL_CERT_FILE Path of the root certificate OpenSSL-based tools, Ruby, Go
REQUESTS_CA_BUNDLE Path of the root certificate Python requests
CURL_CA_BUNDLE Path of the root certificate curl
GIT_SSL_CAINFO Path of the root certificate git

Programs that ignore these variables aren’t captured. See Terminal and runtimes for runtimes that need extra setup, such as older Node.js versions or Java.

Leave out -- and the command, and the proxy runs until you press Control C, send SIGTERM, or --duration runs out. Point any app at 127.0.0.1:PORT in the meantime. With --duration and a wrapped command, the command is stopped when the time is up.

Each --fail-on-… flag adds a check. If any check fails, cloakctl run prints FAILED: with the reasons and exits with 1.

Flag Fails when
--fail-on-5xx Any response had a 5xx status.
--fail-on-error Any response had a 4xx or 5xx status, or any request failed (connection error, DNS failure, timeout).
--fail-on-secrets The secret scanner found a high-severity secret in the traffic: for example an AWS, GitHub, Slack, OpenAI or Anthropic key, a live Stripe key, a private key, a card number, or credentials in a URL or sent over plain HTTP.
--fail-on-schema-change An endpoint’s JSON response changed shape during the run: a field was added or removed, or changed type. See Schema changes.
42 requests, 9 endpoints, 3 errors, 1 possible secrets, 0 schema changes
FAILED: 2 server errors, 1 high-severity secrets
Exit code Meaning
0 No check failed, and the wrapped command (if any) exited with 0.
1 A --fail-on-… check failed, an option was wrong, or a file couldn’t be read or written.
The command’s own code No check failed, but the wrapped command exited with a non-zero code. Your test failures still fail the build.
127 The wrapped command couldn’t be started (for example, it isn’t installed).

--record FILE writes the traffic when the run ends. A file ending in .har gets HAR that any HAR viewer opens. Any other name gets a Cloak Proxy session you can open in the app with File › Open Session…. See Save and open sessions.

--redact removes tokens, cookies, API key headers, credential parameters, password-like fields and anything the secret scanner matches, before the recording is written. Use it whenever the recording leaves your Mac, for example as a CI artifact. See Redaction.

--report FILE writes a Markdown report, the same one as Export Report in Insights:

Section What it lists
Summary line Requests, endpoints, errors, possible secrets and schema changes.
Endpoints Up to 50 endpoint templates (such as /users/{id}) with calls, errors, p50 and p95.
Possible secrets Each finding’s severity, kind, where it was found, host and request id. Values are masked.
Security headers An A to F grade per host with its issues.
Performance Slow and large responses, missing compression, duplicates, N+1 bursts and similar findings.
Schema changes Added, removed and retyped fields per endpoint.

Empty sections are left out. The report is made before redaction, but it only ever shows masked secret values.

--mock FILE loads a .har or .cloaksession file as a mock set and answers matching requests from it instead of the network. A request to a recorded host that isn’t in the recording gets a 404, so nothing slips through to the real API. Requests to other hosts go to the network as usual. Record once against a real backend, then run the same tests offline or in CI without the backend:

Terminal
# Once, against the real API:
cloakctl run --ssl 'api.example.com' --record fixtures/api.har --redact -- npm test
# Every CI run, with no network access to the API:
cloakctl run --mock fixtures/api.har --quiet -- npm test

You can combine --mock with --tools RULES.json to add Map Local, Map Remote or other rules exported from the app with Tools › Export Rules…. See Mock a backend.

cloakctl collection run runs a collection from your API client workspace, with its pre-request scripts, tests, auth and variables. It doesn’t need the app or a proxy. Every flag is listed in cloakctl › Run a collection.

Terminal
cloakctl collection run "Shop API" \
--workspace ./api-workspace \
-e Staging \
-d "Login users" \
--env-var "apiKey=$SHOP_API_KEY" \
-r cli,junit,html \
--reporter-junit-export results/api.xml \
--reporter-html-export results/api.html
Reporter Output Default file
cli Live results in the terminal, then a summary line. Standard output
json The full run as JSON. cloak-run.json
junit JUnit XML, which most CI systems show as test results. cloak-run.xml
html A standalone HTML report. cloak-run.html

Pick several with commas: -r cli,junit,json. The folder for an export path must already exist.

Secret variable values live in the workspace’s git-ignored .cloak/ folder, and {{vault:name}} values live in the macOS Keychain, so neither is in your repository. On a CI runner, pass secrets in with --env-var KEY=VALUE from your CI system’s secret store. See Variables and environments.

collection run exits with 0 when every request and test passed, and 1 when any request failed to send or any test failed. --bail stops the run at the first failure.

This workflow runs on a self-hosted macOS runner that has Cloak Proxy installed in /Applications. It runs a collection with JUnit output, then runs the app’s own tests through the recorder and fails on server errors or leaked secrets.

.github/workflows/api-tests.yml
name: API tests
on: [push, pull_request]
jobs:
api:
runs-on: [self-hosted, macOS]
env:
CLOAKCTL: /Applications/Cloak Proxy.app/Contents/Resources/cloakctl
steps:
- uses: actions/checkout@v4
- name: Prepare results folder
run: mkdir -p results
- name: Run the API collection
env:
SHOP_API_KEY: ${{ secrets.SHOP_API_KEY }}
run: |
"$CLOAKCTL" collection run "Shop API" \
--workspace ./api-workspace \
-e Staging \
--env-var "apiKey=$SHOP_API_KEY" \
--bail \
-r cli,junit \
--reporter-junit-export results/api.xml
- name: Lint the OpenAPI spec
run: '"$CLOAKCTL" spec lint api-workspace/specs/shop-api.yaml'
- name: Record and check the app's API traffic
run: |
"$CLOAKCTL" run --port 9091 --ssl '*' \
--record results/traffic.har --redact \
--report results/report.md \
--fail-on-5xx --fail-on-secrets \
-- npm test
- name: Upload results
if: always()
uses: actions/upload-artifact@v4
with:
name: api-results
path: results/

Adjust the collection name, environment, spec path and test command to your project. --port 9091 keeps the job clear of a Cloak Proxy app running on 9090 on the same runner.

The app’s monitors and scheduled flows run only while the app is open. For checks that run around the clock, schedule cloakctl collection run with cron, launchd or your CI system’s scheduled workflows.