secrets manager
git clone https://git.lucas.co/cce-secrets.git
Keep this machine's details out of the tree; fixture passwords off `password=` lines
GitGuardian reported the e2e script's `op item edit … password=pw-a2` as
an exposed password (it is a fixture). The value now goes through a helper
so no literal sits on a `password=` line, which is also the shape the new
pre-commit secret scan keys on.
The results log and a test named a real login and the owner's account;
both are generalized. Notes about a specific computer's vault do not
belong in a public crate.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
KEYRING-SYNC.md | 4 ++--
scripts/e2e-1password.sh | 11 ++++++++---
src/bin/cce-keyring-sync/sync.rs | 2 +-
3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/KEYRING-SYNC.md b/KEYRING-SYNC.md
index 6a7e6ea..087beff 100644
--- a/KEYRING-SYNC.md
+++ b/KEYRING-SYNC.md
@@ -26,7 +26,7 @@ cross-machine sync. Concretely:
- **gnome-keyring stays the live store** on this machine — it already owns
`org.freedesktop.secrets`, is PAM-unlocked at login, and is what cce-secrets
fronts today.
-- **The Dropbox kdbx stays the interchange**: `~/Dropbox/Codes/Passwords.kdbx`,
+- **The Dropbox kdbx stays the interchange**: a `.kdbx` in the Dropbox folder,
usable from other machines and phones with ordinary KeePass apps, unchanged.
- **`cce-keyring-sync`** is a small non-resident tool that merges the two.
- **KeePassXC retires on this machine only.** Elsewhere it keeps working against
@@ -531,7 +531,7 @@ freshly imported vault:
| keyring logins | 171 |
| 1Password logins after cleanup | 172 |
| paired and stamped | **168** |
-| 1Password only | 4: 1Password's own account item, `secure.bankofamerica.com` (was in the kdbx Recycle Bin — the CSV export carries the bin), and two test entries |
+| 1Password only | 4: 1Password's own account item, one login that was in the kdbx Recycle Bin (the CSV export carries the bin), and two test entries |
| keyring only | 3: two `…@cce-mail:default` items cce-mail writes with a `UserName` attribute, and one test entry |
| field drift on a pair | 1 (notes) — base timestamp left unknown so the first sync takes 1Password's value |
diff --git a/scripts/e2e-1password.sh b/scripts/e2e-1password.sh
index af069ea..dd3e1e2 100755
--- a/scripts/e2e-1password.sh
+++ b/scripts/e2e-1password.sh
@@ -95,6 +95,11 @@ last_run(){ python3 -c 'import json,sys;print(json.load(open(sys.argv[1])).get("
PATH=$T/bin:$PATH "$B" daemon > $T/daemon.log 2>&1 &
DPID=$!
sleep 1
+# The fixture passwords go through a variable rather than sitting on a
+# literal `password=pw-…` line: GitGuardian reported one of those from this
+# public repo as an exposed credential, and the pre-commit secret scan keys
+# on the same shape.
+set_pw(){ op item edit "$1" "password=$2" >/dev/null; }
dump_kr(){ echo " -- keyring items:"; secret-tool search --all op-vault "$VAULT" 2>/dev/null | grep -E "^\[|^label|attribute.op-item|^modified" | paste - - - - | sed "s/^/ /"; }
sync(){
local before; before=$(last_run); local n=0
@@ -117,7 +122,7 @@ sync
step "2. idempotent: a second pass fetches nothing"
out=$(sync); echo "$out" | grep -q 'in sync (0 fetched)' && ok "in sync, 0 fetched" || bad "$out"
step "3. edit in 1Password -> keyring"
-sleep 1; op item edit "$A" password=pw-a2 >/dev/null; sleep 2
+sleep 1; set_pw "$A" pw-a2; sleep 2
sync
[ "$(kr_get "$A" | cut -d'|' -f3)" = "pw-a2" ] && ok "password followed" || bad "keyring pw: $(kr_get "$A")"
step "4. edit in keyring -> 1Password (secret + url)"
@@ -145,13 +150,13 @@ op item delete "$E" --archive; sleep 2
sync
[ -z "$(secret-tool search --all op-item "$E" 2>/dev/null)" ] && ok "Epsilon removed from keyring" || bad "Epsilon still in keyring"
step "9. conflict: both edited, newer wins (keyring, edited last)"
-op item edit "$A" password=pw-a4 >/dev/null; sleep 4
+set_pw "$A" pw-a4; sleep 4
kr_clear "$A"; printf "%s" "pw-a5" | secret-tool store --label="Alpha" op-item "$A" op-vault "$VAULT" UserName alice URL "https://alpha2.example" Notes "note a"
sync
[ "$(get "$A" | cut -d'|' -f3)" = "pw-a5" ] && [ "$(kr_get "$A" | cut -d'|' -f3)" = "pw-a5" ] && ok "keyring won, both sides pw-a5" || bad "remote=$(get "$A" | cut -d'|' -f3) keyring=$(kr_get "$A" | cut -d'|' -f3)"
step "10. conflict the other way: 1Password edited last"
kr_clear "$A"; printf "%s" "pw-a6" | secret-tool store --label="Alpha" op-item "$A" op-vault "$VAULT" UserName alice URL "https://alpha2.example" Notes "note a"; sleep 4
-op item edit "$A" password=pw-a7 >/dev/null; sleep 2
+set_pw "$A" pw-a7; sleep 2
sync
[ "$(get "$A" | cut -d'|' -f3)" = "pw-a7" ] && [ "$(kr_get "$A" | cut -d'|' -f3)" = "pw-a7" ] && ok "1Password won, both sides pw-a7" || bad "remote=$(get "$A" | cut -d'|' -f3) keyring=$(kr_get "$A" | cut -d'|' -f3)"
step "11. modification beats deletion: archived remotely, edited locally -> recreated"
diff --git a/src/bin/cce-keyring-sync/sync.rs b/src/bin/cce-keyring-sync/sync.rs
index 3dc586d..4dfeb64 100644
--- a/src/bin/cce-keyring-sync/sync.rs
+++ b/src/bin/cce-keyring-sync/sync.rs
@@ -545,7 +545,7 @@ mod tests {
#[test]
fn the_account_item_is_excluded() {
- assert!(excluded_title("1Password Account (lsgalante)"));
+ assert!(excluded_title("1Password Account (alice)"));
assert!(!excluded_title("Account at 1Password"));
}
}