forked from molecule-ai/molecule-core
The checkout uses fetch-depth=2, which works for push events (only need HEAD^1). But for pull_request events the diff base is github.event.pull_request.base.sha — the tip of the target branch — which can be many commits behind and therefore absent from the shallow clone, producing: fatal: bad object <sha> (exit 128) Fix: add an explicit `git fetch --depth=1 origin <base-sha>` step that runs only on pull_request events, keeping push events fast. Unblocks: PR #1996 (and any other PR targeting a fast-moving staging). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
108 lines
4.3 KiB
YAML
108 lines
4.3 KiB
YAML
name: Block internal-flavored paths
|
|
|
|
# Hard CI gate. Internal content (positioning, competitive briefs, sales
|
|
# playbooks, PMM/press drip, draft campaigns) lives in Molecule-AI/internal —
|
|
# this public monorepo must never re-acquire those paths. CEO directive
|
|
# 2026-04-23 after a fleet-wide audit found 79 internal files leaked here.
|
|
#
|
|
# Failure mode without this gate: agents (PMM, Research, DevRel, Sales) drop
|
|
# briefs into the easiest path their cwd resolves to (root /research,
|
|
# /marketing, /docs/marketing) and gitignore alone won't catch a `git add -f`
|
|
# or a stale gitignore line. This workflow is the mechanical backstop.
|
|
|
|
on:
|
|
pull_request:
|
|
types: [opened, synchronize, reopened]
|
|
push:
|
|
branches: [main, staging]
|
|
# Required for GitHub merge queue: the queue's pre-merge CI run on
|
|
# `gh-readonly-queue/...` refs needs this check to fire so the queue
|
|
# gets a real result instead of stalling forever AWAITING_CHECKS.
|
|
merge_group:
|
|
types: [checks_requested]
|
|
|
|
jobs:
|
|
check:
|
|
name: Block forbidden paths
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 2 # need previous commit to diff against on push events
|
|
|
|
# For pull_request events the diff base is github.event.pull_request.base.sha,
|
|
# which may be many commits behind HEAD and therefore absent from the
|
|
# shallow clone above. Fetch it explicitly (depth=1 keeps it fast).
|
|
- name: Fetch PR base SHA (pull_request events only)
|
|
if: github.event_name == 'pull_request'
|
|
run: git fetch --depth=1 origin ${{ github.event.pull_request.base.sha }}
|
|
|
|
- name: Refuse if forbidden paths appear
|
|
run: |
|
|
# Paths that must NEVER live in the public monorepo. Add to this
|
|
# list narrowly — broader patterns belong in .gitignore so day-to-day
|
|
# docs work isn't accidentally blocked.
|
|
FORBIDDEN_PATTERNS=(
|
|
"^research/"
|
|
"^marketing/"
|
|
"^docs/marketing/"
|
|
"^comment-[0-9]+\.json$"
|
|
"^test-pmm.*\.(txt|md)$"
|
|
"^tick-reflections.*\.(txt|md)$"
|
|
".*-temp\.(md|txt)$"
|
|
)
|
|
|
|
# Determine the diff base.
|
|
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
|
BASE="${{ github.event.pull_request.base.sha }}"
|
|
HEAD="${{ github.event.pull_request.head.sha }}"
|
|
else
|
|
BASE="${{ github.event.before }}"
|
|
HEAD="${{ github.event.after }}"
|
|
fi
|
|
|
|
# Files added or modified in this change.
|
|
if [ -z "$BASE" ] || echo "$BASE" | grep -qE '^0+$'; then
|
|
# New branch / no previous SHA — check entire tree.
|
|
CHANGED=$(git ls-tree -r --name-only HEAD)
|
|
else
|
|
CHANGED=$(git diff --name-only --diff-filter=AM "$BASE" "$HEAD")
|
|
fi
|
|
|
|
if [ -z "$CHANGED" ]; then
|
|
echo "No changed files to inspect."
|
|
exit 0
|
|
fi
|
|
|
|
OFFENDING=""
|
|
for path in $CHANGED; do
|
|
for pattern in "${FORBIDDEN_PATTERNS[@]}"; do
|
|
if echo "$path" | grep -qE "$pattern"; then
|
|
OFFENDING="${OFFENDING}${path} (matched: ${pattern})\n"
|
|
break
|
|
fi
|
|
done
|
|
done
|
|
|
|
if [ -n "$OFFENDING" ]; then
|
|
echo "::error::Forbidden internal-flavored paths detected:"
|
|
printf "$OFFENDING"
|
|
echo ""
|
|
echo "These paths belong in Molecule-AI/internal, not this public repo."
|
|
echo "See docs/internal-content-policy.md for canonical locations."
|
|
echo ""
|
|
echo "If your file is genuinely public-facing (e.g. a blog post"
|
|
echo "ready to ship), use one of these alternatives instead:"
|
|
echo " • Public-bound blog posts: docs/blog/<slug>.md"
|
|
echo " • Public-bound tutorials: docs/tutorials/<slug>.md"
|
|
echo " • Public devrel content: docs/devrel/<slug>.md"
|
|
echo ""
|
|
echo "If you legitimately need to add a new top-level path that"
|
|
echo "happens to match a forbidden pattern, edit"
|
|
echo ".github/workflows/block-internal-paths.yml and update the"
|
|
echo "FORBIDDEN_PATTERNS list with reviewer signoff."
|
|
exit 1
|
|
fi
|
|
|
|
echo "✓ No forbidden paths in this change."
|