Hardening and Public Launch turns Pomavo into a product you can operate, evaluate, and extend in the open. The release focuses on deterministic automation, stronger identity boundaries, safer outbound networking, faster asset delivery, shared packages, and this public documentation site.
A typed automation engine extracted into its own library
The automation engine is now a dedicated, typed library rather than a loose collection of worker executors. The Automation Engine defines one canonical contract for node ids, ports, data types, object properties, and generic list shapes.
That contract is used by the editor, server-side resolver, runtime orchestrator, and validation layer. When you wire a graph, design-time resolution and runtime execution agree on what each node accepts and emits.
| Engine concept | What it means |
|---|---|
| Canonical node contract | Node ids, inputs, outputs, and type metadata live in one source of truth |
| Primitive types | string, number, boolean, and date |
| Complex objects | ticket, user, state, transition, iteration, project, link, comment, and tag |
| Generics | Generic lists and type variables for flexible nodes |
| Runtime shape guard | Node outputs are checked before downstream nodes consume them |
| Conformance tests | Contract drift is caught before automations reach production |
Object outputs carry the full object shape. A trigger that emits a ticket gives downstream nodes a structured ticket, not a bare id that every node has to resolve again.
Deterministic graph execution
The extracted engine evaluates automation graphs through a clear orchestration spine. It starts from matching triggers, resolves inputs through exact graph edges, executes nodes, gates false branches, and skips expensive output materialization when nothing downstream consumes the value.
Seed from triggers
The plan starts at trigger nodes that match the event.
Resolve inputs
The orchestrator maps source handles to target handles by following graph edges.
Execute nodes
Each executor runs against declared inputs and returns declared outputs.
Validate shapes
The output guard rejects phantom keys and missing consumed keys.
Continue or skip
Conditional branches continue only when their upstream condition is true.
Loops and schedulers are first-class. ForEach runs a downstream sub-graph once per item and Collect forms an ordered list when iterations complete. Scheduler nodes fork a run, snapshot the upstream values needed later, and resume the deferred branch through the Job Pipeline.
Runtime validation that fails loud
Automation bugs are expensive when they silently turn into null three nodes later. Pomavo now validates runtime output shapes against the declared contract as values move between nodes.
| Validation rule | Failure it prevents |
|---|---|
| No phantom keys | A node cannot emit properties its declared type does not include |
| No missing consumed keys | A downstream node cannot consume a property that was never materialized |
| Exact port matching | Source and target handles must line up with the graph contract |
| Lazy output materialization | Nodes compute only values that downstream nodes consume |
| Named violations | Errors identify the node, port, expected shape, and actual shape |
This makes automation behavior deterministic and testable. The conformance suite covers contracts, runtime shapes, resolver parity, graph execution, dynamic handles, node families, and real graph scenarios.
RS256 and JWKS authentication
Authentication has been hardened for public operation. The Auth service issues RS256-signed JWTs, publishes public signing keys through JWKS, and the .NET services validate tokens using cached JWKS keys instead of shared symmetric secrets.
The token path is also cookie-first for the browser. When you select an organization, the Auth service issues a one-hour JWT with user and organization claims, sets it as the pomavo_jwt HTTP-only cookie, and lets frontend API clients send it automatically with credentials: include.
| Auth hardening | Detail |
|---|---|
| RS256 signing | Tokens are signed with an RSA private key and a kid header |
| JWKS validation | Services fetch public keys from /api/auth/jwks and cache them |
| HTTPS metadata | Metadata HTTPS cannot be disabled outside Development |
| Audience | Tokens target pomavo-api |
| Issuer | The public auth URL is the expected issuer |
| Cookie name | pomavo_jwt |
| Cookie flags | HTTP-only, secure in production, same-site lax, path / |
| Expiration | One hour token lifetime |
This design keeps signing authority in the Auth service while letting API services validate tokens independently. It also supports cross-subdomain organization flows without exposing bearer tokens to frontend JavaScript.
SSRF protection for outbound server requests
Public launch required a stricter outbound request boundary. Pomavo now validates server-side URLs before plugin lifecycle calls, agent runtime requests, MCP discovery, MCP server calls, and model provider calls.
The shared validator requires absolute HTTP or HTTPS URLs, requires HTTPS outside approved development localhost cases, disables automatic redirects, resolves DNS itself, and blocks private or sensitive address ranges. It also blocks metadata.google.internal explicitly.
| Blocked target class | Examples |
|---|---|
| Loopback outside dev localhost | 127.0.0.1, ::1 |
| Link-local | 169.254.0.0/16, fe80::/10 |
| Private IPv4 | 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 |
| Unique local IPv6 | fc00::/7 |
| Carrier-grade NAT | 100.64.0.0/10 |
| Unspecified and multicast | 0.0.0.0/8, 224.0.0.0/4 |
| Cloud metadata name | metadata.google.internal |
Outbound URL validation is enforced on the server side. A plugin lifecycle URL that points at a blocked network target is rejected before any request is sent.
Cookie-only browser sessions
The web client no longer needs to store or manage API bearer tokens in JavaScript. The shared API client sends the HTTP-only pomavo_jwt cookie automatically, and the server authentication layer reads the cookie only when there is no Authorization header.
That header precedence is useful because non-browser callers can still use API keys or bearer tokens where appropriate. Browser sessions get safer default behavior, while integrations and automation clients keep explicit machine authentication.
| Caller | Authentication path |
|---|---|
| Browser UI | HTTP-only pomavo_jwt cookie |
| API key client | Organization-bound API key |
| Plugin widget | Short-lived plugin token scoped to the installation and context |
| MCP or integration | API key or configured service credential |
| Internal service | Validated JWT or service-specific configuration |
See the Security Model for how identity, permissions, API keys, plugin sandboxing, and tenant isolation fit together.
CDN-served attachment delivery
Attachments now resolve through a public storage CDN host rather than raw object-storage endpoints. Presigned URLs are signed directly against the CDN host, and nginx forwards the original host so SigV4 signatures remain valid.
This improves the public deployment shape in three ways: browsers do not need to reach the raw MinIO endpoint, CORS is easier to reason about, and attachment delivery can be separated from app and API traffic.
| Attachment path | Result |
|---|---|
| Dedicated public URL | STORAGE_PUBLIC_URL defines the host used for presigned URLs |
| CDN server block | nginx serves storage traffic through the CDN host |
| No host rewriting | Signatures stay valid because the original host is forwarded |
| Explicit CORS | MinIO browser origins are configured without wildcards |
| Public asset reuse | Plugin icons and attachments can use stable public delivery paths |
Open-source @pomavo/ui and @pomavo/sdk
The shared UI and SDK packages are now published under the @pomavo npm scope. Plugin authors can build against the same primitives Pomavo uses, and the first-party GitHub plugin consumes the packages through public imports.
| Package | Purpose |
|---|---|
@pomavo/sdk | Node.js SDK for building Pomavo plugins, with client and server exports |
@pomavo/ui | React UI component library, theme system, API utilities, layout-code helpers, and shared types |
The packages are versioned, built, typechecked, and published through CI. Package publishing uses npm trusted publishing with OIDC and verifies that the tag version matches the package version before publishing.
import { createPomavoClient } from "@pomavo/sdk/client";
import { Button } from "@pomavo/ui";Public docs and Query DSL highlighting
This documentation and marketing site is now part of the product surface. You can point users to architecture docs, plugin docs, security docs, release notes, and the full Query Language reference.
The Query DSL page includes syntax-highlighted examples for filtering, sorting, grouping, aggregation, references, date literals, and bulk mutations.
status != "Done"
group by assignee
return assignee, count() as open_tickets, avg(quot;Story Points") as avg_points
order by open_tickets desc| Docs area | Link |
|---|---|
| Architecture overview | Architecture |
| Automation internals | Automation Engine |
| Security | Security Model |
| Plugins | Plugins |
| GitHub | GitHub |
| Job processing | Job Pipeline |
| Locks | Ticket Locks |
Elastic License 2.0 adoption
Pomavo now ships with the Elastic License 2.0. The source is available for use, copying, distribution, and derivative works under the license terms, while preserving important limits around offering the software as a competing hosted or managed service.
CI hardening for public work
CI now gives public contributors and maintainers clearer guardrails. The web workflow installs dependencies, checks formatting, runs ESLint, runs TypeScript build mode, and builds the web app. The .NET workflow restores and tests the unified test project. The docs workflow builds this site and deploys it through GitHub Pages.
| Workflow | Hardening detail |
|---|---|
| CI | Node install, formatting, ESLint, TypeScript check, web build, .NET restore, .NET tests |
| Docs | GitHub Pages permissions, Pages artifact upload, static site build for Pomavo.Blog |
| Packages | Build and typecheck @pomavo/sdk and @pomavo/ui |
| Publish | OIDC trusted publishing, npm upgrade, workspace resolution from tag, version match check |
| Actions | Updated checkout and setup actions reduce deprecated runtime exposure |
Typed automations
A dedicated engine library makes automation graphs deterministic and testable.
Hardened identity
RS256, JWKS, cookie-only browser sessions, and HTTPS metadata enforcement protect auth boundaries.
Safer integrations
SSRF validation protects server-side outbound calls before they leave Pomavo.
Public surface
Docs, packages, CI, and licensing are ready for external users and contributors.
Next, public launch lets you build on a clearer foundation: typed automation contracts, documented architecture, safer integrations, and shared packages that plugin authors can depend on.