Skip to content

Releases: innerwall-dev/innerwall

v0.4.3 — first-run friction, and flags on either side

Choose a tag to compare

@github-actions github-actions released this 21 Oct 03:58
bcef844

The papercuts a first run hits — commands that accept their flags wherever you type them, console buttons that name the surface they open, install documentation that works as written on every distribution — rebuilt on today's Go security release. v0.4.2 was tagged but never released; this release carries its changes.

  • Rebuilt on Go 1.26.10 (#207). Today's Go security release (CVE-2026-111943) distrusts eight compromised public intermediate certificates in crypto/x509. Innerwall anchors every steady-state verification to the operator's own signing authority, where those chains cannot appear; enrollment run without --bootstrap-ca checks the control plane's certificate against the system trust store, and there the update is a real fix. Both binaries and the container image are built on the fixed toolchain.
  • Flags parse on either side of arguments (#132). Every innerwall and innerwall-agent subcommand reads its flags before or after its positional arguments, so flows list <workload-id> --since 1h works as naturally as the documented order; -- still ends flag parsing. One command gets stricter instead of looser: ruleset update with -f before the ruleset name refuses anything after the name, with an error listing the arguments earlier versions silently ignored — a previously accepted invocation may now error, but none changes meaning. Usage lines show flags first, and the top-level usage lists flows gaps.
  • The console's empty states open the surface they name (#164). The "Open enrollment" buttons on the simulation review and the flow map read "Open provisioning tokens" and land on Workloads → Provisioning tokens, the tab their own instructions point at.
  • The mint dialog's enroll command works as printed (#184). It reads sudo /usr/local/bin/innerwall-agent enroll …, matching the documentation: enrollment writes to a root-owned state directory, and the full path works on distributions whose sudo secure_path omits /usr/local/bin.
  • The deploy page runs the agent as root (#183). Its enroll, daemon, and kill-switch examples take the quickstart's form; the page said observation needs root while its own commands ran without it.
  • Install documentation (#152, #165, #175, #174). Every sudo invocation of the agent uses the full installed path; the deploy README names the CA certificate ca.crt, like every other page; the multi-host guide tells a same-machine VM lab which address to use — the VM network's gateway, from ip route show default, set before the first start; and the compose file's missing-variable error names both remedies, the quickstart's .env line and INNERWALL_IMAGE=innerwall:dev for a development checkout.
  • The automated ADR review posts again, and a failure shows red (#185, #187). Its credential exchange had failed silently on every run since the review changed triggers, behind a green check; the review now posts with the workflow token as one comment it finds and updates by its marker, and a failed review attempt on a pull request from this repository fails its check. The development docs describe the review as it runs.

Upgrading

No migrations, no API change, no agent-contract change. Both binaries are drop-in replacements; agents and control plane may be upgraded in either order.

v0.4.1 — the quickstart runs the released image

Choose a tag to compare

@github-actions github-actions released this 18 Oct 13:19
f090ba8
  • docker compose up never builds over the released image (#171). docker-compose.yml declared both the image .env names and a build from the checkout, so docker compose up -d on the quickstart's path pulled the released image, then built the checkout over it, tagged the local build with the release’s name, and ran that: a control plane reporting v0.4.0+<commit>.dirty, unverified, under the name of a signed image. The compose file is now image-only: it runs the image INNERWALL_IMAGE names, as pulled, and without the variable every docker compose command stops with an error naming the .env line to add. The build moves to docker-compose.dev.yml, which only make dev adds; its build is named innerwall:dev, never a release's name. make dev passes on a docker-compose.override.yml when one is present, as compose did on its own before. The quickstart's commands are unchanged apart from the version they name. Nothing in either binary changes.

v0.4.0 — first binaries, and the cold run's fixes

Choose a tag to compare

@github-actions github-actions released this 18 Oct 03:33
3af59d7
  • Admitted untracked traffic is accepted (#142, #154). A rule's accept also wrote the connection mark, and the kernel ends a rule at that write for a packet it does not track, so admitted untracked traffic fell through to the terminal rule. IPv6 neighbor discovery is never tracked: a rule admitting link-local ICMPv6, the simulation review's own remedy, recorded neighbor discovery as would-block in simulation and dropped it under enforcement, which breaks IPv6 neighbors. Each rule's accept is now paired with one that admits the same traffic unmarked when it is untracked; tracked traffic is marked and attributed exactly as before, and the two modes still differ in the terminal rule alone (ADR-0020 as amended). Agent-side only: no migration and no wire change. Upgrade agents before enforcing on a host with IPv6.
  • The connection-mark mask, as nft list prints it (#143, #154). A listed rule shows ct mark & 0x000Nffff | 0x000N0000, which read as a mask leaking region bits. It is nft's reading of the kernel's mask-and-xor form of the rendered (ct mark & 0x0000ffff) | 0x000N0000, the same write; the rendering is unchanged, and tests now pin the rendered mask and the installed bytecode. The promotion guide and ADR-0020 say how the listing reads.
  • A quiet workload is no longer called silent (#144). The agent ships only the flow windows that hold something, so a workload that receives little inbound traffic — a bastion, a standby replica — goes minutes between reports while its agent runs and observes. v0.3.0's silence derivation read every such stretch longer than two windows as an agent that was not reporting, and wrote agent_silent gaps for evidence that was never lost; the simulation review drew them as one interval spanning the hour and failed its verdict. Every heartbeat already carries the agent's uptime, so the control plane now records the process start each heartbeat implies (migration 00016) and derives no gap for a silence one agent process demonstrably ran through: one that started before the previous report and was still heartbeating within a window of the arriving one (ADR-0019 as amended). A stopped agent still derives its gap with the same bounds — a restarted process's heartbeats place its start after the silence began, and a dead process's last heartbeat is too old to cover the report that ends it — and a quick restart still records nothing. Gaps v0.3.0 already wrote for quiet stretches stay in place, since nothing stored tells them from an outage, and age out with flow retention. The agent is untouched; the migration makes the next release v0.4.0.

v0.3.0 — the silence gap, and operator docs

Choose a tag to compare

@avi-papineni avi-papineni released this 17 Oct 03:45
dccda6a

An agent process that is down now counts against the evidence its workload's verdict rests on, and the operating loop is documented end to end: task guides, a reference for both command lines and the operator API, and a troubleshooting catalog grown from live operation.

  • Operator documentation (#43, #52, #100, #130). Task guides for the operating loop under docs/guides/: labeling, the first ruleset, reading a simulation review, promotion and enforcement (with the kill switch and fail static), the credential lifecycle, and upgrading in place. A multi-host evaluation guide for agents on other machines. A reference under docs/reference/: both command lines, the operator API, workload states and every evidence-gap kind, versioning and install. docs/troubleshooting.md grows from two entries to fifteen. The deploy guide no longer calls the console unshipped, and its flows list example puts the flags before the workload id, the order the command reads. api/openapi.yaml states that the sync_state filter does not exclude workloads whose enforcement was removed on the host. The console captures gain per-theme singles beside the composites, and the capture script writes both forms.
  • An agent's silence is an evidence gap (#114). An agent process that is down leaves the owned table enforcing (fail static, ADR-0011) but observes nothing, and nothing used to say so: a simulation review over the outage could read "safe" on evidence that was never collected. The control plane now derives the gap itself — flow ingest already stamps every report's receipt, so a report that ends a silence longer than the telemetry-liveness allowance (two flow windows) writes an agent_silent gap from the previous receipt to the arriving window's start (migration 00015, ADR-0019 as amended). A window that reaches back over the silence is buffered evidence delivered late and derives nothing, so a telemetry outage the agent rode out, and a quick agent restart, record no gap. The review's verdict, the workload page, GET /api/v1/flows/gaps, and innerwall flows gaps state the new kind like any other; the agent is untouched, and a reported gap claiming the kind is refused at ingest.

Innerwall v0.2.0 — console v3, and honest state

Choose a tag to compare

@avi-papineni avi-papineni released this 16 Oct 02:43
36b06fa

The console is restyled to design package v3, with a new workload page, and it says more truthfully what each host is doing: a removed table, a reconnecting control channel, a drifting clock, and a late renewal each read as what they are. Credential expiry is no longer a cliff, and a label means one thing on every surface.

Console

  • Design package v3 (#118). New tokens and type: DM Sans and Source Code Pro, self-hosted. The chrome, controls and tables are restyled, with 40px rows. The Workloads table gains an Agent column. Every flow map edge is drawn at one 2px width, with decision carried by dash, color and glyph, never by width. The stored theme paints from the first frame. The package is recorded in docs/design/. Between the two releases the console was first restyled to package v2 (#27); v3 supersedes it.
  • The workload page (#118):
    • the workload's identity, mode, and last contact sit in the header strip;
    • the page lands on an Overview of alert cards, status, labels, host facts, and the evidence-gap history;
    • exceptional states are chips beside the tabs on every page, critical first, each opening its explanation;
    • Inbound flows and Listening services gain a filter panel.
  • Search, edit, and navigate (#85):
    • a search palette behind the header box and ⌘K finds workloads by hostname or label and rulesets by name;
    • a workload's labels are edited in place, as a conditioned write with a review of what changes;
    • the Workloads badge counts the workloads needing attention;
    • an address with no screen renders "No such page" instead of redirecting;
    • "Open in policy editor" carries the pair's peers, services, and matched rule into the editor.
  • Policy editor (#76, #80):
    • every finding is reported in one pass, for rulesets, rules, and services;
    • address-shaped peer text is read as a CIDR, typo or not;
    • a pending scope edit and rule edit save as one write, so the previewed combination is what lands;
    • rulesets can be renamed and redescribed;
    • creating a ruleset lands on it;
    • a click on the promotion's held-back confirm keeps the dialog.
  • The control plane's version shows in the account popover, from /me (#87).
  • Flow map edges route around the nodes (#121). An edge that skipped a layer used to run under the cards in it, and a node's edges all left one point, so a fan read as one bundle and its labels landed at ragged offsets. Each edge now follows its own lane, crossing columns level and bending only between them; every label sits in a slot kept for it on its own edge; and a node's edges attach at ports spread along its side.
  • The flow map's graph library and layout load only with the map (#120). The main bundle drops from 891 kB to 636 kB.

Agents and the control plane

  • Credential expiry is no longer a cliff (#102, #110, ADR-0016 amended). A control-plane outage that spanned the agents' renewal window used to lapse every credential and force a re-enrollment per host.
    • The renewal call now accepts a credential expired by at most --renewal-grace (72h by default); every other call still requires a valid one.
    • Expiry is never fatal to the agent: it keeps enforcing from disk and keeps retrying renewal.
    • Enrollment may overwrite an expired stored credential.
    • Renewal is scheduled on monotonic time as well as the wall clock.
    • A late renewal is logged, recorded, and shown.
  • The kill switch is visible (#95, #101). A host whose owned table was removed reports it on its next heartbeat.
    • Its flow reports carry a table_removed evidence gap for as long as the table stays removed.
    • The Workloads table, the workload page, the counts, the attention badge, and a removed filter all say so.
    • A kill-switched host no longer reads as healthy and idle.
  • Reconnecting is told from offline (#95). Ingest records each workload's last flow report. A workload whose control channel is down while its reports keep arriving reads "Reconnecting"; one with no contact on either channel reads "Offline".
  • Agent clock skew is detected (#81, #90).
    • Every flow report carries the agent's clock at send.
    • Skew beyond two windows is logged, recorded on the workload, and shown, with the remedy in docs/troubleshooting.md.
    • A window open across a backwards clock step is cut at the step.
    • A window the control plane refuses as malformed is dropped and recorded as a window_rejected gap. It used to block every window behind it until a restart.
  • Directed reconnects (#53, #107).
    • The agent redials at once on a directed reconnect, and resets its backoff once a stream is established.
    • The gateway logs every directive it cannot deliver.
    • A stream that ends no longer marks a newer live stream of the same workload offline.
  • One label grammar (#34, ADR-0022). It is admitted wherever a label enters: token mint, label edits, scopes and peers, selectors, and read filters. A paste such as app=web env=lab becomes two labels, where it used to become one label no selector could match. The console's label inputs share one parser that mirrors the grammar, and a stored label outside it is drawn quoted.
  • A label scope can match either end of a flow (#36, ADR-0019 amended). The flow map uses endpoint=either, so scoping to a workload that only sends now draws its traffic.
  • Both binaries report their tag and commit (#71): v0.2.0+<commit>, or dev+<commit> for an untagged build.
  • Visibility engages connection tracking itself (#32). On a host where nothing else referenced connection tracking, visibility observed nothing and reported no error. This was listed under v0.1.0 but merged after the tag, so v0.2.0 is the first release that carries it.
  • A peer-only change on a visibility table is one full apply (#95). It no longer logs a set-update refusal blamed on the kernel.

Build and project

  • Go 1.26.9 and golang.org/x/net v0.60.0 clear the advisories reachable from the shipped code; golangci-lint moves to v2.9.0 with them (#35).
  • The automated ADR review runs on pull_request_target, so it can authenticate on a fork's pull request; a review that did not post says so in the job summary (#73, ADR-0014 amended).
  • docs/policy.md states the policy model: a ruleset's scope is the destination, one ruleset per tier (#77).

Upgrading

  • Migrations. Five are added, 00010 through 00014; all are additive. Apply them with innerwall migrate or innerwall serve --migrate.
  • Order. Upgrade the control plane first, then the agents. A v0.1.0 agent keeps working against a v0.2.0 control plane: a report without a send time is judged by its window, and a heartbeat without the table's state leaves the stored one. The renewal grace, skew detection, and kill-switch reporting each work in full only with both ends at v0.2.0.
  • Labels. Writes and read filters outside the grammar are now refused with findings; a read filter outside it was an empty result. Stored labels are not rewritten. Enrollment refuses a provisioning token whose stored labels fall outside the grammar: mint a new token for those labels. A workload's own labels outside it can be repaired in the console's label editor.
  • API. Every surface change is additive:
    • Me.version;
    • health.clock_skew, health.owned_table, health.last_flow_report_at, health.telemetry_live, and health.credential.last_late_renewal;
    • GET /api/v1/workloads/counts;
    • the rollup's endpoint parameter;
    • the gap kinds window_rejected and table_removed.
  • Agent contract. The changes are additive fields: ReportFlowsRequest.sent_at, the heartbeat's owned_table, and the two gap kinds.

Known limitations

  • The server-side evidence guard, the workload deny-list, and clone detection are not built (ROADMAP.md).
  • The aggregation window is set in the control plane's defaults; innerwall serve exposes no flag for it.
  • Linux only, inbound only, one operator.

Innerwall v0.1.0 - visibility, simulation, enforcement

Choose a tag to compare

@avi-papineni avi-papineni released this 06 Oct 21:46
6007581

The first release of Innerwall: one control-plane binary with an embedded operator console, PostgreSQL for everything durable, and a Linux agent that observes flows and programs the native firewall. The operator loop ships end to end — enroll, observe, simulate, promote, enforce — driven entirely from the console.

What's in it

  • Enrollment and identity — token-gated enrollment with no trust-on-first-use window; scoped, expiring, revocable provisioning tokens stored only as digests; short-lived certificates carrying a single URI identity, renewed automatically.

  • Policy sync — one mutually authenticated stream per agent: a snapshot per stream, deltas within it, versions that advance only when rendered output changes, full-jitter reconnects. Agents fail static: the last acknowledged policy survives restarts and reboots.

  • Flows — inbound connections aggregated at the agent and reported on their own RPC, peers resolved at ingest time, and evidence gaps recorded as first-class intervals wherever the agent knows evidence was lost — a review over incomplete evidence says so.

  • Policy, simulation, enforcement — live authoring with conditional writes and inline validation; simulation runs the same ruleset as enforcement with only the terminal verdict changed; promotion is operator-gated behind an explicit acknowledgment of exactly what would be dropped.

  • Operator surface and console — one TLS-only listener, single-operator authentication with sessions and automation tokens, an origin guard on every write, and a console covering simulation review, the flow map, fleet, workload detail, and the policy editor.

Hardening before this tag

Two independent conformance audits of the release candidate were absorbed in full: persist-before-apply acknowledgment, stable connection-mark attribution across policy versions, bounded open flow windows, strict identity parsing, a bounded login throttle, a patched Go toolchain with a govulncheck gate in CI, bundled third-party license texts, migration immutability enforced by CI, and a decision record corrected wherever it had drifted from the shipped system.

Known limitations

Linux agents and inbound enforcement only. One operator. No server-side evidence guard on mode changes, no workload deny-list, no duplicate-identity detection — the recorded revocation story is short-lived certificates and token revocation. See ROADMAP.md for what comes next.

The quickstart in the README is verified end to end on both the Docker Compose and from-source paths. Licensed Apache-2.0; bundled fonts carry their own licenses, shipped alongside.