Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ The sidebar groups records by their job:

Resource types are nested only when the extra grouping adds meaning. Organization settings remain anchored at the bottom.

The Controls page explains what the generated workspace already supplies and what management must tailor before a planned Control becomes implemented. Its operation-tracking column distinguishes Controls linked to recurring or event work in FileGRC from Controls supported by Evidence Artifacts, and it always shows authoritative evidence-source mappings. A Control owner records implementation without a separate per-Control approval, so that status change raises readiness immediately. The Step 2 overview links to separate Policies and Data Retention Schedule pages. The Policies page combines Policies, program Documents, and Training for individual content approval. The Data Retention Schedule page presents the governed schedule document, derived coverage gaps, structured rows, and one Git-bound schedule review whose collection revision includes the document Markdown and rows. Step 3 links, in order, to Controls, Complementary Controls, Evidence Sources, and Obligations. Evidence Sources is a derived coverage page whose fixes remain in canonical Control and Component records, and Step 3 retains derived checks that implemented sources follow the approved schedule. The Finish Step 3 row shows the next blocker, reveals one Git-bound Control collection review when implementation is ready, then reveals Program Content Activation as management's final cutover. Browser, HTTP API, and CLI use the same domain operations and readiness calculations.
The Controls page explains what the generated workspace already supplies and what management must tailor before a planned Control becomes implemented. Its operation-tracking column distinguishes Controls linked to recurring or event work in FileGRC from Controls supported by Evidence Artifacts, and it always shows authoritative evidence-source mappings. A Control owner records implementation without a separate per-Control approval, so that status change raises readiness immediately. The Step 2 overview links to separate Policies and Data Retention Schedule pages. The Policies page combines Policies, program Documents, and Training for individual content approval. The Data Retention Schedule page presents the governed schedule document, derived coverage gaps, structured rows, and one Git-bound schedule review whose collection revision includes the document Markdown and rows. Step 3 links, in order, to Controls, Complementary Controls, Evidence Sources, and Obligations. Evidence Sources is a derived coverage page whose fixes remain in canonical Control and Component records, and Step 3 retains derived checks that implemented sources follow the approved schedule. The Finish Step 3 row shows the next blocker, reveals one Git-bound Control collection review when implementation is ready, then reveals one Activation box as management's final cutover. Its review dialog selects eligible approved Policies, program Documents, and Training by default and applies the selection in one atomic batch. Unavailable records and readiness gaps remain visible in the content disclosure. Policy gaps remain disclosed, and Document and Training prerequisites and exact approval revisions still gate activation. Browser, HTTP API, and CLI use the same domain operations and readiness calculations.

Evidence Artifacts belong in Step 4 because management should create one only when a real export, report, screenshot, signed file, or approved external reference exists. The standard page creates and filters these records. Users select the source Component, link Controls and source operating records, attach or reference the result, record collection facts, and obtain verification before audit use. Risk, governance, vendor review, training and acknowledgement, vulnerability testing, backup and recovery testing, exception, and finding evidence stays on the Step 4 operating records. Fixed artifacts remain behind Evidence Artifact records and are linked from those operating records.

Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "filegrc-monorepo",
"version": "0.16.33",
"version": "0.16.34",
"private": true,
"workspaces": [
"packages/filegrc",
Expand Down
2 changes: 1 addition & 1 deletion packages/create-filegrc/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-filegrc",
"version": "0.16.33",
"version": "0.16.34",
"description": "Create a filegrc workspace for a SOC 2 program",
"license": "MIT",
"repository": {
Expand Down
4 changes: 2 additions & 2 deletions packages/create-filegrc/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,13 +524,13 @@ async function runCombinedSetup(target, input) {
async function writeMinimalLockfile(target, name, versionRange) {
const lock = {
name,
version: "0.16.33",
version: "0.16.34",
lockfileVersion: 3,
requires: true,
packages: {
"": {
name,
version: "0.16.33",
version: "0.16.34",
dependencies: { filegrc: versionRange }
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/create-filegrc/template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ Detached and feature-branch checkouts are read-only in the browser by default. D

1. **Define scope.** Set program ownership, choose the criteria, define the service, Systems, and providers in scope, review any supplemental requirement mappings, and commit the reporting-channel proposals needed by the planned program.
2. **Approve policies.** Review Policies, program Documents, and Training in one table. Have someone other than the owner approve each exact revision. Approval does not mean the linked Controls are implemented.
3. **Implement controls.** Implement the approved requirements, define how each Control works, connect its Evidence sources, and configure Obligations. Activate each unchanged approved Document or Training record with a separate activation date and revision, then activate the selected Policy cutover set.
3. **Implement controls.** Implement the approved requirements, define how each Control works, connect its Evidence sources, and configure Obligations. Use one Activation box to put eligible approved Policies, Documents, and Training into use together, with separate approval and activation revisions.
4. **Operate the program.** Run scheduled and event-driven work, maintain risk, and retain dated evidence.
5. **Audit.** Set up the CPA engagement, support fieldwork, and prepare the evidence packet.

A Policy says what the company commits to do by the date it takes effect. Approval means the company accepts those commitments. It does not prove the work is done. Controls and operating records describe how the company meets them and provide the proof.

FileGRC does not infer technical implementation from Policy prose. Configuration facts belong in Controls, Components, Systems, Obligations, and Evidence. A Control may be implemented while its governing Policy, required program Document, or Training is approved but inactive. Enabled Obligations remain dormant until all of their governing content is active and effective.

Control implementation includes evidence-source and Obligation readiness. Use `npx filegrc program-readiness --json` to see each Control's launch state and next practical check. Implemented means the control works now for its named scope, with a real owner, procedure, usable evidence source, and enabled work rules. It does not claim a future cycle or event has already happened. When the five Step 3 work areas are ready, one eligible reviewer records the implemented Control collection review. Management then activates the unchanged approved program Documents and Training with `npx filegrc activate-content --scaffold`, followed by the approved Policies with `npx filegrc activate-policies --scaffold`. Evidence Readiness requires a current Control collection review and active required content before the candidate period can begin. Create Evidence during Step 4 only after operation produces a real record or artifact. Create engagement terms, management assertions, representation letters, and other Audit Documents in Step 5, link each to one Audit, approve it, then activate it with `npx filegrc activate-documents --audit AUDIT_ID --scaffold`.
Control implementation includes evidence-source and Obligation readiness. Use `npx filegrc program-readiness --json` to see each Control's launch state and next practical check. Implemented means the control works now for its named scope, with a real owner, procedure, usable evidence source, and enabled work rules. It does not claim a future cycle or event has already happened. When the five Step 3 work areas are ready, one eligible reviewer records the implemented Control collection review. Management then activates the unchanged approved Policies, program Documents, and Training together with `npx filegrc activate-content --scaffold`. The individual Policy activation command remains available. Evidence Readiness requires a current Control collection review and active required content before the candidate period can begin. Create Evidence during Step 4 only after operation produces a real record or artifact. Create engagement terms, management assertions, representation letters, and other Audit Documents in Step 5, link each to one Audit, approve it, then activate it with `npx filegrc activate-documents --audit AUDIT_ID --scaffold`.

The Program Overview shows what is done, what is blocked, and what to do next.

Expand Down
2 changes: 1 addition & 1 deletion packages/create-filegrc/template/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "{{project_name}}",
"version": "0.16.33",
"version": "0.16.34",
"private": true,
"description": "filegrc workspace for a SOC 2 program",
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion packages/filegrc/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "filegrc",
"version": "0.16.33",
"version": "0.16.34",
"description": "Zero-dependency Git-native GRC engine",
"license": "MIT",
"repository": {
Expand Down
5 changes: 3 additions & 2 deletions packages/filegrc/src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -1663,8 +1663,9 @@ Options:
filegrc activate-content --scaffold [--program id]
filegrc activate-content <activation.json|-> [--resource id] [--activated-by person-id] [--activated-on YYYY-MM-DD] [--effective-on YYYY-MM-DD] [--preview|--yes] [--json]

Activate approved program Documents and Training in Step 3 after their linked
Controls are implemented and Training has an enabled assignment Obligation.
Activate approved program Policies, Documents, and Training together in Step 3.
Documents require implemented linked Controls; Training also needs an enabled
assignment Obligation. Review disclosed Policy gaps before activation.
Approval, activation, and effective dates remain separate, and activation binds
the exact approved Markdown revision.

Expand Down
68 changes: 60 additions & 8 deletions packages/filegrc/src/document-activation.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { personWasActiveOn } from "./soc2.js";
import { currentCalendarDate } from "./time.js";
import { loadWorkspace } from "./workspace.js";
import { revisionDigest } from "./revisions.js";
import { planPolicyActivation } from "./policy-activation.js";

export async function scaffoldDocumentActivation(input = process.cwd(), options = {}) {
const loaded = await loadWorkspace(input);
Expand Down Expand Up @@ -174,30 +175,81 @@ export async function scaffoldGovernedContentActivation(input = process.cwd(), o
const candidates = oversightReady
? await activationCandidates(loaded, { ...options, auditId: undefined })
: [];
const policies = (oversightReady ? readiness.policyActivations : []).filter(({ state }) => (
["approved-implementation-pending", "ready-to-activate"].includes(state)
));
const count = candidates.length + policies.length;
const revisionById = new Map(loaded.entries.map((entry) => [entry.record.id, contentRevision(entry.source)]));
const today = currentCalendarDate(loaded.workspace.timezone);
return {
available: candidates.length > 0,
available: count > 0,
message: !oversightReady
? "Complete the current Control collection review before Program Content Activation."
: candidates.length
? `${candidates.length} approved governed-content ${candidates.length === 1 ? "record is" : "records are"} ready to activate.`
: "No program Document or Training record is ready to activate. Review the current readiness actions first.",
nextCommand: candidates.length ? null : "npx filegrc program-path --next --json",
: count
? `${count} approved program content ${count === 1 ? "record is" : "records are"} available to activate. Review any Policy gaps before confirming.`
: "No approved program content is available to activate. Review the current readiness actions first.",
nextCommand: count ? null : "npx filegrc program-path --next --json",
programId: readiness.program.id,
policyIds: policies.map(({ policyId }) => policyId),
resourceIds: candidates.map(({ resourceId }) => resourceId),
documentIds: candidates.filter(({ resourceType }) => resourceType === "document").map(({ resourceId }) => resourceId),
trainingIds: candidates.filter(({ resourceType }) => resourceType === "training").map(({ resourceId }) => resourceId),
workflowScope: "program",
activatedByIds: [],
activatedOn: today,
effectiveOn: today,
expectedRevisions: Object.fromEntries(candidates.map(({ resourceId }) => [resourceId, revisionById.get(resourceId)])),
expectedRevisions: Object.fromEntries([
...candidates.map(({ resourceId }) => [resourceId, revisionById.get(resourceId)]),
...policies.map(({ policyId }) => [policyId, revisionById.get(policyId)])
]),
confirmed: false
};
}

export const planGovernedContentActivation = planDocumentActivation;
export const activateGovernedContent = activateDocuments;
export async function planGovernedContentActivation(input = process.cwd(), options = {}) {
if (options.policyIds === undefined) return planDocumentActivation(input, options);
if (options.auditId) throw new Error("Program content activation cannot include Audit Documents. Use Step 5 activation.");
const policyIds = [...new Set((options.policyIds || []).map(String))];
const resourceIds = [...new Set((options.resourceIds || options.documentIds || []).map(String))];
if (!policyIds.length && !resourceIds.length) throw new Error("Select at least one approved program content record to activate.");
const plans = [];
if (policyIds.length) {
const loaded = await loadWorkspace(input);
const readiness = await assessProgramReadiness(loaded, { programId: options.programId });
const eligible = new Set(readiness.policyActivations.filter(({ state }) => (
["approved-implementation-pending", "ready-to-activate"].includes(state)
)).map(({ policyId }) => policyId));
if (policyIds.some((id) => !eligible.has(id))) throw new Error("Every selected Policy must be approved and available for this Program's activation.");
plans.push(await planPolicyActivation(input, { ...options, policyIds }));
}
if (resourceIds.length) plans.push(await planDocumentActivation(input, { ...options, resourceIds }));
return {
operation: "governed-content-activation",
workflowScope: "program",
policyIds,
resourceIds: [...policyIds, ...resourceIds],
documentIds: plans.flatMap((plan) => plan.documentIds || []),
trainingIds: plans.flatMap((plan) => plan.trainingIds || []),
activatedByIds: options.activatedByIds || [],
activatedOn: options.activatedOn,
effectiveOn: options.effectiveOn,
changes: {
update: plans.flatMap((plan) => plan.changes.update),
expectedRevisions: Object.assign({}, ...plans.map((plan) => plan.changes.expectedRevisions)),
validateWholeWorkspace: true
}
};
}

export async function activateGovernedContent(input = process.cwd(), options = {}) {
if (options.policyIds === undefined) return activateDocuments(input, options);
if (options.confirmed !== true) throw new Error("Review program content activation and confirm the write.");
return serializeWorkspaceMutation(input, async (root) => {
const plan = await planGovernedContentActivation(root, options);
const result = await applyGovernedContentActivationBatch(root, plan.changes);
return { ...plan, result };
});
}

function requireDocumentLifecycle(loaded) {
if (!modelSupports(loaded.model, "governed-document-activation")) {
Expand Down
Loading
Loading