1- name : Check Rendered Specs
1+ # Reusable workflow — renders specs from a PR and checks for drift.
2+ #
3+ # Called by the stub on the default branch (check-rendered-specs-stub.yml) via
4+ # pull_request_target. The stub provides the PR details; this workflow does all
5+ # the real work:
6+ # 1. Checks out base branch (trusted tools/scripts)
7+ # 2. Checks out PR head into pr-head/ (untrusted data — TOML configs, specs)
8+ # 3. Renders specs inside a privileged container using azldev -C pr-head/
9+ # 4. Checks for drift (compares rendered output against PR's committed specs)
10+ # 5. Posts a PR comment with results + downloadable fix patch
11+ #
12+ # Security: the PR checkout is data-only. We never execute code from the PR —
13+ # azldev is installed from upstream, scripts come from the base branch checkout.
14+ name : " Check Rendered Specs"
215
316on :
4- pull_request :
5- branches :
6- - tomls/base/main
17+ workflow_call :
18+ inputs :
19+ pr-head-sha :
20+ required : true
21+ type : string
22+ pr-head-repo :
23+ required : true
24+ type : string
25+ pr-number :
26+ required : true
27+ type : string
28+ repo :
29+ required : true
30+ type : string
731
832permissions : {}
933
10- concurrency :
11- group : render-check-${{ github.event.pull_request.number }}
12- cancel-in-progress : true
13-
1434jobs :
1535 check :
1636 name : Rendered specs freshness
@@ -19,11 +39,23 @@ jobs:
1939 contents : read
2040 pull-requests : write # Post/update/delete drift comments on PRs
2141 steps :
22- - name : Checkout
42+ # --- Trusted base branch (tools, scripts, container config) ---
43+ - name : Checkout base (trusted)
2344 uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2445 with :
46+ repository : ${{ inputs.repo }}
47+ ref : tomls/base/main
2548 persist-credentials : false
49+
50+ # --- PR head (untrusted data — TOML configs, overlays, specs) ---
51+ - name : Checkout PR head (data)
52+ uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
53+ with :
54+ repository : ${{ inputs.pr-head-repo }}
55+ ref : ${{ inputs.pr-head-sha }}
56+ path : pr-head
2657 fetch-depth : 0
58+ persist-credentials : false
2759
2860 - name : Set up Go
2961 uses : actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
@@ -46,13 +78,18 @@ jobs:
4678 -f .github/workflows/containers/render.Dockerfile \
4779 .github/workflows/containers/
4880
81+ # Render runs inside a privileged container because mock needs mount
82+ # namespaces. Only the PR checkout is mounted (not the full workspace) —
83+ # this prevents a malicious spec's %() macro from writing to the trusted
84+ # base checkout where our scripts live. The azldev binary is mounted
85+ # read-only from the host's GOPATH.
4986 - name : Render specs
5087 env :
5188 WORKSPACE : ${{ github.workspace }}
5289 run : |
5390 set -o pipefail
5491 docker run --privileged --rm \
55- -v "$WORKSPACE:/workdir" \
92+ -v "$WORKSPACE/pr-head :/workdir" \
5693 -v "$(go env GOPATH)/bin:/gobin:ro" \
5794 -e PATH="/gobin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
5895 azldev-render \
6299 - name : Resolve specs directory
63100 id : specs-dir
64101 run : |
65- SPECS_DIR=$(azldev config dump -q | grep 'rendered-specs-dir' | cut -d"'" -f2)
102+ SPECS_DIR=$(azldev -C pr-head config dump -q | grep 'rendered-specs-dir' | cut -d"'" -f2)
66103 echo "path=$SPECS_DIR" >> "$GITHUB_OUTPUT"
67104
68105 - name : Check for drift
@@ -71,10 +108,11 @@ jobs:
71108 env :
72109 SPECS_DIR : ${{ steps.specs-dir.outputs.path }}
73110 run : |
74- python .github/workflows/scripts/check_rendered_specs.py \
111+ cd pr-head
112+ python -I "$GITHUB_WORKSPACE/.github/workflows/scripts/check_rendered_specs.py" \
75113 --specs-dir "$SPECS_DIR" \
76- --report render-check-report.json \
77- --patch rendered-specs.patch
114+ --report "$GITHUB_WORKSPACE/ render-check-report.json" \
115+ --patch "$GITHUB_WORKSPACE/ rendered-specs.patch"
78116
79117 - name : Upload fix patch
80118 id : upload-patch
85123 archive : false
86124
87125 # Also upload as a zipped artifact so `gh run download` works.
88- # The non-zipped upload above is for browser preview/download, but
89- # `gh run download` doesn't support non-zipped artifacts yet.
90126 # See: https://github.com/cli/cli/issues/13012
91127 - name : Upload fix patch (for gh cli)
92128 if : hashFiles('rendered-specs.patch') != ''
@@ -100,14 +136,12 @@ jobs:
100136 continue-on-error : true
101137 env :
102138 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
103- PR_REPO : ${{ github.repository }}
104- PR_NUMBER : ${{ github.event.pull_request.number }}
105- SPECS_DIR : ${{ steps.specs-dir.outputs.path }}
139+ PR_REPO : ${{ inputs.repo }}
140+ PR_NUMBER : ${{ inputs.pr-number }}
106141 PATCH_URL : ${{ steps.upload-patch.outputs.artifact-url }}
107142 RUN_ID : ${{ github.run_id }}
108143 run : |
109- python .github/workflows/scripts/check_rendered_specs.py \
110- --specs-dir "$SPECS_DIR" \
144+ python -I .github/workflows/scripts/post_render_comment.py \
111145 --repo "$PR_REPO" \
112146 --pr "$PR_NUMBER" \
113147 --report render-check-report.json \
@@ -121,4 +155,3 @@ jobs:
121155 name : render-output
122156 path : |
123157 render-output.json
124- render-check-report.json
0 commit comments