Skip to content

Conversation

@Qbandev
Copy link
Contributor

@Qbandev Qbandev commented Aug 26, 2025

What is the current state of things and why does it need to change?

Currently, the RCA (Root Cause Analysis) label removal process requires manual intervention across 4 MetaMask repositories. When teams submit RCAs via Google Forms, someone needs to:

  • Check the Google Sheets for new RCA submissions
  • Find the corresponding GitHub issues
  • Manually remove the RCA-needed labels

This manual process is time-consuming, error-prone, and creates unnecessary overhead for teams managing post-incident workflows.

What is the solution your changes offer and how does it work?

This PR introduces a reusable GitHub workflow that automates the RCA label removal process across multiple repositories.

📁 Files Changed:

  • Added: .github/scripts/remove-rca-needed-label-sheets.ts - Self-contained TypeScript script (414 lines)
  • Added: .github/workflows/remove-rca-needed-label-sheets.yml - Reusable workflow (76 lines)
  • Modified: .depcheckrc.json - Ignore runtime dependencies

🎯 Key Features:

  • Automated Process: Reads Google Sheets RCA submissions and removes labels from matching GitHub issues
  • Reusable Pattern: Any MetaMask repository can consume this workflow (like create-release-pr.yml)
  • Safety First: Dry-run mode, comprehensive error handling, continues on individual failures
  • Self-Contained: No repository-specific dependencies

🔧 Technical Implementation:

Core Functionality:

  • Connects to Google Sheets API to fetch RCA submissions
  • Queries GitHub GraphQL API for issues with RCA-needed label
  • Dynamically detects "Issue Number" column in sheets
  • Removes labels via GitHub REST API

Security & Best Practices:

  • GraphQL variables prevent injection attacks
  • Exact npm version pinning (--save-exact)
  • Defensive programming with null checking
  • HTTP status codes as enum (no magic numbers)
  • Fails fast on configuration errors

Dependency Strategy:

  • Runtime packages installed locally in scripts directory during workflow execution
  • Uses npm install --no-save to avoid modifying checked-in files
  • Not in package.json to avoid Socket Security alerts
  • .depcheckrc.json configured to ignore these dependencies

📋 How to Use:

Repositories can consume this workflow by creating a simple workflow file:

name: Remove RCA-needed Label

on:
  schedule:
    - cron: '0 */6 * * *'  # Every 6 hours
  workflow_dispatch:
    inputs:
      dry_run:
        description: 'Run in dry-run mode'
        required: false
        default: 'false'
        type: choice
        options: ['true', 'false']
      spreadsheet_id:
        description: 'Google Spreadsheet ID (optional - for testing)'
        required: false
        default: ''  # Empty means use repo's default

jobs:
  remove-rca-labels:
    uses: MetaMask/github-tools/.github/workflows/remove-rca-needed-label-sheets.yml@main
    with:
      dry_run: ${{ github.event.inputs.dry_run || 'false' }}
      spreadsheet_id: ${{ github.event.inputs.spreadsheet_id || 'YOUR_REPO_SHEET_ID' }}  # Required
    secrets:
      github-token: ${{ secrets.GITHUB_TOKEN }}
      google-application-creds-base64: ${{ secrets.GCP_RLS_SHEET_ACCOUNT_BASE64 }}

Note: Replace YOUR_REPO_SHEET_ID with your repository's Google Sheet ID. The input allows override for testing purposes.

Testing & Quality

Validated through:

  • Mock testing for workflow behavior
  • Dry-run mode for safe testing
  • All linting and dependency checks passing
  • No Socket Security blocking alerts

Live testing in fork repository:

Security improvements from Copilot code review:

  • GraphQL injection prevention
  • Exact version pinning for supply chain security
  • Comprehensive null checking and defensive programming

Related Issues

Configuration Required

Before using this workflow, repositories must:

  1. Ensure the Google Sheet is shared with the service account
  2. Have the GCP_RLS_SHEET_ACCOUNT_BASE64 secret configured
  3. Configure appropriate spreadsheet ID if different from the example in the PR description

@socket-security
Copy link

socket-security bot commented Aug 26, 2025

No dependency changes detected. Learn more about Socket for GitHub.

👍 No dependency changes detected in pull request

Reverting package.json and yarn.lock to their state from origin/main branch
to ensure consistency with the main branch. These files were modified in
previous commits but the changes are not needed for the RCA workflow implementation.
Added missing newline at end of file to comply with Prettier formatting rules
Applied Prettier code formatting to ensure consistency with project standards
@Qbandev Qbandev requested a review from Copilot August 26, 2025 12:11

