[codex] Polish public demo and externalize database#1
Conversation
There was a problem hiding this comment.
Code Review
This pull request migrates the public demo deployment from an AWS RDS PostgreSQL instance and VPC to an external PostgreSQL database (such as Neon Free) to eliminate idle infrastructure costs. It also introduces UI improvements, including a mobile-responsive findings table, a dashboard decision card, and a detailed decision brief component. The review feedback identifies several critical issues: potential runtime crashes due to missing optional chaining on nested run and finding.evidence properties, a fragile index-based icon mapping on the dashboard, and an invalid OpenAI model name (gpt-5.4-mini) configured in the Terraform Lambda environment variables.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| function buildDecisionBrief(run: RunDetail, findings: Finding[]): DecisionBriefData { | ||
| const critical = run.severity_counts.critical ?? 0; | ||
| const high = run.severity_counts.high ?? 0; | ||
| const criticalRisk = run.risk_level === "critical"; | ||
| const replacements = run.plan_summary.replacements ?? 0; | ||
| const costOverThreshold = Boolean(run.cost_estimate.over_threshold); | ||
| const productionStatefulChange = run.environment === "prod" && replacements > 0 && (run.blast_radius.level === "high" || run.blast_radius.level === "critical"); | ||
| const topFinding = findings.slice().sort(compareFindingsBySeverity)[0]; |
There was a problem hiding this comment.
Accessing nested properties on the run object (such as severity_counts, plan_summary, cost_estimate, and blast_radius) without optional chaining can lead to runtime crashes if any of these fields are null or undefined in the API response. Using optional chaining ensures robust rendering.
| function buildDecisionBrief(run: RunDetail, findings: Finding[]): DecisionBriefData { | |
| const critical = run.severity_counts.critical ?? 0; | |
| const high = run.severity_counts.high ?? 0; | |
| const criticalRisk = run.risk_level === "critical"; | |
| const replacements = run.plan_summary.replacements ?? 0; | |
| const costOverThreshold = Boolean(run.cost_estimate.over_threshold); | |
| const productionStatefulChange = run.environment === "prod" && replacements > 0 && (run.blast_radius.level === "high" || run.blast_radius.level === "critical"); | |
| const topFinding = findings.slice().sort(compareFindingsBySeverity)[0]; | |
| function buildDecisionBrief(run: RunDetail, findings: Finding[]): DecisionBriefData { | |
| const critical = run.severity_counts?.critical ?? 0; | |
| const high = run.severity_counts?.high ?? 0; | |
| const criticalRisk = run.risk_level === "critical"; | |
| const replacements = run.plan_summary?.replacements ?? 0; | |
| const costOverThreshold = Boolean(run.cost_estimate?.over_threshold); | |
| const productionStatefulChange = run.environment === "prod" && replacements > 0 && (run.blast_radius?.level === "high" || run.blast_radius?.level === "critical"); | |
| const topFinding = findings.slice().sort(compareFindingsBySeverity)[0]; |
| function DecisionBrief({ run, report, decision, topFindings }: { run: RunDetail; report: Report; decision: DecisionBriefData; topFindings: Finding[] }) { | ||
| const changes = run.plan_summary; | ||
| const monthlyDelta = Number(run.cost_estimate.monthly_delta ?? 0); | ||
| return ( | ||
| <Card className="p-5"> | ||
| <div className="grid min-w-0 gap-5 xl:grid-cols-[minmax(0,1fr)_360px]"> | ||
| <div> | ||
| <div className="flex flex-wrap items-center gap-2"> | ||
| <Badge tone={decision.tone}>{decision.title}</Badge> | ||
| <Badge tone={run.github_check?.state === "fail" ? "danger" : run.github_check?.state === "warn" ? "warn" : "neutral"}> | ||
| GitHub check: {run.github_check?.state ?? "not created"} | ||
| </Badge> | ||
| </div> | ||
| <h2 className="mt-4 text-xl font-semibold text-white">What this means for the reviewer</h2> | ||
| <p className="mt-2 text-sm leading-6 text-slate-300">{decision.summary}</p> | ||
| <p className="mt-2 text-sm leading-6 text-slate-400">{report.risk_score.summary}</p> | ||
| <div className="mt-5 grid gap-3 md:grid-cols-3"> | ||
| <DecisionMetric icon={FileSearch} label="Changed resources" value={String(changes.total_resource_changes ?? 0)} detail={`${changes.creates ?? 0} create / ${changes.updates ?? 0} update / ${changes.deletes ?? 0} delete`} /> | ||
| <DecisionMetric icon={AlertTriangle} label="Blast radius" value={`${run.blast_radius.score ?? 0}`} detail={run.blast_radius.summary ?? "No destructive stateful changes detected."} /> | ||
| <DecisionMetric icon={DollarSign} label="Cost delta" value={`$${monthlyDelta.toFixed(2)}/mo`} detail={run.cost_estimate.message ?? "Heuristic estimate"} /> | ||
| </div> | ||
| </div> |
There was a problem hiding this comment.
Similarly to buildDecisionBrief, the DecisionBrief component accesses nested properties on run (like plan_summary, cost_estimate, and blast_radius) directly. If any of these objects are null or undefined, the component will crash. Applying optional chaining prevents potential runtime errors.
function DecisionBrief({ run, report, decision, topFindings }: { run: RunDetail; report: Report; decision: DecisionBriefData; topFindings: Finding[] }) {
const changes = run.plan_summary;
const monthlyDelta = Number(run.cost_estimate?.monthly_delta ?? 0);
return (
<Card className="p-5">
<div className="grid min-w-0 gap-5 xl:grid-cols-[minmax(0,1fr)_360px]">
<div>
<div className="flex flex-wrap items-center gap-2">
<Badge tone={decision.tone}>{decision.title}</Badge>
<Badge tone={run.github_check?.state === "fail" ? "danger" : run.github_check?.state === "warn" ? "warn" : "neutral"}>
GitHub check: {run.github_check?.state ?? "not created"}
</Badge>
</div>
<h2 className="mt-4 text-xl font-semibold text-white">What this means for the reviewer</h2>
<p className="mt-2 text-sm leading-6 text-slate-300">{decision.summary}</p>
<p className="mt-2 text-sm leading-6 text-slate-400">{report.risk_score.summary}</p>
<div className="mt-5 grid gap-3 md:grid-cols-3">
<DecisionMetric icon={FileSearch} label="Changed resources" value={String(changes?.total_resource_changes ?? 0)} detail={`${changes?.creates ?? 0} create / ${changes?.updates ?? 0} update / ${changes?.deletes ?? 0} delete`} />
<DecisionMetric icon={AlertTriangle} label="Blast radius" value={`${run.blast_radius?.score ?? 0}`} detail={run.blast_radius?.summary ?? "No destructive stateful changes detected."} />
<DecisionMetric icon={DollarSign} label="Cost delta" value={`$${monthlyDelta.toFixed(2)}/mo`} detail={run.cost_estimate?.message ?? "Heuristic estimate"} />
</div>
</div>
| DATABASE_URL = var.database_url | ||
| LANGSMITH_PROJECT = "terragate" | ||
| LANGSMITH_TRACING = "false" | ||
| OPENAI_MODEL = "gpt-5.4-mini" |
| {filtered.map((finding) => { | ||
| const evidence = finding.evidence[0]; |
There was a problem hiding this comment.
If finding.evidence is undefined or null, accessing finding.evidence[0] will throw a TypeError and crash the findings list rendering. Using optional chaining (finding.evidence?.[0]) is safer.
| {filtered.map((finding) => { | |
| const evidence = finding.evidence[0]; | |
| {filtered.map((finding) => { | |
| const evidence = finding.evidence?.[0]; |
| {filtered.map((finding) => { | ||
| const evidence = finding.evidence[0]; |
There was a problem hiding this comment.
If finding.evidence is undefined or null, accessing finding.evidence[0] will throw a TypeError and crash the findings table rendering. Using optional chaining (finding.evidence?.[0]) is safer.
| {filtered.map((finding) => { | |
| const evidence = finding.evidence[0]; | |
| {filtered.map((finding) => { | |
| const evidence = finding.evidence?.[0]; |
| {trustSignals.map((control, index) => { | ||
| const Icon = trustControlIcons[index]; | ||
| return ( |
There was a problem hiding this comment.
Mapping trustSignals to trustControlIcons by index is fragile. If trustSignals is updated in demo-scenarios.ts without a corresponding update to trustControlIcons in dashboard.tsx, Icon will be undefined, causing a rendering crash. Adding a guard prevents this.
{trustSignals.map((control, index) => {
const Icon = trustControlIcons[index];
if (!Icon) return null;
return (
Summary
Validation
npm run lintnpm run buildnpm run deploy:cloudflareterraform validatehttps://terragate.hangi87.workers.dev, including demo run creation and mobile overflow check.