Move the authenticated drift check into the repository as tools/compat_auth.py, run daily by .github/workflows/compat-auth.yml on the maintainer's forge only. Credentials come from FH_EMAIL and FH_PASSWORD, the output is pass/fail labels only because the run log is public, and a failed run pushes the report to ntfy. Exit 5 means all hold, 10 drift, anything else that it could not run. Point compat.yml, tools/compat.py and the docs at it, add a README section, and cut 0.5.1.
118 lines
4.7 KiB
YAML
118 lines
4.7 KiB
YAML
name: Signed-in compatibility
|
|
|
|
# compat.yml checks what anyone can see on freshharvest.com. Everything that has
|
|
# actually broken so far sat behind the login, and every one of those breaks was
|
|
# SILENT: subscription rows moved and the integration reported 0 subscriptions,
|
|
# hold dates stopped being ISO and it reported 0 holds. A sensor reading 0 looks
|
|
# like an account with nothing in it, so nobody notices.
|
|
#
|
|
# tools/compat_auth.py signs in, read-only, and checks the markup the sensors and
|
|
# controls are parsed from. It never posts to a write endpoint.
|
|
#
|
|
# WHERE IT RUNS: only on the maintainer's own forge, where the account
|
|
# credentials are repository secrets. The GitHub mirror and forks skip it (the
|
|
# job's `if:`); they have no credentials, and a daily red run would be noise.
|
|
#
|
|
# THE RUN LOG IS PUBLIC. The script prints one pass/fail label per assumption and
|
|
# nothing read from the account. Keep it that way: no `set -x`, never echo an
|
|
# env var, and hand secrets to steps through `env:` only, never inline in `run:`.
|
|
#
|
|
# Secrets: FRESHHARVEST_EMAIL and FRESHHARVEST_PASSWORD (the account), NTFY_URL
|
|
# (the full ntfy topic URL) and NTFY_TOKEN (an access token for that topic).
|
|
|
|
on:
|
|
schedule:
|
|
# 11:41 UTC is 07:41 EDT (06:41 EST): before the day's first Home Assistant
|
|
# refresh, so a break is known before anyone reads a sensor quietly showing 0.
|
|
- cron: "41 11 * * *"
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
compat-auth:
|
|
name: signed-in markup check
|
|
# Not GitHub, and this repository: skips the mirror and every fork.
|
|
if: ${{ github.server_url != 'https://github.com' && github.repository == 'flan/ha-freshharvest' }}
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.13"
|
|
|
|
# Exit 5: every assumption holds. 10: drift. Anything else: it could not run.
|
|
- name: Check the markup behind the login
|
|
id: check
|
|
shell: bash
|
|
env:
|
|
FH_EMAIL: ${{ secrets.FRESHHARVEST_EMAIL }}
|
|
FH_PASSWORD: ${{ secrets.FRESHHARVEST_PASSWORD }}
|
|
run: |
|
|
report="${RUNNER_TEMP:-/tmp}/compat-auth-report.txt"
|
|
rc=0
|
|
# Well inside the job's 10 minutes, so the notify step still gets to run.
|
|
timeout 7m python tools/compat_auth.py > "$report" 2>&1 || rc=$?
|
|
if [ "$rc" -eq 124 ]; then
|
|
printf '\ntimed out after 7 minutes\n' >> "$report"
|
|
fi
|
|
cat "$report"
|
|
echo "rc=$rc" >> "$GITHUB_OUTPUT"
|
|
case "$rc" in
|
|
5) exit 0 ;;
|
|
10) echo "::error::freshharvest.com markup has drifted; see the report above"
|
|
exit 1 ;;
|
|
*) echo "::error::the check could not run (exit $rc)"
|
|
exit 1 ;;
|
|
esac
|
|
|
|
# Runs on drift, on a failed check, and on any earlier step failing.
|
|
- name: Push the report to ntfy
|
|
if: ${{ failure() }}
|
|
shell: bash
|
|
env:
|
|
NTFY_URL: ${{ secrets.NTFY_URL }}
|
|
NTFY_TOKEN: ${{ secrets.NTFY_TOKEN }}
|
|
RC: ${{ steps.check.outputs.rc }}
|
|
# Gitea addresses a run's page by its per-repository run number.
|
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_number }}
|
|
run: |
|
|
if [ -z "$NTFY_URL" ] || [ -z "$NTFY_TOKEN" ]; then
|
|
echo "::error::the NTFY_URL and NTFY_TOKEN secrets must both be set"
|
|
exit 1
|
|
fi
|
|
report="${RUNNER_TEMP:-/tmp}/compat-auth-report.txt"
|
|
if [ ! -s "$report" ]; then
|
|
echo "No report: a step before the check failed." > "$report"
|
|
fi
|
|
if [ "$RC" = "10" ]; then
|
|
title="Fresh Harvest markup drift"
|
|
priority=default
|
|
tags=warning
|
|
else
|
|
title="Fresh Harvest signed-in check could not run"
|
|
priority=high
|
|
tags=rotating_light
|
|
fi
|
|
# -s without -S: a curl error message would name the ntfy host in this public log.
|
|
# The response body echoes the report, so it goes to /dev/null.
|
|
curl_rc=0
|
|
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 30 --retry 2 \
|
|
-H "Authorization: Bearer $NTFY_TOKEN" \
|
|
-H "Title: $title" \
|
|
-H "Priority: $priority" \
|
|
-H "Tags: $tags" \
|
|
-H "Click: $RUN_URL" \
|
|
--data-binary "@$report" \
|
|
"$NTFY_URL") || curl_rc=$?
|
|
if [ "$code" != "200" ]; then
|
|
echo "::error::ntfy push failed (HTTP ${code:-none}, curl exit $curl_rc)"
|
|
exit 1
|
|
fi
|
|
echo "report pushed to ntfy"
|