Skip to content

Clarify review app security guidance#350

Merged
justin808 merged 25 commits into
mainfrom
jg-codex/review-app-security-docs
Jun 30, 2026
Merged

Clarify review app security guidance#350
justin808 merged 25 commits into
mainfrom
jg-codex/review-app-security-docs

Conversation

@justin808

@justin808 justin808 commented Jun 2, 2026

Copy link
Copy Markdown
Member

Summary

  • document that generated review-app workflows skip fork PR heads in public repositories
  • clarify that trusted +review-app-deploy comments still require a branch in the base repository
  • add review-app secret guidance for disposable credentials, scoped Control Plane tokens, SSH deploy keys, and cpln://secret runtime exposure

Verification

  • git diff --check
  • script/check_cpln_links
  • script/check_command_docs

Note

Low Risk
Documentation-only; no runtime, workflow, or secret configuration changes.

Overview
Documentation-only updates to docs/ci-automation.md and docs/secrets-and-env-values.md that spell out review-app security for public and open-source repos—no workflow or generator changes.

ci-automation.md now states upfront that review deploys only run for base-repo branches (fork PRs get help but not deploys because builds use repo secrets), and that maintainers must land fork work on a trusted branch for a review app. It expands CPLN_TOKEN_STAGING guidance (prefer a review/staging token that cannot touch production), DOCKER_BUILD_SSH_KEY cautions (minimal read-only deploy keys), and a new Review App Security For Public Repositories section covering trusted commenters, fork skips, disposable credentials, scoped tokens, separate data stores, rotation, and cleanup. Workflow descriptions and the demo rollout checklist add matching bullets (including verifying staging tokens cannot reach production).

secrets-and-env-values.md adds that review apps execute PR code, so cpln://secret/... does not protect values once mounted, and recommends dummy/disposable/revocable review credentials plus separate secret dictionaries from production or long-lived staging when orgs are shared.

Reviewed by Cursor Bugbot for commit 09f553d. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • Documentation
    • Updated CI/CD automation documentation with enhanced guidance for review-app deployments on public repositories, including security considerations and fork-PR handling.
    • Added comprehensive secrets management best practices for review apps, emphasizing the use of protected secret references and scoped credentials to prevent production access.

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@justin808, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 28 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 417516c6-5c5c-4633-a240-08ffe66f673e

📥 Commits

Reviewing files that changed from the base of the PR and between 09f553d and 9edaec8.

📒 Files selected for processing (2)
  • docs/ci-automation.md
  • docs/secrets-and-env-values.md

Walkthrough

This PR updates two documentation files to enhance guidance around review-app deployments in public repositories. It establishes security constraints for fork PRs, revises secret token requirements, adds a comprehensive review-app security section, and clarifies safe secret storage using Control Plane references and scoped credentials.

Changes

Review App Security for Public Repositories

Layer / File(s) Summary
Security Model and Token Requirements
docs/ci-automation.md
Public repositories restrict review-app deployments to base-repo branches; fork PRs skip deploy workflows but may receive help comments. CPLN_TOKEN_STAGING is documented as a dedicated review/staging token without production access. A new "Review App Security For Public Repositories" section details default behaviors, execution risks, credential disposal requirements, and secret-mounting limits.
Secure Implementation and Credential Handling
docs/ci-automation.md, docs/secrets-and-env-values.md
DOCKER_BUILD_SSH_KEY and tokens must be least-privilege and revocable. Generated workflows skip fork PR heads by design; production promotion remains manual with separate secrets. Review app secrets must be disposable. cpln://secret/... references keep sensitive values protected in Control Plane while allowing safe application mounting; review and staging secret dictionaries must be scoped separately.

Sequence Diagram(s)

(Diagrams are embedded in the hidden review stack artifact above.)

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • shakacode/control-plane-flow#285: Updates review-app command trigger semantics and fork-handling behavior in similar documentation sections.
  • shakacode/control-plane-flow#326: Overlapping updates to docs/ci-automation.md covering review-app and staging secret token requirements, with additional bootstrap instructions.
  • shakacode/control-plane-flow#323: Clarifies PR-open review-app help wrapper behavior for forks and clones, aligning with this PR's fork/public-repo deployment constraints.

Suggested labels

documentation, review needed

Poem

