Skip to content

Repository files navigation

Janitor

CI core coverage aws coverage aws-auth coverage mock coverage ssm coverage

An ephemeral desktop client onto your AWS secrets — Secrets Manager Sets and remote .env files reached over SSM. It stores no secrets and no credentials of its own — it borrows them on demand and forgets them. The name is the thesis: the janitor holds the most keys, yet keeps none.

License: GPL-3.0-only · Status: v0.1.4 released (Linux · macOS · Windows MSIX with auto-update). The masked drift matrix reads real AWS — Secrets Manager Sets and remote .env files over SSM (offline mock behind JANITOR_MOCK=1). Both write engines are built and tested but the app ships read-only by default, with the write paths reachable only via human-gated live-verify binaries (details below) · CI: lint · test · coverage


What it is

Janitor is a cross-platform desktop tool designed for two jobs that the AWS console makes awkward and risky:

  1. Drift detection — line up the same logical Secret Set across N Environments (prod / staging / dev — possibly different AWS accounts and regions) in one masked matrix, so missing or mismatched Entries jump out.
  2. Safe mutation — change a few Entries without ever risking an accidental overwrite of the whole Set.

By design it is an ephemeral client: Values and Credentials are kept in memory only and zeroized after use; the only thing written to disk is non-secret Configwhere Secret Sets live, never a Value. The domain vocabulary (Secret Set, Entry, Value, Environment, Application) is defined in CONTEXT.md.

Why it exists

The dangerous operation in AWS Secrets Manager is the everyday one. A Secret Set's value is a single JSON blob, so "change one Entry" easily becomes a PutSecretValue of a whole in-memory blob that silently drops a teammate's concurrent edit. Janitor's reason to exist is to make that structurally impossible — every write is designed to go through an op-based, replay-on-fresh-fetch, atomic compare-and-swap engine (ADR 0001), never a naive overwrite. The drift matrix is the other half: see the holes — the Gap finding — before they page someone.

What drift looks like

This is how the matrix reads in the running GUI (see Status).

Janitor compares Values masked: it shows presence, Value length, and equality grouping (by hash) without revealing plaintext. Each Entry lands in exactly one state:

Entry                     prod          staging       dev
─────────────────────     ─────────     ─────────     ─────────
SENTRY_DSN                ••• 61 #a     ••• 61 #a     ••• 61 #a     ✓ Aligned
POSTHOG_API_KEY           ••• 47 #b     ••• 41 #c     ••• 47 #d     ~ Drift
ZITADEL_CLIENT_SECRET     ••• 36 #e     ••• 36 #e     —             ! Gap
  • Aligned — present everywhere with identical Values (same hash group). The healthy, boring case.
  • Drift — present everywhere, but Values differ. Sometimes intended (a per-Environment DATABASE_URL), sometimes a bug.
  • Gap — present in some Environments, missing in others. The highest-signal finding — usually a Terraform / compose hole.

••• is the masked Value (plaintext is shown only on an explicit, momentary per-cell reveal), the number is its length, #x is the hash-equality group (same letter ⇒ identical Value), and means the Entry is absent. Value length is a deliberate, accepted side-channel — see the threat model.

Status

The GUI is live: it signs in to IAM Identity Center in a browser, runs guided Discovery, and renders the masked drift matrix from real AWS — across two Providers (Secrets Manager Sets and remote .env files over SSM) and across regions. Both write engines are built and tested behind fakes + replay, but the shipped app stays read-only; the write paths are reachable only via human-gated live-verify-*-write binaries while live verification finishes.

Area State
Secret-shape model — comparable Entries + lossless flatten / unflatten ✅ Implemented & tested — ADR 0008
Zeroizing secret types — Value kept out of Debug / Display / logs ✅ Implemented & tested
Config load / save — atomic TOML write, locations only ✅ Implemented & tested
Comparison matrix (Aligned / Drift / Gap) + masked read model ✅ Implemented & tested — ADR 0009 / 0014
janitor-gui — masked matrix, per-cell reveal, guided Discovery wizard, Manage window, region picker, in-app diagnostic log ✅ Live on real AWS (JANITOR_MOCK=1 for offline mock) — ADR 0003 / 0013 / 0015 / 0017
Identity Center sign-in + per-Environment Credentials + GUI↔AWS worker bridge ✅ Implemented & tested (logic vs. fakes; browser/SDK shell untested by design) — ADR 0002 / 0010 / 0012
Guided sign-in + Discovery — auto-discovered account / role / secret, remembered picks ✅ Implemented & tested — ADR 0011 / 0026
Secrets Manager Provider (read) ✅ Live in the matrix
Remote .env over SSM Provider (read) — pure-Rust MGS data channel, no session-manager-plugin ✅ Live-verified 2026-06-07 — ADR 0025
Non-stomping Secrets Manager write — staged-put + atomic CAS ⚙️ Built & tested behind fakes/replay; read-only, reachable via live-verify-sm-writeADR 0001
Remote .env over SSM write — non-stomping, hash-guarded ⚙️ Built & tested; read-only, reachable via live-verify-ssm-writeADR 0029
Read-write lock — writes unreachable until deliberately unlocked ✅ Worker-enforced invariant — ADR 0032
Packaging + releases — Linux deb/rpm/AppImage, macOS dmg, Windows MSIX auto-update ✅ v0.1.4 — ADR 0007 / 0022 / 0034

The workspace is six crates: janitor-core (offline bedrock — model, compare, Config, the Provider port, the Discovery orchestrator), janitor-gui (Slint), janitor-aws-auth (shared Identity Center auth base; ADR 0024), janitor-aws (Secrets Manager Provider), janitor-ssm (remote .env over SSM Provider; ADR 0025), and janitor-mock (offline canned-data Provider; ADR 0019). cargo test --workspace runs them all; ≥80% coverage gates cover the non-GUI crates, where correctness is proven (ADR 0010 §5, ADR 0016) — the browser / SDK / socket shells stay untested by design.

Install

Prebuilt bundles ship on the Releases page:

  • Linux.deb, .rpm, or .AppImage
  • macOS.dmg (Apple Silicon)
  • Windows.msix, installed via App Installer with auto-update (ADR 0034)

The app ships read-only: it reads and compares secrets but makes no mutating AWS calls. You bring your own IAM Identity Center org — see docs/iam_setup.md.

Build & test

Standard Cargo across the six-crate workspace. Linux needs a few Slint system dependencies first; full commands (build, test, coverage, the GUI, and the human-gated live-verify binaries) live in docs/building.md.

Architecture

Crates split along a trust boundary (ADR 0003). The security-critical logic lives in core and the Provider crates behind a Provider port (ADR 0019); the GUI is a thin, softer-trust view:

  • janitor-core (trusted) — no GUI deps: the secret-shape model, zeroizing in-memory types, Config, the comparison engine, the write-seam types, the provider-agnostic Discovery orchestrator (ADR 0026), and the Provider port every backend implements. This is where correctness is proven.
  • janitor-aws-auth / janitor-aws / janitor-ssm / janitor-mock (trusted) — the Providers: a shared Identity Center auth base, the Secrets Manager backend, the remote-.env-over-SSM backend, and the offline mock. Network / SDK / socket I/O sits behind seams so the logic stays mockable and the coverage gates stay reachable.
  • janitor-gui (softer-trust) — a thin Slint view: the masked comparison matrix, momentary per-cell reveal, the Discovery wizard, the Manage window, and an in-app diagnostic log. No auth / AWS / compare / write logic lives here.

Non-negotiable invariants

These are the spine of the project; the threat model explains what each one defends against.

  • Nothing secret touches disk — no Values, no Credentials, no SSO-token cache. Config (locations only) is the only thing persisted. Secret material lives in zeroizing types and stays out of Debug / Display / logs / errors.
  • Never stomp a Secret Set — all writes go through the op-based, replay-on-fresh, atomic compare-and-swap engine (ADR 0001).
  • Read-only by default — mutating AWS calls are unreachable until the user deliberately switches into a lockable read-write mode; v1 ships read-only (ADR 0004).
  • Memory-only auth — IAM Identity Center Sign-in each launch; no static keys; role Credentials refreshed silently from the SSO token (ADR 0002).

Docs & decisions

This README is only the front door — the depth lives here:

  • CONTEXT.md — the domain glossary (Secret Set, Entry, Value, Environment, Application, the Aligned / Drift / Gap states). Read this first.
  • docs/THREAT-MODEL.md — what Janitor defends against, the explicit non-goals, and the trust boundaries.
  • docs/iam_setup.md — set up an IAM Identity Center org and permission set to run the live live-verify harness (Milestone B).
  • docs/building.md — build, test, coverage, and the human-gated live-verify binaries.
  • Architecture Decision Records — every hard-to-reverse choice, indexed in docs/adr/README.md.
  • CLAUDE.md — working agreements and invariants for contributors (and AI assistants).

New hard-to-reverse decisions get an ADR; new domain terms go in CONTEXT.md. See CLAUDE.md for the conventions.

License

GPL-3.0-only. The GUI builds on Slint under its GPL terms, so the project is GPL throughout (ADR 0003).

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages