getreadystack commited on
Commit
a510a00
·
verified ·
1 Parent(s): 06ebcae

Upload index.html with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +225 -17
index.html CHANGED
@@ -1,19 +1,227 @@
1
  <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
  <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>Audit Log Retention Lint (PCI DSS, CERT-In) — free online check</title>
7
+ <style>
8
+ :root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}
9
+ .wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px}
10
+ textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box}
11
+ .bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer}
12
+ input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}
13
+ table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65}
14
+ .sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}
15
+ .note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa}
16
+ </style>
17
+ <script defer data-auto-init src="https://cdn.jsdelivr.net/npm/@polar-sh/checkout@latest/dist/embed.global.js"></script>
18
+ <script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script>
19
+ <!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/audit-log-retention-lint"></head>
20
+ <body>
21
+ <div class="wrap">
22
+ <h1>Audit Log Retention Lint (PCI DSS, CERT-In)</h1>
23
+ <p class="lede">Flags log-retention values in Loki, CloudWatch, Elasticsearch ILM, S3 lifecycle and Kubernetes audit YAML that are shorter than PCI DSS 10.5.1, CERT-In 2022 or OMB M-21-31 require. Runs entirely in your browser — nothing is uploaded.</p>
24
+ <textarea id="src" spellcheck="false"># log-retention: pci-dss
25
+ # Grafana Loki (loki-config.yaml)
26
+ limits_config:
27
+ retention_period: 744h
28
+ retention_stream:
29
+ - selector: '{namespace="payments"}'
30
+ priority: 1
31
+ period: 168h
32
+ compactor:
33
+ retention_enabled: true
34
+ ---
35
+ # CloudFormation: API audit log group
36
+ Resources:
37
+ ApiAuditLogGroup:
38
+ Type: AWS::Logs::LogGroup
39
+ Properties:
40
+ LogGroupName: /cde/api/audit
41
+ RetentionInDays: 30
42
+ AuditLogBucket:
43
+ Type: AWS::S3::Bucket
44
+ Properties:
45
+ BucketName: cde-audit-logs
46
+ LifecycleConfiguration:
47
+ Rules:
48
+ - Id: archive-then-expire
49
+ Status: Enabled
50
+ Transitions:
51
+ - StorageClass: GLACIER
52
+ TransitionInDays: 30
53
+ ExpirationInDays: 180
54
+ ---
55
+ # kube-apiserver static pod (excerpt)
56
+ spec:
57
+ containers:
58
+ - command:
59
+ - kube-apiserver
60
+ - --audit-log-path=/var/log/kubernetes/audit.log
61
+ - --audit-log-maxage=30
62
+ ---
63
+ # Elasticsearch ILM policy (YAML via ECK / Kibana API)
64
+ policy:
65
+ phases:
66
+ hot:
67
+ actions:
68
+ rollover:
69
+ max_age: 7d
70
+ delete:
71
+ min_age: 90d
72
+ actions:
73
+ delete: {}</textarea>
74
+ <div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>
75
+ <div id="out" aria-live="polite"></div>
76
+ <div id="paid"><strong>Free here:</strong> Every retention finding in the open YAML file, with the clause and the value that passes, no key needed. <strong>In the editor:</strong> Workspace evidence report: every log store's retention across all YAML files in one Markdown table (value, minimum, clause) for your QSA or auditor. — that part asks for a licence key. <a href="https://buy.polar.sh/polar_cl_73892EssmeKJZXapgXXgmOIMw47IdPQLP1lWX0gxfLm" data-polar-checkout data-polar-checkout-theme="light">Get the workspace evidence report — $29 once</a> · one licence key per person or team seat.</div>
77
+ <p class="note">Same engine as the VS Code extension, byte for byte.</p>
78
+ </div>
79
+ <script>var ALR_RULES = [
80
+ {"id": "loki-retention-period", "sev": "error", "target": "total", "title": "Loki retention_period shorter than the minimum", "where": "Grafana Loki limits_config / table_manager", "fix": "retention_period: 8760h (365 days) for PCI DSS; 4320h (180 days) for CERT-In; 21912h (913 days) for OMB M-21-31"},
81
+ {"id": "loki-stream-period", "sev": "error", "target": "total", "title": "Loki retention_stream period shorter than the minimum", "where": "Grafana Loki retention_stream selector", "fix": "period: 8760h, or drop the stream override for audit selectors"},
82
+ {"id": "log-group-retention-days", "sev": "error", "target": "total", "title": "Log group RetentionInDays shorter than the minimum", "where": "AWS::Logs::LogGroup, SAM, Serverless logRetentionInDays, Azure Log Analytics retentionInDays", "fix": "RetentionInDays: 365 (PCI DSS), 180 (CERT-In), 1096 (OMB M-21-31)"},
83
+ {"id": "gcp-bucket-retention-days", "sev": "error", "target": "total", "title": "Cloud Logging bucket retentionDays shorter than the minimum", "where": "Config Connector LoggingLogBucket spec.retentionDays", "fix": "retentionDays: 365 (PCI DSS), 180 (CERT-In), 913 (OMB M-21-31)"},
84
+ {"id": "ilm-delete-min-age", "sev": "error", "target": "total", "title": "ILM/ISM delete phase starts before the minimum", "where": "Elasticsearch ILM or OpenSearch ISM policy, delete phase min_age", "fix": "min_age: 365d on the delete phase (PCI DSS), 180d (CERT-In), 913d (OMB M-21-31)"},
85
+ {"id": "k8s-audit-log-maxage", "sev": "error", "target": "total", "title": "kube-apiserver --audit-log-maxage shorter than the minimum", "where": "kube-apiserver static pod manifest or kubeadm ClusterConfiguration extraArgs", "fix": "--audit-log-maxage=365, or ship the audit log to a store that keeps it 365 days"},
86
+ {"id": "s3-log-expiration", "sev": "error", "target": "total", "title": "S3 lifecycle expires log objects before the minimum", "where": "S3 LifecycleConfiguration ExpirationInDays / Expiration Days on a log or audit bucket", "fix": "ExpirationInDays: 365 or more (PCI DSS), 180 (CERT-In), 913 (OMB M-21-31)"},
87
+ {"id": "s3-cold-transition", "sev": "warn", "target": "hot", "title": "Logs move to an archive tier before the immediately-available window ends", "where": "S3 lifecycle Transition to GLACIER or DEEP_ARCHIVE", "fix": "TransitionInDays: 90 or later (PCI DSS 3 months immediately available); 365 or later for OMB M-21-31 active storage"},
88
+ {"id": "cert-in-region", "sev": "error", "target": "region", "title": "Log store region outside Indian jurisdiction", "where": "region / location keys when the file declares the cert-in profile", "fix": "ap-south-1 or ap-south-2 (AWS), asia-south1 or asia-south2 (GCP), centralindia / southindia / westindia (Azure)"}
89
+ ]
90
+ ;</script>
91
+ <script>/* Audit Log Retention Lint engine — one file for the VS Code extension and the web page. */
92
+ (function (root) {
93
+ var RULES = (typeof module !== 'undefined' && module.exports) ? require('./rules.json') : root.ALR_RULES;
94
+ var BY_ID = {};
95
+ RULES.forEach(function (r) { BY_ID[r.id] = r; });
96
+
97
+ // Minimums in days. total = keep at least this long; hot = immediately available (not archive tier).
98
+ var PROFILES = {
99
+ 'pci-dss': { label: 'PCI DSS v4.0.1 Req. 10.5.1', total: 365, hot: 90, clause: '10.5.1: audit log history at least 12 months, the most recent three months immediately available' },
100
+ 'cert-in': { label: 'CERT-In Directions of 28 April 2022, (iv)', total: 180, hot: 0, region: true, clause: '(iv): logs of all ICT systems kept for a rolling 180 days within Indian jurisdiction' },
101
+ 'm-21-31': { label: 'OMB M-21-31', total: 913, hot: 365, clause: 'M-21-31: 12 months active storage plus 18 months cold storage (30 months)' }
102
+ };
103
+ var INDIA = /^(ap-south-[12]|asia-south[12]|centralindia|southindia|westindia|jioindiacentral|jioindiawest)$/i;
104
+
105
+ function toDays(v) {
106
+ v = String(v).trim().replace(/^["']|["']$/g, '');
107
+ if (/^\d+(\.\d+)?$/.test(v)) return parseFloat(v);
108
+ var unit = { y: 365, w: 7, d: 1, h: 1 / 24, m: 1 / 1440, s: 1 / 86400, ms: 1 / 86400000 };
109
+ var re = /(\d+(?:\.\d+)?)(ms|y|w|d|h|m|s)/g, m, total = 0, seen = '';
110
+ while ((m = re.exec(v))) { total += parseFloat(m[1]) * unit[m[2]]; seen += m[0]; }
111
+ return seen && seen === v ? total : null;
112
+ }
113
+ function fmt(d) { return d >= 1 ? String(Math.round(d * 10) / 10) + ' days' : String(Math.round(d * 24 * 10) / 10) + ' hours'; }
114
+
115
+ function profilesOf(text, opts) {
116
+ var names = (opts && opts.profiles) || null;
117
+ var m = /^\s*#\s*log-retention\s*:\s*([a-z0-9 ,\-]+)$/im.exec(text);
118
+ if (!names && m) names = m[1].split(',').map(function (s) { return s.trim().toLowerCase(); });
119
+ names = (names || ['pci-dss']).filter(function (n) { return PROFILES[n]; });
120
+ return names.length ? names : ['pci-dss'];
121
+ }
122
+
123
+ function check(text, opts) {
124
+ var lines = String(text).split(/\r?\n/), findings = [];
125
+ var profs = profilesOf(text, opts).map(function (n) { return PROFILES[n]; });
126
+ var need = function (key) {
127
+ var best = null;
128
+ profs.forEach(function (p) { if (p[key] && (!best || p[key] > best[key])) best = p; });
129
+ return best;
130
+ };
131
+ function add(id, line, value, days, key) {
132
+ var p = need(key); if (!p || days === null || days === 0 || days >= p[key]) return;
133
+ var r = BY_ID[id];
134
+ findings.push({ check: id, sev: r.sev, line: line + 1,
135
+ msg: r.title + ': ' + value + ' = ' + fmt(days) + ', ' + p.label + ' needs ' + p[key] + ' days (' + p.clause + '). Fix: ' + r.fix + '.' });
136
+ }
137
+ var inIlmDelete = -1, inStream = -1, ilmIndent = 0, streamIndent = 0;
138
+ lines.forEach(function (raw, i) {
139
+ var line = raw.replace(/\s+#.*$/, '');
140
+ if (/^\s*#/.test(raw)) return;
141
+ var ind = raw.search(/\S/);
142
+ var m;
143
+ if (/^\s*"?delete"?\s*:\s*\{?\s*$/.test(line)) { inIlmDelete = i; ilmIndent = ind; }
144
+ else if (inIlmDelete >= 0 && ind <= ilmIndent && line.trim()) inIlmDelete = -1;
145
+ if (/^\s*-?\s*retention_stream\s*:/.test(line)) { inStream = i; streamIndent = ind; }
146
+ else if (inStream >= 0 && ind <= streamIndent && line.trim() && !/^\s*-/.test(line)) inStream = -1;
147
+
148
+ if ((m = /^\s*retention_period\s*:\s*(\S+)/.exec(line))) add('loki-retention-period', i, m[1], toDays(m[1]), 'total');
149
+ if (inStream >= 0 && (m = /^\s*-?\s*period\s*:\s*(\S+)/.exec(line))) add('loki-stream-period', i, m[1], toDays(m[1]), 'total');
150
+ if ((m = /^\s*-?\s*"?(RetentionInDays|retentionInDays|logRetentionInDays|retention_in_days)"?\s*:\s*"?(\d+)/.exec(line))) add('log-group-retention-days', i, m[1] + ': ' + m[2], toDays(m[2]), 'total');
151
+ if ((m = /^\s*-?\s*"?retentionDays"?\s*:\s*"?(\d+)/.exec(line))) add('gcp-bucket-retention-days', i, 'retentionDays: ' + m[1], toDays(m[1]), 'total');
152
+ if (inIlmDelete >= 0 && (m = /^\s*"?min_age"?\s*:\s*"?([0-9a-z.]+)/.exec(line))) add('ilm-delete-min-age', i, 'min_age: ' + m[1], toDays(m[1]), 'total');
153
+ if ((m = /audit-log-maxage["']?\s*[=:]\s*["']?(\d+)/.exec(line))) add('k8s-audit-log-maxage', i, 'audit-log-maxage ' + m[1], toDays(m[1]), 'total');
154
+ if ((m = /^\s*-?\s*"?ExpirationInDays"?\s*:\s*"?(\d+)/.exec(line)) || (m = /^\s*"?Expiration"?\s*:\s*\{?\s*"?Days"?\s*:\s*(\d+)/.exec(line))) {
155
+ var ctx = lines.slice(Math.max(0, i - 25), i + 1).join('\n');
156
+ if (/log|audit|trail|siem/i.test(ctx)) add('s3-log-expiration', i, 'expiration ' + m[1] + ' days', toDays(m[1]), 'total');
157
+ }
158
+ if ((m = /^\s*-?\s*"?TransitionInDays"?\s*:\s*"?(\d+)/.exec(line))) {
159
+ var near = lines.slice(Math.max(0, i - 3), i + 4).join('\n');
160
+ if (/StorageClass"?\s*:\s*"?(GLACIER|DEEP_ARCHIVE)\b/.test(near) && !/GLACIER_IR/.test(near)) add('s3-cold-transition', i, 'transition to archive after ' + m[1] + ' days', toDays(m[1]), 'hot');
161
+ }
162
+ if (need('region') && (m = /^\s*-?\s*"?(region|location|Region|Location)"?\s*:\s*"?([a-z]+[a-z0-9-]*\d?)"?\s*$/.exec(line)) && /\d|india/i.test(m[2]) && !INDIA.test(m[2])) {
163
+ var r = BY_ID['cert-in-region'];
164
+ findings.push({ check: 'cert-in-region', sev: r.sev, line: i + 1, msg: r.title + ': ' + m[1] + ': ' + m[2] + ' is outside India, CERT-In Directions of 28 April 2022, (iv) keep logs within Indian jurisdiction. Fix: ' + r.fix + '.' });
165
+ }
166
+ });
167
+ return { findings: findings, profiles: profs.map(function (p) { return p.label; }) };
168
+ }
169
+
170
+ var api = { engine: { check: check, toDays: toDays }, RULES: RULES, RULE_COUNT: RULES.length, PROFILES: PROFILES };
171
+ if (typeof module !== 'undefined' && module.exports) module.exports = api;
172
+ root.ALRENGINE = api;
173
+ })(typeof window !== 'undefined' ? window : globalThis);
174
+ </script>
175
+ <script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.
176
+ 'use strict';
177
+ function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'); }
178
+ function summaryLine(res) {
179
+ const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;
180
+ return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';
181
+ }
182
+ function toText(res, label) {
183
+ const f = (res && res.findings) || [];
184
+ const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];
185
+ f.forEach(function (x) { lines.push(' ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + ' ' + (x.line ? 'L' + x.line + ' ' : '') + (x.check || x.id || '') + ' ' + (x.msg || x.message || '')); });
186
+ return lines.join('\n');
187
+ }
188
+ function toHtml(res) {
189
+ const f = (res && res.findings) || [];
190
+ if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';
191
+ const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join('');
192
+ return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>';
193
+ }
194
+ var ALRREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };
195
+ if (typeof module !== 'undefined' && module.exports) module.exports = ALRREPORT;
196
+ else window.ALRREPORT = ALRREPORT;
197
+ </script>
198
+ <script>
199
+ (function(){
200
+ var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');
201
+ today.value=new Date().toISOString().slice(0,10);
202
+ function run(){ try { var res=window.ALRENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.ALRREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }
203
+ go.onclick=run; if (src.value.trim()) run();
204
+ })();
205
+ </script>
206
+
207
+
208
+ <section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://open-vsx.org/extension/readystack/audit-log-retention-lint" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'audit-log-retention-lint',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><a href="https://www.npmjs.com/package/@readystack/audit-log-retention-lint" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'audit-log-retention-lint',src:'npm',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://hub.docker.com/r/getreadystack/audit-log-retention-lint" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'audit-log-retention-lint',src:'docker',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">npx @readystack/audit-log-retention-lint &lt;file&gt;
209
+ docker run --rm -v &quot;$PWD:/w&quot; getreadystack/audit-log-retention-lint /w</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://buy.polar.sh/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
210
+ <section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get the full rule table as a PDF</b><div style="opacity:.78;margin:.35rem 0 .8rem">All 9 rules Audit Log Retention Lint (PCI DSS, CERT-In) checks, each with its source and date, on printable pages you can hand to your team or auditor. We email it now, and once more only if a rule changes. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Email me the PDF</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">Sent. It arrives within the hour - check spam too.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"audit-log-retention-lint",lang:"en",source:"rule_table"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);})();</script></section>
211
+
212
+ <section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">Log retention lint for Loki, CloudWatch, ILM, S3 and Kubernetes audit YAML</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">One hour of a lawyer with 15 years' experience is $851 on the DOJ Fitzpatrick Matrix (billing year 2026).</p><a href="https://buy.polar.sh/polar_cl_73892EssmeKJZXapgXXgmOIMw47IdPQLP1lWX0gxfLm" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
213
+ <!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script>
214
+ <script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script>
215
+
216
+ <script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div><section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-27">Updated 2026-09-27</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-27","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku303425_result_card.jpg" alt="Audit Log Retention Lint (PCI DSS, CERT-In)" loading="lazy" style="max-width:100%;border-radius:6px"></p>
217
+ <p>Audit logs gone at day 31: that is what a Loki retention_period of 744h means for a platform engineer whose cluster sits inside a PCI DSS scope, because Requirement 10.5.1 asks for at least 12 months of audit log history, with the most recent three months immediately available for analysis.</p>
218
+ <p>The number that decides this is rarely in a policy document. It is one line of YAML, often copied from an example, and it is written in a different unit in every tool. Loki counts hours (744h). Elasticsearch ILM counts days with a suffix (90d). CloudWatch RetentionInDays counts plain days. kube-apiserver takes --audit-log-maxage=30, also days. Nobody reads 744h and thinks &quot;31 days&quot; during a code review.</p>
219
+ <p>We wrote one sample file with the settings a payments team might ship: Loki, a CloudFormation log group, an S3 audit bucket, a kube-apiserver manifest and an ILM policy. Under PCI DSS the lint returns 7 findings, 6 errors and 1 warning:</p>
220
+ <ul><li>Loki retention_period: 744h is 31 days against 365.</li><li>A Loki retention_stream override for the payments namespace, period: 168h, is 7 days.</li><li>An AWS::Logs::LogGroup with RetentionInDays: 30.</li><li>An S3 audit bucket with ExpirationInDays: 180.</li><li>The same bucket moves logs to GLACIER after 30 days, before the three immediately-available months end (the warning).</li><li>kube-apiserver --audit-log-maxage=30.</li><li>An ILM delete phase at min_age: 90d.</li></ul>
221
+ <p>The fixed file, with 8760h, 400 days and a 90-day archive transition, returns 0.</p>
222
+ <p>Why the rule you declare matters. The same YAML passes or fails depending on who you answer to. The lint knows three profiles. pci-dss applies PCI DSS v4.0.1 Requirement 10.5.1: 365 days total, 90 days immediately available. cert-in applies direction (iv) of the CERT-In Directions of 28 April 2022: logs of all ICT systems kept for a rolling 180 days, within Indian jurisdiction, so a log store in us-east-1 is a finding on its own. Failing to comply with a CERT-In direction can be punished under s.70B(7) of the IT Act with a fine up to ₹1,00,000 or imprisonment up to one year. m-21-31 applies OMB Memorandum M-21-31 for US federal systems: 12 months active storage plus 18 months cold storage, which the lint counts as 913 days total and 365 active. A CloudWatch group at RetentionInDays: 365 passes PCI DSS and fails M-21-31.</p>
223
+ <p>You declare the profile with one comment line at the top of the file, for example # log-retention: pci-dss, cert-in. When several are listed, the strictest minimum wins per check. With no line, PCI DSS applies.</p>
224
+ <p>Why not ask a chatbot? A chatbot can recite 10.5.1, but it does not open the YAML in your repository, and it has to convert 744h, 90d and a bare 30 correctly every time. The lint runs on every save, in the Problems panel, with the line number.</p>
225
+ <p>What it does not do: it reads configuration text only. A retention changed in a cloud console after deploy is not seen, and the lint does not decide whether a system is in scope.</p>
226
+ <p>The file check is free in VS Code and in the browser at getreadystack.com/tools/audit-log-retention-lint, with all 9 rules and no key. A licence key adds the workspace sweep, which walks every YAML file in the folder and writes one Markdown evidence table of file, line, value, minimum and clause, ready for the QSA or auditor.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku303425_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku303425_short.mp4" type="video/mp4"></video><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does Audit Log Retention Lint do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads log-retention settings in YAML files, such as Loki retention_period, CloudWatch RetentionInDays, Elasticsearch ILM delete min_age, S3 lifecycle expiration and kube-apiserver --audit-log-maxage, and flags every value shorter than PCI DSS 10.5.1 (365 days, 90 immediately available), CERT-In 2022 (180 days in India) or OMB M-21-31 (913 days). Each finding gives the line, the clause and the value that passes.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is Audit Log Retention Lint for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Platform, DevOps and SRE engineers who keep logging configuration in YAML and answer to a PCI DSS assessment, the Indian CERT-In directions of April 2022, or US federal logging rules under OMB M-21-31. It suits teams preparing for a QSA visit or a CERT-In incident request who need to know which log store deletes evidence too early.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not just ask a chatbot or read the standard?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A chatbot does not open the YAML in your repository, and it often mixes up units: Loki writes 744h, ILM writes 90d, CloudWatch writes days. The rule is also different per regime: PCI DSS 10.5.1 wants 12 months, CERT-In wants 180 days kept within India, and M-21-31 wants 30 months. The lint converts each unit and applies the strictest declared rule.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what does the licence add?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free: every finding in the open YAML file, in VS Code or in the browser, with clause and fix value, no key and no limit. The $29 licence, paid once, adds the workspace sweep: every YAML file in the folder checked at once and written into one Markdown evidence table of file, line, value, minimum and clause for a QSA or auditor.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does the alternative cost?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">One hour of a lawyer with 15 years&#x27; experience is $851 on the DOJ Fitzpatrick Matrix for billing year 2026. Under India&#x27;s IT Act s.70B(7), failing to comply with a CERT-In direction can be punished with a fine up to ₹1,00,000 or imprisonment up to one year. The lint runs the retention check on every save at no cost.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not just ask ChatGPT or another AI chat?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. Audit Log Retention Lint (PCI DSS, CERT-In) checks the file you open against 9 rules from a rule set dated 2026-09-26, and points at the exact line with the fix. For a filing, an audit or a client you need that dated result on your own files.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does Audit Log Retention Lint do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads log-retention settings in YAML files, such as Loki retention_period, CloudWatch RetentionInDays, Elasticsearch ILM delete min_age, S3 lifecycle expiration and kube-apiserver --audit-log-maxage, and flags every value shorter than PCI DSS 10.5.1 (365 days, 90 immediately available), CERT-In 2022 (180 days in India) or OMB M-21-31 (913 days). Each finding gives the line, the clause and the value that passes."}}, {"@type": "Question", "name": "Who is Audit Log Retention Lint for?", "acceptedAnswer": {"@type": "Answer", "text": "Platform, DevOps and SRE engineers who keep logging configuration in YAML and answer to a PCI DSS assessment, the Indian CERT-In directions of April 2022, or US federal logging rules under OMB M-21-31. It suits teams preparing for a QSA visit or a CERT-In incident request who need to know which log store deletes evidence too early."}}, {"@type": "Question", "name": "Why not just ask a chatbot or read the standard?", "acceptedAnswer": {"@type": "Answer", "text": "A chatbot does not open the YAML in your repository, and it often mixes up units: Loki writes 744h, ILM writes 90d, CloudWatch writes days. The rule is also different per regime: PCI DSS 10.5.1 wants 12 months, CERT-In wants 180 days kept within India, and M-21-31 wants 30 months. The lint converts each unit and applies the strictest declared rule."}}, {"@type": "Question", "name": "What is free and what does the licence add?", "acceptedAnswer": {"@type": "Answer", "text": "Free: every finding in the open YAML file, in VS Code or in the browser, with clause and fix value, no key and no limit. The $29 licence, paid once, adds the workspace sweep: every YAML file in the folder checked at once and written into one Markdown evidence table of file, line, value, minimum and clause for a QSA or auditor."}}, {"@type": "Question", "name": "What does the alternative cost?", "acceptedAnswer": {"@type": "Answer", "text": "One hour of a lawyer with 15 years' experience is $851 on the DOJ Fitzpatrick Matrix for billing year 2026. Under India's IT Act s.70B(7), failing to comply with a CERT-In direction can be punished with a fine up to ₹1,00,000 or imprisonment up to one year. The lint runs the retention check on every save at no cost."}}, {"@type": "Question", "name": "Why not just ask ChatGPT or another AI chat?", "acceptedAnswer": {"@type": "Answer", "text": "A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. Audit Log Retention Lint (PCI DSS, CERT-In) checks the file you open against 9 rules from a rule set dated 2026-09-26, and points at the exact line with the fix. For a filing, an audit or a client you need that dated result on your own files."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:303425,slug:"audit-log-retention-lint",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/python-pci-log-leak-lint"><span class="yj-rel-t">Python Log Leak Lint: PCI DSS Card Data</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/sql-card-data-lint"><span class="yj-rel-t">SQL Card Data Lint (PCI DSS Req 3)</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cloud-cost-landmine-lint"><span class="yj-rel-t">Cloud Cost Landmine Lint for Terraform, CloudFormation and Kubernetes</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cron-schedule-lint"><span class="yj-rel-t">Cron Schedule Lint for crontab, Kubernetes CronJob, GitHub Actions, Spring and</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/k8s-removed-api-lint"><span class="yj-rel-t">Kubernetes Removed API Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/pci-payment-page-script-audit"><span class="yj-rel-t">PCI Payment Page Script Audit: requirement 6.4.3 and 11.6.1 on your checkout m</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section></body>
227
  </html>