@@ -3,6 +3,7 @@ set -euo pipefail
33
44dockerfile=" ${1:- docker/ Dockerfile.ci} "
55workflow=" ${2:- .github/ workflows/ cicd-main.yml} "
6+ fw_final_dockerfile=" ${3:- docker/ Dockerfile.fw_final} "
67
78baseline_arg_line=$( grep -n ' ^ARG BASELINE_MCORE_REF$' " $dockerfile " | cut -d: -f1)
89baseline_clone_line=$( grep -n ' git clone --filter=blob:none --no-checkout' " $dockerfile " | cut -d: -f1)
@@ -24,14 +25,23 @@ trap 'rm -rf "$temporary_dir"' EXIT
2425(( baseline_line < dispatched_copy_line))
2526(( dispatched_copy_line < delta_line))
2627
28+ fw_final_from_line=$( grep -n ' ^FROM ${NEMO_FW_FINAL_BASE_IMAGE} AS nemo_fw_final$' " $fw_final_dockerfile " | cut -d: -f1)
29+ fw_final_root_line=$( grep -n ' ^USER root$' " $fw_final_dockerfile " | cut -d: -f1)
30+ fw_final_clone_line=$( grep -n ' ^RUN git clone --depth 1 https://github.com/NVIDIA-NeMo/NeMo.git' " $fw_final_dockerfile " | cut -d: -f1)
31+ [[ -n " $fw_final_from_line " ]]
32+ [[ -n " $fw_final_root_line " ]]
33+ [[ -n " $fw_final_clone_line " ]]
34+ (( fw_final_from_line < fw_final_root_line))
35+ (( fw_final_root_line < fw_final_clone_line))
36+
2737grep -q -- ' --mount=type=cache,target=/root/.cache/uv' " $dockerfile "
2838if grep -q -- ' --mount=type=secret,id=GH_TOKEN' " $dockerfile " ; then
2939 echo " Baseline MCore clone must not require a GitHub token" >&2
3040 exit 1
3141fi
3242mcore_reinstall_line=$( grep -n ' uv pip install --no-deps --reinstall -e 3rdparty/Megatron-LM' " $dockerfile " | cut -d: -f1)
3343helper_assertion_line=$( grep -n " find 3rdparty/Megatron-LM/megatron/core/datasets -maxdepth 1 -name 'helpers_cpp\*\.so'" " $dockerfile " | cut -d: -f1)
34- final_copy_line=$( grep -n ' ^COPY --chmod=644 \. /opt/Megatron-Bridge$' " $dockerfile " | cut -d: -f1)
44+ final_copy_line=$( grep -nE ' ^COPY ( --chmod=644|--chown=1000:1000) \. /opt/Megatron-Bridge$' " $dockerfile " | cut -d: -f1)
3545[[ -n " $mcore_reinstall_line " ]]
3646[[ -n " $helper_assertion_line " ]]
3747[[ -n " $final_copy_line " ]]
@@ -52,7 +62,7 @@ if grep -q 'MCORE_REF="${{ github.event.inputs.mcore_ref }}"' "$workflow"; then
5262 echo " Dispatch inputs must enter shell steps through env" >&2
5363 exit 1
5464fi
55- test " $( grep -c ' validate_mcore_revision.sh "$MCORE_REPO" "$MCORE_REF"' " $workflow " ) " = 2
65+ test " $( grep -c ' validate_mcore_revision.sh "$MCORE_REPO" "$MCORE_REF" "$TRIGGERED_BY" ' " $workflow " ) " = 2
5666test " $( grep -c ' git fetch "$MCORE_REPO" "$MCORE_REF"' " $workflow " ) " = 2
5767test " $( grep -c ' git checkout "$MCORE_REF"' " $workflow " ) " = 2
5868test " $( grep -c ' test "$(git rev-parse HEAD)" = "$MCORE_REF"' " $workflow " ) " = 1
@@ -99,6 +109,13 @@ ancestor_sha=$(git -C "$revision_worktree" rev-parse HEAD)
99109printf ' main\n' >> " $revision_worktree /file"
100110git -C " $revision_worktree " commit -qam main
101111main_sha=$( git -C " $revision_worktree " rev-parse HEAD)
112+ git -C " $revision_worktree " switch -q -c dev
113+ printf ' dev\n' >> " $revision_worktree /file"
114+ git -C " $revision_worktree " commit -qam dev
115+ dev_ancestor_sha=$( git -C " $revision_worktree " rev-parse HEAD)
116+ printf ' dev tip\n' >> " $revision_worktree /file"
117+ git -C " $revision_worktree " commit -qam dev-tip
118+ dev_sha=$( git -C " $revision_worktree " rev-parse HEAD)
102119git -C " $revision_worktree " branch contributor " $ancestor_sha "
103120git -C " $revision_worktree " switch -q contributor
104121printf ' approved\n' >> " $revision_worktree /file"
@@ -122,6 +139,7 @@ git -C "$revision_worktree" add unapproved
122139git -C " $revision_worktree " commit -q -m unapproved
123140unapproved_sha=$( git -C " $revision_worktree " rev-parse HEAD)
124141git -C " $revision_worktree " push -q " $revision_repo " " $main_sha :refs/heads/main"
142+ git -C " $revision_worktree " push -q " $revision_repo " " $dev_sha :refs/heads/dev"
125143git -C " $revision_worktree " push -q " $revision_repo " " $mirror_sha :refs/heads/pull-request/123"
126144git -C " $revision_worktree " push -q " $revision_repo " " $merge_sha :refs/pull/123/merge"
127145git -C " $revision_worktree " push -q \
@@ -140,9 +158,69 @@ sed "s#\.github/scripts/validate_mcore_repo\.sh#$temporary_dir/revision-bin/repo
140158 " $revision_validator " > " $temporary_dir /revision-validator"
141159chmod +x " $temporary_dir /revision-validator"
142160" $temporary_dir /revision-validator" " $revision_repo " " $ancestor_sha "
161+ " $temporary_dir /revision-validator" " $revision_repo " " $dev_ancestor_sha "
162+ " $temporary_dir /revision-validator" " $revision_repo " " $dev_sha "
143163" $temporary_dir /revision-validator" " $revision_repo " " $mirror_sha "
144164" $temporary_dir /revision-validator" " $revision_repo " " $merge_sha "
145165" $temporary_dir /revision-validator" " $revision_repo " " $queue_sha "
166+ git -C " $revision_worktree " push -q \
167+ " $revision_repo " \
168+ " :refs/heads/gh-readonly-queue/main/pr-123-$main_sha "
169+ if " $temporary_dir /revision-validator" " $revision_repo " " $queue_sha " ; then
170+ echo " MCore revision validation accepted a deleted queue ref without source-run evidence" >&2
171+ exit 1
172+ fi
173+ cat > " $temporary_dir /revision-bin/gh" << 'EOF '
174+ #!/usr/bin/env bash
175+ [[ "$1" == "api" && "$2" == "repos/NVIDIA/Megatron-LM/actions/runs/$TEST_RUN_ID" ]] || exit 1
176+ printf '%s\t%s\t%s\t%s\n' \
177+ "${RUN_REPO:-NVIDIA/Megatron-LM}" \
178+ "${RUN_EVENT:-merge_group}" \
179+ "${RUN_SHA:-}" \
180+ "${RUN_BRANCH:-gh-readonly-queue/main/pr-123-0000000000000000000000000000000000000000}"
181+ EOF
182+ chmod +x " $temporary_dir /revision-bin/gh"
183+ TEST_RUN_ID=123456
184+ trigger_url=" https://github.com/NVIDIA/Megatron-LM/actions/runs/$TEST_RUN_ID "
185+ PATH=" $temporary_dir /revision-bin:$PATH " \
186+ TEST_RUN_ID=" $TEST_RUN_ID " \
187+ RUN_SHA=" $queue_sha " \
188+ RUN_BRANCH=" gh-readonly-queue/main/pr-123-$main_sha " \
189+ " $temporary_dir /revision-validator" " $revision_repo " " $queue_sha " " $trigger_url "
190+ if PATH=" $temporary_dir /revision-bin:$PATH " \
191+ TEST_RUN_ID=" $TEST_RUN_ID " \
192+ RUN_SHA=" $unapproved_sha " \
193+ RUN_BRANCH=" gh-readonly-queue/main/pr-123-$main_sha " \
194+ " $temporary_dir /revision-validator" " $revision_repo " " $queue_sha " " $trigger_url " ; then
195+ echo " MCore revision validation accepted source-run metadata for a different SHA" >&2
196+ exit 1
197+ fi
198+ if PATH=" $temporary_dir /revision-bin:$PATH " \
199+ TEST_RUN_ID=" $TEST_RUN_ID " \
200+ RUN_SHA=" $queue_sha " \
201+ RUN_BRANCH=" pull-request/123" \
202+ " $temporary_dir /revision-validator" " $revision_repo " " $queue_sha " " $trigger_url " ; then
203+ echo " MCore revision validation accepted a non-queue source run" >&2
204+ exit 1
205+ fi
206+ if PATH=" $temporary_dir /revision-bin:$PATH " \
207+ TEST_RUN_ID=" $TEST_RUN_ID " \
208+ RUN_REPO=" example/Megatron-LM" \
209+ RUN_SHA=" $queue_sha " \
210+ RUN_BRANCH=" gh-readonly-queue/main/pr-123-$main_sha " \
211+ " $temporary_dir /revision-validator" " $revision_repo " " $queue_sha " " $trigger_url " ; then
212+ echo " MCore revision validation accepted an untrusted source-run repository" >&2
213+ exit 1
214+ fi
215+ if PATH=" $temporary_dir /revision-bin:$PATH " \
216+ TEST_RUN_ID=" $TEST_RUN_ID " \
217+ RUN_EVENT=" push" \
218+ RUN_SHA=" $queue_sha " \
219+ RUN_BRANCH=" gh-readonly-queue/main/pr-123-$main_sha " \
220+ " $temporary_dir /revision-validator" " $revision_repo " " $queue_sha " " $trigger_url " ; then
221+ echo " MCore revision validation accepted a non-merge-group source run" >&2
222+ exit 1
223+ fi
146224if " $temporary_dir /revision-validator" " $revision_repo " " $queue_sha " x; then
147225 echo " MCore revision validation accepted a malformed queue SHA" >&2
148226 exit 1
@@ -164,11 +242,54 @@ if "$temporary_dir/revision-validator" "$revision_repo" not-a-full-sha; then
164242 exit 1
165243fi
166244
245+ if ! grep -A1 ' ^te = \[$' pyproject.toml | grep -Fxq ' "megatron-core[te]",' ; then
246+ echo " Bridge's TE extra must enable the selected MCore ref's TE extra" >&2
247+ exit 1
248+ fi
249+ grep -Fq ' { name = "megatron-core", extra = ["te"] }' uv.lock
250+ if grep -q ' transformer-engine @ git+https://github.com/NVIDIA/TransformerEngine.git@' pyproject.toml || \
251+ grep -q ' ^name = "transformer-engine"$' pyproject.toml; then
252+ echo " Bridge must inherit the TransformerEngine source and metadata from the selected MCore ref" >&2
253+ exit 1
254+ fi
255+
256+ lock_package_field () {
257+ local lock_file=" $1 "
258+ local package=" $2 "
259+ local field=" $3 "
260+
261+ awk -v package=" $package " -v field=" $field " '
262+ $0 == "[[package]]" { in_package = 1; package_matches = 0; next }
263+ in_package && $0 ~ /^\[\[/ { in_package = 0; package_matches = 0 }
264+ in_package && $0 == "name = \"" package "\"" { package_matches = 1; next }
265+ package_matches && index($0, field " = ") == 1 { print; exit }
266+ ' " $lock_file "
267+ }
268+
269+ mlm_te_source=$( lock_package_field 3rdparty/Megatron-LM/uv.lock transformer-engine source)
270+ bridge_te_source=$( lock_package_field uv.lock transformer-engine source)
271+ if [[ ! " $mlm_te_source " =~ ^source\ = \ \{\ git\ = \ \" https://github.com/NVIDIA/TransformerEngine\. git\? rev= [0-9a-f]{40}# [0-9a-f]{40}\"\ \}$ ]]; then
272+ echo " Selected MCore lock must pin TransformerEngine to a full source revision" > & 2
273+ exit 1
274+ fi
275+ if [[ " $bridge_te_source " != " $mlm_te_source " ]]; then
276+ echo " Bridge must lock the TransformerEngine source selected by MCore" >&2
277+ exit 1
278+ fi
279+
167280composite_action= " .github/actions/test-template/action.yml"
168281if grep -qE ' mcore_(commit|ref)|MCORE_COMMIT|uv sync --all-extras --all-groups' " $composite_action " ; then
169282 echo " Test template must use the already-validated MCore in the built image" >&2
170283 exit 1
171284fi
285+ grep -Fq ' VOLUME_ARGS="--volume ${{ inputs.test-data-path }}:/home/TestData --env HF_HUB_OFFLINE=1"' " $composite_action "
286+ grep -q ' MOUNT_FS: ${{ inputs.is_unit_test == ' \' ' false' \' ' }}' " $composite_action "
287+ grep -q ' HF_HOME=/home/TestData/HF_HOME' " $composite_action "
288+ grep -q ' NEMO_HOME=/home/TestData/nemo_home' " $composite_action "
289+ grep -q ' HF_HOME=/home/ubuntu/.cache/huggingface' " $composite_action "
290+ grep -q ' NEMO_HOME=/home/ubuntu/.cache/nemo' " $composite_action "
291+ grep -q ' HF_MODULES_CACHE=/home/ubuntu/.cache/huggingface/modules' " $composite_action "
292+ grep -q -- ' --env HF_MODULES_CACHE=\$HF_MODULES_CACHE' " $composite_action "
172293
173294# The baseline dependency layer must be structurally independent of the mutable
174295# dispatched checkout. CI validates the ordering statically so this regression
0 commit comments