🐰 A guardian bunny hops through secure review lands,
Forks stay in comments, base branches in hands,
Disposable secrets, no prod-danger touch,
Control Plane holds tight—safety means much! 🔐

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Clarify review app security guidance' directly aligns with the main changes: adding security documentation for review apps, including fork PR handling, secret scoping, and credential best practices.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jg-codex/review-app-security-docs

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 coderabbitai Bot added documentation Improvements or additions to documentation review needed labels Jun 2, 2026
@greptile-apps

greptile-apps Bot commented Jun 2, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds security guidance for review apps in public repositories, explaining why fork PR heads are skipped during deploy, clarifying that trusted +review-app-deploy comments cannot bypass that restriction, and advising that secrets mounted into review-app workloads are readable by PR code regardless of cpln://secret indirection.

  • docs/ci-automation.md: Adds a new "Review App Security For Public Repositories" section with disposable-credential requirements, SSH deploy key scoping guidance, and a clarified description of fork-PR behavior in both the generated workflow summary and the rollout checklist.
  • docs/secrets-and-env-values.md: Adds two paragraphs reinforcing that cpln://secret indirection protects values only at rest, and advising against pointing review-app templates at shared production or persistent staging secret dictionaries.

Confidence Score: 4/5

Documentation-only changes with accurate security guidance; safe to merge.

All changes are documentation. The security claims are accurate and internally consistent, with one bullet point in the new security section using an "unless" clause that reads differently from the clearer prose elsewhere in the file — a reader could interpret it as an automatic workflow check rather than a manual workaround.

The one bullet at line 209 of docs/ci-automation.md that uses "unless the branch exists in the base repository" would benefit from a small reword to match the unambiguous phrasing used later in the same section.

Important Files Changed

Filename Overview
docs/ci-automation.md Adds fork-PR skip explanation at the top, expands secret-scoping guidance for CPLN_TOKEN_STAGING and DOCKER_BUILD_SSH_KEY, and adds a new "Review App Security For Public Repositories" section; one bullet in that section uses ambiguous "unless the branch exists in the base repository" phrasing that differs slightly from the clearer prose elsewhere in the same file.
docs/secrets-and-env-values.md Adds two new paragraphs clarifying that cpln://secret indirection does not protect values after workload mounting, and advising against shared production secret dictionaries for review-app templates; the added content is accurate and consistent with the ci-automation.md guidance.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[PR opened or push] --> B{Is PR head from\nbase repository?}
    B -- Yes\n(same-repo branch) --> C[Review app deploy eligible]
    B -- No\n(fork head) --> D[Skip deploy\nPost help comment only]
    C --> E{Trigger: push or\n+review-app-deploy comment?}
    E -- Push --> F{Is review app\nalready active?}
    F -- Yes --> G[Auto-redeploy]
    F -- No --> H[Skip until first comment]
    E -- Comment --> I{Is commenter\nOWNER / MEMBER /\nCOLLABORATOR?}
    I -- No --> J[Ignore comment]
    I -- Yes --> K[Create or update review app]
    K --> L{Are secrets disposable?\nCPLN_TOKEN_STAGING\nnot prod-scoped?}
    L -- Yes --> M[Safe review-app deploy]
    L -- No --> N[⚠️ Credential exposure risk\nRotate and scope secrets]
    D --> O[Maintainer workaround:\nmove change to base-repo branch\nthen open new PR]
    O --> C
Loading

Reviews (1): Last reviewed commit: "docs: clarify review app security" | Re-trigger Greptile

Comment thread docs/ci-automation.md Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 09f553d9a9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/ci-automation.md Outdated
@justin808 justin808 force-pushed the jg-codex/review-app-security-docs branch from 09f553d to d144951 Compare June 30, 2026 09:38
@justin808

Copy link
Copy Markdown
Member Author

Address-review summary

Scan scope: full PR history; no previous address-review summary cutoff was present.

Mattered

  • Addressed the fork-PR wording so docs do not imply the workflow automatically detects an equivalent base-repo branch.
  • Addressed the review-app org/token guidance so docs state the normal generated flow uses the staging/review org and token, with a separate review-app org requiring customization.

Optional

  • None.

Skipped

  • None.

Next default scan starts after this comment. Say check all reviews to rescan the full PR.

@claude

claude Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review: Clarify review app security guidance

