Automated Control Check Catalog
Purpose. The machine-readable contract for Soon's home-grown GRC: each row is a
check the collectors run against a live system to produce evidence and a pass/fail.
The collectors
(built in the app/infra repo) read this catalog; the results flow to the S3 store and the
Evidence Register. Supports 9.1,
A.8.16, A.5.36.
Status: DRAFT โ the seed set. ~25 checks grounded in Soon's real stack (AWS eu-west-1,
GitHub, Google Workspace, WorkOS, Aikido, GetAgency). Thresholds marked (policy) are
decisions for the owner, aligned to the relevant policy. Grow the catalog as collectors
are built. Review quarterly.
Modes: ๐ค API collector (auto) ยท ๐ AI drift-scan ยท โ๏ธ manual attestation.
Each check's evidence artefact lands in the S3 store keyed by control (see
ISMS-DOC-07-7 ยง4.5).
Check schema (what a collector consumes)
Each check is defined by these fields (illustrative YAML โ the executable copy lives with
the collectors, not in this repo):
- id: CHK-BACKUP-01
controls: [A.8.13]
proves: "RDS automated backups + PITR enabled on all production databases"
target: aws.rds
method: "rds:DescribeDBInstances" # read-only
register_ref: A.8.13 # the Evidence Register row this rolls up to
pass_if: "every prod instance BackupRetentionPeriod >= 7" # (policy)
artefact: json # saved to S3, hashed, manifested
cadence: daily
mode: api
owner: Melvin
A. API collectors โ AWS ๐ค
| Check ID |
Control(s) |
What it proves |
Target ยท method (read-only) |
Pass predicate |
Cadence |
| CHK-BACKUP-01 |
A.8.13 |
RDS automated backups + PITR on prod DBs |
rds:DescribeDBInstances (+ DescribeDBClusters if Aurora) |
every prod instance/cluster BackupRetentionPeriod โฅ 7 (policy) |
daily |
| CHK-ENC-01 |
A.8.24 |
RDS storage encrypted at rest (AES-256) |
rds:DescribeDBInstances (+ DescribeDBClusters) |
StorageEncrypted = true on all prod instances/clusters |
daily |
| CHK-ENC-02 |
A.8.24, A.5.33 |
S3 buckets default-encrypted (incl. evidence store) |
s3api get-bucket-encryption |
SSE-KMS/AES256 on every in-scope bucket |
daily |
| CHK-PUB-01 |
A.5.23, A.8.20 |
S3 Block Public Access on (account + buckets) |
account: s3control get-public-access-block --account-id; bucket: s3api get-public-access-block --bucket |
all four flags true at both scopes |
daily |
| CHK-MFA-01 |
A.5.17, A.8.5 |
MFA on all IAM console users + root |
iam generate-credential-report |
mfa_active = true for all console users; root MFA on |
weekly |
| CHK-KEY-01 |
A.5.16, A.8.2 |
No stale IAM access keys |
iam generate-credential-report |
max active key age โค 90d (policy) |
weekly |
| CHK-LOG-01 |
A.8.15 |
CloudTrail logging on, multi-region, log-file validation |
cloudtrail describe-trails + get-trail-status |
IsMultiRegionTrail and LogFileValidationEnabled true and IsLogging = true (recent LatestDeliveryTime) |
daily |
| CHK-NET-01 |
A.8.20, A.8.22 |
No security group opens sensitive ports to the world |
ec2 describe-security-groups |
no 0.0.0.0/0 or ::/0 ingress on 22/3306/5432/โฆ |
daily |
| CHK-MON-01 |
A.8.16 |
CloudWatch alarms exist for prod health |
cloudwatch describe-alarms |
key alarms present, none in INSUFFICIENT_DATA |
weekly |
| CHK-MON-02 |
A.8.15 |
Log retention configured on prod log groups |
logs describe-log-groups |
retentionInDays set on all prod groups |
monthly |
B. API collectors โ GitHub ๐ค
| Check ID |
Control(s) |
What it proves |
Target ยท method (read-only) |
Pass predicate |
Cadence |
| CHK-SDLC-01 |
A.8.4, A.8.28, A.8.32 |
main protected โ PR review + status checks |
GET repos/{o}/{r}/branches/main/protection |
required_pull_request_reviews โฅ 1; required_status_checks on |
daily |
| CHK-SDLC-02 |
A.8.28, A.8.25 |
Code + secret scanning enabled |
code-scanning / secret-scanning APIs |
enabled on all in-scope prod repos |
weekly |
| CHK-VULN-01 |
A.8.8 |
Dependency alerts on; no criticals past SLA |
Dependabot alerts API |
no open critical alert older than SLA (policy) |
daily |
| CHK-CHG-01 |
A.8.32 |
No direct pushes to main (change goes via PR) |
commits + protection API |
0 non-PR commits to main in window |
weekly |
| CHK-ACC-GH-01 |
A.5.15, A.5.18 |
GitHub org members + admins (access-review input) |
GET orgs/{o}/members, teams |
list exported for quarterly review; no unknown admins |
quarterly |
C. API collectors โ Identity, SaaS & external scans ๐ค
| Check ID |
Control(s) |
What it proves |
Target ยท method (read-only) |
Pass predicate |
Cadence |
| CHK-ACC-GW-01 |
A.5.18 |
Google Workspace users + admin roles (access review) |
Admin SDK Directory users.list |
exported for review; suspended leavers not active |
quarterly |
| CHK-MFA-GW-01 |
A.5.16, A.5.17 |
Google Workspace 2-Step Verification on all users |
Admin SDK users.list (isEnforcedIn2Sv) |
every active non-exempt user isEnforcedIn2Sv = true; the enforcement policy itself via โ๏ธ attestation |
monthly |
| CHK-SSO-01 |
A.5.16 |
WorkOS enterprise SSO connections active |
WorkOS API (connections) |
expected tenant connections active |
monthly |
| CHK-VULN-02 |
A.8.8 |
Aikido scan โ open criticals within SLA |
Aikido API / export |
no open critical finding past SLA (policy) |
weekly |
| CHK-TLS-01 |
A.8.24 |
Public endpoints enforce TLS 1.2+ |
external TLS scanner (testssl / SSL Labs) of Soon domains |
grade โฅ A; TLS 1.2+ only, no weak ciphers |
weekly |
D. Semi-automated / AI drift-scan ๐
| Check ID |
Control(s) |
What it proves |
Method |
Pass predicate |
Cadence |
| CHK-DRIFT-01 |
A.8.24, A.8.5 |
Code/IaC still matches crypto + auth policy (TLS 1.2+, AES-256, MFA) |
scheduled evidence-scan.md run in app/infra repo |
no โ/๐ฉ findings; โ ๏ธ triaged |
weekly |
| CHK-DRIFT-02 |
A.8.31, A.8.33 |
Prod/staging/dev separation; non-prod uses masked/synthetic data |
AI drift-scan of IaC + config |
staging not sharing prod data (Q6) |
monthly |
| CHK-JML-01 |
A.5.18, A.6.5 |
Leaver access revoked within SLA |
compare Linear leaver tickets vs access lists (CHK-ACC-*) |
revoked โค 24h (policy) of leave date |
on event |
E. Manual attestations โ๏ธ (no API โ the GRC tracks that they're due)
| Check ID |
Control(s) |
What it proves |
Method |
Pass predicate |
Cadence |
| CHK-BCP-01 |
A.8.13, A.5.30 |
Backup restore test performed & passed |
Melvin runs restore, records result |
current-period restore test passed (Q5 โ never done yet) |
annual |
| CHK-TRN-01 |
A.6.3, 7.2 |
Security training completed by all staff |
/isms:onboard log |
all staff current on the refresher |
quarterly |
| CHK-HR-01 |
A.6.1, A.6.6 |
Signed NDAs + screening on file |
HR store check |
100% of staff on file |
on join |
| CHK-VEN-01 |
A.5.19โA.5.23 |
Supplier SOC 2 reports + DPAs current |
vendor register review |
current reports/DPAs for AWS, Stripe, etc. on file |
annual |
| CHK-PEN-01 |
A.8.8, A.8.29 |
Current pentest on file + remediation tracked |
GetAgency report + Linear |
current-year pentest present; findings tracked |
annual |
| CHK-MGT-01 |
9.3 |
Management review held & recorded |
meeting-log / review minutes |
at least one review this period |
annual |
How results flow
- A collector runs a check โ produces the artefact +
pass/fail/error.
- Artefact โ S3 evidence store (hashed, manifested per
ISMS-FORM-07-3).
- Collector opens a PR to this repo: updates the matching
Evidence Register row
(Last collected, Status) and appends a CCM results line.
fail / drift โ alert to Slack #security; a human fixes (never auto-remediated).
Mapping key. Each check carries a register_ref (the primary control in its
Control(s) column) = the Evidence Register
row it rolls up to. Per-check history lives in the collector's results.json; the
register row shows the control-level roll-up (the worst status of its checks).
Flags for the owner
- Thresholds marked (policy) (key age, vuln SLAs, restore RPO) โ set them to match
the relevant policy. Set 2026-08-13: vulnerability SLAs Critical 7d / High 30d /
Medium 90d; IAM key age 90 days; backup retention 30 days; log retention 90 days (app)
and 1 year (audit).
- In-scope resource lists (which S3 buckets, prod DBs, repos, domains) โ the collectors
need an explicit scope.
TODO(owner: Thomas/Melvin).
- Coverage is partial by design โ people/process controls (ยงE) stay attestation-based.
Don't report the ISMS as "100% automated"; report auto-covered vs attested.
- Prod data engine = AWS RDS MySQL (
rds-soon-soon-prod, verified in AWS 2026-08-08, per the
Asset Inventory).
Soon does not use Supabase (owner-confirmed) โ CHK-BACKUP-01/ENC-01 (RDS) cover the
production stores. Add DescribeDBClusters too only if any Aurora clusters are introduced.
Change log
| Version |
Date |
Author |
Comments |
| 0.1 |
2026-07-12 |
ISMS |
First draft โ seed catalog of ~25 checks across AWS/GitHub/Workspace/WorkOS/Aikido + AI drift-scans + manual attestations, with check schema, pass predicates and result flow. |