Skip to content

NO-ISSUE: Add tofu plan and validate workflows for pull requests#132

Open
rccrdpccl wants to merge 1 commit into
osac-project:mainfrom
rccrdpccl:ci/plan-on-prs
Open

NO-ISSUE: Add tofu plan and validate workflows for pull requests#132
rccrdpccl wants to merge 1 commit into
osac-project:mainfrom
rccrdpccl:ci/plan-on-prs

Conversation

@rccrdpccl

@rccrdpccl rccrdpccl commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Split into two workflows:

  • validate.yaml: runs on pull_request (no secrets needed), does tofu init -backend=false + tofu validate for immediate feedback on syntax/config errors. Here a potential attacker could technically download a new tofu binary but with no access to the secrets, the risk should be minimal

  • plan.yaml: runs on pull_request_target with a required "plan" environment gate, so a maintainer must approve before secrets (AWS creds, GitHub App token) are exposed to the PR's code. Posts the plan output as a PR comment.

The environment gate mitigates the Pwn Request risk inherent in pull_request_target + checkout PR head: external data sources and provider binaries execute during plan, so untrusted code must not run without human review of the diff.

Assisted-by: Claude Code noreply@anthropic.com

Summary by CodeRabbit

  • New Features
    • Added pull request OpenTofu/Terraform validation and planning for Terraform/CSV changes.
    • Automated plan comments on pull requests with expandable output and updates on subsequent runs.
  • Bug Fixes
    • Improved plan outcome handling so “no changes” and “changes” don’t fail the workflow, while real failures do.
  • Chores
    • Pinned GitHub Actions to specific commit SHAs and adjusted GitHub App token configuration for apply.
    • Updated required CI status checks to remove obsolete checks.

@rccrdpccl rccrdpccl requested review from eliorerz and larsks July 15, 2026 10:05
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds OpenTofu validation and planning workflows for Terraform and CSV pull request changes, including detailed plan reporting through pull request comments. Existing workflows pin actions to commits, and three repositories remove obsolete required status checks.

Changes

Terraform/OpenTofu CI and repository policy

Layer / File(s) Summary
Plan workflow orchestration
.github/workflows/plan.yaml
Triggers planning for relevant pull request changes, configures permissions and concurrency, authenticates access, checks out the PR head, and runs OpenTofu initialization and validation.
Plan result handling
.github/workflows/plan.yaml
Runs tofu plan -detailed-exitcode, captures output and exit status, and fails only for planning errors.
Pull request plan reporting
.github/workflows/plan.yaml
Escapes and truncates plan output, then creates or updates a marked pull request comment.
Validation and CI hardening
.github/workflows/validate.yaml, .github/workflows/apply.yaml, .github/workflows/pre-commit.yaml
Adds backend-disabled OpenTofu validation, moves the apply workflow client ID to job environment configuration, and pins existing GitHub Actions to commit SHAs.
Required status-check policy
repositories.tf
Removes obsolete Prow checks from three repository configurations, retaining the end-to-end status check.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PullRequest
  participant GitHubActions
  participant OpenTofu
  participant AWS
  participant GitHubAPI
  PullRequest->>GitHubActions: trigger plan workflow
  GitHubActions->>OpenTofu: initialize, validate, and plan
  OpenTofu->>AWS: access authenticated infrastructure data
  AWS-->>OpenTofu: return infrastructure data
  GitHubActions->>GitHubAPI: create or update plan comment
Loading

Possibly related PRs

