From fb2222bb21c98a2b091cffcef9de8600aac7ffcc Mon Sep 17 00:00:00 2001 From: DJ Date: Wed, 8 Apr 2026 09:45:43 -0700 Subject: [PATCH 1/2] fix(workflows): address CodeRabbit suggestions deferred from #87 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #90. 1) agent-shield-reusable.yml — SKILL.md frontmatter regex now allows optional leading whitespace (`^[[:space:]]*name:` / `^[[:space:]]*description:`), so indented YAML keys (e.g. under a `metadata:` parent) are recognised as present. Previously the strict column-zero anchor missed them. 2) dependabot-rebase-reusable.yml — fix vacuous-truth merge gate. `[].statusCheckRollup[]? | ... | all(...)` returns true on an empty list (logical convention), which made a PR with no status checks appear "all green" and trigger an auto-merge. New gate also requires at least one COMPLETED check before merging, in addition to the existing all-pass and zero-pending requirements. Also collapses the three `gh pr view` calls into one round-trip via a shared $ROLLUP. 3) dependency-audit-reusable.yml — cargo audit no longer re-runs per workspace member. The new logic finds workspace roots (Cargo.toml files containing `[workspace]`) and audits them once each, then audits standalone crates whose dir is not under any workspace root. For a workspace with N members, that's 1 audit instead of N+1. 4) dependency-audit-reusable.yml — pip-audit now audits both pyproject.toml AND requirements.txt when both exist in the same directory (some projects ship pyproject for tooling and requirements.txt for pinned runtime deps). Previously the elif branch made requirements.txt unreachable. All four were originally raised by CodeRabbit on petry-projects/.github#87 and intentionally deferred to keep that PR no-behavior-change. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/agent-shield-reusable.yml | 6 +- .../workflows/dependabot-rebase-reusable.yml | 25 +++++--- .../workflows/dependency-audit-reusable.yml | 57 +++++++++++++++++-- 3 files changed, 72 insertions(+), 16 deletions(-) diff --git a/.github/workflows/agent-shield-reusable.yml b/.github/workflows/agent-shield-reusable.yml index 86c1c99..2c1e157 100644 --- a/.github/workflows/agent-shield-reusable.yml +++ b/.github/workflows/agent-shield-reusable.yml @@ -112,11 +112,13 @@ jobs: continue fi - if ! echo "$frontmatter" | grep -q '^name:'; then + # Allow optional leading whitespace so indented YAML keys + # (e.g. under a `metadata:` parent) are recognised. + if ! echo "$frontmatter" | grep -qE '^[[:space:]]*name:'; then echo "::error file=$file::Missing 'name' field" status=1 fi - if ! echo "$frontmatter" | grep -q '^description:'; then + if ! echo "$frontmatter" | grep -qE '^[[:space:]]*description:'; then echo "::error file=$file::Missing 'description' field" status=1 fi diff --git a/.github/workflows/dependabot-rebase-reusable.yml b/.github/workflows/dependabot-rebase-reusable.yml index 83eff82..e4f4dfa 100644 --- a/.github/workflows/dependabot-rebase-reusable.yml +++ b/.github/workflows/dependabot-rebase-reusable.yml @@ -113,20 +113,29 @@ jobs: continue fi - # Check if all required checks pass (look at overall rollup) - CHECKS_PASS=$(gh pr view "$PR_NUMBER" --repo "$REPO" \ - --json statusCheckRollup \ - --jq '[.statusCheckRollup[]? | select(.name != null and .status == "COMPLETED") | .conclusion] | all(. == "SUCCESS" or . == "NEUTRAL" or . == "SKIPPED")') - - CHECKS_PENDING=$(gh pr view "$PR_NUMBER" --repo "$REPO" \ - --json statusCheckRollup \ - --jq '[.statusCheckRollup[]? | select(.name != null and .status != "COMPLETED")] | length') + # Check the status check rollup. We need: + # - at least one completed check (so an empty rollup is NOT + # vacuously "passing"), and + # - every completed check is SUCCESS / NEUTRAL / SKIPPED, and + # - zero checks still pending. + ROLLUP=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json statusCheckRollup) + CHECKS_COMPLETED=$(echo "$ROLLUP" | \ + jq '[.statusCheckRollup[]? | select(.name != null and .status == "COMPLETED")] | length') + CHECKS_PASS=$(echo "$ROLLUP" | \ + jq '[.statusCheckRollup[]? | select(.name != null and .status == "COMPLETED") | .conclusion] | all(. == "SUCCESS" or . == "NEUTRAL" or . == "SKIPPED")') + CHECKS_PENDING=$(echo "$ROLLUP" | \ + jq '[.statusCheckRollup[]? | select(.name != null and .status != "COMPLETED")] | length') if [[ "$CHECKS_PENDING" -gt 0 ]]; then echo " Skipping — $CHECKS_PENDING check(s) still pending" continue fi + if [[ "$CHECKS_COMPLETED" -eq 0 ]]; then + echo " Skipping — no completed status checks (cannot confirm safety)" + continue + fi + if [[ "$CHECKS_PASS" != "true" ]]; then echo " Skipping — some checks failed" continue diff --git a/.github/workflows/dependency-audit-reusable.yml b/.github/workflows/dependency-audit-reusable.yml index 51a0613..4e5fbe8 100644 --- a/.github/workflows/dependency-audit-reusable.yml +++ b/.github/workflows/dependency-audit-reusable.yml @@ -163,16 +163,57 @@ jobs: - name: Audit Cargo dependencies run: | - # cargo audit operates on Cargo.lock at workspace root - # For workspaces, a single audit at root covers all crates + # cargo audit operates on Cargo.lock at workspace root, so for a + # workspace a single audit at the root covers every member crate. + # Iterating every Cargo.toml would re-audit the same lockfile N + # times in workspaces. + # + # Strategy: + # 1. Find every Cargo.toml that declares [workspace] — those + # are workspace roots; emit them. + # 2. Find every Cargo.toml that does NOT declare [workspace]; + # those are either standalone crates or workspace members. + # Emit them only if no parent dir is already a workspace + # root we found in step 1. status=0 - while IFS= read -r dir; do + + mapfile -t WORKSPACES < <( + find . -name Cargo.toml -not -path '*/target/*' -print0 \ + | xargs -0 grep -l '^\[workspace\]' 2>/dev/null \ + | xargs -n1 dirname 2>/dev/null \ + | sort -u + ) + + mapfile -t NON_WORKSPACES < <( + find . -name Cargo.toml -not -path '*/target/*' -print0 \ + | xargs -0 grep -L '^\[workspace\]' 2>/dev/null \ + | xargs -n1 dirname 2>/dev/null \ + | sort -u + ) + + # Standalone crates: those whose dir is not under any workspace root + STANDALONE=() + for dir in "${NON_WORKSPACES[@]}"; do + covered=0 + for ws in "${WORKSPACES[@]}"; do + # Trim trailing slash from $ws for accurate prefix match + ws_trim="${ws%/}" + case "$dir/" in + "$ws_trim/"*) covered=1; break ;; + esac + done + if [ "$covered" -eq 0 ]; then + STANDALONE+=("$dir") + fi + done + + for dir in "${WORKSPACES[@]}" "${STANDALONE[@]}"; do echo "::group::cargo audit $dir" if ! (cd "$dir" && cargo generate-lockfile 2>/dev/null; cargo audit); then status=1 fi echo "::endgroup::" - done < <(find . -name 'Cargo.toml' -not -path '*/target/*' -exec dirname {} \; | sort -u) + done exit $status audit-pip: @@ -193,14 +234,18 @@ jobs: - name: Audit Python dependencies run: | status=0 - # Audit each Python project found in the repo + # Audit each Python project found in the repo. Some projects ship + # both pyproject.toml (tooling/build) and requirements.txt (pinned + # runtime deps) — audit BOTH when both are present rather than + # short-circuiting on pyproject.toml. while IFS= read -r dir; do echo "::group::pip-audit $dir" if [ -f "$dir/pyproject.toml" ]; then if ! pip-audit "$dir"; then status=1 fi - elif [ -f "$dir/requirements.txt" ]; then + fi + if [ -f "$dir/requirements.txt" ]; then if ! pip-audit -r "$dir/requirements.txt"; then status=1 fi From 5f457cdecb7f7f818372273ae133d95aeb66d392 Mon Sep 17 00:00:00 2001 From: DJ Date: Wed, 8 Apr 2026 09:52:18 -0700 Subject: [PATCH 2/2] fix(workflows): single space before cron comment in feature-ideation stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The canonical stub had three spaces aligning the comment after the cron expression. Repos that run prettier in their lint chain (e.g. google-app-scripts) hit a `prettier --check` failure on every fresh adoption — see petry-projects/google-app-scripts#151. Bringing the template in line with prettier defaults so future adopters don't drift. --- standards/workflows/feature-ideation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/workflows/feature-ideation.yml b/standards/workflows/feature-ideation.yml index 4807fbc..2b757a4 100644 --- a/standards/workflows/feature-ideation.yml +++ b/standards/workflows/feature-ideation.yml @@ -37,7 +37,7 @@ name: Feature Research & Ideation (BMAD Analyst) on: schedule: - - cron: '0 7 * * 5' # Friday 07:00 UTC (3 AM EDT / 2 AM EST) + - cron: '0 7 * * 5' # Friday 07:00 UTC (3 AM EDT / 2 AM EST) workflow_dispatch: inputs: focus_area: