Repository navigation
Conversation
knihit
force-pushed
the
wc/04-stub-api
branch
from
October 24, 2026 19:28
e4f33ec to
0c0dcd7
Compare
7 of 11 tasks
knihit
force-pushed
the
wc/04-stub-api
branch
2 times, most recently
from
October 25, 2026 19:56
a5b0ca0 to
66fa3a7
Compare
knihit
marked this pull request as ready for review
October 25, 2026 20:03
knihit
requested review from
georgebearden,
ihmaws,
shsenior and
simonkrol
as code owners
October 25, 2026 20:03
knihit
force-pushed
the
wc/04-stub-api
branch
from
October 25, 2026 20:05
66fa3a7 to
4f8e7f3
Compare
ihmaws
reviewed
Oct 27, 2026
knihit
force-pushed
the
wc/04-stub-api
branch
4 times, most recently
from
October 27, 2026 21:25
539cbd3 to
8a31a83
Compare
Base automatically changed from
wc/03-api-contract
to
integration/workflow-canvas
October 27, 2026 22:05
knihit
force-pushed
the
wc/04-stub-api
branch
from
October 27, 2026 22:06
8a31a83 to
24d927c
Compare
The core holds the rules of the API contract and does no IO: a check of workflow text that reports every diagnostic code with its position, an in-memory workflow store with hash-based saves, and a run simulator that works out each stage from an injected clock. A test fails if a core file imports a module that does IO or reads the clock, randomness or network. Adds the yaml parser (2.9.1, exact version) as a dev dependency, and the `test:stub` script. Type stripping runs the stub on Node 24 without a build step, so tsconfig.node.json checks it with erasableSyntaxOnly.
A thin adapter on node:http, with no new dependency. It checks the Host, Origin, token, content type and body, reads the request into typed values and hands the rest to the core, in the order the contract fixes. The stub trades a one-time launch code for a session token, as the contract says. It is for local development and keeps no real credentials. `npm run stub` starts it on 127.0.0.1:5174 and prints the launch address.
Each test starts the stub on a free port, calls it, and checks the reply against the schema of its status in api/openapi.yaml. They cover the six calls, DUPLICATE_KEY and the other diagnostics, the 409 conflicts, the header and body rules, and the order of checks. A fake clock moves the launch window and the stages of a run, so no test waits.
The config starts the stub after the app and exports its URL and launch code, so an end-to-end test can call it. One test shows the wiring. No page uses the stub yet. CI runs `npm run test:stub` on both Node versions.
Adds a README section on running it, what it serves and how it is split, and a changelog entry under Unreleased.
The test now allows only the named createHash import from node:crypto, forbids Date, Math.random, performance, the random functions and globalThis.crypto, and walks core/ at any depth. A set of bad snippets proves each rule. Run ids and timestamps no longer use Date, so the core formats time with its own date arithmetic, which is tested against Date.
A second document is reported at its --- line instead of 1:1. The line and column lookup counts code points from a prefix table, so a 250 KB single-line flow mapping is checked in well under 2 seconds instead of over a minute. A key is named in a message only when it is short and plain, so a key that looks like an access key or a hash is not echoed.
badRequest(), badName() and codePointLength() replace repeated literals, and the test literal for a one-stage workflow is one helper. A test compares the error codes, their statuses, the diagnostic codes, the patterns and the limits of the stub with api/openapi.yaml.
The loopback test reads the address the socket is bound to and checks that a non-loopback address of the machine refuses the connection. The launch window starts when the stub listens. A body past 16 MiB is cut off. npm run dev forwards /api to the stub with the stub's own Origin, so the page and the API share one origin; this is a few lines of config where serving the built page would need a file server with path checks. The stub prints the dev server address, which is a live link. Vitest runs the API and stub tests in Node through a project, so a test file needs no pragma.
Describes the scaffold, every npm script, the API contract and how to run the page against the stub, without notes about later changes.
The page still calls the relative /api. WC_API_TARGET, read in one helper (stub-api/target.ts), picks the server behind the dev proxy and the Playwright run. Unset, it is the stub. The proxy sends the target's own Origin. npm run dev:stub starts the stub and Vite together.
…its error A bad WC_API_TARGET now stops dev, preview and the Playwright configs, but not build or the unit tests, which never use the proxy. The error message no longer repeats a user, password, query or fragment. A bad STUB_PORT gives the same one-line error instead of a stack trace, and port 80 reaches the stub as 80. A test loads playwright.shared.ts with and without WC_API_TARGET, so dropping the env read fails it.
The dev:stub launcher is covered by tests, including that Vite gets an empty WC_API_TARGET. A command that ignores SIGTERM gets SIGKILL after a grace time, set by an injectable timer so the tests need no sleeps. The stub prints the right hint when the dev server runs beside it. The README says the launch code works once.
The Playwright server list moves to a module that reads no environment, so a mistyped WC_API_TARGET or STUB_PORT in the shell no longer fails npm test. The shared config is tested through a dynamic import with the environment set by the test. The redaction masks everything up to the last @, so spaces and unencoded /, # and ? in a password do not leak. The test child exits when its IPC channel closes. The README notes that a SIGKILLed launcher can orphan its children, and the changelog notes that STUB_PORT=0 is now rejected.
redact() masks the userinfo only when the authority holds an `@`. An `@` that appears only after the authority ends (`http://h:1/?k=a@x`) cannot be told from a password with a `/`, `?` or `#`, so everything after `://` is masked in that case. Rewrap a README line and say that STUB_PORT must be 1-65535 without "now".
…d end A reload drops the session token and the launch code from the page. The printed address then failed with 'launch code is not valid'. The stub of dev:stub, and the one that Playwright starts, now give the same token for the same code, with no time limit. A stub started on its own still follows the contract: one use, within 60 seconds.
The dev proxy set Origin to the target's on every request, so any page on another localhost origin could drive POST /api/run through the dev server. Swap the Origin only when it is the page's own (a loopback name on the port the server listens on) and forward any other Origin, or none, unchanged so the API refuses it. Add tests for a foreign and a missing Origin through the proxy, and the Origin header to the README curl example.
knihit
force-pushed
the
wc/04-stub-api
branch
from
October 27, 2026 23:45
24d927c to
597e326
Compare
This branch has not been deployed
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.
Description
Stub API (
workflow-canvas/stub-api/):api/openapi.yaml:POST /api/session,GETandPUT /api/workflow,POST /api/validate,POST /api/runandGET /api/runs/{id}. The UI and the real backend can then be built against one contract.kiro-cliharness. The data is fixed: ahelloworkflow with adraftstage (k-developer) and areviewstage (k-quality-assurance).core/holds the workflow check, the file store and the run simulator, and does no IO.http/is a thin adapter onnode:httpthat checks headers and bodies and hands the rest to the core. A test fails if a core file imports anything but its own modules,yamlandcreateHash, or usesDate,Math.random,performance, a random function or the environment. It walkscore/at any depth, and a set of bad snippets proves each rule.127.0.0.1only, and a test reads the address the socket is bound to and checks that a non-loopback address of the machine refuses the connection. It trades a one-time launch code for a session token, as the contract says, and the other calls need that token. It is a local development stub with no real auth, and the README says so.API backend switch:
WC_API_TARGET(an http or https origin) picks the server behind/api. It is read in one helper,stub-api/target.ts. Unset, it is the stub. A bad value stops the command that needs it with a one-line error that hides credentials, not a stack trace;buildandnpm testnever read it.STUB_PORTmust be 1-65535, soSTUB_PORT=0or any other bad value is rejected: the stub needs a fixed port. The page still calls the relative/api; only the proxy target changes.Origin, not always the stub's. Playwright starts the stub only whenWC_API_TARGETis unset; when it is set, the same tests run against that server.npm run dev:stubstarts the stub and Vite together (a small node launcher, no new dependency). Ctrl+C stops both.npm run devstays Vite only.Origincheck and thePOST /api/sessionstep fromopenapi.yaml, so the same e2e tests can show it matches the stub. The README has one line per mode: stubbed dev, real dev, stubbed e2e, real e2e.Tests:
openapi.yaml. They cover all six calls, theDUPLICATE_KEYand other diagnostics of the contract's examples, the 409 conflicts (file changed, file already exists, file gone), the header and body rules, and the order of checks.Origin; a bad value is refused), the Playwright server list instub-api/web-servers.ts, which reads no environment (no stub when a target is set), the shared Playwright config loaded fresh with and withoutWC_API_TARGET, theSTUB_PORTchecks (including port 80), the redaction of secrets in the error (including spaces and/,#or?in a password; an@after the authority masks everything after://), thedev:stubcommands (Vite gets an emptyWC_API_TARGET) and the launcher (SIGKILL after a grace time, on an injected timer; its test child exits when its parent dies). None of them sleeps./apireaches the stub through the proxy.openapi.yaml. A test of a 250 KB single-line flow mapping checks the position lookup against a 2 second bound, with no sleep.npm run test:stubon Node 24 and 26.Dependency (new):
yaml2.9.1, pinned to the exact version, as a dev dependency. The contract fixes YAML 1.2 with the core schema and asks for exact line and column positions, which this parser gives. It has no dependencies of its own. The HTTP adapter uses onlynode:http.Docs and config:
workflow-canvas/README.mdis brought up to date: layout, every npm script, the API contract, the stub and how to run the page against it.VERSIONis untouched.npm run stub,npm run dev:stubandnpm run test:stub.tsconfig.node.jsonincludesstub-api/, and Vitest runsapi/andstub-api/in Node as a separate project from the UI tests.npm run devforwards/apito the stub, or toWC_API_TARGET.Fixes from the hands-on QA run
npm run dev:stub. A reload drops the session token and the launch code from the page, and the printed address then failed with "The launch code is not valid", so the only way out was to restart the stub. The stub thatdev:stubstarts, and the one that Playwright starts, now take the launch code again and give the same token, with no time limit (SessionGateoptionreusableLaunchCode, switched on by the--with-dev-serverflag).npm run stubon its own still follows the contract: one use, within 60 seconds. This is a deliberate, documented gap between the dev stub and the contract; a real server is unchanged. After a reload the person opens the printed address again.POST /api/sessionon a reusable stub (same token again, still taken after the 60 seconds, a wrong code still refused), and an end-to-end test that the stub gives the same session for the same code. The first two failed before the change.npm test(387 tests),npm run test:e2e(7 tests) andnpm run screenshotspass; lint and typecheck are clean.Type of Change
package.json,Cargo.toml, or CLI dependency)workflow-canvas/Testing
npm test(tests/scripts/**/*.test.js): not run.node --test tests/scripts/readme-no-internal-wording.test.jspasses 4 of 4. It is not one of the CI checks.cli/changed:cd cli && make testpasses (Rust + Python + conformance suites)cli/README.md'ssynth/installsteps, then ran
kiro-cli chat --agent <agent-name>(or the Claude Code equivalent)—
npm run benchmark -- --agent <agent-name> --replicates 1(seedocs/guides/benchmarking.md)rule); formats without comment syntax (e.g. JSON) are exempt
Checked in
workflow-canvas/on Node 24 (the CI matrix also runs Node 26):npm run lint,npm run typecheck,npm test(382 tests, also with a badWC_API_TARGETand with a badSTUB_PORTin the shell),npm run test:stub,npm run api:lint,npm run buildandnpm run test:e2e(6 tests, against the stub and again withWC_API_TARGETset to another running server) all pass. The committed screenshots are unchanged.Screenshots: none. There is no UI change in this PR.
Checklist
cli/changes,cd cli && make lintpasses (cargo clippy -- -D warnings+cargo fmt --check)Agents Affected
None. This changes
workflow-canvas/only. The agent names in the stub are sample data in a fixed workflow file.Notes for Reviewers
integration/workflow-canvas<- Add workflow-canvas scaffold: Vite, React, Cloudscape, CI #77 (wc/01-scaffold) <- Add Playwright end-to-end tests and screenshots for workflow-canvas #78 (wc/02-e2e) <- Add the workflow canvas HTTP API contract and its test #80 (wc/03-api-contract) <- this PR (wc/04-stub-api). Base iswc/03-api-contract. Draft, so review Add workflow-canvas scaffold: Vite, React, Cloudscape, CI #77, Add Playwright end-to-end tests and screenshots for workflow-canvas #78 and Add the workflow canvas HTTP API contract and its test #80 first.openapi.yaml. The stub doubles as a functional test harness for it: the schema checks instub-api/test-support/contract.tswork on any reply.npm run devforwards/apito the target with the target's ownOrigin(the stub by default), so the page and the API share one origin. I chose that over serving the built page because it is a few lines of config; serving the page needs a file server with path checks and a build first.dev:stublauncher is killed with SIGKILL, its children may keep running (the README says so).