Skip to content

Circuit-Stitch/Janitor

Repository files navigation

Janitor

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

An ephemeral desktop client onto AWS Secrets Manager. 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: core + GUI + guided Identity Center sign-in + the GUI↔AWS bridge landed — the matrix reads real AWS (mock behind JANITOR_MOCK=1); no write path yet (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

How the matrix is designed to read — it isn't built yet (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 security-critical core, a GUI tracer-bullet, and a headless Identity Center auth slice all exist and are tested. The GUI still runs on mock data, and no write path or live-wired data flow exists yet.

Area State
Secret-shape model — parse a Secret Set into comparable Entries; lossless flatten / unflatten to dotted-path Names ✅ Implemented & tested
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
janitor-gui (Slint matrix view) — masked cells, per-cell reveal, settings ✅ Tracer-bullet on a mock SecretSourceADR 0003
Identity Center Sign-in + per-Environment Credentials + Secrets Manager I/O ✅ Headless slice in janitor-aws (logic tested vs. fakes; browser/SDK shell untested by design) — ADR 0002 / ADR 0010. Live verification (Milestone B) pending
Guided sign-in — browser → log in → auto-discovered account / role / secret, org + last pick remembered live-verify binary in janitor-aws (ListAccounts/Roles/Secrets + tested select::resolve; stdin/SDK shell untested) — ADR 0011. Live verification (Milestone B) pending
janitor-aws ↔ GUI wiring (real data in the matrix) ✅ Worker-threaded bridge + lazy sign-in; secrets stay in the worker; reveal round-trips; JANITOR_MOCK=1 runs offline — ADR 0012 (live browser path human-gated)
Non-stomping write engine 📋 Designed — ADR 0001, not built

The workspace is four crates — janitor-core (offline, ≥80% coverage gate), janitor-gui (Slint), janitor-aws (async AWS adapter, ≥80% gate on its library surface), and janitor-mock (the offline Provider — canned demo data, ≥80% gate; ADR 0019). cargo test --workspace runs them all; the ≥80% coverage gates cover core, aws, and mock, where correctness is proven (ADR 0010 §5, ADR 0016).

Build & test

Standard Cargo across a four-crate workspace (janitor-core, janitor-gui, janitor-aws, janitor-mock).

Linux system dependencies

janitor-gui uses Slint, whose Linux backend links against a few system libraries (fontconfig, freetype, libxkbcommon) via pkg-config. Without their development packages the build fails in yeslogic-fontconfig-sys with "Package fontconfig was not found in the pkg-config search path." Install them before building:

# Fedora / RHEL
sudo dnf install -y fontconfig-devel freetype-devel libxkbcommon-devel

# Debian / Ubuntu
sudo apt install -y libfontconfig-dev libfreetype-dev libxkbcommon-dev

If a later *-sys crate still fails, you may also need the Wayland / X11 / GL dev packages — on Fedora: wayland-devel libxkbcommon-x11-devel mesa-libGL-devel mesa-libEGL-devel. macOS and Windows need no extra packages.

cargo build                          # build the workspace
cargo test --workspace               # all crates (core + gui + janitor-aws fakes)
cargo test -p janitor-core <name>    # a single core test (substring match)
cargo clippy --all-targets           # lint
cargo fmt                            # format

# Coverage (≥80% gate on janitor-core). Needs the cargo-llvm-cov subcommand:
#   cargo install cargo-llvm-cov
cargo llvm-cov -p janitor-core

cargo run -p janitor-gui             # real AWS via the worker bridge (browser sign-in; needs a configured org)
JANITOR_MOCK=1 cargo run -p janitor-gui          # offline mock (bash); PowerShell: $env:JANITOR_MOCK=1; cargo run -p janitor-gui

# janitor-aws human-gated binaries (need a browser + a real Identity Center org):
# First run? docs/iam_setup.md sets up the Identity Center org + permission set.
cargo run -p janitor-aws --bin loopback-spike   # browser↔loopback shell, no AWS
cargo run -p janitor-aws --bin live-verify      # guided sign-in: log in, then pick (ADR 0011)

Architecture

Two crates, split along a trust boundary (ADR 0003):

  • janitor-core (trusted) — all the security-critical logic, with no GUI dependencies: the secret-shape model, zeroizing in-memory types, Config, and — in future slices — Identity Center auth, Secrets Manager I/O, the comparison engine, and the non-stomping write engine. AWS access will sit behind a client trait so the network stays mockable and the coverage gate stays reachable. This is where correctness is proven.
  • janitor-gui (softer-trust, not yet built) — a thin Slint view: the masked comparison matrix, momentary per-cell reveal, confirm-diff dialogs, and browser launch for Sign-in. 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/iam_setup.md — set up an IAM Identity Center org and permission set to run the live live-verify harness (Milestone B).
  • Architecture Decision Records in docs/adr/:
    • 0001 — Non-stomping writes via staged PutSecretValue + atomic stage CAS
    • 0002 — Identity-Center-only, memory-only authentication
    • 0003 — Core/GUI split, Slint for the view, and the secret-display stance
    • 0004 — Read-only v1 scope, and how non-flat secret shapes are handled
    • 0005 — Clipboard handling and the matrix read model
    • 0006 — Version history and restore as a first-class feature
    • 0007 — CI and distribution: cargo-packager bundles, signed on macOS and Windows
    • 0008 — Secret-shape flattening: leaf-type-preserving dotted paths with escaped dots
    • 0009 — Comparison engine result model (Aligned / Drift / Gap)
    • 0010janitor-aws adapter crate and the Identity Center auth object model
    • 0011 — Guided sign-in: issuer-scoped registration, post-sign-in discovery, remembered picks
    • 0012 — GUI↔AWS bridge: worker thread, a tested Session, and lazy sign-in
  • 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

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors