Files
molecule-core/.gitea/workflows/lint-required-context-exists-in-bp.yml
T
hongming-personalandClaude Opus 4.8 6042ce539c ci(secrets->kms): molecule-core fetches CI bot tokens from Infisical (consolidated)
Replace direct Gitea-Actions-secret bot-token consumption with the proven
#971/#3274 INFISICAL_CI KMS-fetch pattern. Each consumer job gains a
"Fetch <CRED> from Infisical SSOT" step (INFISICAL_CI universal-auth login ->
read_secret GET /api/v3/secrets/raw/<KEY> environment=prod -> null-safe
extractor -> [ -z ] fail-closed -> ::add-mask:: -> export to $GITHUB_ENV),
then the consumer switches secrets.<OLD> -> env.<CRED_KEY>, exported under the
env-var NAME the workflow/script already expects so scripts are unchanged.

CI_STATUS_TOKEN (prod /shared/ci-status) replaces:
  - STATUS_POST_TOKEN  in qa-review.yml (POST status step)
  - STATUS_POST_TOKEN  in security-review.yml (POST status step)
  - STATUS_POST_TOKEN  in reserved-path-review.yml (POST status step)
  - STATUS_POST_TOKEN  in sop-checklist.yml (qa + security refire steps)
  - STATUS_REAPER_TOKEN in status-reaper.yml (compensation POST)

DRIFT_BOT_TOKEN (prod /shared/drift-bot) replaces:
  - DRIFT_BOT_TOKEN in ci-required-drift.yml
  - DRIFT_BOT_TOKEN in lint-continue-on-error-tracking.yml
  - DRIFT_BOT_TOKEN in lint-required-no-paths.yml
  - DRIFT_BOT_TOKEN in lint-no-coe-on-required.yml
  - DRIFT_BOT_TOKEN in lint-bp-context-emit-match.yml
  - DRIFT_BOT_TOKEN in lint-required-context-exists-in-bp.yml

test_gate_review_auto_fire.py: the four assertions that pinned
secrets.STATUS_POST_TOKEN now assert env.CI_STATUS_TOKEN (qa/security POST
steps + qa/security refire steps).

validate-before-delete: the old Gitea Actions secrets (STATUS_POST_TOKEN,
STATUS_REAPER_TOKEN, DRIFT_BOT_TOKEN) are intentionally LEFT IN PLACE. Delete
them only after a green run proves the Infisical fetch path works. Both
consolidated Infisical secrets already exist in prod (verified non-empty).
Bootstrap INFISICAL_CI_* and the auto-injected GITEA_TOKEN/GITHUB_TOKEN are
untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 22:14:05 -07:00

159 lines
7.4 KiB
YAML

name: lint-required-context-exists-in-bp
# Tier 2g hard-gate lint (per mc#1982) — diff-based PR-time
# check. When a PR adds a NEW commit-status emission (workflow YAML
# `name:` + job `name:`-or-key + on:-event), the workflow file must
# carry one of three directives adjacent to the new job:
#
# - `# bp-required: yes` — and BP must list the context
# - `# bp-required: pending #NNN` — acknowledged asymmetry + tracker
# - `# bp-exempt: <reason>` — informational job, not a gate
#
# Default (no directive on a new emitter) = FAIL.
#
# Why this exists
# ---------------
# PR#656 added `CI / all-required (pull_request)` as a sentinel
# context that workflows emit, but BP did NOT list it. When
# platform-build failed, all-required failed, but BP let the PR
# merge anyway → cascade to mc#1982. With this lint, PR#656 would
# have been blocked until either the BP PATCH ran alongside OR
# the author added a `bp-required: pending` directive.
#
# Tier 2g vs Tier 2f
# ------------------
# Tier 2g runs at PR-time (diff-based) and BLOCKS the merge.
# Tier 2f runs daily (scheduled) and FILES a drift issue. They
# share the workflow-context enumeration helpers
# (`_event_map`, `workflow_contexts`, `_job_display`) but the
# semantics are intentionally distinct so they're separate scripts.
# Co-design is documented in mc#1982.
#
# Directive comment lives in the workflow file (NOT PR body)
# ----------------------------------------------------------
# A PR-body claim of "BP exempt" evaporates on merge — the
# asymmetry returns to undetected state and Tier 2f's daily
# scheduled audit can't see it. The directive must live with the
# emitter so both PR-time (Tier 2g) and post-merge (Tier 2f)
# readers consume the same source.
#
# Phase contract (RFC internal#219 §1 ladder)
# -------------------------------------------
# Lands at `continue-on-error: true` (Phase 3 — surface the
# pattern without blocking PRs while the directive convention
# beds in). After 7 days of clean runs on `main` with no false
# positives, follow-up flips to `false`. Tracking: mc#1982.
#
# Cross-links
# -----------
# - mc#1982 (the RFC that specs this lint)
# - PR#656 (the empirical case)
# - mc#1982 (the surfaced cascade)
# - feedback_phantom_required_check_after_gitea_migration (Tier 2f cousin)
# - feedback_behavior_based_ast_gates
#
# Auth: DRIFT_BOT_TOKEN (repo-admin for branch_protections read).
on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- '.gitea/workflows/**'
- '.gitea/scripts/lint_required_context_exists_in_bp.py'
- '.gitea/workflows/lint-required-context-exists-in-bp.yml'
- 'tests/test_lint_required_context_exists_in_bp.py'
env:
GITHUB_SERVER_URL: https://git.moleculesai.app
permissions:
contents: read
concurrency:
group: lint-required-context-exists-in-bp-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
# bp-exempt: this lint is a PR-time advisory and is not intended to
# be a required gate on main. The directive eat-our-own-dogfood
# confirms the convention works on the lint that defines it.
lint:
name: lint-required-context-exists-in-bp
runs-on: ubuntu-latest
timeout-minutes: 5
# Phase 4 (RFC #219 §1): 22 days green since 2026-05-11 port,
# well past the 7-clean-day threshold. PR-time failure is now
# a hard CI signal.
continue-on-error: false
steps:
- name: Check out PR head with full history (need base SHA blobs)
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
# `git show <base-sha>:<path>` needs the base SHA's blobs.
# Same rationale as PR#673 and check-migration-collisions.yml.
fetch-depth: 0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: '3.12'
- name: Install PyYAML
run: python -m pip install --quiet 'PyYAML==6.0.2'
- name: Ensure base ref is reachable locally
# Cheap insurance against runner-version drift.
run: |
git fetch origin "${{ github.event.pull_request.base.ref }}" || true
# KMS consolidation (#971/#3274 pattern): the lint below previously read
# the per-bot Gitea Actions secret `DRIFT_BOT_TOKEN`. We now fetch the
# consolidated DRIFT_BOT_TOKEN from the Infisical SSOT (prod
# /shared/drift-bot) via the CI machine identity and export it to
# $GITHUB_ENV. The lint keeps reading it under the GITEA_TOKEN env var
# name it already expects, so the script is unchanged. The old
# DRIFT_BOT_TOKEN Gitea secret is left in place until a green run
# validates this path (validate-before-delete).
#
# Trust boundary: molecule-core PRs are same-repo (not forks), so the
# INFISICAL_CI_* machine-identity secrets are present on pull_request —
# the same assumption the prior direct DRIFT_BOT_TOKEN consumption made.
- name: Fetch DRIFT_BOT_TOKEN from Infisical SSOT
env:
INFISICAL_CI_CLIENT_ID: ${{ secrets.INFISICAL_CI_CLIENT_ID }}
INFISICAL_CI_CLIENT_SECRET: ${{ secrets.INFISICAL_CI_CLIENT_SECRET }}
INFISICAL_PROJECT_ID: ${{ secrets.INFISICAL_CI_PROJECT_ID }}
run: |
set -uo pipefail
BASE="https://key.moleculesai.app"
TOK=$(curl -fsS -X POST "$BASE/api/v1/auth/universal-auth/login" \
-H 'Content-Type: application/json' \
-d "{\"clientId\":\"$INFISICAL_CI_CLIENT_ID\",\"clientSecret\":\"$INFISICAL_CI_CLIENT_SECRET\"}" \
| python3 -c 'import sys,json; v=json.load(sys.stdin).get("accessToken"); sys.stdout.write(v if isinstance(v,str) else "")')
if [ -z "$TOK" ]; then echo "::error::Infisical accessToken empty - failing closed"; exit 1; fi
read_secret() {
curl -fsS "$BASE/api/v3/secrets/raw/$1?workspaceId=$INFISICAL_PROJECT_ID&environment=prod&secretPath=$2" \
-H "Authorization: Bearer $TOK" \
| python3 -c 'import sys,json; v=json.load(sys.stdin).get("secret",{}).get("secretValue"); sys.stdout.write(v if isinstance(v,str) else "")'
}
DRIFT_BOT_TOKEN=$(read_secret DRIFT_BOT_TOKEN %2Fshared%2Fdrift-bot)
echo "::add-mask::$DRIFT_BOT_TOKEN"
if [ -z "$DRIFT_BOT_TOKEN" ]; then
echo "::error::Infisical returned empty DRIFT_BOT_TOKEN at prod /shared/drift-bot — failing closed."
exit 1
fi
echo "DRIFT_BOT_TOKEN=$DRIFT_BOT_TOKEN" >> "$GITHUB_ENV"
echo "DRIFT_BOT_TOKEN loaded from Infisical (len=${#DRIFT_BOT_TOKEN})"
- name: Run lint-required-context-exists-in-bp
env:
# DRIFT_BOT_TOKEN — repo-admin (needed for branch_protections).
# KMS consolidation: now arrives via $GITHUB_ENV from the fetch step
# above (was secrets.DRIFT_BOT_TOKEN).
GITEA_TOKEN: ${{ env.DRIFT_BOT_TOKEN }}
GITEA_HOST: git.moleculesai.app
REPO: ${{ github.repository }}
BRANCH: main
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
WORKFLOWS_DIR: .gitea/workflows
run: python3 .gitea/scripts/lint_required_context_exists_in_bp.py
- name: Run lint-required-context-exists-in-bp unit tests
run: |
python -m pip install --quiet pytest
python3 -m pytest tests/test_lint_required_context_exists_in_bp.py -v