create-filegrc 0.3.3 → 0.3.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # create-filegrc
2
2
 
3
- Create a Git-native filegrc workspace for a SOC 2 program:
3
+ Create a Git-native filegrc workspace for a SOC 2 program. Use a dedicated private repository so browser-generated compliance commits stay separate from application development history.
4
4
 
5
5
  ```sh
6
6
  npx create-filegrc@latest company-grc
@@ -40,7 +40,7 @@ npx create-filegrc@latest company-grc --config setup.json
40
40
 
41
41
  Generated workspaces also include layered `AGENTS.md` instructions and model-driven headless commands. `filegrc program-path` gives agents the same six steps, exact page guidance, current status, and next actions shown in the renderer. Agents can define program scope, approve policies, implement controls, test External Evidence, complete policy work, trigger event tasks, and prepare later audit packets through the same domain functions used by the renderer.
42
42
 
43
- Git is initialized when needed. The browser can create local commits before a remote is configured.
43
+ Git is initialized on `main` when needed. New workspaces use trunk mode with `main` and `origin`. Browser editing becomes available after that branch has an upstream; each save fast-forwards, validates, commits, and pushes automatically. Existing parent repositories are supported and never receive a nested Git repository.
44
44
 
45
45
  Creation output reports the resolved filegrc version, program timezone, starter record counts, whether installation ran, and whether the target joined an existing Git worktree or received a new repository.
46
46
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-filegrc",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "Create a filegrc workspace for a SOC 2 program",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/cli.js CHANGED
@@ -30,9 +30,30 @@ export async function runCli(argv = process.argv.slice(2)) {
30
30
  `filegrc ${result.engineVersion}${result.enginePackage ? ` from ${result.enginePackage}` : ""}: ` +
31
31
  `${result.install === "installed" ? "installed" : "installation skipped"}`
32
32
  );
33
+ console.log("Use a dedicated private repository for your FileGRC workspace. The browser");
34
+ console.log("commits and pushes each saved program change, so a standalone repository keeps");
35
+ console.log("the compliance audit trail separate from application development history.");
33
36
  console.log(`Git: ${result.gitMode === "existing-worktree" ? "joined existing worktree" : "initialized new repository"}`);
34
- if (result.gitDetached) {
35
- console.log("Warning: detached HEAD detected. Check out a branch before using browser commit, pull, or push.");
37
+ if (result.gitMode === "existing-worktree") {
38
+ console.log("");
39
+ console.log("This FileGRC workspace joined an existing Git repository.");
40
+ console.log("");
41
+ console.log("FileGRC recommends a dedicated private repository because browser saves create");
42
+ console.log("frequent compliance commits. A standalone repository keeps the GRC audit trail");
43
+ console.log("separate from application development history.");
44
+ console.log("");
45
+ console.log("Monorepo mode remains supported. Browser Git operations will commit only files");
46
+ console.log("inside this FileGRC workspace.");
47
+ }
48
+ if (
49
+ result.gitMode === "existing-worktree"
50
+ && result.repository.mode === "trunk"
51
+ && (result.gitDetached || result.gitBranch !== result.repository.authoritativeBranch)
52
+ ) {
53
+ console.log("");
54
+ console.log("The browser will open in read-only mode until this workspace is available on");
55
+ console.log("the configured authoritative branch. File creation and CLI validation still");
56
+ console.log("work from this checkout.");
36
57
  }
37
58
  console.log(`Timezone: ${result.values.timezone}`);
38
59
  for (const stage of result.stages) {
@@ -103,6 +124,9 @@ function parseArgs(argv) {
103
124
  else if (name === "starter") options.starter = next();
104
125
  else if (name === "filegrc-version") options.filegrcVersion = next();
105
126
  else if (name === "filegrc-package") options.filegrcPackage = next();
127
+ else if (name === "repository-mode") options.repositoryMode = next();
128
+ else if (name === "authoritative-branch") options.authoritativeBranch = next();
129
+ else if (name === "repository-remote") options.repositoryRemote = next();
106
130
  else if (name === "service-name") setup.serviceName = next();
107
131
  else if (name === "boundary") setup.boundary = next();
108
132
  else if (name === "service-owner") setup.ownerId = next();
@@ -131,6 +155,9 @@ Options:
131
155
  --starter <profile> security (default) or foundation
132
156
  --filegrc-version <version> Override resolved engine version
133
157
  --filegrc-package <directory> Install an unpublished local filegrc package
158
+ --repository-mode <mode> trunk (default) or manual
159
+ --authoritative-branch <name> Browser write branch, defaults to main
160
+ --repository-remote <name> Browser sync remote, defaults to origin
134
161
  --service-name <name> Complete service setup after creation
135
162
  --boundary <description> Initial service boundary
136
163
  --service-owner <person-id> Defaults to person-policy-owner
package/src/index.js CHANGED
@@ -16,6 +16,7 @@ export async function createFilegrc(options = {}) {
16
16
  const parameterConfig = JSON.parse(await readFile(join(packageRoot, "template-parameters.json"), "utf8"));
17
17
  const target = resolve(options.target ?? "filegrc-program");
18
18
  const starter = normalizeStarterProfile(options.starter);
19
+ const repository = normalizeRepositoryOptions(options);
19
20
  if (options.setup && options.install === false) {
20
21
  throw new Error("Combined service setup requires installation. Remove --no-install or run filegrc setup after npm install.");
21
22
  }
@@ -38,6 +39,7 @@ export async function createFilegrc(options = {}) {
38
39
  await mkdir(target, { recursive: true });
39
40
  await copyTemplate(target, starter);
40
41
  await renderTemplate(target, parameterConfig, values, starter);
42
+ await writeRendererRepositorySettings(target, repository);
41
43
  await writeBaselineRecords(target, values.effective_date, starter);
42
44
  await applyStarterScope(target, starter, values.effective_date);
43
45
  const initialResourceCounts = await summarizeResources(target);
@@ -49,7 +51,7 @@ export async function createFilegrc(options = {}) {
49
51
  await writeMinimalLockfile(target, values.project_name, values.filegrc_version_range);
50
52
  }
51
53
  const joinedExistingWorktree = await isInsideGitWorktree(target);
52
- if (!joinedExistingWorktree) await run("git", ["init"], target);
54
+ if (!joinedExistingWorktree) await run("git", ["init", `--initial-branch=${repository.authoritativeBranch}`], target);
53
55
  const gitHead = await inspectGitHead(target);
54
56
  const setup = options.setup ? await runCombinedSetup(target, options.setup) : null;
55
57
  const resourceCounts = setup ? await summarizeResources(target) : initialResourceCounts;
@@ -67,7 +69,8 @@ export async function createFilegrc(options = {}) {
67
69
  install: installed ? "installed" : "skipped",
68
70
  gitMode: joinedExistingWorktree ? "existing-worktree" : "initialized",
69
71
  gitBranch: gitHead.branch,
70
- gitDetached: gitHead.detached
72
+ gitDetached: gitHead.detached,
73
+ repository
71
74
  };
72
75
  }
73
76
 
@@ -80,6 +83,54 @@ export function normalizeStarterProfile(value = "security") {
80
83
  return normalized;
81
84
  }
82
85
 
86
+ function normalizeRepositoryOptions(options) {
87
+ const mode = String(options.repositoryMode ?? "trunk").trim();
88
+ if (!["trunk", "manual"].includes(mode)) {
89
+ throw new Error("Repository mode must be trunk or manual.");
90
+ }
91
+ return {
92
+ mode,
93
+ authoritativeBranch: normalizeGitSetting(options.authoritativeBranch, "main", "authoritative branch"),
94
+ remote: normalizeGitSetting(options.repositoryRemote, "origin", "repository remote")
95
+ };
96
+ }
97
+
98
+ function normalizeGitSetting(value, fallback, label) {
99
+ const result = String(value ?? fallback).trim();
100
+ if (!safeGitName(result)) {
101
+ throw new Error(`${label} must be a safe Git name.`);
102
+ }
103
+ return result;
104
+ }
105
+
106
+ function safeGitName(value) {
107
+ const segments = value.split("/");
108
+ return Boolean(value)
109
+ && value !== "@"
110
+ && value !== "HEAD"
111
+ && !value.startsWith("-")
112
+ && !value.includes("..")
113
+ && !value.includes("@{")
114
+ && !/[\s~^:?*[\]\\\u0000-\u001f\u007f]/.test(value)
115
+ && segments.every((segment) => (
116
+ segment
117
+ && !segment.startsWith(".")
118
+ && !segment.endsWith(".")
119
+ && !segment.endsWith(".lock")
120
+ ));
121
+ }
122
+
123
+ async function writeRendererRepositorySettings(target, repository) {
124
+ const path = join(target, "data", "renderer.json");
125
+ const renderer = JSON.parse(await readFile(path, "utf8"));
126
+ await writeFile(path, `${JSON.stringify({
127
+ ...renderer,
128
+ repositoryMode: repository.mode,
129
+ authoritativeBranch: repository.authoritativeBranch,
130
+ repositoryRemote: repository.remote
131
+ }, null, 2)}\n`, "utf8");
132
+ }
133
+
83
134
  export async function resolveFilegrcVersion(explicitVersion) {
84
135
  if (explicitVersion) return cleanVersion(explicitVersion);
85
136
  try {
@@ -452,13 +503,13 @@ async function runCombinedSetup(target, input) {
452
503
  async function writeMinimalLockfile(target, name, versionRange) {
453
504
  const lock = {
454
505
  name,
455
- version: "0.3.3",
506
+ version: "0.3.4",
456
507
  lockfileVersion: 3,
457
508
  requires: true,
458
509
  packages: {
459
510
  "": {
460
511
  name,
461
- version: "0.3.3",
512
+ version: "0.3.4",
462
513
  dependencies: { filegrc: versionRange }
463
514
  }
464
515
  }
@@ -58,9 +58,24 @@ Git supplies file authors, commit timestamps, messages, diffs, and revisions. Do
58
58
 
59
59
  Domain events still need explicit dates. Keep values such as `occurredOn`, `approvedOn`, `reviewedOn`, `completedOn`, and audit-period dates in their records.
60
60
 
61
- Make focused commits with messages that explain the reason for the change. The engine never creates commits automatically. Review the workspace diff, then use the commit action on Repository or the Git CLI. The renderer validates the workspace and requires an explicit message before it creates a commit.
61
+ Use a dedicated private repository for your FileGRC workspace. The browser commits and pushes each saved program change, so a standalone repository keeps the compliance audit trail separate from application development history.
62
62
 
63
- Pull before starting work when other people or agents may have changed the repository. Without a remote, the browser's Repository page creates a local commit and hides synchronization actions. With a remote, it pulls with rebase, refuses to pull over uncommitted files, and pushes immediately after it creates a commit. Agents and terminal users own Git synchronization and should run `git pull --rebase`, `git commit`, and `git push` directly. Do not create merge commits for routine synchronization.
63
+ - Prefer creating or cloning FileGRC as a standalone private repository.
64
+ - Run the editable browser from the authoritative branch's main checkout.
65
+ - Do not place a new FileGRC workspace inside an application monorepo unless the organization has explicitly chosen that structure.
66
+ - If FileGRC already lives in a monorepo, do not relocate it automatically.
67
+ - In a monorepo, never include application changes in FileGRC-generated commits.
68
+ - Treat detached and feature-branch copies as read-only unless an explicit development override is active.
69
+
70
+ New workspaces use trunk repository mode with `main` as the authoritative branch and `origin` as the remote. Each browser mutation checks the whole Git worktree, fetches the remote, fast-forwards only, rechecks the edited revision, writes through the normal domain function, validates the workspace, stages only this FileGRC workspace, creates a focused commit, and pushes it. Browser onboarding commits its related workspace, system, and renderer changes together.
71
+
72
+ The Repository page reports `Synced`, `Syncing`, `Not synced`, `Read-only checkout`, or `Git setup required`. A failed push keeps the local FileGRC commit and offers Retry sync when every ahead commit changes only this workspace. FileGRC never pushes an ahead commit that includes files outside this workspace, and it never merges, rebases, switches branches, resolves conflicts, or changes files outside the workspace.
73
+
74
+ Record lifecycle fields are the approval source. Draft, proposed, approved, and retired records may all live on the authoritative branch. Do not use Git branches to represent policy approval.
75
+
76
+ Existing workspaces without `repositoryMode` remain in manual mode. In manual mode, review the workspace diff and use the Repository controls or Git CLI. Agents and terminal users always own their Git synchronization and should pull, commit, and push directly. FileGRC does not replace repository authentication, authorization, branch protection, or review controls.
77
+
78
+ Use `npx filegrc serve --allow-non-authoritative-writes` only for local development in a task worktree. The override is visible in the UI and never commits or pushes.
64
79
 
65
80
  Do not rewrite or remove committed records that explain prior audit periods. Close or retire them. Delete only mistakes and uncommitted drafts.
66
81
 
@@ -93,7 +108,7 @@ Headless agents get the same protection by exporting an edit payload with `fileg
93
108
 
94
109
  ## Renderer settings and onboarding
95
110
 
96
- `data/renderer.json` stores committed renderer preferences. New workspaces set `showOnboarding` to `true`. Completing or skipping onboarding sets it to `false`; the app does not commit that change.
111
+ `data/renderer.json` stores committed renderer and repository preferences. New workspaces set `showOnboarding` to `true`, `repositoryMode` to `trunk`, `authoritativeBranch` to `main`, and `repositoryRemote` to `origin`. In trunk mode, completing or skipping onboarding commits and pushes the related change. Existing settings without `repositoryMode` keep manual behavior.
97
112
 
98
113
  Onboarding explains the file and Git workflow, the program path, policy obligations, and Policy Events before covering report types and the final audit stage. It then collects the initial service boundary, owner, business criticality, highest data classification, internet exposure, and optional program goal. It creates or updates one `system` record and stores that selected system and the management goal on `workspace`. It does not select framework records, link controls to the service, or create evidence. Selecting Type 1 or Type 2 does not create an audit engagement. Completing onboarding opens the Step 1 overview so the user can add the real reviewers and operators, finish the oversight team, and confirm the criteria, commitments, vendors, and systems before approving policies.
99
114
 
@@ -8,6 +8,8 @@ filegrc gives founder-led engineering teams one place to adopt policies, impleme
8
8
 
