Skip to content

Commit 502ea60

Browse files
Merge pull request #10 from pritpatel2412/feature/demo-readiness
feat: add YC application drafts, traction snapshot and fix PR fetch bug
2 parents ebf7868 + 70f85d6 commit 502ea60

8 files changed

Lines changed: 348 additions & 17 deletions

File tree

Architecture.png

988 KB
Loading

docs/DEMO_SCRIPT.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# CodeGuard Demo Script (90 Seconds)
2+
3+
**Objective**: Show YC partners a real, live path through the product that proves we are not just another generic AI coding assistant, but an automated compliance and security audit engine.
4+
5+
**Safety Net / Fallback**:
6+
Before the interview, record a clean, unedited screen recording of this exact flow using Loom or QuickTime. Keep it saved locally as `codeguard-demo-fallback.mp4` on your desktop. If the live environment flakes, network drops, or a pipeline stalls during the interview, immediately say "The network is slow, but here is exactly what this looks like when run cleanly," and hit play.
7+
8+
**Pre-selected Target Repo**: `CodeGuardHQ/demo-express-sqli`
9+
*Why this repo?* It's a tiny, recognizable Express + Postgres application (under 10 files). It contains a genuine, un-obfuscated SQL injection vulnerability (`req.body.id` directly into `db.query`). It is not a contrived toy example with a planted bug comment; it looks exactly like how junior devs actually write endpoints. It guarantees the taint-tracking engine has something real to catch within a 5-second processing window.
10+
11+
---
12+
13+
## The Script & Flow (Target Time: 85 Seconds)
14+
15+
### Step 1: The Context & The Hook (0:00 - 0:15)
16+
*Action: Start on the CodeGuard dashboard showing connected repos.*
17+
**Speaker**: "Companies pay human security firms $10,000 to $50,000 for compliance audits. CodeGuard replaces that with an autonomous security engine. We start by plugging directly into their existing GitHub workflow."
18+
*Action: Click "Connect Repository" and select `CodeGuardHQ/demo-express-sqli`.*
19+
20+
### Step 2: The Continuous Review (0:15 - 0:35)
21+
*Action: Tab over to GitHub. Open a pre-prepared PR on `demo-express-sqli` that adds a new `GET /user` endpoint with a SQL injection.*
22+
**Speaker**: "Developers just work normally. When they open a PR, our agentic engine does a deep semantic analysis."
23+
*Action: Show the PR timeline. Refresh to show the CodeGuard bot instantly dropping a PR comment blocking the merge.*
24+
**Speaker**: "It caught a live SQL injection here by tracing the exact taint path from `req.body` to the database sink. But catching bugs in PRs is commoditized. Here is the actual business."
25+
26+
### Step 3: The Pivot to Audit Mode (0:35 - 0:55)
27+
*Action: Tab back to the CodeGuard dashboard. Click into the repo, click the "Run ASVS 5.0 Audit" button.*
28+
**Speaker**: "When it's time for SOC2 or a vendor security questionnaire, companies need a verified report. Instead of hiring consultants, they run Audit Mode."
29+
*Action: Show the Audit Mode progress bar rapidly analyzing the entire repository against the ASVS 5.0 framework.*
30+
31+
### Step 4: The Compliance Artifact (0:55 - 1:15)
32+
*Action: The audit completes. Open the generated ASVS Readiness Report.*
33+
**Speaker**: "CodeGuard generates a cryptographically signed, line-by-line evidence document proving compliance against the OWASP Application Security Verification Standard. It doesn't just say 'pass' or 'fail'; it links directly to the AST nodes and mitigation controls in the codebase as proof."
34+
*Action: Scroll through the report showing the green checks and the evidence trail.*
35+
36+
### Step 5: The Monetization Gate (1:15 - 1:25)
37+
*Action: Click "Download Official PDF" on the report.*
38+
*Action: The screen dims, and the Pricing Gate modal appears.*
39+
**Speaker**: "Because this replaces a $15,000 manual audit, we charge a fraction of that value. Companies pay here to unlock the official, signed artifact they can hand to their auditors or enterprise buyers."
40+
41+
### Step 6: The Kicker (1:25 - 1:30)
42+
**Speaker**: "We've turned a multi-week, five-figure consulting engagement into a $500 API call."
43+
*Action: End demo. Stop screen share or pause.*
44+
45+
---
46+
47+
## Pre-Flight Checklist (Do this 30 mins before the interview)
48+
1. Ensure `CodeGuardHQ/demo-express-sqli` is disconnected from the local database.
49+
2. Ensure the demo branch is pushed to GitHub, but the PR is *not* opened yet.
50+
3. Verify the local server is running and ngrok/devtunnel is active for the webhook.
51+
4. Verify the fallback video is on the desktop and opens instantly.
52+
5. Practice the talk track twice while clicking through. No reading from this document.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Traction Snapshot - 2026-06-24
2+
3+
## Users & Activity
4+
- Total registered users: 12
5+
- Active users (last 7 days): 0
6+
- Active users (last 30 days): 0
7+
> Fastest path to non-zero: Convert one of the eval corpus source repos maintainers into a free pilot this week.
8+
9+
## Repositories
10+
- Total repositories connected: 13
11+
12+
13+
## Product Usage
14+
- Total PR reviews run: 107
15+
- Total Audit Mode runs completed: 0
16+
17+
## Revenue & Orders
18+
- Audit Orders: 0 audit orders
19+
- Total Revenue: $0
20+
- Paying Customers: 0
21+
> Fastest path to non-zero: Convert one pilot user via the manual-comp flow already built in the pricing mission, or manually invoice a design partner.
22+
23+
## Evaluation Metrics (latest.md)
24+
Precision: 62.5%, Recall: 100.0%, F1: 76.9%
25+
Safety Bypass Rate: 0.0% (0/3 bypass cases slipped through)
26+
27+
## Unit Economics
28+
- Average cost per review/audit: $0.0000 (Total cost: $0.0000)
29+
30+
*Note: This snapshot is generated directly from live database metrics.*

docs/YC_APPLICATION_DRAFT.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# YC Application Draft
2+
3+
## 1. What is your company going to make?
4+
CodeGuard makes an automated compliance and security engine for B2B software companies that need verifiable security audits. As of June 2026, we have processed 107 automated PR reviews across 13 connected repositories using a semantic graph analysis that catches multi-file logic flaws. We will next expand our automated readiness reports to support SOC2 in addition to the ASVS 5.0 framework.
5+
6+
## 2. How many active users or customers do you have? How many are paying?
7+
We have 12 registered users, but currently 0 active users and 0 paying customers. Out of the 13 repositories connected historically, we have seen 0 active users in the last 30 days resulting in $0 of generated revenue. We plan to manually convert one of the maintainers from our evaluation corpus into a free pilot this week to establish active usage.
8+
9+
## 3. Who are your competitors? What do you understand about your business that they don't?
10+
We compete against legacy static analysis tools like Snyk or SonarQube, and human security consulting firms that perform manual compliance audits. Legacy tools analyze files in isolation and miss logic flaws spanning multiple files, whereas our semantic graph engine successfully identified 100% of vulnerabilities in our evaluation dataset without relying on single-file pattern matching. We will continue to build adversarial patch verification to automatically prove that merged fixes cannot be bypassed, rendering traditional manual penetration testing obsolete.
11+
12+
## 4. How do or will you make money?
13+
We charge software companies a flat fee to generate cryptographically signed compliance readiness artifacts on-demand. While we currently have $0 in revenue, replacing a traditional $15,000 manual audit with a $500 automated API call creates a 96% cost reduction for our future buyers. We will implement a monetization gate for downloading the official PDF reports to convert our upcoming pilot users into paying customers.
14+
15+
## 5. Why now?
16+
The release of advanced LLM reasoning models and agentic code review like GitHub Copilot in early 2026 has fundamentally shifted developer expectations away from manual code review. Our AI-driven engine currently achieves a 76.9% F1 score at detecting complex logic vulnerabilities, a capability that was technically impossible prior to the context window and reasoning upgrades of the newest frontier models. We will leverage this capability to generate automated compliance evidence that satisfies the rigorous new ASVS 5.0 framework requirements introduced recently.
17+
18+
---
19+
20+
## ⚠️ Honest Weak-Points Ranking
21+
22+
These answers are ranked from most damaging to least damaging in an actual YC interview context, based on the current live data:
23+
24+
1. **Active Users & Paying Customers (Critical Weakness)**
25+
- *Why it hurts*: Having 0 active users in the last 30 days, despite having 12 registered users and 13 connected repos historically, signals high churn or a product that doesn't solve a hair-on-fire problem. Stating we have 0 paying customers is normal for a pivot, but 0 active users means we don't even have a feedback loop.
26+
- *Impact*: A YC partner will likely stop the interview here and ask why we aren't talking to users.
27+
2. **Unvalidated Revenue Model (Major Weakness)**
28+
- *Why it hurts*: We claim we will charge for Audit Mode, but we have exactly 0 completed Audit Mode runs and $0 revenue. The core business thesis (that people will pay $500 for an automated ASVS artifact instead of a $15,000 manual audit) is currently a hypothesis, not a fact backed by behavior.
29+
- *Impact*: It makes the pricing answer sound like a guess rather than a verified willingness-to-pay.
30+
3. **Pivot Mismatch / Feature Usage (Moderate Weakness)**
31+
- *Why it hurts*: We have processed 107 PR reviews, but our pitch relies heavily on the Audit Mode artifact, which has 0 historical runs. The traction we do have is for a commoditized feature, not the feature we are positioning as our core differentiator.
32+
- *Impact*: It forces us to defend a pivot where we haven't yet proven the new direction has traction.

scratch/vulnerable-demo.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
const express = require('express');
2+
const { exec } = require('child_process');
3+
const db = require('./database'); // Assume a basic pg/mysql wrapper
4+
5+
const router = express.Router();
6+
7+
// HARDCODED SECRET: CodeGuard should flag this immediately as a critical security risk
8+
const AWS_SECRET_ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE";
9+
const STRIPE_API_KEY = "sk_live_this_is_a_fake_key_for_testing_purposes";
10+
11+
/**
12+
* Endpoint 1: VULNERABLE TO SQL INJECTION (SQLi)
13+
* Taint Path: req.body.username -> directly interpolated into raw SQL query.
14+
* CodeGuard's Semantic Engine should catch this cross-file taint flow if db is configured.
15+
*/
16+
router.post('/login', async (req, res) => {
17+
const { username, password } = req.body;
18+
19+
// BAD: Raw string interpolation without parameterized queries
20+
const query = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`;
21+
22+
try {
23+
const result = await db.query(query);
24+
25+
// SENSITIVE DATA LEAK: Returning the entire user record (including password hashes/salts)
26+
res.json({ success: true, user: result.rows[0] });
27+
} catch (err) {
28+
res.status(500).send("Database error");
29+
}
30+
});
31+
32+
/**
33+
* Endpoint 2: VULNERABLE TO COMMAND INJECTION
34+
* Taint Path: req.query.host -> directly executed in the shell
35+
*/
36+
router.get('/ping', (req, res) => {
37+
const host = req.query.host;
38+
39+
// BAD: Unsanitized user input passed to child_process.exec
40+
exec(`ping -c 4 ${host}`, (error, stdout, stderr) => {
41+
if (error) {
42+
return res.status(500).send('Ping failed');
43+
}
44+
res.send(`<pre>${stdout}</pre>`);
45+
});
46+
});
47+
48+
/**
49+
* Endpoint 3: VULNERABLE TO CROSS-SITE SCRIPTING (XSS)
50+
* Taint Path: req.query.name -> directly injected into HTML response
51+
*/
52+
router.get('/greet', (req, res) => {
53+
const name = req.query.name || 'Guest';
54+
55+
// BAD: Reflected XSS. No HTML escaping of user input
56+
res.send(`<h1>Hello, ${name}!</h1><p>Welcome to our platform.</p>`);
57+
});
58+
59+
/**
60+
* Endpoint 4: PATH TRAVERSAL (LFI)
61+
* Taint Path: req.query.file -> readFileSync
62+
*/
63+
router.get('/download', (req, res) => {
64+
const fs = require('fs');
65+
const path = require('path');
66+
67+
const filename = req.query.file;
68+
69+
// BAD: User controls the file path directly without sanitization/validation
70+
const filePath = path.join(__dirname, 'public', 'uploads', filename);
71+
72+
try {
73+
const content = fs.readFileSync(filePath, 'utf8');
74+
res.send(content);
75+
} catch (e) {
76+
res.status(404).send("File not found");
77+
}
78+
});
79+
80+
module.exports = router;
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import "dotenv/config";
2+
import { db } from "../server/db";
3+
import { users, repositories, reviews, audits, auditOrders, apiUsageLog, requestLogs } from "../shared/schema";
4+
import { sql, gte } from "drizzle-orm";
5+
import * as fs from "fs";
6+
import * as path from "path";
7+
8+
async function generateSnapshot() {
9+
console.log("Generating traction snapshot...");
10+
11+
// 1. Users
12+
const totalUsersResult = await db.select({ count: sql<number>`count(*)` }).from(users);
13+
const totalUsers = Number(totalUsersResult[0].count);
14+
15+
const thirtyDaysAgo = new Date();
16+
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
17+
18+
const sevenDaysAgo = new Date();
19+
sevenDaysAgo.getDate() - 7; // Wait, let's just use 7 days ago
20+
21+
const activeUsers30dResult = await db.select({ count: sql<number>`count(distinct ${requestLogs.userId})` })
22+
.from(requestLogs)
23+
.where(gte(requestLogs.timestamp, thirtyDaysAgo));
24+
const activeUsers30d = Number(activeUsers30dResult[0].count);
25+
26+
const activeUsers7dResult = await db.select({ count: sql<number>`count(distinct ${requestLogs.userId})` })
27+
.from(requestLogs)
28+
.where(gte(requestLogs.timestamp, new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)));
29+
const activeUsers7d = Number(activeUsers7dResult[0].count);
30+
31+
// 2. Repositories
32+
const totalReposResult = await db.select({ count: sql<number>`count(*)` }).from(repositories);
33+
const totalRepos = Number(totalReposResult[0].count);
34+
35+
// 3. PR Reviews & Audit Mode runs
36+
const totalReviewsResult = await db.select({ count: sql<number>`count(*)` }).from(reviews);
37+
const totalReviews = Number(totalReviewsResult[0].count);
38+
39+
const totalAuditsResult = await db.select({ count: sql<number>`count(*)` }).from(audits);
40+
const totalAudits = Number(totalAuditsResult[0].count);
41+
42+
// 4. Audit Orders & Revenue
43+
const auditOrdersResult = await db.select({
44+
status: auditOrders.status,
45+
count: sql<number>`count(*)`,
46+
revenue: sql<number>`sum(${auditOrders.priceUsd})`
47+
}).from(auditOrders).groupBy(auditOrders.status);
48+
49+
let totalRevenue = 0;
50+
let ordersSummary = "";
51+
let payingCustomers = 0;
52+
if (auditOrdersResult.length === 0) {
53+
ordersSummary = "0 audit orders";
54+
} else {
55+
ordersSummary = auditOrdersResult.map(row => {
56+
if (row.status === 'marked_paid_manually' || row.status === 'paid') {
57+
totalRevenue += Number(row.revenue || 0);
58+
payingCustomers += Number(row.count);
59+
}
60+
return `${row.count} ${row.status} ($${row.revenue || 0})`;
61+
}).join(", ");
62+
}
63+
64+
// 5. Eval harness
65+
let evalNumbers = "Eval results file not found";
66+
try {
67+
const evalPath = path.join(process.cwd(), "eval/results/latest.md");
68+
if (fs.existsSync(evalPath)) {
69+
const evalContent = fs.readFileSync(evalPath, "utf-8");
70+
// Extract Precision, Recall, F1
71+
const precisionMatch = evalContent.match(/Precision\*\*:\s*([\d.]+%)/);
72+
const recallMatch = evalContent.match(/Recall\*\*:\s*([\d.]+%)/);
73+
const f1Match = evalContent.match(/F1 Score\*\*:\s*([\d.]+%)/);
74+
const bypassMatch = evalContent.match(/Bypass Rate\*\*:\s*(.*)/);
75+
76+
evalNumbers = `Precision: ${precisionMatch?.[1] || 'N/A'}, Recall: ${recallMatch?.[1] || 'N/A'}, F1: ${f1Match?.[1] || 'N/A'}\nSafety Bypass Rate: ${bypassMatch?.[1] || 'N/A'}`;
77+
}
78+
} catch(e) {
79+
console.error("Failed to read eval results", e);
80+
}
81+
82+
// 6. Cost observability
83+
const costResult = await db.select({
84+
totalCost: sql<number>`sum(CAST(${apiUsageLog.costUsd} AS numeric))`
85+
}).from(apiUsageLog);
86+
const totalCost = Number(costResult[0]?.totalCost || 0);
87+
88+
const avgCostPerReview = totalReviews > 0 ? (totalCost / totalReviews).toFixed(4) : "0";
89+
90+
const today = new Date().toISOString().split('T')[0];
91+
const snapshotPath = path.join(process.cwd(), `docs/TRACTION_SNAPSHOT_${today}.md`);
92+
93+
const snapshotContent = `# Traction Snapshot - ${today}
94+
95+
## Users & Activity
96+
- Total registered users: ${totalUsers}
97+
- Active users (last 7 days): ${activeUsers7d}
98+
- Active users (last 30 days): ${activeUsers30d}
99+
${activeUsers7d === 0 ? '> Fastest path to non-zero: Convert one of the eval corpus source repos maintainers into a free pilot this week.' : ''}
100+
101+
## Repositories
102+
- Total repositories connected: ${totalRepos}
103+
${totalRepos === 0 ? '> Fastest path to non-zero: Connect the CodeGuard repo itself and 2 open-source projects owned by the founders.' : ''}
104+
105+
## Product Usage
106+
- Total PR reviews run: ${totalReviews}
107+
- Total Audit Mode runs completed: ${totalAudits}
108+
109+
## Revenue & Orders
110+
- Audit Orders: ${ordersSummary}
111+
- Total Revenue: $${totalRevenue}
112+
- Paying Customers: ${payingCustomers}
113+
${payingCustomers === 0 ? '> Fastest path to non-zero: Convert one pilot user via the manual-comp flow already built in the pricing mission, or manually invoice a design partner.' : ''}
114+
115+
## Evaluation Metrics (latest.md)
116+
${evalNumbers}
117+
118+
## Unit Economics
119+
- Average cost per review/audit: $${avgCostPerReview} (Total cost: $${totalCost.toFixed(4)})
120+
121+
*Note: This snapshot is generated directly from live database metrics.*
122+
`;
123+
124+
fs.mkdirSync(path.join(process.cwd(), "docs"), { recursive: true });
125+
fs.writeFileSync(snapshotPath, snapshotContent);
126+
console.log(`Snapshot written to docs/TRACTION_SNAPSHOT_${today}.md`);
127+
process.exit(0);
128+
}
129+
130+
generateSnapshot().catch(console.error);

server/github.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ export async function setCommitGateStatus(
5555
state: "pending" | "success" | "failure" | "error",
5656
description: string,
5757
targetUrl?: string,
58+
accessToken?: string
5859
) {
59-
const octokit = await getUncachableGitHubClient();
60+
const octokit = await getUncachableGitHubClient(accessToken);
6061
await octokit.repos.createCommitStatus({
6162
owner,
6263
repo,
@@ -69,8 +70,8 @@ export async function setCommitGateStatus(
6970
}
7071

7172
// Fetch PR diff from GitHub
72-
export async function getPullRequestDiff(owner: string, repo: string, prNumber: number): Promise<string> {
73-
const octokit = await getUncachableGitHubClient();
73+
export async function getPullRequestDiff(owner: string, repo: string, prNumber: number, accessToken?: string): Promise<string> {
74+
const octokit = await getUncachableGitHubClient(accessToken);
7475

7576
const response = await octokit.request('GET /repos/{owner}/{repo}/pulls/{pull_number}', {
7677
owner,
@@ -85,8 +86,8 @@ export async function getPullRequestDiff(owner: string, repo: string, prNumber:
8586
}
8687

8788
// Get PR details
88-
export async function getPullRequestDetails(owner: string, repo: string, prNumber: number) {
89-
const octokit = await getUncachableGitHubClient();
89+
export async function getPullRequestDetails(owner: string, repo: string, prNumber: number, accessToken?: string) {
90+
const octokit = await getUncachableGitHubClient(accessToken);
9091

9192
const { data } = await octokit.pulls.get({
9293
owner,
@@ -105,9 +106,10 @@ export async function postReviewComment(
105106
commitId: string,
106107
path: string,
107108
line: number,
108-
body: string
109+
body: string,
110+
accessToken?: string
109111
) {
110-
const octokit = await getUncachableGitHubClient();
112+
const octokit = await getUncachableGitHubClient(accessToken);
111113

112114
try {
113115
await octokit.pulls.createReviewComment({
@@ -131,9 +133,10 @@ export async function postReview(
131133
repo: string,
132134
prNumber: number,
133135
body: string,
134-
event: 'COMMENT' | 'APPROVE' | 'REQUEST_CHANGES' = 'COMMENT'
136+
event: 'COMMENT' | 'APPROVE' | 'REQUEST_CHANGES' = 'COMMENT',
137+
accessToken?: string
135138
) {
136-
const octokit = await getUncachableGitHubClient();
139+
const octokit = await getUncachableGitHubClient(accessToken);
137140

138141
await octokit.pulls.createReview({
139142
owner,

0 commit comments

Comments
 (0)