This PR is a documentation-only addition that explains review-app security constraints for public/open-source repos — fork-PR limitations, scoped token guidance, DOCKER_BUILD_SSH_KEY cautions, and a new top-level security section in ci-automation.md plus expanded secret-handling guidance in secrets-and-env-values.md. The intent and overall framing are sound. Three issues worth addressing before merge:


1. DOCKER_BUILD_SSH_KEY risk scope understated (line 409)

The new paragraph says the key is available to "allowed review-app Docker builds", but both generated workflows pass it:

  • cpflow-deploy-review-app.yml:36DOCKER_BUILD_SSH_KEY: ${{ secrets.DOCKER_BUILD_SSH_KEY }}
  • cpflow-deploy-staging.yml:24 — same

A staging branch push from anyone with write access also receives the key during the Docker build. The caution should say "review-app and staging Docker builds" to avoid underselling the scope.


2. Same-repo auto-deploy trust boundary not documented (line 421)

The security section says "same-repository pull requests can create or update review apps" without stating who qualifies. The generated workflow checks only that the PR head repo matches the base repo — there is no author_association guard on the pull_request auto-deploy path (the OWNER/MEMBER/COLLABORATOR check is only on the issue_comment path). Any external collaborator with push access to the repo can open a same-repo PR that triggers an auto-deploy with CPLN_TOKEN_STAGING and DOCKER_BUILD_SSH_KEY in the Docker build context. This is the most actionable trust boundary for operators of public repos and should be called out explicitly.


3. "open-source repositories" / "public repositories" inconsistency (line 391)

The new org-layout bullet uses "open-source repositories" — the only occurrence of this term in the entire file. Every other new addition (lines 13, 173, 413, 777) uses "public repositories". A maintainer of a public-but-proprietary repo could read "open-source" and conclude the scoped-token recommendation does not apply to them, even though the security concern is identical. Aligning to "public repositories" throughout is straightforward.

Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
@justin808

Copy link
Copy Markdown
Member Author

Address-review summary

Scan scope: since previous summary at 2026-06-30T09:39:31Z.

Mattered

  • Addressed review-app security wording in docs/ci-automation.md: documented that the Docker SSH key can be used by review-app and staging Docker builds, clarified same-repository PR auto-deploy trust boundaries, and aligned the recommendation wording to public repositories. Fixed in 0fab5b1.

Optional

  • Handled the terminology consistency nit inline by changing the recommendation from open-source-specific wording to public-repository wording.

Skipped

  • None.

Next default scan starts after this comment. Say check all reviews to rescan the full PR.

@claude

claude Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review: Clarify review app security guidance

This PR adds welcome security documentation for review apps in public repositories, particularly the fork-PR skipping behavior and the importance of disposable credentials. The two files are well-structured and the guidance is directionally sound. However, the review surfaced five confirmed factual issues — two of which are security-relevant documentation gaps — that should be fixed before merge.

Confirmed Issues

1. release_script and hooks.post_creation are missing from the threat-surface list (security gap)

docs/ci-automation.md line 415–417 lists attack vectors ("Dockerfile, package scripts, Rails initializers, server-rendering code, and application runtime") but omits two cpflow-specific vectors that are arguably more dangerous for review apps:

  • release_script — if a PR's .controlplane/controlplane.yml defines a release_script, cpflow deploy-image --run-release-phase executes it inside the PR-built image with secrets mounted, before any human can inspect the workload. The generated workflow (.github/workflows/cpflow-deploy-review-app.yml line 429) passes ${RELEASE_PHASE_FLAG} directly, so a malicious PR can inject an arbitrary shell script into the deploy pipeline.
  • hooks.post_creationcpflow setup-app runs the post-creation hook (commonly bundle exec rails db:prepare) inside the PR image with secrets mounted. The canonical example in docs/ci-automation.md line 144 already sets this hook for review apps.

Both vectors run untrusted PR code before human review, making them the highest-severity omission in an otherwise thorough security section.

2. "automatically on each push" is false for first-time deploys

Line 421–422 states "same-repository pull requests from any contributor with push access can create or update review apps automatically on each push." This is only true for subsequent pushes to an already-existing review app. The workflow's "Skip auto deploy until a review app is created" step (.github/workflows/cpflow-deploy-review-app.yml lines 255–266) exits early with a message to use +review-app-deploy when no app exists yet. The existing docs at lines 488–491 describe this correctly and directly contradict line 421–422.

