~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

The proxy holds knotless.page's certificate, and serve answers its sites

Merged
Merged chadtmiller.com asked to merge into feature/pages from chadtmiller.com/knotless:pages/deploy

What changes

deploy/setup.sh, given KNOTLESS_PAGES_DOMAIN, sets the proxy up for repositories' sites. With it set, the script:

  • builds Caddy with the caddy-dns/cloudflare module, from a Dockerfile in /etc/knotless-proxy;
  • adds a knotless.page, *.knotless.page block, whose one certificate comes from the DNS challenge, proxying to serve;
  • reads the zone's token from KNOTLESS_PAGES_DNS_TOKEN, sent over ssh stdin so the host's process list never shows it, and keeps it in a 0600 /etc/knotless-proxy/cloudflare.env.

The token is given once, like run.env, triage.env and review.env are: a run without it keeps the file there, and with no file at all the run stops and says the token is needed once.

deploy.yml sets KNOTLESS_PAGES_DOMAIN: knotless.page, which deploy.sh writes to .env and the compose file passes to serve as --pages-domain. It's empty, and so off, when unset.

The deploy/README.md proxy section and local.env.example describe both.

Why

A wildcard certificate can only come from the DNS challenge, which stock Caddy can't answer. The zone's token is scoped to knotless.page alone, and is the one in hetzner-infra's edge stack, which already made the zone's apex and * records.

Each step converges, as the rest of setup.sh does. A rerun writes the same Caddyfile, Dockerfile and compose file. up -d --build builds the image once and from cache after, so a run that changes nothing recreates nothing. Without the domain, the proxy goes back to stock caddy:2 and the Dockerfile is removed.

How it was checked

bash -n on both scripts. Not run against the host yet: that's deploy/setup.sh with the token in deploy/local.env, once this lands on main with the rest of feature/pages.

Shortcomings

Nothing serves knotless.page until feature/pages reaches main and deploys. The module is unpinned, built from caddy:2-builder as stock Caddy is caddy:2.

🤖 Generated with Claude Code

Approved

This adds an optional knotless.page block to the proxy. With KNOTLESS_PAGES_DOMAIN set, setup.sh builds Caddy with the Cloudflare DNS module, serves the apex and *. on one certificate, and passes the domain to serve as --pages-domain. I read the deploy changes (setup.sh, deploy.sh, docker-compose.yml, deploy.yml, local.env.example). I found nothing that must change.

  • The token goes over ssh stdin into a file created under umask 077, so it never shows in the process list.
  • A run with no domain falls back to stock caddy:2 and removes the Dockerfile.
  • An empty --pages-domain "" is filtered to None in knotless-serve/src/lib.rs:1362, so the compose default is safe.
  • The compose heredoc is now unquoted so $CADDY expands. Nothing else in it contains $, so that is safe.

I did not read the other files in the diff (the knotless-serve and knotless crates, tests, docs, changeset). The diff is much larger than the description, and they look like the base branch's pages work, outside what this pull describes.

The unpinned module and the lack of a host run are both stated in the body. Run setup.sh against the host once feature/pages deploys.

Approved

Since my approval at b0f8c32, this pull has only had the pages/serve merge added, and that merge changes three things:

  • knotless/src/jetstream.rs adds nsid::SITE to the collections the firehose keeps, so the index sees site records. This matches the index.site test and the doc comment.
  • knotless/src/site.rs swaps with_context(|| format!(..)) for .context(format!(..)). It behaves the same. It builds the message eagerly, but only on the error path, so it costs nothing that matters.
  • knotless-serve/src/index.rs is rustfmt reflow of a test.

I found nothing that must change. The deploy changes I reviewed before are unchanged. The unpinned module and the missing host run are still the open points the body states, so run setup.sh against the host once feature/pages deploys.

Approved

Since my approval at 14c0e37, the pull has added one test: the_firehose_keeps_every_indexed_collection in knotless-serve/src/lib.rs. It checks that every collection in indexed_collections() passes knotless::jetstream::knotless, so a collection can't be backfilled but dropped by the live firehose. Both functions exist with the signatures the test uses, and the assertion is sound. I found nothing that must change. The deploy changes are as before. The unpinned module and the missing host run are still the open points the body states, so run setup.sh against the host once feature/pages deploys.

Approved

Since my approval at 9d5f0c7, the pull has added hardening for the sites work. I found nothing that must change.

  • SHA-256 check: knotless::release::valid_sha256 accepts only 64 lowercase hex digits. Sites checks it before joining the hash into the kept-files path, and Index::put drops a site record with a bad hash. That closes a path-traversal hole through the record's sha256. The index change moves the filter into SQL (INSERT … SELECT … WHERE ?5). It keeps the old behaviour of skipping non-sites and space records. The new test covers a traversal-style hash.
  • Backslash and control characters: a name containing \ or a control character now returns missing. Before, it could be redirected to /\evil, which a browser reads as another host. The integration test covers /%5Cevil.example.
  • Tests: the path helper now returns Option, and handle in the owner test is the local closure. Both compile as written.

The checks are still queued, so I haven't seen them pass. The deploy changes are as before. The unpinned module and the missing host run are still the open points the body states, so run setup.sh against the host once feature/pages deploys.

Merged as d067ffc