Story: Developer brings up a cluster and deploys a chart
Story ID: STORY-001 Status: Revision 1 Created: 2026-10-13
Statement
As a developer, I want xianyun up to start a local cluster and install the deployers my config lists, so that I can validate a change against a real Kubernetes API without assembling the environment by hand.
Trigger
The developer runs xianyun up in a directory containing xianyun.yaml that lists at least one deployer.
Acceptance Criteria
Scenario: A namespace deployer runs after the cluster starts
Given a k3d-driver config with a "namespace" deployer that lists namespace "demo"
And docker and k3d are available
When the developer runs "xianyun up"
Then the exit code MUST be 0
And "kubectl get namespace demo" MUST succeed
And "kubectl get nodes" MUST report a Ready node
Scenario: Deployers run in dependency order
Given deployer "ingress" with needs ["namespaces"] and a "namespace" deployer named "namespaces"
When the developer runs "xianyun deploy"
Then "namespaces" MUST finish before "ingress" starts
And a failure in "namespaces" MUST stop the run before "ingress" starts
Scenario: A missing tool is reported, not a panic
Given a k3d-driver config and no "k3d" on PATH
When the developer runs "xianyun up"
Then the exit code MUST be non-zero
And the message MUST name "k3d"
And the output MUST NOT contain "panicked at"
Scenario: Deploying one repository’s deployers
Given deployers "web" and "api" that use different repositories
When the developer runs "xianyun deploy --repo web"
Then only the "web" deployer MUST run
EARS Constraints
- When
upis run, the system shall start the cluster before running any deployer. - If a deployer type has no registered manager, then the system shall fail naming the type and shall not report success.
- While a deployer is running, the system shall not start a deployer that lists it in
needs. - If the cluster API doesn’t answer within the wait period, then the system shall exit non-zero without running deployers.
Autonomy Limits
Not applicable; the actor is a human. (An agent calling the same flow through MCP is covered in STORY-002.)
Security Mapping
This story crosses three trust boundaries (config sources to the loader, Xianyun to the cluster, Xianyun to other tools), so all six STRIDE categories are listed.
| Concern | Addressed By |
|---|---|
| Spoofing (a cluster that isn’t the intended one) | Caproni’s documentation says up verifies connectivity to an external cluster’s kubeconfig context before deploying; that wasn’t checked in the Rust code in this review, and showing the context name in the output isn’t specified |
| Tampering (option-shaped positional values, unpinned discovery image) | SR-009, SR-013 (not yet met) |
| Repudiation (which hooks and deployers ran) | No durable record today; SR-014 (not yet met) |
| Information disclosure (temporary kubeconfig left readable) | SR-010, TM-KUBE-002 (not yet met) |
| Denial of service (oversized or alias-bomb config; cluster that never answers) | Fourth EARS constraint covers the wait; NFR-006 covers parsing (not yet met) |
| Elevation of privilege (config-defined hooks) | Prepare hooks run during up (TM-EXEC-001); SR-002 covers the MCP case |
Derived Tests
| Scenario | Test type | Framework |
|---|---|---|
| Namespace deployer runs after start | Integration | nix/tests/e2e-k3d.nix (Tier 2, needs a deployer-bearing config) and crates/xianyun-cli/tests/deploy_registry.rs (planned, unit-level) |
| Dependency order | Unit | #[test] in crates/xianyun-deploy/src/deploy/orchestrator.rs (exists) |
| Missing tool reported | Unit | #[test] in crates/xianyun-cluster/tests/k3d_driver.rs (error variant exists; message assertion planned) |
| Single repository | Unit | #[test] in crates/xianyun-cli/tests/deploy.rs (ignored live test exists) |
Standards Mapping
- SLSA Level: N/A
- SSDF Practices: N/A
- SCVS Controls: N/A
Dependencies
- Depends on: none
- Blocks: STORY-002 (the agent flow reuses
upanddeploy) - Related ADR: ADR-0002, ADR-0008
- Related spec requirement: FR-004, FR-005
Notes
- The first, second, and fourth scenarios pass in the
e2e-deployNixOS VM test, which uses a namespace, a Kustomize overlay, and a Helm chart rather than a Helm chart from a registry. Until 2026-10-14 the first and second failed: the production setup registered no deployer managers (spec GAP-001, closed). - The third scenario has a code path (
DriverError::DriverNotFound("k3d")ink3d.rs:86) but no CLI-level test checks the message or the absence of a panic. upwith the mock driver can’t stand in for a cluster: it builds a real kubectl client against the mock’s fake kubeconfig, and the run stopped at “getting kubectl version” in this review.