{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "secrets-rotation-scheduler",
  "title": "Secrets Rotation Scheduler",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/secrets-rotation-scheduler/SecretsRotationScheduler.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport {\n  AlertTriangle,\n  Check,\n  CheckCircle2,\n  Clock,\n  Copy,\n  Database,\n  Globe,\n  Info,\n  KeyRound,\n  Lock,\n  MoreHorizontal,\n  Pause,\n  Pencil,\n  Play,\n  Plus,\n  RefreshCw,\n  Search,\n  Server,\n  ShieldCheck,\n  Terminal,\n  X,\n} from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n} from '@/components/ui/dialog'\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\nimport { Input } from '@/components/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\n\nexport type SecretType = 'Postgres DB' | 'API Key' | 'RSA Keypair' | 'KMS Key' | 'Redis Auth' | 'MySQL DB'\nexport type RotationStatus = 'healthy' | 'due-soon' | 'manual-needed' | 'paused' | 'rotating'\n\nexport interface RotationSchedule {\n  interval: string\n  daysInterval: number\n  lambdaArn?: string\n  zeroDowntimeVerified: boolean\n}\n\nexport interface ManagedSecret {\n  id: string\n  name: string\n  arn: string\n  type: SecretType\n  schedule: RotationSchedule\n  lastRotated: string\n  nextRotationDue: string\n  dueRelative: string\n  status: RotationStatus\n  currentVersion: string\n  stagingVersion?: string\n  lastLogSnippet?: string\n}\n\nexport interface SecretsRotationStats {\n  totalSecrets: number\n  autoRotationActive: number\n  autoRotationPercentage: number\n  dueSoonCount: number\n  overdueCount: number\n}\n\nexport interface SecretsRotationSchedulerProps {\n  initialSecrets?: ManagedSecret[]\n  initialStats?: SecretsRotationStats\n  className?: string\n}\n\nconst defaultSecrets: ManagedSecret[] = [\n  {\n    id: 'sec-1',\n    name: 'prod/postgres/master-credentials',\n    arn: 'arn:aws:secretsmanager:us-east-1:182938491029:secret:prod/postgres/master-cred-9aF1x',\n    type: 'Postgres DB',\n    schedule: {\n      interval: 'Every 30 Days',\n      daysInterval: 30,\n      lambdaArn: 'arn:aws:lambda:us-east-1:182938491029:function:RotatePostgresMaster',\n      zeroDowntimeVerified: true,\n    },\n    lastRotated: 'Aug 10, 2026',\n    nextRotationDue: 'Sep 09, 2026',\n    dueRelative: 'in 19 days',\n    status: 'healthy',\n    currentVersion: 'v2.4 (AWSCURRENT)',\n    stagingVersion: 'v2.5 (AWSPENDING)',\n    lastLogSnippet:\n      'Postgres dual-user handshake verified. Master role privileges synchronized with 0 connection terminations.',\n  },\n  {\n    id: 'sec-2',\n    name: 'prod/stripe/webhook-secret',\n    arn: 'arn:aws:secretsmanager:us-east-1:182938491029:secret:prod/stripe/wh-sec-48k2p',\n    type: 'API Key',\n    schedule: {\n      interval: 'Every 90 Days',\n      daysInterval: 90,\n      lambdaArn: 'arn:aws:lambda:us-east-1:182938491029:function:RotateStripeWebhook',\n      zeroDowntimeVerified: true,\n    },\n    lastRotated: 'Jul 14, 2026',\n    nextRotationDue: 'Aug 22, 2026',\n    dueRelative: 'in 24 hours',\n    status: 'due-soon',\n    currentVersion: 'v1.8 (AWSCURRENT)',\n    stagingVersion: 'v1.9 (AWSPENDING)',\n    lastLogSnippet: 'Dual webhook signature validation window active. Webhook endpoint test passed with 200 OK.',\n  },\n  {\n    id: 'sec-3',\n    name: 'prod/jwt/signing-key-rsa',\n    arn: 'arn:aws:secretsmanager:us-east-1:182938491029:secret:prod/jwt/rsa-pair-71b3e',\n    type: 'RSA Keypair',\n    schedule: {\n      interval: 'Every 7 Days',\n      daysInterval: 7,\n      lambdaArn: 'arn:aws:lambda:us-east-1:182938491029:function:RotateJWTRSAKeys',\n      zeroDowntimeVerified: true,\n    },\n    lastRotated: 'Aug 18, 2026',\n    nextRotationDue: 'Aug 25, 2026',\n    dueRelative: 'in 4 days',\n    status: 'healthy',\n    currentVersion: 'v9.1 (AWSCURRENT)',\n    stagingVersion: 'v9.2 (AWSPENDING)',\n    lastLogSnippet:\n      'JWKS endpoint updated with secondary public key kid:rsa-2026-w34. Token signature verification succeeded.',\n  },\n  {\n    id: 'sec-4',\n    name: 'prod/aws/kms-envelope-key',\n    arn: 'arn:aws:kms:us-east-1:182938491029:key/mrk-8492019a-9e1b-4f21-99ad',\n    type: 'KMS Key',\n    schedule: {\n      interval: 'Every 365 Days',\n      daysInterval: 365,\n      lambdaArn: 'arn:aws:lambda:us-east-1:182938491029:function:KmsEnvelopeRotationHandler',\n      zeroDowntimeVerified: true,\n    },\n    lastRotated: 'Oct 01, 2025',\n    nextRotationDue: 'Oct 01, 2026',\n    dueRelative: 'in 41 days',\n    status: 'healthy',\n    currentVersion: 'v3.0 (AWSCURRENT)',\n    stagingVersion: 'v3.1 (AWSPENDING)',\n    lastLogSnippet:\n      'Hardware Security Module (HSM) backing key refreshed. Transparent decryption verified for existing ciphertexts.',\n  },\n  {\n    id: 'sec-5',\n    name: 'prod/redis/cache-auth',\n    arn: 'arn:aws:secretsmanager:us-east-1:182938491029:secret:prod/redis/auth-token-6c90d',\n    type: 'Redis Auth',\n    schedule: {\n      interval: 'Manual Only',\n      daysInterval: 0,\n      zeroDowntimeVerified: false,\n    },\n    lastRotated: 'May 12, 2026',\n    nextRotationDue: 'Aug 20, 2026',\n    dueRelative: 'Overdue (1 day)',\n    status: 'manual-needed',\n    currentVersion: 'v1.0 (AWSCURRENT)',\n    stagingVersion: undefined,\n    lastLogSnippet:\n      'Automated lambda execution unconfigured. Dual-AUTH token rotation requires manual trigger or handler attachment.',\n  },\n]\n\nconst defaultStats: SecretsRotationStats = {\n  totalSecrets: 18,\n  autoRotationActive: 15,\n  autoRotationPercentage: 83.3,\n  dueSoonCount: 2,\n  overdueCount: 0,\n}\n\nfunction getTypeBadgeVariant(type: SecretType): 'default' | 'secondary' | 'outline' | 'info' | 'warning' {\n  switch (type) {\n    case 'Postgres DB':\n    case 'MySQL DB':\n      return 'info'\n    case 'API Key':\n      return 'secondary'\n    case 'RSA Keypair':\n      return 'outline'\n    case 'KMS Key':\n      return 'default'\n    case 'Redis Auth':\n      return 'warning'\n    default:\n      return 'outline'\n  }\n}\n\nexport function SecretsRotationScheduler({\n  initialSecrets = defaultSecrets,\n  initialStats = defaultStats,\n  className,\n}: SecretsRotationSchedulerProps) {\n  const [secrets, setSecrets] = React.useState<ManagedSecret[]>(initialSecrets)\n  const [search, setSearch] = React.useState<string>('')\n  const [statusFilter, setStatusFilter] = React.useState<string>('all')\n  const [bannerMessage, setBannerMessage] = React.useState<{ type: 'success' | 'info'; text: string } | null>(null)\n  const [rotatingSecretId, setRotatingSecretId] = React.useState<string | null>(null)\n  const [copiedArn, setCopiedArn] = React.useState<string | null>(null)\n\n  // Dialogs\n  const [isRotateModalOpen, setIsRotateModalOpen] = React.useState<boolean>(false)\n  const [selectedSecretForRotate, setSelectedSecretForRotate] = React.useState<ManagedSecret | null>(null)\n  const [isRotatingInProgress, setIsRotatingInProgress] = React.useState<boolean>(false)\n\n  const [isScheduleModalOpen, setIsScheduleModalOpen] = React.useState<boolean>(false)\n  const [editingSecret, setEditingSecret] = React.useState<ManagedSecret | null>(null)\n  const [formName, setFormName] = React.useState<string>('')\n  const [formArn, setFormArn] = React.useState<string>('')\n  const [formType, setFormType] = React.useState<SecretType>('Postgres DB')\n  const [formInterval, setFormInterval] = React.useState<string>('Every 30 Days')\n  const [formLambdaArn, setFormLambdaArn] = React.useState<string>('')\n  const [formZeroDowntime, setFormZeroDowntime] = React.useState<boolean>(true)\n\n  const [isLogsModalOpen, setIsLogsModalOpen] = React.useState<boolean>(false)\n  const [selectedSecretForLogs, setSelectedSecretForLogs] = React.useState<ManagedSecret | null>(null)\n\n  const filteredSecrets = React.useMemo(() => {\n    const q = search.trim().toLowerCase()\n    return secrets.filter((sec) => {\n      const matchesStatus =\n        statusFilter === 'all' ||\n        sec.status === statusFilter ||\n        (statusFilter === 'healthy' && sec.status === 'healthy') ||\n        (statusFilter === 'due-soon' && sec.status === 'due-soon') ||\n        (statusFilter === 'manual-needed' && sec.status === 'manual-needed') ||\n        (statusFilter === 'paused' && sec.status === 'paused')\n\n      const matchesSearch =\n        !q ||\n        sec.name.toLowerCase().includes(q) ||\n        sec.arn.toLowerCase().includes(q) ||\n        sec.type.toLowerCase().includes(q)\n\n      return matchesStatus && matchesSearch\n    })\n  }, [secrets, search, statusFilter])\n\n  const copyToClipboard = async (text: string, id: string) => {\n    try {\n      await navigator.clipboard.writeText(text)\n      setCopiedArn(id)\n      setTimeout(() => setCopiedArn(null), 2000)\n    } catch {\n      setCopiedArn(id)\n      setTimeout(() => setCopiedArn(null), 2000)\n    }\n  }\n\n  const openInstantRotate = (secret: ManagedSecret) => {\n    setSelectedSecretForRotate(secret)\n    setIsRotateModalOpen(true)\n  }\n\n  const executeRotation = () => {\n    if (!selectedSecretForRotate) return\n    setIsRotatingInProgress(true)\n    const targetId = selectedSecretForRotate.id\n    setRotatingSecretId(targetId)\n\n    setTimeout(() => {\n      setIsRotatingInProgress(false)\n      setIsRotateModalOpen(false)\n      setRotatingSecretId(null)\n\n      setSecrets((prev) =>\n        prev.map((s) =>\n          s.id === targetId\n            ? {\n                ...s,\n                lastRotated: 'Just now',\n                nextRotationDue: 'Sep 20, 2026',\n                dueRelative: 'in 30 days',\n                status: 'healthy',\n                currentVersion: 'v2.5 (AWSCURRENT)',\n                stagingVersion: undefined,\n                lastLogSnippet:\n                  'Zero-downtime rotation completed successfully. Version B verified, promoted to AWSCURRENT, and staged safely.',\n              }\n            : s,\n        ),\n      )\n\n      setBannerMessage({\n        type: 'success',\n        text: `Zero-downtime rotation successfully completed for \"${selectedSecretForRotate.name}\". Credentials validated with 0 dropped sockets.`,\n      })\n    }, 1400)\n  }\n\n  const openScheduleModal = (secret?: ManagedSecret) => {\n    if (secret) {\n      setEditingSecret(secret)\n      setFormName(secret.name)\n      setFormArn(secret.arn)\n      setFormType(secret.type)\n      setFormInterval(secret.schedule.interval)\n      setFormLambdaArn(secret.schedule.lambdaArn || '')\n      setFormZeroDowntime(secret.schedule.zeroDowntimeVerified)\n    } else {\n      setEditingSecret(null)\n      setFormName('')\n      setFormArn('')\n      setFormType('Postgres DB')\n      setFormInterval('Every 30 Days')\n      setFormLambdaArn('arn:aws:lambda:us-east-1:182938491029:function:RotateSecretHandler')\n      setFormZeroDowntime(true)\n    }\n    setIsScheduleModalOpen(true)\n  }\n\n  const saveSchedule = () => {\n    if (!formName.trim()) return\n\n    if (editingSecret) {\n      setSecrets((prev) =>\n        prev.map((s) =>\n          s.id === editingSecret.id\n            ? {\n                ...s,\n                name: formName.trim(),\n                arn: formArn.trim() || s.arn,\n                type: formType,\n                schedule: {\n                  ...s.schedule,\n                  interval: formInterval,\n                  lambdaArn: formLambdaArn.trim() || undefined,\n                  zeroDowntimeVerified: formZeroDowntime,\n                },\n              }\n            : s,\n        ),\n      )\n      setBannerMessage({\n        type: 'info',\n        text: `Rotation schedule for \"${formName}\" updated successfully.`,\n      })\n    } else {\n      const newId = `sec-${Date.now()}`\n      const generatedArn =\n        formArn.trim() ||\n        `arn:aws:secretsmanager:us-east-1:182938491029:secret:${formName.trim().toLowerCase()}-${Math.random().toString(36).substring(2, 7)}`\n\n      const newSecret: ManagedSecret = {\n        id: newId,\n        name: formName.trim(),\n        arn: generatedArn,\n        type: formType,\n        schedule: {\n          interval: formInterval,\n          daysInterval: formInterval.includes('7') ? 7 : formInterval.includes('90') ? 90 : 30,\n          lambdaArn: formLambdaArn.trim() || undefined,\n          zeroDowntimeVerified: formZeroDowntime,\n        },\n        lastRotated: 'Never (Initial)',\n        nextRotationDue: 'Pending First Run',\n        dueRelative: 'in 2 hours',\n        status: 'healthy',\n        currentVersion: 'v1.0 (AWSCURRENT)',\n        stagingVersion: undefined,\n        lastLogSnippet: 'Initial rotation schedule registered with automated zero-downtime dual-version handshake.',\n      }\n      setSecrets((prev) => [newSecret, ...prev])\n      setBannerMessage({\n        type: 'success',\n        text: `New secret rotation schedule registered for \"${newSecret.name}\".`,\n      })\n    }\n    setIsScheduleModalOpen(false)\n  }\n\n  const togglePause = (secret: ManagedSecret) => {\n    const nextStatus: RotationStatus = secret.status === 'paused' ? 'healthy' : 'paused'\n    setSecrets((prev) => prev.map((s) => (s.id === secret.id ? { ...s, status: nextStatus } : s)))\n    setBannerMessage({\n      type: 'info',\n      text: `Rotation schedule for \"${secret.name}\" ${nextStatus === 'paused' ? 'paused' : 'resumed'}.`,\n    })\n  }\n\n  const openLogsModal = (secret: ManagedSecret) => {\n    setSelectedSecretForLogs(secret)\n    setIsLogsModalOpen(true)\n  }\n\n  return (\n    <div data-slot=\"secrets-rotation-scheduler\" className={cn('w-full space-y-6', className)}>\n      {/* Header */}\n      <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div className=\"space-y-1\">\n          <div className=\"flex items-center gap-2\">\n            <div className=\"bg-primary/10 text-primary flex size-8 items-center justify-center rounded-lg\">\n              <Lock className=\"size-4.5\" />\n            </div>\n            <h1 className=\"text-foreground text-2xl font-bold tracking-tight\">\n              Automated Secrets Rotation & Key Lifecycle\n            </h1>\n          </div>\n          <p className=\"text-muted-foreground text-sm\">\n            Configure zero-downtime rotation schedules for database credentials, API keys, and certificates.\n          </p>\n        </div>\n\n        <div className=\"flex items-center gap-2\">\n          <Button onClick={() => openScheduleModal()}>\n            <Plus className=\"mr-1.5 size-4\" />\n            Schedule New Rotation\n          </Button>\n        </div>\n      </div>\n\n      {/* Notification / Action banner */}\n      {bannerMessage && (\n        <div className=\"border-border bg-card flex items-center justify-between gap-3 rounded-lg border p-3 shadow-xs\">\n          <div className=\"flex items-center gap-2.5 text-sm\">\n            {bannerMessage.type === 'success' ? (\n              <CheckCircle2 className=\"text-success size-4 shrink-0\" />\n            ) : (\n              <Info className=\"text-primary size-4 shrink-0\" />\n            )}\n            <span className=\"text-foreground font-medium\">{bannerMessage.text}</span>\n          </div>\n          <Button variant=\"ghost\" size=\"icon\" className=\"size-7\" onClick={() => setBannerMessage(null)}>\n            <X className=\"size-3.5\" />\n            <span className=\"sr-only\">Dismiss</span>\n          </Button>\n        </div>\n      )}\n\n      {/* 4 Key Lifecycle Telemetry Cards */}\n      <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n        {/* Total Managed Secrets */}\n        <Card className=\"shadow-xs\">\n          <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n            <CardTitle className=\"text-muted-foreground text-sm font-medium\">Total Managed Secrets</CardTitle>\n            <div className=\"bg-primary/10 text-primary rounded-lg p-2\">\n              <KeyRound className=\"size-4\" />\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-1\">\n            <div className=\"text-foreground text-2xl font-bold tracking-tight\">\n              {initialStats.totalSecrets} credentials\n            </div>\n            <p className=\"text-muted-foreground text-xs\">Across 4 cloud regions</p>\n          </CardContent>\n        </Card>\n\n        {/* Auto-Rotation Active */}\n        <Card className=\"shadow-xs\">\n          <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n            <CardTitle className=\"text-muted-foreground text-sm font-medium\">Auto-Rotation Active</CardTitle>\n            <div className=\"bg-success/10 text-success rounded-lg p-2\">\n              <RefreshCw className=\"size-4\" />\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-1\">\n            <div className=\"flex items-center gap-2\">\n              <span className=\"text-foreground text-2xl font-bold tracking-tight\">\n                {initialStats.autoRotationActive} / {initialStats.totalSecrets} secrets\n              </span>\n              <Badge variant=\"success\" className=\"text-xs\">\n                {initialStats.autoRotationPercentage}%\n              </Badge>\n            </div>\n            <p className=\"text-muted-foreground text-xs\">Zero-downtime dual versioning enabled</p>\n          </CardContent>\n        </Card>\n\n        {/* Rotation Due Soon */}\n        <Card className=\"border-warning/30 bg-warning/5 bg-warning/10 shadow-xs\">\n          <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n            <CardTitle className=\"text-warning text-sm font-medium\">Rotation Due Soon</CardTitle>\n            <div className=\"bg-warning/20 text-warning rounded-lg p-2\">\n              <Clock className=\"size-4\" />\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-1\">\n            <div className=\"flex items-center gap-2\">\n              <span className=\"text-warning text-2xl font-bold tracking-tight\">\n                {initialStats.dueSoonCount} secrets\n              </span>\n              <Badge variant=\"warning\" className=\"text-xs\">\n                Next 48h\n              </Badge>\n            </div>\n            <p className=\"text-warning/90 text-xs\">Automated queue pre-scheduled</p>\n          </CardContent>\n        </Card>\n\n        {/* Expired / Overdue */}\n        <Card className=\"shadow-xs\">\n          <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n            <CardTitle className=\"text-muted-foreground text-sm font-medium\">Expired / Overdue</CardTitle>\n            <div className=\"bg-success/10 text-success rounded-lg p-2\">\n              <ShieldCheck className=\"size-4\" />\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-1\">\n            <div className=\"flex items-center gap-2\">\n              <span className=\"text-foreground text-2xl font-bold tracking-tight\">\n                {initialStats.overdueCount} critical overdue\n              </span>\n              <Badge variant=\"outline\" className=\"text-xs\">\n                Compliant\n              </Badge>\n            </div>\n            <p className=\"text-muted-foreground text-xs\">Zero security compliance violations</p>\n          </CardContent>\n        </Card>\n      </div>\n\n      {/* Secrets Rotation Table Card */}\n      <Card className=\"shadow-xs\">\n        <CardHeader className=\"pb-3\">\n          <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n            <div>\n              <CardTitle className=\"text-lg font-semibold\">Managed Secrets & Automated Rotation</CardTitle>\n              <CardDescription className=\"text-xs\">\n                {filteredSecrets.length} of {secrets.length} cryptographic secrets configured for automated lifecycle\n                management.\n              </CardDescription>\n            </div>\n\n            <div className=\"flex flex-wrap items-center gap-2\">\n              <div className=\"relative w-full min-w-0 sm:w-64\">\n                <Search className=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\" />\n                <Input\n                  value={search}\n                  onChange={(e) => setSearch(e.target.value)}\n                  placeholder=\"Search secrets or ARN\"\n                  className=\"h-8 pl-9 text-xs\"\n                />\n              </div>\n\n              <Select value={statusFilter} onValueChange={setStatusFilter}>\n                <SelectTrigger className=\"h-8 w-36 text-xs\">\n                  <SelectValue placeholder=\"All Statuses\" />\n                </SelectTrigger>\n                <SelectContent>\n                  <SelectItem value=\"all\">All Statuses</SelectItem>\n                  <SelectItem value=\"healthy\">Automated · Healthy</SelectItem>\n                  <SelectItem value=\"due-soon\">Due Soon (&lt;48h)</SelectItem>\n                  <SelectItem value=\"manual-needed\">Manual Needed</SelectItem>\n                  <SelectItem value=\"paused\">Paused</SelectItem>\n                </SelectContent>\n              </Select>\n\n              <Badge variant=\"outline\" className=\"hidden h-8 items-center gap-1 font-mono text-xs md:inline-flex\">\n                <Globe className=\"size-3\" />\n                AWS us-east-1\n              </Badge>\n            </div>\n          </div>\n        </CardHeader>\n\n        <CardContent className=\"p-0\">\n          <div className=\"overflow-x-auto\">\n            <Table>\n              <TableHeader>\n                <TableRow className=\"hover:bg-transparent\">\n                  <TableHead className=\"min-w-[260px]\">Secret Name & ARN Identifier</TableHead>\n                  <TableHead className=\"min-w-[130px]\">Secret Type</TableHead>\n                  <TableHead className=\"min-w-[170px]\">Rotation Interval</TableHead>\n                  <TableHead className=\"min-w-[200px]\">Last Rotated & Next Due</TableHead>\n                  <TableHead className=\"min-w-[170px]\">Rotation Status</TableHead>\n                  <TableHead className=\"w-16 text-right\">Actions</TableHead>\n                </TableRow>\n              </TableHeader>\n              <TableBody>\n                {filteredSecrets.map((secret) => (\n                  <TableRow key={secret.id} className=\"group transition-colors\">\n                    {/* Secret Name & ARN Identifier */}\n                    <TableCell className=\"py-3.5\">\n                      <div className=\"space-y-1\">\n                        <div className=\"flex items-center gap-1.5\">\n                          <span className=\"text-foreground text-sm font-medium\">{secret.name}</span>\n                          {rotatingSecretId === secret.id && (\n                            <RefreshCw className=\"text-primary size-3.5 animate-spin\" aria-label=\"Rotating now\" />\n                          )}\n                        </div>\n                        <div className=\"flex items-center gap-1.5\">\n                          <code\n                            className=\"text-muted-foreground max-w-[260px] truncate font-mono text-xs sm:max-w-[320px]\"\n                            title={secret.arn}\n                          >\n                            {secret.arn}\n                          </code>\n                          <button\n                            type=\"button\"\n                            className=\"text-muted-foreground hover:text-foreground inline-flex size-4 shrink-0 items-center justify-center transition-colors\"\n                            aria-label={`Copy ARN for ${secret.name}`}\n                            onClick={() => copyToClipboard(secret.arn, secret.id)}\n                          >\n                            {copiedArn === secret.id ? (\n                              <Check className=\"text-success size-3\" />\n                            ) : (\n                              <Copy className=\"size-3\" />\n                            )}\n                          </button>\n                        </div>\n                      </div>\n                    </TableCell>\n\n                    {/* Secret Type Badge */}\n                    <TableCell className=\"py-3.5\">\n                      <Badge variant={getTypeBadgeVariant(secret.type)} className=\"gap-1 text-xs\">\n                        {(secret.type === 'Postgres DB' || secret.type === 'MySQL DB') && (\n                          <Database className=\"size-3\" />\n                        )}\n                        {secret.type === 'API Key' && <KeyRound className=\"size-3\" />}\n                        {secret.type === 'RSA Keypair' && <ShieldCheck className=\"size-3\" />}\n                        {secret.type === 'KMS Key' && <Lock className=\"size-3\" />}\n                        {secret.type === 'Redis Auth' && <Server className=\"size-3\" />}\n                        {secret.type}\n                      </Badge>\n                    </TableCell>\n\n                    {/* Rotation Interval */}\n                    <TableCell className=\"py-3.5\">\n                      <div className=\"space-y-0.5\">\n                        <div className=\"flex items-center gap-1.5 text-xs font-medium\">\n                          <Clock className=\"text-muted-foreground size-3.5 shrink-0\" />\n                          <span className=\"text-foreground\">{secret.schedule.interval}</span>\n                        </div>\n                        {secret.schedule.lambdaArn ? (\n                          <p\n                            className=\"text-muted-foreground max-w-[160px] truncate font-mono text-xs\"\n                            title={secret.schedule.lambdaArn}\n                          >\n                            λ {secret.schedule.lambdaArn.split(':function:')[1] || 'Lambda'}\n                          </p>\n                        ) : (\n                          <p className=\"text-muted-foreground font-mono text-xs\">Manual trigger</p>\n                        )}\n                      </div>\n                    </TableCell>\n\n                    {/* Last Rotated & Next Due */}\n                    <TableCell className=\"py-3.5\">\n                      <div className=\"space-y-0.5 text-xs\">\n                        <div className=\"text-foreground font-medium\">\n                          {secret.nextRotationDue}\n                          {secret.status === 'due-soon' ? (\n                            <span className=\"text-warning font-semibold\"> ({secret.dueRelative})</span>\n                          ) : (\n                            <span className=\"text-muted-foreground\"> ({secret.dueRelative})</span>\n                          )}\n                        </div>\n                        <p className=\"text-muted-foreground text-xs\">\n                          Last: <span className=\"font-mono\">{secret.lastRotated}</span>\n                        </p>\n                      </div>\n                    </TableCell>\n\n                    {/* Rotation Status Badge */}\n                    <TableCell className=\"py-3.5\">\n                      <div className=\"space-y-1\">\n                        {secret.status === 'healthy' && (\n                          <Badge variant=\"success\" className=\"gap-1 text-xs\">\n                            <span className=\"bg-success size-1.5 animate-pulse rounded-full\" />\n                            Automated · Healthy\n                          </Badge>\n                        )}\n                        {secret.status === 'due-soon' && (\n                          <Badge variant=\"warning\" className=\"gap-1 text-xs\">\n                            <Clock className=\"size-3\" />\n                            Rotation Due Soon\n                          </Badge>\n                        )}\n                        {secret.status === 'manual-needed' && (\n                          <Badge variant=\"warning\" className=\"gap-1 text-xs\">\n                            <AlertTriangle className=\"size-3\" />\n                            Manual Rotation Needed\n                          </Badge>\n                        )}\n                        {secret.status === 'paused' && (\n                          <Badge variant=\"secondary\" className=\"gap-1 text-xs\">\n                            <Pause className=\"size-3\" />\n                            Paused\n                          </Badge>\n                        )}\n                        {secret.status === 'rotating' && (\n                          <Badge variant=\"outline\" className=\"gap-1 text-xs\">\n                            <RefreshCw className=\"size-3 animate-spin\" />\n                            Rotating\n                          </Badge>\n                        )}\n\n                        <div className=\"text-muted-foreground font-mono text-xs\">{secret.currentVersion}</div>\n                      </div>\n                    </TableCell>\n\n                    {/* Actions Menu */}\n                    <TableCell className=\"py-3.5 text-right\">\n                      <DropdownMenu>\n                        <DropdownMenuTrigger asChild>\n                          <Button variant=\"ghost\" size=\"icon\" className=\"size-8\">\n                            <MoreHorizontal className=\"size-4\" />\n                            <span className=\"sr-only\">Open actions menu</span>\n                          </Button>\n                        </DropdownMenuTrigger>\n                        <DropdownMenuContent align=\"end\" className=\"w-56\">\n                          <DropdownMenuLabel className=\"text-xs\">Rotation Controls</DropdownMenuLabel>\n                          <DropdownMenuSeparator />\n                          <DropdownMenuItem className=\"cursor-pointer\" onClick={() => openInstantRotate(secret)}>\n                            <Play className=\"text-success mr-2 size-4\" />\n                            <span>Rotate Now (Zero Downtime)</span>\n                          </DropdownMenuItem>\n                          <DropdownMenuItem className=\"cursor-pointer\" onClick={() => openScheduleModal(secret)}>\n                            <Pencil className=\"mr-2 size-4\" />\n                            <span>Edit Schedule</span>\n                          </DropdownMenuItem>\n                          <DropdownMenuItem className=\"cursor-pointer\" onClick={() => openLogsModal(secret)}>\n                            <Terminal className=\"mr-2 size-4\" />\n                            <span>View Rotation Lambda Log</span>\n                          </DropdownMenuItem>\n                          <DropdownMenuSeparator />\n                          <DropdownMenuItem className=\"cursor-pointer\" onClick={() => togglePause(secret)}>\n                            {secret.status !== 'paused' ? (\n                              <>\n                                <Pause className=\"mr-2 size-4\" />\n                                <span>Pause Auto-Rotation</span>\n                              </>\n                            ) : (\n                              <>\n                                <Play className=\"text-success mr-2 size-4\" />\n                                <span>Resume Auto-Rotation</span>\n                              </>\n                            )}\n                          </DropdownMenuItem>\n                        </DropdownMenuContent>\n                      </DropdownMenu>\n                    </TableCell>\n                  </TableRow>\n                ))}\n\n                {filteredSecrets.length === 0 && (\n                  <TableRow>\n                    <TableCell colSpan={6} className=\"text-muted-foreground h-32 text-center text-sm\">\n                      No secrets found matching the selected filter criteria.\n                    </TableCell>\n                  </TableRow>\n                )}\n              </TableBody>\n            </Table>\n          </div>\n        </CardContent>\n      </Card>\n\n      {/* Instant Rotate Modal / Dialog (Zero-Downtime Confirmation) */}\n      <Dialog open={isRotateModalOpen} onOpenChange={setIsRotateModalOpen}>\n        <DialogContent className=\"sm:max-w-xl\">\n          <DialogHeader>\n            <div className=\"flex items-center gap-2\">\n              <div className=\"bg-success/10 text-success rounded-lg p-2\">\n                <RefreshCw className=\"size-5\" />\n              </div>\n              <div>\n                <DialogTitle>Trigger Zero-Downtime Rotation</DialogTitle>\n                <DialogDescription className=\"text-xs\">\n                  AWS Secrets Manager 4-step staging promotion for credential lifecycle safety.\n                </DialogDescription>\n              </div>\n            </div>\n          </DialogHeader>\n\n          <div className=\"space-y-4 py-2\">\n            {/* Target Secret Summary */}\n            <div className=\"border-border bg-muted/50 space-y-2 rounded-lg border p-3\">\n              <div className=\"flex items-center justify-between text-xs\">\n                <span className=\"text-muted-foreground\">Target Secret:</span>\n                <span className=\"text-foreground font-mono font-semibold\">{selectedSecretForRotate?.name}</span>\n              </div>\n              <div className=\"flex items-center justify-between text-xs\">\n                <span className=\"text-muted-foreground\">Current Active:</span>\n                <Badge variant=\"outline\" className=\"font-mono text-xs\">\n                  {selectedSecretForRotate?.currentVersion}\n                </Badge>\n              </div>\n              <div className=\"flex items-center justify-between text-xs\">\n                <span className=\"text-muted-foreground\">Staging Target:</span>\n                <Badge variant=\"info\" className=\"font-mono text-xs\">\n                  {selectedSecretForRotate?.stagingVersion || 'v2.5 (AWSPENDING)'}\n                </Badge>\n              </div>\n            </div>\n\n            {/* 4-Step Zero-Downtime Process Visualizer */}\n            <div className=\"space-y-2\">\n              <span className=\"text-foreground text-xs font-semibold tracking-wider uppercase\">\n                Dual-Version Execution Workflow\n              </span>\n              <div className=\"border-border bg-card space-y-2.5 rounded-lg border p-3.5 text-xs\">\n                <div className=\"flex items-start gap-2.5\">\n                  <div className=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full text-xs font-bold\">\n                    1\n                  </div>\n                  <div className=\"space-y-0.5\">\n                    <p className=\"text-foreground font-semibold\">createSecret (Staging)</p>\n                    <p className=\"text-muted-foreground text-xs\">\n                      Generates 32-byte cryptographic entropy and provisions version{' '}\n                      <code className=\"font-mono font-semibold\">AWSPENDING</code>.\n                    </p>\n                  </div>\n                </div>\n\n                <div className=\"flex items-start gap-2.5\">\n                  <div className=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full text-xs font-bold\">\n                    2\n                  </div>\n                  <div className=\"space-y-0.5\">\n                    <p className=\"text-foreground font-semibold\">setSecret (Dual-Authentication)</p>\n                    <p className=\"text-muted-foreground text-xs\">\n                      Updates target resource (Postgres / API / KMS) so both Version A and Version B remain valid.\n                    </p>\n                  </div>\n                </div>\n\n                <div className=\"flex items-start gap-2.5\">\n                  <div className=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full text-xs font-bold\">\n                    3\n                  </div>\n                  <div className=\"space-y-0.5\">\n                    <p className=\"text-foreground font-semibold\">testSecret (Handshake Verification)</p>\n                    <p className=\"text-muted-foreground text-xs\">\n                      Lambda executes synthetic database query using new credentials to verify validity.\n                    </p>\n                  </div>\n                </div>\n\n                <div className=\"flex items-start gap-2.5\">\n                  <div className=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full text-xs font-bold\">\n                    4\n                  </div>\n                  <div className=\"space-y-0.5\">\n                    <p className=\"text-foreground font-semibold\">finishSecret (Label Promotion)</p>\n                    <p className=\"text-muted-foreground text-xs\">\n                      Moves <code className=\"font-mono font-semibold\">AWSCURRENT</code> to Version B and demotes old\n                      version to <code className=\"font-mono font-semibold\">AWSPREVIOUS</code>.\n                    </p>\n                  </div>\n                </div>\n              </div>\n            </div>\n\n            {/* Zero-Downtime Guarantee Banner */}\n            <div className=\"border-success/20 bg-success/5 text-success flex items-center gap-2.5 rounded-lg border p-3 text-xs\">\n              <ShieldCheck className=\"text-success size-5 shrink-0\" />\n              <span>\n                <strong>Zero-Downtime Guarantee:</strong> Existing connections continue using Version A until Version B\n                is 100% verified. No dropped TCP sockets or authentication spikes.\n              </span>\n            </div>\n          </div>\n\n          <DialogFooter>\n            <Button variant=\"outline\" disabled={isRotatingInProgress} onClick={() => setIsRotateModalOpen(false)}>\n              Cancel\n            </Button>\n            <Button disabled={isRotatingInProgress} className=\"gap-1.5\" onClick={executeRotation}>\n              {isRotatingInProgress ? (\n                <>\n                  <RefreshCw className=\"size-4 animate-spin\" />\n                  <span>Executing Dual-Stage Rotation...</span>\n                </>\n              ) : (\n                <>\n                  <Play className=\"size-4\" />\n                  <span>Confirm & Rotate Immediately</span>\n                </>\n              )}\n            </Button>\n          </DialogFooter>\n        </DialogContent>\n      </Dialog>\n\n      {/* Schedule / Edit Schedule Dialog */}\n      <Dialog open={isScheduleModalOpen} onOpenChange={setIsScheduleModalOpen}>\n        <DialogContent className=\"sm:max-w-lg\">\n          <DialogHeader>\n            <DialogTitle>{editingSecret ? 'Edit Rotation Schedule' : 'Schedule Secret Rotation'}</DialogTitle>\n            <DialogDescription className=\"text-xs\">\n              Configure automated periodic rotation interval and AWS Lambda rotation handler.\n            </DialogDescription>\n          </DialogHeader>\n\n          <div className=\"space-y-4 py-2\">\n            <div className=\"space-y-1.5\">\n              <label htmlFor=\"form-secret-name-react\" className=\"text-foreground text-xs font-medium\">\n                Secret Name / Path\n              </label>\n              <Input\n                id=\"form-secret-name-react\"\n                value={formName}\n                onChange={(e) => setFormName(e.target.value)}\n                placeholder=\"e.g. prod/postgres/replica-credentials\"\n                className=\"text-xs\"\n              />\n            </div>\n\n            <div className=\"grid grid-cols-2 gap-3\">\n              <div className=\"space-y-1.5\">\n                <label htmlFor=\"form-secret-type-react\" className=\"text-foreground text-xs font-medium\">\n                  Secret Type\n                </label>\n                <Select value={formType} onValueChange={(val) => setFormType(val as SecretType)}>\n                  <SelectTrigger id=\"form-secret-type-react\" className=\"text-xs\">\n                    <SelectValue placeholder=\"Secret Type\" />\n                  </SelectTrigger>\n                  <SelectContent>\n                    <SelectItem value=\"Postgres DB\">Postgres DB</SelectItem>\n                    <SelectItem value=\"MySQL DB\">MySQL DB</SelectItem>\n                    <SelectItem value=\"API Key\">API Key</SelectItem>\n                    <SelectItem value=\"RSA Keypair\">RSA Keypair</SelectItem>\n                    <SelectItem value=\"KMS Key\">KMS Key</SelectItem>\n                    <SelectItem value=\"Redis Auth\">Redis Auth</SelectItem>\n                  </SelectContent>\n                </Select>\n              </div>\n\n              <div className=\"space-y-1.5\">\n                <label htmlFor=\"form-secret-interval-react\" className=\"text-foreground text-xs font-medium\">\n                  Rotation Interval\n                </label>\n                <Select value={formInterval} onValueChange={setFormInterval}>\n                  <SelectTrigger id=\"form-secret-interval-react\" className=\"text-xs\">\n                    <SelectValue placeholder=\"Interval\" />\n                  </SelectTrigger>\n                  <SelectContent>\n                    <SelectItem value=\"Every 7 Days\">Every 7 Days</SelectItem>\n                    <SelectItem value=\"Every 30 Days\">Every 30 Days</SelectItem>\n                    <SelectItem value=\"Every 60 Days\">Every 60 Days</SelectItem>\n                    <SelectItem value=\"Every 90 Days\">Every 90 Days</SelectItem>\n                    <SelectItem value=\"Every 365 Days\">Every 365 Days</SelectItem>\n                    <SelectItem value=\"Manual Only\">Manual Only</SelectItem>\n                  </SelectContent>\n                </Select>\n              </div>\n            </div>\n\n            <div className=\"space-y-1.5\">\n              <label htmlFor=\"form-secret-lambda-react\" className=\"text-foreground text-xs font-medium\">\n                Rotation Lambda Function ARN\n              </label>\n              <Input\n                id=\"form-secret-lambda-react\"\n                value={formLambdaArn}\n                onChange={(e) => setFormLambdaArn(e.target.value)}\n                placeholder=\"arn:aws:lambda:us-east-1:182938491029:function:RotateSecret\"\n                className=\"font-mono text-xs\"\n              />\n            </div>\n\n            <div className=\"border-border bg-muted/40 flex items-center justify-between rounded-lg border p-3\">\n              <div className=\"space-y-0.5\">\n                <p className=\"text-foreground text-xs font-medium\">Zero-Downtime Dual Versioning</p>\n                <p className=\"text-muted-foreground text-xs\">Verify staging version before promoting AWSCURRENT</p>\n              </div>\n              <Badge variant=\"success\" className=\"text-xs\">\n                Active\n              </Badge>\n            </div>\n          </div>\n\n          <DialogFooter>\n            <Button variant=\"outline\" onClick={() => setIsScheduleModalOpen(false)}>\n              Cancel\n            </Button>\n            <Button disabled={!formName.trim()} onClick={saveSchedule}>\n              {editingSecret ? 'Save Changes' : 'Create Rotation Schedule'}\n            </Button>\n          </DialogFooter>\n        </DialogContent>\n      </Dialog>\n\n      {/* View Rotation Lambda Log Dialog */}\n      <Dialog open={isLogsModalOpen} onOpenChange={setIsLogsModalOpen}>\n        <DialogContent className=\"sm:max-w-2xl\">\n          <DialogHeader>\n            <div className=\"flex items-center gap-2\">\n              <Terminal className=\"text-primary size-5\" />\n              <DialogTitle className=\"font-mono text-base\">{selectedSecretForLogs?.name}</DialogTitle>\n            </div>\n            <DialogDescription className=\"font-mono text-xs\">\n              Lambda Handler: {selectedSecretForLogs?.schedule.lambdaArn || 'arn:aws:lambda:...:RotateDefault'}\n            </DialogDescription>\n          </DialogHeader>\n\n          <div className=\"space-y-3 py-1\">\n            <div className=\"border-border bg-muted/60 flex items-center justify-between rounded-md border px-3 py-2 text-xs\">\n              <div className=\"flex items-center gap-2\">\n                <span className=\"text-muted-foreground\">Last Invocation:</span>\n                <span className=\"text-foreground font-mono font-medium\">{selectedSecretForLogs?.lastRotated}</span>\n              </div>\n              <div className=\"flex items-center gap-2\">\n                <span className=\"text-muted-foreground\">Status:</span>\n                <Badge variant=\"success\" className=\"font-mono text-xs\">\n                  200 OK - SUCCESS\n                </Badge>\n              </div>\n            </div>\n\n            {/* Terminal Output Simulation */}\n            <div className=\"border-border text-success space-y-1.5 overflow-x-auto rounded-lg border bg-black/90 p-4 font-mono text-xs dark:bg-black\">\n              <p className=\"text-muted-foreground\">\n                START RequestId: 4f8b91a2-631c-4b89-9801-ec8492019a Version: $LATEST\n              </p>\n              <p className=\"text-success\">\n                [INFO] Step 1/4 createSecret: Generating 32-byte cryptographic entropy for AWSPENDING...\n              </p>\n              <p className=\"text-success\">\n                [INFO] Step 2/4 setSecret: Applying shadow credentials to destination cluster. Dual-auth enabled.\n              </p>\n              <p className=\"text-success\">\n                [INFO] Step 3/4 testSecret: Executing test query `SELECT 1` from staging connection pool -&gt; Verified\n                (6.4ms)\n              </p>\n              <p className=\"text-success\">\n                [INFO] Step 4/4 finishSecret: Swapped AWSCURRENT label to staging version. Previous marked AWSPREVIOUS.\n              </p>\n              <p className=\"text-muted-foreground\">END RequestId: 4f8b91a2-631c-4b89-9801-ec8492019a</p>\n              <p className=\"text-muted-foreground\">\n                REPORT RequestId: 4f8b91a2-631c-4b89-9801-ec8492019a Duration: 342.15 ms Billed Duration: 343 ms Memory\n                Size: 256 MB Max Memory Used: 68 MB\n              </p>\n            </div>\n          </div>\n\n          <DialogFooter>\n            <Button variant=\"outline\" onClick={() => setIsLogsModalOpen(false)}>\n              Close Logs\n            </Button>\n          </DialogFooter>\n        </DialogContent>\n      </Dialog>\n    </div>\n  )\n}\n\nexport default SecretsRotationScheduler\n",
      "type": "registry:block",
      "target": "~/components/blocks/SecretsRotationScheduler.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/card.json",
    "https://uipkge.dev/r/react/dialog.json",
    "https://uipkge.dev/r/react/dropdown-menu.json",
    "https://uipkge.dev/r/react/input.json",
    "https://uipkge.dev/r/react/select.json",
    "https://uipkge.dev/r/react/table.json"
  ],
  "description": "AWS Secrets Manager style automated credential rotation scheduler and security key audit with lifecycle telemetry cards, zero-downtime dual-version rotation workflow, rotation lambda log inspection, and schedule configuration dialogs.",
  "categories": [
    "security",
    "app",
    "devops",
    "dashboard"
  ]
}