@metasession.co/devaudit-cli 0.1.29 → 0.1.31

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.
@@ -0,0 +1,218 @@
1
+ # Periodic Review — quarterly auto-generation of compliance/governance/periodic-review.md
2
+ #
3
+ # Generated by `devaudit install` / `devaudit update` from sdlc-config.json.
4
+ # Do not edit manually — re-run the CLI (`devaudit update`) to regenerate.
5
+ #
6
+ # Why this exists:
7
+ # - SOC 2 CC4.1 (Monitoring of internal controls) and ISO 27001 A.12.1
8
+ # (Operational procedures and responsibilities) require periodic
9
+ # review of controls + procedures. The portal flags `periodic_review`
10
+ # evidence as `expired` after 365 days.
11
+ # - The v0.1.30 starter at compliance/governance/periodic-review.md
12
+ # covers the operator's first attestation. This workflow auto-
13
+ # regenerates it quarterly with locally-derived metrics + a clearly-
14
+ # marked "Review notes (operator fills in)" section, opens a PR so
15
+ # a human reviews + approves before it lands on develop, then
16
+ # compliance-evidence.yml uploads it as `periodic_review` evidence.
17
+ #
18
+ # DevAudit-Installer#98 WS3.
19
+
20
+ name: Periodic Review
21
+
22
+ on:
23
+ schedule:
24
+ # Quarterly: 1st of Jan / Apr / Jul / Oct at 09:00 UTC.
25
+ - cron: '0 9 1 */3 *'
26
+ workflow_dispatch:
27
+
28
+ permissions:
29
+ contents: write
30
+ pull-requests: write
31
+
32
+ jobs:
33
+ generate:
34
+ name: Generate quarterly periodic-review.md
35
+ runs-on: ubuntu-latest
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ with:
39
+ fetch-depth: 0
40
+ # Need write access for the chore branch.
41
+ token: ${{ secrets.DEVAUDIT_USER_TOKEN || github.token }}
42
+
43
+ - name: Compute review period
44
+ id: period
45
+ run: |
46
+ # End of period = today. Start = ~90 days back (rough quarter).
47
+ PERIOD_END=$(date -u +%Y-%m-%d)
48
+ PERIOD_START=$(date -u -d '90 days ago' +%Y-%m-%d)
49
+ REVIEW_ID=$(date -u +%Y-Q%q 2>/dev/null || date -u +%Y-%m)
50
+ BRANCH="chore/periodic-review-${REVIEW_ID//[^A-Za-z0-9-]/-}"
51
+ echo "period_start=${PERIOD_START}" >> "$GITHUB_OUTPUT"
52
+ echo "period_end=${PERIOD_END}" >> "$GITHUB_OUTPUT"
53
+ echo "review_id=${REVIEW_ID}" >> "$GITHUB_OUTPUT"
54
+ echo "branch=${BRANCH}" >> "$GITHUB_OUTPUT"
55
+
56
+ - name: Derive metrics from repo state
57
+ id: metrics
58
+ env:
59
+ GH_TOKEN: ${{ github.token }}
60
+ PERIOD_START: ${{ steps.period.outputs.period_start }}
61
+ run: |
62
+ # Counts come from local state — no portal API call needed.
63
+ # The portal can render against its own data; this summary is
64
+ # for the operator's review-and-attest moment.
65
+ RTM_REQS=0
66
+ PENDING_RELEASES=0
67
+ APPROVED_RELEASES=0
68
+ INCIDENT_REPORTS=0
69
+ if [ -f compliance/RTM.md ]; then
70
+ RTM_REQS=$(grep -oE '^\| REQ-[0-9]+ ' compliance/RTM.md | wc -l | tr -d ' ')
71
+ fi
72
+ if [ -d compliance/pending-releases ]; then
73
+ PENDING_RELEASES=$(find compliance/pending-releases -maxdepth 1 -name 'RELEASE-TICKET-REQ-*.md' -type f 2>/dev/null | wc -l | tr -d ' ')
74
+ fi
75
+ if [ -d compliance/approved-releases ]; then
76
+ APPROVED_RELEASES=$(find compliance/approved-releases -maxdepth 1 -name 'RELEASE-TICKET-REQ-*.md' -type f 2>/dev/null | wc -l | tr -d ' ')
77
+ fi
78
+ if [ -d compliance/governance ]; then
79
+ INCIDENT_REPORTS=$(find compliance/governance -maxdepth 1 -name 'incident-report*.md' -type f 2>/dev/null | wc -l | tr -d ' ')
80
+ fi
81
+ # CI pass-rate over the period — best-effort via gh.
82
+ CI_RUNS=$(gh run list --branch develop --limit 100 --json conclusion,createdAt 2>/dev/null || echo '[]')
83
+ TOTAL_RUNS=$(echo "$CI_RUNS" | jq --arg since "${PERIOD_START}T00:00:00Z" '[.[] | select(.createdAt >= $since)] | length' 2>/dev/null || echo 0)
84
+ PASSED_RUNS=$(echo "$CI_RUNS" | jq --arg since "${PERIOD_START}T00:00:00Z" '[.[] | select(.createdAt >= $since and .conclusion == "success")] | length' 2>/dev/null || echo 0)
85
+ PASS_RATE="n/a"
86
+ if [ "$TOTAL_RUNS" -gt 0 ]; then
87
+ PASS_RATE="$((100 * PASSED_RUNS / TOTAL_RUNS))%"
88
+ fi
89
+ {
90
+ echo "rtm_reqs=${RTM_REQS}"
91
+ echo "pending_releases=${PENDING_RELEASES}"
92
+ echo "approved_releases=${APPROVED_RELEASES}"
93
+ echo "incident_reports=${INCIDENT_REPORTS}"
94
+ echo "ci_total=${TOTAL_RUNS}"
95
+ echo "ci_passed=${PASSED_RUNS}"
96
+ echo "ci_pass_rate=${PASS_RATE}"
97
+ } >> "$GITHUB_OUTPUT"
98
+
99
+ - name: Render periodic-review.md
100
+ env:
101
+ PERIOD_START: ${{ steps.period.outputs.period_start }}
102
+ PERIOD_END: ${{ steps.period.outputs.period_end }}
103
+ REVIEW_ID: ${{ steps.period.outputs.review_id }}
104
+ RTM_REQS: ${{ steps.metrics.outputs.rtm_reqs }}
105
+ PENDING_RELEASES: ${{ steps.metrics.outputs.pending_releases }}
106
+ APPROVED_RELEASES: ${{ steps.metrics.outputs.approved_releases }}
107
+ INCIDENT_REPORTS: ${{ steps.metrics.outputs.incident_reports }}
108
+ CI_TOTAL: ${{ steps.metrics.outputs.ci_total }}
109
+ CI_PASSED: ${{ steps.metrics.outputs.ci_passed }}
110
+ CI_PASS_RATE: ${{ steps.metrics.outputs.ci_pass_rate }}
111
+ run: |
112
+ mkdir -p compliance/governance
113
+ cat > compliance/governance/periodic-review.md <<EOF
114
+ ---
115
+ title: "Periodic Review of Internal Controls (${REVIEW_ID})"
116
+ period_start: "${PERIOD_START}"
117
+ period_end: "${PERIOD_END}"
118
+ reviewer: "REPLACE — name + role"
119
+ last_reviewed_at: "${PERIOD_END}"
120
+ review_cadence_days: 90
121
+ ---
122
+
123
+ > ℹ️ Auto-generated by Periodic Review workflow on ${PERIOD_END}.
124
+ > The CI-derived metrics below are filled in automatically. The
125
+ > **Review notes** and **Sign-off** sections still require the
126
+ > human attestation — replace the REPLACE markers before merging
127
+ > this PR. Auditors will reject auto-generated stubs with no
128
+ > human attestation.
129
+
130
+ # Periodic Review of Internal Controls
131
+
132
+ **Framework coverage:** \`SOC2.CC4.1\` (Monitoring of internal controls), \`ISO27001.A.12.1\` (Operational procedures and responsibilities)
133
+
134
+ **Evidence type:** \`periodic_review\` · **Cadence:** every 90 days. The portal flags this evidence as \`expired\` after 365 days.
135
+
136
+ ## 1. Review period
137
+
138
+ - **From:** ${PERIOD_START}
139
+ - **To:** ${PERIOD_END}
140
+ - **Reviewer:** REPLACE — name + role
141
+ - **Approver (different person, dual-actor):** REPLACE
142
+
143
+ ## 2. Activity summary (auto-derived from repo state)
144
+
145
+ | Metric | Value |
146
+ | ----------------------------------------- | ------------------------- |
147
+ | Total tracked REQs in RTM | ${RTM_REQS} |
148
+ | Pending releases at period end | ${PENDING_RELEASES} |
149
+ | Approved releases (cumulative) | ${APPROVED_RELEASES} |
150
+ | Incident reports on disk | ${INCIDENT_REPORTS} |
151
+ | CI runs on \`develop\` (this period) | ${CI_TOTAL} |
152
+ | CI runs passing | ${CI_PASSED} |
153
+ | CI pass rate | ${CI_PASS_RATE} |
154
+
155
+ ## 3. Review notes (operator fills in)
156
+
157
+ REPLACE — qualitative observations about the period. What worked? What didn't? What follow-ups are required? Reference incident reports under \`compliance/governance/incident-report-*.md\` if any.
158
+
159
+ ## 4. Control-effectiveness judgement
160
+
161
+ REPLACE — for each material control area, document evidence + reviewer judgement:
162
+
163
+ - **Access control (ISO 27001 A.5.15):** REPLACE — effective / partially / not
164
+ - **Change management (ISO 27001 A.8.32 / SOC 2 CC8.1):** REPLACE
165
+ - **Security testing (ISO 27001 A.8.29):** REPLACE
166
+ - **Logging and monitoring (ISO 27001 A.8.16 / EUAIA Art. 12):** REPLACE
167
+ - **Operational procedures (ISO 27001 A.12.1):** REPLACE
168
+
169
+ ## 5. Follow-up actions
170
+
171
+ | # | Finding | Severity | Owner | Due | Issue |
172
+ | - | ------- | -------- | ----- | --- | ----- |
173
+ | 1 | REPLACE | REPLACE | REPLACE | REPLACE | REPLACE |
174
+
175
+ ## 6. Sign-off
176
+
177
+ | Role | Name | Date |
178
+ | -------------------------- | ------- | ------- |
179
+ | Reviewer | REPLACE | REPLACE |
180
+ | Approver (dual-actor) | REPLACE | REPLACE |
181
+ | Decision | REPLACE — controls effective / partially effective / not effective |
182
+
183
+ ---
184
+
185
+ _Source data: \`compliance/RTM.md\`, \`compliance/pending-releases/\`, \`compliance/approved-releases/\`, \`compliance/governance/incident-report-*.md\`, GitHub Actions runs on \`develop\` since ${PERIOD_START}._
186
+ EOF
187
+ echo "Generated compliance/governance/periodic-review.md"
188
+
189
+ - name: Open / update review PR
190
+ env:
191
+ GH_TOKEN: ${{ secrets.DEVAUDIT_USER_TOKEN || github.token }}
192
+ BRANCH: ${{ steps.period.outputs.branch }}
193
+ REVIEW_ID: ${{ steps.period.outputs.review_id }}
194
+ run: |
195
+ # Configure git for the bot commit.
196
+ git config user.name 'devaudit-bot'
197
+ git config user.email 'devaudit-bot@users.noreply.github.com'
198
+ # Branch from develop. If a branch from a prior failed run exists,
199
+ # blow it away and start fresh; we always regenerate from the latest
200
+ # repo state.
201
+ git fetch origin develop
202
+ git checkout -B "${BRANCH}" origin/develop
203
+ git add compliance/governance/periodic-review.md
204
+ if git diff --cached --quiet; then
205
+ echo "No change to periodic-review.md — nothing to do."
206
+ exit 0
207
+ fi
208
+ git commit -m "chore(compliance): periodic review ${REVIEW_ID} (auto-generated)" -m "Quarterly periodic-review.md regenerated by Periodic Review workflow." -m "" -m "REPLACE markers in the Review notes / Control-effectiveness / Sign-off sections require human attestation before this PR can merge."
209
+ git push --force-with-lease origin "${BRANCH}"
210
+ # Open PR (or update existing).
211
+ EXISTING=$(gh pr list --head "${BRANCH}" --json number --jq '.[0].number' || true)
212
+ if [ -z "$EXISTING" ]; then
213
+ gh pr create --base develop --head "${BRANCH}" \
214
+ --title "chore(compliance): periodic review ${REVIEW_ID}" \
215
+ --body "Auto-generated quarterly periodic-review for **${REVIEW_ID}** by the \`Periodic Review\` workflow.\n\n**Required before merge:**\n- [ ] Replace \`REPLACE — …\` markers in the **Review notes** section\n- [ ] Fill in control-effectiveness judgement for each control area\n- [ ] Add reviewer + approver names (dual-actor)\n- [ ] List follow-up actions with owners + dates\n\nSee [\`docs/governance-templates.md\`](https://github.com/metasession-dev/DevAudit-Installer/blob/main/docs/governance-templates.md#soc-2--trust-services-criteria) (SDLC repo) for guidance.\n\nCloses \`SOC2.CC4.1\` + \`ISO27001.A.12.1\` for the period once the PR lands on develop."
216
+ else
217
+ echo "PR #${EXISTING} already open for this period — branch updated in place."
218
+ fi