mirror of
https://github.com/runbear-io/beardrive.git
synced 2026-08-25 08:08:08 +02:00
Catch a credential when it syncs, not only when you share it (#162)
* refactor(secrets): lift the share-time credential rules into internal/secrets The rules only ever ran on the rarest path a file takes. Moving them out of internal/webapp is what lets internal/syncer run the same six rules on the path every file takes, without inverting the dependency. Pure move plus one addition: Label(), the six human strings that until now lived only in the frontend's SECRET_LABELS — so 'bdrive share' stops printing a bare rule id where the web dialog says 'an AWS access key'. Rule ids and the rule/line JSON tags are unchanged: Browser.tsx keys off them, so they are a wire contract. * feat(sync): warn when a synced file looks like it holds a credential The six share-time rules now run on the path every file takes. A file with an AWS key in it used to ride a normal sync to the hub, to every teammate's disk and into every future agent's context with no badge and no warning — while the Share dialog one click later blocked that exact file. Warn, never block: the op is journaled and pushed exactly as before. A hold arm would mean a false positive silently parks someone's changes, and it would break the cycle's degrade-to-offline posture. - scan() reads the blob PutBlobFile just wrote (the bytes that were actually journaled), only on the branches that wrote one — an unchanged file is still never re-read. - Findings persist per path in secrets-<mount>.json, merged rather than replaced: nearly every cycle scans zero files, and a whole-set rewrite would erase the warning seconds after it appeared. Fixing the file clears it. - bdrive status grows a secrets block; the agent hook appends one advisory sentence. Rule ids and line numbers only, never the matched bytes. - SaveSecrets failing logs and continues: advisory telemetry never gets a veto over convergence. * docs: the credential check now runs on sync, not only on share README, the CLI reference and project-files get the new bdrive status block and the warn-never-block posture, with the three limits stated (checked when it changes, first 1 MiB, writing device only). Diagrams: internal/secrets is a package of its own in the overview, secretLog joins the sync engine, and the share-gate class notes that it no longer owns the rules. * test(sync): assert an unchanged file is never re-read for credentials The check must ride the branch that already reads the file. Clearing the record by hand and cycling proves it: a scan that re-read unchanged files would put the finding back, and the daemon's 3-second tick would pay for it on every file.
This commit is contained in:
@@ -24,7 +24,7 @@ One binary, `bdrive` — the CLI, the sync daemon, and the web server.
|
||||
| `bdrive sync [folder]` | Run one sync cycle now. Refuses folders this device never `init`ed and folders paused by `bdrive stop`. `--note <text>` stamps session context onto changes; `--note-ttl` (default 30m) bounds it. `--prune` also removes from the hub what `.bdriveignore` now excludes (files stay on disk everywhere). `--hook <label>` is agent-hook plumbing: it also reports the files teammates changed since the agent's last turn |
|
||||
| `bdrive hooks [install\|uninstall]` | Register turn-boundary sync hooks in each detected agent platform's user config — once per machine, covering every folder. Run automatically by `bdrive init`; idempotent; `--agent` overrides detection. `uninstall` removes only BearDrive's own hook entries |
|
||||
| `bdrive read-log [folder]` | Hook plumbing: queue agent file reads for the hub's read heatmap. Registered by `bdrive hooks install` |
|
||||
| `bdrive status [folder]` | Projects, daemon state, pending changes |
|
||||
| `bdrive status [folder]` | Projects, daemon state, pending changes, and any synced files that looked like they held credentials when they last changed |
|
||||
| `bdrive log [folder] [-p path] [-n N]` | Change history: account, device, time, file — newest first by the time shown, which is when the file was written (ops recorded before this was tracked, and deletes, show their sync time instead) |
|
||||
| `bdrive restore <file> [version]` | Put an earlier version of a file back, as a new change. No version restores the previous one; `--list` shows the versions with their short hashes |
|
||||
| `bdrive export [folder]` | Export the whole project — all devices' history and content — to a portable `.tar.gz` (`-o` names the file) |
|
||||
@@ -199,9 +199,10 @@ version wins and the path comes back. Run `--prune` again once they have synced.
|
||||
|
||||
### `bdrive status` — and the two degraded access states
|
||||
|
||||
Alongside `pending`, `status` prints an `access:` line whenever the hub is
|
||||
refusing this device. Neither is the same as being offline, and neither ever
|
||||
touches your files:
|
||||
Alongside `pending`, `status` prints a `secrets:` block naming any synced file
|
||||
that looked like it held a credential when it last changed, and an `access:`
|
||||
line whenever the hub is refusing this device. Neither access state is the same
|
||||
as being offline, and neither ever touches your files:
|
||||
|
||||
```
|
||||
pending: 3 local change(s) not yet pushed
|
||||
@@ -224,6 +225,29 @@ identity was never bound to your account, which is fixed by updating `bdrive`
|
||||
and running `bdrive login` on that machine, not in Project settings. Checking
|
||||
your permissions there will show `write` and tell you nothing.
|
||||
|
||||
### The credential warning
|
||||
|
||||
The six rules `bdrive share` checks at mint time also run on **every file as it
|
||||
syncs** — the path every file takes, rather than the rare one:
|
||||
|
||||
```
|
||||
secrets: 1 file(s) looked like they contain credentials when they last changed
|
||||
deploy.md:12 an AWS access key
|
||||
```
|
||||
|
||||
It **only ever warns**. The change is journaled and pushed exactly as it would
|
||||
be otherwise; the finding appears here and in an agent's context at the start
|
||||
of its next turn. Nothing is held, blocked, or un-pushed — a false positive
|
||||
costs one line of text, never a stalled file.
|
||||
|
||||
Fixing the file is the whole remedy: the next cycle reads it again and the line
|
||||
goes away, with no command and no flag. Three limits worth knowing: a file is
|
||||
checked **when it changes** (so this never says a file is clean), only its
|
||||
first 1 MiB is read, and the check runs on the device that made the change — a
|
||||
file synced from elsewhere is not flagged here until it next changes here.
|
||||
Rule names and line numbers only; the matched text is never printed, logged, or
|
||||
stored.
|
||||
|
||||
`bdrive sync` shows the same two as `remote: read-only (pull only)` /
|
||||
`remote: no access — sync paused` with the reason on the line below, and the
|
||||
daemon logs each once on transition rather than on every tick — including the
|
||||
|
||||
@@ -123,7 +123,9 @@ Nothing is keyed by folder path, which is why moves and renames are free.
|
||||
├─ blobs/ content-addressed file content (sha256)
|
||||
├─ journal/ one append-only op log per device
|
||||
├─ state.json what's materialized
|
||||
└─ sync.json lamport clock + push cursor
|
||||
├─ sync.json lamport clock + push cursor
|
||||
└─ secrets-<mount-id>.json files that looked like they held credentials when
|
||||
they last changed (what `bdrive status` reports)
|
||||
```
|
||||
|
||||
Also here for a running project: `daemon.pid` and `daemon.log`.
|
||||
|
||||
Reference in New Issue
Block a user