diff --git a/.github/workflows/deploy-public-site.yml b/.github/workflows/deploy-public-site.yml new file mode 100644 index 0000000..b07367a --- /dev/null +++ b/.github/workflows/deploy-public-site.yml @@ -0,0 +1,59 @@ +name: Deploy Public Site + +on: + push: + branches: [main] + paths: + - ".github/workflows/deploy-public-site.yml" + - "website/**" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: secopsai-public-site-production + cancel-in-progress: false + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + + - name: Set up Node.js 22 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 + with: + node-version: "22" + + - name: Deploy reviewed website directory + env: + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + run: | + npx --yes wrangler@4.114.0 pages deploy website \ + --project-name website \ + --branch main \ + --commit-hash "${GITHUB_SHA}" \ + --commit-message "Deploy SecOpsAI public site ${GITHUB_SHA}" + + - name: Verify public installer contents + run: | + set -euo pipefail + verify_installer() { + installer="$1" + marker="$2" + output="${RUNNER_TEMP}/${installer}" + curl -fsSL --retry 8 --retry-all-errors --retry-delay 5 \ + "https://secopsai.dev/${installer}?release=${GITHUB_SHA}" \ + -o "$output" + if [ "$(sed -n '1p' "$output")" != "#!/bin/sh" ]; then + echo "${installer} did not return a POSIX shell installer" >&2 + exit 1 + fi + grep -F "$marker" "$output" >/dev/null + } + verify_installer "install.sh" 'SECOPSAI_INSTALL_REF:-v1.0.0' + verify_installer "install-hermes.sh" 'MIN_VERSION="0.18.2"' diff --git a/docs/deployment-guide.md b/docs/deployment-guide.md index ac1bbcc..b2217d8 100644 --- a/docs/deployment-guide.md +++ b/docs/deployment-guide.md @@ -63,7 +63,10 @@ copies under `docs/`: - `website/install-hermes.sh` and `www/install-hermes.sh` This is the recommended path because the existing Cloudflare Pages Git -deployments require no separate Worker credential or manual route update. +deployment requires no separate Worker route. The repository also runs +`.github/workflows/deploy-public-site.yml` after relevant `main` changes. That +workflow publishes the reviewed `website/` directory explicitly and verifies +the contents of both public installer endpoints before it succeeds. You have two fallback options if the apex site is moved away from these Pages projects. diff --git a/tests/test_hermes_installers.py b/tests/test_hermes_installers.py index dfb1c4c..f7e7217 100644 --- a/tests/test_hermes_installers.py +++ b/tests/test_hermes_installers.py @@ -43,6 +43,10 @@ def test_public_hermes_installer_and_worker_route_are_wired() -> None: standard = (ROOT / "docs" / "install.sh").read_text(encoding="utf-8") assert (ROOT / "website" / "install.sh").read_text(encoding="utf-8") == standard assert (ROOT / "www" / "install.sh").read_text(encoding="utf-8") == standard + deployment = (ROOT / ".github" / "workflows" / "deploy-public-site.yml").read_text(encoding="utf-8") + assert "wrangler@4.114.0 pages deploy website" in deployment + assert "verify_installer \"install-hermes.sh\"" in deployment + assert "CLOUDFLARE_API_TOKEN" in deployment def test_tracked_website_copies_are_identical_and_contain_hermes_tab() -> None: