Skip to content
jwcarmanPublic

Occlude

CI Maven Central Javadoc Docs License Java

Maintainability Rating Reliability Rating Security Rating Vulnerabilities Quality Gate Status Coverage

Opaque references to sensitive values, for Java.

Some values should not simply become text: personal and regulated data, credentials, untrusted input from outside. Once such a value is a String in your application, nothing can tell you where it went — a log line, an event, a prompt.

Occlude takes custody of the value and hands back an occluded reference. It travels anywhere, because holding one is not permission to read it. Turning it back into a value is the one checked operation, and it always names where the value is going.

Occluded<Mail> mail = customerMail.occlude(incoming);   // the real thing stays here

vendorLlm.reveal(mail);        // Denied  — above that sink's ceiling
quarantinedLlm.reveal(mail);   // Allowed

Built on Denning's lattice model and on the object-capability model: authority is held, never looked up. There is no registry and no charter.get("customer-mail"). Code can perform an operation because something handed it the portal that performs it — so "what can this class do?" is answered by reading its constructor parameters.

Install

<dependency>
  <groupId>org.jwcarman.occlude</groupId>
  <artifactId>occlude-spring-boot-starter</artifactId>
  <version>0.2.0</version>
</dependency>

That is the Spring Boot path; add a Postgres driver beside it. Plain Java, the BOM, and trying it in memory are in Getting Started. Occlude's encryption and serialisation come from codec, a small library it depends on.

In one page

An application declares axes — the questions it asks about every value, such as a tenant, a sensitivity, whether it was vouched for — and every value carries a label answering them. Every place a value may go declares a ceiling, and reading is decided against both. Deriving a value joins its parents' labels, so an ordinary derivation cannot weaken one, and a value made from two tenants' data carries a mixture no ceiling admits.

DefaultCharter charter = new DefaultCharter(Axes.of(TENANT, SENSITIVITY));

Occlude<Mail> customerMail = charter.source("customer-mail", MAIL,
    ctx -> Label.of(TENANT, ctx.get("tenant").orElseThrow()).with(SENSITIVITY, PERSONAL));
Reveal<Mail> supportDesk = charter.reveal("support-desk",
    ctx -> Ceiling.of(TENANT, Constraint.atMost(ctx.get("tenant").orElseThrow()))
                  .with(SENSITIVITY, Constraint.atMost(PERSONAL)), MAIL);

charter.bind(Bindings.of(storage).withIdentity(currentAccess));

A charter is where authority is declared, and each declaration hands back the one object able to perform it — a portal. Holding the portal is the only way to perform the operation; nothing can look one up. Every operation writes a line to a tamper-evident record, allowed and refused alike. Storage is Postgres, and everything it keeps is encrypted and signed.

module what it is
occlude-api the portals and results application code holds
occlude-core the charter, labels and ceilings, and MemoryStorage for tests
occlude-jdbc encrypted, signed storage in Postgres 13+
occlude-spring-boot-starter Spring Boot wiring, with the JDBC store
occlude-bom versions for all of the above

Read the docs

The documentation site is the manual:

Building

./mvnw clean verify

Java 25. The JDBC tests need Docker, for Testcontainers.