[object Object]

← back to Cli Printing Press

feat(ci): add verify-skill drift check (#766)

1af0f275a4cc20026e29c8e3d18563759d3764d7 · 2026-05-08 17:57:57 -0700 · Trevin Chow

Files touched

Diff

commit 1af0f275a4cc20026e29c8e3d18563759d3764d7
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Fri May 8 17:57:57 2026 -0700

    feat(ci): add verify-skill drift check (#766)
---
 .github/workflows/verify-skill-drift-check.yml | 90 ++++++++++++++++++++++++++
 internal/cli/verify_skill_sync_test.go         | 44 +++++++++++++
 2 files changed, 134 insertions(+)

diff --git a/.github/workflows/verify-skill-drift-check.yml b/.github/workflows/verify-skill-drift-check.yml
new file mode 100644
index 00000000..3ce5a700
--- /dev/null
+++ b/.github/workflows/verify-skill-drift-check.yml
@@ -0,0 +1,90 @@
+name: Verify Skill Drift
+
+on:
+  schedule:
+    - cron: '23 12 * * *'
+  workflow_dispatch:
+  push:
+    branches: [main]
+    paths:
+      - 'scripts/verify-skill/verify_skill.py'
+      - '.github/workflows/verify-skill-drift-check.yml'
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+permissions:
+  contents: read
+  issues: write
+
+jobs:
+  compare-library-copy:
+    runs-on: ubuntu-latest
+    timeout-minutes: 5
+    env:
+      LIBRARY_VERIFY_SKILL_URL: https://raw.githubusercontent.com/mvanhorn/printing-press-library/main/.github/scripts/verify-skill/verify_skill.py
+      GH_TOKEN: ${{ github.token }}
+    steps:
+      - uses: actions/checkout@v6
+
+      - name: Compare verify-skill scripts
+        shell: bash
+        run: |
+          set -euo pipefail
+
+          local_script="scripts/verify-skill/verify_skill.py"
+          library_script="${RUNNER_TEMP:-/tmp}/library-verify_skill.py"
+
+          curl -fsSL --retry 3 --retry-delay 2 "$LIBRARY_VERIFY_SKILL_URL" -o "$library_script"
+
+          local_hash="$(sha256sum "$local_script" | awk '{print $1}')"
+          library_hash="$(sha256sum "$library_script" | awk '{print $1}')"
+
+          {
+            echo "### verify-skill drift check"
+            echo
+            echo "- Printing Press canonical: \`$local_hash\`"
+            echo "- printing-press-library copy: \`$library_hash\`"
+          } >> "$GITHUB_STEP_SUMMARY"
+
+          if ! cmp -s "$local_script" "$library_script"; then
+            cat <<'EOF' >> "$GITHUB_STEP_SUMMARY"
+
+          The canonical verify-skill script and the printing-press-library CI copy have drifted.
+
+          From a workspace containing sibling checkouts of both repositories, update the library copy with:
+
+          ```bash
+          cp scripts/verify-skill/verify_skill.py ../printing-press-library/.github/scripts/verify-skill/verify_skill.py
+          ```
+          EOF
+
+            issue_title="verify-skill drift detected with printing-press-library"
+            existing_issue="$(gh issue list --state open --search "$issue_title in:title" --json number --jq '.[0].number // empty')"
+            if [[ -z "$existing_issue" ]]; then
+              issue_body="${RUNNER_TEMP:-/tmp}/verify-skill-drift-issue.md"
+              cat > "$issue_body" <<EOF
+          The canonical verify-skill script in cli-printing-press no longer matches the printing-press-library CI copy.
+
+          - Printing Press canonical: \`$local_hash\`
+          - printing-press-library copy: \`$library_hash\`
+          - Library source: $LIBRARY_VERIFY_SKILL_URL
+
+          From a workspace containing sibling checkouts of both repositories, update the library copy with:
+
+          \`\`\`bash
+          cp scripts/verify-skill/verify_skill.py ../printing-press-library/.github/scripts/verify-skill/verify_skill.py
+          \`\`\`
+          EOF
+
+              gh issue create --title "$issue_title" --body-file "$issue_body"
+            else
+              echo "Existing open drift issue: #$existing_issue" >> "$GITHUB_STEP_SUMMARY"
+            fi
+
+            echo "::error::verify-skill drift detected between cli-printing-press and printing-press-library"
+            exit 1
+          fi
+
+          echo "verify-skill scripts are in sync."
diff --git a/internal/cli/verify_skill_sync_test.go b/internal/cli/verify_skill_sync_test.go
index e7bfb658..e8810fb1 100644
--- a/internal/cli/verify_skill_sync_test.go
+++ b/internal/cli/verify_skill_sync_test.go
@@ -8,7 +8,10 @@ import (
 	"os"
 	"path/filepath"
 	"runtime"
+	"strings"
 	"testing"
+
+	"gopkg.in/yaml.v3"
 )
 
 // TestVerifySkillScriptInSync ensures the script embedded into the binary
@@ -64,6 +67,47 @@ func TestVerifySkillScriptInSync(t *testing.T) {
 	}
 }
 
+func TestVerifySkillDriftWorkflowGuardsLibraryCopy(t *testing.T) {
+	t.Parallel()
+
+	repoRoot := findRepoRoot(t)
+	workflowPath := filepath.Join(repoRoot, ".github", "workflows", "verify-skill-drift-check.yml")
+	data, err := os.ReadFile(workflowPath)
+	if err != nil {
+		t.Fatalf("read verify-skill drift workflow %s: %v", workflowPath, err)
+	}
+
+	var workflow map[string]any
+	if err := yaml.Unmarshal(data, &workflow); err != nil {
+		t.Fatalf("parse verify-skill drift workflow YAML: %v", err)
+	}
+
+	content := string(data)
+	required := []string{
+		"name: Verify Skill Drift",
+		"schedule:",
+		"cron:",
+		"push:",
+		"branches: [main]",
+		"scripts/verify-skill/verify_skill.py",
+		".github/workflows/verify-skill-drift-check.yml",
+		"issues: write",
+		"https://raw.githubusercontent.com/mvanhorn/printing-press-library/main/.github/scripts/verify-skill/verify_skill.py",
+		"GH_TOKEN: ${{ github.token }}",
+		"sha256sum",
+		"cmp -s",
+		"gh issue list",
+		"gh issue create",
+		"exit 1",
+		"cp scripts/verify-skill/verify_skill.py ../printing-press-library/.github/scripts/verify-skill/verify_skill.py",
+	}
+	for _, want := range required {
+		if !strings.Contains(content, want) {
+			t.Fatalf("verify-skill drift workflow should contain %q", want)
+		}
+	}
+}
+
 // findRepoRoot walks up from the test file's location until it finds go.mod.
 // This is more robust than relying on PWD or runtime.Caller alone, because
 // `go test ./...` runs each package from its own directory.

← 172c6c29 fix(cli): close redfin retro verification gaps (#762)  ·  back to Cli Printing Press  ·  chore(main): release 4.1.0 (#729) a5b57248 →