Move 'permissions: contents: read' from workflow level to the record-deployment
job (GitHub Actions least-privilege, rule S8264), keeping this workflow uniform
with the astrolabe copy. Single-job workflow, but consistent and future-proof.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review round 1 follow-ups:
- Reference the built-in $GITHUB_SHA env var in run scripts instead of
interpolating ${{ github.sha }}, removing the GitHub Actions script-injection
surface (SonarCloud security rating on new code).
- Add a concurrency group (cancel-in-progress: false) to
pact-record-deployment.yml so back-to-back tag pushes don't race the recording.
- Add timeout-minutes: 5 to guard against a hung tailnet join.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds the missing record-deployment half of the Pact can-i-deploy loop and
stops can-i-deploy from failing every merge while the broker's production
environment is still empty.
- New pact-record-deployment.yml: on tag push, records a production
deployment of nextcloud-mcp-server keyed by the tagged commit SHA, which
matches the SHA pact.yml publishes consumer pacts / verification results
with. Recording the tag string would not link to the verified pacts.
- pact.yml can-i-deploy: wrapped in shadow mode (runs for signal, emits a
warning annotation on failure, always exits 0). can-i-deploy cannot pass
until both nextcloud-mcp-server and astrolabe have recorded a production
deployment, so gating now would block merges on a bootstrap gap.
Tracked on Deck card #325. Promotion to a hard gate is a follow-up.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>