firevault 0.2.0-beta.2 → 0.2.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,18 @@
1
1
  # Changelog
2
2
 
3
- ## 0.2.0-beta.1 - Unreleased
3
+ ## Unreleased
4
+
5
+ - Added optional VS Code settings support during `firevault init` to hide the nested `.firevault` Git repository from the parent workspace Source Control panel.
6
+
7
+ ## 0.2.0-beta.3
8
+
9
+ - Changed `firevault doctor` to treat service account paths outside `.firevault` as informational rather than a failure.
10
+
11
+ ## 0.2.0-beta.2
12
+
13
+ - Fixed CLI version reporting to read from `package.json` instead of a hardcoded version.
14
+
15
+ ## 0.2.0-beta.1
4
16
 
5
17
  - Added `firevault status` for compact local recovery health checks.
6
18
  - Added `firevault doctor` for actionable local setup validation.
package/README.md CHANGED
@@ -52,6 +52,8 @@ firevault init
52
52
 
53
53
  `firevault init` asks for your Firebase project ID, service account path, output directory, and collections. It creates `.firevault/`, writes `.firevault/config.json`, writes `.firevault/.gitignore`, can initialize Git inside `.firevault/`, and adds `.firevault/` to the parent app repo `.gitignore` when the parent is a Git repo.
54
54
 
55
+ If VS Code settings are detected, init can also hide `.firevault` from the parent workspace Source Control panel by adding `.firevault` to `git.ignoredRepositories`. This only affects the parent VS Code UI; `.firevault` remains a normal Git repository and works normally when opened directly.
56
+
55
57
  During setup, Firevault looks for likely Firebase project IDs in local files such as `.env.local`, `.env.development`, `firebase.json`, and common Firebase config files. Detection is best-effort and transparent: if Firevault finds candidates, it shows where they came from and lets you accept one or enter a value manually.
56
58
 
57
59
  Firevault also looks for likely local service account files such as `serviceAccountKey.json`, `service-account.json`, `firebase-service-account.json`, and `credentials/firebase.json`. It never prints private key contents. If you select a service account path, Firevault adds that path to `.gitignore`.
@@ -133,7 +133,7 @@ export function runDoctor() {
133
133
  }
134
134
  const serviceAccountDisplayPath = displayPathFromApp(config.workspaceRoot, config.serviceAccountPathAbsolute);
135
135
  if (!isInside(config.workspaceRoot, config.serviceAccountPathAbsolute)) {
136
- addCheck(checks, "FAIL", "Service account path is outside .firevault", "Set serviceAccountPath to a path inside .firevault, such as ./serviceAccountKey.json");
136
+ addCheck(checks, "INFO", "Service account path is outside .firevault", "External credential paths are supported. Ensure the file is securely managed and excluded from Git.");
137
137
  }
