Skip to main content
skill GitHub Copilot official · GitHub

salesforce-apex-quality — GitHub Copilot skill: Apex quality

Checks Apex for governor-limit risks, security gaps, and missing tests. Use it when GitHub Copilot reviews or generates Salesforce classes, triggers, and test code.

Install into GitHub Copilot · Skills CLI (Vercel) All methods and platforms ↓
npx skills add github/awesome-copilot --skill salesforce-apex-quality
Open on GitHub

What salesforce-apex-quality does

This skill reviews Apex classes, trigger handlers, batch jobs, and test classes. It flags SOQL or DML inside loops, requires an explicit sharing declaration, checks CRUD/FLS enforcement, and prevents user input from being joined into dynamic SOQL. It also asks for current Apex idioms and PNB coverage across Positive, Negative, and Bulk paths.

The rules cover trigger structure as well: one trigger per object, a small trigger body, and reuse of an existing framework when the project already has one. Bulk tests should process 200–251 records, while async work should use Test.startTest() and Test.stopTest(). The modern syntax guidance targets API 62.0 / Winter '25+.

Install it when GitHub Copilot is writing or reviewing Salesforce Apex. Check the API version first if the project predates the listed modern syntax.

What it helps with

  • catch SOQL and DML inside loops
  • enforce CRUD/FLS before user-facing data access
  • block user-controlled SOQL injection
  • cover Positive, Negative, and Bulk test paths
  • review Salesforce trigger architecture

Example prompts for the agent

  • Review this Apex class for governor-limit risks, CRUD/FLS, and SOQL injection.
  • Generate an AccountService test class with Positive, Negative, and Bulk paths.
  • Check this trigger handler for sharing model and bulk-safety issues.

How to install salesforce-apex-quality

1Skills CLI (Vercel)

npx skills add github/awesome-copilot --skill salesforce-apex-quality

2GitHub CLI

gh skill install github/awesome-copilot salesforce-apex-quality

3Manually: put the files in place

.github/skills/salesforce-apex-quality/SKILL.md

From the same set554

The whole set →
git-commit official github This skill reviews Git changes, stages related files, and creates Conventional Commits. Use it when you want an agent to make one commit or split work into separate commits. GitHub Copilot 47,165installs excalidraw-diagram-generator official github Turn a plain-language description into an Excalidraw diagram. Useful for mapping processes, system structure, and relationships between entities. GitHub Copilot 31,639installs multi-stage-dockerfile official github This skill guides GitHub Copilot in writing multi-stage Dockerfiles for different languages and frameworks. Use it when the final runtime image should contain fewer build dependencies. GitHub Copilot 29,688installs documentation-writer official github Skill that turns the agent into a technical writer following the Diátaxis framework: tutorials, how-to guides, reference, and explanation. Proposes structure before writing. GitHub Copilot 27,757installs prd official github Turns a feature idea into a structured PRD with user stories, technical requirements, and risks. Use it when planning a software feature or an AI-powered one. GitHub Copilot 24,035installs refactor official github This skill reshapes existing code without changing its external behavior. Use it for gradual cleanup of large functions, duplication, weak types, and code smells. GitHub Copilot 22,321installs java-springboot official github Gives GitHub Copilot Spring Boot development practices, from project layout to tests and security. Use it when writing or reviewing Java application code. GitHub Copilot 21,272installs create-readme official github This skill reviews a project and creates a structured README.md. Use it when the repository needs clear documentation based on its actual files and code. GitHub Copilot 19,081installs

Similar

visual-edit-precision Adit Jain Skill for targeted UI changes when you show elements on a screenshot or point them out in code. Edits only what you selected, without refactoring the entire component. Claude Code CX Codex Cursor 2,800installs swiftui-ui-patterns official OpenAI This skill helps build and refactor SwiftUI interfaces, from navigation and state to layouts and controls. Use it for new screens or changes to an existing project. CX Codex GP ChatGPT 114installs improve-codebase-architecture Matt Pocock This skill scans a codebase for architectural friction, then builds a visual HTML report with refactoring candidates. Use it before a deeper architecture review. Claude Code 1,163,035installs tdd Matt Pocock Guides the red-green TDD loop: ensures tests are written first, keep them at public interfaces, and avoid coupling to implementation details. Claude Code 1,141,062installs triage Matt Pocock This skill moves issues and external PRs through triage states, verification, and agent briefs. It fits maintainers managing an issue queue. Claude Code 990,453installs codebase-design Matt Pocock This skill helps design modules with small interfaces and hidden complexity. Use it when refactoring code, choosing a seam, or making tests easier to write. Claude Code 850,344installs code-review Matt Pocock Reviews changes from a chosen reference point against repository standards and the originating spec. Use it for a branch, PR, or work in progress. Claude Code 789,521installs implement Matt Pocock Implements work from a specification or tickets, following a test-driven flow and ending with review and a commit. Use it when a coding task needs a defined delivery routine. Claude Code 774,700installs

Questions about salesforce-apex-quality

How do I install salesforce-apex-quality in GitHub Copilot?

Run npx skills add github/awesome-copilot --skill salesforce-apex-quality. The skill is then available at .github/skills/salesforce-apex-quality/SKILL.md. You can also run gh skill install github/awesome-copilot salesforce-apex-quality.

What does salesforce-apex-quality do?

It checks Apex for governor-limit risks, sharing declarations, CRUD/FLS, SOQL injection, trigger structure, and PNB test coverage. It applies to classes, triggers, batch jobs, and test classes.

Which Apex API version is used for the modern idioms?

The rules list API 62.0 / Winter '25+ for features such as optional chaining, null coalescing, and WITH USER_MODE.

Source text

SKILL.md · MIT
---
name: salesforce-apex-quality
description: 'Apex code quality guardrails for Salesforce development. Enforces bulk-safety rules (no SOQL/DML in loops), sharing model requirements, CRUD/FLS security, SOQL injection prevention, PNB test coverage (Positive / Negative / Bulk), and modern Apex idioms. Use this skill when reviewing or generating Apex classes, trigger handlers, batch jobs, or test classes to catch governor limit risks, security gaps, and quality issues before deployment.'
---

# Salesforce Apex Quality Guardrails

Apply these checks to every Apex class, trigger, and test file you write or review.

## Step 1 — Governor Limit Safety Check

Scan for these patterns before declaring any Apex file acceptable:

### SOQL and DML in Loops — Automatic Fail

```apex
// ❌ NEVER — causes LimitException at scale
for (Account a : accounts) {
    List<Contact> contacts = [SELECT Id FROM Contact WHERE AccountId = :a.Id]; // SOQL in loop
    update a; // DML in loop
}

// ✅ ALWAYS — collect, then query/update once
Set<Id> accountIds = new Map<Id, Account>(accounts).keySet();
Map<Id, List<Contact>> contactsByAccount = new Map<Id, List<Contact>>();
for (Contact c : [SELECT Id, AccountId FROM Contact WHERE AccountId IN :accountIds]) {
    if (!contactsByAccount.containsKey(c.AccountId)) {
        contactsByAccount.put(c.AccountId, new List<Contact>());
    }
    contactsByAccount.get(c.AccountId).add(c);
}
update accounts; // DML once, outside the loop
```

Rule: if you see `[SELECT` or `Database.query`, `insert`, `update`, `delete`, `upsert`, `merge` inside a `for` loop body — stop and refactor before proceeding.

## Step 2 — Sharing Model Verification

Every class must declare its sharing intent explicitly. Undeclared sharing inherits from the caller — unpredictable behaviour.

| Declaration | When to use |
|---|---|
| `public with sharing class Foo` | Default for all service, handler, selector, and controller classes |
| `public without sharing class Foo` | Only when the class must run elevated (e.g. system-level logging, trigger bypass). Requires a code comment explaining why. |
| `public inherited sharing class Foo` | Framework entry points that should respect the caller's sharing context |

If a class does not have one of these three declarations, **add it before writing anything else**.

## Step 3 — CRUD / FLS Enforcement

Apex code that reads or writes records on behalf of a user must verify object and field access. The platform does **not** enforce FLS or CRUD automatically in Apex.

```apex
// Check before querying a field
if (!Schema.sObjectType.Contact.fields.Email.isAccessible()) {
    throw new System.NoAccessException();
}

// Or use WITH USER_MODE in SOQL (API 56.0+)
List<Contact> contacts = [SELECT Id, Email FROM Contact WHERE AccountId = :accId WITH USER_MODE];

// Or use Database.query with AccessLevel
List<Contact> contacts = Database.query('SELECT Id, Email FROM Contact', AccessLevel.USER_MODE);
```

Rule: any Apex method callable from a UI component, REST endpoint, or `@InvocableMethod` **must** enforce CRUD/FLS. Internal service methods called only from trusted contexts may use `with sharing` instead.

## Step 4 — SOQL Injection Prevention

```apex
// ❌ NEVER — concatenates user input into SOQL string
String soql = 'SELECT Id FROM Account WHERE Name = \'' + userInput + '\'';

// ✅ ALWAYS — bind variable
String soql = [SELECT Id FROM Account WHERE Name = :userInput];

// ✅ For dynamic SOQL with user-controlled field names — validate against a whitelist
Set<String> allowedFields = new Set<String>{'Name', 'Industry', 'AnnualRevenue'};
if (!allowedFields.contains(userInput)) {
    throw new IllegalArgumentException('Field not permitted: ' + userInput);
}
```

## Step 5 — Modern Apex Idioms

Prefer current language features (API 62.0 / Winter '25+):

| Old pattern | Modern replacement |
|---|---|
| `if (obj != null) { x = obj.Field__c; }` | `x = obj?.Field__c;` |
| `x = (y != null) ? y : defaultVal;` | `x = y ?? defaultVal;` |
| `System.assertEquals(expected, actual)` | `Assert.areEqual(expected, actual)` |
| `System.assert(condition)` | `Assert.isTrue(condition)` |
| `[SELECT ... WHERE ...]` with no sharing context | `[SELECT ... WHERE ... WITH USER_MODE]` |

## Step 6 — PNB Test Coverage Checklist

Every feature must be tested across all three paths. Missing any one of these is a quality failure:

### Positive Path
- Expected input → expected output.
- Assert the exact field values, record counts, or return values — not just that no exception was thrown.

### Negative Path
- Invalid input, null values, empty collections, and error conditions.
- Assert that exceptions are thrown with the correct type and message.
- Assert that no records were mutated when the operation should have failed cleanly.

### Bulk Path
- Insert/update/delete **200–251 records** in a single test transaction.
- Assert that all records processed correctly — no partial failures from governor limits.
- Use `Test.startTest()` / `Test.stopTest()` to isolate governor limit counters for async work.

### Test Class Rules
```apex
@isTest(SeeAllData=false)   // Required — no exceptions without a documented reason
private class AccountServiceTest {

    @TestSetup
    static void makeData() {
        // Create all test data here — use a factory if one exists in the project
    }

    @isTest
    static void givenValidInput_whenProcessAccounts_thenFieldsUpdated() {
        // Positive path
        List<Account> accounts = [SELECT Id FROM Account LIMIT 10];
        Test.startTest();
        AccountService.processAccounts(accounts);
        Test.stopTest();
        // Assert meaningful outcomes — not just no exception
        List<Account> updated = [SELECT Status__c FROM Account WHERE Id IN :accounts];
        Assert.areEqual('Processed', updated[0].Status__c, 'Status should be Processed');
    }
}
```

## Step 7 — Trigger Architecture Checklist

- [ ] One trigger per object. If a second trigger exists, consolidate into the handler.
- [ ] Trigger body contains only: context checks, handler invocation, and routing logic.
- [ ] No business logic, SOQL, or DML directly in the trigger body.
- [ ] If a trigger framework (Trigger Actions Framework, ff-apex-common, custom base class) is already in use — extend it. Do not create a parallel pattern.
- [ ] Handler class is `with sharing` unless the trigger requires elevated access.

## Quick Reference — Hardcoded Anti-Patterns Summary

| Pattern | Action |
|---|---|
| SOQL inside `for` loop | Refactor: query before the loop, operate on collections |
| DML inside `for` loop | Refactor: collect mutations, DML once after the loop |
| Class missing sharing declaration | Add `with sharing` (or document why `without sharing`) |
| `escape="false"` on user data (VF) | Remove — auto-escaping enforces XSS prevention |
| Empty `catch` block | Add logging and appropriate re-throw or error handling |
| String-concatenated SOQL with user input | Replace with bind variable or whitelist validation |
| Test with no assertion | Add a meaningful `Assert.*` call |
| `System.assert` / `System.assertEquals` style | Upgrade to `Assert.isTrue` / `Assert.areEqual` |
| Hardcoded record ID (`'001...'`) | Replace with queried or inserted test record ID |

© github · MIT · github/awesome-copilot

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor