diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index d834d198..98db0b54 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -1,12 +1,12 @@ name: Documentation +# Publishes the docs site to the Cloudflare Worker that serves it. +# +# TRIGGERS ON `development`, NOT ON A `documentation` BRANCH. This file used to +# listen on a branch called `documentation`; nobody has pushed to one since +# 2026-05-25, so the site simply stopped being rebuilt while every docs change +# merged to development satisfied its review and published nothing. on: - # `development` is where the work lands. This used to trigger on a - # `documentation` branch that exists but nobody updates — so the workflow - # was green and idle while the live site aged. Measured today: - # softwarecatalog.conduction.nl and stackiq.conduction.nl both still serve - # the pre-rename "SoftwareCatalog" title while docs/docusaurus.config.js - # says 'Stackiq'. push: branches: [development] pull_request: @@ -14,69 +14,31 @@ on: jobs: deploy: - # Permission CEILING for the called documentation workflow, not a grant. - # The callee has three jobs and this block is their UNION, which is what the - # token already resolves to today: - # build contents: read - # deploy contents: write (peaceiris/actions-gh-pages pushes to gh-pages) - # image contents: read, packages: write (buildx push to GHCR) - # - # ⚠️ `packages: write` is load-bearing at RUNTIME, not merely statically: - # the callee's `build-image` input DEFAULTS TO TRUE, so the `image` job - # really does run on a push to `development` and really does push to - # GHCR. Dropping it 403s that push. - # - # It would be required even if that job were disabled, because GitHub - # validates the callee's DECLARED job permissions against this ceiling - # before dispatch — including for jobs an `if:` will skip — so a too-low - # ceiling makes the whole call fail to start rather than run with less. - permissions: - contents: write - packages: write uses: ConductionNL/.github/.github/workflows/documentation.yml@main - # A reusable workflow receives NO secrets by default, and the - # `permissions:` block above governs the TOKEN, not the secrets. Without - # this block `secrets.CF_API_TOKEN` is empty inside the callee, its - # "Publish to the Cloudflare Worker" step skips itself on its own guard, - # and the run finishes GREEN having written only gh-pages — which nothing - # serves. The live site never changes and no check goes red to say so. - # - # Mapped explicitly rather than `secrets: inherit`, because `inherit` - # hands the callee EVERY secret this repo holds — signing cert and key, - # appstore token, deploy keys — for the sake of two Cloudflare values. - # This way only those two cross the boundary. - # - # The exposure above is the ONLY reason for the explicit mapping. The - # names are the same on both sides: the org secrets really are - # `CF_API_TOKEN` / `CF_ACCOUNT_ID` — the names ConductionNL/.github's own - # deploy-docs.yml reads directly, and the names the callee declares under - # `workflow_call.secrets`. - # - # This block first read `secrets.CLOUDFLARE_API_TOKEN` / - # `secrets.CLOUDFLARE_ACCOUNT_ID`, which are not secrets anywhere in this - # org. Mapping from a name that does not exist is NOT an error — it - # yields an empty string — so the callee's publish step would have skipped - # itself on its own guard and the run would still have finished green. - # Measured on planninq run 32760529026, where that spelling did merge: - # "Publish to the Cloudflare Worker" SKIPPED, the log showing - # `CF_API_TOKEN:` with no value. + # A reusable workflow receives NO secrets by default. Without this block the + # callee's publish step finds CF_API_TOKEN empty, skips itself on its own + # `if:` guard, and the run finishes GREEN having changed nothing -- the + # failure that left the fleet's docs sites on May builds. The names are the + # same on both sides; the org secrets really are CF_API_TOKEN/CF_ACCOUNT_ID. secrets: CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }} CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }} with: - # `stackiq.conduction.nl` resolves as of 2026-08-23 — attached as a - # second custom domain on the SAME `softwarecatalog-docs` worker that - # serves `softwarecatalog.conduction.nl`. Both hosts answer 200. - # (The comment that used to sit here said the new host answered 000; - # that was true when it was written and is not any more.) cname: stackiq.conduction.nl + # softwarecatalog.conduction.nl is the retired hostname. It stays in docs-hosts so + # existing links keep resolving, and canonical-host below turns it into a + # 301 rather than a second live copy of every page. + # EVERY host this worker answers on, in FULL: wrangler reconciles the + # worker's triggers against this list, so a host left out is REMOVED and + # goes dark. docs-hosts: softwarecatalog.conduction.nl,stackiq.conduction.nl - - # The worker that ALREADY holds both custom domains. Without this the - # callee derives the name from `cname` — `stackiq-docs` — which does not - # exist. Deploying that would create a SECOND worker while both custom - # domains keep routing to `softwarecatalog-docs`: every deploy green, - # reaching nobody. Renaming the worker is a Cloudflare-side move, not - # something this file can perform. + # The ONE hostname this site is reached on. Every other host in + # docs-hosts answers 301 to the same path here. Before this, both hostnames + # served identical content and the retired name stayed as discoverable + # as the current one. + canonical-host: stackiq.conduction.nl + # PINNED. Deriving the name is how a deploy goes green and reaches + # nobody: wrangler creates the derived worker and publishes there while + # the custom domains keep routing to the real one. worker-name: softwarecatalog-docs