Skip to content

Conversation

@witmicko
Copy link
Contributor

@witmicko witmicko commented Dec 9, 2025

Changes

  • Onboarding workflow (.github/workflows/onboard-new-repo.yml)

    • Manual trigger: Enter org + repo name to onboard any repository
    • Automated trigger: Responds to repository_dispatch events from webhooks
    • Auto-detects default branch from target repository
  • PR template improvements (.github/templates/onboarding-pr-body-automated.md)

    • Added auto-merge warning and opt-out instructions
    • Detailed language configuration examples with YAML snippets
    • Better formatting and structure

Usage

Manual:

  1. Go to Actions → "Onboard New Repository with SAST"
  2. Enter organization and repository name
  3. Run workflow

Automated:
Set up webhook to send repository_dispatch with:

{
  "event_type": "new_repository_created",
  "client_payload": {
    "organization": "MetaMask",
    "repository": "repo-name",
    "base_branch": "main"
  }
}

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Adds an automated workflow to onboard repositories to the MetaMask Security Code Scanner, plus PR body templates and an example scanner workflow.
> 
> - **Workflows**:
>   - Add onboarding workflow `/.github/workflows/onboard-new-repo.yml` to create PRs that add the scanner to target repos.
>     - Supports manual and `repository_dispatch` triggers, auto-detects default branch, handles empty repos, creates branch/PR, and substitutes variables in PR body.
>   - Add reusable scanner workflow template `/.github/templates/security-code-scanner.yml` with default `paths-ignored`, secrets, and `{ DEFAULT_BRANCH }` placeholder.
> - **Templates**:
>   - Add automated PR body `/.github/templates/onboarding-pr-body-automated.md` with auto-merge notice, checklist, config examples, and variable `{{SECURITY_SCANNING_URL}}`.
>   - Add templates README `/.github/templates/README.md` describing usage and variables.
> - **Examples**:
>   - Add example workflow `examples/security-code-scanner.yml` for reference usage.
> - **Docs**:
>   - Update `CHANGELOG.md` with recent changes and fixes.
> 
> <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 6d3ad6bdd9fafa1b6fecb4482478abcf4e708dc6. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

@witmicko witmicko changed the title Onboarding automation feat: add SAST onboarding automation Dec 9, 2025
@witmicko witmicko marked this pull request as ready for review December 9, 2025 13:13
@witmicko witmicko requested a review from a team as a code owner December 9, 2025 13:13
To configure the scanner for your repository's specific needs,
please review the workflow file and adjust as necessary."

git push origin "$BRANCH_NAME"
Copy link

Choose a reason for hiding this comment

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

Bug: Documented opt-out mechanism not implemented in workflow

The PR template instructs users to add a .github/no-security-scanner file to "prevent future onboarding attempts", but the workflow never checks for this file's existence before creating the branch and PR. Teams that follow the opt-out instructions will continue receiving unwanted onboarding PRs, breaking the documented contract.

Additional Locations (1)

Fix in Cursor Fix in Web

if [ "${{ github.event_name }}" = "repository_dispatch" ]; then
ORG="${{ github.event.client_payload.organization }}"
REPO_NAME="${{ github.event.client_payload.repository }}"
REPO="$ORG/$REPO_NAME"
Copy link

Choose a reason for hiding this comment

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

Bug: Unsanitized repository_dispatch payload enables command injection

Values from github.event.client_payload.organization and github.event.client_payload.repository are used directly in shell commands via ${{ }} expression syntax. Since repository_dispatch events can be triggered by external webhooks with arbitrary payloads, a malicious actor could inject shell commands through these fields. The values are used in API calls, git operations, and file paths without any validation or sanitization.

Fix in Cursor Fix in Web

repository: ${{ steps.target.outputs.repository }}
token: ${{ secrets.ONBOARDING_TOKEN }}
path: target-repo
ref: ${{ steps.target.outputs.base_branch }}
Copy link

Choose a reason for hiding this comment

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

Bug: Opt-out file check documented but never implemented

The PR body template tells users to add a .github/no-security-scanner file to prevent future onboarding attempts, but the workflow never checks for this file's existence. Repositories that have opted out will still receive onboarding PRs, causing frustration for teams that explicitly declined the scanner.

Additional Locations (1)

Fix in Cursor Fix in Web

# Copy the security scanner workflow template and replace placeholders
sed "s/{ DEFAULT_BRANCH }/$BASE_BRANCH/g" \
../scanner-repo/.github/templates/security-code-scanner.yml \
> .github/workflows/security-code-scanner.yml
Copy link

Choose a reason for hiding this comment

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

Bug: sed fails when branch name contains forward slashes

The sed command uses / as a delimiter when substituting { DEFAULT_BRANCH } with $BASE_BRANCH. If the default branch name contains a forward slash (e.g., release/main or feature/default), the substitution will fail because the / in the branch name will be interpreted as a sed delimiter. Using a different delimiter like | or # would handle this edge case.

Fix in Cursor Fix in Web

echo "Repository empty status: $IS_EMPTY"
shell: bash
env:
GH_TOKEN: ${{ secrets.ONBOARDING_TOKEN }}
Copy link

Choose a reason for hiding this comment

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

Bug: Opt-out file check documented but never implemented

The PR body template instructs users to add a .github/no-security-scanner file to prevent future onboarding attempts, but the workflow never checks for this file's existence. The onboarding will proceed regardless of whether a team has opted out, making the documented opt-out mechanism non-functional.

Additional Locations (1)

Fix in Cursor Fix in Web

run: |
if [ "${{ github.event_name }}" = "repository_dispatch" ]; then
ORG="${{ github.event.client_payload.organization }}"
REPO_NAME="${{ github.event.client_payload.repository }}"
Copy link

Choose a reason for hiding this comment

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

Bug: Script injection via unsanitized repository_dispatch payload

The workflow directly interpolates github.event.client_payload.organization and github.event.client_payload.repository into shell commands using ${{ }} syntax. Since repository_dispatch payloads can be controlled by external actors (anyone with a token that has write access), a malicious payload containing shell metacharacters like backticks or $() would execute arbitrary commands during workflow runs. This is a documented GitHub Actions script injection vulnerability pattern. Values should be passed via environment variables rather than direct interpolation.

Fix in Cursor Fix in Web

REPO_NAME="${{ github.event.client_payload.repository }}"
REPO="$ORG/$REPO_NAME"
else
REPO="${{ inputs.organization }}/${{ inputs.repository }}"
Copy link

Choose a reason for hiding this comment

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

Bug: Shell command injection via unsanitized user inputs

The workflow directly interpolates user-controlled values from github.event.client_payload.organization, github.event.client_payload.repository, inputs.organization, and inputs.repository into shell commands using ${{ }} syntax. This is a known GitHub Actions security vulnerability allowing shell command injection. The repository_dispatch event's client_payload can be sent by anyone with repository access, and malicious values like foo; malicious_command would execute arbitrary commands. The safer approach is to pass these values through environment variables.

Fix in Cursor Fix in Web

# Copy the security scanner workflow template and replace placeholders
sed "s/{ DEFAULT_BRANCH }/$BASE_BRANCH/g" \
../scanner-repo/.github/templates/security-code-scanner.yml \
> .github/workflows/security-code-scanner.yml
Copy link

Choose a reason for hiding this comment

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

Bug: Sed command breaks on branch names containing slashes

The sed command uses / as the delimiter when replacing { DEFAULT_BRANCH } with $BASE_BRANCH. If the default branch name contains a / character (e.g., release/main or develop/stable), the sed substitution will fail or produce incorrect output because the / in the branch name will be interpreted as a delimiter boundary.

Fix in Cursor Fix in Web


1. **Add a comment on this PR** explaining why your team is opting out
2. **Close this PR** to prevent auto-merge
3. **Add a `.github/no-security-scanner` file** to your repository to prevent future onboarding attempts
Copy link

Choose a reason for hiding this comment

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

Bug: Opt-out file documented but never checked in workflow

The PR body template instructs teams to add a .github/no-security-scanner file to "prevent future onboarding attempts", but the workflow never actually checks for this file before proceeding with onboarding. This means the documented opt-out mechanism doesn't work - repositories that have added the file will still receive onboarding PRs.

Additional Locations (1)

Fix in Cursor Fix in Web

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.

2 participants