Skip to content

Releases: cjohnstoniv/wardyn

v0.6.6

v0.6.6 Pre-release
Pre-release

Choose a tag to compare

@cjohnstoniv cjohnstoniv released this 28 Aug 21:27

A follow-up to 0.6.5 for the k8s runner: on a cluster where the runs namespace cannot reach the
control plane, the setup connectivity probe could never pass, and nothing on the console said why.
Reported by the same enterprise adopter on managed Kubernetes after verifying every 0.6.5 item on
their deployment.

Fixed

  • The connectivity probe timed out before an exec-mode run could finish. Every exec is
    wrapped by wardyn-rec, which uploads the session cast to the control plane through the
    proxy after the task exits. That upload waited up to 60s when the control plane was
    unreachable, the probe waited only 50s, so on such a cluster the probe killed its own run at
    +50s every time — reported as "did not finish within 50s" under the proxy heading, with the
    task long since done. The recorder's upload is now bounded (5s connect, 20s total; delivery
    stays non-fatal), the probe's budget is 90s (runner backstop 120s), and a run that started but
    never reported back is its own timed_out verdict, whose detail carries the sandbox agent's
    state at the deadline and points at WARDYN_CONTROL_PLANE_URL. The recorder bound ships
    inside the agent images: rebuild any image pinned through WARDYN_AGENT_IMAGES from 0.6.6 (or
    pull the published agent-base:0.6.6) — a pre-0.6.6 image keeps the 60s upload tail, which
    the 90s budget covers only for a fast task.
  • A k8s exec container that never starts no longer hangs the run. Wait polled a Waiting
    ephemeral container forever; a hard start failure (CreateContainerConfigError,
    ErrImagePull, …) now fails the run with exec_started: false in its run.complete event,
    the probe reports it as not_run naming the reason, and AgentStatus surfaces the waiting
    reason.
  • The probe run is labelled base, the image key it actually dispatches, instead of
    claude-code; the "Agent image toolchains" setup row names both the claude-code harness
    image and the probe's base image.

Added

  • warning on a passing probe when its recording never landed. Egress can work while the
    proxy pod cannot reach the control plane — every run then completes and silently loses its
    session recording. The probe now checks that its own cast arrived and, if not, says so with
    the WARDYN_CONTROL_PLANE_URL to check.
  • Console Ingress read timeout guidance. The probe is one HTTP request of up to 90s;
    ingress-nginx's default 60s proxy-read-timeout turns the verdict into a 504. The chart's
    values and README show the annotation to set.

v0.6.5

v0.6.5 Pre-release
Pre-release

Choose a tag to compare

@cjohnstoniv cjohnstoniv released this 28 Aug 16:30

A patch for the k8s runner on managed, multi-tenant Kubernetes — where a platform team owns RBAC
and namespaces, a baseline default-deny NetworkPolicy already exists, the Postgres DSN Secret is
operator-owned, and packages come from an allowlist mirror. Reported by an enterprise adopter on
managed Kubernetes; every item below was verified against the code before it was fixed.

Security

  • golang.org/x/crypto 0.54.0 → 0.55.0 (GO-2026-6303). The SSH gateway's
    ssh.NewServerConn reaches the code path where the source-address critical
    option was not enforced for non-public-key auth callbacks; govulncheck
    reports it as reachable and would block the merge gate. Fixed upstream in
    0.55.0; x/net and x/text move with it as indirect dependencies.
  • The chart's NetworkPolicy governs the control-plane pod only. Its podSelector matched
    app.kubernetes.io/name + instance — the two labels the shared helper puts on every pod the
    release creates, and that sandbox pods can carry through caller-supplied labels. Any pod in the
    release namespace carrying those two labels inherited the control plane's ingress rules (every non-http inbound port
    denied) and, because NetworkPolicy allows are additive, its egress allowances. The selector now
    also pins app.kubernetes.io/component: control-plane, which the pod template already carried; the
    Deployment's own immutable spec.selector is untouched, so upgrades apply cleanly.

Added

  • k8s.rbac.create (default true). false renders no Role/RoleBinding/ClusterRole/
    ClusterRoleBinding and nothing in k8s.runsNamespace, for a platform that provisions runner RBAC
    out of band and refuses cluster-scoped objects from tenants. The serviceAccount.create=false
    without a name refusal stays either way.

  • ingress.* — an optional Ingress for the console's http port (class, annotations, hosts,
    TLS). Off by default; the render is unchanged until enabled. The UI-sandbox gateway keeps its own
    hand-authored Ingress on its own hostname by design.

  • secrets.ageKeySecretRef — the age identity from its own Secret, independent of the DSN
    Secret, for a DSN a managed-Postgres operator owns and no one can add a key to. Naming it alongside
    ageKeyFromSecret/ageKey is refused at render: two Secrets, one identity, and booting under the
    wrong one is unrecoverable.

  • defaultPolicy — the default RunPolicy as JSON text (--set-file defaultPolicy=my.json),
    rendered into a ConfigMap, mounted read-only, with WARDYN_DEFAULT_POLICY pointed at it and a
    checksum annotation that rolls the pod on change. Until now the only chart-level choice was one of
    the files baked into the image, whose shipped floor is CC2 — unadvertised on any cluster with no
    k8s.runtimeClasses pinned.

  • WARDYN_K8S_ACK_AMBIENT_DEFAULT_DENY=1 — an acknowledgement, distinct from
    WARDYN_K8S_ALLOW_UNENFORCED_NETPOL, for the one canary shape a tenant cannot fix: the baseline
    phase's pod ran and could not reach the API server because the namespace already carries a
    default-deny NetworkPolicy the platform team owns. Boot proceeds, the log says loudly that
    enforcement is acknowledged rather than proven, and the setup page shows it as a warn row. A
    canary pod that never started still refuses boot with no override. The refusal message now names
    the acknowledgement next to the exemption it already named.

  • A confinement_floor setup row that warns when the default policy's floor is a class this
    runner does not advertise — every run on the default policy would be refused before launch — and
    names the two remedies (lower the floor via defaultPolicy/WARDYN_DEFAULT_POLICY, or pin a
    RuntimeClass).

  • A not_run verdict for the setup connectivity probe, distinct from blocked: the probe
    sandbox never started (an image pull, a confinement class this host cannot enforce), so nothing was
    learned about the network. The console says so instead of "fix the proxy".

  • OIDC public clients. WARDYN_OIDC_CLIENT_SECRET is optional; without it the token exchange
    runs as a public client (client_id in the body, PKCE S256 — which every login already sent).

  • GOPROXY build arg on every Go builder stage, plumbed through make and Compose like
    NPM_REGISTRY; empty is identical to unset.

  • The release pipeline can be rehearsed. release.yml gains a
    workflow_dispatch with dry_run (default true): it builds every image, the
    CLI cross-builds and the chart package, runs the SBOM merge and its zero-npm
    assertion, and pushes, signs, attests and uploads nothing.

    This pipeline could previously only be exercised by tagging, so its bugs were
    unobservable until a real tag pushed — which is why 0.6.2 shipped images with no
    provenance and 0.6.3 shipped an SBOM that understated its own contents. Both
    would have failed a dry run. make release-check was green every time, because
    it validates the repository, not the workflow.

Fixed

  • The setup connectivity probe blamed the proxy for its own failures. It pulled
    agent-claude-code — an image the project deliberately stopped publishing in 0.6.2 — and dispatched
    at the default policy's CC2 floor, so on a stock managed cluster it failed at the image pull or at
    no confinement substrate can enforce class "CC2", and both surfaced as Blocked under the
    proxy heading with "fix the proxy above". It now runs the published agent-base image (override
    key base in WARDYN_AGENT_IMAGES) at the strongest class the runner actually advertises — the
    probe tests egress, not the floor — and a sandbox that never started is not_run, never blocked.
    agent-base's agent-run stub honours WARDYN_TASK_MODE=exec so it can carry the probe;
    make setup builds wardyn/agent-base:local on the from-source path and the Compose stack maps
    the base key to it.
  • A failed run.complete read as a clean exit. The probe decoded the failure event's missing
    exit_code as 0 and reported reached for a run whose watcher had errored.
  • email_verified absent is no longer "false". With WARDYN_OIDC_EMAIL_DOMAINS set, an
    id_token with no email_verified claim at all — the norm for Entra ID — denied every login with
    the message for a claim the IdP had set to false. Absent is its own email_verified_absent
    outcome: the operator gets a server-side warning naming the claim, the issuer and the variable; the
    user is told the provider sent no claim and to ask for App Roles instead of "verify your email".
    The sign-in copy also named a variable that does not exist (WARDYN_OIDC_ALLOWED_EMAIL_DOMAINS).
  • The setup barrier picker says it is a browser-local default. Its instruction read as if it
    set the server's floor; it never did (the footnote below it already said so).
  • NPM_REGISTRY was bypassed by the npm self-upgrade. The agent image Dockerfiles ran
    npm install -g npm@<version> before npm config set registry, so behind a mirror that does not
    proxy the public registry the build failed on its first install. The registry is set first.

Not in this patch: an operator-configurable model-provider base URL (an internal OpenAI-compatible
gateway as a first-class provider) — the supported path today is the EgressRedirect header-injection
lane, documented in docs/OPERATIONS.md; a Gateway-API HTTPRoute variant of ingress.*.

v0.6.4

v0.6.4 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 27 Aug 07:26

fix(sbom): merge the UI lockfile, and correct what 0.6.2 claimed

The released sbom-wardynd.cdx.json for 0.6.3 carries 1,070 components: 114 Go
modules, 4 Debian packages, and ZERO of the 611 npm packages actually in the
bundle. 0.6.2's notes said switching syft from the source tree to the pushed
image fixed that. It did not, and could not: wardynd embeds the console as a Vite
bundle, which strips every package.json, so there is no manifest in the image for
any scanner to find however you point it. Changing the scan TARGET fixed the
OS-package blindness and nothing else.

The plan I wrote said the fix was to merge a lockfile-derived scan. I implemented
the target change, saw "scans the image now", and did not check the number — the
one number the whole change was about.

The lockfile is the only place those versions still exist, so the release merges
syft dir:ui into the image SBOM. Rehearsed against the actual 0.6.3 artifact:
1,681 components, 611 npm, 114 golang, 4 deb.

The job now FAILS when the merge leaves zero npm packages. An SBOM that
understates what it describes is the failure this whole campaign is about, and it
shipped anyway because nothing asserted the outcome — only that a file existed.

Signed-off-by: cjohnstoniv cjohnstoniv@users.noreply.github.com

v0.6.1

v0.6.1 Pre-release
Pre-release

Choose a tag to compare

@cjohnstoniv cjohnstoniv released this 25 Aug 17:02

First patch on 0.6. Three CI jobs that had never run before the v0.6.0 push went
red on it; two were real, pre-existing defects. Plus the security sweep and a
documentation regression.

Fixed

  • The desktop tier could not boot on older Docker Compose.
    deploy/desktop/docker-compose.yaml include:d the base compose file and then
    re-declared services.wardynd to add one volume — a service-name collision that
    newer Compose merges and older Compose refuses outright
    (services.wardynd conflicts with imported resource). The mount moves into the
    base file as ${WARDYN_MANAGED_DIR:-…}:/etc/wardyn:ro, the same
    variable-with-harmless-default idiom that file already uses for
    WARDYN_WORKSPACES_ROOT and WARDYN_BEDROCK_AWS_DIR; the desktop file is now
    include:-only, so nothing can collide at any Compose version.
    wardyn-desktop.sh exports the variable, and every non-desktop deployment
    leaves it unset and mounts nothing.
  • make compose-config now validates the desktop entrypoint too. It only ever
    parsed the base file and the CI overlay, and the desktop guard was a text grep
    that never asked Compose to resolve the include: — which is why the collision
    above was invisible to every daemon-free gate and surfaced first in CI.
  • The agent images' bundled npm carried a CRITICAL. node-tar 7.5.11
    (CVE-2026-59873, gzip-bomb DoS) ships inside npm's own vendored node_modules,
    so no application-level pin reaches it — and the current
    node:22-bookworm-slim still ships it. claude-code and codex-cli now
    install npm@11.19.0, which vendors the patched 7.5.19. aws-sso is
    debian-based with no npm and is unaffected.
  • Five development-scope advisories pinned forward via pnpm.overrides, all
    at patch level with no direct-dependency bump: brace-expansion 2.1.2/5.0.7,
    undici 7.29.0, postcss 8.5.23, mermaid 11.16.1, dompurify 3.4.13. These
    are build/test tooling and the docs diagram gate — nothing in ui/src imports
    any of them, so the shipped bundle is unchanged. make npm-audit is unchanged
    and still --prod --audit-level=high by design: development-scope tooling is
    outside its scope by construction, not by suppression, and there is no ignore
    list.

Changed

  • The Quickstart no longer implies a model is required. Connecting a model was
    sequenced as step 2 of getting started with no qualifier, while the code has
    reported it as optional and explicitly non-blocking since 0.4 (setup status
    renders it INFO, never a gap to clear). The model step now follows a working
    wardyn run, is introduced as optional, and says outright that skipping it is a
    supported end state. The run example now explains that --task-mode exec means
    no agent and no model, and that --agent names a sandbox image rather than
    asserting an AI runs the task.
  • Wardyn describes itself as a governed-sandbox control plane for any workload
    on the surfaces that still said "for coding agents" — the Helm chart's
    description and keywords, and the GitHub repository description. Coding agents
    remain the flagship use; they were never the whole product, and the console's
    own copy already said so.
  • ROADMAP.md names the underlying wart: POST /runs requires an agent field
    even for task_mode=exec runs that have no agent, which is a wire-contract
    change to fix.

The recorded walkthrough series is unchanged in this release and remains attached to v0.6.0; the README links point there.

v0.6.0

v0.6.0 Pre-release
Pre-release

Choose a tag to compare

@cjohnstoniv cjohnstoniv released this 25 Aug 14:27

Added

  • Members onboard their own workspaces from the console. The Workspaces
    screen and the New-Run wizard's Add-a-workspace dialog now work for a member
    session against the member-scoped routes: create and scan your OWN
    workspaces, with the admin-set mount boundary shown in place — the daemon
    tells the console the member's local-dir root (member_local_dir_root on
    GET /me), and the path field says so. The writable checkbox does not
    exist for members (the request never carries writable; the server-side
    allowlist is the boundary either way). The mock at
    docs/design/ui-batch2-mock.md is the design source of truth for every
    string.
  • Workspace reassignment (offboarding). POST /workspaces/{id}/reassign
    (admin-only) moves a member-owned workspace to operator ownership
    (owned_by=''), audited workspace.reassign with from_owner. Members get
    the same constant 403 as every admin-only workspace route — deliberately
    more existence-blind than a 404 split.
  • No impersonation in the audit trail. When an admin acts on a
    member-owned workspace, the audit actor stays the ADMIN's identity, and the
    event carries workspace_owner naming the member — cross-user admin access
    is queryable (?actor= plus workspace_owner ≠ actor), pinned by a guard
    test at every workspace write site.
  • A failed run says why, in the console. The run page's FAILED state
    renders the failure_hint the backend has stamped since migration 0044
    bare server text beside the state badge, nothing when there is no hint.
    The unlisted-host copy in the New-Run wizard now describes what the proxy
    actually does (refused-and-raised, approve once, retry gets through), and
    the egress panel names the agent CLI's telemetry endpoint for what it is.
  • Desktop install lane. deploy/desktop/ gains install.sh (managed
    dir, per-device age key minted at install — never distributed via MDM),
    com.wardyn.daemon.plist (launchd), and wardyn-desktop.sh
    (docker compose --env-file … -p wardyn-desktop up -d --no-build --pull always, healthz wait, idempotent wardyn site-config apply).
    wardyn_pick_docker_host now recognizes a Colima socket the way it does
    Rancher's — without it, confinement silently collapses on Colima Macs.
  • Desktop honesty gates. scripts/test-desktop-profile.sh joins
    make test-scripts (which CI runs), and a desktop-envelope CI job boots
    compose with the example profile and asserts the managed policy file is
    exactly what the daemon serves, an unpoliced run resolves to the ceiling,
    and profile synthesis stays clamped. The one scripted macOS smoke run is an
    operator step documented in docs/DESKTOP.md — run once, paste output; CI
    does not cover it and the doc says so.
  • ROADMAP truth. The desktop slice moves to 0.6; interactive
    tool-approvals→console is marked deferred to 0.7 with its reasons (the
    prompt-tool contract is non-interactive-only, the hook alternative fails
    open on timeout, and a self-service member who could approve can already
    attach).
  • Per-user API tokens. A signed-in human mints wdn_… bearer tokens for
    themselves (POST /me/tokens returns the plaintext exactly once; GET/
    DELETE /me/tokens); an admin can list and revoke anyone's (/tokens).
    Only the SHA-256 is stored (migration 0045). A token authenticates as
    the human who minted it
    — it publishes the same context the OIDC session
    does, so grants, RBAC and ownership bind identically and a member's token
    can never reach an admin route. Audited token.create/token.revoke.
  • wardynd -rotate-age-key <path>: age-key rotation as a maintenance
    mode.
    With the daemon stopped, mints a new age identity, re-encrypts every
    stored secret in one transaction (any row that fails to decrypt aborts the
    whole rotation), swaps the key file atomically and exits. The wardyn CLI
    never sees the key. Audited secret.rekey (count only, no names).
  • Hash-chained audit log (migration 0047). Every new event carries
    prev_hash/row_hash (SHA-256 over the previous hash and the row's
    immutable fields, computed by Postgres under a transaction-scoped advisory
    lock so chain order equals commit order). The head hash rides the audit-sink
    stream so an external SIEM can detect truncation; GET /audit/chain/verify
    (admin) walks the chain and reports the first break. Tamper-evident, not
    tamper-proof — a database owner can rewrite the whole chain; the threat
    model says so.
  • env_secret grant kind. Injects a named stored secret as a sandbox
    environment variable at dispatch. Resident for the run's lifetime and not
    revocable mid-run — its own threat-model row — so it is admin-only unless
    WARDYN_ALLOW_MEMBER_ENV_SECRET opens it to members. The grant-pairing
    table is now closed: an unknown grant kind is refused instead of falling
    through unclamped.
  • git_pat per-run lease. A git_pat approval decided with
    decision_scope=run re-mints for the rest of that run under the one
    decision; mints are stamped lease in credential.mint. The scope is
    compared as stored — a legacy approval never silently becomes a lease.
  • Second-human egress approval. WARDYN_EGRESS_SECOND_HUMAN=1 refuses an
    egress decision by the run's own creator (authz.denied,
    reason: second_human_required). The shared admin token has no per-human
    identity and bypasses the rule — that bypass is audited
    (approval.second_human.bypass) and documented as break-glass, not hidden.
  • auth.failed audit event. Admin-token 401s and rejected OIDC session
    cookies used to fail silently; they now emit a content-free auth.failed
    (reason, source IP, path) behind a process-local token bucket so a scanner
    cannot flood the append-only log.
  • WARDYN_AUDIT_SOURCE stamps a static source field on every event a
    sink serializes — one SIEM index can tell instances apart. Sink payloads
    only, never Postgres. OPERATIONS.md gains Splunk HEC / generic-webhook
    recipes.
  • WARDYN_REQUIRE_OPERATOR_SET_EGRESS (default off) applies the
    scan-seeded provenance guard that already protected secrets to egress
    domains: a run may not carry egress the operator never set.
  • Setup status grades the permissioning posture — the fail-open
    enforcement switches are scored as a check, informational and non-blocking.
  • If-Match on PUT /permissions/enforcement and site-config apply.
    Both whole-replace surfaces return an ETag; a stale If-Match is refused
    with 412 before the write reaches the store. Omitting the header keeps
    today's behaviour.
  • SSH admin override is bounded-stale, not permanent (migration 0046).
    Every OIDC login re-stamps role/role_checked_at on the principal's
    registered keys; the gateway refuses the override once the stamp is older
    than WARDYN_SSH_ROLE_TTL (default 24h). Keys registered before 0.6 carry
    no stamp and never gain the override until their owner logs in again. A
    direct-SQL admin-key registration must stamp role_checked_at too — the
    API path already does; a bare role='admin' insert is correctly refused as
    never-checked, and docs/SSH.md now says so explicitly.
  • Session revocation. POST /sessions/revoke (admin; wardyn sessions revoke --sub … | --all) invalidates every current console session for one
    principal or for everyone, effective immediately (migration 0049).
    Sessions are stateless cookies, so revocation is a per-principal cutoff
    time the middleware checks on every request — fail-closed when the store
    errors. It also revokes every unrevoked API token the target holds: a
    wdn_ bearer is that human's session in another form, so "revoke a human
    now" covers both in one call. Audited session.revoke (with
    tokens_revoked); a request presenting a revoked cookie surfaces as
    auth.failed with reason: revoked_session.
  • wardyn support-bundle gathers version, healthz, setup status, a bounded
    audit tail and the compose config — secret values redacted, including
    commented-out lines — into a tar.gz for a support ticket.
  • OIDC token exchange retries transient IdP errors (5xx/timeout, at most
    three attempts with backoff) and distinguishes them from a configuration
    error on the error page.
  • linux/arm64 images. wardynd, wardyn-proxy and the agent images build
    for linux/amd64,linux/arm64 (pure-Go cross-compile; QEMU only for runtime
    stages); every base-image pin is an index digest, enforced by
    scripts/test-image-pins.sh. The release lane signs and attaches an SBOM
    for the agent images too, the agent CLI is pinned to an exact version, and
    CI runs a trivy scan (CRITICAL fails; accepted CVEs live in .trivyignore).
  • Managed desktop envelope. deploy/desktop/wardyn.env.example +
    docs/DESKTOP.md: a local daemon per laptop under an MDM-managed policy
    file, developer = operator. The ceiling is stated verbatim — the developer
    is not the adversary in this tier — and the operator-unclamped inline-policy
    path is named, not hidden.
  • Member-owned workspaces (backend, migration 0048). A member may now
    create, update, delete and scan their own workspaces (owned_by); a foreign
    member's workspace answers the byte-identical 404 a missing one does. A
    member's local_dir mounts are allowed only under operator/MDM-set roots
    (WARDYN_MEMBER_WORKSPACE_ROOTS, or a per-member
    WARDYN_MEMBER_WORKSPACE_ROOTS_MAP that replaces the shared list),
    canonicalized at bind time (symlink and .. escapes refused, $HOME
    dotfiles denied), and writable only under WARDYN_MEMBER_WRITABLE_ROOTS
    minus WARDYN_MEMBER_WRITABLE_DENY — both unset means no writable member
    mount at all. WARDYN_MEMBER_MODE=1 refuses to start alongside local mode.
    The console flow and the reassign action follow in the next stage.
  • **The wait_for_review hold window and concurrency are configurable...
Read more

v0.5.0

v0.5.0 Pre-release
Pre-release

Choose a tag to compare

@cjohnstoniv cjohnstoniv released this 18 Aug 06:12

Security

  • Go-live hardening: 29 confirmed ship-blockers closed across two adversarial
    review waves
    , each with a regression test proven to fail on the pre-fix
    commit. The load-bearing ones: a member's inline_policy llm_inspection
    block is now clamped under the default ceiling (its detector_sidecar_url
    could otherwise become an un-allowlisted egress channel), and its secret
    corpus is referenced by name and resolved only at dispatch — never stored in
    a policy row, written to the append-only audit log, or copied into a
    compose/profile proposal; the git-broker's value-returning mint lanes refuse
    the GitHub App private key and the other reserved platform secrets; a
    disabled integration no longer grants a run model access; an explicit
    WARDYN_LOCAL_MODE=true no longer silently disables a configured OIDC/RBAC
    deployment (boot refuses the contradiction); a client-settable run.Task can
    no longer forge the operator-reserved harness-login path; SSH ssh.auth
    success is audited only after signature verification, not at key-offer time;
    an empty-ceiling github_token repo list is deny-all for a hand-authored
    spec; a tokened corp-mirror redirect is dialed to its real port, not always
    443; the exec-less (krun/CC3) sandbox path now applies the same fail-closed
    resource-cap gate as the exec path; and the host ground-truth sensor no
    longer forwards uncorrelated host-wide kernel events to the audit log/SIEM by
    default.
  • OIDC sessions now carry a derived admin/member role (WARDYN_OIDC_ROLE_MAP,
    internal/auth/oidc's deriveRole). Upgrading forces one SSO re-login: a pre-0.5
    session cookie carries no role and now decodes as no session (decodeSession), never
    as an authenticated session with an undefined role.
  • Authorization enforcement: the admin/member role is now enforced, plus
    owner-or-admin scoping.
    requireOperator/isOperator gate on the session's
    role instead of re-checking WARDYN_OIDC_OPERATOR_EMAILS directly (the
    allowlist still works — it feeds role derivation via LegacyAdminEmails, one
    source of truth instead of two). GET /metrics now carries the admin gate
    explicitly. A member is scoped to their OWN runs/approvals on GET /runs,
    GET /approvals (unscoped), and GET /audit (?run_id= of an owned run,
    else an empty result — never a cross-user leak); GET/kill/profile/grants on
    a run, the recording replay, an approval decide, and the attach-ticket mint
    all use an owner-or-admin gate that answers a foreign resource with the
    byte-identical 404 a missing one gets (no existence oracle). Attach tickets
    now carry the minting principal's role (migration 0034), since the
    interactive-attach WebSocket's ?ticket= lane authenticates entirely off the
    ticket and never runs the normal session check. GET /setup/status redacts
    operator-diagnostic detail (environment checks, resident CLI detection,
    secret names, runner detail) for a member. A member's inline_policy on
    POST /runs (and its preflight dry-run) is now clamped to the operator's
    default policy ceiling before resolution, and bringing a custom sandbox
    image (image) is admin-only. Two routes move from admin-only to
    owner-or-admin: minting an attach ticket and deciding an approval, both
    restricted to the run's own creator (or an admin) either way. A new
    authz.denied audit action records a member's admin-surface or BYOI
    denials (not a foreign-resource 404 — that stays silent by design, matching
    the no-existence-oracle rule above).

Added

  • An interactive run can start on a seed, at boot. The run's task
    previously ignored for an interactive run — is now its optional boot seed,
    interpreted per interactive_start: with "agent" the sandbox starts the
    agent CLI on that prompt in a persistent tmux session the moment it boots
    (supervised: the agent reads and plans, then parks its first tool approval
    in the pane until you attach — set seed_auto_tools to let it use tools
    unsupervised before you join); with "shell" the seed runs as a startup
    command before the terminal is yours. Attaching joins the live session.
    Empty task = today's idle sandbox, unchanged. Server-launched runs
    (record/verify/login) are excluded from seeding by construction. The seed
    travels as env into the sandbox and is consumed at boot — needs an image
    rebuild
    (make agent-images-core); an older image ignores it and comes
    up idle. The CLI gains this with zero new flags: wardyn run --interactive
    with a task now seeds.

  • Autonomous Claude runs can park every tool action on a human:
    tool_approvals: "hold".
    Instead of --dangerously-skip-permissions,
    the run's claude executes under --permission-mode manual with an
    in-sandbox relay (wardyn-toolgate, a stdio MCP permission-prompt tool)
    that raises each gated tool use as a tool_call approval — the exact
    command or edit as the decision context — and blocks until an operator
    approves or denies it in the console (the run cockpit's approval strip now
    shows tool holds beside egress holds). Deny and expiry both refuse the
    action and the run continues; a relay that cannot reach the control plane
    denies rather than proceeds. Default stays "auto" (the sandbox is the
    boundary); hold is per-run, Claude-only (codex has no external approval
    contract), and read-only commands the harness itself deems safe still run
    without asking.

  • Egress approvals carry a decision scope: once, run, until, or
    always.
    POST /approvals/{id}/approve and /deny accept
    decision_scope (plus decision_expires_at for until) on an
    egress_domain approval; wardyn approve/wardyn deny gain --scope/
    --until, the SDK gains DecisionOpts (pkg/client), and the console's
    approval queue gains a scope picker (Once / This run / Until… / Always)
    beside Approve/Deny. Omit the field and nothing changes — the default
    stays run, today's original behavior, held in the proxy's per-host cache
    for the rest of the run. once releases a single connection (one CONNECT
    tunnel on HTTPS; one request on plain HTTP) and is spent on first use;
    until is the same, bounded by a decision_expires_at up to 30 days out
    and enforced by the run's own proxy sidecar; always is
    operator-only and persists the host onto the target workspace's
    approved_egress/denied_egress (migrations
    0039_approval_decision_scope.sql, 0040_workspace_denied_egress.sql,
    0041_run_workspace_ids.sql) so every future run against that workspace
    inherits the decision instead of re-raising it — deny beats allow, as
    everywhere else in the proxy. New PUT /workspaces/{id}/denied-egress
    (full-replace, mirrors approved-egress) is the only way to undo a
    permanent deny, including one that broke a workspace's own credential
    injection.

  • Runs have a name. POST /api/v1/runs accepts title and description,
    both persisted on the run (migration 0038_run_title.sql) and returned by
    every read. Runs that share a title are grouped on the Runs board — which
    now groups by title rather than by state; the triage the state sections
    provided survives as the state facet, attention-first group ordering, and
    per-state counts in each group header. wardyn run gains --title /
    --description. Both fields are optional on the wire and required in the
    console
    : the site-config probe, harness login and workspace record/verify all
    create runs with no human to name them, so a server-side requirement would
    break them. Untitled runs — including every run created before this — display
    by their task exactly as before.

  • An interactive run can open straight into the agent.
    interactive_start:"agent" makes the attach shell launch the image's agent CLI
    in the prepared workspace, once, on first attach; "shell" (the default) keeps
    today's bare terminal. Request-scoped like task_mode — carried to the sandbox
    as WARDYN_INTERACTIVE_START and consumed by the image's attach ~/.bashrc,
    so it covers the console terminal and the SSH gateway alike (both go through
    the same Runner.Attach). Needs an image rebuildmake agent-images-core
    — to take effect; until then an older image ignores the variable and degrades
    to a shell, which is the previous behavior.

  • The Integrations page's Tools tab, the integration→tool "carries"
    chips in the workspace wizard (base-image, build, and verify steps), and
    the client-side mirrors of the bake conditions. Tools are what the image
    carries; the Integrations surface now speaks only to connections.

  • The artifact_mirror/host_proxy derivations. The Integrations surface
    no longer synthesizes rows from EgressRedirects/UpstreamProxySecretRef:
    that is network topology, it already has a surface (Corporate network), and
    showing it twice made one config look like two. Nothing about how a run
    redirects or chains through the corporate proxy changes.

  • Kubernetes runner substrate (internal/runner/k8s, -tags k8s,
    WARDYN_RUNNER=k8s): a second, independent confinement substrate behind the
    existing substrate.Substrate seam — wardynd creates/manages sandboxes as
    pods instead of Docker containers. L1 (NetworkPolicy-enforced), not L0
    (structural) like Docker: a boot-time two-phase egress canary proves the
    cluster's CNI actually enforces NetworkPolicy before the substrate will
    start at all, refusing to boot otherwise
    (WARDYN_K8S_ALLOW_UNENFORCED_NETPOL=1 is the loud, logged opt-out). CC1
    out of the box; WARDYN_CONFINEMENT_MAP/the chart's k8s.runtimeClasses
    pin CC2/CC3 to a registered RuntimeClass. Not at parity with Docker yet —
    no BYOI/devcontainer builds, no local_dir mounts, no per-pod PIDs/disk
    enforcement, no k8s ground-truth correlator (see
    deploy/helm/wardyn/README.md/docs/OPERATIONS.md's "Known gaps").

  • **The Helm chart ...

Read more

v0.4.3 — clarity release

Pre-release

Choose a tag to compare

@cjohnstoniv cjohnstoniv released this 29 Jul 17:20

A clarity release: no new features, no API changes. A repo-wide audit rewrote the
docs around a single quickstart, redrew the architecture diagram, and fixed the
places where the docs described something the code does not do. It also found two
CI gates that had been passing without checking anything.

Operators upgrading: nothing to do — no schema, config, or interface changed.

Maintainers: the CI merge gate collapsed five single-command jobs into one
gates matrix, so the required status checks on main must be renamed from
govulncheck/staticcheck/gitleaks/licenses/license-headers to
gates (<name>). Until that is applied, a pull request waits forever on contexts
that no longer report. See RELEASING.md, "Repo settings".

Fixed

  • The nightly live e2e jobs were passing while their assertions failed. Both
    steps pipe make into tee to capture evidence, but GitHub's implicit shell has
    no pipefail, so the step took tee's exit code. These are the jobs that prove
    the L0 egress boundary, the metadata block, and the kill cascade.
  • make dco accepted any non-empty sign-off, including Signed-off-by: nobody
    the format assertion was lost when the check moved to git's trailer parsing.
  • The README claimed gVisor/CC2 is your default barrier. pick_policy checks for
    a configured model first, so a gVisor host running a model gets a CC1 floor. All
    three outcomes are now stated.
  • docs/ENV.md documented an admin-token default that does not exist, so a
    reader who set only WARDYN_TOKEN got an unauthenticated control plane: the real
    default is empty, and an empty token with no OIDC on loopback auto-enables no-auth
    local mode. Both the binary and compose defaults are now stated.
  • The compose README described the make setup menu backwards, and told readers
    team/SSO was "coming soon" where the roadmap says it is not scheduled.
  • Example scenario commands now run as written (--policy, wardyn run list,
    wardyn deny, and a policy file that actually parses).
  • The Helm docs quoted three different, all-wrong chart versions.
  • Three API payloads emitted null where they had emitted [], one of them a live
    response body.

Changed

  • The console's default sizing is back to 100%. 0.4.0's 17.6px root font token is
    16px again, the sizing that shipped through 0.3.1. The pxrem text-utility
    conversion stays — those values were computed against a 16px base, so each reproduces
    its original size — and --font-size in ui/src/styles/theme.css remains the single
    knob for anyone who wants the larger console back.

  • Docs consolidated and de-duplicated (repo-wide audit). The quickstart is told
    once (README → docs/TRY-IT.md); docs/FRESH-START.md,
    docs/ADO-GIT-BROKER.md and docs/TEST-GAPS.md are gone (the troubleshooting
    table moved into TRY-IT); pre-0.4 release notes live in
    CHANGELOG-ARCHIVE.md; new docs/README.md index.

  • Diagrams redrawn and gated. The system-overview diagram has no edge
    crossings and is inlined in the README (the stale architecture.png is gone);
    make diagrams now label-checks the diagram side too and enforces a style guide.

  • Doc accuracy fixes. The default-barrier claim now states the CC1 fallback on
    runsc-less hosts; ENV.md documents the real (empty) admin-token default and the
    no-auth local-mode consequence; the compose README's setup-menu note was inverted;
    example TASK.md commands run as written.

  • Build plumbing. make release-check is now a strict superset of make ci;
    make help is self-documenting; the nightly uploads real e2e evidence; screenshots
    are freshness-gated and the README hero shot is script-captured.

v0.4.2 — corporate-network fixes: a hang, a regression, two false claims (pre-alpha)

Choose a tag to compare

@cjohnstoniv cjohnstoniv released this 21 Jul 03:26

A follow-up to 0.4.1 from the same adopter, now running the containerized stack on a
corporate laptop end to end. The full report — including the gaps still open — is in
docs/adoption/. One entry below is a
regression 0.4.1 introduced; two more were bugs that had been silent for longer.

Fixed

  • An unreachable corporate proxy no longer hangs an approved request. When the
    configured upstream proxy accepted the TCP connection but never answered the CONNECT,
    wardyn-proxy waited forever: the handshake read had no deadline, and the MITM path had
    already told the agent 200 Connection Established. An operator saw an approved egress
    sit there with nothing to act on. The handshake is now bounded and a stalled upstream
    surfaces as a normal dial failure — deny + 502, logged. This is the reported "200 then
    hang" on hosts whose connectivity client binds its proxy to loopback only.

  • The make setup UI fallback no longer reinstalls. 0.4.1 taught make setup to build
    the UI on the host when the registry can't serve pnpm — but it retried via make ui, which
    reinstalls, and the reinstall's postinstall scripts fetch platform-specific native binaries
    (@tailwindcss/oxide-*, @esbuild/*) that a partial mirror also refuses. So the fallback
    died anyway, with node_modules already complete. It now rebuilds from an existing
    node_modules when the lockfile matches, and only reinstalls when the tree is absent or
    stale. Note the ceiling: a fresh clone has no node_modules, so this fixes the second and
    later make setup, not a cold start.

  • The New Run wizard no longer claims you have no model access when you do. With an
    operator-configured cloud model (Bedrock), the Access step still defaulted to the api-key
    option and warned in red that the run's first model call would 404 — while dispatch was
    going to supply model access automatically, and the secret list it pointed at held no model
    key. The preflight now asks the same resolver dispatch uses, and Review defers to that
    verdict instead of guessing. When the preflight is unavailable the old local check still
    applies, so a real gap is never hidden.

Added

  • wardyn setup proxy-relay <listen-port> <proxy-port>. Forwards a reachable port to a
    forward proxy bound to 127.0.0.1, which no container can reach — a sandbox's loopback is
    its own, and on a VM-backed Docker host the runtime VM can't reach the host's loopback
    either. Foreground and unsupervised on purpose (Wardyn owns no host daemons); it fails
    immediately if nothing is listening on the target port. See
    docs/adoption/loopback-only-forward-proxy.md.

  • The Host proxy step warns when a detected proxy is loopback-bound, naming the symptom
    and the fix, instead of leaving it to be discovered at the first launch. Shows up in
    wardyn setup status too.

  • wardyn site-config get|apply. The corporate baseline (upstream-proxy ref, artifact
    mirrors, SCM hosts) lives in Postgres, so make reset and make reset-all take it with the
    volume — a reset previously came back up looking healthy with egress silently unconfigured.
    The baseline is now a file you can keep; it carries secret names, never values. reset-all
    also names what it is about to destroy and prints the capture command first.

Changed

  • Writable workspaces name the VM-backed-host caveat. An adopter reported that a
    writable: true host mount is read-only in practice under the Wall tier on macOS. Testing
    on a native Linux host with all four runtimes did not reproduce it — runc, gVisor, Kata
    and libkrun all wrote successfully — so the cause appears to be the macOS→VM file-sharing
    layer beneath the runtime, not the barrier itself. The Workspaces banner now says exactly
    that, scoped to VM-backed runtimes, rather than claiming a tier "cannot write" (which would
    be a new false statement of the kind these reports keep surfacing). The measured
    tier↔writability matrix is in the adoption doc.

  • The agent registers its workspace as a git safe.directory. A bind-mounted checkout is
    owned by the host user, whose uid rarely matches the sandbox agent's, so git refused every
    command with "detected dubious ownership" — which reads like a Wardyn defect rather than a
    uid mismatch.

v0.4.1 — corporate-network onboarding fixes (pre-alpha)

Choose a tag to compare

@cjohnstoniv cjohnstoniv released this 20 Jul 17:02

A corporate-network onboarding fix release, from two adopter field reports (kept in
docs/adoption/). Both are onboarding-trust bugs on the containerized
default path: one hard-blocked make setup, the other made the Getting-Started
checklist assert something it never actually checked. No interface changes.

Fixed

  • make setup no longer dies on a registry that can't serve pnpm. Behind a
    corporate allowlist mirror that hasn't onboarded pnpm, the image's default
    ui-build stage failed with a raw npm error code E404 (or 403) and the stack
    never came up — the one command the docs tell a new user to run did not work out of
    the box. scripts/up.sh now catches a failed build and retries with the UI built on
    your host (make ui + WARDYN_UI_STAGE=ui-prebuilt), explaining each step. The
    escape hatch was already there; it just required knowing an env var the failure
    never named. An explicit WARDYN_UI_STAGE is still honored and disables the
    fallback, and the OSS path with a working registry is unchanged — the retry branch
    is never entered. Chose retry over probing the registry first: the 404 is on the
    tarball path, so a mirror that proxies metadata answers a probe with 200 and the
    build dies anyway.

  • Staging a corporate CA no longer breaks the image build. The ui-build stage
    ran update-ca-certificates, but its node:*-bookworm-slim base purges the
    ca-certificates package in its own build, so the binary is absent — meaning any
    operator who followed make doctor's own advice and staged deploy/images/corp-ca.pem
    hit a hard exit 127, every time, before the pnpm step even ran. That stage now
    relies on NODE_EXTRA_CA_CERTS alone (npm/pnpm are its only TLS clients, and they
    read it). deploy/images/README.md's snippet — which is what produced the bug —
    was corrected so it stops reproducing it.

  • The Host proxy step tells the truth on the containerized stack. It reported
    "No host-side proxy configuration detected" on hosts unambiguously behind a
    corporate proxy, in the same session whose HTTP_PROXY Wardyn's own image build had
    just consumed. DetectHostProxy() runs in the wardynd process, and in a distroless
    container every tier is structurally blind: the env tier sees only the container's
    env (compose forwarded the proxy as a build arg only), HOME is unset so no
    shell profile or tool config is reachable, there is no git binary, and the OS/PAC
    tier dispatches on the process's GOOS. make setup now runs the same detector
    on the host (new wardyn setup detect-proxy, from a host-native binary the image
    cross-compiles) and seeds the result in, recovering the macOS scutil/PAC,
    Windows-registry, shell-profile, git and tool-config tiers that are inherently
    host-side. It re-runs on every up, so it cannot go stale across a network change.
    Deliberately not done by forwarding HTTP_PROXY into wardynd's runtime
    environment: Go's net/http honors those names process-wide, which would silently
    reroute wardynd's own OIDC discovery, audit webhooks, GitHub App minting and AWS
    credential chain through the corporate proxy — a live-traffic change to fix a
    diagnostic. A run's egress is unaffected either way (the sandbox env is built from
    scratch and always points at wardyn-proxy).

  • An honest empty result when detection genuinely can't look. When wardynd is
    containerized and no host-side reading was seeded, the step no longer asserts a
    false negative: it says detection ran inside the container, names what it therefore
    could not read, and carries a next step. The step's static lede ("Wardyn detected
    these host proxy settings…"), which rendered unconditionally above an empty
    result, is gone. Same honesty rule the Vault/KVM copy already followed.

  • A set-but-empty HTTP_PROXY no longer counts as a detected proxy. os.LookupEnv
    reports ok for export HTTP_PROXY=, and every consumer downstream tested presence
    only — so an empty value rendered a blank-valued "detected" row. Empty and
    whitespace-only values are now filtered, in the one place all tiers route through.

v0.4.0 — containerized setup, container workspaces, Bedrock SSO (pre-alpha)

Choose a tag to compare

@cjohnstoniv cjohnstoniv released this 20 Jul 05:15

Wardyn remains pre-alpha: interfaces are not stable and this release changes
several defaults. Read "Upgrading from 0.3.1" below before pulling it onto a
host that was running 0.3.1.

Added

  • The console's default sizing now matches 110% browser zoom. The root font
    token moved from 16px to 17.6px and the hardcoded px text utilities were
    converted to rem, so text and spacing scale together rather than the small
    labels being left behind. One token (--font-size in ui/src/styles/theme.css)
    rescales the whole console.

  • Container as an execution environment. A workspace can now be a container
    image (a new container kind, Source = image ref, no mount) alongside a local
    directory or repository, and any workspace/container can carry an operator-owned
    model/harness credential binding (none|managed|api_key|bedrock — secret
    names/refs only, never secret values). A run inherits the model access of the
    workspace/container it picks; the binding is folded into the run policy at create
    and injected proxy-side, so the sandbox never holds the credential. Onboard and
    edit bindings from the Workspaces screen or PUT /workspaces/{id}/llm-cred
    (migration 0024_workspace_llm_cred).

  • YAML policies. wardyn run --policy-file and wardyn policy create|update -f
    accept JSON or YAML; wardyn policy render -f <file> (or -f -) converts either
    to canonical JSON and strictly validates it without touching the control plane.
    Commented examples ship in examples/policies/: sandbox.yaml,
    sandbox-claude.yaml, and sandbox-workspace.yaml (a governed agent on a real
    local directory — note the mount source must be an onboarded local_dir
    workspace, and read_only defaults to true, so edits need it set false).

  • wardyn subscription connect|status|disconnect. Capture a claude setup-token
    from stdin only (never argv, never .env), stored age-encrypted and injected
    proxy-side into eligible runs — the sandbox holds only an inert sentinel. Connect
    is idempotent (skip-if-live, --reconnect to replace). The reserved secret name
    wardyn-harness-anthropic-oauth is blocked from the generic secrets API so this
    is the only supported path. WARDYN_SUBSCRIPTION_TOKEN seeds it headlessly through
    scripts/up.sh / scripts/ci-run.sh. SDK: ConnectManagedSubscription /
    DisconnectManagedSubscription. The setup-token is long-lived (~1 year),
    age-encrypted and non-rotating — documented, not hidden.

  • wardyn setup status: the console's readiness checklist in the terminal
    (same /setup/status source), each unmet check naming the exact next command.

  • AI Run Composer on the container path. A composer backend that runs the real
    claude inside a governed one-shot sandbox with the managed subscription injected
    proxy-side (never resident), mirroring the governed scan-run pattern — brokered
    /internal/compose-results/{runID}, WARDYN_COMPOSE_ONLY agent-run mode,
    cross-run guard, fail-closed when no subscription is connected, reclaim-on-timeout.

  • Containerized AWS SSO login for Bedrock. A fourth Bedrock credential path for
    SSO-only orgs: the operator authorizes a device code in any browser and Bedrock
    runs get short-lived role credentials — no host aws sso login, no ~/.aws mount.
    deploy/images/aws-sso is a dedicated login image (AWS CLI v2, GPG-verified) so
    ~600 MB of CLI stays out of normal runs; cmd/wardyn-aws-sso uploads the SSO cache
    through the brokered internal endpoint; runs_bedrock materializes a minimal
    synthetic ~/.aws (sso-session + hashed cache file). The pane collects your org
    portal URL and the server seeds a credential-free [sso-session wardyn] via
    WARDYN_AWS_SSO_CONFIG_B64; Wardyn persists no copy. Honest bound: the SSO
    token and the derived role credentials are resident in the sandbox (the UI says
    so with an amber chip), and Wardyn cannot revoke a captured SSO session. Validated
    against a fake sso-oidc/portal built from the real botocore service models, not
    against a live IAM Identity Center.

  • Standard AWS environment is honored. WARDYN_BEDROCK_REGION /
    WARDYN_BEDROCK_AWS_PROFILE fall back to AWS_REGION / AWS_DEFAULT_REGION /
    AWS_PROFILE; the Wardyn-specific names still win. A region alone cannot enable
    Bedrock (that also needs a model), so this cannot switch the transport on by surprise.

  • Corporate-network image builds. Corp-CA staging (corp-ca.pem, documented in
    deploy/images/README.md) and NPM_REGISTRY / HTTP_PROXY / HTTPS_PROXY /
    NO_PROXY are threaded into every docker build and through compose build.args;
    Dockerfile.wardynd gains a UI_STAGE selector (ui-build default,
    ui-prebuilt via WARDYN_UI_STAGE) so a mirror that cannot serve pnpm consumes a
    host-built ui/dist. up.sh builds agent images one at a time and continues past a
    blocked image with a summary instead of aborting the bring-up. corepack does not
    work around a mirror missing pnpm
    (it fetches from the same 404ing registry path)
    — hence the prebuilt stage.

  • Opt-in native agent-CLI install for corp networks (npm stays the default):
    CLAUDE_INSTALL=native installs the native claude binary, checksum-verified
    against the release manifest from downloads.claude.ai (the only host it contacts —
    allowlist it) or from a host-staged binary for fully offline builds;
    CLAUDE_CODE_VERSION pins it. CODEX_INSTALL=native is staged-only and fails
    loudly if no binary is staged, because codex has no Wardyn-verified public download
    contract. scripts/stage-agent-binary.sh does the host-side staging.

  • Shared-host concurrency for the compose control plane. Every explicitly named
    compose object is parameterized off WARDYN_NS (default wardyn, so the
    single-user default is byte-for-byte unchanged): container names, the internal
    network (WARDYN_INTERNAL_NETWORK, now threaded into wardynd config), and the
    recordings volume. WARDYN_PG_PORT parameterizes the Postgres host port.
    ci-run.sh takes a per-job COMPOSE_PROJECT_NAME + WARDYN_NS (unique per
    invocation, pinnable via WARDYN_CI_PROJECT), ephemeral host ports, a
    container-health wait, and a project-scoped down --volumes that can no longer wipe
    another job's stack. make test-e2e-concurrent (scripts/test-concurrent.sh) is the
    live two-job acceptance test and passes. Boundary: this is safe for one trusted
    operator
    (e.g. a CI fleet under one service account), not for mutually distrusting
    tenants.

  • Fail-closed resource caps. On a host where the daemon silently ignores
    NanoCPUs/Memory/PidsLimit (cgroup v1, or rootless without controller
    delegation), the sandbox ran effectively uncapped and nothing detected it. The
    daemon's ContainerCreate response warnings are now authoritative: any
    "…Limitation discarded" warning refuses the run and rolls the sandbox back.
    WARDYN_ALLOW_UNENFORCEABLE_CAPS=1 overrides on a trusted host (downgrades to a
    loud warning); wardyn doctor surfaces the signal pre-boot as an advisory hint.

  • Run type in the New Run wizard. The Basics step offers "Agent run" vs
    "Governed command" (a plain shell command, task_mode=exec, no agent, no LLM
    credentials), and bring-your-own base image is promoted out of Advanced into a
    first-class field. Picking a container workspace attaches it as the run's base
    image (it rides run.image, so the backend resolves it back by image ref to inherit
    its bound credentials instead of 422ing at the onboarded-mount gate).

  • Harness-aware demo. A fifth demo ("The agent in the box") appears on /demos
    once a model/harness provider is connected, scoped to Anthropic egress. Like every
    demo it comes up idle and you run claude yourself in the attached terminal. The
    four keyless egress-boundary demos stay LLM-free and remain the frozen set inside
    Getting Started.

  • Enterprise onboarding and a corp-aware doctor. The wizard now offers the
    Bedrock credentials the backend already read but never exposed — the preferred
    never-resident bearer (bedrock-api-key) and the SSO session token
    (aws-session-token), ordered by resolveBedrockAuth precedence. up.sh wires
    operator-provided Bedrock config (region/model, ~/.aws bind with the uid-1000 ACL
    note) into deploy/compose/.env on the container path. Rancher Desktop is detected
    by docker context and its non-bind-mountable ~/.rd/docker.sock is remapped to the
    in-VM socket, and wardyn setup wall gains a Rancher branch (rdctl shell) instead
    of telling a Rancher user to install Colima. doctor warns when a forward proxy is
    set with no corp CA staged (before a three-minute build dies on x509) and asserts the
    chosen docker socket is actually bind-mountable, not merely reachable.

  • Rootless and Podman: documented and probed. THREAT-MODEL now states the
    supported rootless model — rootless Docker/Podman is supported at CC1 only; CC2
    and CC3 are refused fail-closed (gVisor needs --TESTONLY-unsafe-nonroot, Kata needs
    device passthrough) — and reframes the upstream corp-proxy hop as a supported,
    operator-configured egress lane with its bounds stated (it does not make private IPs
    reachable; only the resolved-IP re-check is deferred to that proxy). It also answers
    the JVM/Deno trust-store question: MITM is not mandatory for any egress class, so
    only a client pointed at an explicitly MITM'd host is affected. scripts/test-podman.sh
    probes the exact primitives the runner depends on and passes against a live
    rootless Podman 4.9.3
    (internal bridge blocks off-host egress, runtimes map
    readable, host-gateway resolves, caps verified by reading the container's cgroup v2
    cpu.max/memory.max/pids.max).

  • docs/ADO-GIT-BROKER.md: a reviewed design only for never-resident
    proxy-side Azure DevOps git egress. The working l...

Read more