Skip to content

feat(authoring) (2/5): runtime bindings, MCP probing and the security policies - #1

Closed
zjncs wants to merge 175 commits into
feat/authoring-domainfrom
feat/authoring-runtime
Closed

zjncs wants to merge 175 commits into
feat/authoring-domainfrom
feat/authoring-runtime

Conversation

@zjncs

@zjncs zjncs commented Oct 10, 2026

Copy link
Copy Markdown
Owner

Layer (b) of the authoring platform split (iflytek#934 on iflytek/skillhub), stacking on iflytek#935. This is the layer that wants the dedicated security review.

Note: this PR is stacked on the fork while iflytek#935 (layer a) is under review upstream; it will be retargeted to iflytek/skillhub main as soon as (a) lands. The diff below is exactly the (b)-only slice.

What this layer adds

Runtime bindings + validation layers

  • RuntimeBinding per draft: agent type (local-script, openai-compatible), config, tool allowlist, MCP server declarations — validated at save time, persisted as JSONB, managed via GET/PUT /drafts/{id}/runtime
  • CONFIG layer: validation.yaml spec parsing (defensive YAML), binding validation, MCP servers probed for real (initialize → tools/list) with tool discovery in the event stream; unknown toolFilters warn without failing
  • BEHAVIOR layer: script tasks through the runtime adapters — inline (cleared environment, isolated workspace, interpreter allowlist, path confinement) or docker (locked-down container: no network, dropped capabilities, read-only root, memory/cpu/pids caps, tmpfs); prompt tasks via the OpenAI-compatible adapter with an MCP tool loop; assertion evaluation (exit code, stdout/stderr contains, timeout)

Security policies

  • Shared AuthoringSecurityPolicy gates OpenAI-compatible and http/sse MCP endpoints at save time and again at connect time: cloud-metadata/link-local/multicast always rejected; loopback/RFC1918/ULA/CGNAT/RFC 2544 behind per-surface allow-private-endpoints flags (default off); unresolvable hosts rejected
  • stdio MCP: off by default; in docker execution-mode its command runs inside a hardened container torn down on close; envRefs limited to the operator-configured allowlist (default empty = all rejected)
  • execution-mode defaults to docker; inline fails startup outside local/dev/test (AuthoringStartupGuard)
  • HTTP redirects never followed; response bodies and stdio lines capped at 2 MiB

Verification

  • Security/MCP/adapter unit tests: policy classification per surface (hermetic DNS via an injected resolver), redirect refusal against the metadata range, response/line caps, envRef allowlist filtering, docker-wrapped command construction, real-container isolation checks, OpenAI tool-loop with MCP execution
  • AuthoringRuntimeFlowIntegrationTest (Testcontainers PostgreSQL): three-layer validation with inline script execution, script stdout in the event stream, and save-time rejection of cloud-metadata endpoints, non-allowlisted envRefs and metadata-range LLM endpoints
  • Full backend suite running on the branch (each layer green on its own)

Known limitation (documented): the policy resolves hostnames at check time; the HTTP client re-resolves at connect time, which mitigates but cannot fully eliminate DNS-rebinding races.

FenjuFu and others added 3 commits September 29, 2026 12:16
…t entries

Signed-off-by: FenjuFu <fufenjupku@gmail.com>
Add a first-class zcode profile so skills can be installed into ZCode's
skills directories with --agent zcode:

- project-level: <project>/.zcode/skills/
- user-level: ~/.zcode/skills/

The profile follows the existing makeProfile pattern with automatic
detection of both scopes, and is covered by unit tests. Docs tables and
the CLI changelog are updated accordingly.

Signed-off-by: twodogegg <971270272@qq.com>
reward-* tags pointed at PR merge commits and statistic-* tags at the
default branch HEAD, so they became the nearest tag in git describe for
later commits. statistic-* releases were also created without
--latest=false, so the GitHub API marked them as the Latest release.

- Point new reward-* / statistic-* tags at a parentless empty-tree commit
  (the merge commit SHA is kept in its message) so no branch reaches them;
  tag contents and dates are read as before
- Create statistic-* releases with --latest=false
- Drop the describe-based "new commits since last statistic" check, which
  cannot see detached tags; count-reward.ts already exits when there is
  no reward data for the previous month

Same fix as iflytek/astron-agent#1695.

Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 10, 2026 06:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@zjncs

zjncs commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

Full-suite verification for this layer: clean mvnw clean test on the branch — 1101 tests, 0 failures, 0 errors (1 skip = the docker adapter test without a docker daemon). The earlier red run mentioned in passing was an artifact of a stale build directory (rebase leftovers), not the branch; this clean run is the authoritative result.

Tivonsico and others added 4 commits October 11, 2026 00:29
Both checks gate every pull request but were not mentioned in the contribution guide, so first-time contributors only discover them after opening a PR.

Signed-off-by: FenjuFu <fufenjupku@gmail.com>
Signed-off-by: lys1313013 <lys1313013@gmail.com>
Signed-off-by: Danny5487401 <64348131+Danny5487401@users.noreply.github.com>
@zjncs
zjncs force-pushed the feat/authoring-domain branch from c75b210 to 56531d2 Compare October 12, 2026 03:21
@zjncs
zjncs force-pushed the feat/authoring-runtime branch from fc75d54 to f1ebf3c Compare October 12, 2026 03:25
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
XiaoSeS and others added 27 commits October 20, 2026 16:16
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
…oard

fix(suite): support copying install commands over HTTP
…con-968

fix(auth): bundle Keycloak, Auth0 and Okta login icons
…-closeout

docs(namespace): clarify invitation recovery and delivery status
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
…lity

fix(dsh): support verified Harness 0.2.1-rc.2 compatibility
…ry-20261020

feat(github-sync): import and continuously sync public GitHub skills
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
chore(dsh): prepare 0.3.1 compatibility release
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
…rage-design

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
…-design

feat(storage): add S3-compatible deployment options
Layer (b) of the authoring platform (iflytek#934), stacking on iflytek#935:

- **Runtime bindings**: agent type + config + tool allowlist + MCP server
  declarations per draft, persisted as JSONB and validated at save time;
  local-script and OpenAI-compatible agent types
- **CONFIG and BEHAVIOR validation layers**: validation.yaml spec parsing
  (defensive YAML), per-task execution through the runtime adapters
  (inline subprocesses with a cleared environment, or the docker backend
  with a locked-down container), MCP servers probed for real during
  validation with tool discovery surfaced in the event stream; assertion
  evaluation (exit codes, stdout/stderr contains, timeouts)
- **Security policies** (the layer that wants the dedicated review):
  the shared AuthoringSecurityPolicy gates OpenAI-compatible and http/sse
  MCP endpoints at save time and again at connect time — cloud-metadata
  and link-local addresses are always rejected, loopback/RFC1918/ULA/
  CGNAT/RFC2544 ranges sit behind per-surface flags; stdio MCP transport
  is disabled by default and, in docker execution mode, wraps its command
  in a hardened container (no network, dropped capabilities, read-only
  root, resource caps) that is torn down on close; envRefs may only name
  variables in the operator-configured allowlist; docker execution-mode
  is the default and inline mode fails startup outside local/dev/test;
  HTTP redirects are never followed and response/stdio line sizes are
  capped at 2 MiB.

Verified: security-policy and MCP unit tests (policy classification per
surface, redirect refusal, response caps, envRef filtering, docker-wrapped
commands), adapter tests including a real-container isolation check, and
the runtime flow integration test (three-layer validation with inline
script execution; cloud-metadata/envRefs/LLM-surface bindings rejected
at save time).

Signed-off-by: zjncs <18910855655@163.com>
…ime orchestrator

Rebases the runtime layer onto main, which now carries iflytek#935 plus the
follow-up hardening (FutureTask per run with duplicate-submit fencing,
a wall-clock watchdog on the timer, settle-first cancellation with
worker interrupt, appendTerminalEvent, revision-pinned
materializeSnapshot, and the PackageEntry streaming API).

The three-phase orchestrator keeps all of it: the watchdog remains the
hard deadline while the behavior layer keeps its between-task soft
deadline; the cooperative cancel signal is now the worker's interrupt
status; the config/behavior layers read the pinned snapshot and the
draft id from the run instead of a reloaded draft. The upstream
orchestrator test is adapted to the runtime-layer constructor (no
adapters registered — the lifecycle paths under test never reach the
config layer) and passes unchanged in its assertions.

Signed-off-by: zjncs <18910855655@163.com>
…s deletable

The validation container drops every capability, including DAC_OVERRIDE,
so the mounted workspace must be world-readable on the host for the
in-container interpreter to open the script, and directories must be
traversable and writable so the script can create artifacts. Fresh JVM
temp directories are owner-only on Linux (umask 077 runners, hardened
hosts), which broke script execution with 'sh: can't open: Permission
denied' — macOS Docker Desktop masks this by remapping ownership inside
its VM, which is why the local suite passed while the hosted-runner CI
failed.

The container also runs as the host JVM's uid:gid (--user) so files the
script creates inside the mount belong to the same user that cleans the
workspace up; running as the image-default root left artifacts that the
host user (and the test harness) could not delete.

Signed-off-by: zjncs <18910855655@163.com>
The push of this rebase did not create a workflow run (GitHub-side
hiccup); an empty commit to retrigger the backend-tests check.

Signed-off-by: zjncs <18910855655@163.com>
Picks up upstream API drift (S3 storage options, github-sync, dsh 0.3.1)
on top of the authoring endpoints.

Signed-off-by: zjncs <18910855655@163.com>
@zjncs
zjncs force-pushed the feat/authoring-runtime branch from 831e58d to d4cd9f0 Compare October 21, 2026 08:57
@zjncs

zjncs commented Oct 28, 2026

Copy link
Copy Markdown
Owner Author

Superseded by the split: layer b1 is under upstream review as iflytek#1003, and the security half (b2) is fork PR #7. Closing this pre-split PR to keep the queue unambiguous.

@zjncs zjncs closed this Oct 28, 2026
Sign up for free to 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.