You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two related concerns for a git-backed workspace (#147) that aren't covered yet:
Secrets in git: env vars carrying API keys / tokens / passwords belong nowhere near a commit. Bruno's .bru files cleanly separate vars.secret from vars so the secret section can be gitignored. Bowire today stores all env vars in one file — committing it means committing secrets.
Concurrent writers: when the workbench is open and the operator runs bowire run --workspace-root . in another terminal, both want to write to the same disk store. Today that's a race; one writer wins, the other corrupts.
Both block real team adoption of the git-workspace shape.
Proposal — Part 1: Secret-File Separation
Storage shape
<workspaceRoot>/
environments/
staging.json # non-secret vars committed
staging.secrets.json # secret vars — gitignored
staging.example.json # template — committed, no real values
secrets/ # workspace-wide secrets (cross-env)
GH_TOKEN # one file per secret name
DB_PASSWORD
.gitignore # excludes *.secrets.json and secrets/
Resolution
Env-var resolution merges <env>.json + <env>.secrets.json at read time so the operator's {{API_KEY}} resolves whether the value lives in either file.
Editing a secret in the UI writes to the secret file; editing a non-secret writes to the regular file.
The Settings UI shows a clear visual distinction (key icon, masked value, "stored in secrets/" hint).
.example templates
For every staging.secrets.json a sibling staging.example.json lists the expected keys with placeholder values.
Committed to git so a new team member sees what they need to fill in.
Workbench auto-generates / updates the example when the operator adds a new secret name.
Migration
One-shot: walk every env, prompt the operator to mark which vars are secrets ("any var named *_KEY, *_TOKEN, *_PASSWORD, *_SECRET, Authorization defaults pre-flagged").
Splits the existing single-file env into base + secrets + example.
Workbench writes .bowire-lock on workspace open, removes on workspace close + clean shutdown.
CLI commands that write to the storage root (bowire run, bowire mock --record, bowire workspace migrate-format) check for the lock + warn:
Warning: workspace is open in another process (bowire workbench, PID 12345 on host bowire-dev).
Continuing may overwrite unsaved changes.
Override with --force-write.
Read-only commands (bowire run --dry-run, bowire export) skip the check.
Stale-lock detection
Lock includes PID + hostname. CLI tries kill -0 <pid> (Unix) / Process.GetProcessById (Windows) on the same host before refusing.
If the holding process is gone, CLI removes the stale lock + writes its own.
Crash recovery
Workbench on startup checks if its own old lock file exists; if so, treats it as "ungraceful shutdown" + offers to reload from the last known good state.
Acceptance
Secret-File separation
<env>.secrets.json + <env>.example.json files alongside the regular env file.
.gitignore defaults include *.secrets.json + secrets/.
Resolver merges both files at read time.
secret.NAME prefix resolves through secrets/NAME.
Settings UI shows key icon + masked value for secret-stored vars.
Migration prompt classifies existing vars; operator approves before splitting.
.example template auto-generated from current secret keys.
Workspace lock
.bowire-lock written + removed by the workbench.
CLI writes check the lock + warn with override flag.
Why
Two related concerns for a git-backed workspace (#147) that aren't covered yet:
.brufiles cleanly separatevars.secretfromvarsso the secret section can be gitignored. Bowire today stores all env vars in one file — committing it means committing secrets.bowire run --workspace-root .in another terminal, both want to write to the same disk store. Today that's a race; one writer wins, the other corrupts.Both block real team adoption of the git-workspace shape.
Proposal — Part 1: Secret-File Separation
Storage shape
Resolution
<env>.json+<env>.secrets.jsonat read time so the operator's{{API_KEY}}resolves whether the value lives in either file.secret.NAMEsource prefix (Multi-source {{...}} variable resolver #125 reserved this) resolves throughsecrets/NAME..exampletemplatesstaging.secrets.jsona siblingstaging.example.jsonlists the expected keys with placeholder values.Migration
*_KEY,*_TOKEN,*_PASSWORD,*_SECRET,Authorizationdefaults pre-flagged").Proposal — Part 2: Workspace Lock File
Storage shape
Acquisition
.bowire-lockon workspace open, removes on workspace close + clean shutdown.bowire run,bowire mock --record,bowire workspace migrate-format) check for the lock + warn:bowire run --dry-run,bowire export) skip the check.Stale-lock detection
kill -0 <pid>(Unix) /Process.GetProcessById(Windows) on the same host before refusing.Crash recovery
Acceptance
Secret-File separation
<env>.secrets.json+<env>.example.jsonfiles alongside the regular env file..gitignoredefaults include*.secrets.json+secrets/.secret.NAMEprefix resolves throughsecrets/NAME..exampletemplate auto-generated from current secret keys.Workspace lock
.bowire-lockwritten + removed by the workbench..gitignoredefault).Composes with
secret.NAMEplaceholder already reserved; this issue defines the backing store.storageRoot.Out of scope