> adobe-policy-guardrails

Implement Adobe-specific lint rules, CI policy checks, and runtime guardrails covering credential scanning (p8_ patterns), Firefly content policy pre-screening, PDF Services quota enforcement, and OAuth scope validation. Trigger with phrases like "adobe policy", "adobe lint", "adobe guardrails", "adobe eslint", "adobe content policy".

fetch
$curl "https://skillshub.wtf/jeremylongshore/claude-code-plugins-plus-skills/adobe-policy-guardrails?format=md"
SKILL.mdadobe-policy-guardrails

Adobe Policy & Guardrails

Overview

Automated policy enforcement for Adobe integrations: credential pattern scanning (Adobe OAuth secrets use p8_ prefix), Firefly content policy pre-screening, PDF Services quota guardrails, and OAuth scope validation.

Prerequisites

  • ESLint configured in project
  • CI/CD pipeline (GitHub Actions)
  • Understanding of Adobe credential patterns

Instructions

Guardrail 1: Adobe Credential Pattern Scanner

Adobe OAuth Server-to-Server secrets follow the p8_ prefix pattern:

# .github/workflows/adobe-security.yml
name: Adobe Security Scan
on: [push, pull_request]
jobs:
  credential-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Scan for Adobe credential patterns
        run: |
          EXIT_CODE=0

          # Adobe OAuth client secrets (p8_ prefix)
          if grep -rE "p8_[A-Za-z0-9_-]{20,}" --include="*.ts" --include="*.js" --include="*.py" --include="*.json" --include="*.yaml" --include="*.yml" . 2>/dev/null | grep -v node_modules | grep -v '.git'; then
            echo "::error::Adobe client_secret pattern (p8_) found in source code"
            EXIT_CODE=1
          fi

          # Adobe IMS access tokens (JWT format)
          if grep -rE "eyJ[A-Za-z0-9_-]{100,}\.[A-Za-z0-9_-]{100,}" --include="*.ts" --include="*.js" . 2>/dev/null | grep -v node_modules | grep -v '.git' | grep -v '\.test\.' | grep -v '__mock'; then
            echo "::warning::Potential Adobe access token found in source (may be test fixture)"
          fi

          # Org IDs (format: HEXSTRING@AdobeOrg)
          if grep -rE "[A-F0-9]{24}@AdobeOrg" --include="*.ts" --include="*.js" --include="*.json" . 2>/dev/null | grep -v node_modules | grep -v '.git' | grep -v '.env.example'; then
            echo "::warning::Adobe Org ID found in source — consider using env var"
          fi

          exit $EXIT_CODE

Guardrail 2: Firefly Content Policy Pre-Screener

// src/adobe/guardrails/content-policy.ts
// Pre-screen prompts before sending to Firefly API to avoid wasted credits

interface ContentPolicyResult {
  allowed: boolean;
  violations: string[];
  suggestions: string[];
}

const CONTENT_RULES = [
  {
    name: 'real-people',
    pattern: /\b(photo of|portrait of|picture of)\s+(a\s+)?(real|actual|specific)\s+(person|man|woman|child)/i,
    message: 'Firefly cannot generate images of specific real people',
    suggestion: 'Use generic descriptions like "a professional in a business suit"',
  },
  {
    name: 'trademarks',
    pattern: /\b(nike|adidas|apple|google|microsoft|disney|marvel|coca.?cola|pepsi|starbucks|mcdonalds)\b/i,
    message: 'Firefly will reject prompts containing brand trademarks',
    suggestion: 'Use generic descriptions like "athletic shoes" or "tech company logo style"',
  },
  {
    name: 'explicit-content',
    pattern: /\b(nude|naked|explicit|pornograph|gore|violent|bloody|graphic death)\b/i,
    message: 'Firefly rejects explicit or violent content',
    suggestion: 'Use appropriate imagery descriptions',
  },
  {
    name: 'celebrity',
    pattern: /\b(celebrity|famous|actor|actress|politician|president|singer|musician)\s+(name|like|resembling)/i,
    message: 'Firefly cannot generate images of identifiable celebrities',
    suggestion: 'Describe the style or aesthetic without naming individuals',
  },
];

export function screenFireflyPrompt(prompt: string): ContentPolicyResult {
  const violations: string[] = [];
  const suggestions: string[] = [];

  for (const rule of CONTENT_RULES) {
    if (rule.pattern.test(prompt)) {
      violations.push(`[${rule.name}] ${rule.message}`);
      suggestions.push(rule.suggestion);
    }
  }

  return {
    allowed: violations.length === 0,
    violations,
    suggestions,
  };
}

// Usage in API layer
export function guardFireflyPrompt(prompt: string): void {
  const result = screenFireflyPrompt(prompt);
  if (!result.allowed) {
    throw new Error(
      `Firefly content policy pre-check failed:\n` +
      result.violations.join('\n') +
      '\n\nSuggestions:\n' +
      result.suggestions.join('\n')
    );
  }
}

Guardrail 3: PDF Services Quota Enforcement

// src/adobe/guardrails/pdf-quota.ts
// Enforce PDF Services monthly transaction limits

class PdfQuotaGuard {
  private monthlyLimit: number;
  private transactionsUsed: number = 0;
  private monthStart: Date;

  constructor(tier: 'free' | 'paid' = 'free') {
    this.monthlyLimit = tier === 'free' ? 500 : Infinity;
    this.monthStart = new Date(new Date().getFullYear(), new Date().getMonth(), 1);
  }

  check(): { allowed: boolean; remaining: number; warning: boolean } {
    // Reset counter on new month
    const now = new Date();
    if (now.getMonth() !== this.monthStart.getMonth()) {
      this.transactionsUsed = 0;
      this.monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
    }

    const remaining = this.monthlyLimit - this.transactionsUsed;
    return {
      allowed: remaining > 0,
      remaining,
      warning: remaining < this.monthlyLimit * 0.2,
    };
  }

  record(): void {
    const status = this.check();
    if (!status.allowed) {
      throw new Error(`PDF Services quota exhausted (${this.monthlyLimit} transactions/month)`);
    }
    this.transactionsUsed++;
    if (status.warning) {
      console.warn(`PDF Services: ${status.remaining - 1} transactions remaining this month`);
    }
  }
}

export const pdfQuota = new PdfQuotaGuard(
  process.env.ADOBE_PDF_TIER === 'paid' ? 'paid' : 'free'
);

Guardrail 4: OAuth Scope Validation

// Verify that the requested scopes match what the environment should use
function validateAdobeScopes(scopes: string, environment: string): void {
  const scopeList = scopes.split(',').map(s => s.trim());

  // Development should only have minimal scopes
  if (environment === 'development') {
    const prodOnlyScopes = ['ff_apis'];
    const violations = scopeList.filter(s => prodOnlyScopes.includes(s));
    if (violations.length > 0) {
      console.warn(`Adobe scope warning: ${violations.join(', ')} should not be in development`);
    }
  }

  // Required scopes that should always be present
  const required = ['openid', 'AdobeID'];
  const missing = required.filter(s => !scopeList.includes(s));
  if (missing.length > 0) {
    throw new Error(`Adobe required scopes missing: ${missing.join(', ')}`);
  }
}

Guardrail 5: Runtime Operation Guard

// Prevent dangerous operations based on environment
const BLOCKED_IN_PROD: Record<string, string> = {
  'delete-all-assets': 'Mass deletion blocked in production',
  'reset-quota-counter': 'Quota reset blocked in production',
  'use-test-credentials': 'Test credentials blocked in production',
};

function guardAdobeOperation(operation: string): void {
  const isProd = process.env.NODE_ENV === 'production';
  if (isProd && BLOCKED_IN_PROD[operation]) {
    throw new Error(`BLOCKED: ${BLOCKED_IN_PROD[operation]}`);
  }
}

Output

  • CI secret scanning for Adobe credential patterns (p8_, JWTs, Org IDs)
  • Firefly prompt pre-screening avoiding wasted credits on policy violations
  • PDF Services quota enforcement with monthly tracking
  • OAuth scope validation per environment
  • Runtime operation guards for production safety

Error Handling

IssueCauseSolution
Secret scan false positiveTest fixture contains patternExclude test dirs from scan
Prompt wrongly rejectedPattern too broadRefine regex; allow legitimate uses
Quota counter resetServer restartPersist counter in Redis/DB
Scope validation failsWrong env varCheck NODE_ENV and ADOBE_SCOPES

Resources

Next Steps

For architecture blueprints, see adobe-architecture-variants.

┌ stats

installs/wk0
░░░░░░░░░░
github stars1.7K
██████████
first seenMar 23, 2026
└────────────

┌ repo

jeremylongshore/claude-code-plugins-plus-skills
by jeremylongshore
└────────────