Skip to content

Releases: plat5dev/plat5

v0.6.0

Choose a tag to compare

@kylkrie kylkrie released this 14 Oct 02:26

Breaking:

  • Identity realms, one credential. People live in the directory and are linked to IdP subjects on first sign-in. API keys and sessions share one table and one validate call; the gateway asks once and the realm decides the route. v1 credentials issued before this release still validate. (d935810)
  • Organization slug removed. The org id is the address and name is the label. (34825e7)
  • Staff-only routes. GET /users and GET /members/{member_id}/user are staff-only and off the customer catalog (7308c32). A person's status moved to PATCH /users/{user_id}/status, staff-only; PATCH /users/{user_id} now changes the name only (c13a956).
  • Org lifecycle events. organization.created and member.created are written in the same transaction as the create (a1fa5a5). Removing a member revokes their keys, deletes sessions and records member.removed; removed is final, and re-adding the person creates a new member id. Org delete records organization.deleted (4aab010).

Also

  • A user route is recorded in the person's own audit log, and in the org's when the service names it (d935810).
  • Docs describe the model as realms, one credential, and owners (9a7d93b).
  • Compose images pinned to v0.6.0 (f1ba8f1).

Full changelog: v0.5.0...v0.6.0

v0.5.0

Choose a tag to compare

@kylkrie kylkrie released this 09 Oct 20:03

This release is everything since v0.4.4.

Breaking

  • The gateway now requires AUDIT_URL at boot, because audit is on by default. Set AUDIT_URL to the audit service's internal base URL, e.g. http://audit:3003. If you don't want audit, set AUDIT_ENABLED=false on the gateway. Any value other than true or false refuses boot.
  • Route-registry apply now rejects service names that aren't 1–128 characters of [A-Za-z0-9._-]. The audit event's service field has the same limit.
  • On organization and member routes that are audited, the gateway writes the audit intent before forwarding. While audit is down, those requests return 503 and the service is not called. Writes are audited by default.
  • The gateway's check order changed: authenticate, rate limit, audit intent, then required_labels. A request denied by labels (403) now counts against the rate limit.
  • The compose admin role in compose/roles.yml gains org:audit:read. Update your own ROLES_FILE if you want the same.

Added

  • Audit service (services/audit, new image). Each audited organization or member request is recorded as one event in the subject org's audit log. The intent is written before the request is forwarded, and the outcome is written afterwards in the background. An event stays pending until its outcome arrives. A dropped or failed outcome write leaves the event pending.

  • GET /org/audit-events is published by the audit catalog (services/audit/routes.yml) and requires the label org:audit:read.

  • docs/audit.md describes the model and its guarantees.

  • Route audit: true|false overrides the default, which is to audit writes. It applies to organization and member routes only.

  • The identity invite list (GET /org/invites) sets audit: true, because it returns live tokens.

  • Services can report what changed on X-Plat5-Audit-Details. The gateway stores it as sent and always strips it from requests and responses. It accepts one ASCII JSON object of at most 4096 bytes and ignores anything else with a warning.

  • Gateway config:

    • AUDIT_ENABLED
    • AUDIT_URL
    • INTERNAL_AUTH_TOKEN is now also sent to audit.
  • New metrics:

    • Gateway: audit_writes_total and audit_intent_duration_seconds.
    • Audit service: audit_intents_total and audit_outcomes_total.
  • Compose files, CI, and the release workflow now include the audit service.

  • Gateway request log lines (request completed and request failed) now carry the following fields, each present only when known:

    • auth_type: jwt, user_apikey, member_apikey, or member_session
    • key_prefix
    • user_id (admitted on user routes)
    • organization_id and member_id (admitted on organization and member routes)

    key_prefix is set before validation, so 401 and 403 lines carry it. It matches key_prefix on identity's key list, or a session's token_prefix. The key, token, and JWT are never logged, and the line has no labels or role (#21).

Changed

  • Identity now reports changes to audit as from/to and reports creates by id. It never reports a secret or user_id. A new auditx helper does this for organization, member, service-account, invite, and member-key handlers.
  • Organization update now reads the prior values and applies the change in one store call. Previously it read the organization first and saved it afterwards.
  • Docs: wording for labels in the gateway route_config comments and in naming-conventions.md now matches the implementation (#20).
  • Docs: updated routes.md, gateway-contract.md, identity.md, roles.md, self-hosting.md, and telemetry.md for audit.

Fixed

  • Route-registry apply now refuses routes that can't be recorded in the audit log.
  • The audit service reads the org's prior state under the lock, so concurrent writes see consistent prior values.

Images

All at v0.5.0:

  • ghcr.io/plat5dev/gateway:v0.5.0
  • ghcr.io/plat5dev/route-registry:v0.5.0
  • ghcr.io/plat5dev/identity:v0.5.0
  • ghcr.io/plat5dev/audit:v0.5.0

Compose images are pinned to v0.5.0 (PLAT5_VERSION).

Full changelog: v0.4.4...v0.5.0

v0.4.4

Choose a tag to compare

@kylkrie kylkrie released this 08 Oct 18:01

Roles replace key scopes. This is everything since v0.3.2: v0.4.0 through v0.4.3 were iteration tags with no separate notes.

Breaking

  • Key and session scopes are gone. A member key or session now carries its member's role labels, and nothing narrows it below that. To give a machine less access, give it a service account with a smaller role. Restricted (scoped) keys and sessions are revoked on upgrade.
  • Roles come from a deployment roles file. ROLES_FILE on identity points to a YAML file that maps role slugs to labels, with creator_role, default_role and an optional service_account_default_role. Roles are on or off for the whole deployment: if ROLES_FILE is unset, every member holds every label (["*"]). An invalid file or unknown keys refuse boot. See docs/roles.md and the starter file compose/roles.yml.
  • Routes declare required_labels, not required_scopes. The permissions field on the wire is labels. It is always a list and never null.
  • Org writes in the identity catalog are labeled: org:write, org:delete, org:members:write and org:service-accounts:write. A member whose role lacks the label gets 403, with any of its keys or sessions.
  • added_by and created_by are removed from identity requests and responses.
  • Identity migrations are folded into one schema. No scopes compatibility is left.
  • Compose requires PLAT5_VERSION from the env file. The pin lives only in .env.template.

Added

  • role on member, invite and service-account writes. A slug that isn't in the file returns 422.
  • GET /organizations/{organization_id}/roles lists the deployment's roles. It's published at the edge as GET /org/roles so a console can show a role picker.
  • A write can't take an org's last creator_role holder to zero (422).

Fixed

  • gateway: a CORS preflight returns 204 and completes (#15).
  • identity: the request log records the status the client actually received (#14).
  • route-registry: restore validates like apply, lookalike paths conflict, and paths are canonical (#16).
  • route-registry: specific 422s for credentials in a url and for an out-of-range port. The missing-url message no longer mentions plat5.yml (#19).
  • docs: a route-config url must be exactly http://host:port (#17).

Images

ghcr.io/plat5dev/gateway:v0.4.4, ghcr.io/plat5dev/route-registry:v0.4.4, ghcr.io/plat5dev/identity:v0.4.4

Full changelog: v0.3.2...v0.4.4

v0.3.2

Choose a tag to compare

@kylkrie kylkrie released this 07 Oct 17:34
4d9385c

Breaking: route url must be exactly http://host:port.
Before: url: api:3000
After: url: http://api:3000
Bare host:port, https://, paths, and query strings now return 422 on route apply. Routes already stored keep routing until re-applied.

  • Minted API keys and sessions are capped at the parent's scopes; an omitted scope list inherits the parent's. (#2)
  • 409 ROUTE_CONFLICT names the service that owns a path. (#3)
  • 422 on missing url says to add the service under upstreams: in plat5.yml or set url. (#15)
  • Gateway returns 502 instead of panicking on a bad upstream address.