-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathJustfile
More file actions
281 lines (233 loc) · 14 KB
/
Copy pathJustfile
File metadata and controls
281 lines (233 loc) · 14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# Pinned ZenML server image version — bump here when upgrading.
# Must match pyproject.toml, uv.lock, the server Dockerfiles, CI/release
# workflow pins, and helm/Chart.yaml; contract tests enforce alignment.
ZENML_SERVER_TAG := "0.96.1"
DOCKER_REPO := "zenmldocker/kitaru-server"
DOCKER_TAG := "latest"
UI_TAG := "latest"
# List available recipes
default:
@just --list
# Run all checks (format, lint, OpenAPI, typecheck, typos, yaml, actions, links)
check:
@printf '─── Format Check ───────────────────────────────\n'
@just format-check
@printf '\n─── Lint ───────────────────────────────────────\n'
@just lint
@printf '\n─── OpenAPI ────────────────────────────────────\n'
@just openapi-check
@printf '\n─── Changelog ──────────────────────────────────\n'
@just changelog-check
@printf '\n─── Type Check ─────────────────────────────────\n'
@just typecheck
@printf '\n─── Typos ──────────────────────────────────────\n'
@just typos
@printf '\n─── YAML Check ─────────────────────────────────\n'
@just yaml-check
@printf '\n─── Actions Lint ───────────────────────────────\n'
@just actions-lint
@printf '\n─── Links ──────────────────────────────────────\n'
@just links
@printf '\n─── MCP Docs Index ─────────────────────────────\n'
@just mcp-docs-index-check
@printf '\n─────────────────────────────────────────────────\n'
@printf 'All checks passed!\n'
# Check code formatting without modifying files
format-check:
uv run ruff format --check .
# Run linter
lint:
uv run ruff check .
# Verify the committed OpenAPI specification matches the application schema
openapi-check:
uv run bash scripts/check_openapi.sh
# Validate the changelog fragments under changelog.d
changelog-check:
uv run python scripts/changelog_fragments.py check
# Run type checker
typecheck:
uv run ty check
# Check for typos in source code
typos:
uvx typos
# Check YAML formatting (skips dependabot.yml — yamlfix unquotes its `time:` value, which Dependabot then rejects as an integer)
yaml-check:
find .github -type f \( -name '*.yml' -o -name '*.yaml' \) ! -name dependabot.yml -print0 | xargs -0 uv run yamlfix --check
# Lint GitHub Actions workflows (requires actionlint: brew install actionlint)
actions-lint:
actionlint
# Audit GitHub Actions workflows with zizmor. For richer online checks, run:
# GH_TOKEN=$(gh auth token) just zizmor
zizmor:
uvx zizmor --config=.github/zizmor.yml .github/workflows/ .github/dependabot.yml
# Audit Python dependencies for known vulnerabilities (honors .github/pip-audit-ignored.txt)
# Command substitution instead of xargs: BSD xargs skips the command entirely
# on empty input, which would turn an empty ignore list into a no-op audit.
audit:
uv run pip-audit $(awk '/^(CVE|GHSA|PYSEC)-/ {printf "--ignore-vuln %s ", $1}' .github/pip-audit-ignored.txt)
# Check raw Markdown links — offline only (requires lychee: brew install lychee).
# Source MDX uses docs-app-root routes such as /guides/...; site-build validates
# those after materializing public /docs/... links, where lychee can resolve them.
links:
lychee --offline --root-dir . './**/*.md'
# Check raw Markdown links including external URLs (slow, used in CI)
links-external:
lychee --root-dir . './**/*.md'
# Auto-fix formatting, lint issues, and YAML
fix:
uv run ruff format .
uv run ruff check . --fix
find .github -type f \( -name '*.yml' -o -name '*.yaml' \) ! -name dependabot.yml -print0 | xargs -0 uv run yamlfix
# Run tests (e.g., `just test`, `just test -x`, `just test tests/test_foo.py`)
test *ARGS:
uv run pytest {{ ARGS }}
# Run tests with coverage and print the least-covered files (e.g., `just coverage tests/cli`)
coverage *ARGS:
uv run coverage erase
uv run coverage run -m pytest {{ ARGS }}
uv run coverage combine -q
uv run coverage report --skip-covered --sort=cover
# Run all property tests with the heavy nightly profile
fuzz: fuzz-importers fuzz-evaluators fuzz-api-models fuzz-mcp fuzz-adapters fuzz-filters fuzz-api
# Heavy property-test run for importer parse() and normalization contracts
fuzz-importers:
HYPOTHESIS_PROFILE=nightly uv run --project plugins pytest -c plugins/pyproject.toml plugins/tests/importers/test_fuzz_parse.py plugins/tests/importers/test_normalization_properties.py --hypothesis-show-statistics
# Heavy property-test run for deterministic evaluator pointer, arithmetic, and budget contracts
fuzz-evaluators:
HYPOTHESIS_PROFILE=nightly uv run --project plugins pytest -c plugins/pyproject.toml plugins/tests/evaluators/test_deterministic_properties.py plugins/tests/evaluators/test_numeric_properties.py --hypothesis-show-statistics
# Heavy property-test run for selected API model wire contracts
fuzz-api-models:
HYPOTHESIS_PROFILE=nightly uv run --extra server pytest tests/api_models/test_wire_properties.py --hypothesis-show-statistics
# Heavy property-test run for the core tree (MCP tool boundary, credential redaction)
fuzz-mcp:
HYPOTHESIS_PROFILE=nightly uv run --extra server --extra cli --extra mcp pytest tests/mcp/test_fuzz_tools.py tests/cli/test_redaction_properties.py --hypothesis-show-statistics
# Heavy property-test run for adapter capture, codec, and record/replay contracts
fuzz-adapters:
HYPOTHESIS_PROFILE=nightly uv run --project plugins pytest -c plugins/pyproject.toml plugins/tests/adapters/langgraph/test_capture_properties.py plugins/tests/adapters/langgraph/test_codec.py plugins/tests/adapters/claude_agent_sdk/test_codec.py plugins/tests/adapters/pydantic_ai/test_record_replay_properties.py plugins/tests/adapters/openai_agents/test_record_replay_properties.py --hypothesis-show-statistics
# Heavy grammar-aware property tests for recursive JSON list filters
fuzz-filters:
HYPOTHESIS_PROFILE=nightly uv run --extra server pytest tests/server/test_fuzz_filters.py --hypothesis-show-statistics
# Compare generated filter results with PostgreSQL in isolated databases
fuzz-filters-pg MAX_EXAMPLES="25":
KITARU_FUZZ_POSTGRES=1 KITARU_TEST_REQUIRE_POSTGRES=1 KITARU_FUZZ_PG_MAX_EXAMPLES={{ MAX_EXAMPLES }} uv run --extra server pytest tests/server/test_fuzz_filters_pg.py --hypothesis-show-statistics
# Heavy API fuzzing run against a live server (requires docker compose up -d db)
fuzz-api:
HYPOTHESIS_PROFILE=nightly KITARU_FUZZ=1 KITARU_FUZZ_RANDOM=1 KITARU_FUZZ_MAX_EXAMPLES=400 uv run --extra server --group fuzz pytest tests/server/test_fuzz_api.py -p no:randomly --hypothesis-show-statistics
# Run isolated successful agent/version API sequences against PostgreSQL
fuzz-api-sequences MAX_EXAMPLES="25" MAX_ACTIONS="15":
KITARU_FUZZ_API_SEQUENCES=1 KITARU_TEST_REQUIRE_POSTGRES=1 KITARU_FUZZ_API_SEQUENCE_MAX_EXAMPLES={{ MAX_EXAMPLES }} KITARU_FUZZ_API_SEQUENCE_MAX_ACTIONS={{ MAX_ACTIONS }} uv run --extra server --group fuzz pytest tests/server/test_fuzz_api_sequences.py -p no:randomly --hypothesis-show-statistics
# Run authenticated task-attempt lifecycle sequences against PostgreSQL
fuzz-task-lifecycle MAX_EXAMPLES="25" MAX_ACTIONS="10":
KITARU_FUZZ_TASK_LIFECYCLE=1 KITARU_TEST_REQUIRE_POSTGRES=1 KITARU_FUZZ_TASK_LIFECYCLE_MAX_EXAMPLES={{ MAX_EXAMPLES }} KITARU_FUZZ_TASK_LIFECYCLE_MAX_ACTIONS={{ MAX_ACTIONS }} uv run --extra server --group fuzz pytest tests/server/test_fuzz_task_lifecycle.py -p no:randomly --hypothesis-show-statistics
# Check Alembic migrations against the ORM schema (requires docker compose up -d db)
migration-check:
uv run python scripts/check_migrations.py
# Build the package locally (does not publish)
build:
uv build
# Verify CLI optional dependencies from isolated wheel and sdist installations
cli-artifact-smoke:
uv run --no-sync python scripts/smoke_cli_artifacts.py
# Verify default plugin discovery and registration from isolated wheels
plugin-artifact-smoke:
uv run --no-sync python scripts/smoke_plugin_artifacts.py
# Verify the measured MCP schemas and committed snapshots
mcp-schema-check:
uv run --extra mcp python scripts/report_mcp_schema.py --check
# Verify that the bundled MCP docs search index matches the GitBook sources.
mcp-docs-index-check:
uv run --no-sync python scripts/build_mcp_docs_index.py --check
# Verify clean base and MCP installations from the single wheel under dist/
mcp-wheel-smoke:
uv run --no-sync python scripts/smoke_mcp_wheel.py dist
# Download/extract the Kitaru UI bundle into the packaged location the server serves.
# Defaults to the latest stable kitaru-ui-v* release.
# Pass UI_TAG=kitaru-ui-v0.2.0 to pin a stable release.
ui-bundle:
@set -e; \
if [ "{{ UI_TAG }}" = "latest" ]; then \
printf 'Downloading latest stable Kitaru UI bundle into src/kitaru/_ui/dist\n'; \
bash scripts/download-ui.sh; \
else \
printf 'Downloading Kitaru UI bundle {{ UI_TAG }} into src/kitaru/_ui/dist\n'; \
TAG="{{ UI_TAG }}" bash scripts/download-ui.sh; \
fi; \
printf '\nThe server serves this bundle from src/kitaru/_ui/dist. Next: just ui-serve\n'
# Download/extract an explicit prerelease Kitaru UI bundle for local testing.
ui-bundle-prerelease:
@set -e; \
if [ "{{ UI_TAG }}" = "latest" ]; then \
printf 'Error: pass an explicit prerelease tag, e.g. UI_TAG=kitaru-ui-v0.3.0-rc.1\n' >&2; \
exit 1; \
fi; \
printf 'Downloading prerelease Kitaru UI bundle {{ UI_TAG }} into src/kitaru/_ui/dist\n'; \
KITARU_UI_ALLOW_PRERELEASE=true TAG="{{ UI_TAG }}" bash scripts/download-ui.sh; \
printf '\nThe server serves this bundle from src/kitaru/_ui/dist. Next: just ui-serve\n'
# Run the API server from source, serving the downloaded UI bundle. Requires docker compose up -d db.
ui-serve:
@test -f src/kitaru/_ui/dist/index.html || { printf 'Error: src/kitaru/_ui/dist/index.html not found. Run just ui-bundle first.\n' >&2; exit 1; }
KITARU_SERVER_DB_HOST=localhost KITARU_SERVER_DB_PORT=5433 KITARU_SERVER_DB_NAME=kitaru_ui \
KITARU_SERVER_JWT_SIGNING_KEY=dev KITARU_SERVER_SECRET_ENCRYPTION_KEY=dev KITARU_SERVER_ANALYTICS_OPT_IN=false \
exec uv run uvicorn kitaru.server.api.main:app --factory --port 8000
# Audit the public example coverage manifest without running examples or providers.
example-coverage-audit:
uv run --with pyyaml python scripts/audit-example-coverage.py
# Build and push the dev base image for remote stack testing (K8s, etc.).
# The image bakes in kitaru from local source + ZenML from PyPI.
# Remote-smoke operators must pass their own target registry/image.
dev-image REPO="":
@test -n "{{ REPO }}" || { printf 'Error: pass REPO=<operator-image-repo> for the remote smoke flow image.\n' >&2; exit 1; }
docker build -f docker/Dockerfile.dev -t kitaru-dev .
docker tag kitaru-dev {{ REPO }}:latest
docker push {{ REPO }}:latest
@printf 'Dev image pushed to {{ REPO }}:latest\n'
# Build production server image (ZenML server base + Kitaru + packaged Kitaru UI).
# Override variables on the command line:
# just server-image # bundle latest stable UI
# just UI_TAG=kitaru-ui-v0.2.0 server-image # bundle specific stable UI
# just DOCKER_TAG=v0.2.0 server-image # specific image tag
server-image:
@set -e; \
if [ "{{ UI_TAG }}" = "latest" ]; then \
bash scripts/download-ui.sh; \
else \
TAG="{{ UI_TAG }}" bash scripts/download-ui.sh; \
fi
docker build -f docker/Dockerfile --target server \
--build-arg ZENML_SERVER_TAG={{ ZENML_SERVER_TAG }} \
-t kitaru-server .
docker tag kitaru-server {{ DOCKER_REPO }}:{{ DOCKER_TAG }}
@printf 'Server image built: {{ DOCKER_REPO }}:{{ DOCKER_TAG }}\n'
# Build and push production server image
server-image-push: server-image
docker push {{ DOCKER_REPO }}:{{ DOCKER_TAG }}
@printf 'Server image pushed: {{ DOCKER_REPO }}:{{ DOCKER_TAG }}\n'
# Build dev server image for local UI testing.
# Requires docker/kitaru-ui-dist/ to exist (copy from kitaru-ui/dist/).
server-dev-image:
@test -f docker/kitaru-ui-dist/index.html || { printf 'Error: docker/kitaru-ui-dist/index.html not found.\nBuild kitaru-ui first: cd kitaru-ui && pnpm build\nThen: cp -r dist/ /path/to/kitaru/docker/kitaru-ui-dist/\n' >&2; exit 1; }
docker build -f docker/Dockerfile.server-dev --target server \
--build-arg ZENML_SERVER_TAG={{ ZENML_SERVER_TAG }} \
-t kitaru-server-dev .
@printf 'Server dev image built: kitaru-server-dev\n'
# Generate changelog and SDK reference content from Python source
generate-docs:
uv run python scripts/generate_changelog_docs.py
uv run python scripts/generate_cli_docs.py
@# fumapy is bundled in the fumadocs-python npm package, not on PyPI.
@# Auto-install it if docs/node_modules exists (requires prior pnpm install in docs/).
@test -d docs/node_modules/fumadocs-python && uv pip install -q docs/node_modules/fumadocs-python || true
uv run python scripts/generate_sdk_docs.py
cd docs && node scripts/convert-sdk-docs.mjs
# Preview docs locally (run generate-docs first if CLI pages needed)
docs:
cd docs && pnpm run dev
# Build docs (full static export)
docs-build:
cd docs && pnpm run build
# Lint and format-check the docs app (Biome); CI runs this in docs.yml
docs-lint:
cd docs && pnpm run lint
# Validate the docs static export as it will be served under /docs
docs-validate:
cd docs && pnpm run validate:export