Skip to content

Commit e3800f6

Browse files
authored
fix(code-placeholders): reject arithmetic comparisons and heredoc operands (#8760)
* fix(code-placeholders): harden shell placeholder interpolation in arithmetic contexts * fix(code-placeholders): keep integer attributes across re-declaration and unset -f, guard shell values against subscript expansions * fix(code-placeholders): end assignment-value scope at the word, carry attributes into heredoc bodies * fix(code-placeholders): treat a declaration as pending inside its own command's expansions * fix(code-placeholders): narrow arithmetic guards and preserve literal data * fix(code-placeholders): skip continued newlines before comparison operands * fix(code-placeholders): preserve command scope across process substitutions
1 parent b6861b3 commit e3800f6

4 files changed

Lines changed: 512 additions & 139 deletions

File tree

‎.github/workflows/checks.yml‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,22 @@ jobs:
614614
- name: Install ripgrep
615615
run: command -v rg || (sudo apt-get update && sudo apt-get install -y ripgrep)
616616

617+
- name: Verify shell placeholder compilation in Bash
618+
if: matrix.shard == 1
619+
working-directory: apps/sim
620+
env:
621+
SHELL_PLACEHOLDERS_REPORT_PATH: ${{ runner.temp }}/shell-placeholders.json
622+
run: bun scripts/test-shell-placeholders-e2e.ts
623+
624+
- name: Upload shell placeholder execution report
625+
if: failure() && matrix.shard == 1
626+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
627+
with:
628+
name: shell-placeholders
629+
path: ${{ runner.temp }}/shell-placeholders.json
630+
if-no-files-found: warn
631+
retention-days: 7
632+
617633
- name: Run tests
618634
env:
619635
NODE_OPTIONS: '--no-warnings --max-old-space-size=8192'

‎apps/sim/lib/execution/code-placeholders/shared.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,12 +327,12 @@ export function createOffsetRangeLookup(
327327
* The placeholders lying wholly inside `[start, end]`. Occurrences are ordered and never
328328
* overlap, so the matches are one contiguous run found by bisection.
329329
*/
330-
export function occurrencesWithin(
331-
occurrences: readonly CodePlaceholderOccurrence[],
330+
export function occurrencesWithin<T extends Pick<CodePlaceholderOccurrence, 'start' | 'end'>>(
331+
occurrences: readonly T[],
332332
start: number,
333333
end: number
334-
): CodePlaceholderOccurrence[] {
335-
const matches: CodePlaceholderOccurrence[] = []
334+
): T[] {
335+
const matches: T[] = []
336336
for (
337337
let index = partitionPoint(occurrences, (occurrence) => occurrence.start < start);
338338
index < occurrences.length && occurrences[index].end <= end;

0 commit comments

Comments
 (0)