feat: Cloudflare Artifacts REST API client#6
Merged
Conversation
Wraps the full control plane documented at https://developers.cloudflare.com/artifacts/api/rest-api/ — six repo endpoints (create / list / get / delete / fork / import) and three token endpoints (create / list / delete) — so repos and git tokens can be managed end-to-end alongside the existing wire-protocol support. Function and field names mirror upstream verbatim (`create_repo`, `default_branch`, `plaintext`, `expires_at`, …) so the client can be cross-referenced against the Cloudflare TypeScript types directly. `Exgit.CloudflareArtifacts.new/1` returns a `%Req.Request{}` configured with bearer auth and `base_url`; per-endpoint functions use Req's `:path_params` and `:json` steps with no manual URL building. Errors are surfaced as `{:error, %Req.Response{}}` so callers can pattern-match on upstream codes directly (e.g. `code: 10103` for `ttl out of range`). Transport-level failures pass through Req's exception unchanged. `%Repo{}` and `%Token{}` redact the `:token` and `:plaintext` fields in their `Inspect` impls. Tests: * Bypass-backed unit suite covering every endpoint's URL, body, query params, auth header, and v4 envelope parsing — including a pin on Req's path-segment URL-encoding behavior. * Live lifecycle smoketest (`:cloudflare_api`) that creates a fresh repo, mints write+read tokens, pushes via exgit, clones via exgit with byte-equality assertion, lists/revokes tokens, and deletes the repo. Gated on `CF_ARTIFACT_ACCOUNT_ID` + `CF_ARTIFACT_API_TOKEN`. The new `:cloudflare_api` tag is decoupled from `:cloudflare` so the existing wire-roundtrip CI step is unaffected; the lifecycle test opts in once new secrets are wired. Adds Bypass as a test-only dep. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The first pass prefixed both with `CF_ARTIFACT_` for symmetry with the existing `CF_ARTIFACT_REMOTE` / `CF_ARTIFACT_TOKEN` (which are artifact-scoped — a wire URL and a repo-scoped git token). But the account ID and API token are *generic* Cloudflare credentials — reusable across any CF product — so the artifact prefix was wrong. `CF_ARTIFACT_NAMESPACE` keeps its prefix since it really is artifact-specific. Verified end-to-end against a real account: full lifecycle (create → write-token → push → read-token → clone with byte-equal verification → list → revoke → delete) completes in ~5s. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
create_repo,default_branch,plaintext,expires_at, …) so the client can be cross-referenced against the upstream TypeScript types directly.Exgit.CloudflareArtifacts.new/1returns a%Req.Request{}with bearer auth +base_urlpre-configured; per-endpoint functions lean on Req's:path_paramsand:jsonsteps — no manual URL building. Errors come back as{:error, %Req.Response{}}so callers can pattern-match on upstream codes (e.g.code: 10103forttl out of range); transport-level failures pass through Req's exception.%Repo{}and%Token{}redact:token/:plaintextin theirInspectimpls.:cloudflare_api) creates a fresh repo, mints write+read tokens, pushes via exgit, clones via exgit with byte-equality, lists/revokes tokens, and deletes the repo.New env vars (live test only)
The
:cloudflare_apitag is excluded by default and is decoupled from the existing:cloudflaretag, so this PR doesn't change CI behavior. To wire the lifecycle test in CI later, add:CF_ACCOUNT_ID— Cloudflare account ID (generic, not artifact-specific)CF_API_TOKEN— Cloudflare API token withArtifacts > Edit(generic)CF_ARTIFACT_NAMESPACE(optional, defaults to"default")Test plan
mix format --check-formattedmix compile --warnings-as-errorsMIX_ENV=dev mix credo --strictMIX_ENV=dev mix dialyzermix test --warnings-as-errors— 720 tests, 0 failuresmix deps.unlock --check-unused🤖 Generated with Claude Code