Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
4ca066f
test: MCP auth — URL validation, token expiry, and client secret life…
claude Mar 27, 2026
9c5b445
test: copilot provider — finish reason mapping and tool preparation
claude Mar 27, 2026
fa6288b
test: log-buffer, RWLock concurrency, SSE chunk splitting — 13 new tests
claude Mar 27, 2026
4c39dd6
test: SQL tool formatters — check, equivalence, semantics (38 tests)
claude Mar 27, 2026
01cd4b2
test: stats display + MCP OAuth XSS prevention — 26 new tests
claude Mar 27, 2026
f876f7d
test: util — proxy detection and lazy error recovery
claude Mar 27, 2026
5cc85f7
test: session compaction — observation mask and arg truncation
claude Mar 28, 2026
694db3c
test: bus — publish/subscribe/once/unsubscribe mechanics
claude Mar 28, 2026
0ac0b71
test: lazy utility and credential-store — error retry, reset, sensiti…
claude Mar 28, 2026
c4a6ca2
test: provider/transform — temperature, topP, topK, smallOptions, max…
claude Mar 28, 2026
cd8f16c
test: fingerprint + context — fill coverage gaps in core utilities
claude Mar 28, 2026
3d028c2
test: session todo — CRUD lifecycle with database persistence
claude Mar 28, 2026
c53bf3a
test: finops recommendations + dbt manifest edge cases — 12 new tests
claude Mar 28, 2026
c55940b
test: provider — sampling parameter functions (temperature, topP, topK)
claude Mar 28, 2026
7e64c74
test: session utilities — isDefaultTitle, fromRow/toRow, createObserv…
claude Mar 28, 2026
eb24377
test: provider — temperature, topP, topK model parameter defaults
claude Mar 28, 2026
4a458fe
test: agent — .env read protection and analyst write denial
claude Mar 28, 2026
72819b1
test: docker discovery + copilot provider compatibility
claude Mar 28, 2026
fe56135
Merge remote-tracking branch 'origin/test/hourly-20260327-1609' into …
anandgupta42 Mar 28, 2026
365d150
Merge remote-tracking branch 'origin/test/hourly-20260327-2019' into …
anandgupta42 Mar 28, 2026
2bba8dc
Merge remote-tracking branch 'origin/test/hourly-20260327-2119' into …
anandgupta42 Mar 28, 2026
c1df79c
Merge remote-tracking branch 'origin/test/hourly-20260327-2213' into …
anandgupta42 Mar 28, 2026
7182c23
Merge remote-tracking branch 'origin/test/hourly-20260328-0321' into …
anandgupta42 Mar 28, 2026
1fe1540
Merge remote-tracking branch 'origin/test/hourly-20260328-0627' into …
anandgupta42 Mar 28, 2026
7cb4368
Merge remote-tracking branch 'origin/test/hourly-20260328-0722' into …
anandgupta42 Mar 28, 2026
b898f34
Merge remote-tracking branch 'origin/test/hourly-20260328-0813' into …
anandgupta42 Mar 28, 2026
6e1f2e3
Merge remote-tracking branch 'origin/test/hourly-20260328-1318' into …
anandgupta42 Mar 28, 2026
1eceef3
Merge remote-tracking branch 'origin/test/hourly-20260328-1020' into …
anandgupta42 Mar 28, 2026
3ee3250
Merge remote-tracking branch 'origin/test/hourly-20260327-2311' into …
anandgupta42 Mar 28, 2026
f66e053
Merge remote-tracking branch 'origin/test/hourly-20260328-0414' into …
anandgupta42 Mar 28, 2026
1957eb5
Merge remote-tracking branch 'origin/test/hourly-20260328-0507' into …
anandgupta42 Mar 28, 2026
b565bd7
Merge remote-tracking branch 'origin/test/hourly-20260328-0910' into …
anandgupta42 Mar 28, 2026
4610f26
Merge remote-tracking branch 'origin/test/hourly-20260328-1210' into …
anandgupta42 Mar 28, 2026
abb3c40
Merge remote-tracking branch 'origin/test/hourly-20260327-1918' into …
anandgupta42 Mar 28, 2026
131974a
Merge remote-tracking branch 'origin/test/hourly-20260328-1414' into …
anandgupta42 Mar 28, 2026
3109411
Merge remote-tracking branch 'origin/test/hourly-20260328-0108' into …
anandgupta42 Mar 28, 2026
c4eff01
test: consolidate 18 test PRs — 434 new tests, deduplicated, with bug…
anandgupta42 Mar 28, 2026
8a4b557
fix: resolve typecheck errors in test files
anandgupta42 Mar 28, 2026
3c298ff
fix: remove flaky `setTimeout` in todo bus event test
anandgupta42 Mar 28, 2026
5c7de83
fix: address CodeRabbit review feedback
anandgupta42 Mar 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .github/meta/commit.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
release: v0.5.11
fix: remove flaky `setTimeout` in todo bus event test

Update README changelog to reflect releases v0.5.1 through v0.5.11.
Previous README only listed up to v0.5.0, missing 10 versions of features
including `check` CLI, skill management, session tracing, Codespaces support,
impact analysis, Snowflake Cortex, MCP auto-discovery, and more.
`Bus.publish` is synchronous — the event is delivered immediately,
no 50ms delay needed. Removes resource contention risk in parallel CI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
51 changes: 51 additions & 0 deletions packages/dbt-tools/test/log-buffer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { describe, test, expect, beforeEach } from "bun:test"
import { bufferLog, getRecentDbtLogs, clearDbtLogs } from "../src/log-buffer"

describe("dbt log-buffer", () => {
beforeEach(() => {
clearDbtLogs()
})

test("buffers log messages in insertion order", () => {
bufferLog("first")
bufferLog("second")
bufferLog("third")
expect(getRecentDbtLogs()).toEqual(["first", "second", "third"])
})

test("evicts oldest entries when buffer exceeds 100", () => {
for (let i = 0; i < 105; i++) {
bufferLog(`msg-${i}`)
}
const logs = getRecentDbtLogs()
expect(logs).toHaveLength(100)
expect(logs[0]).toBe("msg-5")
expect(logs[99]).toBe("msg-104")
})

test("clearDbtLogs empties the buffer", () => {
bufferLog("something")
clearDbtLogs()
expect(getRecentDbtLogs()).toEqual([])
})

test("getRecentDbtLogs returns a copy, not a reference", () => {
bufferLog("original")
const copy = getRecentDbtLogs()
copy.push("injected")
expect(getRecentDbtLogs()).toEqual(["original"])
})

test("handles empty buffer", () => {
expect(getRecentDbtLogs()).toEqual([])
})

test("buffer stays at exactly 100 after repeated overflow", () => {
for (let i = 0; i < 200; i++) {
bufferLog(`msg-${i}`)
}
expect(getRecentDbtLogs()).toHaveLength(100)
expect(getRecentDbtLogs()[0]).toBe("msg-100")
expect(getRecentDbtLogs()[99]).toBe("msg-199")
})
})
9 changes: 6 additions & 3 deletions packages/opencode/src/altimate/tools/altimate-core-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const AltimateCoreCheckTool = Tool.define("altimate_core_check", {
},
})

function formatCheckTitle(data: Record<string, any>): string {
export function formatCheckTitle(data: Record<string, any>): string {
const parts: string[] = []
if (!data.validation?.valid) parts.push("validation errors")
if (!data.lint?.clean) parts.push(`${data.lint?.findings?.length ?? 0} lint findings`)
Expand All @@ -66,14 +66,17 @@ function formatCheckTitle(data: Record<string, any>): string {
return parts.length ? parts.join(", ") : "PASS"
}

function formatCheck(data: Record<string, any>): string {
export function formatCheck(data: Record<string, any>): string {
const lines: string[] = []

lines.push("=== Validation ===")
if (data.validation?.valid) {
lines.push("Valid SQL.")
} else {
lines.push(`Invalid: ${data.validation?.errors?.map((e: any) => e.message).join("; ") ?? "unknown"}`)
const validationMessages = (data.validation?.errors ?? [])
.map((e: any) => (typeof e === "string" ? e : e?.message))
.filter(Boolean)
lines.push(`Invalid: ${validationMessages.join("; ") || "unknown"}`)
}

lines.push("\n=== Lint ===")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const AltimateCoreEquivalenceTool = Tool.define("altimate_core_equivalenc
...(error && { error }),
...(findings.length > 0 && { findings }),
},
output: formatEquivalence(data),
output: formatEquivalence(isRealFailure ? { ...data, error } : data),
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
Expand All @@ -65,17 +65,17 @@ export const AltimateCoreEquivalenceTool = Tool.define("altimate_core_equivalenc
},
})

function extractEquivalenceErrors(data: Record<string, any>): string | undefined {
export function extractEquivalenceErrors(data: Record<string, any>): string | undefined {
if (Array.isArray(data.validation_errors) && data.validation_errors.length > 0) {
const msgs = data.validation_errors
.map((e: any) => (typeof e === "string" ? e : (e.message ?? String(e))))
.map((e: any) => (typeof e === "string" ? e : (e?.message ?? String(e))))
.filter(Boolean)
Comment on lines +68 to 72
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Propagate extracted errors into formatted output.

Now that extractEquivalenceErrors can surface validation failures, execute should pass that resolved error into formatEquivalence; otherwise output can conflict with error title/metadata (see Line 55).

🛠️ Suggested fix
-        output: formatEquivalence(data),
+        output: formatEquivalence(isRealFailure ? { ...data, error } : data),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/src/altimate/tools/altimate-core-equivalence.ts` around
lines 68 - 72, The execute flow isn't propagating the extracted validation error
into the formatter: call extractEquivalenceErrors(data) inside execute, capture
the returned string (e.g., extractedError or errorMsg) and pass that value into
formatEquivalence so the formatted output includes the resolved error and
consistent title/metadata; update the execute function to compute const error =
extractEquivalenceErrors(data) (or similar) and supply it to
formatEquivalence(...) alongside the existing inputs (ensuring formatEquivalence
receives the error parameter).

return msgs.length > 0 ? msgs.join("; ") : undefined
}
return undefined
}

function formatEquivalence(data: Record<string, any>): string {
export function formatEquivalence(data: Record<string, any>): string {
if (data.error) return `Error: ${data.error}`
const lines: string[] = []
lines.push(data.equivalent ? "Queries are semantically equivalent." : "Queries produce different results.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,17 @@ export const AltimateCoreSemanticsTool = Tool.define("altimate_core_semantics",
},
})

function extractSemanticsErrors(data: Record<string, any>): string | undefined {
export function extractSemanticsErrors(data: Record<string, any>): string | undefined {
if (Array.isArray(data.validation_errors) && data.validation_errors.length > 0) {
const msgs = data.validation_errors
.map((e: any) => (typeof e === "string" ? e : (e.message ?? String(e))))
.map((e: any) => (typeof e === "string" ? e : (e?.message ?? String(e))))
.filter(Boolean)
return msgs.length > 0 ? msgs.join("; ") : undefined
}
return undefined
}

function formatSemantics(data: Record<string, any>): string {
export function formatSemantics(data: Record<string, any>): string {
if (data.error) return `Error: ${data.error}`
if (data.valid) return "No semantic issues found."
const lines = ["Semantic issues:\n"]
Expand Down
49 changes: 49 additions & 0 deletions packages/opencode/test/agent/agent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -810,3 +810,52 @@ test("analyst prompt contains /data-viz skill", async () => {
},
})
})

// --- .env read protection tests ---

test("builder agent asks for .env file reads but allows regular files", async () => {
await using tmp = await tmpdir()
await Instance.provide({
directory: tmp.path,
fn: async () => {
const builder = await Agent.get("builder")
expect(builder).toBeDefined()
// .env files require user approval (security: prevents accidental secret exposure)
expect(PermissionNext.evaluate("read", ".env", builder!.permission).action).toBe("ask")
expect(PermissionNext.evaluate("read", ".env.local", builder!.permission).action).toBe("ask")
expect(PermissionNext.evaluate("read", ".env.production", builder!.permission).action).toBe("ask")
expect(PermissionNext.evaluate("read", "config/.env.staging", builder!.permission).action).toBe("ask")
// Regular files are allowed without prompting
expect(PermissionNext.evaluate("read", "src/index.ts", builder!.permission).action).toBe("allow")
expect(PermissionNext.evaluate("read", "package.json", builder!.permission).action).toBe("allow")
// .env.example is explicitly allowed (safe to share)
expect(PermissionNext.evaluate("read", ".env.example", builder!.permission).action).toBe("allow")
},
})
})

// --- analyst agent write denial tests ---

test("analyst agent denies file modification and todo tools", async () => {
await using tmp = await tmpdir()
await Instance.provide({
directory: tmp.path,
fn: async () => {
const analyst = await Agent.get("analyst")
expect(analyst).toBeDefined()
// Analyst is read-only — file modification tools should be denied.
// The analyst config starts with "*": "deny" then selectively allows
// read-only tools. edit/write/todowrite are not in the allow list,
// so they fall through to the catch-all deny.
expect(evalPerm(analyst, "edit")).toBe("deny")
expect(evalPerm(analyst, "write")).toBe("deny")
expect(evalPerm(analyst, "todowrite")).toBe("deny")
expect(evalPerm(analyst, "todoread")).toBe("deny")
// Read operations are explicitly allowed after the "*": "deny" base,
// so last-match-wins produces "allow"
expect(evalPerm(analyst, "read")).toBe("allow")
expect(evalPerm(analyst, "grep")).toBe("allow")
expect(evalPerm(analyst, "glob")).toBe("allow")
},
})
})
151 changes: 151 additions & 0 deletions packages/opencode/test/altimate/altimate-core-check-formatters.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { describe, test, expect } from "bun:test"
import { formatCheckTitle, formatCheck } from "../../src/altimate/tools/altimate-core-check"

describe("formatCheckTitle", () => {
test("returns PASS for all-clean result", () => {
const data = {
validation: { valid: true },
lint: { clean: true, findings: [] },
safety: { safe: true },
pii: { findings: [] },
}
expect(formatCheckTitle(data)).toBe("PASS")
})

test("lists all failure categories when everything fails", () => {
const data = {
validation: { valid: false, errors: [{ message: "bad syntax" }] },
lint: { clean: false, findings: [{ rule: "L001" }, { rule: "L002" }] },
safety: { safe: false, threats: [{ type: "injection" }] },
pii: { findings: [{ column: "ssn", category: "SSN" }] },
}
const result = formatCheckTitle(data)
expect(result).toContain("validation errors")
expect(result).toContain("2 lint findings")
expect(result).toContain("safety threats")
expect(result).toContain("PII detected")
})

test("treats missing sections as failures (undefined is falsy)", () => {
// When data is empty, !undefined is true, so each section looks like a failure
const data = {} as Record<string, any>
const result = formatCheckTitle(data)
expect(result).toContain("validation errors")
expect(result).toContain("safety threats")
// lint.findings?.length is undefined, ?? 0 yields "0 lint findings"
expect(result).toContain("0 lint findings")
})

test("shows lint finding count when clean is false but findings is undefined", () => {
const data = {
validation: { valid: true },
lint: { clean: false },
safety: { safe: true },
pii: { findings: [] },
}
// lint.findings?.length is undefined, ?? 0 yields "0 lint findings"
expect(formatCheckTitle(data)).toBe("0 lint findings")
})

test("only shows failing sections, not passing ones", () => {
const data = {
validation: { valid: true },
lint: { clean: true },
safety: { safe: false, threats: [{ type: "drop_table" }] },
pii: { findings: [] },
}
expect(formatCheckTitle(data)).toBe("safety threats")
})
})

describe("formatCheck", () => {
test("formats all-pass result with four sections", () => {
const data = {
validation: { valid: true },
lint: { clean: true },
safety: { safe: true },
pii: { findings: [] },
}
const output = formatCheck(data)
expect(output).toContain("=== Validation ===")
expect(output).toContain("Valid SQL.")
expect(output).toContain("=== Lint ===")
expect(output).toContain("No lint findings.")
expect(output).toContain("=== Safety ===")
expect(output).toContain("Safe — no threats.")
expect(output).toContain("=== PII ===")
expect(output).toContain("No PII detected.")
})

test("formats validation errors", () => {
const data = {
validation: { valid: false, errors: [{ message: "syntax error at line 3" }, { message: "unknown column" }] },
lint: { clean: true },
safety: { safe: true },
pii: {},
}
const output = formatCheck(data)
expect(output).toContain("Invalid: syntax error at line 3; unknown column")
})

test("formats lint findings with severity and rule", () => {
const data = {
validation: { valid: true },
lint: {
clean: false,
findings: [
{ severity: "warning", rule: "L001", message: "Unnecessary whitespace" },
{ severity: "error", rule: "L003", message: "Indentation not consistent" },
],
},
safety: { safe: true },
pii: {},
}
const output = formatCheck(data)
expect(output).toContain("[warning] L001: Unnecessary whitespace")
expect(output).toContain("[error] L003: Indentation not consistent")
})

test("formats safety threats", () => {
const data = {
validation: { valid: true },
lint: { clean: true },
safety: {
safe: false,
threats: [{ severity: "critical", type: "sql_injection", description: "Tautology detected: 1=1" }],
},
pii: {},
}
const output = formatCheck(data)
expect(output).toContain("[critical] sql_injection: Tautology detected: 1=1")
})

test("formats PII findings with column and confidence", () => {
const data = {
validation: { valid: true },
lint: { clean: true },
safety: { safe: true },
pii: {
findings: [
{ column: "ssn", category: "SSN", confidence: "high" },
{ column: "email", category: "EMAIL", confidence: "medium" },
],
},
}
const output = formatCheck(data)
expect(output).toContain("ssn: SSN (high confidence)")
expect(output).toContain("email: EMAIL (medium confidence)")
})

test("handles empty/missing sections without crashing", () => {
const data = {} as Record<string, any>
const output = formatCheck(data)
// Should still produce all four section headers
expect(output).toContain("=== Validation ===")
expect(output).toContain("=== Lint ===")
expect(output).toContain("=== Safety ===")
expect(output).toContain("=== PII ===")
// validation.valid is undefined (falsy) → "Invalid: unknown"
expect(output).toContain("Invalid:")
})
})
Loading
Loading