The publish job never worked as written: npx surfer is the unscoped package (0.0.2), and the --token flow belonged to the v6 CLI, which Surfer has moved past. This switches to the current major.
@cloudron/surfer@7.2.0, pinned exactly - the workflow publishes whatever is committed, and an unpinned latest would let a breaking upstream release ship straight to the live site (same rule the docs repo already applies to its Surfer install).
Auth is the Cloudron username allan plus the per-app password in the SURFER_PASSWORD secret, against the app datacontroller.io.
deploy instead of put: it archives the build, extracts to a staging folder and swaps it in, so a failed upload leaves the current site serving - and it records the ref and commit in the site's deploy history, which is what makes a stale deployment datable. put --delete purges before uploading and is the one to avoid.
Adds workflow_dispatch so a deploy can be run by hand, and a concurrency group so two deploys cannot race.
The deploy message carries ${gitea.ref_name} and the short SHA.
Verification: surfer deploy --help on 7.2.0 confirms the flags used here. The end-to-end proof needs the SURFER_PASSWORD secret on the repo - once it is there, a dispatch from main publishes the same content the site already serves, which is a safe way to prove the pipeline before relying on it.
The publish job never worked as written: `npx surfer` is the unscoped package (0.0.2), and the `--token` flow belonged to the v6 CLI, which Surfer has moved past. This switches to the current major.
- `@cloudron/surfer@7.2.0`, pinned exactly - the workflow publishes whatever is committed, and an unpinned `latest` would let a breaking upstream release ship straight to the live site (same rule the docs repo already applies to its Surfer install).
- Auth is the Cloudron username `allan` plus the per-app password in the `SURFER_PASSWORD` secret, against the app `datacontroller.io`.
- `deploy` instead of `put`: it archives the build, extracts to a staging folder and swaps it in, so a failed upload leaves the current site serving - and it records the ref and commit in the site's deploy history, which is what makes a stale deployment datable. `put --delete` purges before uploading and is the one to avoid.
- Adds `workflow_dispatch` so a deploy can be run by hand, and a concurrency group so two deploys cannot race.
- The deploy message carries `${gitea.ref_name}` and the short SHA.
Verification: `surfer deploy --help` on 7.2.0 confirms the flags used here. The end-to-end proof needs the `SURFER_PASSWORD` secret on the repo - once it is there, a dispatch from `main` publishes the same content the site already serves, which is a safe way to prove the pipeline before relying on it.
The publish job used `npx surfer put --token` - the unscoped package, which
resolves to 0.0.2, and the v6 token flow, which Surfer no longer accepts. Move
to @cloudron/surfer 7.2.0, pinned: username allan plus the per-app password in
the SURFER_PASSWORD secret, app datacontroller.io.
`deploy` rather than `put`: it tars the build, extracts to a staging folder and
swaps it in, so a failed upload leaves the current site serving, and it records
the build's ref and commit in the site history. Also adds workflow_dispatch, so
a deploy can be run by hand without pushing to main.
Checked the full diff: .gitea/workflows/publish.yml only (workflow_dispatch trigger, deploy concurrency group, surfer v6 put replaced by v7 deploy). The exact tool pin, the atomic-swap deploy and set -euo pipefail are the right shape.
.gitea/workflows/publish.yml:45 - npx --yes @cloudron/surfer@7.2.0 pins the version but not the artifact: npx resolves from the registry at deploy time and never reads package-lock.json, so no integrity hash is checked for the tool that publishes the live site. Add @cloudron/surfer 7.2.0 as an exact devDependency (npm i -E, so save-exact/ignore-scripts keep it pinned) and invoke npx surfer, so the lockfile pins the tarball the workflow deploys with.
.gitea/workflows/publish.yml:48 - --password "$SURFER_PASSWORD" expands the app password into the command line, where it is visible in the runner's process table and in any command echo. Pass it via an environment variable or stdin if surfer 7 accepts one; keep the secret out of argv.
.gitea/workflows/publish.yml:47 - --username allan hardcodes the deploying account. Move it to a repository variable so a change of owner, or a second operator, does not need a workflow edit.
3 findings above for review.
Checked the full diff: .gitea/workflows/publish.yml only (workflow_dispatch trigger, deploy concurrency group, surfer v6 `put` replaced by v7 `deploy`). The exact tool pin, the atomic-swap deploy and `set -euo pipefail` are the right shape.
- .gitea/workflows/publish.yml:45 - `npx --yes @cloudron/surfer@7.2.0` pins the version but not the artifact: npx resolves from the registry at deploy time and never reads package-lock.json, so no integrity hash is checked for the tool that publishes the live site. Add @cloudron/surfer 7.2.0 as an exact devDependency (`npm i -E`, so save-exact/ignore-scripts keep it pinned) and invoke `npx surfer`, so the lockfile pins the tarball the workflow deploys with.
- .gitea/workflows/publish.yml:48 - `--password "$SURFER_PASSWORD"` expands the app password into the command line, where it is visible in the runner's process table and in any command echo. Pass it via an environment variable or stdin if surfer 7 accepts one; keep the secret out of argv.
- .gitea/workflows/publish.yml:47 - `--username allan` hardcodes the deploying account. Move it to a repository variable so a change of owner, or a second operator, does not need a workflow edit.
3 findings above for review.
allan
merged commit 59f169e32d into main2026-10-28 00:39:38 +00:00
allan
deleted branch ci/surfer-app-password2026-10-28 00:39:38 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The publish job never worked as written:
npx surferis the unscoped package (0.0.2), and the--tokenflow belonged to the v6 CLI, which Surfer has moved past. This switches to the current major.@cloudron/surfer@7.2.0, pinned exactly - the workflow publishes whatever is committed, and an unpinnedlatestwould let a breaking upstream release ship straight to the live site (same rule the docs repo already applies to its Surfer install).allanplus the per-app password in theSURFER_PASSWORDsecret, against the appdatacontroller.io.deployinstead ofput: it archives the build, extracts to a staging folder and swaps it in, so a failed upload leaves the current site serving - and it records the ref and commit in the site's deploy history, which is what makes a stale deployment datable.put --deletepurges before uploading and is the one to avoid.workflow_dispatchso a deploy can be run by hand, and a concurrency group so two deploys cannot race.${gitea.ref_name}and the short SHA.Verification:
surfer deploy --helpon 7.2.0 confirms the flags used here. The end-to-end proof needs theSURFER_PASSWORDsecret on the repo - once it is there, a dispatch frommainpublishes the same content the site already serves, which is a safe way to prove the pipeline before relying on it.Checked the full diff: .gitea/workflows/publish.yml only (workflow_dispatch trigger, deploy concurrency group, surfer v6
putreplaced by v7deploy). The exact tool pin, the atomic-swap deploy andset -euo pipefailare the right shape.npx --yes @cloudron/surfer@7.2.0pins the version but not the artifact: npx resolves from the registry at deploy time and never reads package-lock.json, so no integrity hash is checked for the tool that publishes the live site. Add @cloudron/surfer 7.2.0 as an exact devDependency (npm i -E, so save-exact/ignore-scripts keep it pinned) and invokenpx surfer, so the lockfile pins the tarball the workflow deploys with.--password "$SURFER_PASSWORD"expands the app password into the command line, where it is visible in the runner's process table and in any command echo. Pass it via an environment variable or stdin if surfer 7 accepts one; keep the secret out of argv.--username allanhardcodes the deploying account. Move it to a repository variable so a change of owner, or a second operator, does not need a workflow edit.3 findings above for review.