Storage and DNS
Cloudflare integration
Ahena works with your Cloudflare account to set up and check R2 object storage (buckets and CORS) and DNS records. Your app talks to R2 directly through the generated storage code. Ahena is never in the request path.
What Ahena inspects
Read-only: inspecting and Doctor never change anything at Cloudflare.
- The token: whether it's active, when it expires, and which R2 and DNS permissions it has.
- Accounts, zones, zone status and nameservers.
- R2 buckets and their CORS rules, including rules Ahena didn't create.
- The DNS records you declared in
ahena.config.ts.
What Ahena configures
You declare what you want in ahena.config.ts; ahena plan shows each change with its classification before anything is applied.
| Change | Classification | Notes |
|---|---|---|
| Create an R2 bucket | BILLABLE | R2 usage beyond the free tier is billed. Needs an admin and an extra confirmation; --yes also needs --allow-billable. |
| Set CORS | CONFIRMATION_REQUIRED | Ahena manages one rule (id: "ahena") and keeps every other rule. |
| Add a DNS record | CONFIRMATION_REQUIRED | — |
| Change an existing DNS record (A, AAAA or CNAME content, or replace the SPF record) | DESTRUCTIVE | It overwrites a live record, and the zone is shared by every environment. |
Refused outright:
*or localhost CORS origins in production, and non-https production origins.- CNAMEs that would collide with other records, and records outside the zone.
Generated code: src/ahena/providers/cloudflare.ts (an S3 client for R2), src/ahena/storage/index.ts (upload, download, remove, presigned URLs and raw) and .env.example.cloudflare.
How Ahena verifies
After every write, Ahena reads Cloudflare back. Each change ends in one of these states, and the plan's outcome says why:
- VERIFIED: Ahena read the provider back and saw the desired state. The CLI shows ✓ only for VERIFIED.
- APPLIED_UNVERIFIED: The provider accepted the change, but the re-read doesn't show it yet (after bounded polling), or the re-read failed.
Before each write, Ahena plans again with full pagination and checks the token's permission; afterwards it reads the bucket, CORS rules or DNS record back. A listing that can't be read completely never counts as "absent".
If a request may have reached Cloudflare but the answer was lost, Ahena re-reads before deciding: done, safe to retry, or “check before retrying”.
What Doctor diagnoses
Key checks from ahena doctor. Each finding says why it matters, where, the impact and whether Ahena can fix it. The full list is in the Cloudflare docs.
| Check | What it means |
|---|---|
cloudflare.token | Token active, expiring within 14 days, or inactive. |
cloudflare.r2.access | Whether the token can list R2 buckets. |
cloudflare.r2.bucket | The configured bucket exists. |
cloudflare.r2.cors_wildcard | A production bucket allows every origin. |
cloudflare.dns.zone | Zone active, pending nameservers, missing, or no permission. |
cloudflare.dns.record.<type>.<name> | A configured record is present, wrong, missing or conflicting. |
More on findings, health and continuous checks: Doctor.
Approvals
Cloudflare changes here are classified BILLABLE, CONFIRMATION_REQUIRED and DESTRUCTIVE. Every change is planned and shown as a diff first. Ahena itself enforces who can approve it:
- SAFE changes are applied without asking.
- In production, every other change needs approval in the Ahena dashboard, signed in, by an admin.
- In other environments, CONFIRMATION_REQUIRED changes are approved in the CLI; BILLABLE and DESTRUCTIVE changes always need the dashboard.
- MANUAL steps are never applied by Ahena.
--yes and --allow-billable don't replace a dashboard approval. See approvals for how it works and why the browser.
Manual steps
These are MANUAL: Ahena never does them. It lists them with the exact steps when they apply.
- Zone pending: turn off DNSSEC at the registrar, replace its nameservers with the two Cloudflare shows (Doctor prints them), and wait for activation.
- Token missing a permission: edit the token in the Cloudflare dashboard and add the permission Doctor names.
- Create R2 access keys for your app in the dashboard (R2 → Manage API tokens). Ahena doesn't create them.
Credentials and permissions
| Name | Secret | Notes |
|---|---|---|
CLOUDFLARE_API_TOKEN | Yes | A user or account-owned API token, stored envelope-encrypted and bound to the environment. |
CLOUDFLARE_ACCOUNT_ID | No | 32 hex characters. Ahena lists your accounts to pick from. |
Least privilege
- Create a custom token with only what you use: Account › Workers R2 Storage › Read (Doctor, inspect) and Write (buckets, CORS); Zone › Zone › Read (zone status); Zone › DNS › Read or Edit (checking or adding records).
- Ahena checks what the token can do and reports a missing permission as a named Doctor finding.
- The generated app code uses an R2 access key, never your Cloudflare API token.
Each credential Ahena stores gets its own key and is envelope-encrypted, bound to the environment. See security.
Workflow example
Connect, check, plan, then apply. Placeholders (…) stand for your own values.
CLOUDFLARE_API_TOKEN=… ahena connect cloudflare -e productionConnect and pick the account.
ahena doctor -e productionCheck the token's permissions, the zone, the bucket and CORS.
ahena plan -e productionSee each change with its classification; a new bucket is BILLABLE.
ahena apply -e productionApprove and apply. Billable and destructive changes are always approved in the dashboard.
ahena generate cloudflare -e productionWrite the S3-compatible storage adapter.
Verification status
Live verified: token and permission checks, account and zone inspection, Doctor and planning (read-only)
Verified against the real provider API for the capabilities listed. Its other capabilities are validated by Ahena's automated provider contract and conformance tests.
How Cloudflare is tested
- Verified against the real Cloudflare API, read-only: token verification, permission detection, accounts and zones, Doctor, a plan that was correctly refused, and disconnect.
- Writes (buckets, CORS and DNS records) are tested only against a simulated API. R2 isn't enabled on the test account, and DNS writes need a throwaway zone.
- When the token can't read its own policies, Ahena probes write permission with a request to a target that can't exist. That relies on Cloudflare checking permission before existence, which still needs confirming against the real API.
- The generated storage code is typechecked against the AWS SDK, not run.
The providers overview explains Ahena's testing methodology and what has been verified for every provider.
Limitations
- Ahena never deletes buckets, objects, CORS rules it didn't create, or DNS records.
- Zones must already be in the account. Ahena doesn't add domains or change registrars.
- Workers routes and custom domains aren't managed yet.
Disconnecting
ahena disconnect cloudflare removes the stored token (Ahena didn't create it, so it doesn't revoke it); buckets, objects and DNS records are untouched.