name: Heartbeat
on:
schedule:
# Run daily at 6 AM UTC
- cron: '0 6 * * *'
workflow_dispatch:
inputs:
task:
description: 'Task to run'
required: false
default: 'security-scan'
type: choice
options:
- security-scan
- branch-reap
- full-audit
jobs:
heartbeat:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout git-steer
uses: actions/checkout@v4
- name: Generate token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.GIT_STEER_APP_ID }}
private-key: ${{ secrets.GIT_STEER_PRIVATE_KEY }}
owner: ry-ops
- name: Get managed repos
id: repos
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
# Fetch managed repos from git-steer-state
REPOS=$(gh api repos/ry-ops/git-steer-state/contents/config/managed-repos.yaml \
--jq '.content' | base64 -d | grep -E '^\s+-\s+' | sed 's/.*- //' || echo "")
if [ -z "$REPOS" ]; then
# Fall back to installation repos
REPOS=$(gh api /installation/repositories --jq '.repositories[].full_name')
fi
echo "repos<<EOF" >> $GITHUB_OUTPUT
echo "$REPOS" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Security scan
if: inputs.task == 'security-scan' || inputs.task == '' || inputs.task == 'full-audit'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
echo "## Security Scan Results"
echo ""
TOTAL_ALERTS=0
REPOS_WITH_ALERTS=0
while IFS= read -r repo; do
[ -z "$repo" ] && continue
ALERTS=$(gh api "repos/$repo/dependabot/alerts" --jq '[.[] | select(.state == "open")] | length' 2>/dev/null || echo "0")
if [ "$ALERTS" -gt 0 ]; then
echo "- **$repo**: $ALERTS open alerts"
TOTAL_ALERTS=$((TOTAL_ALERTS + ALERTS))
REPOS_WITH_ALERTS=$((REPOS_WITH_ALERTS + 1))
# Show critical/high
CRITICAL=$(gh api "repos/$repo/dependabot/alerts" \
--jq '[.[] | select(.state == "open" and .security_advisory.severity == "critical")] | length' 2>/dev/null || echo "0")
HIGH=$(gh api "repos/$repo/dependabot/alerts" \
--jq '[.[] | select(.state == "open" and .security_advisory.severity == "high")] | length' 2>/dev/null || echo "0")
if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then
echo " - Critical: $CRITICAL, High: $HIGH"
fi
fi
done <<< "${{ steps.repos.outputs.repos }}"
echo ""
echo "**Summary:** $TOTAL_ALERTS alerts across $REPOS_WITH_ALERTS repos"
# Store results for potential notification
echo "total_alerts=$TOTAL_ALERTS" >> $GITHUB_OUTPUT
echo "repos_with_alerts=$REPOS_WITH_ALERTS" >> $GITHUB_OUTPUT
- name: Log heartbeat to state
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
ENTRY="{\"timestamp\":\"$TIMESTAMP\",\"task\":\"${{ inputs.task || 'scheduled' }}\",\"status\":\"completed\"}"
echo "Heartbeat completed at $TIMESTAMP"