fix(ci): move bp-directive into lint window (#2186 follow-up) #2210

Closed
core-be wants to merge 3 commits from fix/2185-bp-directive-window into feat/2185-manifest-entry-existence-check
@@ -0,0 +1,82 @@
name: manifest-entry-existence-check
# Gitea Actions port of the manual "GET /api/v1/repos/<name> for each
# manifest entry" audit that the engineer-b identity ran on 2026-06-04 to
# fix #2183 (main-red on 0b91c18031 — publish-workspace-server-image
# failed at the Pre-clone manifest deps step because manifest.json
# referenced 2 non-existent repos: free-beats-all + medo-smoke).
#
# The bug class is "latent 404 in manifest.json only surfaces on the
# next push to main, which is too late". This workflow moves the check
# to PR-review time so the bad entry never reaches main.
#
# Trigger: only on PRs that modify manifest.json. The `paths:` filter
# keeps the workflow out of the PR-CI test matrix for every other PR.
#
# Auth: anonymous Gitea API. Per the 2026-05-08 OSS-surface contract
# (commit 15935143c8d2 _comment), every entry in manifest.json is
# public on git.moleculesai.app. No new secrets required.
#
# Failure surface: each broken entry is named in an ::error:: annotation
# so the PR author sees exactly which line to fix. Mirrors the
# `Pre-clone manifest deps` step's per-entry error format in
# publish-workspace-server-image.yml.
#
# NOT a required status check today. Open design question tracked in
# #2185 — making it required is a CTO ruling (admin-only branch-protection
# config). Watchdog + post-merge RCA is the current backstop.
on:
pull_request:
paths:
- manifest.json
permissions:
contents: read
jobs:
# Design question: whether this should be a hard required check.
# The PR-time emit is asymmetric until the CTO rules. Tracking: #2185.
# bp-required: pending #2185 — do NOT flip to yes until BP lists the context.
check-entries:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Verify each manifest entry resolves on Gitea
run: |
set -euo pipefail
# Strip JSON5 // comments first to match the publish workflow's
# `Pre-clone manifest deps` parsing path — Integration Tester
# appends `// Triggered by ...` which breaks `jq` otherwise.
sed '/^[[:space:]]*\/\//d' manifest.json > /tmp/manifest.json
# Anonymous API is enough: per the 2026-05-08 OSS-surface contract
# (15935143c8d2 _comment), every entry is public on Gitea.
count=$(jq -r '(.plugins + .workspace_templates + .org_templates) | length' /tmp/manifest.json)
echo "Checking $count manifest entries against Gitea..."
missing=()
for i in $(seq 0 $((count-1))); do
name=$(jq -r "(.plugins + .workspace_templates + .org_templates)[$i].name" /tmp/manifest.json)
repo=$(jq -r "(.plugins + .workspace_templates + .org_templates)[$i].repo" /tmp/manifest.json)
for attempt in 1 2 3; do
http_code=$(curl -s -o /dev/null -w "%{http_code}" "https://git.moleculesai.app/api/v1/repos/${repo}")
if [ "$http_code" = "200" ]; then
echo " OK $name -> $repo"
break
elif [ "$http_code" = "404" ]; then
echo "::error::manifest entry '$name' points at '$repo' which does not exist on Gitea (404)"
missing+=("$name:$repo")
break
else
echo " attempt $attempt: $name -> $repo returned HTTP $http_code, retrying in $((attempt * 2))s"
sleep $((attempt * 2))
fi
done
done
if [ "${#missing[@]}" -gt 0 ]; then
echo "::error::${#missing[@]} manifest entries are broken:"
printf ' - %s\n' "${missing[@]}"
exit 1
fi
echo "All $count manifest entries resolve on Gitea."