9
9
  It is open source, MIT licensed, and runs locally.
10
10
 
11
+ Use a dedicated private repository for your FileGRC workspace. The browser commits and pushes each saved program change, so a standalone repository keeps the compliance audit trail separate from application development history.
12
+
11
13
  ```sh
12
14
  npx create-filegrc@latest company-grc
13
15
  cd company-grc
@@ -27,6 +29,10 @@ The repository is the program. There is no separate application database.
27
29
 
28
30
  Use the same source through the local web app, a text editor, the CLI, or CI. Browser and CLI actions call the same rules, so engineers and agents see the same validation and readiness results.
29
31
 
32
+ New workspaces use `main` as the authoritative browser branch. Browser saves fetch and fast-forward from `origin`, validate the change, create a focused commit, and push it. Draft, proposed, approved, and retired records all live on that branch because record status, not a Git branch, represents approval.
33
+
34
+ Detached and feature-branch checkouts are read-only in the browser by default. Developers can run `npx filegrc serve --allow-non-authoritative-writes` for local task-worktree edits; that override never commits or pushes. Existing workspaces without `repositoryMode` keep manual browser Git behavior. CLI and agent workflows continue to manage Git explicitly.
35
+
30
36
  ## One path from setup to audit
31
37
 
32
38
  ![filegrc SOC 2 program overview](docs/filegrc-home.png)
@@ -185,3 +185,5 @@ git diff
185
185
  ```
186
186
 
187
187
  Review every changed JSON, Markdown, and attachment. Confirm the diff contains no secrets, temporary files, source exports with prohibited data, or derived `.filegrc/` output. Make one focused commit whose message says why the compliance record changed.
188
+
189
+ These commands are for CLI and agent work, which continues to manage Git explicitly. Browser saves in trunk mode commit and push automatically from the configured authoritative branch. Do not use a feature branch as a record approval state, and never include application changes when this workspace lives in a monorepo.
@@ -4,5 +4,8 @@
4
4
  "type": "renderer-settings",
5
5
  "title": "Renderer settings",
6
6
  "showOnboarding": true,
7
+ "repositoryMode": "trunk",
8
+ "authoritativeBranch": "main",
9
+ "repositoryRemote": "origin",
7
10
  "completedStagePageIds": []
8
11
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "{{project_name}}",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "private": true,
5
5
  "description": "filegrc workspace for a SOC 2 program",
6
6
  "type": "module",