3. "push access" is the wrong permission threshold

The same bullet uses "push access" as the gate, but the workflow checks github.event.pull_request.head.repo.full_name == github.repository — a same-repository-origin check, not a permission level. "Push access" implies a GitHub permission role that the workflow never inspects. A security auditor mapping this to GitHub's role model will get the wrong picture.

4. CPLN_ORG_STAGING presented as always-configured when it's optional

Line 429 says the workflow "targets the staging/review Control Plane org and token from CPLN_ORG_STAGING and CPLN_TOKEN_STAGING", implying CPLN_ORG_STAGING is always present. Lines 185 and 196 explicitly label it an override that is inferred from cpln_org in controlplane.yml when not set. A reader auditing their CI configuration may incorrectly flag a correctly-configured repo as missing a required variable.

5. "skipped" framing understates GitHub's platform-level enforcement

Line 423 says "fork pull requests are skipped for review-app deploys," framing this as a workflow design choice. In practice the workflow uses the pull_request event, so GitHub itself withholds repository secrets from fork PRs at the platform level — the workflow's if: condition is belt-and-suspenders, not the primary guard. The cpflow-delete-review-app.yml workflow even documents this distinction: it uses pull_request_target intentionally and relies on explicit if: conditions as the primary guard precisely because that event does expose secrets. The asymmetry is worth explaining so readers don't conclude that switching to pull_request_target would be safe because "the workflow skips forks anyway."

Minor / Structural

  • docs/secrets-and-env-values.md line 23 — "scope identities" uses a Control Plane term of art without definition or a link. Readers who don't already know that an Identity is a named service account resource bound to a workload via a policy have no actionable path from this sentence.
  • docs/ci-automation.md line 409 — The DOCKER_BUILD_SSH_KEY security warning is placed after the "Advanced optional repository variables" subsection rather than adjacent to the variable's own definition at line 396. A reader who stops reading at "Optional repository secret for private dependency builds" will miss the constraint.

Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
Comment thread docs/secrets-and-env-values.md Outdated
@justin808

Copy link
Copy Markdown
Member Author

Address-review summary

Scan scope: current-head unresolved review threads on PR #350 fetched on 2026-06-30T10:08Z; no check all reviews override.

Mattered

  • Addressed the review-app threat-surface docs by naming PR-controlled release scripts and post-creation hooks.
  • Corrected same-repository review-app deployment wording to distinguish first creation from later automatic updates.
  • Clarified the fork-PR secret boundary and the generated workflow's explicit same-repository guard.
  • Clarified how the generated review-app workflow resolves its staging/review org and token.

Optional

  • Fixed the Control Plane identity wording so the review-app secret-scoping guidance is actionable without prior product terminology.

Skipped

  • None.

Next default scan starts after this comment. Say check all reviews to rescan the full PR.

@claude

claude Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review: Clarify review app security guidance

This is a docs-only PR adding security guidance for review apps on public repos. The framing is accurate and the new section fills a real gap. Three findings worth addressing before merge.

CONFIRMED -- hooks.pre_deletion omitted from the attack-surface list (ci-automation.md lines 415-418)

The docs warn about release_script and hooks.post_creation as PR-controllable attack surfaces, but omit hooks.pre_deletion. This hook also executes in the PR's container image: the nightly cleanup workflow runs cpflow cleanup-stale-apps which calls cpflow delete which invokes run_pre_deletion_hook via cpflow run --image latest (lib/command/base.rb). The hook command string comes from the base branch's controlplane.yml, but the execution environment is the PR's built Docker image. A PR that embeds malicious code in its Dockerfile or entrypoints will have that code run with staging CP credentials when nightly cleanup teardown fires -- even after the PR closes. Suggestion: extend the list at line 416-417 to include hooks.pre_deletion alongside hooks.post_creation.

PLAUSIBLE -- Security section omits the auto-delete-on-close trigger (ci-automation.md line 426)

Line 426 states that +review-app-delete is accepted only from trusted commenters. This is narrowly true for the comment command, but cpflow-delete-review-app.yml also fires on pull_request_target: closed with no commenter gate. Line 505 already correctly documents this, but the new security section omits it. A reader of the security section alone could incorrectly conclude that deletion is exclusively commenter-gated. Suggestion: add a note that review apps are also auto-deleted when the PR closes (no trusted-commenter check for that path).

