molecule-ci/.github/workflows/validate-org-template.yml
Hongming Wang 56facc8a42 fix(validate): fetch validator scripts from molecule-ci instead of expecting them in caller
The validate-org-template.yml and validate-plugin.yml workflows
expected `.molecule-ci/scripts/` to be vendored INTO each calling
repo. That worked for the repos that copied the directory in, but
broke on the ones that didn't:

- molecule-ai-org-template-medo-smoke
- molecule-ai-org-template-molecule-worker-gemini
- molecule-ai-org-template-reno-stars
- molecule-ai-plugin-molecule-compliance
- molecule-ai-plugin-molecule-freeze-scope
- molecule-ai-plugin-molecule-prompt-watchdog

Surfaced when the secret-scan rollout PRs hit those repos and the
required validate check failed on missing
`.molecule-ci/scripts/requirements.txt`.

Mirror the same fix already in validate-workspace-template.yml: a
second `actions/checkout@v4` of molecule-ci into
`.molecule-ci-canonical/`, with script paths re-pointed accordingly.
Single source of truth — callers never need to vendor or sync.

Also adds `.molecule-ci-canonical` to the secret-scan SKIP_DIRS so
the side-checked-out tree doesn't get walked.

Callers can drop their vendored `.molecule-ci/scripts/` copies in a
follow-up cleanup. Both shapes work after this PR — the vendored
copy is harmless dead weight, not a conflict.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 01:56:25 -07:00

78 lines
3.2 KiB
YAML

name: Validate Org Template
on:
workflow_call:
jobs:
validate:
name: Org template validation
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
# Canonical validator script lives in molecule-ci, fetched fresh on
# every run. The previous setup expected `.molecule-ci/scripts/` to
# be vendored INTO each org-template repo, which drifted across the
# 5 org-template repos as the validator evolved. Single source of
# truth eliminates that drift class entirely. Mirrors the same
# pattern already used by validate-workspace-template.yml.
- uses: actions/checkout@v4
with:
repository: Molecule-AI/molecule-ci
path: .molecule-ci-canonical
- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip"
cache-dependency-path: .molecule-ci-canonical/.molecule-ci/scripts/requirements.txt
- run: pip install pyyaml -q
- run: python3 .molecule-ci-canonical/.molecule-ci/scripts/validate-org-template.py
- name: Check for secrets
run: |
python3 - << 'PYEOF'
import os, re, sys
from pathlib import Path
PATTERNS = [
re.compile(r'''["']sk-ant-[a-zA-Z0-9]{50,}["']'''),
re.compile(r'''["']ghp_[a-zA-Z0-9]{36,}["']'''),
re.compile(r'''["']AKIA[A-Z0-9]{16}["']'''),
re.compile(r'''["'][a-zA-Z0-9/+=]{40}["']'''),
re.compile(r'''["']sk_test_[a-zA-Z0-9]{24,}["']'''),
re.compile(r'''["']Bearer\s+[a-zA-Z0-9_.-]{20,}["']'''),
re.compile(r'''ghp_[a-zA-Z0-9]{36,}'''),
re.compile(r'''sk-ant-[a-zA-Z0-9]{50,}'''),
]
SKIP_DIRS = {'.molecule-ci', '.molecule-ci-canonical', '.git', 'node_modules', '__pycache__'}
EXTENSIONS = {'.yaml', '.yml', '.md', '.py', '.sh'}
def is_false_positive(line):
ctx = line.lower()
return '...' in ctx or '<example' in ctx or '</example' in ctx
root = Path(os.environ.get('GITHUB_WORKSPACE', '.'))
warnings = []
for dirpath, dirnames, filenames in os.walk(root):
dirnames[:] = [d for d in dirnames if d not in SKIP_DIRS]
for filename in filenames:
if Path(filename).suffix not in EXTENSIONS:
continue
filepath = Path(dirpath) / filename
try:
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
for lineno, line in enumerate(f.readlines(), 1):
for pattern in PATTERNS:
for match in pattern.finditer(line):
if not is_false_positive(line):
warnings.append(f" {filepath}:{lineno}: {match.group(0)[:40]}...")
except Exception:
pass
if warnings:
print("::error::Potential secret found in committed files:")
for w in warnings:
print(w)
sys.exit(1)
else:
print("::notice::No secrets detected")
PYEOF