diff --git a/.markdownlint.yaml b/.markdownlint.yaml index fe072ce..25d6b1a 100644 --- a/.markdownlint.yaml +++ b/.markdownlint.yaml @@ -10,3 +10,6 @@ MD036: false # Compact table style is allowed MD060: false + +# Unordered list style (dash vs asterisk) is flexible +MD004: false diff --git a/scripts/ci-health-check.sh b/scripts/ci-health-check.sh new file mode 100755 index 0000000..7fbbab3 --- /dev/null +++ b/scripts/ci-health-check.sh @@ -0,0 +1,106 @@ +#!/bin/bash +# CI Health Check Script +# Checks CI health across all privilegedescalation repos and reports failures + +set -euo pipefail + +# Configuration +ORG="privilegedescalation" +MAX_AGE_DAYS=30 +CRITICAL_THRESHOLD=3 # Number of consecutive failures to consider critical + +# Colors for output +RED='\033[0;31m' +YELLOW='\033[1;33m' +GREEN='\033[0;32m' +NC='\033[0m' # No Color + +# Repos to monitor +REPOS=( + "org" + "infra" + "headlamp-sealed-secrets-plugin" + "headlamp-rook-plugin" + "headlamp-intel-gpu-plugin" + "headlamp-kube-vip-plugin" + "headlamp-tns-csi-plugin" + "headlamp-argocd-plugin" + "headlamp-polaris-plugin" +) + +echo "=== CI Health Check for $ORG ===" +echo "Generated: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" +echo "" + +# Track issues +FAILURES=() +STALE_REPOS=() +NO_CI_REPOS=() + +for repo in "${REPOS[@]}"; do + echo "Checking $repo..." + + # Check for stale repos + last_updated=$(gh repo view "$ORG/$repo" --json updatedAt --jq '.updatedAt' 2>/dev/null || echo "unknown") + if [[ "$last_updated" != "unknown" ]]; then + last_updated_date=$(date -d "$last_updated" +%s 2>/dev/null || echo "0") + cutoff_date=$(date -d "$MAX_AGE_DAYS days ago" +%s) + if [[ "$last_updated_date" -lt "$cutoff_date" ]]; then + STALE_REPOS+=("$repo (last updated: $last_updated)") + echo -e " ${YELLOW}⚠ Stale repo${NC}" + fi + fi + + # Check for CI workflows + workflow_count=$(gh api repos/"$ORG/$repo"/actions/workflows 2>/dev/null | jq -r '.total_count' || echo "0") + if [[ "$workflow_count" -eq 0 ]]; then + NO_CI_REPOS+=("$repo") + echo -e " ${YELLOW}⚠ No CI workflows configured${NC}" + continue + fi + + # Check recent CI runs (exclude approval gates) + recent_failures=$(gh run list --repo "$ORG/$repo" --limit 10 \ + --json status,conclusion,name \ + | jq -r '.[] | select(.conclusion == "failure") | select(.name | contains("CI") or contains("E2E") or contains("ci") or contains("e2e")) | .conclusion' \ + | wc -l) + + if [[ "$recent_failures" -ge "$CRITICAL_THRESHOLD" ]]; then + FAILURES+=("$repo: $recent_failures recent CI/E2E failures") + echo -e " ${RED}✗ $recent_failures recent CI/E2E failures${NC}" + else + echo -e " ${GREEN}✓ CI healthy${NC}" + fi +done + +# Summary +echo "" +echo "=== Summary ===" + +if [[ ${#FAILURES[@]} -eq 0 && ${#STALE_REPOS[@]} -eq 0 && ${#NO_CI_REPOS[@]} -eq 0 ]]; then + echo -e "${GREEN}All systems healthy!${NC}" + exit 0 +else + if [[ ${#FAILURES[@]} -gt 0 ]]; then + echo -e "${RED}CI Failures:${NC}" + for failure in "${FAILURES[@]}"; do + echo " - $failure" + done + fi + + if [[ ${#STALE_REPOS[@]} -gt 0 ]]; then + echo -e "${YELLOW}Stale Repos (no updates in $MAX_AGE_DAYS+ days):${NC}" + for stale in "${STALE_REPOS[@]}"; do + echo " - $stale" + done + fi + + if [[ ${#NO_CI_REPOS[@]} -gt 0 ]]; then + echo -e "${YELLOW}Repos without CI:${NC}" + for no_ci in "${NO_CI_REPOS[@]}"; do + echo " - $no_ci" + done + fi + + exit 1 +fi diff --git a/skills/safety/SKILL.md b/skills/safety/SKILL.md index 9c9e954..0897072 100644 --- a/skills/safety/SKILL.md +++ b/skills/safety/SKILL.md @@ -2,7 +2,8 @@ name: safety description: > Non-negotiable safety rules for all agents at Privileged Escalation. Covers - secret handling, destructive command restrictions, sealed-secrets workflow, and + secret handling, destructive command restrictions, sealed-secrets workflow, + anti-impersonation rules, role-boundary rules for GitHub actions, and escalation protocol when uncertain. --- @@ -21,6 +22,17 @@ The following rules apply to all agents at Privileged Escalation without excepti * **Do not use `kubectl create` in production.** The `privilegedescalation` namespace is Flux-managed. Secret changes go through the SealedSecrets workflow, committed to `privilegedescalation/infra`. +* **Never impersonate another agent or human.** Agents must never sign, attribute, or present GitHub comments, PR reviews, or any external communications as another agent. Every comment must accurately identify the authoring agent. Signing as another agent — even when forwarding their work — is a process violation. + +* **Post GitHub comments only within your defined SDLC role.** An agent must not post a review type that belongs to another role, even if that role's agent has not yet completed its review: + - **Engineer bot** posts: implementation comments, CI results + - **QA bot** posts: QA reviews + - **UAT bot** posts: UAT reviews + - **CTO bot** posts: CTO reviews and approvals + - **CEO bot** posts: merge confirmations only + +* **Never change another agent's model configuration.** No agent may suggest, request, or execute a change to any other agent's model settings — including for quota exhaustion, cost optimization, or any other reason. Quota issues must be escalated to the board. This is a non-negotiable board directive. + ## If you are unsure If you are unsure whether an action is safe, stop. Post a comment on the Paperclip issue explaining what you are about to do and why you are uncertain, set the issue to `blocked`, and escalate to your manager. Do not guess.