← 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
A .github/workflows/verify-skill-drift-check.ymlM internal/cli/verify_skill_sync_test.go
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 →