DEV Community

Manage Secret Scanning Custom Patterns as Code With a Safe REST Sync

REST API Management for Secret Scanning Custom Patterns

GitHub's July 13, 2026 changelog lists REST API management for secret scanning custom patterns. That makes a reviewed configuration-as-code workflow possible.

Primary source: GitHub Changelog archive, July 2026. Follow the July 13 entry to the current REST documentation before implementation. The transport below is an unexecuted design. Endpoint paths, payload fields, permissions, pagination, and plan availability must come from the linked official API reference-not from guessed examples.

Define the Sync Contract

A safe synchronizer should:

  • read desired patterns from version control
  • fetch the remote collection
  • match each pattern by a stable identity
  • emit create, update, unchanged, and delete actions
  • refuse deletion unless explicitly enabled
  • apply only after the plan is reviewed
patterns.json -> normalize -> diff remote -> plan.json -> approval -> apply

Keep API-specific payloads opaque to the diff engine:

{
  "patterns": [
    {
      "stableKey": "internal-service-token-v1",
      "remoteId": "SET_AFTER_CREATION",
      "payload": {
        "REPLACE_WITH_DOCUMENTED_FIELD": "REPLACE_WITH_REVIEWED_VALUE"
      }
    }
  ],
  "allowDelete": false
}

Placeholders are deliberate. A secret detector's regex fields and matching semantics are security contracts and should never be invented from a blog post.

Build a Deterministic Planner

export function plan(desired, current) {
  const remote = new Map(current.map(x => [x.id, x]));
  const changes = [];

  for (const item of desired.patterns) {
    if (!item.remoteId) {
      changes.push({ action: "create", key: item.stableKey });
      continue;
    }

    const found = remote.get(item.remoteId);
    if (!found) throw new Error(`Missing remote pattern ${item.remoteId}`);

    const same =
      JSON.stringify(canonical(found)) ===
      JSON.stringify(canonical(item.payload));
    changes.push({
      action: same ? "unchanged" : "update",
      key: item.stableKey
    });
    remote.delete(item.remoteId);
  }

  for (const orphan of remote.values()) {
    changes.push({ action: "delete", id: orphan.id });
  }

  return changes;
}

canonical() should compare only documented mutable fields, sorted consistently. Server-generated values otherwise create endless drift.

Run planning with read permission in pull requests. Put apply behind a protected environment and a separate write credential. Never print tokens or full secret-like fixture values.

Fail Closed on Ambiguity

Renaming can look like create plus delete. Pagination can hide remote resources. API normalization can look like drift. Any of these should stop apply.

Require explicit approval for deletion and record:

  • pattern owner and purpose
  • positive, negative, boundary, and high-volume synthetic fixtures
  • known false positives
  • documented endpoint and API version
  • rollback procedure
  • planned remote ID

The sync does not prove a regular expression is safe or effective. It does not replace GitHub's pattern testing facilities, historical scans, or review of reduced coverage. Its value is the delivery contract: declarative state, deterministic planning, non-destructive defaults, separated credentials, and an auditable apply step.

Comments

No comments yet. Start the discussion.