Skip to content

0.9.0

Choose a tag to compare

@watchlight-ai watchlight-ai released this 05 Sep 22:42
· 10 commits to main since this release
331daf8

Four changes tighten what is accepted, and each can turn something that previously worked into an error or a different verdict, so this is 0.9.0 rather than a patch.

All three of the first group came from an adversarial harness that tries to break the engine rather than demonstrate it. Each was reproduced against 0.8.2 before being fixed.

An unrecognised enforcement effect fails at load

@enforcement_effect("require_approval")   NeedsApproval
@enforcement_effect("needs_approval")     Allow          <- before
@enforcement_effect("not_a_real_value")   Allow          <- before

A one-character typo turned a human-in-the-loop guard into an unconditional permit, silently. The engine drops an effect it does not implement, which is the closed direction on a forbid, where terminate and quarantine make a deny stronger, and the open direction on a permit, where dropping require_approval leaves a plain allow.

The value is now refused with PolicyError naming the accepted set. A misspelled annotation name only warns, because an unknown annotation is legal Cedar and may legitimately be yours. load is whole-file or nothing.

An empty principal no longer becomes the agent

principal: "" was silently replaced by the acting agent, so user?.id ?? "" recorded a person's action against the runtime. Empty, whitespace-only and control-character principals now raise, at every boundary that takes one. An absent subject should name no principal, and the record then says so.

An unnamed governor is no longer matchable

A governor with no name invented one, and a policy could match it on any unconfigured deployment. It now sets neither reserved actor key, so a policy reading the actor cannot match it, and records a reserved placeholder that no real agent can wear. The zero-configuration quickstart still runs, deliberately.

Audit records are typed

A discriminated union on the event field, so a sink breaks at compile time when a record's shape moves rather than silently reading undefined. The untyped form is still available as an escape hatch.

Also in this release

The approval store expiry contract, with an optional prune that never moves a verdict. The default governor can be asked whether it can still be configured, accepts re-application of what is already in force, and takes its audit destination from the environment. The front page speaks both lanes.

A correction to our own documentation

Three descriptions of an untyped principal were in circulation and none was right. A bare identifier matches a policy naming that id under User, Agent, Group or Role, and not under Tool, Resource or Workflow. When it matches more than one, an allow beats a forbid, which is the opposite of Cedar's usual rule, so a forbid naming an agent can be defeated by a permit naming a user with the same id.

The guidance is unchanged, name the entity type, and now has a real reason behind it.

Migrations

An absent subject names no principal rather than an empty string. A policy naming an agent uses Agent::. A TypeScript sink annotated AuditRecord narrows on event, or annotates UnknownAuditRecord to keep the untyped bag.

pip install "watchlight==0.9.0"
npm install @watchlight/sdk@0.9.0