Skip to content

Sentinel

Sentinel #29

Workflow file for this run

name: Sentinel
on:
workflow_dispatch:
schedule:
- cron: "0 7,8 * * 6"
permissions:
contents: write
concurrency:
group: sentinel-scan
cancel-in-progress: false
jobs:
scan:
runs-on: ubuntu-latest
timeout-minutes: 10
env:
DOPPLER_TOKEN_PRESENT: ${{ secrets.DOPPLER_TOKEN != '' }}
steps:
- name: Check Europe/Rome schedule
id: schedule
if: github.event_name == 'schedule'
run: |
# Non guardare l'ora a runtime: GitHub ritarda i job schedulati anche
# di oltre un'ora, quindi l'ora di Roma è quasi sempre gia' scivolata
# oltre le 09:00. Decidi in base a QUALE cron ha triggerato + fuso DST.
# 09:00 Europe/Rome = 07:00 UTC in estate (+0200), 08:00 UTC in inverno (+0100).
offset=$(TZ=Europe/Rome date +%z)
sched="${{ github.event.schedule }}"
should_run=false
if [ "$offset" = "+0200" ] && [ "$sched" = "0 7 * * 6" ]; then should_run=true; fi
if [ "$offset" = "+0100" ] && [ "$sched" = "0 8 * * 6" ]; then should_run=true; fi
if [ "$should_run" != "true" ]; then
echo "Cron $sched con offset $offset fuori dalla finestra 09:00 Europe/Rome, skip."
fi
echo "should_run=$should_run" >> "$GITHUB_OUTPUT"
- name: Verifica variabili Doppler
if: github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true'
env:
DOPPLER_PROJECT: ${{ vars.DOPPLER_PROJECT }}
DOPPLER_CONFIG: ${{ vars.DOPPLER_CONFIG }}
run: |
if [ -z "${DOPPLER_PROJECT:-}" ]; then
echo "::warning::DOPPLER_PROJECT non impostato"
fi
if [ -z "${DOPPLER_CONFIG:-}" ]; then
echo "::warning::DOPPLER_CONFIG non impostata"
fi
if [ "${DOPPLER_TOKEN_PRESENT}" != "true" ]; then
echo "::notice::DOPPLER_TOKEN assente: il fetch non verrà eseguito."
fi
- name: Fetch secrets from Doppler
if: ${{ env.DOPPLER_TOKEN_PRESENT == 'true' && vars.DOPPLER_PROJECT != '' && vars.DOPPLER_CONFIG != '' && (github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true') }}
uses: dopplerhq/secrets-fetch-action@v2.0.0
with:
doppler-token: ${{ secrets.DOPPLER_TOKEN }}
doppler-project: ${{ vars.DOPPLER_PROJECT }}
doppler-config: ${{ vars.DOPPLER_CONFIG }}
inject-env-vars: true
- name: Apply GitHub email secret fallback
if: github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true'
env:
GITHUB_SENTINEL_EMAIL_TO: ${{ secrets.SENTINEL_EMAIL_TO }}
GITHUB_SENTINEL_EMAIL_FROM: ${{ secrets.SENTINEL_EMAIL_FROM }}
GITHUB_SENTINEL_GMAIL_USER: ${{ secrets.SENTINEL_GMAIL_USER }}
GITHUB_SENTINEL_GMAIL_APP_PASSWORD: ${{ secrets.SENTINEL_GMAIL_APP_PASSWORD }}
GITHUB_SENTINEL_ICLOUD_USER: ${{ secrets.SENTINEL_ICLOUD_USER }}
GITHUB_SENTINEL_ICLOUD_APP_PASSWORD: ${{ secrets.SENTINEL_ICLOUD_APP_PASSWORD }}
GITHUB_BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
run: |
for name in \
SENTINEL_EMAIL_TO \
SENTINEL_EMAIL_FROM \
SENTINEL_GMAIL_USER \
SENTINEL_GMAIL_APP_PASSWORD \
SENTINEL_ICLOUD_USER \
SENTINEL_ICLOUD_APP_PASSWORD \
BLOB_READ_WRITE_TOKEN
do
fallback_name="GITHUB_${name}"
if [ -z "${!name:-}" ] && [ -n "${!fallback_name:-}" ]; then
echo "${name}=${!fallback_name}" >> "$GITHUB_ENV"
fi
done
- name: Check email secrets
if: github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true'
run: |
missing=0
for name in \
SENTINEL_EMAIL_TO \
SENTINEL_EMAIL_FROM \
SENTINEL_GMAIL_USER \
SENTINEL_GMAIL_APP_PASSWORD
do
if [ -z "${!name}" ]; then
echo "::error::Secret mancante: $name"
missing=1
fi
done
if [ "$missing" -ne 0 ]; then
echo "Configura i secret Gmail prima di avviare la scansione Sentinel."
exit 1
fi
- name: Checkout
if: github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true'
uses: actions/checkout@v6
- name: Setup Node
if: github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true'
uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
- name: Install
if: github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true'
run: npm ci
- name: Test
if: github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true'
run: npm test
- name: Build
if: github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true'
run: npm run build
- name: Scan
id: scan
if: github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true'
run: |
set +e
npm run sentinel -- scan
status=$?
echo "exit_code=$status" >> "$GITHUB_OUTPUT"
exit 0
- name: Generate dashboard
if: github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true'
run: npm run sentinel -- dashboard
- name: Publish dashboard to Vercel Blob
# La dashboard live legge da Vercel Blob: senza questo step resta ferma
# anche se lo scan gira. Salta con notice se il token non e' disponibile.
if: ${{ github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true' }}
run: |
if [ -z "${BLOB_READ_WRITE_TOKEN:-}" ]; then
echo "::warning::BLOB_READ_WRITE_TOKEN assente: dashboard live non aggiornata."
exit 0
fi
npm run sentinel -- publish-dashboard
- name: Commit application outputs
if: github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
mkdir -p data snapshots reports
git add data snapshots reports
if git diff --cached --quiet; then
echo "Nessun output da committare."
exit 0
fi
git commit -m "chore: update sentinel outputs"
git push
- name: Fail on scan errors
if: github.event_name != 'schedule' || steps.schedule.outputs.should_run == 'true'
run: |
if [ "${{ steps.scan.outputs.exit_code }}" != "0" ]; then
echo "Scan conclusa con exit code ${{ steps.scan.outputs.exit_code }}."
exit 1
fi