Skip to main content

5.3 Release Notes

Patch Releases​

All patch release notes for 5.3.x are available on the releases page.

Node Identity​

node.hostname and replication.hostname must now be a bare hostname or IP literal. This value is the node's identity — it becomes the node's TLS certificate common name and the host that replication advertises to peers and dials to reach the node — so a URL or host:port value corrupted certificate matching and replication without surfacing an error: a node configured as http://host:9926 advertised and dialed a host literally named http (harper#2218).

Configuration validation now rejects these values at startup, so an existing install whose node.hostname or replication.hostname is a URL, host:port, or a non-string value will fail to start until it is corrected to a bare host. The startup error names the offending value and the reason it was rejected. A bare hostname (server-one), an IPv4 literal (10.0.0.5), and an unbracketed IPv6 literal (::1) are valid; a scheme, port, path, credentials, query string, fragment, bracketed IPv6 literal ([::1]), or non-string value is rejected. Route entries under replication.routes are unaffected and may still be URLs.

When node.hostname is unset, Harper resolves the identity to the first valid bare host among replication.hostname, the host in replication.url, the TLS certificate common name, and the Operations API host, falling back to 127.0.0.1. A derived source that is empty or unusable is skipped rather than failing startup.

Replication URLs now also bracket a bare IPv6 literal correctly (::1 becomes ws://[::1]:9933), which the URL parser previously rejected.

See Configuration Options.

Component Deploys​

Staged Build Retention​

deploy_component builds each release under <componentsRoot>/.deploy-staging/<deploymentId> and validates it before swapping it live. A build that completes but is never activated now survives startup, bounded per component by the new deployment.stagingRetention.maxCount setting (default 5; 0 keeps none). Older builds are removed at the start of the component's next deploy and at startup; anything belonging to an in-flight or unsettled deploy is never touched. Groundwork for deploying from an already-staged build (harper#2315). See Configuration Options.

Root Config Follows the Live Release​

A component's entry in the root harper-config.yaml now changes only once its new release is live. A package deploy used to write the entry before it built, so a deploy that failed to install or validate still left config naming the failed release, and the next restart installed it. The entry is now recorded with the deploy's activation and published after the swap, and startup settles a deploy that was interrupted partway through, so config and the live component agree after a crash, including whether the component runs isolated (harper#2315).

A payload deploy now removes package, install, and credentials from the component's entry, keeping its other keys such as host, urlPath, and isolated. Previously they stayed, so a node installing the component from its config entry installed the old package instead of the payload release that was live. See How a deploy updates the root config.

Security​

Route-Owned Authentication​

Harper now defers rejection of an unrecognized Basic or Bearer credential on the application HTTP port until a handler claims the request. Harper-owned routes still return the normal unauthorized response. Unowned routes can fall through to application middleware with the original Authorization header unchanged. This lets catch-all applications and reverse proxies apply their own authentication schemes without URL exemptions or header rewriting, and the unauthorized response such an application returns — including its own WWW-Authenticate challenge — is passed back to the client unchanged. Internal authentication failures continue to fail closed. See Authentication and route ownership.

Operation Allowlist Enforcement​

A role's permission.operations allowlist is now checked before every other privilege check on the role, so an operation the list omits is denied whatever else the role carries. Table DDL and SQL previously went around it.

A role that relied on either will lose access on upgrade. Two cases to audit, both fixed by adding the operation to the list:

  • operations combined with structure_user — create_table, create_attribute, drop_table, and drop_attribute now have to be listed. structure_user still scopes them to its databases.
  • operations omitting sql — the role can no longer run SQL.

Roles with no operations field are unaffected, as are roles that already list everything they call. See Operation Permissions.

OIDC Trusted Publishing​

A CI runner can now authenticate to Harper with no stored credential. It presents an identity token minted by its own provider, and if that token verifies against a trust policy configured on the instance, Harper returns a one-hour operation token for the user the policy names — the same exchange npm, PyPI, and AWS STS AssumeRoleWithWebIdentity use. This replaces a 30-day refresh-token secret with a rule you configure once and revoke with drop_oidc_trust.

Policies are managed with add_oidc_trust, list_oidc_trust, and drop_oidc_trust (all super_user), and live in the replicated system.hdb_oidc_trust table. A policy pins the issuer, an instance-specific audience, and a set of claim constraints. For GitHub Actions those constraints must pin the repository, pin the workflow, and gate the ref — a policy naming only a repository and workflow is refused, because anyone who can push a branch could otherwise add the trusted workflow to it and mint a token. Issuers with no registered profile must pin sub, which makes Kubernetes service accounts, GCP service accounts, and SPIFFE identities work with no provider-specific configuration.

A policy can also carry an operations list, narrowing the minted token to a subset of its user's role on the Operations API and SQL paths — narrowing only, and not covering an application's REST/GraphQL data path, so the policy's user should still be a least-privilege role for the data it can reach.

Identity tokens are single-use, though the replay record replicates asynchronously, so two simultaneous replays against different nodes can both succeed. Exchanges are recorded in the authentication audit stream when logging.auditAuthEvents.logSuccessful / logFailed is enabled — they are off by default, so turn them on before you need the trail. Every rejection returns the same message, with the specific reason written to the oidc-trust log. In the CLI, the exchange ranks below every configured credential, so enabling it does not silently re-point a pipeline that still has a token secret set. See OIDC Trusted Publishing and Workload identity.