This comment was marked as outdated.

This comment was marked as outdated.

jluque0101
jluque0101 previously approved these changes Aug 26, 2025
@jluque0101
Copy link

hey @Qbandev overall lgtm I wonder if has it been run in a test repo or similar?

- Add dynamic column detection for Issue Number field with fallback
- Use optional chaining for error handling to prevent undefined access
- Add comment explaining the default spreadsheet ID is public and shared
- Improve error message handling throughout the script
- Replace process.exit() with early returns after core.setFailed()
- Add @ts-ignore comments for process.env and Buffer usage
- Improve error handling consistency throughout the script
- core.setFailed() already handles exit codes properly
- Remove default spreadsheet ID from reusable workflow
- Make spreadsheet_id a required input parameter
- Ensures each consuming repository explicitly configures their RCA sheet
- Prevents accidental use of wrong spreadsheet across repositories
@Qbandev Qbandev requested a review from Copilot August 27, 2025 07:23

This comment was marked as outdated.

- Remove import of GitHub type from internal @actions/github/lib/utils
- Use ReturnType<typeof getOctokit> instead of InstanceType<typeof GitHub>
- Simplify octokit instantiation by removing explicit type annotation
- Use only public API from @actions/github for better stability
@Qbandev Qbandev requested a review from Copilot August 27, 2025 07:53

This comment was marked as outdated.

- Add HTTP_NOT_FOUND constant to replace magic number 404
- Remove fallback to hardcoded column index 4
- Fail fast when 'Issue Number' column is not found in sheet headers
- Better error message to guide users when sheet structure is incorrect
- Improves code clarity and maintainability
@Qbandev Qbandev requested a review from Copilot August 27, 2025 08:12

This comment was marked as outdated.

- Use consistent error handling with String(error) fallback
- Optimize npm install by combining all packages in one command
- Use stricter regex pattern ^#?(\d+)$ for issue number extraction
- Trim whitespace before regex matching for better reliability
- Use range A:Z to cover possible changes
@Qbandev Qbandev requested a review from Copilot August 27, 2025 08:22
- Replace single HTTP_NOT_FOUND constant with HttpStatusCode enum
- Add comprehensive JSDoc documentation for RcaFormResponse interface
- Move SheetsV4 type alias to top of file with other type definitions
- Better code organization with all types grouped at the top
@Qbandev Qbandev requested a review from Copilot August 27, 2025 09:07

This comment was marked as outdated.

- Pin npm package versions for security and reproducibility
- Use caret (^) versioning to allow patch and minor updates
- Extract PAGE_SIZE and LABEL_NAME as constants in GraphQL query
- Document PAGE_SIZE as GitHub API maximum (100)
- Reuse existing RCA_NEEDED_LABEL constant for consistency
@Qbandev Qbandev requested a review from Copilot August 27, 2025 09:20

This comment was marked as outdated.

- Use exact versions (no caret) for npm packages in CI for better security
- Add --save-exact flag to prevent version drift
- Refactor GraphQL query to use proper variables instead of string interpolation
- Prevents potential GraphQL injection vulnerabilities
- Add defensive null checks for toString() calls
- Fix log message consistency to use extracted issue number
- Improve defensive programming throughout
@Qbandev Qbandev requested a review from Copilot August 27, 2025 09:35

This comment was marked as outdated.

Qbandev added 10 commits August 27, 2025 12:25
- Install runtime dependencies in /tmp directory
- Remove unnecessary checkout-and-setup action
- Use simple Node.js setup instead
- Fixes npm/Yarn patch protocol conflicts
The package version doesn't exist and isn't needed by the script
The consuming repository's tsconfig extends packages that aren't installed
in our temporary directory, causing tsx to fail. Using --no-config prevents
tsx from looking for tsconfig files.
Use npx to invoke tsx with correct argument passing
…irectories

Create a minimal tsconfig in temp directory to stop tsx from finding
the consuming repository's tsconfig which extends unavailable packages
Checkout consuming repository first, then github-tools as subdirectory
to ensure github-tools files aren't deleted by the second checkout
Remove overengineered temporary directory setup and use npx's built-in
package installation capabilities instead. This is much cleaner and
achieves the same result with less complexity.
Create a minimal tsconfig.json in /tmp and use TSX_TSCONFIG_PATH
environment variable to prevent tsx from using the consuming
repository's tsconfig that may have incompatible extensions.
Switch to a simpler approach that installs packages locally
in the scripts directory, ensuring tsx can find all required
modules through standard Node.js module resolution.
Added successful test run links demonstrating:
- Test 1: Correctly preserves label when issue not in RCA sheet
- Test 2: Successfully removes label when issue is in RCA sheet
@Qbandev Qbandev requested review from Copilot and jluque0101 August 27, 2025 12:22
This file should not be committed to the repository as it contains
PR-specific documentation that belongs in the GitHub PR interface,
not in the codebase.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces an automated GitHub Actions workflow to remove "RCA-needed" labels from GitHub issues once corresponding Root Cause Analysis (RCA) submissions are found in Google Sheets, eliminating the need for manual label management across MetaMask repositories.

