@@ -81,25 +81,28 @@ jobs:
8181
8282 - name : Run Semantic Analysis (Sandboxed)
8383 uses : geomys/sandboxed-step@v1.2.0
84- # FIX: 'env' must be a sibling to 'with', not a child.
85- # This injects the vars into the process environment where the sandbox can see them.
86- env :
87- MODE : ${{ steps.mode.outputs.mode }}
88- WORKTREE_DIR : ${{ steps.prep.outputs.worktree_dir }}
89- HAS_GO : ${{ steps.prep.outputs.has_go_files }}
9084 with :
9185 disable-network : ' true'
92- # Assuming 'run' is a valid input parameter for geomys/sandboxed-step.
93- # If this action does not support a 'run' input, you must use 'entrypoint'.
86+ # CONTEXT INJECTION:
87+ # We inject vars via interpolation. We write to a local artifact
88+ # instead of trying to hit the runner's step summary directly.
9489 run : |
90+ export MODE="${{ steps.mode.outputs.mode }}"
91+ export WORKTREE_DIR="${{ steps.prep.outputs.worktree_dir }}"
92+ export HAS_GO="${{ steps.prep.outputs.has_go_files }}"
93+
94+ # Strict mode enabled after exports
9595 set -euo pipefail
9696
97- echo "## Semantic Analysis Report ($MODE)" >> $GITHUB_STEP_SUMMARY
98- echo "| File | Status | Match % |" >> $GITHUB_STEP_SUMMARY
99- echo "| :--- | :--- | :--- |" >> $GITHUB_STEP_SUMMARY
97+ # Define local report artifact (Safe Write)
98+ REPORT_FILE="scan_report.md"
99+
100+ echo "## Semantic Analysis Report ($MODE)" >> "$REPORT_FILE"
101+ echo "| File | Status | Match % |" >> "$REPORT_FILE"
102+ echo "| :--- | :--- | :--- |" >> "$REPORT_FILE"
100103
101104 if [ "$HAS_GO" != "true" ]; then
102- echo "No Go files changed." >> $GITHUB_STEP_SUMMARY
105+ echo "No Go files changed." >> "$REPORT_FILE"
103106 exit 0
104107 fi
105108
@@ -113,18 +116,15 @@ jobs:
113116 LOGIC_FAIL=0
114117
115118 # Process the pre-calculated diff stream
116- # The structure matches 'git diff -z --name-status' output
117119 while IFS= read -r -d '' status; do
118120 case "$status" in
119121 R*|C*)
120- # Rename or Copy: consumes two paths (old, new)
121122 IFS= read -r -d '' old_path
122123 IFS= read -r -d '' new_path
123124 OLD_FILE_REF="$old_path"
124125 NEW_FILE_REF="$new_path"
125126 ;;
126127 *)
127- # Modify/Add/Delete: consumes one path
128128 IFS= read -r -d '' path
129129 OLD_FILE_REF="$path"
130130 NEW_FILE_REF="$path"
@@ -133,36 +133,30 @@ jobs:
133133
134134 if [[ "$NEW_FILE_REF" != *.go ]] && [[ "$OLD_FILE_REF" != *.go ]]; then continue; fi
135135
136- # Resolve New File (HEAD)
137136 if [ -f "$NEW_FILE_REF" ]; then
138137 NEW_FILE="$NEW_FILE_REF"
139138 else
140139 NEW_FILE=""
141140 fi
142141
143- # Resolve Old File (Base Worktree)
144142 OLD_FILE="$WORKTREE_DIR/$OLD_FILE_REF"
145143 if [ ! -f "$OLD_FILE" ]; then
146144 OLD_FILE=""
147145 fi
148146
149- # Skip if both are missing
150147 if [[ -z "$NEW_FILE" ]] && [[ -z "$OLD_FILE" ]]; then continue; fi
151148
152- # Handle Additions (New File)
153149 if [[ -z "$OLD_FILE" ]]; then
154- echo "| \`$NEW_FILE_REF\` | New File | N/A |" >> $GITHUB_STEP_SUMMARY
150+ echo "| \`$NEW_FILE_REF\` | New File | N/A |" >> "$REPORT_FILE"
155151 continue
156152 fi
157153
158- # Handle Deletions
159154 if [[ -z "$NEW_FILE" ]]; then
160- echo "| \`$OLD_FILE_REF\` | Deleted | N/A |" >> $GITHUB_STEP_SUMMARY
155+ echo "| \`$OLD_FILE_REF\` | Deleted | N/A |" >> "$REPORT_FILE"
161156 continue
162157 fi
163158
164- # Execute SFW using the local binary built in the previous step
165- # We use '|| true' to capture exit codes without crashing the script (due to set -e)
159+ # Execute SFW
166160 if ! OUTPUT=$(./bin/sfw diff "$OLD_FILE" "$NEW_FILE"); then
167161 echo "::error::sfw failed to process $NEW_FILE_REF"
168162 ERROR_COUNT=$((ERROR_COUNT + 1))
@@ -176,40 +170,47 @@ jobs:
176170 continue
177171 fi
178172
179- # Parse Results using jq (replaces 'bc' dependency)
173+ # Parse Results
180174 PCT=$(echo "$OUTPUT" | jq -r '.summary.semantic_match_pct // 0')
181175 MODIFIED=$(echo "$OUTPUT" | jq -r '.summary.modified // 0')
182-
183- # Logic check using jq to avoid floating point issues in shell
184176 IS_BELOW_100=$(echo "$OUTPUT" | jq -r 'if (.summary.semantic_match_pct // 0) < 100 then "true" else "false" end')
185177
186178 if [ "$IS_BELOW_100" = "true" ]; then
187179 STATUS_ICON="Modified ($MODIFIED)"
188- echo "| \`$NEW_FILE_REF\` | $STATUS_ICON | **$PCT%** |" >> $GITHUB_STEP_SUMMARY
180+ echo "| \`$NEW_FILE_REF\` | $STATUS_ICON | **$PCT%** |" >> "$REPORT_FILE"
189181
190182 if [ "$MODE" == "BLOCKER" ]; then
191183 echo "::error file=$NEW_FILE_REF::Logic change detected in safe refactor! ($PCT%)"
192184 LOGIC_FAIL=1
193185 fi
194186 else
195187 STATUS_ICON="Preserved"
196- echo "| \`$NEW_FILE_REF\` | $STATUS_ICON | **$PCT%** |" >> $GITHUB_STEP_SUMMARY
188+ echo "| \`$NEW_FILE_REF\` | $STATUS_ICON | **$PCT%** |" >> "$REPORT_FILE"
197189 fi
198190
199191 done < diff_stream.bin
200192
201193 if [ $ERROR_COUNT -gt 0 ]; then
202- echo "" >> $GITHUB_STEP_SUMMARY
203- echo "**CI FAILED**: Tool execution failures detected." >> $GITHUB_STEP_SUMMARY
194+ echo "" >> "$REPORT_FILE"
195+ echo "**CI FAILED**: Tool execution failures detected." >> "$REPORT_FILE"
204196 exit 1
205197 fi
206198
207199 if [ $LOGIC_FAIL -eq 1 ]; then
208- echo "" >> $GITHUB_STEP_SUMMARY
209- echo "**CI FAILED**: Logic changed in 'semantic-safe' PR." >> $GITHUB_STEP_SUMMARY
200+ echo "" >> "$REPORT_FILE"
201+ echo "**CI FAILED**: Logic changed in 'semantic-safe' PR." >> "$REPORT_FILE"
210202 exit 1
211203 fi
212204
205+ - name : Publish Analysis Report
206+ if : always()
207+ # This runs on the host, so it has access to GITHUB_STEP_SUMMARY.
208+ # It reads the artifact produced by the sandbox.
209+ run : |
210+ if [ -f "scan_report.md" ]; then
211+ cat scan_report.md >> $GITHUB_STEP_SUMMARY
212+ fi
213+
213214 - name : Cleanup Worktree
214215 if : always()
215216 env :
0 commit comments