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
12 changes: 10 additions & 2 deletions docs/data-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ Key format: `namespace`.
| `statuses` | array of string | No | |
| `criticalities` | array of enum | No | Values: `low`, `medium`, `high`, `critical` |
| `membershipMode` | enum | Yes | Values: `as-of` |
| `cutoff` | enum | Yes | Values: `window-start`, `window-end` |
| `cutoff` | enum | Yes | Values: `window-start`, `window-end`, `review-date`, `coverage-end` |

### `obligation-member`

Expand Down Expand Up @@ -1402,6 +1402,7 @@ Markdown companions:
| `evidenceIds` | array of id | No | References: `evidence` |
| `scheduledFor` | date | Yes | Scheduled for |
| `cancellation` | object (`cancellation`) | Conditional | Required when `status` is `canceled`. Allowed when `status` is `canceled`. |
| `coverage` | object (`coverage-period`) | No | Work coverage |

At least one of `attendeeIds`, `externalAttendees` is required when `status` is `complete`.

Expand Down Expand Up @@ -2246,6 +2247,7 @@ Record Markdown: shown by default as an implicit companion file.
| `reviewedOn` | date | Conditional | Required when `status` is `complete`. Allowed when `status` is `complete`. |
| `scheduledFor` | date | No | Scheduled for |
| `componentIds` | array of id | No | Components References: `component` |
| `coverage` | object (`coverage-period`) | No | Work coverage |

#### `incident`

Expand Down Expand Up @@ -2367,6 +2369,7 @@ Record Markdown: shown by default as an implicit companion file.
| `scheduledFor` | date | Yes | Scheduled for |
| `cancellation` | object (`cancellation`) | Conditional | Required when `status` is `canceled`. Allowed when `status` is `canceled`. |
| `componentIds` | array of id | No | Components References: `component` |
| `coverage` | object (`coverage-period`) | No | Work coverage |

#### `backup-test`

Expand Down Expand Up @@ -2405,6 +2408,7 @@ Record Markdown: shown by default as an implicit companion file.
| `scheduledFor` | date | No | Scheduled for |
| `cancellation` | object (`cancellation`) | Conditional | Required when `status` is `canceled`. Allowed when `status` is `canceled`. |
| `componentIds` | array of id | No | Components References: `component` |
| `coverage` | object (`coverage-period`) | No | Work coverage |

### Evidence

Expand Down Expand Up @@ -2555,6 +2559,7 @@ Record Markdown: shown by default as an implicit companion file.
| `externalActivity` | object (`external-activity-reference`) | Conditional | Required when `status` is `externally-managed`. Allowed when `status` is `externally-managed`. |
| `ownerIds` | array of id | Yes | Owners Relation group: `accountable-party`. References: `person`, `team`, `appointment` |
| `cancellation` | object (`cancellation`) | Conditional | Required when `status` is `canceled`. Allowed when `status` is `canceled`. |
| `coverage` | object (`coverage-period`) | No | Work coverage |

### Issues and Remediation

Expand Down Expand Up @@ -2719,10 +2724,11 @@ Record Markdown: available when needed as an implicit companion file.
| `approvedOn` | date | Conditional | Required when `status` is one of `approved`, `active`, `retired`. |
| `effectiveAt` | timestamp | Conditional | Required when `status` is one of `active`, `retired`. |
| `timezone` | string (timezone) | Conditional | Required when `status` is one of `approved`, `active`, `retired`. |
| `cutoverDecision` | enum | No | Values: `new-windows-only`, `supersede-open-window`, `keep-open-window` |
| `cutoverDecision` | enum | No | Values: `new-windows-only`, `supersede-open-window`, `keep-open-window`, `correct-open-window` |
| `supersedesId` | id | No | References: `obligation-rule` |
| `retiredOn` | date | Conditional | Required when `status` is `retired`. |
| `preparationPurpose` | enum | No | Preparation purpose Values: `operation`, `applicability-review`, `test-execution` |
| `completionCoverage` | enum | No | Required proof coverage Values: `point-in-time`, `whole-period` |

#### `obligation-occurrence`

Expand Down Expand Up @@ -2761,6 +2767,8 @@ Record Markdown: shown by default as an implicit companion file.
| `auditPopulationIds` | array of id | No | References: `audit-population` |
| `ownerIds` | array of id | Yes | Relation group: `accountable-party`. References: `person`, `team`, `appointment` |
| `programId` | id | Yes | References: `program` |
| `requiredCoverage` | object (`coverage-period`) | No | Required proof coverage |
| `populationSourceRevision` | string | No | Recorded population source commit |

### Audits

Expand Down
34 changes: 34 additions & 0 deletions docs/obligation-population-timing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Obligation populations and work coverage

A recurring review or test can inspect conditions on one date. Its yearly or monthly cadence does not by itself require proof covering every day in that period. Management must choose the criterion that matches the actual governing procedure.

FileGRC 0.21 adds optional model v13 fields. Adopt the 0.21 dependency line and deploy tested readers before saving them. Earlier runtimes reject that dependency line. Unchanged prior workspaces keep their original rules and population cutoffs; installing this release does not convert them or require a model migration.

For a snapshot, set the rule's `completionCoverage` to `point-in-time` and selector `cutoff` to `review-date`. Supply `--population-as-of YYYY-MM-DD` when recording or scaffolding reconciliation. Use the actual population observation date, which may differ from the completion or edit date. A new same-day snapshot binds committed source scope. Commit that occurrence on its observation date to retain contemporaneous proof; later historical recording uses the temporal Collection Review route. A past snapshot needs an immutable temporal Collection Review, or the supported correction below backed by retained occurrence rows. Do not infer historical populations from today's inventory.

For a whole-period duty, set `completionCoverage` to `whole-period`. The required range runs from the recurrence cycle's first day through the day before the next cycle, separately from the allowed execution window. Set an allowed window that permits work after that period ends. Completion proof must state an explicit `coverage` range containing the entire required range, with actual execution after its full inclusive final day. A point result or early test cannot satisfy it. Selector `coverage-end` keeps the population open through that required period's inclusive end. Existing window-start and window-end cutoffs retain their inclusive behavior.

When every current member has valid proof or a reviewed disposition but the population or required period remains open, Work Queue shows Waiting with its original deadline and cutoff or period end. Even zero or non-applicable populations wait until a whole-period duty ends. New eligible or unresolved members restore actionable work. Waiting suppresses due reminders, while period and audit completeness still require final population reconciliation. The day after a fixed cutoff, reconcile the final population; FileGRC does not silently close it.

## Correct an inappropriate open snapshot rule

Use this route only when the actual duty was a point review or test. It does not remove an explicit whole-period duty, postpone a deadline, expand proof scope, or approve independent schedule oversight.

```sh
npx filegrc correct-obligation-rule RULE_ID --scaffold --json > correction.json
```

Fill the successor title and rationale, actual current `approvedByIds`, `approvedOn` and `effectiveAt`, and both confirmations. In `corrections`, select supported open occurrences and their actual `populationAsOf` dates. Keep `sourceRevision` and `expectedRevisions` unchanged. The successor preserves frequency, anchor, allowed window and selector filters. Its source occurrence and all prior approvals remain auditable. The correction retains passed, failed, exception and non-applicable rows, plus proof links. Known eligible additions enter as pending work.

```sh
npx filegrc correct-obligation-rule RULE_ID correction.json --preview --json > preview.json
```

Review every resulting date, member disposition, proof link and new pending member. Copy the preview's `revision` into the payload's `confirmedRevision`, then apply the unchanged payload:

```sh
npx filegrc correct-obligation-rule RULE_ID correction.json --yes --json
npx filegrc reconcile-obligation OBLIGATION_ID --scaffold --window-start ORIGINAL_START --json > occurrence.json
```

Review and fill the normal reconciliation conclusion, reviewers and actual reconciliation time. Save that mutation through `reconcile-obligation`, validate, and inspect the Git diff before committing. Keep original operating records byte-for-byte unchanged when their work facts remain accurate. A limited recovery test continues to prove only the recovery scope it actually tested.
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.20.8",
"version": "0.21.0",
"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.20.8",
"version": "0.21.0",
"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/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,7 @@ export function baselineRecordFiles(effectiveDate, starter = "security") {
? { ...obligation.recurrence, anchorDate: effectiveDate }
: obligation.recurrence,
...(obligation.window ? { window: obligation.window } : {}),
...(starterObligationSelector(obligation.id) ? { selector: starterObligationSelector(obligation.id) } : {}),
...(starterObligationSelector(obligation.id) ? { selector: starterObligationSelector(obligation.id), completionCoverage: "point-in-time" } : {}),
...(obligation.id === "obligation-annual-penetration-test" ? { preparationPurpose: "applicability-review" }
: ["backup-test", "exercise", "penetration-test", "vulnerability-scan", "security-scan", "alert-path-test"].includes(obligation.activityType) ? { preparationPurpose: "test-execution" } : {}),
rationale: starterObligationRationale(obligation.id),
Expand Down Expand Up @@ -1221,7 +1221,7 @@ function starterObligationSelector(obligationId) {
return definition ? {
...definition,
membershipMode: "as-of",
cutoff: "window-end"
cutoff: obligationId === "obligation-annual-critical-vendor-review" ? "window-end" : "review-date"
} : null;
}

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.20.8",
version: "0.21.0",
lockfileVersion: 3,
requires: true,
packages: {
"": {
name,
version: "0.20.8",
version: "0.21.0",
dependencies: { filegrc: versionRange }
}
}
Expand Down
2 changes: 2 additions & 0 deletions packages/create-filegrc/template/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ Program records, owners, Person email addresses, and dates remain authoritative

Run `npx filegrc obligations --json` to see scheduled work, event tasks, owners, deadlines, and requested proof. In Step 4, record the work shown there. Use `npx filegrc guide obligation --json` and `data/AGENTS.md` for the completion and event-trigger commands. The resulting dated operating record or completed Action Item is the output.

A periodic review or test may inspect a point in time without claiming continuous coverage. Read [Obligation population timing](https://github.com/Alignbase/filegrc/blob/main/docs/obligation-population-timing.md) before choosing `completionCoverage` and selector cutoff. A `review-date` snapshot requires the actual `--population-as-of` observation date and committed scope. A `whole-period` duty requires explicit proof range coverage after the recurrence period ends. Preserve existing end-cutoff campaigns and unfinished members. Waiting means current member work is recorded but the population is still open; final reconciliation remains required. Use `npx filegrc correct-obligation-rule RULE_ID --scaffold --json` for a reviewed successor correcting an inappropriate open snapshot rule, preserving the original window, proofs and approvals. Upgrade local and hosted readers to the 0.21 line before adopting these optional model v13 fields.

## Headless Markdown

Create and update JSON plus Markdown in one mutation envelope when practical. You can also inspect or replace a companion directly:
Expand Down
2 changes: 2 additions & 0 deletions packages/create-filegrc/template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,5 @@ Your team performs the control work and reviews responses before submission. An
For a nonmaterial administrative correction, choose **Nonmaterial amendment** on a supported record page or run `npx filegrc amend-nonmaterial RESOURCE_ID --scaffold`. The owner can correct an administrative label or a verified equivalent reporting email alias while preserving the original record and approval. Changes to commitments, recipients, access, scope, schedules, governed content or evidence conclusions keep their normal reviews.

The nonmaterial amendment workflow is available from FileGRC 0.19.0 with model v13. Existing workspaces need no model migration. The 0.19 runtime also reads existing 0.18 workspaces; 0.18 runtimes reject repositories pinned to 0.19, so hosted services must approve and install the new runtime before owners adopt these records.

Periodic reviews, population cutoffs, and whole-period proof have separate meanings. See the [Obligation population timing guide](https://github.com/Alignbase/filegrc/blob/main/docs/obligation-population-timing.md) before choosing or correcting a schedule.
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.20.8",
"version": "0.21.0",
"private": true,
"description": "filegrc workspace for a SOC 2 program",
"type": "module",
Expand Down
63 changes: 60 additions & 3 deletions packages/filegrc/model/v13.json
Original file line number Diff line number Diff line change
Expand Up @@ -4380,6 +4380,13 @@
"allowedWhen": {
"status": "canceled"
}
},
"coverage": {
"type": "object",
"required": false,
"label": "Work coverage",
"description": "The actual date or period inspected by this work. A whole-period duty requires an explicit range covering its required period; a completed test does not imply future coverage.",
"objectType": "coverage-period"
}
},
"listFields": [
Expand Down Expand Up @@ -6020,6 +6027,13 @@
"component"
],
"label": "Components"
},
"coverage": {
"type": "object",
"required": false,
"label": "Work coverage",
"description": "The actual date or period inspected by this work. A whole-period duty requires an explicit range covering its required period; a completed test does not imply future coverage.",
"objectType": "coverage-period"
}
},
"listFields": [
Expand Down Expand Up @@ -6342,6 +6356,13 @@
"component"
],
"label": "Components"
},
"coverage": {
"type": "object",
"required": false,
"label": "Work coverage",
"description": "The actual date or period inspected by this work. A whole-period duty requires an explicit range covering its required period; a completed test does not imply future coverage.",
"objectType": "coverage-period"
}
},
"listFields": [
Expand Down Expand Up @@ -6481,6 +6502,13 @@
"component"
],
"label": "Components"
},
"coverage": {
"type": "object",
"required": false,
"label": "Work coverage",
"description": "The actual date or period inspected by this work. A whole-period duty requires an explicit range covering its required period; a completed test does not imply future coverage.",
"objectType": "coverage-period"
}
},
"listFields": [
Expand Down Expand Up @@ -8465,6 +8493,13 @@
"allowedWhen": {
"status": "canceled"
}
},
"coverage": {
"type": "object",
"required": false,
"label": "Work coverage",
"description": "The actual date or period inspected by this work. A whole-period duty requires an explicit range covering its required period; a completed test does not imply future coverage.",
"objectType": "coverage-period"
}
},
"listFields": [
Expand Down Expand Up @@ -9030,7 +9065,8 @@
"values": [
"new-windows-only",
"supersede-open-window",
"keep-open-window"
"keep-open-window",
"correct-open-window"
]
},
"supersedesId": {
Expand All @@ -9054,6 +9090,15 @@
],
"label": "Preparation purpose",
"description": "Classify the adopted work. A review decides applicability or cadence; test execution needs a real result for the declared population."
},
"completionCoverage": {
"type": "enum",
"values": [
"point-in-time",
"whole-period"
],
"label": "Required proof coverage",
"description": "Point-in-time work is executed within the allowed window. Whole-period work must prove the complete recurrence period, separately from its allowed execution window."
}
},
"listFields": [
Expand Down Expand Up @@ -9202,6 +9247,15 @@
"relation": [
"program"
]
},
"requiredCoverage": {
"type": "object",
"objectType": "coverage-period",
"label": "Required proof coverage"
},
"populationSourceRevision": {
"type": "string",
"label": "Recorded population source commit"
}
},
"listFields": [
Expand Down Expand Up @@ -11151,8 +11205,11 @@
"type": "enum",
"values": [
"window-start",
"window-end"
]
"window-end",
"review-date",
"coverage-end"
],
"description": "window-start and window-end use inclusive calendar boundaries. review-date freezes an explicitly observed snapshot on its actual date. coverage-end uses the required whole-period proof boundary."
}
}
},
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.20.8",
"version": "0.21.0",
"description": "Zero-dependency Git-native GRC engine",
"license": "MIT",
"repository": {
Expand Down
Loading
Loading