feat: add Checks system for YAML workflow execution - #84
Open
Ziinc wants to merge 6 commits into
Open
Conversation
Implements a Checks tab in ShowWorkspace that reads workflow definitions from .treq/workflows/*.yaml and allows manual job execution with per-step pass/fail results. - core/checks.rs: business logic for listing and running workflows, with parallel job execution via std::thread and DB persistence of results - commands/checks.rs: Tauri command wrappers (list_workflows, run_workflow_job, run_workflow) - local_db.rs: workflow_runs table for persisting job results - NAPI dispatch: three new arms so JS integration tests use real Rust code - ChecksTab.tsx: React component with per-job and per-workflow Run buttons, step-level pass/fail icons (data-testid for test queries) - ShowWorkspace.tsx: new Checks tab trigger and content panel - api.ts / api-types.ts: TypeScript types and invoke wrappers - Rust unit tests (9), Rust integration tests (7), JS integration tests (6)
- Add explicit repository trust requirement before running any workflow job; untrusted repos see a UI banner with a "Trust Repository" button - Validate workflow filenames (reject path separators and '..') and working-directory values (reject absolute paths and parent traversal) to prevent path escape from .treq/workflows/ - Canonicalize file paths and confirm containment within the workflows directory before reading or executing any workflow file - Skip invalid YAML files when listing workflows instead of failing the entire listing call - Replace unbounded thread spawning in run_workflow with a bounded executor (MAX_CONCURRENT_JOBS = 4) using a channel semaphore pattern - Add per-step timeout (STEP_TIMEOUT_SECS = 60) with polling loop; kills the child process and returns a timeout error on expiry - Switch step execution from cmd.output() to spawn() + Stdio::null() for safe stdin handling in the NAPI/test context while enabling timeout - Add repo_trust table to local.db; add is_repo_trusted / trust_repo functions in local_db, Tauri commands, and NAPI dispatch - Update JS integration tests to pre-trust repos before running jobs - Update Rust integration tests to call trust_repo before execution tests - Add new unit tests: trust guard, path traversal rejection, invalid YAML skip, filename and working-directory validation
- Apply biome/cargo formatting to satisfy the verify CI job - Hoist userEvent.setup() into a beforeEach hook in the checks integration test, per the local/user-event-setup-in-setup lint rule - Remove unused get_latest_workflow_run and the now-orphaned WorkflowRunRecord struct, flagged by local/no-unused-pub-rust-functions; historical run retrieval is follow-up work with no caller yet - Add scripts/screenshot/specs/checks-tab.spec.tsx covering the trust gate, enabled-after-trust state, and per-step pass/fail rendering
Ziinc
force-pushed
the
claude/checks-yaml-workflows-72iq7u
branch
from
July 26, 2026 11:25
ed8928b to
172326f
Compare
Contributor
📸 App QA screenshotsRe-ran the flow whose spec this PR adds or modifies — 3 captures. Other specs in the library were not run. checks-tab
Each bullet under a capture is what the spec claims that image should show — open the PNG and check it. commit |
Captures per-step output from workflow checks into newline-delimited JSON,
queries it with bundled DuckDB, and adds a GitHub-Actions-style viewer.
Log collection
- Step execution switches from discarding output to piped stdout/stderr,
drained on separate threads so large output on both pipes cannot deadlock
- Each line is timestamped, ANSI-stripped, and classified info/warning/error
by content (not by stream — cargo and npm write progress to stderr)
- Written to .treq/runs/{run_id}/{job_id}.jsonl; job ids are sanitised to a
safe filename charset
- A timed-out step records an explicit error line before being terminated
Run history
- workflow_runs now holds one row per invocation, with a new
workflow_job_results child table carrying per-job status and log path
- Legacy per-job workflow_runs rows are migrated by dropping the old shape
- "Run All" groups every job under a single run; re-running creates a new
run so older runs stay browsable
- A failing job no longer aborts unrelated in-flight jobs
Querying and export
- core/checks_logs.rs reads the JSONL via DuckDB read_json_auto with
level, step and substring filters plus pagination
- Log paths are resolved and confirmed to stay inside .treq/runs
- Export renders a run's logs to a plain .log file
UI
- LogsBrowser: monospace lines, timestamp column, amber warnings and red
errors, level/step/search filters, Back and Export
- ChecksTab gains a run-history list and opens logs from a job or a step;
results and the open log view reset when the workspace changes
Tests
- 28 Rust unit tests, 11 JS integration tests
- New checks-logs-browser screenshot spec covering history, viewer and filter
…lter Level filter - LogQuery.level becomes levels: Vec<String>, applied as a SQL IN clause; an empty or absent list means no filtering - New LogLevelFilter multi-select built on DropdownMenuCheckboxItem, shared by the run logs browser and the new Logs tab; the menu stays open on select so several levels can be ticked in one pass Repo-wide data source - A DuckDB `logs` view spans .treq/runs/**/*.jsonl, recovering run_id and job_id from each file's path so lines can be grouped across runs - get_repo_logs browses every run's lines with level and search filters SQL explorer - run_logs_sql executes ad-hoc queries against the `logs` view and returns columns plus stringified rows - Only single read-only statements are accepted (SELECT, WITH, DESCRIBE, SHOW, EXPLAIN, SUMMARIZE); writes, multiple statements, and ATTACH/COPY/INSTALL style keywords are rejected before reaching DuckDB - Results are capped by wrapping the user's query in an outer LIMIT UI - LogsTab is offered on the home repo only, with Browse and SQL Explorer views - Browse renders timestamp, run id, job id and message per line, reusing the logs browser's level colouring - LogsSqlExplorer provides a query editor, starter templates, a result grid with NULL rendering, and inline error reporting Tests - 35 Rust unit tests covering multi-level filtering, the cross-run view and SQL validation - 7 new JS integration tests for the Logs tab, level filter and explorer - New logs-tab-sql-explorer screenshot spec; existing specs updated for the multi-select
Log records now follow the OpenTelemetry log data model, and both logs surfaces gain a chart, line selection and a path into an agent session. OpenTelemetry structure - Records carry time_unix_nano, observed_time_unix_nano, severity_number, severity_text, body, trace_id, span_id, resource and scope - A run becomes a trace and each job a span; ids are derived from the run and job so re-reads stay stable rather than random - Step, stream and run/job identity move into attributes, using OTel's own log.iostream convention for the standard stream - The DuckDB view projects the standard field names and lifts attributes into columns, so queries say job_id rather than digging through the map - UI level names are translated to severity text at the query boundary, so stored records stay standard Timeseries chart - New query_log_timeseries buckets records by time and severity - EChart wraps Apache ECharts for React: the instance lives in a ref, only the option object is pushed on update, and the canvas plus its resize observer are disposed on unmount - LogsTimeseriesChart stacks severities over a shared time axis above the feed Logs Explorer - Renamed from SQL Explorer - Templates move from a button row into a dropdown, each item carrying a description, and expand from three to five Selection and send-to-agent - useLineSelection supports drag-select for contiguous runs and a multi-select mode for gathering scattered lines - LogFeed is shared by the run and repo-wide browsers, with a Send to agent action for the selection - The explorer can send a whole result set - All three open a fresh agent session seeded with the content, following the existing create-agent-with-review pattern Tests - 41 Rust unit tests covering the OTel shape, severity mapping, trace/span ids and timeseries bucketing - 195 JS tests including drag-select, multi-select, template listing and the OTel columns - New logs-otel-chart-agent screenshot spec; existing specs updated
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements a Checks tab in ShowWorkspace that reads workflow definitions
from
.treq/workflows/*.yamland allows manual job execution with per-steppass/fail results.
Core
core/checks.rs: business logic for listing and running workflows, withbounded-concurrency job execution and DB persistence of results
commands/checks.rs: Tauri command wrappers (list_workflows,run_workflow_job,run_workflow,is_repo_trusted,trust_repo)local_db.rs:workflow_runstable for persisting job results, plus arepo_trusttable backing the execution guardSecurity
explicitly trusted first; untrusted repos surface a banner and disabled
run buttons instead of silently executing repository-defined commands
..,and resolved paths are canonicalized and confirmed to stay inside
.treq/workflows/working-directoryvalues reject absolute paths and parenttraversal
Execution
thread-per-job spawning
Frontend
ChecksTab.tsx: per-job and per-workflow Run buttons, step-levelpass/fail icons, and the trust banner
ShowWorkspace.tsx: new Checks tab trigger and content panelapi.ts/api-types.ts: TypeScript types and invoke wrappersTests
scripts/screenshot/specs/checks-tab.spec.tsxcovering the trust gate,the enabled-after-trust state, and per-step pass/fail rendering
Follow-up (not in this PR)