PLAUSIBLE -- Tightly scoped token guidance is not actionable (ci-automation.md lines 173, 391)

The phrase tightly scoped token appears twice in new text without explaining that on Control Plane, scope is determined by the service account and RBAC policies -- not a property of the token itself. There is no link to Control Plane service account or policy docs, and no cpflow command to help. A user following this has no clear path to actually scoping CPLN_TOKEN_STAGING. Suggestion: add a note such as: create a Control Plane service account with a policy limited to review-app CI operations and generate a token for that account, with a link to Control Plane RBAC docs.

Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
@justin808

justin808 commented Jun 30, 2026

Copy link
Copy Markdown
Member Author

Address-review summary

Scan scope: current-head unresolved review threads on PR #350 fetched on 2026-06-30T10:26Z; no check all reviews override.

Mattered

  • Addressed the review-app teardown security gap by documenting that hooks.pre_deletion can run through the latest PR-built image during deletion or scheduled cleanup.
  • Clarified that review apps are also deleted automatically when the pull request closes, separate from the trusted-comment +review-app-delete path.

Optional

  • Handled the Control Plane token-scoping actionability feedback by explaining that CPLN_TOKEN_STAGING should come from service account policies limited to review/staging CI operations.

Skipped

  • None.

Next default scan starts after this comment. Say check all reviews to rescan the full PR.

@claude

claude Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review: Clarify review app security guidance

This PR adds a detailed "Review app security for repositories with external contributors" section to ci-automation.md and a matching "Review app secrets" section to secrets-and-env-values.md. The technical content is accurate (all internal links resolve, workflow guard descriptions match the actual YAML), and the coverage of the fork-PR threat model is thorough. Eight issues worth addressing before merge:


Findings (most severe first)

1. Semantic ambiguity: "public repositories" vs. "external contributors" used interchangeably
The new section heading is "Review app security for repositories with external contributors" but the intro paragraph (line 13), rollout checklist item 15 (line 834), and the cross-reference in secrets-and-env-values.md all say "public repositories." These are not equivalent — a private repo can have external contributors; a public repo may not. The guidance applies to any repo that accepts untrusted PR code, regardless of visibility. Pick one term and use it consistently, or clarify that "external contributors" is the intended scope and update the other references to match.

2. "Separate, disposable environment" path is mentioned but never defined (ci-automation.md line 18)
The intro offers "or otherwise review it through a separate, disposable environment" as an alternative to rebasing fork code, but the rest of the doc gives no guidance on what this means, how to provision it, or what the security requirements are. A maintainer who wants to skip the rebase path has no actionable information and may improvise unsafely. Either define the term (even briefly, with a link) or remove the alternative and say rebasing to a trusted branch is the only supported path.

3. GITHUB_TOKEN write-access warning doesn't confirm the generated default is already safe (ci-automation.md line 446)
The text warns pull_request_target "runs with base-repository GITHUB_TOKEN permissions, which may include write access unless restricted." It never states that the generated cpflow-delete-review-app.yml already pins permissions: contents: read; issues: write; pull-requests: write. An operator reading this doesn't know whether they need to act or are already protected. Add a sentence confirming the generated default, e.g.: "The generated cpflow-delete-review-app.yml already sets permissions: to the minimum required; only customized copies are at risk."

4. Generated Workflow Behavior bullet omits manual dispatch as a first-review-app-creation path (ci-automation.md line 537)
The bullet reads "Creates a review app when someone comments +review-app-deploy." The security section at line 432 correctly states that creating the first review app requires "either a +review-app-deploy comment from a trusted commenter or a manual workflow dispatch by a repository collaborator." The behavior summary is the reference operators consult day-to-day; it should match the security section.

5. Nightly cleanup bullet missing hooks.pre_deletion credential-disposability warning (ci-automation.md line 580)
Every other delete path (PR-close teardown, +review-app-delete comment, manual dispatch) now carries the warning that hooks.pre_deletion executes through the latest PR-built image and review-app credentials must remain disposable. The cpflow-cleanup-stale-review-apps.yml section at lines 580–581 has no equivalent note — the most automated and least-watched delete path is the one missing the alert. This is also the path most likely to run after a malicious fork PR's review app is forgotten.

