Skip to content

feat(server): restore the Nitro control plane with registered routes - #24

Closed
RedStar071 wants to merge 2 commits into
mainfrom
feat/restore-nitro-server
Closed

feat(server): restore the Nitro control plane with registered routes#24
RedStar071 wants to merge 2 commits into
mainfrom
feat/restore-nitro-server

Conversation

@RedStar071

@RedStar071RedStar071 commented Aug 10, 2026

Copy link
Copy Markdown
Member

Restores apps/server, which #21 removed, and fixes the two P1 review findings from #2 that were never resolved against it: the built server registered no routes (404 on every path) and ignored the documented AGENT_ZERO_PORT.

Routes actually register now. The root cause of the original 404s is that this Nitro release ships with filesystem scanning disabled (serverDir defaults to false), so route files were silently ignored no matter where they lived. The config opts in explicitly:

exportdefaultdefineConfig({compatibilityDate: '2026-05-22',serverDir: true,});

Handlers under server/routes/ are one-line shells (health.get.ts, tasks/index.get.ts, tasks/index.post.ts, tasks/[id].get.ts, tasks/[id]/evidence.get.ts) over the transport-independent task API restored in src/router.ts, with the HTTP shaping (404s, body validation via the taskInput schema) in src/http.ts so it stays unit-testable without a listener.

AGENT_ZERO_PORT is honored.aube run start boots through a wrapper that maps the documented variable onto NITRO_PORT before the listener reads its environment; explicit NITRO_PORT/PORT still win. The mapping is a pure tested function.

Task checkouts are authorized against a managed root.POST /tasks is unauthenticated transport, so the repository field is no longer a raw filesystem path: it is an identifier that must canonically resolve (via realpath, so symlinks cannot escape) to a directory strictly inside the operator-configured AGENT_ZERO_CHECKOUT_ROOT. Without a configured root the route fails closed with 403 and runs nothing. The resolution is a pure tested function in src/checkout.ts.

Build follows the repo toolchain.build runs nitro build && tsdown, so the listener comes from the Nitro pipeline while the library surface and start wrapper go through the shared tsdown config, addressing the tsdown-bypass note from #2.

Verified against a real built server in the sandbox: with AGENT_ZERO_PORT=4040 the listener binds 4040 (3000 refuses), GET /health and GET /tasks return 200, GET /tasks/missing-task returns a JSON 404, and malformed or schema-invalid POST /tasks bodies return 400. The full check suite (check:repo, lint:ci, typecheck, test with 28 server tests, build) passes locally; the lockfile gains only the new importer (pure additions, resolved with aube 1.38.0).

One behavior note: taskResponse/evidenceResponse keep the in-memory task store semantics of the original server; the restored router.ts only adapts to the current modelFromEnvironment(config.model) signature and reports version 0.3.0.


View with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is enabled.

Confidence Score: 5/5

No blocking failure remains.

The prior path-access concern was tested through the HTTP endpoint and its predicted unauthorized execution did not occur.

T-Rex T-Rex Logs

What T-Rex did

  • Ran the reproducible built listener path-authorization harness to create fixtures, start the listener, send the four HTTP requests, and verify the task counts.
  • Observed that the absolute path traversal and symlink-escape external requests were rejected with HTTP 403 and left the task count at zero.
  • Observed that the in-root, relative repo checkout request returned HTTP 200 and created one completed read-only task with zero model calls.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (2): Last reviewed commit: "fix(server): authorize task checkouts ag..." | Re-trigger Greptile

Restores apps/server removed in #21 and fixes the unresolved review findings
from #2 against it: file-based routing is now actually enabled (serverDir is
opt-in in this Nitro release), so /health and the task API respond over HTTP,
and the documented AGENT_ZERO_PORT is honored through a start wrapper that
maps it onto NITRO_PORT before the listener boots. The build now runs tsdown
alongside nitro build for the library surface and start wrapper.
RedStar071 added a commit that referenced this pull request Aug 10, 2026
The Nitro control plane is being restored in #24 and honors this variable,
so dropping it as a leftover of the removed server no longer applies.
@socket-security

socket-securityBot commented Aug 10, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

DiffPackageSupply Chain
Security
VulnerabilityQualityMaintenanceLicense
Addednitro@​3.0.260522-beta981008292100
Added@​agent-zero/​github@​0.3.0N/AN/AN/AN/AN/A

View full report


export const taskInput = z
.object({
repository: z.string().min(1),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1securityUnauthenticated task route accepts arbitrary local paths

POST /tasks accepts any non-empty repository value without authenticating the caller, authorizing the requested checkout, or constraining it to an approved root. The value then reaches loadConfig, createRunner, and agent.run, allowing a client that can reach the listener to process arbitrary server-local directories and their repository policy. Resolve an authorized server-side repository identifier instead of accepting a filesystem path, and enforce canonical containment within managed checkout roots before task execution.

Artifacts

Baseline before PR #24 with no POST task route

  • A detached worktree at the parent commit was checked for the task POST route and HTTP handler; both were absent, establishing the pre-change baseline.

Runtime API validation source for unauthenticated task path acceptance

  • This executed script starts the built Nitro server without model credentials and sends unauthenticated POST requests using an empty and a controlled existing directory path.

Unauthenticated POST task path acceptance after PR #24

  • The live server returned HTTP 400 for an empty path and HTTP 200 for a controlled existing server-local directory without an Authorization header, with a completed agent task; this confirms the exposure.

Focused server HTTP tests

  • The focused server HTTP test suite was executed and all seven tests passed, confirming the checked transport behavior remains executable.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/server/src/router.ts
Line: 31
Comment:
**Unauthenticated task route accepts arbitrary local paths**`POST /tasks` accepts any non-empty `repository` value without authenticating the caller, authorizing the requested checkout, or constraining it to an approved root. The value then reaches `loadConfig`, `createRunner`, and `agent.run`, allowing a client that can reach the listener to process arbitrary server-local directories and their repository policy. Resolve an authorized server-side repository identifier instead of accepting a filesystem path, and enforce canonical containment within managed checkout roots before task execution.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude CodeFix in CursorFix in Cursor Cloud Agents

POST /tasks is unauthenticated transport, so the requested repository is
untrusted input. The route no longer accepts a raw filesystem path: the
body carries an identifier that must canonically resolve (realpath, so
symlinks cannot escape) to a directory strictly inside the operator
configured AGENT_ZERO_CHECKOUT_ROOT. Without a configured root the route
fails closed with 403 and runs nothing.
Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
@RedStar071
RedStar071 deleted the feat/restore-nitro-server branch August 10, 2026 09:39
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@RedStar071