Skip to main content

make-cloudflare

Cloudflare Pages direct upload for mkrun, in Python: publish a built directory with no Node on the machine and no wrangler in the pipeline.

# Makefile.py in a consuming repo
# /// script
# requires-python = ">=3.11"
# dependencies = ["mkrun>=0.4", "make-cloudflare>=0.1"]
# ///
from make_cloudflare import cloudflare  # importing is what registers the group
$ mk cloudflare.deploy site/dist --project mkrun     # production (branch main)
$ mk cloudflare.deploy site/dist --branch try        # a preview, on its own URL
$ mk cloudflare.projects                             # what the account has
$ mk cloudflare.deployments --limit 5                # one project's recent ones
$ mk -n cloudflare.deploy site/dist                  # the plan; nothing is sent

Credentials are the two variables wrangler already reads, so a repository that deploys from CI needs no new secret: CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN (a token with Cloudflare Pages: Edit). The token's name ends in TOKEN, so mkrun treats it as a credential — it is withheld from the environment until a task asks for it, redacted in everything printed, and readable from the encrypted store. The project can come from --project or from CLOUDFLARE_PAGES_PROJECT in the repo's env layer.

Why this exists

wrangler pages deploy is four HTTPS calls and a hash. Reaching them through npx costs a Node toolchain in repositories that otherwise have none — a Rust one, a frontage one — and a node_modules in the deploy image of every one of them.

POST /accounts/<acct>/pages/projects/<p>/upload-token   -> a short-lived JWT
POST /pages/assets/check-missing                        -> what is not stored yet
POST /pages/assets/upload                               -> the files, batched
POST /pages/assets/upsert-hashes
POST /accounts/<acct>/pages/projects/<p>/deployments    -> the manifest

Three things make a naive port wrong, and all three fail silently — every call returns 200 and the site serves the old bytes, or none:

  • The hash is BLAKE3 of a strange input: the base64 text of the contents with the extension (no dot) appended, first 32 hex characters. Not of the bytes, and not SHA-256. tests/test_pages.py locks it with a golden value.
  • _headers, _redirects and _routes.json are not assets. They are fields on the deployment. Walk them in as ordinary files and the deploy reports success while the site's CSP stops applying.
  • check-missing, upload and upsert-hashes take the JWT, not the account token, and carry no /accounts/<id> prefix — the JWT already names the account.

What it does not do

Pages Functions. A directory holding _worker.js or functions/ is refused by name rather than half-deployed: bundling a Worker is a build step, not an upload, and wrangler should keep doing it.

Steps 2 and 3 are undocumented. They exist because wrangler uses them, and Cloudflare can change them without a changelog; the documented deployments endpoint alone cannot upload a file. That is the real cost of dropping wrangler, and it is the reason this is a small module with a golden test rather than a wrapper nobody reads.

Nothing here is specific to any owner or account. The group name is cloudflare, and it merges with a repo's own cloudflare.* tasks — groups are namespaces — so only a same-named task collides; this package claims deploy, projects and deployments, nothing else. blake3 is the one dependency, and it lives here rather than in the runner so mkrun itself stays dependency-free.

Metadata

Release files for make-cloudflare 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for make-cloudflare 0.1.0
File Size Uploaded
make_cloudflare-0.1.0.tar.gz 12.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for make-cloudflare 0.1.0
File Interpreter ABI Platform
make_cloudflare-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 23.4 kB

Release files / make_cloudflare-0.1.0.tar.gz

Download URL make_cloudflare-0.1.0.tar.gz
Size 12.6 kB
Tags Source
SHA-256 checksum
How to use checksums
459debbfebcf2c3404ec3ee3f724ec4ff7bde69040ceba3c8051d6c8a824326d
BLAKE2b-256 checksum
How to use checksums
cc25064b4a3a2501a1fb12e8cc799248d1b52ec13a3c15abce4e57d8beced22c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / make_cloudflare-0.1.0-py3-none-any.whl

Download URL make_cloudflare-0.1.0-py3-none-any.whl
Size 10.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1cf9df07c6ebb74f1041ef255a3a0d1d6838fd2917db9cbb0b8ea5664cb98136
BLAKE2b-256 checksum
How to use checksums
e838dc93ce7873fe2527a97c42dbcb6336fbdf988d572a6abcfcd2724de5b047
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page