|
| 1 | +#!/usr/bin/env bash |
| 2 | +set -euo pipefail |
| 3 | + |
| 4 | +dockerfile="${1:-docker/Dockerfile.ci}" |
| 5 | +workflow="${2:-.github/workflows/cicd-main.yml}" |
| 6 | + |
| 7 | +baseline_arg_line=$(grep -n '^ARG BASELINE_MCORE_REF$' "$dockerfile" | cut -d: -f1) |
| 8 | +baseline_clone_line=$(grep -n 'git clone --filter=blob:none --no-checkout' "$dockerfile" | cut -d: -f1) |
| 9 | +baseline_line=$(grep -n 'Install the main-branch environment from an immutable baseline context' "$dockerfile" | cut -d: -f1) |
| 10 | +dispatched_copy_line=$(grep -n '^COPY 3rdparty/Megatron-LM /opt/Megatron-Bridge/3rdparty/Megatron-LM$' "$dockerfile" | cut -d: -f1) |
| 11 | +delta_line=$(grep -n 'syncing the dispatched dependency delta' "$dockerfile" | cut -d: -f1) |
| 12 | +repo_validator=".github/scripts/validate_mcore_repo.sh" |
| 13 | +revision_validator=".github/scripts/validate_mcore_revision.sh" |
| 14 | +temporary_dir=$(mktemp -d) |
| 15 | +trap 'rm -rf "$temporary_dir"' EXIT |
| 16 | + |
| 17 | +[[ -n "$baseline_arg_line" ]] |
| 18 | +[[ -n "$baseline_clone_line" ]] |
| 19 | +[[ -n "$baseline_line" ]] |
| 20 | +[[ -n "$dispatched_copy_line" ]] |
| 21 | +[[ -n "$delta_line" ]] |
| 22 | +((baseline_arg_line < baseline_clone_line)) |
| 23 | +((baseline_clone_line < baseline_line)) |
| 24 | +((baseline_line < dispatched_copy_line)) |
| 25 | +((dispatched_copy_line < delta_line)) |
| 26 | + |
| 27 | +grep -q -- '--mount=type=cache,target=/root/.cache/uv' "$dockerfile" |
| 28 | +if grep -q -- '--mount=type=secret,id=GH_TOKEN' "$dockerfile"; then |
| 29 | + echo "Baseline MCore clone must not require a GitHub token" >&2 |
| 30 | + exit 1 |
| 31 | +fi |
| 32 | +mcore_reinstall_line=$(grep -n 'uv pip install --no-deps --reinstall -e 3rdparty/Megatron-LM' "$dockerfile" | cut -d: -f1) |
| 33 | +helper_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) |
| 35 | +[[ -n "$mcore_reinstall_line" ]] |
| 36 | +[[ -n "$helper_assertion_line" ]] |
| 37 | +[[ -n "$final_copy_line" ]] |
| 38 | +((delta_line < mcore_reinstall_line)) |
| 39 | +((mcore_reinstall_line < helper_assertion_line)) |
| 40 | +((helper_assertion_line < final_copy_line)) |
| 41 | +grep -q 'BASELINE_MCORE_REF=$(git -C 3rdparty/Megatron-LM rev-parse HEAD)' "$workflow" |
| 42 | +grep -q 'validate_mcore_revision.sh' "$workflow" |
| 43 | +grep -q 'BASELINE_MCORE_REF=${{ env.BASELINE_MCORE_REF }}' "$workflow" |
| 44 | +grep -q 'test "$(git -C 3rdparty/Megatron-LM rev-parse HEAD)" = "$BASELINE_MCORE_REF"' "$dockerfile" |
| 45 | +grep -q 'if \[ -n "$BASELINE_MCORE_REF" \]; then' "$dockerfile" |
| 46 | +if grep -q '^COPY 3rdparty/Megatron-LM /opt/Megatron-Bridge/baseline/' "$dockerfile"; then |
| 47 | + echo "Mutable MCore must not enter the baseline dependency layer" >&2 |
| 48 | + exit 1 |
| 49 | +fi |
| 50 | +test "$(grep -c '^ MCORE_REF: ${{ github.event.inputs.mcore_ref }}$' "$workflow")" = 3 |
| 51 | +if grep -q 'MCORE_REF="${{ github.event.inputs.mcore_ref }}"' "$workflow"; then |
| 52 | + echo "Dispatch inputs must enter shell steps through env" >&2 |
| 53 | + exit 1 |
| 54 | +fi |
| 55 | +test "$(grep -c 'validate_mcore_revision.sh "$MCORE_REPO" "$MCORE_REF"' "$workflow")" = 2 |
| 56 | +test "$(grep -c 'git fetch "$MCORE_REPO" "$MCORE_REF"' "$workflow")" = 2 |
| 57 | +test "$(grep -c 'git checkout "$MCORE_REF"' "$workflow")" = 2 |
| 58 | +test "$(grep -c 'test "$(git rev-parse HEAD)" = "$MCORE_REF"' "$workflow")" = 1 |
| 59 | + |
| 60 | +install_workflow=".github/workflows/install-test.yml" |
| 61 | +grep -q '^ MCORE_COMMIT: ${{ github.event.inputs.mcore_commit }}$' "$install_workflow" |
| 62 | +grep -q '^ MCORE_REPO: ${{ github.event.inputs.mcore_repo' "$install_workflow" |
| 63 | +grep -q 'validate_mcore_revision.sh "$MCORE_REPO" "$MCORE_COMMIT"' "$install_workflow" |
| 64 | +grep -q 'git fetch "$MCORE_REPO" "$MCORE_COMMIT"' "$install_workflow" |
| 65 | +grep -q 'git checkout "$MCORE_COMMIT"' "$install_workflow" |
| 66 | +if grep -qE '(git fetch|EXPECTED_COMMIT=).*\$\{\{ github\.event\.inputs\.mcore_(repo|commit)' "$install_workflow"; then |
| 67 | + echo "Install workflow interpolates dispatch inputs into its shell" >&2 |
| 68 | + exit 1 |
| 69 | +fi |
| 70 | + |
| 71 | +"$repo_validator" https://github.com/NVIDIA/Megatron-LM.git |
| 72 | +if "$repo_validator" https://github.com/example-contributor/Megatron-LM.git; then |
| 73 | + echo "MCore repository validation accepted an untrusted contributor fork" >&2 |
| 74 | + exit 1 |
| 75 | +fi |
| 76 | +if "$repo_validator" https://github.com/not-a-fork/Megatron-LM.git; then |
| 77 | + echo "MCore repository validation accepted an untrusted repository" >&2 |
| 78 | + exit 1 |
| 79 | +fi |
| 80 | +if "$repo_validator" 'https://github.com/example/Megatron-LM.git;touch /tmp/injected'; then |
| 81 | + echo "MCore repository validation accepted shell metacharacters" >&2 |
| 82 | + exit 1 |
| 83 | +fi |
| 84 | +if "$repo_validator" https://example.com/example/Megatron-LM.git; then |
| 85 | + echo "MCore repository validation accepted a non-GitHub host" >&2 |
| 86 | + exit 1 |
| 87 | +fi |
| 88 | + |
| 89 | +revision_repo="file://$temporary_dir/Megatron-LM.git" |
| 90 | +revision_worktree="$temporary_dir/revision-worktree" |
| 91 | +git init --bare -q "$temporary_dir/Megatron-LM.git" |
| 92 | +git init -q "$revision_worktree" |
| 93 | +git -C "$revision_worktree" config user.name test |
| 94 | +git -C "$revision_worktree" config user.email test@example.com |
| 95 | +printf 'base\n' >"$revision_worktree/file" |
| 96 | +git -C "$revision_worktree" add file |
| 97 | +git -C "$revision_worktree" commit -q -m base |
| 98 | +ancestor_sha=$(git -C "$revision_worktree" rev-parse HEAD) |
| 99 | +printf 'main\n' >>"$revision_worktree/file" |
| 100 | +git -C "$revision_worktree" commit -qam main |
| 101 | +main_sha=$(git -C "$revision_worktree" rev-parse HEAD) |
| 102 | +git -C "$revision_worktree" branch contributor "$ancestor_sha" |
| 103 | +git -C "$revision_worktree" switch -q contributor |
| 104 | +printf 'approved\n' >>"$revision_worktree/file" |
| 105 | +git -C "$revision_worktree" commit -qam approved |
| 106 | +mirror_sha=$(git -C "$revision_worktree" rev-parse HEAD) |
| 107 | +git -C "$revision_worktree" switch -q --detach "$main_sha" |
| 108 | +git -C "$revision_worktree" merge -q --no-ff -s ours "$mirror_sha" -m merge |
| 109 | +merge_sha=$(git -C "$revision_worktree" rev-parse HEAD) |
| 110 | +git -C "$revision_worktree" switch -q --detach "$main_sha" |
| 111 | +printf 'orphan\n' >"$revision_worktree/orphan" |
| 112 | +git -C "$revision_worktree" add orphan |
| 113 | +git -C "$revision_worktree" commit -q -m orphan |
| 114 | +orphan_sha=$(git -C "$revision_worktree" rev-parse HEAD) |
| 115 | +printf 'unapproved\n' >"$revision_worktree/unapproved" |
| 116 | +git -C "$revision_worktree" add unapproved |
| 117 | +git -C "$revision_worktree" commit -q -m unapproved |
| 118 | +unapproved_sha=$(git -C "$revision_worktree" rev-parse HEAD) |
| 119 | +git -C "$revision_worktree" push -q "$revision_repo" "$main_sha:refs/heads/main" |
| 120 | +git -C "$revision_worktree" push -q "$revision_repo" "$mirror_sha:refs/heads/pull-request/123" |
| 121 | +git -C "$revision_worktree" push -q "$revision_repo" "$merge_sha:refs/pull/123/merge" |
| 122 | +git -C "$revision_worktree" push -q "$revision_repo" "$orphan_sha:refs/pull/456/merge" |
| 123 | +git -C "$revision_worktree" push -q "$revision_repo" "$unapproved_sha:refs/heads/unapproved" |
| 124 | + |
| 125 | +mkdir -p "$temporary_dir/revision-bin" |
| 126 | +cat >"$temporary_dir/revision-bin/repo-validator" <<EOF |
| 127 | +#!/usr/bin/env bash |
| 128 | +[[ "\${1:-}" == "$revision_repo" ]] |
| 129 | +EOF |
| 130 | +chmod +x "$temporary_dir/revision-bin/repo-validator" |
| 131 | +sed "s#\.github/scripts/validate_mcore_repo\.sh#$temporary_dir/revision-bin/repo-validator#" \ |
| 132 | + "$revision_validator" >"$temporary_dir/revision-validator" |
| 133 | +chmod +x "$temporary_dir/revision-validator" |
| 134 | +"$temporary_dir/revision-validator" "$revision_repo" "$ancestor_sha" |
| 135 | +"$temporary_dir/revision-validator" "$revision_repo" "$mirror_sha" |
| 136 | +"$temporary_dir/revision-validator" "$revision_repo" "$merge_sha" |
| 137 | +if "$temporary_dir/revision-validator" "$revision_repo" "$orphan_sha"; then |
| 138 | + echo "MCore revision validation accepted a PR merge without an approved mirror parent" >&2 |
| 139 | + exit 1 |
| 140 | +fi |
| 141 | +if "$temporary_dir/revision-validator" "$revision_repo" "$unapproved_sha"; then |
| 142 | + echo "MCore revision validation accepted an existing commit on an unapproved ref" >&2 |
| 143 | + exit 1 |
| 144 | +fi |
| 145 | +if "$temporary_dir/revision-validator" "$revision_repo" 0000000000000000000000000000000000000000; then |
| 146 | + echo "MCore revision validation accepted a nonexistent SHA" >&2 |
| 147 | + exit 1 |
| 148 | +fi |
| 149 | +if "$temporary_dir/revision-validator" "$revision_repo" not-a-full-sha; then |
| 150 | + echo "MCore revision validation accepted a malformed SHA" >&2 |
| 151 | + exit 1 |
| 152 | +fi |
| 153 | + |
| 154 | +composite_action=".github/actions/test-template/action.yml" |
| 155 | +if grep -qE 'mcore_(commit|ref)|MCORE_COMMIT|uv sync --all-extras --all-groups' "$composite_action"; then |
| 156 | + echo "Test template must use the already-validated MCore in the built image" >&2 |
| 157 | + exit 1 |
| 158 | +fi |
| 159 | + |
| 160 | +# The baseline dependency layer must be structurally independent of the mutable |
| 161 | +# dispatched checkout. CI validates the ordering statically so this regression |
| 162 | +# check never pulls or executes an external container image. |
| 163 | +assert_baseline_precedes_dispatched_copy() { |
| 164 | + local candidate="$1" |
| 165 | + local baseline_sync_line |
| 166 | + local mutable_copy_line |
| 167 | + |
| 168 | + baseline_sync_line=$(grep -n 'uv sync --link-mode copy --locked --all-extras --all-groups --no-group diffusion' "$candidate" | head -1 | cut -d: -f1) |
| 169 | + mutable_copy_line=$(grep -n '^COPY 3rdparty/Megatron-LM /opt/Megatron-Bridge/3rdparty/Megatron-LM$' "$candidate" | head -1 | cut -d: -f1) |
| 170 | + [[ -n "$baseline_sync_line" && -n "$mutable_copy_line" ]] || return 1 |
| 171 | + ((baseline_sync_line < mutable_copy_line)) |
| 172 | +} |
| 173 | + |
| 174 | +if ! assert_baseline_precedes_dispatched_copy "$dockerfile"; then |
| 175 | + echo "Mutable MCore enters the Dockerfile before the baseline layer is complete" >&2 |
| 176 | + exit 1 |
| 177 | +fi |
| 178 | + |
| 179 | +cat >"$temporary_dir/early-copy.Dockerfile" <<'EOF' |
| 180 | +COPY 3rdparty/Megatron-LM /opt/Megatron-Bridge/3rdparty/Megatron-LM |
| 181 | +RUN uv sync --link-mode copy --locked --all-extras --all-groups --no-group diffusion |
| 182 | +EOF |
| 183 | +if assert_baseline_precedes_dispatched_copy "$temporary_dir/early-copy.Dockerfile"; then |
| 184 | + echo "Cache-order regression accepted an early mutable MCore copy" >&2 |
| 185 | + exit 1 |
| 186 | +fi |
0 commit comments