https://material-identity.eu/.well-known/security.txt and .../pgp-security.asc both return 404 on the live site, even though #108 merged, the deploy ran green, and npm run build writes both files into site/.well-known/.
Cause
actions/upload-pages-artifact builds its tarball with a hardcoded exclusion:
tar -cvf "$RUNNER_TEMP/artifact.tar" --exclude=.git --exclude=.github --exclude=.[^/]* ...
That last pattern drops every dot-entry, .well-known/ included. The directory never reaches the artifact, so Pages never had it. This is inside the action, not an input we can flip — include-hidden-files governs the upload of the tar itself, not what goes into it.
Verified against the origin directly, which rules out the Worker:
| path (on the Pages origin) |
status |
/.well-known/security.txt |
404 |
/.well-known/pgp-security.asc |
404 |
/context.jsonld |
200 |
/index.html |
200 |
The - [ ] After deploy: curl the live path box on #108 was the right instinct; the assumption behind it ("the artifact upload includes dotfiles") was simply wrong.
Fix
Store the files at a non-dotted origin path and let the Worker map the canonical URI onto it. This is what the Worker is already for — a stateless URI + Accept -> origin file + headers mapping — so the indirection costs nothing and adds no CI complexity.
scripts/build.ts emits site/well-known/ instead of site/.well-known/. The tracked source stays at .well-known/ in the repo root, which is the convention and is what a repo-root consumer expects.
worker/index.ts rewrites /.well-known/<x> to origin /well-known/<x>, keeping the existing content types and the 1-day cache ceiling.
The public URL stays exactly https://material-identity.eu/.well-known/security.txt, which is the only address RFC 8615 and RFC 9116 care about. The Pages origin is never advertised (deploy.yml says so), so its internal layout is free.
Rejected alternative: replacing upload-pages-artifact with a hand-rolled tar + upload-artifact pair. It would keep the origin layout tidy but puts the deploy path's correctness in our hands for the sake of a directory name nobody sees.
Ratchet
A build test asserting the output path is not enough — that is what we already had, and it passed while the site 404'd. The gap is that nothing tests the deployed artifact. Add a post-deploy smoke step to deploy.yml that curls both canonical URLs and fails the run on a non-200, so a silently-dropped file can never again look like a successful deploy.
https://material-identity.eu/.well-known/security.txtand.../pgp-security.ascboth return 404 on the live site, even though #108 merged, the deploy ran green, andnpm run buildwrites both files intosite/.well-known/.Cause
actions/upload-pages-artifactbuilds its tarball with a hardcoded exclusion:That last pattern drops every dot-entry,
.well-known/included. The directory never reaches the artifact, so Pages never had it. This is inside the action, not an input we can flip —include-hidden-filesgoverns the upload of the tar itself, not what goes into it.Verified against the origin directly, which rules out the Worker:
/.well-known/security.txt/.well-known/pgp-security.asc/context.jsonld/index.htmlThe
- [ ] After deploy: curl the live pathbox on #108 was the right instinct; the assumption behind it ("the artifact upload includes dotfiles") was simply wrong.Fix
Store the files at a non-dotted origin path and let the Worker map the canonical URI onto it. This is what the Worker is already for — a stateless
URI + Accept -> origin file + headersmapping — so the indirection costs nothing and adds no CI complexity.scripts/build.tsemitssite/well-known/instead ofsite/.well-known/. The tracked source stays at.well-known/in the repo root, which is the convention and is what a repo-root consumer expects.worker/index.tsrewrites/.well-known/<x>to origin/well-known/<x>, keeping the existing content types and the 1-day cache ceiling.The public URL stays exactly
https://material-identity.eu/.well-known/security.txt, which is the only address RFC 8615 and RFC 9116 care about. The Pages origin is never advertised (deploy.ymlsays so), so its internal layout is free.Rejected alternative: replacing
upload-pages-artifactwith a hand-rolledtar+upload-artifactpair. It would keep the origin layout tidy but puts the deploy path's correctness in our hands for the sake of a directory name nobody sees.Ratchet
A build test asserting the output path is not enough — that is what we already had, and it passed while the site 404'd. The gap is that nothing tests the deployed artifact. Add a post-deploy smoke step to
deploy.ymlthat curls both canonical URLs and fails the run on a non-200, so a silently-dropped file can never again look like a successful deploy.