Suggested reviewers: larsks, eliorerz


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error plan.yaml tees raw tofu plan output to logs and posts the unredacted output to a PR comment; that can expose secrets/PII/customer data. Redact sensitive sections before teeing/commenting, or post only a summary and keep full plan output in a restricted artifact.
✅ Passed checks (10 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change by adding OpenTofu plan and validate workflows for pull requests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No-Hardcoded-Secrets ✅ Passed No hardcoded secrets found; AWS/App credentials are sourced from GitHub secrets, and the only literal credential-like value is a non-secret GitHub App client ID.
No-Weak-Crypto ✅ Passed No MD5/SHA1/DES/RC4/3DES/Blowfish/ECB or custom crypto was added; exact weak-crypto searches over changed files returned no matches.
No-Injection-Vectors ✅ Passed No prohibited injection patterns found; plan output is HTML-escaped before comment posting, and no eval/exec/yaml.load/sql or shell-injection changes were introduced.
Container-Privileges ✅ Passed No container/K8s manifests were changed, and the touched files contain no privileged/root/host* settings.
Ai-Attribution ✅ Passed HEAD commit includes the required Assisted-by: Claude Code trailer, and no Co-Authored-By markers were found in the commit or changed files.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

coderabbitai[bot]
coderabbitai Bot previously requested changes Jul 15, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/plan.yaml:
- Line 29: Pin every third-party action to an immutable full commit SHA instead
of a mutable tag: update actions/checkout at .github/workflows/plan.yaml lines
29-29, actions/create-github-app-token at lines 35-35, opentofu/setup-opentofu
at lines 42-42, and actions/github-script at lines 67-67, preserving each
action’s existing version.
- Around line 3-4: Replace the credentialed pull_request_target workflow trigger
with a pull_request-based flow for untrusted PR execution, and ensure checkout
and OpenTofu planning use the repository’s trusted ref rather than the PR head.
Keep AWS credentials and the GitHub App token out of all jobs that execute
attacker-controlled code, including the referenced environment approval and
planning steps.

In @.github/workflows/validate.yaml:
- Around line 3-7: Add a workflow-level concurrency configuration to the
validation workflow, using a pull-request-scoped group and setting
cancel-in-progress to true so superseded runs are cancelled while separate pull
requests remain isolated.
- Around line 19-24: Replace the mutable version tags in the workflow steps
using actions/checkout and opentofu/setup-opentofu with full immutable commit
SHAs corresponding to the intended v7 and v2 releases, respectively. Preserve
the existing action configuration, including tofu_wrapper: false.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 830ec18b-26af-4a90-8fef-de61cf36174e

📥 Commits

Reviewing files that changed from the base of the PR and between 568e268 and 2cbb365.

📒 Files selected for processing (2)
  • .github/workflows/plan.yaml
  • .github/workflows/validate.yaml

Comment thread .github/workflows/plan.yaml
Comment thread .github/workflows/plan.yaml Outdated
Comment thread .github/workflows/validate.yaml
Comment thread .github/workflows/validate.yaml Outdated
@rccrdpccl rccrdpccl changed the title Add tofu plan and validate workflows for pull requests NO-ISSUE: Add tofu plan and validate workflows for pull requests Jul 15, 2026
@rccrdpccl rccrdpccl dismissed coderabbitai[bot]’s stale review July 15, 2026 10:35

addressed all concerns

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/apply.yaml:
- Line 41: Replace the hardcoded client ID in the workflow’s client-id
configuration with the established environment-variable reference used by
workflows such as plan.yaml, preserving the existing authentication behavior and
variable naming convention.

In @.github/workflows/plan.yaml:
- Around line 84-93: Review the plan output handling in the workflow’s
plan-comment generation and ensure sensitive Terraform values cannot be
published verbatim in the PR comment. Audit the providers and resources used by
this repository’s Terraform configuration for correctly marked sensitive
attributes, and add or apply redaction before the `<pre>` content is constructed
for any values not protected by provider schemas.
- Around line 28-31: Update the “Checkout PR” actions/checkout step to disable
credential persistence by setting persist-credentials to false, ensuring the
checkout token is not retained before OpenTofu execution; leave the existing ref
unchanged.
- Around line 33-39: Update the “Generate a token” step using
actions/create-github-app-token so it scopes the installation token to the
specific repository required by this job via repositories, rather than relying
only on owner. Add the minimum required permission, including
permission-contents: read, and preserve the existing client-id and private-key
inputs.
- Around line 100-105: Update the comment lookup around listComments to use
github.paginate with the existing issues.listComments request, so all pages of
comments are retrieved before searching. Keep the existing marker-based
comments.find logic and ensure it operates on the complete paginated result.

In @.github/workflows/validate.yaml:
- Line 23: Set persist-credentials to false on each actions/checkout step in
.github/workflows/validate.yaml (23-23), .github/workflows/apply.yaml (36-36),
and .github/workflows/pre-commit.yaml (16-16); no other checkout behavior should
change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 9bedb393-5288-4282-bd35-0fff3c4e4ec3

📥 Commits

Reviewing files that changed from the base of the PR and between 2cbb365 and 577851f.

📒 Files selected for processing (5)
  • .github/workflows/apply.yaml
  • .github/workflows/plan.yaml
  • .github/workflows/pre-commit.yaml
  • .github/workflows/validate.yaml
  • repositories.tf
💤 Files with no reviewable changes (1)
  • repositories.tf

Comment thread .github/workflows/apply.yaml Outdated
Comment thread .github/workflows/plan.yaml
Comment on lines +33 to +39
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3
with:
client-id: ${{ env.CONFIG_APP_CLIENT_ID }}
private-key: ${{ secrets.CONFIG_APP_SECRET }}
owner: ${{ github.repository_owner }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== workflow excerpt ==\n'
nl -ba .github/workflows/plan.yaml | sed -n '1,140p'

printf '\n== usages of generate-token / CONFIG_APP ==\n'
rg -n "generate-token|CONFIG_APP|create-github-app-token|permission-contents|repositories:" .github/workflows . -g '!**/node_modules/**' || true

Repository: osac-project/github-config

Length of output: 228


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== workflow excerpt ==\n'
python3 - <<'PY'
from pathlib import Path
p = Path('.github/workflows/plan.yaml')
for i, line in enumerate(p.read_text().splitlines(), 1):
    if 1 <= i <= 140:
        print(f"{i:4d}: {line}")
PY

printf '\n== relevant occurrences ==\n'
rg -n "generate-token|CONFIG_APP|create-github-app-token|permission-contents|repositories:" .github/workflows . -g '!**/node_modules/**' || true

Repository: osac-project/github-config

Length of output: 5767


🌐 Web query:

actions/create-github-app-token v3 repositories owner permissions input documentation

💡 Result:

The actions/create-github-app-token action (version 3) uses the owner, repositories, and permission-prefixed inputs to control the scope and capabilities of the generated installation access token [1][2][3]. Owner and Repository Scoping - owner: Specifies the organization or user account where the GitHub App is installed [3][4]. If left empty, it defaults to the current repository owner [1][3]. - repositories: A comma or newline-separated list of repository names [1][2]. If owner is provided but repositories is empty, the token is scoped to all repositories in that owner's installation [1][3]. If both owner and repositories are empty, the token is scoped only to the current repository [1][3]. Repository names can include the owner (e.g., owner/repo1) [1][2]. Permission Inputs - The action supports granular control via inputs prefixed with permission- (e.g., permission-pull-requests, permission-contents) [3][4]. - By default, if no specific permissions are provided, the generated token inherits all permissions currently granted to the GitHub App installation [1][2][3]. - It is recommended to explicitly list only the permissions required for your specific use case, following GitHub's principle of least privilege for GITHUB_TOKEN [1][3]. - Note: If you request a permission via an input that the GitHub App installation does not actually possess, the action will fail with an error [3][4]. Installation permissions are managed at the account level; if the app requests new permissions after installation, an administrator must approve them before they are available to the action [1][2][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('.github/workflows/plan.yaml')
for i, line in enumerate(p.read_text().splitlines(), 1):
    if 25 <= i <= 50:
        print(f"{i:4d}: {line}")
PY

printf '\n== file names ==\n'
git ls-files '.github/workflows/*'

Repository: osac-project/github-config

Length of output: 1291


Scope the GitHub App token to the repo(s) this job actually needs. owner alone widens the installation token to every repository the app can access; add repositories and request only the minimum permissions, e.g. permission-contents: read, to reduce the blast radius if later steps expose the token.

🧰 Tools
🪛 zizmor (1.26.1)

[error] 39-39: dangerous use of GitHub App tokens (github-app): token granted access to all repositories for this owner's app installation

(github-app)


[error] 35-35: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions

(github-app)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/plan.yaml around lines 33 - 39, Update the “Generate a
token” step using actions/create-github-app-token so it scopes the installation
token to the specific repository required by this job via repositories, rather
than relying only on owner. Add the minimum required permission, including
permission-contents: read, and preserve the existing client-id and private-key
inputs.

Sources: Path instructions, Linters/SAST tools

Comment on lines +84 to +93
const marker = '<!-- tofu-plan -->';
const body = [
marker,
`### OpenTofu Plan`,
'',
summary,
'',
'<details><summary>Show plan output</summary>',
'',
`<pre>${plan.substring(0, 60000)}</pre>`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔵 Trivial

Full plan output is posted to a public-ish PR comment verbatim.

HTML-escaping protects rendering, but it doesn't redact attribute values — that relies entirely on the underlying provider schemas marking fields sensitive. Worth double-checking that all providers/resources touched by this repo's .tf correctly mark sensitive attributes, since anything unmarked will land in the PR comment as plaintext.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/plan.yaml around lines 84 - 93, Review the plan output
handling in the workflow’s plan-comment generation and ensure sensitive
Terraform values cannot be published verbatim in the PR comment. Audit the
providers and resources used by this repository’s Terraform configuration for
correctly marked sensitive attributes, and add or apply redaction before the
`<pre>` content is constructed for any values not protected by provider schemas.

Source: Path instructions

Comment thread .github/workflows/plan.yaml Outdated
TF_CLI_ARGS: "-no-color"
TF_IN_AUTOMATION: "true"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify action versions and the pinned commit SHA.

echo "Latest actions/checkout release:"
gh api repos/actions/checkout/releases --jq '.[0].tag_name'

echo "Latest actions/setup-python release:"
gh api repos/actions/setup-python/releases --jq '.[0].tag_name'

echo "Checking if the pinned SHA exists in actions/checkout:"
gh api repos/actions/checkout/commits/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 --jq '"Found commit authored by: " + .commit.author.name' || echo "Error: Commit not found in actions/checkout!"

Repository: osac-project/github-config

Length of output: 340


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== validate.yaml ==\n'
sed -n '1,120p' .github/workflows/validate.yaml

printf '\n== apply.yaml ==\n'
sed -n '1,140p' .github/workflows/apply.yaml

printf '\n== pre-commit.yaml ==\n'
sed -n '1,120p' .github/workflows/pre-commit.yaml

Repository: osac-project/github-config

Length of output: 4154


Disable persist-credentials on checkout. actions/checkout writes the workflow token into git config by default; these three jobs don't need that access, so set persist-credentials: false on each step in .github/workflows/validate.yaml, .github/workflows/apply.yaml, and .github/workflows/pre-commit.yaml.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 23-23: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

📍 Affects 3 files
  • .github/workflows/validate.yaml#L23-L23 (this comment)
  • .github/workflows/apply.yaml#L36-L36
  • .github/workflows/pre-commit.yaml#L16-L16
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/validate.yaml at line 23, Set persist-credentials to false
on each actions/checkout step in .github/workflows/validate.yaml (23-23),
.github/workflows/apply.yaml (36-36), and .github/workflows/pre-commit.yaml
(16-16); no other checkout behavior should change.

Sources: Path instructions, Linters/SAST tools

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
.github/workflows/plan.yaml (1)

34-41: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

App token still inherits all installation permissions.

repositories: github-config narrows the token to this repo (fix applied from earlier review), but no permission-* input is set, so the token still carries every permission the app installation has been granted for this repo (per actions/create-github-app-token docs: "By default, the token inherits all of the installation's permissions... We recommend to explicitly list the permissions that are required"). Since this step only needs the token for tofu plan, add e.g. permission-contents: read to cap the blast radius if the token is ever exposed.

🔒 Proposed fix
       - name: Generate a token
         id: generate-token
         uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1  # v3
         with:
           client-id: ${{ env.CONFIG_APP_CLIENT_ID }}
           private-key: ${{ secrets.CONFIG_APP_SECRET }}
           owner: ${{ github.repository_owner }}
           repositories: github-config
+          permission-contents: read

As per path instructions, "Least privilege: minimize GITHUB_TOKEN permissions." This is the still-open half of a previously flagged concern (the repositories scoping was addressed, permission scoping wasn't).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/plan.yaml around lines 34 - 41, Restrict the token created
by the generate-token step to the permissions required by tofu plan by adding an
explicit read-only contents permission input, such as permission-contents: read,
alongside the existing repository scope. Do not broaden the token or change the
client, owner, or repository settings.

Sources: Path instructions, Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/apply.yaml:
- Around line 40-46: Update the “Generate a token” step using
actions/create-github-app-token to set its repositories input to the current
repository, matching the least-privilege configuration in plan.yaml while
preserving the existing owner and credential inputs.

In @.github/workflows/plan.yaml:
- Around line 1-123: Add a Terraform-focused SAST/SCA validation step to the
plan job before TF init and any tofu plan execution, using an approved scanner
such as tfsec, checkov, or tflint. Configure it to analyze the checked-out
Terraform changes and fail the workflow on detected violations, ensuring
untrusted PR infrastructure is scanned before credentials are used.

---

Duplicate comments:
In @.github/workflows/plan.yaml:
- Around line 34-41: Restrict the token created by the generate-token step to
the permissions required by tofu plan by adding an explicit read-only contents
permission input, such as permission-contents: read, alongside the existing
repository scope. Do not broaden the token or change the client, owner, or
repository settings.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: c833bd07-df59-44ca-a06c-6f5e6a8fbc4a

📥 Commits

Reviewing files that changed from the base of the PR and between 577851f and de9ff84.

📒 Files selected for processing (5)
  • .github/workflows/apply.yaml
  • .github/workflows/plan.yaml
  • .github/workflows/pre-commit.yaml
  • .github/workflows/validate.yaml
  • repositories.tf
💤 Files with no reviewable changes (1)
  • repositories.tf

Comment on lines 40 to 46
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@v3
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3
with:
client-id: Iv23lipEOAvwk5QqNUie
client-id: ${{ env.CONFIG_APP_CLIENT_ID }}
private-key: ${{ secrets.CONFIG_APP_SECRET }}
owner: ${{ github.repository_owner }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Restrict GitHub App token scope to the current repository.

The actions/create-github-app-token step currently omits the repositories input, which causes the generated token to inherit access to all repositories the GitHub App is installed in. For least privilege, restrict the token to the current repository (consistent with the configuration in plan.yaml).

🛡️ Proposed fix to limit token scope
       - name: Generate a token
         id: generate-token
         uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1  # v3
         with:
           client-id: ${{ env.CONFIG_APP_CLIENT_ID }}
           private-key: ${{ secrets.CONFIG_APP_SECRET }}
           owner: ${{ github.repository_owner }}
+          repositories: ${{ github.event.repository.name }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@v3
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3
with:
client-id: Iv23lipEOAvwk5QqNUie
client-id: ${{ env.CONFIG_APP_CLIENT_ID }}
private-key: ${{ secrets.CONFIG_APP_SECRET }}
owner: ${{ github.repository_owner }}
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3
with:
client-id: ${{ env.CONFIG_APP_CLIENT_ID }}
private-key: ${{ secrets.CONFIG_APP_SECRET }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }}
🧰 Tools
🪛 zizmor (1.26.1)

[error] 46-46: dangerous use of GitHub App tokens (github-app): token granted access to all repositories for this owner's app installation

(github-app)


[error] 42-42: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions

(github-app)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/apply.yaml around lines 40 - 46, Update the “Generate a
token” step using actions/create-github-app-token to set its repositories input
to the current repository, matching the least-privilege configuration in
plan.yaml while preserving the existing owner and credential inputs.

Comment on lines +1 to +123
name: Plan

on:
pull_request_target:
paths:
- "**/*.tf"
- "**/*.csv"

permissions:
contents: read
pull-requests: write

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
plan:
runs-on: ubuntu-latest
environment: plan
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
CONFIG_APP_CLIENT_ID: Iv23lipEOAvwk5QqNUie
TF_CLI_ARGS: "-no-color"
TF_IN_AUTOMATION: "true"
steps:
- name: Checkout PR
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: false

- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3
with:
client-id: ${{ env.CONFIG_APP_CLIENT_ID }}
private-key: ${{ secrets.CONFIG_APP_SECRET }}
owner: ${{ github.repository_owner }}
repositories: github-config

- name: Setup OpenTofu
uses: opentofu/setup-opentofu@a1320f892987e89d278cc92dc5adc984fb93aca4 # v2
with:
tofu_wrapper: false

- name: TF init
run: tofu init

- name: TF Validate
run: tofu validate

- name: TF Plan
id: plan
run: |
set +e
tofu plan -detailed-exitcode 2>&1 | tee plan_output.txt
exitcode=${PIPESTATUS[0]}
echo "exitcode=$exitcode" >> "$GITHUB_OUTPUT"
if [ "$exitcode" -eq 1 ]; then
exit 1
fi
env:
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}

- name: Comment plan on PR
if: always() && steps.plan.outcome != 'skipped'
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
const fs = require('fs');
const raw = fs.readFileSync('plan_output.txt', 'utf8');
const plan = raw.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
const exitcode = '${{ steps.plan.outputs.exitcode }}';

let summary;
if (exitcode === '0') {
summary = 'No changes. Infrastructure is up-to-date.';
} else if (exitcode === '2') {
summary = 'Changes detected. Review the plan below.';
} else {
summary = 'Plan failed. See details below.';
}

const marker = '<!-- tofu-plan -->';
const body = [
marker,
`### OpenTofu Plan`,
'',
summary,
'',
'<details><summary>Show plan output</summary>',
'',
`<pre>${plan.substring(0, 60000)}</pre>`,
'',
'</details>',
'',
`*Commit: ${context.payload.pull_request.head.sha}*`,
].join('\n');

const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existing = comments.find(c => c.body.includes(marker));

if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

No SAST/SCA scan for the Terraform/CSV changes before they're planned with real credentials.

This pipeline runs tofu plan against untrusted PR diffs with AWS credentials and an App token, but there's no tfsec/checkov/tflint-style static analysis step to catch obviously malicious or misconfigured Terraform before a human approves the plan environment gate.

As per path instructions, ".github/workflows/**/*" changes should include "SAST/SCA steps in pipeline."

🧰 Tools
🪛 zizmor (1.26.1)

[error] 11-11: overly broad permissions (excessive-permissions): pull-requests: write is overly broad at the workflow level

(excessive-permissions)


[error] 3-7: use of fundamentally insecure workflow trigger (dangerous-triggers): pull_request_target is almost always used insecurely

(dangerous-triggers)


[info] 75-75: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[warning] 11-11: permissions without explanatory comments (undocumented-permissions): needs an explanatory comment

(undocumented-permissions)


[info] 18-18: workflow or action definition without a name (anonymous-definition): this job

(anonymous-definition)


[error] 36-36: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions

(github-app)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/plan.yaml around lines 1 - 123, Add a Terraform-focused
SAST/SCA validation step to the plan job before TF init and any tofu plan
execution, using an approved scanner such as tfsec, checkov, or tflint.
Configure it to analyze the checked-out Terraform changes and fail the workflow
on detected violations, ensuring untrusted PR infrastructure is scanned before
credentials are used.

Source: Path instructions

Split into two workflows:

- validate.yaml: runs on pull_request (no secrets needed), does
  tofu init -backend=false + tofu validate for immediate feedback
  on syntax/config errors.

- plan.yaml: runs on pull_request_target with a required "plan"
  environment gate, so a maintainer must approve before secrets
  (AWS creds, GitHub App token) are exposed to the PR's code.
  Posts the plan output as a PR comment.

The environment gate mitigates the Pwn Request risk inherent in
pull_request_target + checkout PR head: external data sources and
provider binaries execute during plan, so untrusted code must not
run without human review of the diff.

Also:
- Pin all third-party actions to immutable commit SHAs
- Set persist-credentials: false on all checkout steps
- Paginate listComments to handle PRs with 30+ comments
- Extract CONFIG_APP_CLIENT_ID env var in apply.yaml
- Remove stale Prow required status checks (ci/prow/temp,
  ci/prow/unit) from fulfillment-service, osac-operator, osac-aap

Note: the GitHub App token is intentionally NOT scoped to a single
repository — the Terraform GitHub provider manages all repos in
the org, so both plan and apply need org-wide access.

Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Riccardo Piccoli <rpiccoli@redhat.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (4)
.github/workflows/apply.yaml (1)

40-46: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Restrict GitHub App token scope to the current repository.

The actions/create-github-app-token step omits the repositories input, causing the generated token to inherit access to all repositories the GitHub App is installed in. For least privilege, restrict the token to the current repository.

🛡️ Proposed fix
       - name: Generate a token
         id: generate-token
         uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1  # v3
         with:
           client-id: ${{ env.CONFIG_APP_CLIENT_ID }}
           private-key: ${{ secrets.CONFIG_APP_SECRET }}
           owner: ${{ github.repository_owner }}
+          repositories: ${{ github.event.repository.name }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/apply.yaml around lines 40 - 46, Update the “Generate a
token” step using actions/create-github-app-token to set its repositories input
to the current repository, preserving the existing owner and credential
configuration while limiting the token to this repository only.
.github/workflows/plan.yaml (3)

34-40: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

App token still scoped to the whole owner installation.

repositories and permission-* inputs are still missing; owner alone grants the generated token access to every repo the App installation can reach. This was flagged previously and not yet addressed in this diff.

🔒 Proposed fix
       - name: Generate a token
         id: generate-token
         uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1  # v3
         with:
           client-id: ${{ env.CONFIG_APP_CLIENT_ID }}
           private-key: ${{ secrets.CONFIG_APP_SECRET }}
-          owner: ${{ github.repository_owner }}
+          owner: ${{ github.repository_owner }}
+          repositories: ${{ github.event.repository.name }}
+          permission-contents: read
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/plan.yaml around lines 34 - 40, Update the “Generate a
token” step using the actions/create-github-app-token configuration to restrict
the token to the intended repository and explicitly declare the required
permission-* inputs, rather than relying on owner-only installation scope.
Preserve the existing client-id, private-key, and owner settings while adding
repository and least-privilege permission configuration.

Sources: Path instructions, Linters/SAST tools


50-53: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

No SAST/SCA scan before credentialed plan runs.

Still no tfsec/checkov/tflint-style static analysis before tofu plan executes with AWS credentials and an App token against untrusted PR diffs. Previously flagged, still absent.

As per path instructions, ".github/workflows/**/*" changes require "SAST/SCA steps in pipeline."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/plan.yaml around lines 50 - 53, Add a SAST/SCA
static-analysis step to the workflow between the “TF Validate” and “TF Plan”
steps, using an approved Terraform scanner such as tfsec, checkov, or tflint.
Ensure the scan runs before the credentialed “TF Plan” step and analyzes the
untrusted PR Terraform changes.

Source: Path instructions


85-99: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Full plan output still posted verbatim to a public-ish PR comment.

HTML-escaping guards rendering but doesn't redact attribute values — that depends entirely on every touched provider/resource marking sensitive fields correctly. Any unmarked attribute lands in plaintext in the PR comment. This was raised previously and is unchanged.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/plan.yaml around lines 85 - 99, Update the body
construction around the `plan` interpolation so the PR comment no longer embeds
raw OpenTofu plan output. Remove the `<pre>` plan section or replace it with a
trusted redacted artifact/link, ensuring unmarked sensitive provider or resource
attributes cannot appear in the public comment while preserving the summary and
commit metadata.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In @.github/workflows/apply.yaml:
- Around line 40-46: Update the “Generate a token” step using
actions/create-github-app-token to set its repositories input to the current
repository, preserving the existing owner and credential configuration while
limiting the token to this repository only.

In @.github/workflows/plan.yaml:
- Around line 34-40: Update the “Generate a token” step using the
actions/create-github-app-token configuration to restrict the token to the
intended repository and explicitly declare the required permission-* inputs,
rather than relying on owner-only installation scope. Preserve the existing
client-id, private-key, and owner settings while adding repository and
least-privilege permission configuration.
- Around line 50-53: Add a SAST/SCA static-analysis step to the workflow between
the “TF Validate” and “TF Plan” steps, using an approved Terraform scanner such
as tfsec, checkov, or tflint. Ensure the scan runs before the credentialed “TF
Plan” step and analyzes the untrusted PR Terraform changes.
- Around line 85-99: Update the body construction around the `plan`
interpolation so the PR comment no longer embeds raw OpenTofu plan output.
Remove the `<pre>` plan section or replace it with a trusted redacted
artifact/link, ensuring unmarked sensitive provider or resource attributes
cannot appear in the public comment while preserving the summary and commit
metadata.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 10513d7b-e79d-4d57-a5ba-1132c158e5c5

📥 Commits

Reviewing files that changed from the base of the PR and between de9ff84 and 754e3a2.

📒 Files selected for processing (5)
  • .github/workflows/apply.yaml
  • .github/workflows/plan.yaml
  • .github/workflows/pre-commit.yaml
  • .github/workflows/validate.yaml
  • repositories.tf
💤 Files with no reviewable changes (1)
  • repositories.tf

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant