[TERMINAL · SKILLS]
> mounting /skills...
> indexing 295 manifests...
> linking agents: claude · codex · gemini · cursor
> ready.
[░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0%
Terminal.skills
Use Cases/Build an Automated Compliance Evidence Collector

Build an Automated Compliance Evidence Collector

Automate SOC 2 and ISO 27001 evidence collection from AWS, GitHub, and HR systems — reducing audit prep from 6 weeks to 3 days and generating continuous compliance dashboards for investors.

#postgresql#database#sql#relational#jsonb
Works with:claude-codeopenai-codexgemini-clicursor

Skills stack · 6 skills

Avg quality 93/100·All SAFE
>

typescript

v

Not yet scored
View skill
>

postgresql

v1.0.0

Assists with designing schemas, writing performant queries, managing indexes, and operating PostgreSQL databases. Use when working with JSONB, full-text search, window functions, CTEs, row-level security, replication, or performance tuning. Trigger words: postgresql, postgres, sql, database, jsonb, rls, window functions, cte.

87/100 quality
1.53× impact
SAFE
View skill
>

redis

v1.0.0

Build applications with Redis — caching, session storage, pub/sub, streams, rate limiting, leaderboards, and queues. Use when tasks involve in-memory data storage, real-time messaging, distributed locking, or performance optimization with caching layers.

93/100 quality
1.81× impact
SAFE
View skill
>

hono

v1.0.0

You are an expert in Hono, the ultrafast web framework for the edge. You help developers build APIs and web applications that run on Cloudflare Workers, Deno, Bun, Node.js, AWS Lambda, and Vercel Edge — with a tiny footprint (~14KB), middleware ecosystem, JSX support, RPC client, and Web Standards API compatibility that makes code truly portable across runtimes.

93/100 quality
3.00× impact
SAFE
View skill
>

zod

v1.0.0

You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.

100/100 quality
1.21× impact
SAFE
View skill
>

github-actions

v1.0.0

Build CI/CD pipelines with GitHub Actions — workflows, jobs, steps, triggers, caching, artifacts, matrix builds, secrets, environments, reusable workflows, and custom actions. Use when tasks involve automating tests, builds, deployments, code quality checks, or any GitHub-triggered automation.

93/100 quality
1.02× impact
SAFE
View skill
$

The Problem

A 50-person SaaS startup needs SOC 2 Type II for enterprise sales. Their auditor requests 150+ pieces of evidence: access reviews, encryption configs, backup logs, code review records, employee training completions. The engineering team manually screenshots AWS consoles, exports GitHub PR histories, and compiles spreadsheets. Audit prep takes 6 weeks of part-time work from 4 engineers. Last year, they failed 3 controls because evidence was stale — screenshots were from 6 months ago, not current state.

Step 1: Evidence Requirement Registry

typescript
// src/compliance/registry.ts
import { z } from 'zod';

export const EvidenceRequirement = z.object({
  id: z.string(),
  framework: z.enum(['soc2', 'iso27001', 'hipaa', 'gdpr']),
  control: z.string(),          // e.g., "CC6.1" for SOC 2
  controlName: z.string(),
  description: z.string(),
  evidenceType: z.enum(['config_snapshot', 'access_review', 'log_export', 'policy_doc', 'training_record', 'metric']),
  source: z.enum(['aws', 'github', 'okta', 'hr_system', 'manual']),
  collector: z.string(),        // function name
  frequency: z.enum(['daily', 'weekly', 'monthly', 'quarterly', 'on_demand']),
  retentionDays: z.number().int(),
});

export const requirements: z.infer<typeof EvidenceRequirement>[] = [
  {
    id: 'soc2-cc6.1-encryption',
    framework: 'soc2',
    control: 'CC6.1',
    controlName: 'Logical and Physical Access Controls',
    description: 'Evidence that data at rest is encrypted',
    evidenceType: 'config_snapshot',
    source: 'aws',
    collector: 'collect-aws-encryption',
    frequency: 'weekly',
    retentionDays: 400,
  },
  {
    id: 'soc2-cc6.1-access-review',
    framework: 'soc2',
    control: 'CC6.1',
    controlName: 'Logical and Physical Access Controls',
    description: 'Quarterly access review showing appropriate permissions',
    evidenceType: 'access_review',
    source: 'aws',
    collector: 'collect-iam-access-review',
    frequency: 'quarterly',
    retentionDays: 400,
  },
  {
    id: 'soc2-cc8.1-code-review',
    framework: 'soc2',
    control: 'CC8.1',
    controlName: 'Change Management',
    description: 'Evidence that all production changes are peer-reviewed',
    evidenceType: 'log_export',
    source: 'github',
    collector: 'collect-pr-reviews',
    frequency: 'weekly',
    retentionDays: 400,
  },
  {
    id: 'soc2-cc7.2-monitoring',
    framework: 'soc2',
    control: 'CC7.2',
    controlName: 'System Monitoring',
    description: 'Evidence of security monitoring and alerting',
    evidenceType: 'config_snapshot',
    source: 'aws',
    collector: 'collect-cloudwatch-alarms',
    frequency: 'monthly',
    retentionDays: 400,
  },
  {
    id: 'soc2-cc1.4-training',
    framework: 'soc2',
    control: 'CC1.4',
    controlName: 'Security Awareness Training',
    description: 'Evidence that all employees completed security training',
    evidenceType: 'training_record',
    source: 'hr_system',
    collector: 'collect-training-records',
    frequency: 'quarterly',
    retentionDays: 400,
  },
];

Step 2: Evidence Collectors

typescript
// src/compliance/collectors.ts
import { IAMClient, ListUsersCommand, ListAttachedUserPoliciesCommand, GetLoginProfileCommand } from '@aws-sdk/client-iam';
import { RDSClient, DescribeDBInstancesCommand } from '@aws-sdk/client-rds';
import { S3Client, GetBucketEncryptionCommand, ListBucketsCommand } from '@aws-sdk/client-s3';
import { Pool } from 'pg';

const iam = new IAMClient({});
const rds = new RDSClient({});
const s3 = new S3Client({});
const db = new Pool({ connectionString: process.env.DATABASE_URL });

interface Evidence {
  requirementId: string;
  collectedAt: string;
  data: Record<string, unknown>;
  status: 'pass' | 'fail' | 'warning';
  details: string;
}

export const collectors: Record<string, () => Promise<Evidence>> = {
  'collect-aws-encryption': async () => {
    // Check RDS encryption
    const rdsInstances = await rds.send(new DescribeDBInstancesCommand({}));
    const unencrypted = (rdsInstances.DBInstances ?? []).filter(db => !db.StorageEncrypted);

    // Check S3 bucket encryption
    const buckets = await s3.send(new ListBucketsCommand({}));
    const bucketResults = [];
    for (const bucket of buckets.Buckets ?? []) {
      try {
        await s3.send(new GetBucketEncryptionCommand({ Bucket: bucket.Name }));
        bucketResults.push({ bucket: bucket.Name, encrypted: true });
      } catch {
        bucketResults.push({ bucket: bucket.Name, encrypted: false });
      }
    }
    const unencryptedBuckets = bucketResults.filter(b => !b.encrypted);

    const passed = unencrypted.length === 0 && unencryptedBuckets.length === 0;

    return {
      requirementId: 'soc2-cc6.1-encryption',
      collectedAt: new Date().toISOString(),
      data: {
        rdsInstances: rdsInstances.DBInstances?.map(db => ({
          id: db.DBInstanceIdentifier, encrypted: db.StorageEncrypted, engine: db.Engine,
        })),
        s3Buckets: bucketResults,
      },
      status: passed ? 'pass' : 'fail',
      details: passed
        ? 'All RDS instances and S3 buckets are encrypted'
        : `${unencrypted.length} unencrypted RDS, ${unencryptedBuckets.length} unencrypted S3 buckets`,
    };
  },

  'collect-pr-reviews': async () => {
    const token = process.env.GITHUB_TOKEN;
    const org = process.env.GITHUB_ORG;

    // Fetch merged PRs from last period
    const res = await fetch(
      `https://api.github.com/search/issues?q=org:${org}+is:pr+is:merged+merged:>${thirtyDaysAgo()}`,
      { headers: { Authorization: `token ${token}` } }
    );
    const data = await res.json() as any;

    const prs = data.items ?? [];
    const unreviewed = prs.filter((pr: any) => pr.pull_request?.review_comments === 0);
    const reviewRate = prs.length > 0 ? (prs.length - unreviewed.length) / prs.length : 1;

    return {
      requirementId: 'soc2-cc8.1-code-review',
      collectedAt: new Date().toISOString(),
      data: {
        totalPRs: prs.length,
        reviewedPRs: prs.length - unreviewed.length,
        unreviewedPRs: unreviewed.map((pr: any) => ({ url: pr.html_url, title: pr.title })),
        reviewRate: `${(reviewRate * 100).toFixed(1)}%`,
      },
      status: reviewRate >= 0.95 ? 'pass' : reviewRate >= 0.85 ? 'warning' : 'fail',
      details: `${(reviewRate * 100).toFixed(1)}% of PRs reviewed (${prs.length} total)`,
    };
  },

  'collect-iam-access-review': async () => {
    const users = await iam.send(new ListUsersCommand({}));
    const accessDetails = [];

    for (const user of users.Users ?? []) {
      const policies = await iam.send(new ListAttachedUserPoliciesCommand({ UserName: user.UserName }));
      let hasConsoleAccess = false;
      try {
        await iam.send(new GetLoginProfileCommand({ UserName: user.UserName }));
        hasConsoleAccess = true;
      } catch {}

      accessDetails.push({
        userName: user.UserName,
        policies: policies.AttachedPolicies?.map(p => p.PolicyName),
        hasConsoleAccess,
        lastActivity: user.PasswordLastUsed?.toISOString() ?? 'never',
        mfaEnabled: false, // would check separately
      });
    }

    const staleUsers = accessDetails.filter(u =>
      u.lastActivity === 'never' || new Date(u.lastActivity) < new Date(Date.now() - 90 * 86400000)
    );

    return {
      requirementId: 'soc2-cc6.1-access-review',
      collectedAt: new Date().toISOString(),
      data: { users: accessDetails, staleUsers },
      status: staleUsers.length === 0 ? 'pass' : 'warning',
      details: `${accessDetails.length} users, ${staleUsers.length} stale (90+ days inactive)`,
    };
  },
};

function thirtyDaysAgo(): string {
  return new Date(Date.now() - 30 * 86400000).toISOString().split('T')[0];
}

Step 3: Compliance Dashboard

typescript
// src/api/compliance.ts
import { Hono } from 'hono';
import { Pool } from 'pg';

const app = new Hono();
const db = new Pool({ connectionString: process.env.DATABASE_URL });

app.get('/v1/compliance/dashboard', async (c) => {
  const { rows: controls } = await db.query(`
    SELECT r.control, r.control_name, r.framework,
      e.status, e.collected_at, e.details
    FROM evidence e
    JOIN (SELECT requirement_id, MAX(collected_at) as latest
          FROM evidence GROUP BY requirement_id) latest
      ON e.requirement_id = latest.requirement_id AND e.collected_at = latest.latest
    JOIN requirements r ON e.requirement_id = r.id
    ORDER BY r.framework, r.control
  `);

  const summary = {
    total: controls.length,
    passing: controls.filter(c => c.status === 'pass').length,
    failing: controls.filter(c => c.status === 'fail').length,
    warnings: controls.filter(c => c.status === 'warning').length,
    complianceRate: controls.length > 0
      ? (controls.filter(c => c.status === 'pass').length / controls.length * 100).toFixed(1) + '%'
      : 'N/A',
  };

  return c.json({ summary, controls });
});

export default app;

Results

  • Audit prep time: 3 days (was 6 weeks)
  • Evidence freshness: always current (was 6 months stale)
  • Failed controls: zero (was 3 in previous audit)
  • Continuous compliance: dashboard shows real-time status for investors
  • Engineer time: 2 hours/quarter for audit support (was 160+ hours/year across 4 engineers)
  • Stale IAM users: found 4 with 90+ day inactive accounts — security gap closed
  • Unreviewed PRs: caught 3% bypass rate — branch protection tightened