Go to file
claude-ceo-assistant (Claude Opus 4.7 on Hongming's MacBook) 120b71c564 feat(actions): add audit-force-merge composite action
§SOP-6 force-merge detector, hosted as a Gitea Actions composite
action so it can be vendored into every org repo via a single
`uses:` line instead of copy-pasting the bash. Source of truth
for the audit script logic.

Why composite vs reusable workflow: Gitea 1.22.6 doesn't support
cross-repo `uses: org/repo/.gitea/workflows/X.yml@ref`. Cross-repo
reusable workflows landed in go-gitea/gitea#32562 (1.26.0, Oct 2025)
and have not been backported. Composite actions resolve via the
actions-fetch path which works cross-repo against a public callee.
Re-evaluate when operator host runs Gitea ≥ 1.26.

Consumer workflow shape:

    on:
      pull_request_target:
        types: [closed]
    jobs:
      audit:
        if: github.event.pull_request.merged == true
        runs-on: ubuntu-latest
        steps:
          - uses: molecule-ai/molecule-ci/.gitea/actions/audit-force-merge@main
            with:
              gitea-token: ${{ secrets.SOP_TIER_CHECK_TOKEN }}
              repo: ${{ github.repository }}
              pr-number: ${{ github.event.pull_request.number }}
              required-checks: |
                sop-tier-check / tier-check (pull_request)

No actions/checkout step needed in the consumer — the audit script
does pure API calls, never reads working tree. Removing checkout is
also a small security win (PR head code never loaded).

Verified end-to-end on internal#123 + molecule-core#150 with the
inline copies (which this PR will replace via consumer-side stub
PRs once merged). Tier: low.
2026-05-08 20:29:40 -07:00
.gitea/actions/audit-force-merge feat(actions): add audit-force-merge composite action 2026-05-08 20:29:40 -07:00
.github/workflows fix(ci): replace cross-repo actions/checkout with direct git clone 2026-05-07 01:37:34 -07:00
.molecule-ci/scripts fix(validate): recognize !external + !include as opaque refs (skip, not error) 2026-05-08 08:52:32 -07:00
docs docs: pin reusable-workflow examples from @main to @v1 (P133) 2026-04-30 01:04:06 -07:00
scripts ci: lock down validate-workspace-template against fork-PR untrusted code (P135) 2026-04-30 01:07:58 -07:00
.gitignore chore: remove accidentally-committed __pycache__ + gitignore Python caches (#20) 2026-04-28 12:18:46 -07:00
README.md docs: pin reusable-workflow examples from @main to @v1 (P133) 2026-04-30 01:04:06 -07:00

molecule-ci

Shared CI workflows for the Molecule AI ecosystem. Every plugin, workspace template, and org template repo calls these reusable workflows to enforce a standard validation gate.

Usage

Plugin repos (molecule-ai-plugin-*)

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  validate:
    uses: Molecule-AI/molecule-ci/.github/workflows/validate-plugin.yml@v1

Workspace template repos (molecule-ai-workspace-template-*)

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  validate:
    uses: Molecule-AI/molecule-ci/.github/workflows/validate-workspace-template.yml@v1

Org template repos (molecule-ai-org-template-*)

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  validate:
    uses: Molecule-AI/molecule-ci/.github/workflows/validate-org-template.yml@v1

Any repo with auto-merge enabled

PR-time guards (currently: disable auto-merge on follow-up push). Consume from a thin caller:

# .github/workflows/pr-guards.yml
name: pr-guards
on:
  pull_request:
    types: [synchronize]
permissions:
  pull-requests: write
jobs:
  disable-auto-merge-on-push:
    uses: Molecule-AI/molecule-ci/.github/workflows/disable-auto-merge-on-push.yml@v1

When the team lands more PR-time guards in this repo, add them as additional jobs in the same caller — keeps each consuming repo's footprint to one file.

What each workflow validates

validate-plugin

Check Severity What it catches
plugin.yaml exists Error Missing manifest
Required fields (name, version, description) Error Incomplete plugin
Has content (SKILL.md, hooks/, skills/, or rules/) Error Empty plugin
SKILL.md starts with heading Warning Bad formatting
No committed secrets Error Leaked API keys
No build artifacts Error node_modules, pycache

validate-workspace-template

Check Severity What it catches
config.yaml exists Error Missing config
Required fields (name, runtime) Error Incomplete template
template_schema_version: 1 Error Missing version contract
Known runtime check Warning Typo in runtime name
adapter.py imports molecule_runtime Warning Legacy imports
Dockerfile builds Error Broken image
molecule-ai-workspace-runtime dependency Warning Missing base package
No committed secrets Error Leaked API keys

validate-org-template

Check Severity What it catches
org.yaml exists Error Missing org definition
Required fields (name) Error Incomplete template
Workspace structure valid Error Malformed hierarchy
files_dir references exist Warning Broken system-prompt paths
template_schema_version present Warning Missing version contract
No committed secrets Error Leaked API keys

disable-auto-merge-on-push

PR-time safety guard. When pull_request:synchronize fires (= a new commit pushed to an open PR) and auto-merge is already enabled, this workflow disables auto-merge and posts a comment requiring the operator to re-engage explicitly.

Why it exists: on 2026-04-27, molecule-core PR #2174 auto-merged with only its first commit because the second commit was pushed AFTER the merge queue had locked the PR's SHA. The second commit ended up orphaned on a merged-and-deleted branch.

Pairs with the org-wide repo setting "Automatically delete head branches" (already enabled on all 10 Molecule-AI repos). Defense in depth:

  1. Repo setting blocks pushes to a merged-and-deleted branch (catches the post-merge orphan case).
  2. This workflow catches the in-queue race (push during queue processing) by force-disabling auto-merge.

Together they cover the full lifecycle of "auto-merge enabled → new commits arrive" without operator discipline.

False-positive note: if a CI bot pushes (dependency update, secret rotation), this also disables auto-merge. That's intentional — the operator who originally enabled auto-merge gets notified and re-engages, which is exactly the verify-after-machine-edits behavior we want.

License

Business Source License 1.1 — © Molecule AI.