Key changes:

  • Added a reusable GitHub workflow that integrates Google Sheets API with GitHub GraphQL/REST APIs
  • Created a TypeScript script that fetches RCA submissions from Google Sheets and removes labels from matching closed GitHub issues
  • Updated dependency configuration to handle runtime-installed packages

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
.github/workflows/remove-rca-needed-label-sheets.yml Reusable workflow that sets up environment and executes the RCA label removal script
.github/scripts/remove-rca-needed-label-sheets.ts TypeScript script containing core logic for Google Sheets integration and GitHub label management
.depcheckrc.json Updated to ignore runtime-installed dependencies that aren't in package.json
pr-description.md Documentation file explaining the feature implementation and usage

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

The null check on line 282 already ensures issueNumberValue is not null,
so the optional chaining operators on toString() and trim() are unnecessary.

As noted by Copilot code review.
@Qbandev Qbandev changed the title feat: add remove rca gha feat(INFRA-2864): add remove rca gha Aug 27, 2025
Copy link
Contributor

@XxdpavelxX XxdpavelxX left a comment

Choose a reason for hiding this comment

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

Looks good to me, but lets get confirmation from someone on the mobile team that this does what they want.

@Qbandev Qbandev merged commit d354252 into main Aug 27, 2025
18 checks passed
@Qbandev Qbandev deleted the feat(INFRA-2864)/rca-needed-label-removal branch August 27, 2025 15:09
github-merge-queue bot pushed a commit to MetaMask/metamask-extension that referenced this pull request Aug 28, 2025
## **Description**

This PR integrates the automated `RCA-needed` label removal workflow
from the [github-tools
repository](https://github.com/MetaMask/github-tools). The workflow
automatically removes the `RCA-needed` label from GitHub issues once a
Root Cause Analysis (RCA) has been submitted via Google Forms.

The solution consumes a **reusable workflow** from `github-tools` that:
- Reads RCA submissions from a Google Sheet
- Removes the label from matching issues
- Eliminates manual tracking and reduces noise in issue management

The workflow runs automatically every 6 hours. It integrates with the
existing RCA process established in INFRA-2406 and INFRA-2510.

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/35371?quickstart=1)

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: INFRA-2864

## **Dependencies**

> [!NOTE]
> This PR depends on the `github-tools` PR being merged first [feat: add
remove rca gha](MetaMask/github-tools#109) ✅
**MERGED**

## **Files Changed**

This PR adds only one file:
- `.github/workflows/remove-rca-needed-label-sheets.yml` - Workflow that
consumes the reusable workflow from github-tools

Note: The core implementation (script and reusable workflow) is located
in [github-tools](https://github.com/MetaMask/github-tools) repository.

## **Implementation Details**

### **Reusable Workflow Integration**

This PR adds a simple workflow file
(`.github/workflows/remove-rca-needed-label-sheets.yml`) that consumes
the reusable workflow from `github-tools`:

```yaml
on:
  schedule:
    - cron: '0 */6 * * *'  # Run every 6 hours

jobs:
  remove-rca-labels:
    name: Remove RCA-needed Labels
    uses: MetaMask/github-tools@d354252
    with:
      spreadsheet_id: '1Y16QEnDwZuR3DAQIe3T5LTWy1ye07GNYqxIei_cMg24'
      sheet_name: 'Form Responses 1'
    secrets:
      github-token: ${{ secrets.GITHUB_TOKEN }}
      google-application-creds-base64: ${{ secrets.GCP_RLS_SHEET_ACCOUNT_BASE64 }}
```

### Testing Completed
- ✅ Reusable workflow tested in `github-tools` repository
- ✅ Successfully tested in fork repository: [Test Run
#1](https://github.com/consensys-test/metamask-extension-test-fork/actions/runs/17266390093)
and [Test Run
#2](https://github.com/consensys-test/metamask-extension-test-fork/actions/runs/17266424658)

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants