diff --git a/CLAUDE.md b/CLAUDE.md index b0497e6..bdee705 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,9 +3,27 @@ **incredigo** is a local-first, encrypted, RAM-only credential custody tool (Go). The folder is still named `credrot/`; the module/binary are `incredigo`. -> Read this first, then [`DESIGN.md`](DESIGN.md) (architecture + threat model) and — -> if present locally — `docs/ROTATION.md` (rotation design; **gitignored**, shared -> individually, not on the upstream repo). +> Read this first, then [`VISION.md`](VISION.md) (who it's for + the mission), +> [`DESIGN.md`](DESIGN.md) (architecture + threat model), [`docs/MARKET.md`](docs/MARKET.md) +> (competitive landscape + positioning) and — if present locally — `docs/ROTATION.md` +> (rotation design; **gitignored**, shared individually, not on the upstream repo). + +## Vision — catch vibe-coding security disasters before they happen + +The primary user is the **vibe coder**: the fast-moving AI-assisted builder (OpenClaw / Hermes / +Claude-Code / Cursor) who ships in a weekend and accumulates dozens of credentials — +`.env` keys, `sk_live`, `DATABASE_URL`, GitHub PATs, AWS keys, Supabase `service_role` — each +**generated once, pasted in, and never rotated**. incredigo finds that sprawl on the machine, +custodies it in RAM, backs it up, **rotates what's scriptable**, and **guides the human through +the rest** — before a forgotten key becomes a breach. **Secondary user:** the non-technical +password reuser (weak/reused passwords saved in the browser) — same engine, friendlier face, via +the browser worklist + change-URL links. + +Tailor every feature to those two. **Do NOT build toward enterprise PAM / machine-identity-at- +scale / compliance-cert / SaaS-hub** territory — that's the incumbents' moat. The target +credential surface (the driver + scanner roadmap) is the **20-credential list in `VISION.md`**. +Full crystallized vision in [`VISION.md`](VISION.md); competitive rationale in +[`docs/MARKET.md`](docs/MARKET.md). ## North-star goal @@ -104,5 +122,6 @@ on top (do not put an LLM in the deterministic destructive hot path). - Commits: end messages with the `Co-Authored-By: Claude …` trailer. Push only when asked. Remote is **gitea only, never GitHub** (`https://100.117.177.50:3030/trill-technician/incredigo`). -- Design docs (`docs/ROTATION.md`) are kept local/gitignored by request; `DESIGN.md`, - `README.md`, `docs/SECURITY.md`, `docs/ADDING_A_SCANNER.md` are tracked. +- Design docs (`docs/ROTATION.md`) are kept local/gitignored by request; `VISION.md`, + `DESIGN.md`, `README.md`, `docs/MARKET.md`, `docs/SECURITY.md`, `docs/ADDING_A_SCANNER.md` + are tracked. diff --git a/VISION.md b/VISION.md new file mode 100644 index 0000000..66c256e --- /dev/null +++ b/VISION.md @@ -0,0 +1,143 @@ +# incredigo — Vision + +## Catch vibe-coding security disasters before they happen. + +You build an app in a weekend with Claude, OpenClaw, Hermes, Cursor. By Sunday night you've +accumulated three dozen credentials — an Anthropic key, a Stripe `sk_live`, a `DATABASE_URL`, a +GitHub PAT, an AWS access key, a Supabase `service_role` — each **generated once, pasted into a +`.env`, and forgotten.** Maybe it got committed. Maybe it's in your shell history. Maybe it's in +eight places. You'll "deal with security later." + +**incredigo is the safety net for later-that-never-comes.** It finds every credential sprawled +across your machine, locks them in a RAM-only vault, takes a verified backup, **rotates the ones +a script can rotate**, and hands you a **guided, ranked checklist** for the ones that need a human +— all local-first: no cloud, no server, no SaaS, one binary. The forgotten `sk_live` gets rotated +*before* it becomes a breach disclosure. + +> **One line:** *The local-first credential rotator that saves fast-moving AI-assisted builders +> from the security debt they're accumulating in real time.* + +--- + +## The problem + +The "vibe coder" — the AI-assisted builder who ships fast and worries about security after the +fact — is the fastest-growing developer cohort, and the one accruing credential risk fastest: + +- **Secrets sprawl is exploding.** GitGuardian's *State of Secrets Sprawl 2026*: **29M new + hardcoded secrets in 2025, +34% YoY**, with each live secret appearing in **~8 locations on + the same machine** (`.env`, shell history, IDE configs, cached tokens, build artifacts). +- **Generate-once, rotate-never.** AI codegen mints keys on demand and pastes them inline. They + are rarely scoped, rarely rotated, often duplicated, and frequently committed. +- **No tool serves the cleanup.** Enterprise PAM/secrets platforms (CyberArk, Vault, Doppler) + rotate *what already lives in their hub*; they don't go discover the mess on your laptop. The + one consumer attempt at automating the long tail (Dashlane) gave up as "too brittle." + +That gap — **discover the sprawl on this machine, then rotate it, self-custody, no cloud** — is +incredigo's reason to exist. (Full competitive analysis: [`docs/MARKET.md`](docs/MARKET.md).) + +--- + +## Who this is for + +**Primary — the security-literate-enough vibe coder.** OpenClaw / Hermes / Claude-Code / Cursor +builders who move fast and accumulate credentials across `.env`, `~/.aws`, `~/.netrc`, `~/.ssh`, +`~/.docker`, `~/.kube`, `docker-compose.yml`, plus a gopass store. They distrust (or can't legally +use) a SaaS secret hub, live on the CLI, and want **headless rotation in CI *and* an interactive +TUI**. Job-to-be-done: *"Find every credential I have, back them up, rotate what's automatable, +and give me a clean checklist for the rest — without anything leaving my machine."* + +**Secondary — the non-technical password reuser.** People who never change their passwords, reuse +weak ones, and let the browser remember everything. The *same engine* (discover → back up → +rotate / guide), with a friendlier face: point it at the browser's saved-login store, and it +produces a ranked, deduplicated worklist with a direct **change-password link** per site — never a +plaintext password dump, never bypassing MFA. The bridge from "developer tool" to "anyone with a +password problem." + +--- + +## The 20 credentials a vibe coder accumulates + +The target surface. Each maps to how incredigo handles it: **[DB]** in-place database rotation +driver · **[API]** provider-API rotation driver · **[LOCAL]** self-generated secret incredigo can +regenerate + propagate · **[GUIDE]** no rotation API → guided worklist + change-URL (human in the +loop, never bypassing MFA/CAPTCHA). + +| # | Credential | Where it lives | Why it bites vibe coders | Handling | +|---|---|---|---|---| +| 1 | **LLM API keys** (Anthropic, OpenAI, Gemini, Groq, OpenRouter, Mistral, HuggingFace) | `.env`, shell rc, `~/.config` | The defining vibe-coder key; minted constantly, pasted inline, billed by usage | GUIDE → API | +| 2 | **AI infra keys** (Pinecone/Qdrant/Weaviate, Replicate/Fal/ElevenLabs/Stability) | `.env` | Spun up per experiment, never cleaned up | GUIDE | +| 3 | **MCP / agent-gateway tokens** (OpenClaw/Hermes/Claude MCP server configs) | `~/.claude.json`, MCP config files | Grant broad tool/host access; rarely scoped or rotated | GUIDE / LOCAL | +| 4 | **AWS access keys** | `~/.aws/credentials`, `.env` | Long-lived, over-privileged, leak to GitHub constantly | **API (IAM)** | +| 5 | **GCP service-account JSON** | `~/.config/gcloud`, `.env` | Whole-key files copied around | API | +| 6 | **Cloudflare API token / global key** | `.env`, `~/.cloudflared` | Global key = account-wide; pasted into scripts | GUIDE / API | +| 7 | **Deploy-platform tokens** (Vercel, Netlify, Railway, Render, Fly.io) | `.env`, `~/.vercel` | One token = full deploy control | GUIDE / API | +| 8 | **Postgres DSN** | `.env` `DATABASE_URL`, `docker-compose.yml` | Default/weak passwords, reused across envs | **DB ✅** | +| 9 | **MySQL / MariaDB DSN** | same | same | DB | +| 10 | **Redis URL / password** | `.env`, compose | Often no password at all | DB | +| 11 | **Managed-DB keys** (Supabase `service_role`, Neon, PlanetScale, Mongo Atlas) | `.env` | `service_role` bypasses row-level security — catastrophic if leaked | GUIDE / API | +| 12 | **Git platform PATs** (GitHub, GitLab, Gitea, Bitbucket) | `~/.netrc`, `~/.config/gh`, git credential store | Broad-scope `repo` tokens; rarely expire | **API** | +| 13 | **Package-registry tokens** (npm `~/.npmrc`, PyPI, crates.io) | home configs | Publish rights → supply-chain risk | GUIDE | +| 14 | **Container-registry creds** (Docker Hub, GHCR) | `~/.docker/config.json` | Base64 "auth" mistaken for encryption | GUIDE | +| 15 | **CI/CD secrets** (GitHub Actions secrets, workflow env) | repo settings, `.github/workflows` | 59% of leaked-secret machines are CI runners | API / GUIDE | +| 16 | **SSH private keys / deploy keys** | `~/.ssh/id_*` | Unencrypted keys, shared deploy keys, never rotated | **driver: regen + `authorized_keys`** | +| 17 | **Kubeconfig tokens / client certs** | `~/.kube/config` | Cluster-admin creds in a dotfile | GUIDE | +| 18 | **Payment / auth / messaging keys** (Stripe `sk_live`, Clerk/Auth0/Firebase, Twilio, SendGrid/Resend, Slack/Discord, webhook signing secrets) | `.env` | Money + identity + spam blast radius | GUIDE / API | +| 19 | **App signing / session secrets** (Django `SECRET_KEY`, NextAuth secret, Rails `master.key`, JWT secrets) | `.env`, config | Self-generated randoms — easy to rotate, easy to forget | **LOCAL: regenerate + propagate** | +| 20 | **Browser-saved passwords + manager exports** | Chrome/Firefox login DB, CSV | Reused, weak, never changed (the secondary market) | **GUIDE: worklist + change-URL** | + +This list is the **driver-ladder roadmap** and the **scanner roadmap** at once: every `[DB]`/`[API]`/ +`[LOCAL]` row is a future one-file `Rotator`; every row is a discovery surface. + +### Secondary-persona extension: network credentials (VPN + router) + +The 20 above are the **primary (vibe-coder)** surface and remain the centre of gravity. Two +adjacent credential classes serve the **secondary persona** ("anyone with a password problem") +and are deliberately added — they reuse the same safe spine, not a new product: + +- **VPN keys/credentials.** *Self-hosted WireGuard* rotates exactly like SSH (`[LOCAL]`: + regenerate the keypair in RAM, propagate the new public key to the peer, verify the handshake, + drop the old). *Mullvad* is the one mainstream consumer VPN with a real device-key rotation API + (`[API]`, account-number auth). Commercial account passwords (Nord/Express/Proton) have no + rotation API → `[GUIDE]`. +- **Router admin password.** *OpenWrt* (and other SSH/`ubus`-exposing prosumer firmware) is + programmatically rotatable (`[API/LOCAL]` via `uci`/`ubus`). Generic consumer routers + (TP-Link/Netgear/Asus web-UI) have no stable API → `[GUIDE]` / browser long-tail. + +These stay within the non-goals below (self-owned only, never an attack tool, never bypass +MFA/CAPTCHA); they do **not** pull incredigo toward enterprise network/PAM management. + +--- + +## How incredigo answers it + +The same safe spine for every credential, automatable or not: + +1. **Discover** — scan the machine's credential surface (`.env`, `~/.aws`, `~/.netrc`, `~/.ssh`, + `~/.docker`, `~/.kube`, git, `--path`, browser export). +2. **Custody** — load secrets into a RAM-only memguard vault (mlock/DONTDUMP); plaintext never + hits disk. +3. **Backup (mandatory)** — a sealed, **verified** snapshot before anything changes. No backup, + no rotation. Non-negotiable. +4. **Rotate** — drivers change the automatable ones in place (verify-new-before-revoke-old), and + close the blast radius by guiding consumer updates (`.env`, CI vars, k8s). +5. **Guide** — for the no-API long tail, emit a ranked, deduplicated worklist with per-site + change-password links; the human acts, MFA/CAPTCHA are never bypassed. + +Headless for CI (`$INCREDIGO_PASSPHRASE`, no TTY) or interactive via the TUI. The PGP passphrase +is the single root of trust — back up the key, use a strong passphrase. + +--- + +## Non-goals + +- **Not enterprise PAM.** No fight with CyberArk/Vault/Delinea over machine-identity-at-scale, + compliance certifications, or a managed cloud service. (See `docs/MARKET.md`.) +- **Not a SaaS secret hub.** No server, no daemon, no telemetry, nothing leaves the machine. +- **Not an attack tool.** Self-owned accounts only, with the owner's authorization. Never resembles + credential stuffing or account takeover; never bypasses MFA/CAPTCHA — it hands off to the human. +- **Not "auto-change everything."** Fully-silent browser rotation is a known tar pit (Dashlane). + incredigo rotates what's scriptable and *guides* the rest. + +See [`DESIGN.md`](DESIGN.md) for architecture + threat model and [`docs/MARKET.md`](docs/MARKET.md) +for the competitive landscape. diff --git a/docs/FINDINGS-2026-06-16.md b/docs/FINDINGS-2026-06-16.md new file mode 100644 index 0000000..9d8d386 --- /dev/null +++ b/docs/FINDINGS-2026-06-16.md @@ -0,0 +1,280 @@ +# Findings — controlled-environment test run (2026-06-16) + +Source: `~/incredigo-lab-stage/lab-harness.sh` (fresh isolated gopass store + fake, +canary-tagged inputs for all 8 scanners). FAKE creds only; never touches a real store. + +## Live rotation POC — first real driver (postgres), 2026-06-16 + +**Result: real end-to-end cutover proven** in the `incredigo-sbx` Multipass VM (real +gopasspw/gopass 1.15.16, real PostgreSQL 16, isolated `GOPASS_HOMEDIR`/`GNUPGHOME`, +FAKE `labapp@labdb` role). + +Flow exercised by the shipped binary via `incredigo rotate --execute` +(gated: `INCREDIGO_ALLOW_EXECUTE=1` + `--execute`): + +1. **Backup gate** sealed + verified 1 entry → `~/.incredigo/rotation-backups/.age` before any change (Hard Rule #1). +2. **Rotate** ran `ALTER USER labapp WITH PASSWORD '<48-hex>'` over the OLD connection. +3. **Verify(new)** → `SELECT 1` with the new secret passed. +4. **Store** the rebuilt DSN back into gopass at the same entry; **re-read + Verify(stored)** passed. +5. **RevokeOld** = no-op (in-place ALTER is itself the cutover). + +Cutover assertions (all passed): +- OLD password (`oldpw835`) **rejected** after rotation — `FATAL: password authentication failed`. +- NEW 24-byte hex password (read back from gopass) **authenticates**. +- Audit log (`rotate-execute`) contains **no password substring** (old or new). + +Spine: `internal/rotate/execute.go` (`Execute`), driver `internal/rotate/postgres.go` +(self-registers via `init`), sourcing `cmd/incredigo` `gopassCredsForExecute` +(Mode A — reconstructs `Source` from the gopass path segment), persistence +`sink.Gopass.Show`/`InsertAt`. Unit proof of the same cutover (no live DB): +`internal/rotate/postgres_test.go:TestPostgresRotateRealCutover`. Full suite: 45 green. + +## Live rotation POC — gitea PAT driver (provider-API pattern), 2026-06-17 + +**Result: real create-new → verify → revoke-old cutover proven** against a real +Gitea 1.25.0 (sqlite, http on loopback) inside the `incredigo-sbx` VM, isolated +gopass store, self-owned `labadmin` account. This is the **first provider-API +driver** and the first whose `RevokeOld` is a real destructive API call. + +Provision: `~/incredigo-lab-stage/lab-provision-gitea.sh` (stands up Gitea, mints a +seed token via basic auth, seeds the driver-ready blob into gopass). Flow exercised +by the shipped binary via `incredigo rotate --execute` (gated): + +1. **Backup gate** sealed + verified 1 entry before any change (Hard Rule #1). +2. **Rotate** `POST /api/v1/users/labadmin/tokens` (basic auth) → new token. +3. **Verify(new)** `GET /api/v1/user` with the new token → 200, `login=labadmin`. +4. **Store** the rebuilt blob back into gopass; **re-read + Verify(stored)** passed. +5. **RevokeOld** `DELETE …/tokens/` — a real token deletion. + +Cutover assertions (all passed): +- OLD token → `GET /user` returns **401** after rotation (revoked). +- NEW token (read back from gopass) → **200**, `login=labadmin`. +- Gitea token list now shows only `incredigo-rotated-`; the seed token is gone. +- Audit log (`rotate-execute`) contains **no token substring** (old or new); old ≠ new. + +Spine: `internal/rotate/gitea.go` (single-line `https://user:token@host/?name=&pw=` +blob so it round-trips the existing single-line gopass sink; `authManage` prefers +basic auth when a mgmt password is present, else token auth). Discovery for the +gitea PAT type: `internal/discover/tea.go` (Gitea `tea` CLI config → driver-ready +blob, Source `gitea`). Unit proof of the same enforced cutover (httptest Gitea +emulator that 401s a revoked token): `internal/rotate/gitea_test.go`. + +## SSH key driver (unit-proven cutover), 2026-06-17 + +`internal/rotate/sshkey.go` mints a new ed25519 keypair **entirely in memory** +(golang.org/x/crypto/ssh; private key never touches disk — Hard Rule #3), installs +only the new PUBLIC key into `authorized_keys`, verifies by SSH-dialing the +authority, and `RevokeOld` removes the old public key (atomic rewrite). Proven by an +**in-process SSH server** test: old key rejected after revoke, new key works, no +`PRIVATE KEY` material in `authorized_keys` (`internal/rotate/sshkey_test.go`). +Discovery broadened (`internal/discover/ssh.go`): content-based key detection (not +just `id_*`) + `~/.ssh/config` `IdentityFile` parsing. Live VM POC not yet run. + +Full suite after all three drivers: **50 green**, `-race` clean on +rotate/sink/vault/discover. + +## Live rotation POC — AWS IAM access key driver (cloud-key pattern), 2026-06-17 + +**Result: real create-new → verify → revoke-old cutover proven** against a +self-hosted **moto 5.2.2** mock AWS (`moto_server` on http://127.0.0.1:5000) inside +the `incredigo-sbx` VM, isolated gopass store, self-created IAM user `labapp`. This +is the cleanest provider-API driver: the OLD credential **self-identifies** — an +access key's `AccessKeyId` is non-secret and rides in the secret blob, so RevokeOld +deletes exactly the right key (no name-capture dance Gitea needed). + +Implementation note: the driver speaks the AWS **Query protocol** (form-POST +`Action=…&Version=…`) signed with **hand-rolled SigV4** (`crypto/hmac`) — zero new +go.mod deps, keeping the static binary lean (the AWS SDK v2 would have added ~50 +indirect deps). Spine: `internal/rotate/aws.go`. Secret blob is the single line +`aws://:@aws/?region=[&endpoint=]` so it +round-trips the single-line gopass sink; `endpoint=` overrides the API base for +moto/LocalStack, absent → real `iam/sts.amazonaws.com`. Discovery broadened: +`internal/discover/aws.go` now emits that driver-ready blob (was the bare secret) and +resolves region from env / `~/.aws/config`. + +Flow exercised by the shipped binary via `incredigo rotate --execute` (gated): + +1. **Backup gate** sealed + verified 1 entry before any change (Hard Rule #1). +2. **Rotate** IAM `CreateAccessKey` (no UserName → moto resolves the calling + identity from the signing key) → new key pair. +3. **Verify(new)** STS `GetCallerIdentity` with the new key → ARN returned. +4. **Store** the rebuilt blob into gopass; **re-read + Verify(stored)** passed. +5. **RevokeOld** IAM `DeleteAccessKey` targeting the OLD `AccessKeyId` — a real delete. + +Cutover assertions (all passed, `lab-verify-aws.sh`): +- After rotate, IAM `ListAccessKeys(labapp)` shows **only** the new key; the old + `AccessKeyId` is **gone** at the provider. old ≠ new. +- New key (read back from gopass) authenticates; audit log (`rotate-execute`) carries + **no AccessKeyId and no SecretAccessKey**. + +**moto enforcement caveat (investigated, important).** moto's STS +`GetCallerIdentity` does **not** validate access-key existence — a *deleted* key +still returns a (generic `user/moto`) ARN rather than a 403. So against moto, the +driver's STS-based Verify cannot itself prove "old key dead"; the live cutover proof +is therefore **IAM `ListAccessKeys`** (ground truth that the delete took effect), +asserted in `lab-verify-aws.sh`. The *enforced* 403-on-revoked-key path (what real +AWS does) is proven instead by the **unit test**: `internal/rotate/aws_test.go`'s +`awsEmu` reads the `AccessKeyId` from the SigV4 `Credential=` header and rejects any +key not currently present, so `TestAWSRotateRealCutover` asserts the old key returns +403 after revoke, the new key still authenticates, and old ≠ new. The driver's Verify +(plain "ARN non-empty") is correct for real AWS, which **does** 403 an invalid key; +no moto-specific leniency was baked into the driver. + +Provision: `~/incredigo-lab-stage/lab-provision-aws.sh` (starts moto, creates +`labapp` + seed key via boto3, seeds the driver-ready blob into isolated gopass); +verify: `~/incredigo-lab-stage/lab-verify-aws.sh`. Unit proofs: +`TestAWSRotateRealCutover` (enforced cutover), `TestAWSSecretRoundTrip` (blob carries +`/`+`=` secrets intact), `TestSigV4HeadersStable` (Authorization shape). + +Full suite after four drivers: **53 green**, `-race` clean on +rotate/sink/vault/discover. + +## VPN / router / DB-clone batch — 5 drivers, 3 live cutovers, 2026-06-18 + +Approved expansion (VPN + router secondary persona, plus Tier-1 DB clones). Five new +one-file drivers, each with a table-driven unit test (cutover proof + leak-check). Three +were additionally proven **live** in the `incredigo-sbx` VM against real services; one is +unit-proven with a live QEMU POC deferred; one is unit-only by design. + +| Driver | Pattern | Live POC | Proof | +|--------|---------|----------|-------| +| `mysql` | in-place DB password | **PASS** (real MariaDB) | `lab-provision-dbclones.sh` | +| `redis` | in-place `CONFIG SET requirepass` | **PASS** (real redis-server) | `lab-provision-dbclones.sh` | +| `wireguard` | local keypair regen + peer propagate | **PASS** (real `wg`) | `lab-provision-wg.sh` | +| `openwrt` | in-place SSH `passwd` | deferred (QEMU on 1-CPU VM) | unit: in-process SSH server | +| `mullvad` | provider-API device key | n/a (needs paid acct) | unit: httptest TLS emulator | + +**MySQL + Redis live cutover (`lab-provision-dbclones.sh`, all assertions PASS).** Real +`mariadb-server` + `redis-server`, isolated gopass, fake `labapp@labdb` and a fake redis +`requirepass`. Backup gate sealed+verified first; `rotate --execute` flipped both; the +OLD password is **rejected** and the NEW one (read back via `gopass show -o`) +**authenticates** for each engine. + +> **Driver gap found & fixed — MariaDB unprivileged self-rotation.** MariaDB rejects +> `ALTER USER CURRENT_USER() IDENTIFIED BY …` for a non-admin (ERROR 1227 — it demands the +> global `CREATE USER` privilege even for one's *own* account), which is exactly the +> target persona's situation (a vibe coder's DB user is scoped to one schema with +> `GRANT ALL ON app.*`). The MySQL-only `USER()` spelling also fails on MariaDB (ERROR +> 1064). Fix (`internal/rotate/mysql.go`): try a fallback chain — `ALTER USER +> CURRENT_USER()` (MySQL self-service) → `SET PASSWORD = PASSWORD('…')` (MariaDB / MySQL +> 5.7) → `SET PASSWORD = '…'` (MySQL 8 / MariaDB ≥10.4); first to succeed wins. After the +> fix the live POC passed on MariaDB. + +**WireGuard live cutover (`lab-provision-wg.sh`, all assertions PASS).** Real +`wireguard-tools`: `wg0` = ours, `wg1` = the peer that trusts us. Seeds `wg0`'s old +private key into isolated gopass, `rotate --execute` mints a new clamped curve25519 +keypair, applies the new private key to `wg0` (via stdin → `wg set wg0 private-key +/dev/stdin`, never argv), and re-points the peer to the new public key (carrying over +allowed-ips). Assertions: private key changed; peer trusts NEW pubkey; peer **dropped** +OLD pubkey; and the headline compatibility proof — **`wg0`'s live interface public key +equals the public key our Go code derived**, i.e. our in-process curve25519 derivation +matches real `wg pubkey`. + +> **POC scripting gotcha (Mode A prefix).** Mode A reconstructs the driver `Source` from +> the **first** path segment after `--prefix` (`imported//`). The WG POC +> first ran with `--prefix imported/wireguard/`, which made `Source="wg0"` (no driver +> Detected it → ROTATED 0). Fix: point `--prefix` at the `imported/` **root** so +> `imported/wireguard/wg0` resolves `Source="wireguard"`. This is a harness fix, not a +> driver bug, but worth recording: narrowing the prefix below the source dir breaks +> source recovery. + +**OpenWrt (unit-proven, live deferred).** `internal/rotate/openwrt.go` dials the router +with the OLD password and runs BusyBox `passwd`, feeding the new password twice on the +SSH-encrypted stdin (never argv); setting the password IS the cutover (RevokeOld no-op). +Proven by an **in-process SSH server** (`openwrt_test.go`) with a mutable current +password: old password stops authenticating after rotate, new works, no secret in argv or +error strings. A live OpenWrt-in-QEMU POC is the heaviest (full-system emulation on the +1-CPU sandbox VM) and is **deferred**. + +**Mullvad (unit-only by design).** `internal/rotate/mullvad.go` is the provider-API +device-key pattern: fetch an access token from the account number, `POST +/accounts/v1/devices {pubkey}` to register a freshly-derived WireGuard key, verify the +device lists that exact pubkey, then `DELETE` the old device. Proven against an httptest +**TLS** emulator (`mullvad_test.go`) that inspects every request body for the private key +(never sent) and 404s a deleted device. No live POC — that needs a real paid Mullvad +account; the API contract is faithfully emulated instead. + +**Discovery broadened (Hard-rule standing directive — dynamic discovery per type).** The +env scanner (`internal/discover/env.go`) now tags DB connection URLs by scheme: +`postgres`/`postgresql` → `postgres`, `mysql`/`mariadb` → `mysql`, `redis`/`rediss` → +`redis` (requires a `user:password` authority), so `DATABASE_URL`/`REDIS_URL`/`MYSQL_URL` +in a `.env` route straight to the matching in-place driver, kept regardless of the +secret-name heuristic. Regression: `scanners_test.go:TestEnvScanner`. + +Full suite after the batch: **68 green**, `-race` clean on rotate/sink/vault/discover. + +## Summary + +- Harness result: **31/31 PASS**, including the global secret-leak canary (no CANARY + token or `PRIVATE KEY` material reached any command output). +- One **real defect** found by manual triage of the backup gate, since fixed. + +## Defect 1 — backup gate silently under-covered dot-segment entries (FIXED) + +**Severity:** high — a silent violation of Hard Rule #1 (backup before rotate). + +**Symptom.** After `migrate`, the store held 10 imported credentials, but the rotate +dry-run backup gate sealed/verified only **7**. The 3 missing were the `.env`-derived +entries: `imported/env/.env/{api_token,database_url,sendgrid_api_key}`. + +**Root cause.** `internal/sink/gopass.go:slug()` lower-cased and space-collapsed the +credential Identity but **kept leading dots**. An env credential has +`Identity = ".env / API_TOKEN"`, so `StorePath` became +`imported/env/.env/api_token`. The `.env` path segment is dot-prefixed, and gopass +**hides dot-prefixed directories/leaves from `ls --flat`**. `bundle.ListPaths` (and the +backup gate that consumes it) enumerate via `ls --flat`, so those 3 entries were +invisible — never sealed, never verified. + +**Why it was silent.** The gate's integrity check compares *sealed == verified* counts. +Both were 7, so 7==7 passed. The gate had no notion of *expected* count, so +under-coverage produced no error. + +**Fix.** `slug()` now strips leading dots per `/`-separated path segment, so +`.env` → `env` (`imported/env/env/api_token`). Entries are now enumerable and the gate +covers all of them. Regression test: `internal/sink/bundle_test.go:TestStorePathNoDotSegment` +asserts no produced StorePath contains a dot-prefixed segment. Full suite: 42 tests +green, `-race` clean on `sink`/`rotate`. + +## Root cause of the *lapse* (why it stayed silent) and prevention + +The slug bug was the trigger, but it stayed silent because of a deeper flaw in the gate: +`rotate.Snapshot` asserts `verified == res.n`, and **both counts descend from the same +`gopass ls --flat` enumeration** (`ExportTo` → `ListPaths`, bundle.go). A blind spot in +that enumeration is inherited by both sides, so the comparison can never catch it. The +check proves *round-trip integrity* (the bundle re-reads to the same count it sealed), not +*coverage* (the bundle holds every credential in the store). **A safety gate that compares +two values derived from the same source cannot detect an error in that source.** + +Prevention, layered: + +1. **Source fix (done).** `slug()` strips leading dots → incredigo can no longer write any + path that `ls --flat` hides. `TestStorePathNoDotSegment` locks it in. This removes the + only trigger incredigo controls and is backend-agnostic. +2. **Independent coverage cross-check (done, harness).** `lab-harness.sh` T8b counts the + on-disk `*.gpg` files under `imported/` — ground truth that does **not** go through + `ls --flat` — and asserts the gate sealed exactly that many. This is where an + independent count is cheap and reliable (`GOPASS_HOMEDIR` is known/controlled). It would + have failed loudly on the original 7-vs-10. + +**Production gate — deliberately *not* changed.** Adding the same on-disk `.gpg` walk to +`rotate.Snapshot` would couple the safety-critical gate to gopass's fs-backend layout +(store-dir resolution varies by gopass version/mount and breaks for non-fs backends). That +trades one fragility for another and could make the gate *falsely* abort or pass. The +two-layer defense above (write-side invariant + harness cross-check) closes the class +without that coupling. If we later want an in-gate coverage assertion, the clean path is a +backend-agnostic enumeration primitive in `sink` (not an fs-layout assumption) — a separate +design task. + +## ICM evaluation (does the methodology help here?) + +**Recommendation: do not adopt ICM for the incredigo codebase now.** ICM +(`icm-scaffold` skill) structures an *LLM-orchestrated* workflow as numbered +markdown stages — "folders are the program, one agent reads the right file at the +right moment." incredigo is a deterministic **compiled Go tool** with a package +architecture, an interface/registry extension model, and a real test suite. ICM's +folders-as-program model does not map onto a binary, and the project directive +explicitly bans an LLM in the destructive hot path. Adopting ICM here would add +scaffolding with no control-flow benefit. The one place it *could* fit later is the +**AI-router / browser long-tail** rotation layer (ROTATION.md step 4), which is by +design a skill/MCP layer *on top* of the Go core — revisit ICM only when that layer +is built. diff --git a/docs/MARKET.md b/docs/MARKET.md new file mode 100644 index 0000000..a1ef8bd --- /dev/null +++ b/docs/MARKET.md @@ -0,0 +1,231 @@ +# incredigo — Market Analysis & Positioning (2026-06-16) + +Research into the credential/secret **rotation** market: who sells it, who buys it, where +the white space is, and who incredigo should be built for. Sourced web research (2025–2026); +treat market-size figures as analyst-dependent and the academic adoption numbers as +directional (see Caveats). + +--- + +## TL;DR + +- The **money** is in enterprise **PAM** (~$4.3–5.6B, ~22% CAGR) and **machine-identity** + rotation — and it is consolidating fast: **CyberArk → Palo Alto Networks (~$25B, Jul 2025)**, + **HashiCorp Vault → IBM ($6.4B, Feb 2025)**. That is not a fight a local-first CLI wins. +- **Three credible white-space wedges incredigo already targets:** + 1. **Local-file secret discovery + rotation** for solo devs / small teams (sprawl is + exploding: **+34% YoY**, secrets appear in **~8 places per machine**). Incumbents assume + you've *already* migrated into their hub — nobody owns "find the mess on this laptop, then + rotate it." → incredigo **Mode B**. + 2. **Local-first / RAM-only / no-cloud / no-server.** OpenBao/Infisical/Bitwarden prove the + no-cloud demand, but every one is a **server/daemon**. A **single RAM-only binary** is + genuinely differentiated. + 3. **The manual/browser "long tail"** of accounts with no rotation API. Every incumbent — + enterprise PAM *and* consumer password managers — explicitly refuses this. The one serious + consumer attempt (**Dashlane**) **publicly gave up** as "too brittle." → incredigo's + **guided worklist + change-URL** layer. +- **RFC 8615 `.well-known/change-password` is a thin primitive** (~12% top-site adoption, often + unhelpful redirects). It confirms "auto-change everything" is unrealistic and validates + incredigo's split: **rotate what's automatable, guide the human through the rest.** + +--- + +## 1. Vendors — who sells rotation, and to whom + +### Enterprise secrets platforms + +| Vendor | Rotation story | Pricing | Typical client | +|---|---|---|---| +| **HashiCorp Vault** (now **IBM**, $6.4B, closed Feb 27 2025) | Core = **dynamic short-lived secrets** + static rotation. Moved to **BSL** license (2023) → OpenBao fork. **HCP Vault Secrets SaaS sunset** (EOS Jun 30 2025, EOL Jul 1 2026). | Community Edition free (self-host); HCP Vault Dedicated ~$1.58/hr | Large enterprise, platform/DevOps | +| **CyberArk** (incl. **Conjur**) — **being acquired by Palo Alto Networks (~$25B, announced Jul 30 2025)** | PAM market leader; automated rotation + deep audit. Conjur = machine/DevOps secrets. | Conjur OSS free; enterprise ~$1,000–1,500 / identity / yr | Large/regulated enterprise | +| **Akeyless** | Vaultless SaaS, JIT access + automated rotation ("Distributed Fragments Cryptography") | Custom / contact sales | Mid-large enterprise (**78% of revenue from public corps**, 2 Fortune-5) | +| **Doppler** | Fully automated rotation, broad integrations (AWS/GCP/CI/KMS) | From **$3/user/mo** | Dev/DevOps teams, startup→midmarket | +| **Infisical** (OSS, MIT) | Rotation for Postgres/MySQL/AWS IAM; **flagged for limited retry/failure guidance** | Cloud from $8/user/mo; self-host free | Developers, OSS-leaning, self-host shops | +| **Phase** | Automated rotation + keeps deployments in sync; cloud or self-host | — | Dev/DevOps, compliance-driven | + +### Cloud-native (rotation = "you write the Lambda/Function") + +| Vendor | Rotation story | Pricing | +|---|---|---| +| **AWS Secrets Manager** | Native rotation for **RDS/Redshift/DocumentDB only**; others need custom Lambda. re:Invent 2025: "zero-touch rotation" for some 3rd-party secrets. | $0.40/secret/mo + $0.05/10k calls | +| **Azure Key Vault** | Microsoft-centric; FIPS/gov favored | $0.03/10k ops | +| **GCP Secret Manager** | Rotation = schedule → Pub/Sub → **Cloud Function you author** | $0.06/secret version/mo | + +### PAM specialists + +- **Delinea** — PAM + password rotation, **mid-market** (fast deploy, low TCO); 2024 Gartner MQ Leader. +- **BeyondTrust** — PAM + credential rotation, **enterprise**; Gartner MQ Leader ×6, 2025 Forrester Wave Leader (PIM). +- **Teleport** (w/ StrongDM, HashiCorp Boundary) — **certificate/ephemeral-access**, cloud-native/DevOps; ephemeral certs reduce the *need* to rotate long-lived secrets. + +### Password managers w/ rotation crossover + +- **1Password** — Business $7.99/user/mo; Secrets Automation via self-hosted Connect Server. +- **Bitwarden** — OSS, client-side crypto, self-hostable; Secrets Manager for devs; business from $4/user/mo; $100M Series B (2022). +- **Keeper** — KeeperPAM: automated rotation + session recording + discovery; business from $6/user/mo. + +**Pattern:** every vendor rotates **what has an API** (databases, cloud IAM, AD) and assumes +secrets are **already centralized in their store**. None of them owns *discovery of sprawl on a +local machine* or *the no-API long tail*. + +--- + +## 2. PAM market — size & leaders + +- **Size 2025→2026:** Mordor **$4.25B → $5.17B**; Fortune Business Insights **$4.51B → $5.58B**. +- **Growth:** Mordor → **$13.83B by 2031 (~21.7% CAGR)**; Precedence → up to ~$30B by 2034 (~23.8%). +- **Leaders:** CyberArk, BeyondTrust, Delinea, One Identity, ARCON, Wallix, ManageEngine, Okta. +- **Why rotation matters here:** automated rotation/vaulting is a **core PAM primitive**, now + driven by **machine identities outnumbering humans ~40:1**. + +**Implication for incredigo:** do not compete in PAM. Be the tool that serves the people PAM +is too heavy/expensive/cloud-bound to serve. + +--- + +## 3. Consumer auto-password-change — a graveyard + +- **Dashlane** removed its automatic Password Changer in **early 2022** — officially "an + extremely complex feature that was prone to breaking." (Also killed its free plan Sept 16 2025.) + This is the canonical cautionary tale. +- **Chrome / Google Password Manager** — announced **Automated Password Change** at I/O 2025; + navigates the site and fills the change form **with per-change user approval** (no silent + action). Rollout late 2025, **limited English-language cooperative sites only**. +- **Apple** — no general web auto-changer; leans into **passkeys** + a change-password URL quirk. +- **Academic verdict (arxiv 2511.10111, Nov 2025, 111 Tranco sites):** *"no popular third-party + or browser-embedded password manager supports automated website password updates."* Sites use + **diverse, confusing** flows, often **break autocomplete**, and some **deliberately block + automation**. The industry's real answer is **passkeys**, not auto-change. + +**Implication:** fully-automatic browser rotation is a known tar pit. incredigo's **guided, +human-in-the-loop worklist** (rotate what's scriptable; hand the human a ranked, linked +checklist for the rest; never bypass MFA/CAPTCHA) is the *pragmatic* shape that survives where +"automate everything" died. This matches Hard Rule #5 (self-owned only) and #6 (dry-run default). + +--- + +## 4. RFC 8615 `.well-known/change-password` + +- W3C "A Well-Known URL for Changing Passwords" lets tools deep-link to a site's change page. +- **Adoption (Tranco top 200, 2025):** ~**12.2%** support the W3C path; ~**33.8%** support + Apple's competing URL-quirk. Adopters incl. Google, GitHub, WordPress, Facebook, X. **Most + redirects land on a generic security page, not the change form.** +- Consumed by Chrome and Safari; Bitwarden has open community requests. + +**Implication:** good enough to power incredigo's **offline change-URL generation** (already +built: curated table + RFC 8615 well-known + host fallback), but thin enough that it can't be +the whole answer — reinforcing the rotate-vs-guide split. + +--- + +## 5. Underserved segments (the white space) + +**A. Solo devs & small teams with local secret sprawl.** +- **GitGuardian State of Secrets Sprawl 2026:** **29M new hardcoded secrets in 2025, +34% YoY**; + each live secret appeared in **~8 locations on the same machine** (.env, shell history, IDE + configs, cached tokens, build artifacts); **59% of compromised machines were CI/CD runners**. +- **Snyk:** ~28M credentials leaked on GitHub in 2025. +- No major vendor owns **discover-then-rotate of sprawl already on the box** (.aws/.netrc/ssh/ + docker/kube) — they start *after* migration into their hub. → **incredigo Mode B.** + +**B. Privacy-conscious / no-cloud.** +- HashiCorp's BSL relicense spawned **OpenBao** (LF/MPL-2.0 fork of Vault 1.14, joined OpenSSF + Jun 2025). Infisical (MIT) and Bitwarden Secrets Manager also serve no-cloud. +- **But all are servers/daemons.** A **local-first, RAM-only, single binary** with no + infrastructure is unoccupied ground. → **incredigo's core architecture.** + +**C. The no-API "long tail."** +- *"Password managers won't rotate your bank login, email recovery keys, or IoT device admin + panels unless you manually initiate each one."* Enterprise PAM rotates what has an API; the + manual long tail is **explicitly out of scope**; the one consumer attempt (Dashlane) failed. + → **incredigo's guided worklist.** + +**D. OSS rotation specifically (not storage).** Even among OSS tools rotation is the weak spot +(Infisical retry/failure gaps; GCP "write your own function"; AWS native only first-party DBs). + +--- + +## 6. Who incredigo should be tailored for + +**Primary persona — "the security-literate solo dev / small-team lead."** +- Has secrets scattered across `.env`, `~/.aws`, `~/.netrc`, `~/.ssh`, `docker-compose.yml`, + `k8s/*.yaml`, plus a gopass store. +- Distrusts (or can't afford / can't legally use) a SaaS secrets hub. Wants self-custody. +- Comfortable on the CLI; wants **headless automation in CI** *and* an interactive TUI. +- Job-to-be-done: *"Find every credential I have, back them up safely, rotate the ones a script + can rotate, and give me a clean checklist for the rest — without anything ever leaving my + machine."* + +**Secondary personas:** +- **Privacy/sovereignty buyers** (journalists, activists, infosec consultants, regulated EU + shops who can't ship secrets to US clouds) — value RAM-only / no-cloud + the PGP-as-root-of-trust model. +- **Homelab / self-hosted operators** — rotate Postgres/Redis/SSH/router/NAS creds with one tool. +- **Incident responders / pentest cleanup** — after a leak, *discover + mass-rotate + audit* on a + host quickly. (Aligns with the GitGuardian "8 copies per secret" reality.) + +**Explicit non-targets (for now):** Fortune-500 PAM, machine-identity-at-scale, compliance-cert +checkboxes (SOC2/FedRAMP managed service). Those are the incumbents' moats. + +**Positioning line:** *"The local-first credential rotator: discover the secrets sprawled across +your machine, back them up, rotate what's automatable, and get a guided worklist for the rest — +RAM-only, no cloud, no server, one binary."* + +--- + +## 7. Extension vectors (ranked by leverage vs. white space) + +Tied to the gaps above, not feature-for-feature parity with PAM. + +1. **Breadth of self-hostable rotation drivers** (the credibility multiplier). After postgres: + **MySQL/MariaDB, Redis, SSH `authorized_keys`, Gitea/GitHub/GitLab PATs, AWS IAM access keys + (moto-tested), HTTP basic-auth / reverse-proxy htpasswd, S3-compatible keys.** Each is a + self-contained `Rotator` — exactly the homelab/solo-dev surface incumbents skip. +2. **Consumer-grade reset-flow engine** (the highest-leverage *category* move): a generalized, + declarative **"email/OTP reset-flow" runner** for the long tail — site recipe = change-URL + + form selectors + (human-supplied) OTP step. Human-in-the-loop, never bypasses MFA. This is the + space Dashlane vacated and Chrome only half-fills. +3. **"Eliminate, don't rotate" recommender.** Where a credential *can* be replaced by something + that needs no rotation (passkeys, OIDC/SSO, short-lived certs, SSH certificates, cloud + workload identity), **recommend the elimination** instead of rotating. This rides the + industry's actual direction (passkeys) and is a differentiator no rotator markets. +4. **Consumer propagation / blast-radius closeout.** After rotating a secret, update the places + that consume it (.env, CI variables, k8s secrets) — the read-only `blast` map already finds + them; the next step is *guided* (not silent) propagation. +5. **GitOps / IaC rotation** — rotate a secret and open a PR that updates the encrypted value + (SOPS/age) in the repo. Serves the "59% of leaks are in CI/CD runners" reality. +6. **Standards plumbing** — RFC 7009 token revocation, RFC 8693 token exchange, SCIM for + user-store rotation, ACME for TLS cert rotation. Each widens automatable coverage. + +**Recommended next two:** finish the **driver ladder** (#1 — proves the core works broadly and is +low-risk) and prototype the **reset-flow engine** (#2 — the actual unoccupied market). #3 +(eliminate-don't-rotate) is the cheapest *positioning* win and worth a small advisory module. + +--- + +## Caveats on data quality + +- **PAM market sizes differ materially by analyst** (Mordor vs Fortune vs Precedence) — cite the + firm with each figure. +- The **`.well-known` adoption (12.2% / 33.8%)** and **111-site automation study** come from + **arxiv 2511.10111**; some per-metric numbers in the HTML preprint were redacted — treat the + fine-grained automation percentages as **directional** and verify against the final PDF before + quoting precisely. +- **Doppler's funding/valuation** was not found in public trackers; needs a dedicated dig if required. +- Acquisition values/dates (CyberArk/PANW, HashiCorp/IBM) are as announced in 2025; confirm close + status before citing as completed. + +## Sources + +- IBM/HashiCorp: https://www.hashicorp.com/en/blog/hashicorp-officially-joins-the-ibm-family · https://siliconangle.com/2025/02/27/ibm-completes-6-4b-hashicorp-acquisition-following-regulatory-approvals/ +- Vault pricing/license: https://infisical.com/blog/hashicorp-vault-pricing · https://envmanager.com/blog/hashicorp-vault-pricing +- CyberArk/PANW: https://www.paloaltonetworks.com/company/press/2025/palo-alto-networks-announces-agreement-to-acquire-cyberark--the-identity-security-leader · Conjur pricing: https://infisical.com/blog/cyberark-conjur-pricing +- Akeyless: https://www.akeyless.io/secrets-management/ · https://www.prnewswire.com/news-releases/akeyless-raises-65m-to-provide-secrets-management-as-a-service-for-devops-and-multi-cloud-environments-301679894.html +- Doppler/Infisical: https://www.doppler.com/blog/infisical-doppler-secrets-management-comparison-2025 · https://securityboulevard.com/2025/06/infisical-vs-doppler-secrets-management-comparison-for-2025/ +- AWS/Azure/GCP: https://www.pulumi.com/blog/secrets-management-tools-guide/ · https://www.techleague.io/blog/security/aws-secrets-manager-vs-azure-key-vault-vs-gcp-secret-manager-2026/ · https://dev.to/kazuya_dev/aws-reinvent-2025-zero-touch-secret-rotation-now-available-for-your-third-party-secrets-sec230-fne +- PAM market: https://www.mordorintelligence.com/industry-reports/privileged-access-management-pam-market · https://www.fortunebusinessinsights.com/privileged-access-management-market-112360 · https://www.precedenceresearch.com/privileged-access-management-market +- PAM leaders: https://techcloudpro.com/blog/cyberark-vs-delinea-vs-beyondtrust-pam-comparison/ · https://www.beyondtrust.com/resources/competitor-comparisons/delinea-alternative +- Consumer auto-change: https://www.cloudwards.net/dashlane-review/ · https://thehackernews.com/2025/05/google-chrome-can-now-auto-change.html · https://developer.chrome.com/docs/identity/automated-password-change +- Academic study: https://arxiv.org/abs/2511.10111 (HTML: https://arxiv.org/html/2511.10111v2) +- RFC 8615 / change-password URL: https://www.rfc-editor.org/rfc/rfc8615.html · https://www.w3.org/TR/change-password-url/ · https://web.dev/articles/change-password-url +- Secrets sprawl: https://thehackernews.com/2026/03/the-state-of-secrets-sprawl-2026-9.html · https://snyk.io/articles/state-of-secrets/ · https://www.doppler.com/blog/what-is-secrets-sprawl-and-how-to-prevent-it-in-2025 +- OSS/no-cloud: https://openssf.org/blog/2025/06/17/openbao-joins-the-openssf-to-advance-secure-secrets-management-in-open-source/ · https://infisical.com/blog/open-source-secrets-management-devops +- Long tail: https://lifetips.alibaba.com/tech-efficiency/automated-password-rotation-for-personal-accounts diff --git a/docs/assets/_igo_options.html b/docs/assets/_igo_options.html deleted file mode 100644 index 9125e59..0000000 --- a/docs/assets/_igo_options.html +++ /dev/null @@ -1,91 +0,0 @@ - -
- - -
- - - - - - - - - - - - - - - go - -
A · DIAMOND-DOT
dark tile · i-dot = Strata core
-
- - -
- - - - - - - - - go - -
B · KNOCKOUT
orange tile · bold solid
-
- - -
- - - - - - - - - - - - - - igo - -
C · STACK
Strata mark over igo
-
- - -
- - - - - - - - - ig - - - - - - -
D · DIAMOND-O
the 'o' becomes the vault
-
- -
- diff --git a/docs/assets/_igo_options.png b/docs/assets/_igo_options.png deleted file mode 100644 index ab3de0a..0000000 Binary files a/docs/assets/_igo_options.png and /dev/null differ diff --git a/docs/assets/banner-A.png b/docs/assets/banner-A.png new file mode 100644 index 0000000..72f0090 Binary files /dev/null and b/docs/assets/banner-A.png differ diff --git a/docs/assets/banner-A.svg b/docs/assets/banner-A.svg new file mode 100644 index 0000000..d3b5ac1 --- /dev/null +++ b/docs/assets/banner-A.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + go + + inCREDiGO + Guards your credentials in locked memory. + Leaves no trace on disk. + + local-first + RAM-only + offline + no plaintext at rest + + diff --git a/docs/assets/banner-B.png b/docs/assets/banner-B.png new file mode 100644 index 0000000..7e5dc5e Binary files /dev/null and b/docs/assets/banner-B.png differ diff --git a/docs/assets/banner-B.svg b/docs/assets/banner-B.svg new file mode 100644 index 0000000..6e15464 --- /dev/null +++ b/docs/assets/banner-B.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + go + + inCREDiGO + Guards your credentials in locked memory. + Leaves no trace on disk. + + local-first + RAM-only + offline + no plaintext at rest + + diff --git a/docs/assets/banner-C.png b/docs/assets/banner-C.png new file mode 100644 index 0000000..1345e96 Binary files /dev/null and b/docs/assets/banner-C.png differ diff --git a/docs/assets/banner-C.svg b/docs/assets/banner-C.svg new file mode 100644 index 0000000..0c40a54 --- /dev/null +++ b/docs/assets/banner-C.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + igo + + inCREDiGO + Guards your credentials in locked memory. + Leaves no trace on disk. + + local-first + RAM-only + offline + no plaintext at rest + + diff --git a/docs/assets/banner-D.png b/docs/assets/banner-D.png new file mode 100644 index 0000000..f3ad683 Binary files /dev/null and b/docs/assets/banner-D.png differ diff --git a/docs/assets/banner-D.svg b/docs/assets/banner-D.svg new file mode 100644 index 0000000..a108750 --- /dev/null +++ b/docs/assets/banner-D.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + g + + + inCREDiGO + Guards your credentials in locked memory. + Leaves no trace on disk. + + local-first + RAM-only + offline + no plaintext at rest + + diff --git a/docs/assets/icon-A-diamond-dot.svg b/docs/assets/icon-A-diamond-dot.svg new file mode 100644 index 0000000..92abf56 --- /dev/null +++ b/docs/assets/icon-A-diamond-dot.svg @@ -0,0 +1,7 @@ + + + + + + go + diff --git a/docs/assets/icon-A.png b/docs/assets/icon-A.png new file mode 100644 index 0000000..b49b547 Binary files /dev/null and b/docs/assets/icon-A.png differ diff --git a/docs/assets/icon-B-knockout.svg b/docs/assets/icon-B-knockout.svg new file mode 100644 index 0000000..ebd8142 --- /dev/null +++ b/docs/assets/icon-B-knockout.svg @@ -0,0 +1,7 @@ + + + + + + go + diff --git a/docs/assets/icon-B.png b/docs/assets/icon-B.png new file mode 100644 index 0000000..6a9ca54 Binary files /dev/null and b/docs/assets/icon-B.png differ diff --git a/docs/assets/icon-C-stack.svg b/docs/assets/icon-C-stack.svg new file mode 100644 index 0000000..4c23e96 --- /dev/null +++ b/docs/assets/icon-C-stack.svg @@ -0,0 +1,7 @@ + + + + + + igo + diff --git a/docs/assets/icon-C.png b/docs/assets/icon-C.png new file mode 100644 index 0000000..a6f6ab8 Binary files /dev/null and b/docs/assets/icon-C.png differ diff --git a/docs/assets/icon-D-diamond-o.svg b/docs/assets/icon-D-diamond-o.svg new file mode 100644 index 0000000..fdf09b3 --- /dev/null +++ b/docs/assets/icon-D-diamond-o.svg @@ -0,0 +1,8 @@ + + + + + + g + + diff --git a/docs/assets/icon-D.png b/docs/assets/icon-D.png new file mode 100644 index 0000000..612fbb7 Binary files /dev/null and b/docs/assets/icon-D.png differ diff --git a/docs/assets/igo-samples.png b/docs/assets/igo-samples.png new file mode 100644 index 0000000..7bb5f09 Binary files /dev/null and b/docs/assets/igo-samples.png differ