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 +2 -2
- package/package.json +1 -1
- package/src/cli.js +29 -2
- package/src/index.js +55 -4
- package/template/AGENTS.md +18 -3
- package/template/README.md +6 -0
- package/template/data/AGENTS.md +2 -0
- package/template/data/renderer.json +3 -0
- package/template/package.json +1 -1
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.
|
|
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
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.
|
|
35
|
-
console.log("
|
|
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.
|
|
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.
|
|
512
|
+
version: "0.3.4",
|
|
462
513
|
dependencies: { filegrc: versionRange }
|
|
463
514
|
}
|
|
464
515
|
}
|
package/template/AGENTS.md
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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`.
|
|
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
|
|
package/template/README.md
CHANGED
|
@@ -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
|

|
package/template/data/AGENTS.md
CHANGED
|
@@ -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.
|