Commit Graph
59 Commits
Author SHA1 Message Date
Drew Newberry 1d33d4c2a7 fix(cluster): skip DNS probe for IP-literal registry hosts (#229) 2026-03-11 09:20:56 -07:00
Drew Newberry 53b3cb76a2 feat(cli): detect port conflicts before gateway start, add sandbox delete --all, and improve spinner spacing (#225) 2026-03-11 01:06:23 -07:00
Drew Newberry 756950140c refactor(python): rename navigator module to openshell and migrate config to gateway paths (#220) 2026-03-10 22:24:04 -07:00
Drew Newberry d6c6e97679 chore: remove navigator references from codebase (#208) 2026-03-10 14:46:11 -07:00
Drew Newberry 984d1a6e5c chore: rename project from NemoClaw to OpenShell (#198) 2026-03-10 11:49:09 -07:00
Drew Newberry 1cf54ca055 feat(bootstrap): switch container registry from CloudFront CDN to GHCR with token auth (#167) 2026-03-09 23:46:23 -07:00
Miyoung Choi 066c2f80fe ci(docs): finish setting up PR doc preview workflow (#160) 2026-03-09 22:58:27 -07:00
Drew Newberry c355ad3696 fix(docker): remove unsupported npm dedupe -g command (#194)
npm 11 does not support `npm dedupe -g` in global mode, causing the
sandbox container build to fail with error code EDEDUPEGLOBAL.

The dedupe was intended to remove nested copies of vulnerable
dependencies, but npm 11 already handles global package installation
differently. The force-upgrade of tar and @hono/node-server already
ensures the patched versions are installed.
2026-03-09 22:12:34 -07:00
Drew Newberry a83109c359 fix(containers): remediate high-severity container vulnerabilities and remove openclaw (#191) 2026-03-09 21:39:14 -07:00
Drew Newberry a2de1f24e5 feat: add Cloudflare tunnel auth support (#178) 2026-03-09 18:39:42 -07:00
Drew Newberry ffeaf0dd59 fix(sandbox): fix create ordering race, dual-registry credentials, and policy identity clearing (#176) 2026-03-08 15:57:00 -07:00
Piotr Mlocek 68525bb81a fix(build): propagate packaged version through cluster artifacts (#164)
Pass the computed cargo version through Docker and cluster packaging paths so deployed clusters report the built artifact version while keeping latest and explicit version tags aligned.
2026-03-06 18:17:03 -08:00
Piotr Mlocek 31d7ca53ff refactor(inference): simplify routing — introduce inference.local, remove implicit catch-all (#146)
Remove multi-route CRUD system and replace with single managed cluster
route (inference.local). Key changes:

- Remove inference route CRUD RPCs and CLI commands
- Remove InspectForInference OPA action; policy is binary allow/deny
- Introduce AuthHeader enum and InferenceProviderProfile in navigator-core
- Router is now provider-agnostic: auth style carried on ResolvedRoute
- Replace InferenceRouteSpec with ClusterInferenceConfig (2 fields vs 8)
- Rename proto: routing_hint->name, SandboxResolvedRoute->ResolvedRoute,
  GetSandboxInferenceBundle->GetInferenceBundle, drop sandbox_id param
- Rename RouteConfig.route -> RouteConfig.name; use inference.local
- Add 'nemoclaw cluster inference update' for partial config changes
- Delete stale navigator.inference.v1.rs checked-in proto file
- Update architecture docs, agent skills, and CLI reference

Closes #133
2026-03-06 13:54:23 -08:00
Drew Newberry 91c7f84ccf feat(sandbox): upgrade Landlock to ABI V2 and fix sandbox venv PATH (#151) 2026-03-06 11:55:57 -08:00
Drew Newberry a8e9b43dcc refactor(e2e): replace bash e2e tests with Rust integration tests (#150) 2026-03-06 09:01:49 -08:00
Drew Newberry 338fa121c9 chore(cluster): upgrade k3s to v1.35.2 and remove K3S_VERSION from mise.toml (#152) 2026-03-06 01:35:06 -08:00
Drew Newberry 8c63413809 fix(docker): remediate container scan vulnerabilities across CI, cluster, and sandbox images (#144) 2026-03-05 22:08:31 -08:00
Drew Newberry fc22cfd2f7 fix(cluster): replace openssl with /dev/urandom in cluster image (#139) 2026-03-05 16:20:19 -08:00
Drew Newberry dfe7ba732e fix(cluster): add openssl package to cluster image (#137)
The entrypoint script uses 'openssl rand -hex 32' to generate the SSH
handshake secret (added in e9f1071), but the rancher/k3s base image
does not include openssl. This causes the container to exit with code
127 immediately on startup.

Fixes #136
2026-03-05 14:43:03 -08:00
John T. MyersandJohn Myers e9f10719f4 fix(security): harden sandbox SSH with mandatory HMAC secret, NetworkPolicy, and nonce replay detection (#127)
* fix(security): harden sandbox SSH with mandatory HMAC secret, NetworkPolicy, and nonce replay detection

Closes #25

- Make NEMOCLAW_SSH_HANDSHAKE_SECRET mandatory: server and sandbox both
  refuse to start if the secret is empty/unset. Cluster deployments
  auto-generate it via openssl rand in the entrypoint script.
- Add Kubernetes NetworkPolicy restricting sandbox port 2222 ingress to
  the gateway pod only, preventing lateral movement from other cluster
  workloads.
- Add NSSH1 nonce replay detection with a TTL-bounded cache, rejecting
  replayed handshakes within the timestamp validity window.
- Add unit tests for verify_preface (valid, replay, expired, bad HMAC,
  malformed) and env injection.

* fix(deploy): pass sshHandshakeSecret in fast deploy helm upgrade

---------

Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
2026-03-05 12:21:18 -08:00
Drew Newberry 4a78865b90 feat(ci): add CLI binary builds and snapshot release to publish workflow (#110) 2026-03-04 23:57:22 -08:00
Drew Newberry 99bba8028a feat(sandbox): support policy discovery and restrictive defaults on sandbox containers (#84) 2026-03-04 17:17:22 -08:00
Drew Newberry d920d39dd4 chore: more contributing improvements (#103) 2026-03-04 13:20:24 -08:00
Drew Newberry 90da02a7ed chore: simplify contributing workflow and documentation (#92) 2026-03-04 13:06:32 -08:00
Drew Newberry 9099bc3972 chore: rename Navigator to NemoClaw across user facing contracts (#73) 2026-03-03 11:41:19 -08:00
Drew Newberry 46381e65cf fix(ci): harden cargo build retry by wiping target dir and disabling sccache (#77)
The multi-arch publish job fails with 'extern location does not exist'
errors for version_check when BuildKit cache mounts contain stale
artifacts. The existing retry logic (cargo clean + retry) was
ineffective because:

1. cargo clean relies on its own metadata to decide what to remove,
   which can itself be stale on BuildKit cache mounts shared across
   different build profiles (debug vs release).

2. sccache remained enabled during the retry, so a corrupt memcached
   cache entry would reproduce the same failure even after cleaning.

Replace cargo clean with rm -rf /build/target/* for a thorough wipe,
and unset RUSTC_WRAPPER on retry so cargo falls back to raw rustc.
2026-03-03 11:32:07 -08:00
Alexander Watson 1d7909cb38 chore: add open-source compliance files and SPDX headers (#71)
Add Apache 2.0 licensing, SPDX copyright headers on all source files,
DCO enforcement, third-party notices, and CI enforcement.

- LICENSE: Apache License 2.0 full text
- DCO: Developer Certificate of Origin 1.1
- SPDX headers on all 176 source files (.rs, .py, .proto, .rego, .sh,
  .toml, .yaml, Dockerfiles)
- scripts/update_license_headers.py: header management with --check mode
- scripts/generate_third_party_notices.py: dependency license aggregation
- THIRD-PARTY-NOTICES: generated listing of all Rust and Python deps
- build/license.toml: mise tasks for license:check and license:update
- CI: license-headers job in checks.yml, DCO check workflow
- CONTRIBUTING.md: DCO sign-off requirement and license header docs
- Cargo.toml: license changed to Apache-2.0, repository URL updated
- pyproject.toml: license field added

Closes #58
2026-03-03 09:30:56 -08:00
Drew Newberry a17959f76e fix(sandbox): eliminate SSH transport race causing flaky E2E tests (#69) 2026-03-03 01:24:57 -08:00
Drew Newberry 53899f92f9 chore(ci): switch sccache from local disk to memcached backend (#68) 2026-03-03 00:20:31 -08:00
Drew Newberry fc29a30bc7 fix(ci,publish): harden publish flow and cache nemoclaw wheel builds (#55) 2026-03-02 18:41:58 -08:00
Drew Newberry e0909850e9 test: bring back e2e tests on Github CI (#48) 2026-03-01 22:48:51 -08:00
Drew Newberry a71f2a5e7d ci: add GitHub Actions CI workflow with lint, test, and image build (#1) 2026-02-27 10:10:28 -08:00
Drew Newberry 52a0d980f0 chore(sandbox): unpin openclaw 2026-02-26 12:32:27 -08:00
Drew Newberry 5fd4885a7c feat(sandbox): VS Code Remote-SSH support with platform detection fix and network policy (!42)
Closes #34

## Summary

- Add `nav ssh-proxy` name mode (`--cluster`/`--name`) and `nav sandbox ssh-config` for VS Code Remote-SSH integration
- Fix VS Code Remote-SSH platform misdetection (was defaulting to Windows/PowerShell)
- Fix sandbox network policy for VS Code server connectivity
- Fix sandbox user shell configuration

## Problem

VS Code Remote-SSH was failing to connect to Navigator sandboxes due to three issues:

1. **Platform misdetection**: VS Code sends `uname -rsv` after a `ready:` marker and expects a response within ~1ms. Forced PTY allocation in `shell_request`, interactive bash (`-i`), and leaked supervisor env vars added enough latency that VS Code timed out and defaulted to "Platform: windows", then tried `powershell`.
2. **Broken network policy**: The `vscode` entry in `dev-sandbox-policy.yaml` was at the YAML top-level instead of nested under `network_policies:` (indentation bug). The VS Code server binary also needed a glob entry.
3. **No login shell**: The sandbox user had `/usr/sbin/nologin` as its shell.

## Changes

| File | Change |
|------|--------|
| `crates/navigator-sandbox/src/ssh.rs` | Remove forced PTY in `shell_request`, remove `-i` flag from pipe exec, add `env_clear()` + explicit `SHELL`/`PATH` to both shell spawn paths |
| `deploy/docker/sandbox/Dockerfile.base` | Change sandbox user shell to `/bin/bash`, set home to `/sandbox`, add `.bashrc`/`.profile` |
| `dev-sandbox-policy.yaml` | Fix `vscode:` indentation under `network_policies:`, add `/sandbox/.vscode-server/*` binary glob |
| `crates/navigator-cli/src/main.rs` | Add `--cluster`/`--name` to `SshProxy`, add `SshConfig`/`Policy`/`Logs` subcommands (rebase merge) |
| `crates/navigator-cli/src/ssh.rs` | Update `print_ssh_config` to use `--cluster` flag |
| `examples/vscode-remote-sandbox.md` | User-facing example and docs |

## How to use

```bash
# Create a persistent sandbox
nav sandbox create --keep my-sandbox

# Generate SSH config
nav sandbox ssh-config my-sandbox >> ~/.ssh/config

# Open VS Code
code --remote ssh-remote+nav-my-sandbox /sandbox
```

## Testing

- All 307 tests pass
- Clippy clean on modified crates
2026-02-26 09:06:37 -08:00
Drew Newberry 07b5ddac33 feat(cluster): speed up local deploy loop with incremental change tracking (!53)
## Summary
- Track last deployed local changes and only redeploy new deltas in auto mode.
- Add per-component fingerprints (server/sandbox/helm) persisted to .cache/cluster-deploy-fast.state.
- Update docs for the new incremental deploy behavior.

```
mise run cluster

....

________________________________________________________
Executed in   75.21 secs      fish           external
   usr time  578.03 millis    0.25 millis  577.78 millis
   sys time  364.45 millis    1.22 millis  363.22 millis
```

with a change to `navigator-sandbox` (triggers rust recompile)

```
⟩ time mise run cluster:deploy
[cluster:deploy] $ build/scripts/cluster-deploy-fast.sh
Change detection took 0s
Fast deploy plan:
  build server:  0
  build sandbox: 1
  helm upgrade:  1

...

________________________________________________________
Executed in   25.88 secs      fish           external
   usr time  618.91 millis    0.24 millis  618.67 millis
   sys time  557.71 millis    1.54 millis  556.18 millis



```

(most time is spent in docker build)

## Test Plan
- mise run pre-commit
2026-02-25 08:34:43 -08:00
Drew Newberry 2d85338940 feat(platform): cleanup api surface area and mtls flows (!39)
Closes #48, #52

## Summary
- Replace the envoy-gateway-based TLS setup with inline PKI generation during cluster bootstrap, generating CA, server, and client certificates directly in the `navigator-bootstrap` crate
- Remove all envoy gateway Helm templates (`gateway.yaml`, `gatewayclass.yaml`, `grpcroute.yaml`, PKI job, traffic policies) and the `Dockerfile.pki-job`
- Add native mTLS support to the navigator server with `tokio-rustls`, mounting client TLS certs as volumes into sandbox pods
- Update cluster entrypoint, healthcheck, and deploy scripts to work with the new direct-TLS architecture
- Add TLS security e2e test and fix formatting/clippy warnings

## Test Plan
- All unit tests pass (`cargo test --workspace`)
- Clippy clean (`cargo clippy --workspace --all-targets`)
- Format clean (`cargo fmt --all -- --check`)
- Python tests pass (`uv run pytest python/`)
- Full `mise run pre-commit` passes
2026-02-24 11:33:33 -08:00
Drew Newberry c011a1cfb4 chore: changes for intial openclaw demo 2026-02-23 22:56:27 -08:00
John Myers 113e92ff08 fix(sandbox): prevent 30s stalls in HTTP proxy response relay (!44)
## Summary
- Fix L7 REST relay response framing so chunked HTTP responses are parsed by chunk-size + trailer termination, instead of waiting for socket close semantics.
- Prevent ~30s stalls observed in `gh auth status` when talking to `api.github.com` through the sandbox proxy.
- Keep detailed debug timing around response framing/chunk completion to make future networking investigations easier.

## Additional changes in this branch
- Adds sandbox policy generation skill docs under `.agent/skills/generate-sandbox-policy/`.
- Includes related sandbox config/image updates in `dev-sandbox-policy.yaml` and `deploy/docker/sandbox/Dockerfile.base`.

## Test plan
- `cargo test -p navigator-sandbox l7::rest::tests:: -- --nocapture`
- `cargo test -p navigator-sandbox -- --nocapture`
- `mise run pre-commit`
- Manual: rebuilt `navigator-sandbox:dev`, ran `gh auth status` in sandbox, and confirmed the previous long proxy delay no longer reproduces.
2026-02-23 15:40:55 -08:00
Piotr Mlocek 34fd3cbf64 feat(inference): inference interception and routing (!38)
Closes #67

## Summary

Implements transparent inference interception and routing for sandboxed AI agents. The sandbox proxy intercepts outbound AI SDK calls (OpenAI, Anthropic) and reroutes them through the gateway to policy-controlled backends — enabling organizations to redirect inference traffic to local or self-hosted models without modifying agent code.

**Decision model** — a tri-state OPA evaluation for every CONNECT request:
1. Binary + endpoint explicitly allowed in `network_policies` → **allow** (pass through)
2. Not explicitly allowed + `inference.allowed_routes` configured → **inspect for inference** (TLS intercept, detect API patterns, route through gateway)
3. Otherwise → **deny**

No endpoint declarations or binary lists needed for inference routing. Just configure `inference.allowed_routes`.

## Key Changes

### Sandbox (interception)
- **OPA policy**: New `network_action` Rego rule with three outcomes (`allow`, `inspect_for_inference`, `deny`). New `NetworkAction` enum replaces `PolicyDecision.allowed` bool for the proxy's main decision path.
- **Proxy**: New `InspectForInference` path — TLS-terminates client, parses HTTP, detects inference API patterns (`POST /v1/chat/completions`, `/v1/completions`, `/v1/messages`), strips auth headers, forwards via gRPC.
- **New module**: `l7/inference.rs` — `InferenceApiPattern`, `detect_inference_pattern()`, HTTP request/response parsing.
- **gRPC client**: New `proxy_inference()` for sandbox→gateway forwarding.
- **Sandbox init**: Creates OPA engine when inference is configured, even without `network_policies`.

### Gateway (dispatch)
- **InferenceService**: `ProxyInference` RPC loads sandbox policy, resolves allowed routes, dispatches to router. Full CRUD for inference routes.
- **Proto**: `InferenceRoute`, `InferenceRouteSpec`, `ProxyInferenceRequest/Response`, Inference gRPC service.

### Router (backend proxying)
- **New crate**: `navigator-router` with `Router`, `proxy_with_candidates()`, protocol-based route selection, backend HTTP proxying with auth header rewriting.
- **Mock support** for testing (`mock://` scheme).

### CLI
- `nav inference create/update/delete/list` commands for route management.

### Python SDK
- Updated protobuf bindings. Removed old `inference.py` client (replaced by transparent interception).

### Documentation
- New `architecture/inference-routing.md` — end-to-end system documentation.
- Updated `architecture/sandbox.md` — proxy, OPA, and source index sections.
- Updated `architecture/README.md` — new subsystem overview and diagram.

## Addendum: Chunked Transfer Compatibility

This branch now also fixes intercepted SDK requests that send chunked request bodies:

- `inspect_for_inference` now accepts `Transfer-Encoding: chunked` and decodes chunked request bodies before forwarding to the gateway
- Removed the prior `411 Length Required` response for chunked intercepted requests
- Added request/response header sanitization for framing and hop-by-hop headers (`content-length`, `transfer-encoding`, `connection`, etc.) to keep forwarded requests and returned responses valid
- Added unit tests for chunked parsing and header sanitization

Note: this improves compatibility for streaming-style SDK request patterns; true token-by-token passthrough response streaming is still a separate follow-up.

## Minimal Policy for Inference Routing

```yaml
inference:
  allowed_routes:
    - local
```

Any outgoing connection from a binary not explicitly allowed in `network_policies` will be intercepted and checked for inference API patterns.

## Test Plan

- [x] `cargo test --workspace` — all tests pass
- [x] `mise run pre-commit` — all checks pass
- [x] E2E: OpenAI chat completions routed through gateway
- [x] E2E: Anthropic messages routed through gateway
- [x] E2E: Python OpenAI SDK from sandbox (`examples/inference/inference.py`)
- [x] E2E test: `e2e/python/test_inference_routing.py`
2026-02-23 11:48:48 -08:00
Drew Newberry 6dc97171ed feat(sandbox): add image build/push and fix cluster deploy (!34)
Closes #44

## Summary

- Add `nav sandbox image push --dockerfile <path>` command to build and push custom container images into the cluster
- Fix sandbox Docker build failure caused by OpenClaw installer TTY access
- Fix sandbox proxy crash when network namespace is unavailable (fall back to loopback)
- Add e2e test for the full custom image build and sandbox creation flow
- Rename and rewrite BYOC architecture doc to reflect current state

## Changes

### `navigator-bootstrap`
- New `build` module (`src/build.rs`) with `build_and_push_image()` public API
- Builds via bollard `Docker::build_image()`, streams output to caller
- `.dockerignore` support with glob matching, 8 unit tests

### `navigator-cli`
- Added `SandboxImageCommands::Push` subcommand with `--dockerfile`, `--tag`, `--context`, `--build-arg` flags
- Added `test:e2e:custom-image` mise task

### `navigator-sandbox`
- Proxy now falls back to `127.0.0.1:3128` when no network namespace or explicit bind address is available, instead of erroring out

### Docker / Infra
- Sandbox Dockerfile: replaced OpenClaw native installer (`curl | bash`) with `npm install -g openclaw` to avoid `/dev/tty` failures in Docker build

### Documentation
- Renamed `architecture/sandbox-byoc.md` to `sandbox-custom-containers.md`
- Rewrote doc to describe current behavior (CLI usage, push pipeline, supervisor behavior, design decisions) instead of listing implementation changes

### Tests
- Added `e2e/bash/test_sandbox_custom_image.sh` covering image push + sandbox create with custom image
2026-02-22 20:32:18 -08:00
Drew Newberry 1c939a255a feat(sandbox): enable port forwarding and setup openclaw (!33) 2026-02-19 16:03:23 -08:00
Piotr Mlocek a5400113fb chore(ci): add Linux-hosted macOS wheel builds (!30)
## Summary
- add a Docker-based macOS arm64 wheel build path so darwin wheels can be produced from Linux CI hosts
- wire macOS wheel builds into release publish workflows (`publish:main` and `publish:tag`) alongside existing Linux wheel builds
- mirror `crazymax/osxcross:latest` into `$CI_REGISTRY_IMAGE/third_party/osxcross:latest` and use that mirrored image in CI publish jobs

## Scope Notes
- this MR focuses on shipping reliable macOS wheel build support first
- temporary MR-only smoke-job wiring was removed after validation so the branch reflects final intended CI behavior
- broader cache optimization work is tracked separately in issue #43

## Test Plan
- run `mise run pre-commit`
- validate `.gitlab-ci.yml` with `uv run --with pyyaml python -c 'import yaml, pathlib; yaml.safe_load(pathlib.Path(".gitlab-ci.yml").read_text())'`
2026-02-17 22:25:52 -08:00
Drew Newberry f362963c7b feat(sandbox): add provider entity to support configuring tools such as claude, outlook, etc (!23)
## Summary
- Add `Provider` entity for managing 3p deps from a sandbox
- Add provider CRUD API/server persistence and new CLI workflows (`nav provider create/get/list/update/delete`), including `--from-existing` laptop discovery.
- Integrate providers into sandbox create flow: infer from command (`-- claude`), support repeatable `--provider <type>`, prompt before auto-create, and allow manual in-sandbox setup.
- Add a dedicated `navigator-providers` crate with per-provider modules and mockable discovery test helpers.

## Key UX Changes
- `nav sandbox create --provider gitlab -- claude`
- Missing provider prompt now asks before creating from local state.
- `nav provider list --names` for scripting/cleanup.

## Test Plan
- `mise run cluster:deploy`
- `mise run test:e2e:sandbox`
- `mise run pre-commit`

Closes #19
Closes #22
Closes #11
2026-02-16 14:40:32 -08:00
Piotr Mlocek 71a2213a3f fix(ci): make the multiplatform wheel build work in CI 2026-02-13 19:01:14 -08:00
Piotr Mlocek 566010db18 fix(ci): install cargo:cargo-edit on the CI image, add file that got missed 2026-02-13 15:21:09 -08:00
Drew Newberry 4ef5c0d2dd chore(ci): speed up ci builds and improve caching (!20) 2026-02-13 11:06:25 -08:00
Drew Newberry d2f3ca71d4 feat(sandbox): add callable python exec API and refresh e2e coverage (!19)
Closes #13

## Summary
- add Python sandbox execution APIs for command and callable workflows
- consolidate sandbox policy fixtures and expand e2e test coverage for policy and Python exec paths
- update CI/build config and images for sandbox e2e execution dependencies

## Test Plan
- mise run pre-commit
2026-02-12 23:30:24 -08:00
Piotr Mlocek c094769a43 feat(server): add an inference router (!13)
Closes #3
2026-02-11 19:09:14 -08:00
Drew Newberry 0b6aa0f742 feat(cluster): push locally-built images into k3s containerd for local dev (!16)
## Summary
- Add a "push" path for local development that exports Docker images from the host daemon and imports them directly into the k3s containerd runtime, eliminating the need for a local registry or remote image pulls during `mise run cluster`
- Add `mise run cluster:deploy` task for fast iterative rebuilds (~25s) against a running cluster without recreating it
- Update `cluster-entrypoint.sh` to patch HelmChart manifest with local image tags and `IfNotPresent` pull policy when push mode is active

## Details

Previously, after the local registry (k3d + skaffold) was removed, `mise run cluster` only pulled component images from the remote CloudFront registry. This meant local code changes required a remote publish cycle to test in-cluster.

This MR adds a push path that sits alongside the existing pull path:
- **`push.rs`** — Uses bollard to `export_images()` all 3 component images into a single tar (with shared layer dedup), uploads via Docker `put_archive` API into the cluster container, then runs `ctr images import` to load them into containerd
- **`docker.rs`** — Passes `IMAGE_TAG` and `IMAGE_PULL_POLICY` env vars into the cluster container when `NAVIGATOR_PUSH_IMAGES` is set
- **`lib.rs`** — Wires push into the deploy flow between `clean_stale_nodes()` and `wait_for_cluster_ready()`, guarded by `remote_opts.is_none() && NAVIGATOR_PUSH_IMAGES`
- **`cluster-entrypoint.sh`** — Patches the baked-in HelmChart manifest with sed to use the local image tag and pull policy before k3s starts
- **`cluster.toml`** — Updated `[cluster]` task to tag and push images; new `[cluster:deploy]` task for iterative deploys via `docker save | ctr import` + `helm upgrade`

The remote deploy path (`nav cluster admin deploy --remote`) is completely unaffected — the push logic only activates for local deploys with the env var set.

## Test Plan
- `mise run cluster` — end-to-end success, cluster healthy with local images (~168s)
- `mise run cluster:deploy` — iterative deploy success, helm upgrade + rollout (~43s)
- `mise run pre-commit` — all checks pass (fmt, clippy, 82 tests, python lint)
- Verified images present in containerd: `ctr -a /run/k3s/containerd/containerd.sock images ls | grep navigator/`
- Remote path verified safe via code analysis (guards prevent push logic from running)
2026-02-11 09:26:02 -08:00
Drew Newberry 894c419e93 fix(ci): publish_ecr_images correctly publishes images (!15) 2026-02-10 23:04:32 -08:00