Skip to content

Require workflow permission for action installs#418

Merged
ralyodio merged 1 commit into
masterfrom
fix/github-workflow-install-permissions
May 23, 2026
Merged

Require workflow permission for action installs#418
ralyodio merged 1 commit into
masterfrom
fix/github-workflow-install-permissions

Conversation

@ralyodio
Copy link
Copy Markdown
Contributor

Summary

  • request GitHub App Workflows: write permission in the app manifest
  • load installation permissions before action installs
  • return a clear 403 when a workflow action install needs the permission update

Verification

  • pnpm --filter sh1pt-dot-com build

Operational note

Existing GitHub App installations must accept the updated Workflows: write permission in GitHub before sh1pt can open PRs that add or update .github/workflows/*.yml.

@github-actions
Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #418

No security issues found.

Full AI Analysis

Looking at this pull request, I'll analyze each change for potential security vulnerabilities.

Analysis Summary

This PR adds GitHub Workflows write permissions to a GitHub App configuration and implements permission checking before installing actions that write to .github/workflows/. Let me examine each change:

  1. Permission additions - Adding workflows: 'write' permission
  2. Permission validation - Adding checks before installing workflow files
  3. Database schema update - Adding permissions field to track installation permissions
  4. Error handling - Better error messages for permission issues

Security Findings

Severity File Line Issue Suggestion
NO SECURITY ISSUES FOUND - - - -

Detailed Analysis

No security vulnerabilities detected. Here's why each change is secure:

✅ Permission Model (Lines 14, 49)

  • Adding workflows: 'write' follows the principle of least privilege
  • Only grants necessary permissions for the intended functionality
  • Properly declared in both interface and manifest

✅ Authorization Checks (Lines 77-84, 118-130)

  • Implements proper permission validation before sensitive operations
  • Checks both manifest requirements and installation permissions
  • Returns appropriate 403 errors when permissions are insufficient
  • No bypass opportunities identified

✅ Input Validation (Lines 140-144)

  • requiresWorkflowWrite() safely checks file destinations
  • Uses startsWith() with proper path normalization
  • No path traversal vulnerabilities (removes leading slashes correctly)

✅ Database Changes (Lines 19, 62)

  • Adding optional permissions field is safe
  • No injection risks in the SELECT query
  • Maintains existing authorization model

✅ Error Handling (Lines 118-130)

  • Provides helpful error messages without exposing sensitive information
  • Maintains proper HTTP status codes
  • No information disclosure vulnerabilities

Positive Security Aspects

  1. Defense in Depth: Multiple permission checks (pre-check + API response handling)
  2. Fail Secure: Returns 403 when permissions are insufficient rather than proceeding
  3. Clear Error Messages: Helps users understand permission requirements without exposing internals
  4. Principle of Least Privilege: Only requests necessary permissions

The changes appear to be a security improvement, adding proper authorization checks for a sensitive operation (writing workflow files).

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 23, 2026

Greptile Summary

This PR gates workflow-file action installs behind a Workflows: write GitHub App permission, adding it to the app manifest, loading it from the DB during authorization, and returning a descriptive 403 before (and after) attempting the GitHub API call.

  • Adds workflows: 'write' to the GitHub App manifest (buildManifest) and the ManifestPermissions interface, and updates the setup page copy to document the new permission.
  • Extends authorizeInstallation to select the permissions JSON column from github_installations, then uses two new helpers (requiresWorkflowWrite / hasWorkflowWrite) to short-circuit with a clear 403 before hitting the GitHub API; a second 403 handler catches the edge case where the DB permission is stale but GitHub rejects the call anyway.

Confidence Score: 4/5

Safe to merge; the new permission gate is well-defended with both a pre-flight DB check and a GitHub API fallback, so no regression path is left unguarded.

The install route now reads permissions from the DB for its pre-flight check, but if the webhook handler doesn't refresh that column when a user accepts the new GitHub App permission, the pre-flight will incorrectly block them with 403 even after they've accepted. The downstream GitHub 403 fallback only covers the inverse case. Everything else — the manifest update, the helper functions, and the setup UI copy — is straightforward and correct.

The install route and github-installation.ts are worth a second look to confirm the permissions column is kept current by the installation webhook.

Important Files Changed

Filename Overview
sites/sh1pt.com/app/api/v1/github/installations/[id]/repos/[repoId]/actions/[actionId]/install/route.ts Adds a pre-flight permission check and a GitHub-API-level 403 fallback for workflow file installs; helper functions are correct but the pre-flight relies on the DB permissions column being kept current by webhooks.
sites/sh1pt.com/lib/github-installation.ts Adds permissions field to InstallationRow interface and includes it in the Supabase SELECT query; change is minimal and correct.
sites/sh1pt.com/app/admin/github/setup/page.tsx Adds workflows: 'write' to the GitHub App manifest interface, buildManifest output, and setup UI copy; straightforward and correct.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Route as install/route.ts
    participant DB as Supabase (github_installations)
    participant GH as GitHub API

    Client->>Route: POST /install
    Route->>DB: authorizeInstallation() SELECT permissions
    DB-->>Route: InstallationRow (with permissions)
    Route->>Route: requiresWorkflowWrite(manifest.files)?
    alt needs workflows:write AND permissions missing
        Route-->>Client: 403 - update App permissions and retry
    else permission OK (or action has no workflow files)
        Route->>GH: openPackPullRequest()
        alt GitHub returns 403 Resource not accessible by integration
            GH-->>Route: 403
            Route-->>Client: 403 - update App permissions and retry
        else success / other outcome
            GH-->>Route: outcome
            Route-->>Client: 200 / 409 / 5xx
        end
    end
Loading

Fix All in Codex Fix All in Claude Code

Reviews (1): Last reviewed commit: "Require workflow permission for action i..." | Re-trigger Greptile

Comment on lines +77 to +85
if (requiresWorkflowWrite(entry.manifest.files) && !hasWorkflowWrite(auth.installation.permissions)) {
return NextResponse.json(
{
error:
'GitHub App needs Workflows: write permission to install actions into .github/workflows. Update the sh1pt GitHub App permissions, accept the installation update in GitHub, then retry.',
},
{ status: 403 },
);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Pre-flight check depends on DB permissions staying fresh

hasWorkflowWrite reads from the permissions column that was just added to the SELECT in authorizeInstallation. If the webhook handler that updates github_installations doesn't write the permissions JSON when an installation is updated (i.e., when a user accepts the new Workflows: write request in GitHub), a user who has already accepted the permission will still receive a 403 here until the row is resynced. The fallback handler on line 118 catches the inverse case (DB says ✓ but GitHub says ✗), but there's no matching recovery path for the false-negative. Is the permissions column reliably refreshed by the installation webhook? Is the permissions column in github_installations updated by the installation webhook event when a user accepts new GitHub App permissions?

Fix in Codex Fix in Claude Code

@ralyodio ralyodio merged commit 2678387 into master May 23, 2026
7 checks passed
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