138
138
  else if (existsSync(config.serviceAccountPathAbsolute)) {
139
139
  addCheck(checks, "OK", "Service account file present");
@@ -164,10 +164,14 @@ export function runDoctor() {
164
164
  addCheck(checks, "WARN", "No Git remote origin configured", "git -C .firevault remote add origin <private-repo-url>");
165
165
  }
166
166
  workflowChecks(checks, config.workspaceRoot);
167
- const serviceAccountIgnored = workspaceIsGitRepo
167
+ const serviceAccountIsInsideWorkspace = isInside(config.workspaceRoot, config.serviceAccountPathAbsolute);
168
+ const serviceAccountIgnored = workspaceIsGitRepo && serviceAccountIsInsideWorkspace
168
169
  ? isPathIgnored(config.serviceAccountPath, config.workspaceRoot)
169
170
  : undefined;
170
- if (serviceAccountIgnored === true || gitignoreContains(config.workspaceRoot, config.serviceAccountPath)) {
171
+ if (!serviceAccountIsInsideWorkspace) {
172
+ addCheck(checks, "INFO", "Service account ignore check skipped for external path");
173
+ }
174
+ else if (serviceAccountIgnored === true || gitignoreContains(config.workspaceRoot, config.serviceAccountPath)) {
171
175
  addCheck(checks, "OK", "Service account file ignored");
172
176
  }
173
177
  else {
@@ -236,6 +236,53 @@ function ensureGitignoreEntries(gitignorePath, entries) {
236
236
  const prefix = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
237
237
  appendFileSync(gitignorePath, `${prefix}${missingEntries.join("\n")}\n`);
238
238
  }
239
+ function isRecord(value) {
240
+ return value !== null && typeof value === "object" && !Array.isArray(value);
241
+ }
242
+ function hasVsCodeConfig(appRoot) {
243
+ return existsSync(path.join(appRoot, ".vscode"));
244
+ }
245
+ async function shouldHideWorkspaceFromVsCode(options, appRoot, rl) {
246
+ if (!hasVsCodeConfig(appRoot)) {
247
+ return false;
248
+ }
249
+ if (options.yes) {
250
+ return true;
251
+ }
252
+ if (!rl) {
253
+ throw new Error("Prompt interface is required for interactive init.");
254
+ }
255
+ console.log("VS Code detected.");
256
+ const answer = (await rl.question("Hide .firevault repository from the parent VS Code workspace? (Y/n): "))
257
+ .trim()
258
+ .toLowerCase();
259
+ return answer === "" || answer === "y" || answer === "yes";
260
+ }
261
+ function updateVsCodeSettings(appRoot) {
262
+ const vscodeDir = path.join(appRoot, ".vscode");
263
+ const settingsPath = path.join(vscodeDir, "settings.json");
264
+ const settings = existsSync(settingsPath)
265
+ ? JSON.parse(readFileSync(settingsPath, "utf-8"))
266
+ : {};
267
+ if (!isRecord(settings)) {
268
+ throw new Error(".vscode/settings.json must contain a JSON object.");
269
+ }
270
+ const existingIgnoredRepositories = settings["git.ignoredRepositories"];
271
+ if (existingIgnoredRepositories !== undefined &&
272
+ !Array.isArray(existingIgnoredRepositories)) {
273
+ throw new Error(".vscode/settings.json field git.ignoredRepositories must be an array.");
274
+ }
275
+ const ignoredRepositories = existingIgnoredRepositories
276
+ ? [...existingIgnoredRepositories]
277
+ : [];
278
+ if (ignoredRepositories.includes(".firevault")) {
279
+ return false;
280
+ }
281
+ mkdirSync(vscodeDir, { recursive: true });
282
+ settings["git.ignoredRepositories"] = [...ignoredRepositories, ".firevault"];
283
+ writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`);
284
+ return true;
285
+ }
239
286
  export async function runInit(options) {
240
287
  console.log("Firevault");
241
288
  console.log("Undo button for Firestore.");
@@ -256,6 +303,7 @@ export async function runInit(options) {
256
303
  const shouldInitGit = workspaceIsGitRepository
257
304
  ? false
258
305
  : await promptForGitInit(options, rl);
306
+ const shouldHideVsCodeWorkspace = await shouldHideWorkspaceFromVsCode(options, appRoot, rl);
259
307
  const config = await promptForConfig(options, workspaceRoot, rl);
260
308
  config.collections = config.collections.map((collection) => collection.trim());
261
309
  validateConfig(config);
@@ -290,6 +338,15 @@ export async function runInit(options) {
290
338
  ensureGitignoreEntries(path.join(appRoot, ".gitignore"), parentIgnoreEntries);
291
339
  console.log("Updated parent .gitignore safety entries.");
292
340
  }
341
+ if (shouldHideVsCodeWorkspace) {
342
+ const updatedVsCodeSettings = updateVsCodeSettings(appRoot);
343
+ if (updatedVsCodeSettings) {
344
+ console.log("Updated VS Code settings to hide .firevault from the parent workspace.");
345
+ }
346
+ else {
347
+ console.log("VS Code settings already hide .firevault from the parent workspace.");
348
+ }
349
+ }
293
350
  console.log("Created .firevault/config.json.");
294
351
  console.log("Updated .firevault/.gitignore safety entries.");
295
352
  console.log("");
@@ -107,6 +107,7 @@ Behavior:
107
107
  - refuses to overwrite `.firevault/config.json` unless `--force` is provided,
108
108
  - adds `.firevault/` to the parent app repo `.gitignore` when the parent is a Git repo,
109
109
  - appends `.firevault/.gitignore` safety entries, including the selected service account path, without duplicating existing lines,
110
+ - optionally adds `.firevault` to VS Code `git.ignoredRepositories` for the parent workspace when `.vscode/` is detected and the user accepts,
110
111
  - never creates service accounts, opens browsers, runs `gcloud`, commits, pushes, creates GitHub repositories, contacts Firebase, or writes secrets.
111
112
 
112
113
  ## Firebase Access
@@ -134,6 +135,8 @@ Operational commands work from the app root or from inside `.firevault/` by disc
134
135
 
135
136
  `firestore-backups/` is not ignored inside `.firevault/` by default. The `.firevault` repository exists to commit backup data.
136
137
 
138
+ VS Code may show nested Git repositories in the parent app Source Control panel. Firevault can optionally update `.vscode/settings.json` in the parent app to hide `.firevault` from that parent workspace UI using `git.ignoredRepositories`. This does not change Git behavior and does not prevent opening `.firevault` directly in VS Code.
139
+
137
140
  ## GitHub Actions Automation
138
141
 
139
142
  `firevault setup-github-action` is a local workflow-file generator for scheduled offsite snapshots. It writes `.firevault/.github/workflows/firevault-snapshot.yml` and stops there.
@@ -45,6 +45,7 @@ Next fixes:
45
45
  Use clear severity:
46
46
 
47
47
  - `OK`: check passed.
48
+ - `INFO`: supported setup choice or useful context.
48
49
  - `WARN`: setup can work locally but recovery posture is weaker.
49
50
  - `FAIL`: setup is incomplete or unsafe enough that normal recovery workflows may fail.
50
51
 
@@ -54,6 +55,8 @@ Exit codes:
54
55
  - `1` if warnings are present and no checks fail.
55
56
  - `2` if any `FAIL`.
56
57
 
58
+ `INFO` checks do not affect the exit code.
59
+
57
60
  ## Checks
58
61
 
59
62
  ### Workspace
@@ -103,16 +106,25 @@ Edit .firevault/config.json or rerun `firevault init --force`
103
106
 
104
107
  Checks:
105
108
 
106
- - configured `serviceAccountPath` resolves inside `.firevault`,
107
- - file exists.
109
+ - configured `serviceAccountPath` may resolve inside or outside `.firevault`,
110
+ - file exists when the path is inside `.firevault`.
111
+
112
+ External credential paths are supported. A service account file outside `.firevault` is not inherently unsafe because users may keep credentials in secure locations such as `~/.config`, password-manager mounted paths, or shared secret directories.
108
113
 
109
114
  Do not parse the service account JSON in the first version. Parsing is local, but it starts pulling doctor toward credential validation. Save that for a later `--verify` mode.
110
115
 
111
116
  Result:
112
117
 
118
+ - `INFO Service account path is outside .firevault`
113
119
  - `OK Service account file present`
114
120
  - `FAIL Service account file missing`
115
121
 
122
+ Message for external paths:
123
+
124
+ ```txt
125
+ External credential paths are supported. Ensure the file is securely managed and excluded from Git.
126
+ ```
127
+
116
128
  Fix:
117
129
 
118
130
  ```txt
@@ -216,7 +228,9 @@ Review .firevault/.github/workflows/firevault-snapshot.yml or rerun `firevault s
216
228
  Checks:
217
229
 
218
230
  - `.firevault/.gitignore` exists,
219
- - configured service account path is ignored by Git.
231
+ - configured service account path is ignored by Git when the path is inside `.firevault`.
232
+
233
+ If the configured service account path is outside `.firevault`, skip `.firevault/.gitignore` enforcement and report an informational check instead. External credential paths should be managed by the external location's security and Git ignore policy.
220
234
 
221
235
  Best check:
222
236
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firevault",
3
- "version": "0.2.0-beta.2",
3
+ "version": "0.2.0-beta.4",
4
4
  "description": "Undo button for Firestore. Git-style history, rollback, and recovery for Firestore projects.",
5
5
  "keywords": [
6
6
  "firebase",