feat(project): schemas for prepared questions and the web environment (G-K1) - #178
Merged
Merged
Conversation
… (G-K1) JSON Schemas, TypeScript types and validators for the two files the demo project adds (design demo-as-github-project.md 5.2a): ai/prepared-questions.json and the https-json catalog file of the web environment, with the rules of 3.6: https only, no credentials or ports, no loopback or private hosts by name or number, an allow-list of address prefixes for a trusted project, size limits, unknown keys refused, strings carried as text. A recorded fixture of the demo project in the new layout (datatug-demo-projects 0e5b98f plus the new files, Invoice rows from chinookdb.com) lets the later tasks test without the network; its spec recomputes the golden result from it. The three web files live under web/, not environments/web/: datatug validate (CLI v0.52.0) refuses any server driver but sqlite3, sqlserver, mysql and oracle (datatug-core pkg/datatug/server.go:86). See fixtures/chinook-demo.README.md. Nothing is imported by shipped code or exported from the barrel; the production build is byte-identical. ajv 8.20.0 (already in the lockfile) is a dev dependency for the schema-versus-validator spec. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…(G-K1 review r1)
Blocker B1: the allow-list was checked on a template with {table} replaced by
a stand-in, so `.%2{table}` spliced into `..` for a table named e or E and
climbed out of the allowed prefix. Now:
- a URL template has {table} exactly once, in a path segment that starts with
a letter or digit; no %, ? or # anywhere; no empty segment and no segment
that starts with a dot (checkUrlTemplate);
- expandUrlTemplate(template, table, trust) validates the table name, expands,
parses, and re-checks the parsed URL against the general rules, the allow-list
and dot segments; it returns a CheckedDataUrl, the only way to a fetchable URL
(tableUrls does it for a catalog's two templates);
- a property test over 20,000 generated templates and ten table names.
Minors: IPv6 ranges parsed properly (::/8 in every spelling, site-local, Teredo,
NAT64 prefixes, 6to4, ORCHID, discard), localhost.. refused; text lengths counted
in code points; bidi controls, line separators, zero-width and tag characters
refused in texts; a leading byte order mark dropped; $schema needs a character;
homepage and upstream.repository allow no brace; a mutation test over 2,500 documents
proves the schema and the validator cannot drift in either direction; NOTICE.md
(Chinook MIT text copied from upstream) and DATA-LICENSE.md in the fixture; the
byte cap on the stream and the jsDelivr pin caveat documented.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
13 tasks
Contributor
Author
|
[review r2 #178] Reviewed-Head: 58b964f Two rounds by an independent Opus reviewer with executable probes. Round 1 found the allow-list checked a stand-in address rather than the expanded one; closed. Re-run on this head: 1.77 million template expansions issued 7,436 URLs with zero escapes from the allowed prefixes; the golden result recomputes from the fixture (24 countries, 412 invoices, Ireland 8.32); nothing shipped imports the directory. All four checks pass. Seven minors are carried to #180, each assigned to the task that wires these functions. VERDICT: blockers=0 majors=0 minors=7 land=yes 🤖 Generated with Claude Code |
trakhimenok
enabled auto-merge (squash)
October 2, 2026 18:20
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.
What
Task G-K1, the two file formats, of
demo-as-github-project.md(backstage design, 5.2a, 4.8, 3.6, 5.4, 6.4): JSON Schemas, TypeScript types and validators forai/prepared-questions.jsonand thehttps-jsoncatalog file, and a recorded fixture of the demo project in the new layout. New files only, underlibs/datatug/main/src/lib/project-files/. Nothing is imported by shipped code or exported from the barrel; the app's routes, start-up file, chat page and IndexedDB are untouched.Decision (orchestrator, following the design's own fallback in 5.2a)
The first step of the task found that the project validation and the CLI loader reject the
webenvironment as 5.2a writes it. Per the design, the three files live underweb/at the project root (web/web.env.json,web/catalogs/chinook/chinook.db.json,web/catalogs/geo/geo.db.json) until the CLI accepts the new drivers; the app loader will look there.datatug validatestays green on the released CLI. Not chosen: writing the server entry assqlite3(a server entry must not name a driver it is not).Measured 2026-10-02, CLI v0.52.0 (built from the commit the tag points to,
3751870) and the installed release 0.51.0, which is whatdatatug/datatug-actionruns (datatug validate -d=<dir>):datatug/chinook-demoat0aca653plus the new files)DataTug project is valid., exit 0environments/web/web.env.jsonwith servershttps-jsonandingitdb(the design's shape)validation failed for environment at index=5, id=web: invalid env db server at index 0: bad value for field [driver]: unexpected value: https-json.(withingitdbalone:unexpected value: ingitdb.). Listingwebindatatug-project.jsonchanges nothing: the loader finds environments by directory.web/at the root, plusai/prepared-questions.jsonDataTug project is valid., exit 0The later CLI task (moves the files to
environments/web/)Change
datatug-corepkg/datatug/server.go:86, thedefaultbranch ofServerRef.Validate: accepthttps-jsonandingitdbas file-like drivers with no host and no port, exactly ascase "sqlite3"does (reject a host or a port, return nil). Then releasedatatug-core, bump and release the CLI (the action usesreleases/latest). Catalog files need no change:DbCatalogBase.Validatealready accepts any non-empty driver and the loader ignores unknown fields. After that release the three files move toenvironments/web/as a path change only: the schemas and validators describe documents, not locations, andweb.env.jsonalready carries the design's drivers. Written up infixtures/chinook-demo.README.md.Files
libs/datatug/main/src/lib/project-files/schemas/prepared-questions.schema.jsonhttps-jsoncataloglibs/datatug/main/src/lib/project-files/schemas/https-json-catalog.schema.jsonlibs/datatug/main/src/lib/project-files/prepared-questions.ts,libs/datatug/main/src/lib/project-files/https-json-catalog.tslibs/datatug/main/src/lib/project-files/project-address-rules.tslibs/datatug/main/src/lib/project-files/project-file-limits.tslibs/datatug/main/src/lib/project-files/fixtures/chinook-demo/,fixtures/chinook-demo.manifest.json,fixtures/chinook-demo.README.mdPinning: schemas are referenced by commit, not tag:
https://raw.githubusercontent.com/datatug/datatug-apps/<commit>/libs/datatug/main/src/lib/project-files/schemas/<name>.schema.json. Pin the commit onmainthat lands this change (a squash changes the SHA, so take it after the merge). The schema blobs are1dd111042022a34df979273cc5e7b82e5c323129(prepared questions) and5cdb33bb93b05225cde7618e827953aa8cc7ac1c(catalog) at head 58b964f;git rev-parse <commit>:<path>must give the same.Acceptance (task text and the security list of 3.6)
schemas/*.schema.jsonproject-file-schemas.spec.ts:295,302(schema and validator agree on 60+ documents; ajv strict mode compiles both)prepared-questions.ts:69,https-json-catalog.ts:89prepared-questions.spec.ts,https-json-catalog.spec.tsproject-address-rules.ts:46(v4 ranges :125, v6 :163)project-address-rules.spec.ts:13(http to localhost/127.0.0.1/[::1], decimal/hex/octal spellings, mapped, NAT64, 6to4, link-local,user:pass@,trusted@evil),https-json-catalog.spec.ts:133project-address-rules.ts:17,190,203;https-json-catalog.ts:199project-address-rules.spec.ts:145,https-json-catalog.spec.ts:267(another path on chinookdb.com, another repo on jsDelivr, the right repo at a branch or short commit,..out of the prefix, look-alike hosts);trustis a required option, never defaultedschemas/*(maxItems,maxLength,maxProperties); 256 KB file capproject-file-limits.ts:6enforced byparse*on bytesproject-file-schemas.spec.ts:358(schema numbers equalproject-file-limits.ts; every string bounded),prepared-questions.spec.ts:472,https-json-catalog.spec.ts:481(multi-byte text over the cap)prepared-questions.spec.ts:313,https-json-catalog.spec.ts:415,project-file-schemas.spec.ts("no markup-bearing field")additionalProperties: falseeverywhere;ProblemCollector.onlyKeys(project-file-problems.ts)__proto__is an unknown key; the schema walk inproject-file-schemas.spec.tsfails on any object without ithttps-json-catalog.ts:142-154https-json-catalog.spec.ts:334datatug-demo-projects0e5b98fplus the new filesfixtures/chinook-demo/(22 files = rows 1 to 22 of design 4.3)chinook-demo-fixture.spec.ts:49(manifest of sizes and SHA-256),:82,:166(new files pass validators and schemas),:208(the golden result recomputed from the fixture alone: 24 countries, 412 invoices, Ireland 8.32 first, Czech Republic 8.29, USA 1.53 at rank 17)fixtures/chinook-demo.README.mdInterpretations the design did not spell out:
urlTemplate,keys,sha256anddriverare required, the rest optional; with a fallback address every keyed table needs a checksum; addresses carry no port and no IP-literal host shape in the schema, and loopback and private numbers are refused by the validator; a text has no control characters; a table name has no leading underscore. Invoice rows are the chinookdb.com file (a local clone ofdatatug/chinookdbat its mirror commit0b6bb6b, SHA-25688eb7fae…c373c).ajv8.20.0 (already in the lockfile transitively) is added as a dev dependency for the schema-versus-validator spec only; the validators themselves have no dependency and noeval.Review round 1 (independent review at aff4a7b: 1 blocker, 6 minors), fixed at 58b964f
{table}exactly once, in a path segment that starts with a letter or digit; no%,?or#anywhere; no empty segment and no segment starting with a dot (checkUrlTemplate,project-address-rules.ts).expandUrlTemplate(template, table, trust)validates the table name, expands, parses, and re-checks the parsed URL (general rules, prefix list, dot segments); it returns aCheckedDataUrl, the only way to a fetchable URL (tableUrls(catalog, table, trust)for both templates). Property test over 20,000 generated templates x 10 table names; the reviewer's cases ported (project-address-rules.spec.ts,https-json-catalog.spec.ts).$schemaneeds a character; lengths counted in code points in the validator;homepageandupstream.repositoryallow no brace; a mutation test over about 2,500 documents (project-file-schemas.spec.ts) fails if either side accepts what only the other should refuse (the only allowed gap: rules a schema cannot state).checkProjectAddressdirect calls: IPv6 expanded and range-tested (all of::/8in every spelling, site-local, Teredo, NAT64 well-known and local-use, 6to4, ORCHID, discard, documentation); the host is read as the URL parser reads it;localhost..and empty labels refused.fixtures/chinook-demo/NOTICE.md(Chinook MIT text copied from upstreamLICENSE.mdat7f67772, trailing spaces removed because the repo's whitespace hook refuses them) anddata/geo/DATA-LICENSE.md, both in the manifest.Production bundle
Before: a clean copy of
origin/main(453423a); re-proved after review round 1; after: this branch. Same build-info stamp,pnpm nx build datatug-app --configuration=production --excludeTaskDependencies --skip-nx-cache.diff -rqof the twodist/apps/datatug-apptrees: no differences (1,797 files each; the sorted listing of per-file SHA-256 hashes hashes to9216987ae99ff52bca5e6b378d1441b7d2a685e980d509a185bc9828ce241235for both). Byte-identical, hashes included, as no shipped code imports the new files.Verification run locally
wb run -- pnpm exec vitest run src/lib/project-filesinlibs/datatug/main: 5 files, 534 tests pass; statement coverage of the new modules 96.7%, lines 98.4%pnpm nx lint datatug-main: clean;pnpm run check:zoneless: OK;tscover the library and spec configs: no error inproject-files🤖 Generated with Claude Code