{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"c-trace-16","type":"registry:block","title":"Dependency audit","description":"Vulnerable packages that open to the chain that pulled them in, with the upgrade or lockfile update that fixes each.","dependencies":[],"registryDependencies":["@reui/badge","button","trace"],"files":[{"path":"c-trace-16.tsx","type":"registry:block","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { Badge } from \"@/components/reui/badge\"\n\nimport { Button } from \"@/components/ui/button\"\nimport {\n  Trace,\n  TraceCollapsible,\n  TraceCollapsibleContent,\n  TraceCollapsibleTrigger,\n  TraceDescription,\n  TraceIcon,\n  TraceLine,\n  TraceTitle,\n} from \"@/components/ui/trace\"\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\ntype Advisory = {\n  id: string\n  pkg: string\n  version: string\n  severity: \"high\" | \"moderate\"\n  kind: string\n  issue: string\n  // From apps/web down to the vulnerable package, before and after the fix.\n  path: string[]\n  fixedPath: string[]\n  fix: { action: string; done: string; why: string }\n}\n\nconst ADVISORIES: Advisory[] = [\n  {\n    id: \"CVE-2024-45296\",\n    pkg: \"path-to-regexp\",\n    version: \"0.1.7\",\n    severity: \"high\",\n    kind: \"ReDoS\",\n    issue: \"Backtracking regex in route parsing, fixed in 0.1.10\",\n    path: [\"express 4.19.2\", \"path-to-regexp 0.1.7\"],\n    fixedPath: [\"express 4.20.0\", \"path-to-regexp 0.1.10\"],\n    fix: {\n      action: \"Upgrade express to 4.20.0\",\n      done: \"Upgraded express to 4.20.0\",\n      why: \"express 4.19.2 pins 0.1.7, so express itself has to move.\",\n    },\n  },\n  {\n    id: \"CVE-2024-4068\",\n    pkg: \"braces\",\n    version: \"3.0.2\",\n    severity: \"high\",\n    kind: \"Memory exhaustion\",\n    issue: \"No limit on input length, fixed in 3.0.3\",\n    path: [\"lint-staged 15.2.2\", \"micromatch 4.0.5\", \"braces 3.0.2\"],\n    fixedPath: [\"lint-staged 15.2.2\", \"micromatch 4.0.5\", \"braces 3.0.3\"],\n    fix: {\n      action: \"Update the lockfile\",\n      done: \"Updated braces to 3.0.3\",\n      why: \"micromatch asks for ^3.0.2, which already allows 3.0.3.\",\n    },\n  },\n  {\n    id: \"CVE-2024-55565\",\n    pkg: \"nanoid\",\n    version: \"3.3.7\",\n    severity: \"moderate\",\n    kind: \"Predictable IDs\",\n    issue: \"Non-integer sizes weaken the output, fixed in 3.3.8\",\n    path: [\"postcss 8.4.38\", \"nanoid 3.3.7\"],\n    fixedPath: [\"postcss 8.4.38\", \"nanoid 3.3.8\"],\n    fix: {\n      action: \"Update the lockfile\",\n      done: \"Updated nanoid to 3.3.8\",\n      why: \"postcss asks for ^3.3.7, which already allows 3.3.8.\",\n    },\n  },\n]\n\n// The chain decides the fix: a parent that pins the version needs an upgrade,\n// a caret range only a lockfile update.\nexport function Pattern() {\n  const [fixed, setFixed] = React.useState<string[]>([])\n  const [announcement, setAnnouncement] = React.useState(\"\")\n  const triggers = React.useRef(new Map<string, HTMLButtonElement>())\n  const open = ADVISORIES.filter((a) => !fixed.includes(a.id))\n  const high = open.filter((a) => a.severity === \"high\").length\n\n  function fix(advisory: Advisory) {\n    setFixed((current) => [...current, advisory.id])\n    setAnnouncement(advisory.fix.done)\n    // The button lives in the panel it changes, so focus returns to the row,\n    // and the status line says what changed.\n    triggers.current.get(advisory.id)?.focus()\n  }\n\n  return (\n    <div className=\"flex w-full max-w-md flex-col gap-4 text-sm\">\n      <Trace>\n        <TraceLine>\n          <TraceIcon>\n            <IconPlaceholder\n              lucide=\"PackageIcon\"\n              tabler=\"IconPackage\"\n              hugeicons=\"PackageIcon\"\n              phosphor=\"PackageIcon\"\n              remixicon=\"RiBox3Line\"\n            />\n          </TraceIcon>\n          <TraceTitle>Audited 1,284 dependencies</TraceTitle>\n          <TraceDescription>\n            {open.length ? `${open.length} open, ${high} high` : \"all fixed\"}\n          </TraceDescription>\n        </TraceLine>\n        {ADVISORIES.map((advisory) => {\n          const done = fixed.includes(advisory.id)\n          return (\n            <TraceCollapsible key={advisory.id}>\n              <TraceCollapsibleTrigger\n                ref={(node: HTMLButtonElement | null) => {\n                  if (node) triggers.current.set(advisory.id, node)\n                  else triggers.current.delete(advisory.id)\n                }}\n              >\n                <TraceLine>\n                  <TraceIcon>\n                    {done ? (\n                      <IconPlaceholder\n                        lucide=\"ShieldCheckIcon\"\n                        tabler=\"IconShieldCheck\"\n                        hugeicons=\"Shield01Icon\"\n                        phosphor=\"ShieldCheckIcon\"\n                        remixicon=\"RiShieldCheckLine\"\n                      />\n                    ) : (\n                      <IconPlaceholder\n                        lucide=\"ShieldAlertIcon\"\n                        tabler=\"IconShieldExclamation\"\n                        hugeicons=\"ShieldEnergyIcon\"\n                        phosphor=\"ShieldWarningIcon\"\n                        remixicon=\"RiShieldLine\"\n                      />\n                    )}\n                  </TraceIcon>\n                  <TraceTitle>\n                    {done\n                      ? advisory.fix.done\n                      : `${advisory.kind} in ${advisory.pkg} ${advisory.version}`}\n                  </TraceTitle>\n                  {done ? null : (\n                    <Badge\n                      variant={\n                        advisory.severity === \"high\"\n                          ? \"destructive-light\"\n                          : \"warning-light\"\n                      }\n                    >\n                      {advisory.severity}\n                    </Badge>\n                  )}\n                </TraceLine>\n              </TraceCollapsibleTrigger>\n              <TraceCollapsibleContent>\n                <div className=\"flex flex-col gap-3\">\n                  <p>{advisory.issue}.</p>\n                  <Trace>\n                    <TraceLine>\n                      <TraceTitle>apps/web</TraceTitle>\n                    </TraceLine>\n                    {(done ? advisory.fixedPath : advisory.path).map((step) => (\n                      <TraceLine key={step}>\n                        <TraceIcon>\n                          <IconPlaceholder\n                            lucide=\"CornerDownRightIcon\"\n                            tabler=\"IconCornerDownRight\"\n                            hugeicons=\"ArrowMoveDownRightIcon\"\n                            phosphor=\"ArrowElbowDownRightIcon\"\n                            remixicon=\"RiCornerDownRightLine\"\n                          />\n                        </TraceIcon>\n                        <TraceTitle>\n                          <code className=\"text-xs\">{step}</code>\n                        </TraceTitle>\n                      </TraceLine>\n                    ))}\n                  </Trace>\n                  {done ? (\n                    <p>{advisory.fix.why}</p>\n                  ) : (\n                    <div className=\"flex items-center gap-3\">\n                      <Button\n                        size=\"xs\"\n                        variant=\"outline\"\n                        onClick={() => fix(advisory)}\n                      >\n                        {advisory.fix.action}\n                      </Button>\n                      <code className=\"text-xs\">{advisory.id}</code>\n                    </div>\n                  )}\n                </div>\n              </TraceCollapsibleContent>\n            </TraceCollapsible>\n          )\n        })}\n      </Trace>\n      <p role=\"status\" className=\"sr-only\">\n        {announcement}\n      </p>\n    </div>\n  )\n}","target":"components/examples/c-trace-16.tsx"}],"meta":{"order":16,"gridSize":2,"label":"Security Audit"}}