Skip to main content 홈 크리에이터 jeremylongshore claude-code-plugins-plus-skills sentry-policy-guardrails
sentry-policy-guardrails Enforce organizational governance and policy guardrails for Sentry usage.
Use when standardizing Sentry configuration across services, enforcing
PII scrubbing, building shared config packages, or auditing drift.
Trigger with phrases like "sentry governance", "sentry policy",
"sentry standards", "enforce sentry config", "sentry compliance".
설치로 이동 Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill sentry-policy-guardrails명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... 이 저장소의 다른 Skills Implement user sign-up and sign-in flows with Clerk.
Use when building authentication UI, customizing sign-in experience,
or implementing OAuth social login.
Trigger with phrases like "clerk sign-in", "clerk sign-up",
"clerk login flow", "clerk OAuth", "clerk social login".
Implement session management and middleware with Clerk.
Use when managing user sessions, configuring route protection,
or implementing token refresh and custom JWT templates.
Trigger with phrases like "clerk session", "clerk middleware",
"clerk route protection", "clerk token", "clerk JWT".
Configure enterprise SSO, role-based access control, and organization management.
Use when implementing SSO integration, configuring role-based permissions,
or setting up organization-level controls.
Trigger with phrases like "clerk SSO", "clerk RBAC",
"clerk enterprise", "clerk roles", "clerk permissions", "clerk organizations".
jeremylongshore
jeremylongshore/claude-code-plugins-plus-skills
GitHub 저장소 열기 name sentry-policy-guardrails description Enforce organizational governance and policy guardrails for Sentry usage.
Use when standardizing Sentry configuration across services, enforcing
PII scrubbing, building shared config packages, or auditing drift.
Trigger with phrases like "sentry governance", "sentry policy",
"sentry standards", "enforce sentry config", "sentry compliance".
allowed-tools Read, Write, Edit, Grep, Glob, Bash(node:*), Bash(npm:*), Bash(npx:*), Bash(curl:*), Bash(grep:*), Bash(git:*) version 1.51.0 license MIT author Jeremy Longshore <jeremy@intentsolutions.io> tags ["saas","sentry","compliance","governance","policy","ci","cost-governance"] compatibility Designed for Claude Code, also compatible with Codex and OpenClaw
Sentry Policy Guardrails
Overview
Organizational governance framework that prevents Sentry configuration drift across multiple services. A shared npm package (@company/sentry-config) wraps Sentry.init() to enforce PII scrubbing, naming conventions, tagging standards, and per-tier trace rate caps. CI checks block policy violations before merge, and a monthly drift audit detects projects that have fallen out of compliance.
Prerequisites
@sentry/node v8+ installed in target services
Internal npm registry available (GitHub Packages, Artifactory, or similar)
Team structure and project ownership defined in Sentry
SENTRY_AUTH_TOKEN with org:read and project:read scopes
Compliance requirements identified (SOC 2, GDPR, HIPAA)
Instructions
Step 1 — Build the Shared Configuration Package
Create @company/sentry-config that wraps Sentry.init() with non-negotiable defaults.
Mandatory PII scrubbing (cannot be bypassed):
import type { Event } from '@sentry/node' ;
const SENSITIVE_HEADERS = [
'authorization' , 'cookie' , 'set-cookie' ,
'x-api-key' , 'x-auth-token' , 'x-csrf-token' ,
];
const PII_PATTERNS = [
{ pattern : /\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{1,7}\b/g , replacement : '[CC_REDACTED]' },
{ pattern : /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g , replacement : '[EMAIL_REDACTED]' },
{ pattern : /\b\d{3}-\d{2}-\d{4}\b/g , : },
];
( ): | {
(event. ?. ) {
( h ) event. . [h];
}
(event. ) event. = (event. );
(event. ?. ) {
( exc event. . ) {
(exc. ) exc. = (exc. );
}
}
event;
}
( ): {
( { pattern, replacement } ) {
str = str. ( (pattern. , pattern. ), replacement);
}
str;
}
replacement
'[SSN_REDACTED]'
export
function
scrubEvent
event : Event
Event
null
if
request
headers
for
const
of
SENSITIVE_HEADERS
delete
request
headers
if
message
message
scrubPII
message
if
exception
values
for
const
of
exception
values
if
value
value
scrubPII
value
return
function
scrubPII
str : string
string
for
const
of
PII_PATTERNS
replace
new
RegExp
source
flags
return
Governed init with naming validation, tag injection, and tier-based caps:
import * as Sentry from '@sentry/node' ;
import { scrubEvent } from './scrubbers' ;
const ENFORCED : Partial <Sentry .NodeOptions > = {
sendDefaultPii : false ,
debug : false ,
maxBreadcrumbs : 50 ,
sampleRate : 1.0 ,
maxValueLength : 500 ,
};
const VALID_ENVS = ['production' , 'staging' , 'development' , 'canary' , 'sandbox' ];
const TIER_TRACE_CAPS : Record <string , number > = { critical : 0.5 , standard : 0.2 , internal : 0.05 };
interface PolicyOptions {
serviceName : string ;
dsn : string ;
version : string ;
tags : { service : string ; team : string ; tier : 'critical' | 'standard' | 'internal' };
environment ?: string ;
tracesSampleRate ?: number ;
beforeSend ?: Sentry .NodeOptions ['beforeSend' ];
}
export function initSentry (opts : PolicyOptions ): void {
if (!opts.dsn ) throw new Error ('@company/sentry-config: dsn required' );
if (!/^[a-z][a-z0-9-]{2,39}$/ .test (opts.serviceName )) {
throw new Error (`Invalid service name "${opts.serviceName} " — use lowercase kebab-case, 3-40 chars` );
}
const env = (opts.environment || process.env .NODE_ENV || 'development' ).toLowerCase ();
if (!VALID_ENVS .includes (env)) {
throw new Error (`Invalid environment "${env} ". Allowed: ${VALID_ENVS.join(', ' )} ` );
}
const tierCap = TIER_TRACE_CAPS [opts.tags .tier ] ?? 0.2 ;
const sha = (process.env .GIT_SHA || process.env .COMMIT_SHA || '' ).substring (0 , 7 );
const release = sha
? `${opts.serviceName} @${opts.version} +${sha} `
: `${opts.serviceName} @${opts.version} ` ;
Sentry .init ({
dsn : opts.dsn ,
environment : env,
release,
serverName : opts.serviceName ,
...ENFORCED ,
debug : env !== 'production' ,
tracesSampleRate : Math .min (opts.tracesSampleRate ?? 0.1 , tierCap),
beforeSend (event, hint ) {
const scrubbed = scrubEvent (event);
if (!scrubbed) return null ;
return opts.beforeSend ? (opts.beforeSend as Function )(scrubbed, hint) : scrubbed;
},
initialScope : {
tags : {
service : opts.tags .service ,
team : opts.tags .team ,
tier : opts.tags .tier ,
deployment : process.env .DEPLOYMENT_ID || 'unknown' ,
region : process.env .AWS_REGION || process.env .GCP_REGION || 'unknown' ,
},
},
});
}
Service usage (two lines to adopt):
import { initSentry } from '@company/sentry-config' ;
initSentry ({
serviceName : 'payments-api' ,
dsn : process.env .SENTRY_DSN !,
version : '2.4.1' ,
tags : { service : 'payments-api' , team : 'payments' , tier : 'critical' },
});
Step 2 — Enforce Compliance via CI Add a GitHub Actions workflow to every service repository that blocks policy violations.
name: Sentry Policy Check
on: [pull_request ]
jobs:
sentry-compliance:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Block hardcoded DSNs
run: |
if grep -rn "https://[a-f0-9]*@.*ingest.*sentry" \
--include="*.ts" --include="*.js" \
--exclude-dir=node_modules --exclude-dir=dist src/; then
echo "::error::Hardcoded Sentry DSN — use SENTRY_DSN env var"
exit 1
fi
- name: Block sendDefaultPii true
run: |
if grep -rn "sendDefaultPii.*true" \
--include="*.ts" --include="*.js" \
--exclude-dir=node_modules src/; then
echo "::error::sendDefaultPii must be false"
exit 1
fi
- name: Block direct Sentry.init calls
run: |
HITS=$(grep -rn "Sentry\.init(" --include="*.ts" --include="*.js" \
--exclude-dir=node_modules --exclude="*sentry-config*" src/ || true)
if [ -n "$HITS" ]; then
echo "::error::Use initSentry() from @company/sentry-config"
echo "$HITS"
exit 1
fi
- name: Verify shared config dependency
run: |
if ! grep -q "@company/sentry-config" package.json; then
echo "::warning::Not using shared Sentry config package"
fi
Optional ESLint rule for IDE feedback:
module .exports = {
meta : { type : 'problem' , messages : { bad : 'Use initSentry() from @company/sentry-config' } },
create (ctx ) {
return {
CallExpression (node) {
if (node.callee .type === 'MemberExpression' &&
node.callee .object .name === 'Sentry' &&
node.callee .property .name === 'init' &&
!ctx.getFilename ().includes ('sentry-config' )) {
ctx.report ({ node, messageId : 'bad' });
}
},
};
},
};
Step 3 — Drift Detection and Cost Governance Monthly drift audit across all Sentry projects:
#!/bin/bash
set -euo pipefail
ORG="${SENTRY_ORG:?required} " TOKEN="${SENTRY_AUTH_TOKEN:?required} "
API="https://sentry.io/api/0"
VIOLATIONS=0
echo "=== Sentry Drift Audit — $(date -u +%Y-%m-%d) ==="
PROJECTS=$(curl -s -H "Authorization: Bearer $TOKEN " \
"$API /organizations/$ORG /projects/?all_projects=1" \
| python3 -c "import json,sys; [print(p['slug']) for p in json.load(sys.stdin)]" )
for P in $PROJECTS ; do
echo "--- $P ---"
curl -s -H "Authorization: Bearer $TOKEN " "$API /projects/$ORG /$P /" \
| python3 -c "
import json, sys, re
p = json.load(sys.stdin)
fails = 0
for label, val in [
('Data Scrubber', p.get('dataScrubber', False)),
('IP Scrubbing', p.get('scrubIPAddresses', False)),
('Naming', bool(re.match(r'^[a-z]+-[a-z0-9]+-[a-z]+$', p['slug']))),
]:
status = 'PASS' if val else 'FAIL'
print(f' [{status}] {label}')
if not val: fails += 1
missing = [f for f in ['password','ssn','credit_card','api_key','secret']
if f not in p.get('sensitiveFields', [])]
if missing:
print(f' [FAIL] Sensitive Fields: missing {missing}')
fails += 1
else:
print(f' [PASS] Sensitive Fields')
sys.exit(1 if fails else 0)
" || VIOLATIONS=$((VIOLATIONS + 1 ))
done
echo ""
echo "Projects with violations: $VIOLATIONS / $(echo "$PROJECTS " | wc -l) "
[ "$VIOLATIONS " -eq 0 ] && echo "STATUS: ALL COMPLIANT" || { echo "STATUS: DRIFT DETECTED" ; exit 1; }
Per-team cost quotas (run weekly):
const QUOTAS = [
{ team : 'payments' , errors : 10_000 , transactions : 50_000 },
{ team : 'platform' , errors : 20_000 , transactions : 100_000 },
{ team : 'growth' , errors : 15_000 , transactions : 200_000 },
{ team : 'infrastructure' , errors : 8_000 , transactions : 20_000 },
];
async function main ( ) {
const org = process.env .SENTRY_ORG !, token = process.env .SENTRY_AUTH_TOKEN !;
const headers = { Authorization : `Bearer ${token} ` };
const stats = await fetch (
`https://sentry.io/api/0/organizations/${org} /stats_v2/?` +
'field=sum(quantity)&groupBy=project&groupBy=category&interval=1d&statsPeriod=30d' ,
{ headers },
).then (r => r.json ()) as any ;
const projects = await fetch (
`https://sentry.io/api/0/organizations/${org} /projects/?all_projects=1` ,
{ headers },
).then (r => r.json ()) as any [];
const teamOf = new Map (projects.map ((p : any ) => [p.slug , p.teams ?.[0 ]?.slug || 'unknown' ]));
const usage = new Map <string , { errors : number ; txns : number }>();
for (const g of stats.groups || []) {
const team = teamOf.get (g.by .project ) || 'unknown' ;
if (!usage.has (team)) usage.set (team, { errors : 0 , txns : 0 });
const u = usage.get (team)!;
if (g.by .category === 'error' ) u.errors += g.totals ['sum(quantity)' ];
if (g.by .category === 'transaction' ) u.txns += g.totals ['sum(quantity)' ];
}
let overBudget = false ;
for (const q of QUOTAS ) {
const u = usage.get (q.team ) || { errors : 0 , txns : 0 };
const ePct = ((u.errors / q.errors ) * 100 ).toFixed (0 );
const tPct = ((u.txns / q.transactions ) * 100 ).toFixed (0 );
const flag = u.errors > q.errors || u.txns > q.transactions ? 'OVER' : 'OK' ;
console .log (`[${q.team} ] errors=${u.errors} /${q.errors} (${ePct} %) txns=${u.txns} /${q.transactions} (${tPct} %) [${flag} ]` );
if (flag === 'OVER' ) overBudget = true ;
}
if (overBudget) { console .error ('ACTION REQUIRED: budget exceeded' ); process.exit (1 ); }
}
main ();
name: Sentry Monthly Audit
on:
schedule: [{ cron: '0 9 1 * *' }]
workflow_dispatch:
jobs:
drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: bash scripts/audit-sentry-drift.sh
env:
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
cost:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npx tsx scripts/check-team-quotas.ts
env:
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
Output
@company/sentry-config shared package with enforced PII scrubbing, naming validation, and tier-based trace rate caps
Mandatory beforeSend chain: headers, credit cards, emails, and SSNs scrubbed before any custom logic
Naming standards enforced at init: release format, validated environments, kebab-case service names
Required tags injected: service, team, tier, deployment, region
CI workflow blocking hardcoded DSNs, PII collection, and direct Sentry.init() calls
Monthly drift audit checking data scrubber, IP scrubbing, sensitive fields, and naming compliance
Per-team cost quota enforcement with weekly budget checks
Error Handling Error Cause Solution Invalid service name at initName not kebab-case or wrong length Rename to lowercase kebab-case, 3-40 chars, letter start Invalid environment at initNon-standard environment string Use: production, staging, development, canary, or sandbox CI blocks Sentry.init() Direct call outside shared config Replace with initSentry() from @company/sentry-config CI blocks hardcoded DSN DSN string in source code Move to SENTRY_DSN environment variable Drift audit [FAIL] on data scrubber Project settings changed in UI Re-enable in Project Settings then Security and Privacy Team over budget Noisy errors or high trace volume Add ignoreErrors filters or lower tracesSampleRate beforeSend scrubbing bypassedService using raw Sentry.init() Adopt @company/sentry-config which chains scrubbing first
Examples import { initSentry } from '@company/sentry-config' ;
initSentry ({
serviceName : 'user-service' ,
dsn : process.env .SENTRY_DSN !,
version : '1.0.0' ,
tags : { service : 'user-service' , team : 'platform' , tier : 'standard' },
});
Critical service with custom filtering:
import { initSentry } from '@company/sentry-config' ;
initSentry ({
serviceName : 'checkout-api' ,
dsn : process.env .SENTRY_DSN !,
version : '3.2.0' ,
tags : { service : 'checkout-api' , team : 'payments' , tier : 'critical' },
tracesSampleRate : 0.4 ,
beforeSend (event ) {
if (event.exception ?.values ?.some (e => e.value ?.includes ('PaymentTimeout' ))) {
return null ;
}
return event;
},
});
Resources
Next Steps
Publish @company/sentry-config to internal registry and onboard first two services
Add the CI policy workflow to all service repositories via shared workflow or template
Schedule the drift audit as a monthly cron and cost check as weekly
Communicate per-team quotas to engineering leads with Slack budget alerts