6. Fork-guard re-explanation in secrets-and-env-values.md will drift from the authoritative version (secrets-and-env-values.md lines 29–31)
The secrets doc re-explains the two-axis fork guard (caller if: + reusable workflow source-validation step) at a different level of detail than the authoritative explanation in ci-automation.md. If a future workflow adds a third trigger axis (e.g., schedule or repository_dispatch), both files need updating; one will be missed. Consider replacing the duplicate explanation with a one-sentence summary and a link: "See Review app security for repositories with external contributors for a full description of how both guards interact."

7. CHANGELOG.md missing entry
AGENTS.md mandates keeping CHANGELOG.md updated for user-visible changes. This PR adds operator-facing guidance about token scoping, secret disposability, and SSH key handling — all of which affect how maintainers configure deployed projects. No entry exists under [Unreleased].

8. Manual dispatch fork-guard rationale omitted (ci-automation.md line 538–540)
The new text states that "dispatching with a fork PR number causes a hard workflow failure" without the rationale. The comment-command path carries the reason explicitly: "because the workflow builds Docker images with repository secrets." Without the rationale, a collaborator who hits the hard failure might propose removing the guard thinking it's an unintentional error rather than a deliberate security boundary.

Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
Comment thread docs/secrets-and-env-values.md Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f105673dc8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/ci-automation.md Outdated
@claude

claude Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review: Clarify review app security guidance

This PR adds thorough security documentation for review-app deployments in public repositories — the coverage of fork-PR guards, token scoping, template trust, and credential hygiene is genuinely useful and technically grounded. Two factual inaccuracies and three gaps in the guidance survived verification and are worth addressing before merge.

Confirmed bugs in the documentation

1. Incorrect claim about release_script/hook token access (lines 422–423)
The text says PR-controlled release_script and hook commands "can read the staging token directly while they execute on the runner." This is factually wrong: those commands run in remote Control Plane containers via cpflow run (through run_command_in_latest_image in base.rb), not on the runner. The runner's CPLN_TOKEN env var is not forwarded to that container (--use-local-token is not passed by run_command_in_latest_image). The actual exposure — CPLN_TOKEN written to $GITHUB_ENV for all subsequent runner steps — is real but belongs to custom runner steps added after setup, not to hooks/release_script. The distinction matters: the mitigation for the runner-step exposure (audit custom steps) differs from the mitigation for workload-level access (scoped identity/secrets). See inline comment for suggested rewrite.

2. skip_secrets_setup warning is incomplete (lines 425–426)
The doc warns that templates can still attach an identity even when skip_secrets_setup is set. It misses the more dangerous path: skip_secrets_setup is itself read from the PR branch's controlplane.yml at runtime (setup_app.rb:59 reads config.current[:skip_secrets_setup]). A PR can set the flag to false (or omit it) to force automatic identity binding, overriding the base-branch config. The only tamper-proof control is the CLI flag --skip-secrets-setup passed externally by the workflow itself, not the config file value. See inline comment.

Plausible gaps

3. hooks.pre_deletion base-branch mechanism not explained (lines 468–469)
The warning to "never check out PR or fork code in the same job as the delete step" gives only one consequence ("could let a PR replace the guard script itself"). It misses a second: checking out PR code also pulls in controlplane.yml from the PR branch, making the hooks.pre_deletion command itself PR-controlled — separate from and in addition to the guard-script risk. The doc also never explains that "the command comes from base-branch config" is an emergent property of actions/checkout defaulting to the base branch when no ref: is specified under pull_request_target, not a cpflow guarantee. See inline comment.

4. Injection field list anchors on two examples (lines 478–479)
The guidance to avoid interpolating head.ref and head.label directly into run: steps uses "such as" framing, but most developers will anchor on the two named fields and not self-apply the rule to equally dangerous fields like title, body, and head.repo.description. Adding one sentence that names the broader category explicitly would close this. See inline comment.

5. Dispatch vs. comment permission level undifferentiated (lines 431–432)
"+review-app-deploy comment from a trusted commenter or a manual workflow dispatch by a repository collaborator" implies both paths are open to the same audience. GitHub enforces write access for workflow_dispatch at the platform level, while the trusted-commenter check accepts any COLLABORATOR — including read-only outside collaborators. This is a minor precision gap rather than a security hole (the platform gate prevents actual misuse), but it could confuse a read-only collaborator wondering why they can comment-deploy but not dispatch. See inline comment.

Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
@claude

claude Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review: Clarify review app security guidance

This PR adds ~140 lines of documentation to docs/ci-automation.md and docs/secrets-and-env-values.md explaining review-app security boundaries for public repositories — covering fork-PR guards, token scoping, teardown credential safety, and the pull_request_target delete path. The content is detailed and technically accurate in the main. A few issues are worth addressing before merge.

Findings (most-severe first)

1. Self-contradictory claim about Guard 1 and secret access (ci-automation.md:443)
Line 443 states "Removing either guard opens a path to deploy untrusted code with repository-secret access." The very next sentence then says "GitHub also withholds repository secrets from fork pull_request runs" — which means removing Guard 1 (the job-level if: that skips fork pull_request runs) alone does not open a repository-secret-access path; GitHub's own isolation covers that. Only Guard 2 (the reusable workflow's source-validation step for issue_comment events) is the actual secret-access guard. The claim should distinguish: both guards are worth preserving, but only Guard 2 removal creates secret-access exposure; Guard 1's value is preventing untrusted staging deploys even without repository-secret access.

2. pull_request_target explanation gives only the benefit, not the danger (ci-automation.md:448)
The bullet says the PR-close path uses pull_request_target "so the staging token is available for teardown," but never states the mechanism: pull_request_target runs in the base-repository context, so fork-close events have full repository-secret access. The same fact that makes it useful for teardown is what makes checking out fork code there catastrophic. A separate paragraph covers this (line 475), but the bullet most readers land on first doesn't make the connection.

3. CPLN_TOKEN export mechanism is understated (ci-automation.md:422)
"The generated setup action also exports CPLN_TOKEN_STAGING as CPLN_TOKEN for later runner shell steps" implies the token is present only in steps that explicitly reference it. In reality the setup action writes it to GITHUB_ENV, injecting it into the process environment of every subsequent runner shell step for the duration of the job — including third-party actions, package-manager hooks, and any subprocess that inherits the environment. The mitigation ("keep custom runner steps after setup trusted") is correct but the mechanism should be named so maintainers understand the scope.

4. Template policy escalation vector not addressed in secrets doc (docs/secrets-and-env-values.md:28)
The guidance to keep review-app and staging secret dictionaries separate doesn't mention the adjacent attack: PR-controlled .controlplane/templates/ identity and policy templates applied by cpflow setup-app at first review-app creation can bind the review workload's identity to the shared staging secret dictionary, bypassing the separation. The ci-automation.md security section covers this, but the secrets doc — where an operator configuring dictionaries would read — should cross-reference it explicitly.

5. Heading case inconsistent with rest of file (ci-automation.md:413)
Every other ## heading in ci-automation.md uses Title Case ("Quick Start", "Docker Builds with Private Dependencies", "Generated Workflow Behavior", etc.). The new heading uses sentence case: "Review app security for repositories with external contributors." Should be "Review App Security for Repositories with External Contributors." The anchor and cross-references would need to be updated consistently.

6. Missing paragraph break in secrets doc (docs/secrets-and-env-values.md:31–32)
"Removing any guard leaves one or more trigger paths unprotected." runs directly into "For repositories with external contributors, treat..." with no blank line, causing them to render as one paragraph. The second sentence is the stronger warning and is easy to miss without the break.

7. Missing CHANGELOG entry
This PR adds a substantial new section directly affecting what public-repo maintainers are told to do. Per AGENTS.md, user-visible changes belong in CHANGELOG.md under [Unreleased].

8. Duplicate trusted-commenter bullet (ci-automation.md:447)
The standalone bullet "+review-app-deploy and +review-app-delete comment commands are accepted only from trusted commenters" is fully redundant — the preceding bullet already established the trusted-commenter gate for deploy, and the delete workflow section covers the delete command separately. It adds no new information.

Comment thread docs/ci-automation.md
Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated
Comment thread docs/secrets-and-env-values.md
Comment thread docs/secrets-and-env-values.md Outdated
Comment thread docs/ci-automation.md Outdated
Comment thread docs/ci-automation.md Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5696a62e2b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/secrets-and-env-values.md Outdated
@justin808 justin808 merged commit 5f092dd into main Jun 30, 2026
6 checks passed
@justin808 justin808 deleted the jg-codex/review-app-security-docs branch June 30, 2026 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation review needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant