Skip to content

Commit 0203b6a

Browse files
committed
release: v0.5.19
1 parent b724e1c commit 0203b6a

File tree

6 files changed

+344
-12
lines changed

6 files changed

+344
-12
lines changed

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.5.19] - 2026-04-04
9+
10+
### Added
11+
12+
- **`${VAR}` environment variable interpolation in configs** — use shell/dotenv-style `${DB_PASSWORD}`, `${MODE:-production}` (with defaults), or `$${VAR}` (literal escape) anywhere in `altimate.json` and MCP server configs. Values are JSON-escape-safe so passwords containing quotes or backslashes can't corrupt your config structure. The existing `{env:VAR}` syntax continues to work for raw text injection. (#655, closes #635)
13+
14+
### Fixed
15+
16+
- **Plan agent warns when the model refuses to tool-call** — if the plan agent's model returns text without invoking any tools, altimate-code now surfaces a one-shot TUI warning suggesting you switch models via `/model` instead of silently hanging. Telemetry event `plan_no_tool_generation` emitted for session-level diagnosis. (#653)
17+
- **GitLab MR review: large-diff guard & prompt-injection hardening** — MRs exceeding 50 files or 200 KB of diff text are truncated upfront with a user-visible warning, and the review prompt explicitly frames MR content as untrusted input. (#648)
18+
- **Atomic trace file writes**`FileExporter` now writes to a temp file and renames, preventing partial/corrupt trace JSON on crash or SIGKILL. Stale `.tmp.*` artifacts older than 1 hour are swept during prune. (#646)
19+
- **15s timeout on credential validation**`AltimateApi.validateCredentials()` no longer hangs indefinitely if the auth endpoint stalls. (#648)
20+
- **Shadow-mode SQL pre-validation telemetry** — measures catch-rate for structural errors (missing columns, tables) against cached schema before enabling user-visible blocking in a future release. Fire-and-forget, zero impact on the `sql_execute` hot path. No raw SQL, schema identifiers, or validator error text transmitted. (#643, #651)
21+
- **GitLab docs rewrite** — replaced "work in progress" warning with a complete guide: quick-start, authentication, self-hosted instances, model selection, CI example. (#648)
22+
23+
### Testing
24+
25+
- 25 new adversarial tests covering env-var interpolation (JSON-escape safety, single-pass substitution, ReDoS, escape hatch, defaults), atomic write hygiene (race conditions, tmp sweep, sessionId sanitization), and telemetry identifier-leak guards. New ClickHouse finops/profiles/registry coverage. (#624)
26+
827
## [0.5.18] - 2026-04-04
928

1029
### Added

packages/opencode/src/altimate/observability/tracing.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,18 @@ export class FileExporter implements TraceExporter {
201201

202202
private async pruneOldTraces() {
203203
const entries = await fs.readdir(this.dir, { withFileTypes: true })
204+
// Sweep stale temp files (crashes between writeFile and rename leave .tmp.*
205+
// artifacts). Older than 1 hour = definitely abandoned.
206+
const staleCutoff = Date.now() - 60 * 60 * 1000
207+
const tmpFiles = entries.filter((e) => e.isFile() && /\.json\.tmp\.[0-9]+\./.test(e.name))
208+
await Promise.allSettled(
209+
tmpFiles.map(async (e) => {
210+
const p = path.join(this.dir, e.name)
211+
const stat = await fs.stat(p).catch(() => undefined)
212+
if (stat && stat.mtimeMs < staleCutoff) await fs.unlink(p).catch(() => undefined)
213+
}),
214+
)
215+
204216
const jsonFiles = entries
205217
.filter((e) => e.isFile() && e.name.endsWith(".json"))
206218
.map((e) => e.name)

packages/opencode/src/altimate/telemetry/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,6 @@ export namespace Telemetry {
656656
/** true when schema scan hit the column-scan cap — flags samples biased by large-warehouse truncation */
657657
schema_truncated: boolean
658658
duration_ms: number
659-
error_message?: string
660659
}
661660
// altimate_change end
662661
// altimate_change start — config env-var interpolation telemetry

packages/opencode/src/altimate/tools/sql-execute.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,7 @@ async function preValidateSql(sql: string, warehouse: string | undefined, queryT
205205

206206
// If the dispatcher itself failed, don't treat missing data as "valid".
207207
if (!validationResult.success) {
208-
const errMsg = typeof validationResult.error === "string" ? validationResult.error : undefined
209-
trackPreValidation("error", "dispatcher_failed", 0, Date.now() - startTime, false, ctx, errMsg)
208+
trackPreValidation("error", "dispatcher_failed", 0, Date.now() - startTime, false, ctx)
210209
return { blocked: false }
211210
}
212211

@@ -231,8 +230,7 @@ async function preValidateSql(sql: string, warehouse: string | undefined, queryT
231230
return { blocked: false }
232231
}
233232

234-
const errorMsgs = structuralErrors.map((e: any) => e.message).join("\n")
235-
trackPreValidation("blocked", "structural_error", columns.length, Date.now() - startTime, schemaTruncated, ctx, errorMsgs)
233+
trackPreValidation("blocked", "structural_error", columns.length, Date.now() - startTime, schemaTruncated, ctx)
236234
// Shadow mode: caller discards the result. When blocking is enabled in the
237235
// future, build errorOutput here with the structural errors and
238236
// schemaContext keys for user-facing guidance.
@@ -258,12 +256,12 @@ function trackPreValidation(
258256
duration_ms: number,
259257
schema_truncated: boolean,
260258
ctx: TrackCtx,
261-
error_message?: string,
262259
) {
263-
// Mask schema identifiers (table / column names, paths, user IDs) from the
264-
// validator error BEFORE it leaves the process — these are PII-adjacent and
265-
// must not land in App Insights as raw strings.
266-
const masked = error_message ? Telemetry.maskString(error_message).slice(0, 500) : undefined
260+
// Validator errors often embed raw schema identifiers (table / column names)
261+
// and paths that are PII-adjacent. maskString() only strips string literals,
262+
// not identifiers, so we intentionally drop the error text entirely from the
263+
// shadow telemetry payload. The `reason` + `masked_sql_hash` fields are
264+
// sufficient to correlate events with local logs for diagnosis.
267265
Telemetry.track({
268266
type: "sql_pre_validation",
269267
timestamp: Date.now(),
@@ -276,7 +274,6 @@ function trackPreValidation(
276274
schema_columns,
277275
schema_truncated,
278276
duration_ms,
279-
...(masked && { error_message: masked }),
280277
})
281278
}
282279
// altimate_change end

0 commit comments

Comments
 (0)