Author SHA1 Message Date
adelvalleandAlvaro Del Valle c987ed07c5 EC2 source-code discovery and reliability triage (#2)
Second discovery pass over the Scrivas EC2 estate (`716468089330`, `us-east-2`, 7 instances). Prompted by two client signals: they do not hold the source code for their own platform (built under contract by the incumbent vendor), and they are reporting production reliability issues.

All access was **read-only** — no writes, restarts or config changes on any instance.

## Source code is recoverable

**All 10 application repositories exist as complete git checkouts on Scrivas-owned instances**, with full commit history rather than deployed artifacts.

| Tier | Location | Repos |
|---|---|---|
| App | `Scrivas_dev_env:/home/admin/` | `scrivas_backend` (1380 commits), `scrivas_gate` (183), `scrivas_search` (96), `patient` (59) |
| ML | `ML_dev:/srv/` | `post_processor` (137), `sai_suggestions` (93), `ml_monitoring` (62), `patient-summary-service` (49), `patient_document_parser` (41), `soniox_transcriber` (25) |

Every remote points at `git@git.devteam.space:scrivas/*` — the contractor's self-hosted GitLab, which Scrivas does **not** control. The on-instance checkouts are the client's only independent leverage over their own source.

**Gap:** both `/var/www` frontends are build output with no `.git`. Frontend source is not recoverable from EC2.

**Time-sensitive:** `scrivas_backend` received a commit on the assessment date. Development is active on infrastructure the contractor controls. Mirroring the repos to Scrivas-controlled storage is the recommended immediate action and is **not** included in this PR — it needs a scope decision first (it involves the contractor's GitLab credentials held on the dev box).

## Reliability triage

Production runs **23 containers on a single 15 GiB host** — including 3 Postgres instances, Kafka and OpenSearch — at **73% memory at rest**, with **no per-container memory limits** and **no swap** on any of the 7 instances. With no limits the OOM killer selects by resident size, so it would typically kill a database rather than the worker that caused the pressure. That matches the "random, unreproducible" symptom profile.

Kafka, OpenSearch and search-api additionally carry restart policy `no`, so a host reboot yields a partially-recovered stack that looks healthy from outside.

**Recorded as a structural exposure, not an observed root cause.** No OOM event appears in retained logs, `State.OOMKilled` is false on all 23 containers, and `RestartCount` is **0** on every one — the Celery workers showing "Up 6 hours" were redeployed, not crash-restarted. Confirming the hypothesis needs CloudWatch history these boxes do not retain, which is itself a finding and the basis for recommendations 3–5 in the report.

One encouraging contrast: the **ML tier is well-built** — ECR images tagged by commit SHA, blue/green slots, passing health checks. The application tier is compose-from-git-checkout with uncommitted `.env.save` and `docker-compose.yml.bkp` files in the prod working tree. The better pattern already exists in-house.

## Contents

| File | |
|---|---|
| `scripts/ec2_code_discovery.py` | EC2 inventory — describe + user data |
| `scripts/ec2_code_inspect.py` | read-only SSM probe set; commands reviewable in `PROBES` |
| `findings/ec2_code_discovery_report.md` | narrative writeup |
| `findings/code_dashboard.html` | client-facing dashboard, matching the existing design system |
| `findings/ec2_code_inspect*.json` | raw probe output |
| `index.html` | links the new dashboard and evidence |

## Review notes

- Probe output was **scanned for credentials before commit** ��� no AWS keys, passwords, tokens or private key blocks. The probe set reads manifests and VCS metadata, never file contents.
- Git metadata was read **as the owning user** (`sudo -u`) rather than by writing a `safe.directory` entry into root's gitconfig, to preserve the read-only guarantee.
- Several prod probes initially returned empty and were re-run with stderr visible; the empties were artifacts (`last` is not installed on prod), not clean health. Worth knowing when reading the JSON.
- The dashboard keeps the "what the evidence does not show" section in the **client-facing** version. If CloudWatch later points elsewhere, overclaiming a root cause would cost more credibility than the softer framing gains.

https://claude.ai/code/session_01YMxVaHXJsqpqKwncNQ9b1e
Co-authored-by: Alvaro Del Valle <alvaro.delvalle2@gmail.com>
Reviewed-on: #2
2026-09-02 14:36:28 -06:00
adelvalle 9e3d1f58d5 Merge pull request 'Update proposal levers with Prowler benchmark findings' (#1) from update-proposal-levers into main
Reviewed-on: #1
2026-08-19 15:23:08 -06:00
7 changed files with 1392 additions and 2 deletions
+318
View File
@@ -0,0 +1,318 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Scrivas — Source Code &amp; Reliability</title>
<style>
:root {
--bg:#eef0f3; --panel:#ffffff; --panel-2:#f7f8fa; --ink:#171d27;
--ink-soft:#4a5563; --ink-faint:#79828f; --line:#dde1e7; --line-soft:#e8ebef;
--accent:#0d6e78; --accent-ink:#0a565e;
--good:#2f8657; --warn:#b5832a; --crit:#bd463b;
--crit-bg:#fbeceb; --good-bg:#eaf4ee; --warn-bg:#f8f1e2;
--mono: ui-monospace,"SF Mono","SFMono-Regular",Menlo,Consolas,monospace;
--sans: ui-sans-serif,system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
--shadow:0 1px 2px rgba(20,26,38,.04),0 6px 20px -12px rgba(20,26,38,.18);
}
@media (prefers-color-scheme:dark){:root{
--bg:#0d1117;--panel:#161c26;--panel-2:#1b222e;--ink:#e8ecf1;--ink-soft:#aab3c0;
--ink-faint:#7c8695;--line:#28303c;--line-soft:#212934;--accent:#3bb4bf;--accent-ink:#8fdfe6;
--good:#54b681;--warn:#d6a94a;--crit:#e26b60;--crit-bg:#2a1917;--good-bg:#132419;--warn-bg:#251d10;
--shadow:0 1px 2px rgba(0,0,0,.3),0 8px 24px -14px rgba(0,0,0,.6);}}
:root[data-theme="dark"]{
--bg:#0d1117;--panel:#161c26;--panel-2:#1b222e;--ink:#e8ecf1;--ink-soft:#aab3c0;
--ink-faint:#7c8695;--line:#28303c;--line-soft:#212934;--accent:#3bb4bf;--accent-ink:#8fdfe6;
--good:#54b681;--warn:#d6a94a;--crit:#e26b60;--crit-bg:#2a1917;--good-bg:#132419;--warn-bg:#251d10;
--shadow:0 1px 2px rgba(0,0,0,.3),0 8px 24px -14px rgba(0,0,0,.6);}
:root[data-theme="light"]{
--bg:#eef0f3;--panel:#ffffff;--panel-2:#f7f8fa;--ink:#171d27;--ink-soft:#4a5563;
--ink-faint:#79828f;--line:#dde1e7;--line-soft:#e8ebef;--accent:#0d6e78;--accent-ink:#0a565e;
--good:#2f8657;--warn:#b5832a;--crit:#bd463b;--crit-bg:#fbeceb;--good-bg:#eaf4ee;--warn-bg:#f8f1e2;
--shadow:0 1px 2px rgba(20,26,38,.04),0 6px 20px -12px rgba(20,26,38,.18);}
*{box-sizing:border-box;}
body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--sans);line-height:1.5;-webkit-font-smoothing:antialiased;}
.wrap{max-width:1120px;margin:0 auto;padding:32px 24px 64px;}
header{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:16px;padding-bottom:20px;border-bottom:2px solid var(--ink);}
.eyebrow{font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--accent);font-weight:700;}
h1{font-size:clamp(24px,4vw,34px);margin:6px 0 4px;letter-spacing:-.02em;text-wrap:balance;font-weight:750;}
.sub{color:var(--ink-soft);font-size:14px;}
.idcard{font-family:var(--mono);font-size:12px;color:var(--ink-soft);text-align:right;line-height:1.7;}
.idcard b{color:var(--ink);}
.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin:22px 0 12px;}
@media (max-width:760px){.kpis{grid-template-columns:repeat(2,1fr);}}
.kpi{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:16px;box-shadow:var(--shadow);position:relative;overflow:hidden;}
.kpi::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--accent);}
.kpi.crit::before{background:var(--crit);}.kpi.warn::before{background:var(--warn);}.kpi.good::before{background:var(--good);}
.kpi .n{font-size:28px;font-weight:750;letter-spacing:-.02em;font-variant-numeric:tabular-nums;}
.kpi.crit .n{color:var(--crit);}.kpi.warn .n{color:var(--warn);}.kpi.good .n{color:var(--good);}
.kpi .lbl{font-size:12px;color:var(--ink-faint);margin-top:2px;}
.kpi .meta{font-size:11px;color:var(--ink-soft);margin-top:8px;}
section{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:22px 24px;margin-bottom:18px;box-shadow:var(--shadow);}
.sec-head{display:flex;align-items:baseline;gap:10px;margin-bottom:16px;flex-wrap:wrap;}
.sec-head .tag{font-family:var(--mono);font-size:12px;color:var(--accent);font-weight:700;}
.sec-head h2{font-size:17px;margin:0;letter-spacing:-.01em;}
.sec-head .note{margin-left:auto;font-size:12px;color:var(--ink-faint);}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:18px;}
@media (max-width:820px){.grid2{grid-template-columns:1fr;}}
table{width:100%;border-collapse:collapse;font-size:13px;}
th{text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--ink-faint);
font-weight:700;padding:0 10px 8px 0;border-bottom:1px solid var(--line);}
td{padding:9px 10px 9px 0;border-bottom:1px solid var(--line-soft);vertical-align:top;color:var(--ink-soft);}
td b{color:var(--ink);}
tbody tr:last-child td{border-bottom:none;}
.num{font-family:var(--mono);font-variant-numeric:tabular-nums;text-align:right;color:var(--ink);}
code{font-family:var(--mono);font-size:12px;color:var(--ink-soft);}
.scroll{overflow-x:auto;}
.pill{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:700;padding:3px 9px;border-radius:999px;white-space:nowrap;}
.pill.crit{background:var(--crit-bg);color:var(--crit);}
.pill.good{background:var(--good-bg);color:var(--good);}
.pill.warn{background:var(--warn-bg);color:var(--warn);}
.callout{border-radius:10px;padding:14px 16px;font-size:13px;color:var(--ink-soft);margin:0 0 16px;
background:var(--warn-bg);border:1px solid color-mix(in srgb,var(--warn) 30%,transparent);}
.callout.crit{background:var(--crit-bg);border-color:color-mix(in srgb,var(--crit) 30%,transparent);}
.callout.good{background:var(--good-bg);border-color:color-mix(in srgb,var(--good) 30%,transparent);}
.callout b{color:var(--ink);}
.callout p{margin:8px 0 0;}
.memtrack{height:26px;background:var(--panel-2);border:1px solid var(--line);border-radius:7px;overflow:hidden;display:flex;margin:6px 0 4px;}
.memtrack .used{background:var(--crit);height:100%;}
.memtrack .cache{background:color-mix(in srgb,var(--warn) 55%,transparent);height:100%;}
.memlegend{display:flex;gap:16px;font-size:11.5px;color:var(--ink-faint);flex-wrap:wrap;}
.memlegend i{display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:5px;vertical-align:baseline;}
ol.steps{margin:0;padding-left:20px;font-size:13px;color:var(--ink-soft);}
ol.steps li{margin-bottom:9px;}
ol.steps b{color:var(--ink);}
footer{display:flex;flex-wrap:wrap;gap:18px;margin-top:24px;font-size:12px;color:var(--ink-faint);font-family:var(--mono);}
</style>
</head>
<body>
<div class="wrap">
<header>
<div>
<div class="eyebrow">Dasnuve · Cloud Discovery</div>
<h1>Source Code Recovery &amp; Reliability Triage</h1>
<div class="sub">What is running on the Scrivas EC2 estate, where the source lives, and why production is fragile.</div>
</div>
<div class="idcard">
Account <b>716468089330</b><br>
Region <b>us-east-2</b> · 7 instances<br>
2026-08-28 · <b>CONFIDENTIAL</b>
</div>
</header>
<div class="kpis">
<div class="kpi good">
<div class="n">10</div>
<div class="lbl">Repos recoverable on EC2</div>
<div class="meta">Full git history, not just build output</div>
</div>
<div class="kpi warn">
<div class="n">2</div>
<div class="lbl">Frontends <u>not</u> recoverable</div>
<div class="meta">Deployed build only — no <code>.git</code></div>
</div>
<div class="kpi crit">
<div class="n">23</div>
<div class="lbl">Prod containers, one host</div>
<div class="meta">Incl. 3 × Postgres, Kafka, OpenSearch</div>
</div>
<div class="kpi crit">
<div class="n">0</div>
<div class="lbl">Memory limits set</div>
<div class="meta">And zero swap, on all 7 instances</div>
</div>
</div>
<section>
<div class="sec-head">
<span class="tag">01</span><h2>The source code is recoverable — and that is time-sensitive</h2>
<span class="note">Scrivas_dev_env · ML_dev</span>
</div>
<div class="callout good">
<b>All 10 application repositories exist as complete git checkouts on Scrivas-owned instances</b>, with full
commit history — not merely deployed artifacts. Scrivas can recover its codebase from its own AWS account today.
<p>Every repository points at a single external remote: <code>git@git.devteam.space:scrivas/&lt;repo&gt;.git</code>
the incumbent contractor's self-hosted GitLab, which Scrivas does <b>not</b> control. The on-instance checkouts are
therefore the client's only independent leverage over their own source.</p>
</div>
<div class="grid2">
<div>
<div class="sec-head"><span class="tag">APP</span><h2>Scrivas_dev_env <code>/home/admin/</code></h2></div>
<div class="scroll"><table>
<thead><tr><th>Repository</th><th class="num">Commits</th><th>Last commit</th></tr></thead>
<tbody>
<tr><td><b>scrivas_backend</b></td><td class="num">1380</td><td>2026-08-28 · Vasilii</td></tr>
<tr><td><b>scrivas_gate</b></td><td class="num">183</td><td>2026-08-14 · Vasilii</td></tr>
<tr><td><b>scrivas_search</b></td><td class="num">96</td><td>2026-06-24 · Azamat</td></tr>
<tr><td><b>patient</b></td><td class="num">59</td><td>2026-08-13 · vturtugeshev</td></tr>
</tbody>
</table></div>
</div>
<div>
<div class="sec-head"><span class="tag">ML</span><h2>ML_dev <code>/srv/</code></h2></div>
<div class="scroll"><table>
<thead><tr><th>Repository</th><th class="num">Commits</th><th>Last commit</th></tr></thead>
<tbody>
<tr><td><b>post_processor</b></td><td class="num">137</td><td>2026-06-30</td></tr>
<tr><td><b>sai_suggestions</b></td><td class="num">93</td><td>2026-06-16</td></tr>
<tr><td><b>ml_monitoring</b></td><td class="num">62</td><td>2026-07-20</td></tr>
<tr><td><b>patient-summary-service</b></td><td class="num">49</td><td>2026-06-12</td></tr>
<tr><td><b>patient_document_parser</b></td><td class="num">41</td><td>2026-06-16</td></tr>
<tr><td><b>soniox_transcriber</b></td><td class="num">25</td><td>2026-06-16</td></tr>
</tbody>
</table></div>
</div>
</div>
<div class="callout" style="margin:18px 0 0;">
<b>The gap:</b> <code>/var/www/scrivas_frontend</code> and <code>/var/www/Scrivas_admin_frontend</code> are
<b>deployed build output with no <code>.git</code></b>. Frontend source cannot be recovered from EC2 and must be
obtained from the contractor's GitLab.
<p><b>Why this is urgent:</b> <code>scrivas_backend</code> received a commit <b>on the day of this assessment</b>.
Development is active on infrastructure the contractor controls. Mirror all 10 repos
(<code>git clone --mirror</code>) to Scrivas-controlled storage <i>before</i> any contract conversation changes
access posture.</p>
</div>
</section>
<section>
<div class="sec-head">
<span class="tag">02</span><h2>Two tiers, two engineering standards</h2>
<span class="note">the better pattern already exists in-house</span>
</div>
<div class="grid2">
<div>
<div class="sec-head"><span class="tag">APP</span><h2>Application tier <span class="pill crit">fragile</span></h2></div>
<p class="sub" style="font-size:13px;">23 containers on a <b>single host</b><code>encounter_api</code>,
<code>gate_api</code>, <code>patient_api</code>, 8 Celery workers, <code>celery_beat</code>,
<b>3 × Postgres 17.5</b>, Redis, Kafka, Debezium CDC, OpenSearch, autoheal.</p>
<p class="sub" style="font-size:13px;">Deployed by <code>docker-compose</code> directly from git checkouts.
No orchestration, no image registry, no immutable artifact.</p>
</div>
<div>
<div class="sec-head"><span class="tag">ML</span><h2>ML tier <span class="pill good">mature</span></h2></div>
<p class="sub" style="font-size:13px;">Deployed from <b>ECR</b>
(<code>…dkr.ecr.us-east-2…/scrivas/*</code>) with <b>commit-SHA image tags</b> and
<b>blue/green slots</b> (<code>dev-green-*</code>, <code>stage-blue-*</code>).</p>
<p class="sub" style="font-size:13px;">Health checks defined and passing across every service.
This is a materially stronger delivery pipeline — and a template the application tier can adopt.</p>
</div>
</div>
</section>
<section>
<div class="sec-head">
<span class="tag">03</span><h2>Reliability findings</h2>
<span class="note">ranked by likely contribution to reported instability</span>
</div>
<div class="scroll"><table>
<thead><tr><th>#</th><th>Finding</th><th>Evidence</th><th>Risk</th></tr></thead>
<tbody>
<tr><td class="num">1</td><td><b>No memory limit on any prod container</b></td><td><code>HostConfig.Memory=0</code> on all 23</td><td><span class="pill crit">High</span></td></tr>
<tr><td class="num">2</td><td><b>No swap on any instance</b></td><td><code>swapon --show</code> empty, all 7</td><td><span class="pill crit">High</span></td></tr>
<tr><td class="num">3</td><td><b>Prod at 73% memory at rest</b></td><td>11 GiB used of 15 GiB</td><td><span class="pill crit">High</span></td></tr>
<tr><td class="num">4</td><td><b>Whole stack on one host, incl. 3 databases</b></td><td><code>docker ps</code> — 23 containers</td><td><span class="pill crit">High</span></td></tr>
<tr><td class="num">5</td><td><b>3 prod containers set to never restart</b></td><td>Kafka, OpenSearch, search-api — policy <code>no</code></td><td><span class="pill crit">High</span></td></tr>
<tr><td class="num">6</td><td>Prod OS differs from dev/stage</td><td>Ubuntu <b>26.04</b> vs <b>24.04</b> elsewhere</td><td><span class="pill warn">Medium</span></td></tr>
<tr><td class="num">7</td><td><code>autoheal</code> deployed in production</td><td><code>willfarrell/autoheal:1.2.0</code></td><td><span class="pill warn">Medium</span></td></tr>
<tr><td class="num">8</td><td>Uncommitted config drift in prod checkouts</td><td><code>docker-compose.yml.bkp</code>, <code>.env.save</code></td><td><span class="pill warn">Medium</span></td></tr>
<tr><td class="num">9</td><td>47 interactive login sessions on prod</td><td><code>uptime</code> (32 on Ml_prod)</td><td><span class="pill warn">Medium</span></td></tr>
<tr><td class="num">10</td><td><code>sai-suggestions-redis.service</code> failed</td><td>ML_stage <code>systemctl --state=failed</code></td><td><span class="pill good">Low</span></td></tr>
</tbody>
</table></div>
</section>
<section>
<div class="sec-head">
<span class="tag">04</span><h2>Primary hypothesis: unbounded memory on a shared host</h2>
</div>
<p class="sub" style="font-size:13px;margin-top:0;">Production memory, at rest — before any workload spike:</p>
<div class="memtrack" role="img" aria-label="Production memory: 11 GiB used, 3.5 GiB cache, of 15 GiB total">
<div class="used" style="width:73%"></div><div class="cache" style="width:23%"></div>
</div>
<div class="memlegend">
<span><i style="background:var(--crit)"></i>11 GiB used (73%)</span>
<span><i style="background:color-mix(in srgb,var(--warn) 55%,transparent)"></i>3.5 GiB cache</span>
<span><i style="background:var(--panel-2);border:1px solid var(--line)"></i>441 MiB free</span>
<span><b style="color:var(--crit)">0 B swap</b></span>
</div>
<div class="callout crit" style="margin-top:18px;">
Findings 14 compound into a single failure mode. Production runs 23 containers — including three Postgres
instances, Kafka and OpenSearch — on one 15 GiB host already <b>73% consumed at rest</b>, with
<b>no per-container memory limits</b> and <b>no swap</b>. A single Celery worker handling an oversized document
or audio chunk can exhaust host memory. With no limits, the kernel OOM killer selects by resident size — so it
will typically kill a <b>database</b>, not the worker that caused the problem.
<p>That yields precisely the profile a client reports as "random reliability issues": unpredictable, uncorrelated
with the triggering workload, and difficult to reproduce.</p>
<p><b>Finding 5 compounds recovery.</b> Kafka, OpenSearch and search-api carry restart policy <code>no</code> — if
they die or the host reboots, they <b>stay down</b> until someone intervenes. Everything else is
<code>unless-stopped</code>, so a reboot yields a partially-recovered stack that looks healthy from the outside.</p>
<p><b>Finding 7 corroborates.</b> Someone deliberately deployed <code>autoheal</code>, a daemon whose only job is
restarting containers that fail health checks. That treats a symptom — and indicates health-check failures were
frequent enough to be worth automating around.</p>
</div>
<div class="callout">
<b>What the evidence does not show — stated plainly, because it bounds the conclusion.</b>
<p>· <b>No OOM kill was captured.</b> <code>dmesg</code> and <code>journalctl</code> on prod show no OOM events in
the retained window; <code>State.OOMKilled</code> is <code>false</code> on all 23 containers.</p>
<p>· <b>No crash-looping.</b> <code>RestartCount</code> is <b>0</b> on every prod container. The Celery workers
showing "Up 6 hours" were <b>redeployed</b> at 13:49 that day, not restarted by failure.</p>
<p>· <code>last</code> is not installed on prod, so reboot history could not be read there.</p>
<p>Findings 15 are therefore a demonstrated <b>structural exposure</b>, not an observed root cause. Confirming
the hypothesis requires history these instances do not currently retain — which is itself a finding.</p>
</div>
</section>
<section>
<div class="sec-head"><span class="tag">05</span><h2>Recommended next steps</h2></div>
<div class="grid2">
<div>
<div class="sec-head"><span class="tag">NOW</span><h2>Immediate</h2></div>
<ol class="steps">
<li><b>Mirror all 10 repos</b> to Scrivas-controlled storage. Highest value, lowest effort, time-sensitive.</li>
<li><b>Set <code>unless-stopped</code></b> on Kafka, OpenSearch and search-api — removes the silent partial-recovery failure.</li>
</ol>
<div class="sec-head" style="margin-top:18px;"><span class="tag">PROVE</span><h2>Confirm the hypothesis</h2></div>
<ol class="steps" start="3">
<li><b>Enable per-container memory metrics</b> in CloudWatch — <code>EC2-CloudWatchAgent-Role</code> is already attached.</li>
<li><b>Add <code>mem_limit</code> per service</b>, sized from observed peaks; add swap as an OOM buffer.</li>
<li><b>Query historic <code>mem_used_percent</code></b> to date the onset of instability.</li>
</ol>
</div>
<div>
<div class="sec-head"><span class="tag">FIX</span><h2>Structural</h2></div>
<ol class="steps" start="6">
<li><b>Move the three Postgres instances</b> off the shared application host.</li>
<li><b>Align prod OS/AMI with stage</b> — 26.04 vs 24.04 makes staging an unreliable rehearsal for production.</li>
<li><b>Extend the ML tier's pattern</b> — ECR, commit-SHA tags, blue/green — to the application tier. The better pattern already exists in-house.</li>
<li><b>Reconcile config drift</b> (<code>.env.save</code>, <code>docker-compose.yml.bkp</code>) into version control.</li>
<li><b>Audit the 47 interactive prod sessions.</b></li>
</ol>
</div>
</div>
</section>
<footer>
<span>Read-only · SSM probes via <code>dasnuve-scrivas-louis-impersonation</code></span>
<span>Reproduce: <code>scripts/ec2_code_inspect.py</code></span>
<span>Raw: <code>findings/ec2_code_inspect.json</code></span>
<span>Narrative: <code>findings/ec2_code_discovery_report.md</code></span>
</footer>
</div>
</body>
</html>
+142
View File
@@ -0,0 +1,142 @@
# Scrivas — EC2 Code Discovery & Reliability Triage
**Prepared by:** Dasnuve · **Date:** 2026-08-28
**Access:** `dasnuve-scrivas-louis-impersonation``arn:aws:iam::716468089330:user/louis`
**Method:** Read-only EC2 describe + SSM `AWS-RunShellScript` probes (no writes, no restarts, no config changes).
**Scripts:** `scripts/ec2_code_discovery.py` (inventory), `scripts/ec2_code_inspect.py` (probes)
**Raw:** `findings/ec2_code_inspect.json`, `findings/ec2_code_inspect_prod.json`
---
## 1. Headline: the source code is recoverable
**All 10 application repositories exist as full git checkouts on Scrivas-owned EC2 instances**, with complete
history — not just deployed artifacts. The client can recover their codebase from their own account today.
All repos point to a single external remote:
> `git@git.devteam.space:scrivas/<repo>.git`
`git.devteam.space` is the **incumbent contractor's self-hosted GitLab** (DevTeam.Space; commit authors are
`@devteamspace.com`). Scrivas does not control this host. The checkouts on EC2 are therefore the client's
only leverage over their own source.
### Application repos — `Scrivas_dev_env` (i-010066e6c9027aa6e), `/home/admin/`
| Repo | Commits | Branch | Last commit |
|---|---:|---|---|
| `scrivas_backend` | **1380** | `dev` | 2026-08-28 — Vasilii |
| `scrivas_gate` | 183 | `dev` | 2026-08-14 — Vasilii |
| `scrivas_search` | 96 | `dev` | 2026-06-24 — Azamat |
| `patient` | 59 | `dev` | 2026-08-13 — vturtugeshev@webiomed.ru |
### ML repos — `ML_dev` (i-095bd68aff22b103b), `/srv/`
| Repo | Commits | Last commit |
|---|---:|---|
| `post_processor` | 137 | 2026-06-30 — Yegor Kovalev |
| `sai_suggestions` | 93 | 2026-06-16 |
| `ml_monitoring` | 62 | 2026-07-20 |
| `patient-summary-service` | 49 | 2026-06-12 |
| `patient_document_parser` | 41 | 2026-06-16 |
| `soniox_transcriber` | 25 | 2026-06-16 |
**Not in git:** `/var/www/scrivas_frontend` and `/var/www/Scrivas_admin_frontend` on the dev box are
**deployed build output only — no `.git`**. Frontend source is *not* recoverable from EC2 and must come
from the contractor's GitLab. This is the one genuine gap.
### Recommended immediate action
Mirror all 10 repos (`git clone --mirror`) off the instances to Scrivas-controlled storage **before** any
contract conversation changes access posture. `scrivas_backend` received a commit *today* — the contractor
is actively developing, so the on-box checkouts are current.
---
## 2. Architecture as actually deployed
Two clearly different engineering standards are in play.
**Application tier — `scrivas_prod_env` (i-073154fb4fa773bbd), Ubuntu 26.04, m6a.xlarge, 15 GiB**
23 containers on a **single host**: `encounter_api`, `gate_api`, `patient_api`, 8 Celery workers,
`celery_beat`, **3× Postgres 17.5**, Redis 8.2.1, Kafka 4.1.1, Debezium CDC 2.7.3, OpenSearch, autoheal.
Deployed via `docker-compose` from git checkouts. No orchestration, no registry.
**ML tier — `Ml_prod` / `ML_stage` / `ML_dev`, 7.6 GiB**
Deployed from **ECR** (`716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/*`) with commit-SHA image
tags and **blue/green slots** (`dev-green-*`, `stage-blue-*`). Health checks present and passing.
This tier is materially more mature than the application tier.
**`Netbird_scrivas` (i-02754e7ae419cd5db)** — NetBird VPN mesh (server, dashboard, Traefik v3.6).
---
## 3. Reliability findings
Ranked by likely contribution to the reported instability.
| # | Finding | Evidence | Risk |
|---|---|---|---|
| 1 | **No memory limit on any prod container** | `HostConfig.Memory=0` on all 23 | **High** |
| 2 | **No swap on any instance** | `swapon --show` empty, all 7 | **High** |
| 3 | **Prod at 11 GiB / 15 GiB (73%) steady-state** | `free -h` | **High** |
| 4 | **Entire prod stack on one host — incl. 3 databases** | `docker ps` | **High** |
| 5 | **Three prod containers have restart policy `no`** | `scrivas-kafka`, `scrivas-opensearch`, `scrivas_search-search-api-1` | **High** |
| 6 | **Prod OS differs from dev/stage** | prod Ubuntu 26.04 vs 24.04 elsewhere | Medium |
| 7 | **`autoheal` deployed in prod** | `willfarrell/autoheal:1.2.0` | Medium |
| 8 | **Uncommitted config drift in prod checkouts** | `docker-compose.yml.bkp`, `.bkpwithlogs`, `src/gate/.env.save` | Medium |
| 9 | **47 interactive login sessions on prod** | `uptime` (32 on `Ml_prod`) | Medium |
| 10 | `sai-suggestions-redis.service` failed on ML_stage | `systemctl --state=failed` | Low |
### The primary hypothesis: unbounded memory on a shared host
Findings 14 compound into one failure mode. Prod runs 23 containers — including three Postgres
instances, Kafka, and OpenSearch — on a single 15 GiB box that is already **73% consumed at rest**,
with **no per-container memory limits** and **no swap**. Any single Celery worker processing an
oversized document or audio chunk can exhaust host memory. With no limits, the kernel OOM killer
chooses the victim — and it will typically pick the largest RSS process, which is a **database**, not
the worker that caused the problem.
That produces exactly the symptom profile a client describes as "random reliability issues":
unpredictable, uncorrelated with the triggering workload, and hard to reproduce.
Finding 5 makes it worse. Kafka, OpenSearch, and the search API have restart policy `no` — if they
die or the host reboots, **they stay down** until someone intervenes manually. Everything else is
`unless-stopped`, so a reboot yields a partially-recovered stack.
The presence of `autoheal` (finding 7) is corroborating: someone deliberately installed a daemon whose
only job is restarting containers that fail health checks. That is treatment of a symptom, and it tells
us health-check failures were frequent enough to be worth automating around.
### What the evidence does *not* show
Stated plainly, because it constrains the conclusion:
- **No OOM kill was captured in the current logs.** `dmesg` and `journalctl` on prod show no OOM events
in the retained window. `State.OOMKilled` is `false` on all 23 containers.
- **No crash-looping.** `RestartCount` is **0** on every prod container. The Celery workers showing
"Up 6 hours" were **redeployed** at 13:49 today, not restarted by failure.
- `last` is not installed on prod, so reboot history could not be read there.
So findings 15 are a demonstrated **structural exposure**, not an observed root cause. Confirming the
hypothesis requires history the boxes do not currently retain.
---
## 4. Recommended next steps
**Immediately**
1. Mirror all 10 repos to Scrivas-controlled storage. Highest-value, lowest-effort, time-sensitive.
2. Set restart policy to `unless-stopped` on Kafka, OpenSearch, and search-api.
**To confirm the memory hypothesis** — the current boxes cannot answer this from retained logs
3. Enable CloudWatch per-container memory metrics (the `EC2-CloudWatchAgent-Role` profile is already attached).
4. Add `mem_limit` per service in compose, sized from observed peaks; add swap as an OOM buffer.
5. Query CloudWatch for historic `mem_used_percent` on prod to date the onset of instability.
**Structural**
6. Move the three Postgres instances off the shared application host.
7. Align prod OS/AMI with stage (26.04 vs 24.04 makes staging an unreliable rehearsal).
8. Extend the ML tier's ECR + commit-SHA + blue/green pattern to the application tier — the better
pattern already exists in-house.
9. Reconcile the uncommitted prod config drift into version control.
10. Audit the 47 interactive prod sessions.
+302
View File
@@ -0,0 +1,302 @@
{
"generated": "2026-08-28T15:49:39.403488-04:00",
"region": "us-east-2",
"probes": [
"os_release",
"uptime_load",
"disk",
"memory",
"code_dirs",
"git_checkouts",
"git_remotes",
"manifests",
"processes",
"listening",
"systemd_units",
"systemd_failed",
"docker",
"docker_images",
"oom_kills",
"svc_restarts",
"reboots",
"cron"
],
"results": {
"i-095bd68aff22b103b": {
"os_release": {
"status": "Success",
"stdout": "PRETTY_NAME=\"Ubuntu 24.04.4 LTS\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"24.04\"\nVERSION=\"24.04.4 LTS (Noble Numbat)\"\nVERSION_CODENAME=noble\nID=ubuntu\nID_LIKE=debian\nHOME_URL=\"https://www.ubuntu.com/\"\nSUPPORT_URL=\"https://help.ubuntu.com/\"\nBUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu/\"\nPRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\nUBUNTU_CODENAME=noble\nLOGO=ubuntu-logo\nLinux ip-172-31-26-26 7.0.0-1010-aws #10~24.04.1-Ubuntu SMP PREEMPT Mon Jul 27 17:41:33 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux",
"stderr": ""
},
"uptime_load": {
"status": "Success",
"stdout": " 19:49:42 up 15 days, 13:34, 0 user, load average: 0.07, 0.11, 0.09\n0.07 0.11 0.09 1/556 3708993",
"stderr": ""
},
"disk": {
"status": "Success",
"stdout": "Filesystem Size Used Avail Use% Mounted on\n/dev/root 193G 46G 148G 24% /\ntmpfs 3.8G 0 3.8G 0% /dev/shm\ntmpfs 1.6G 2.2M 1.6G 1% /run\ntmpfs 5.0M 0 5.0M 0% /run/lock\nefivarfs 128K 3.8K 120K 4% /sys/firmware/efi/efivars\n/dev/nvme0n1p16 881M 202M 617M 25% /boot\n/dev/nvme0n1p15 105M 6.2M 99M 6% /boot/efi\noverlay 193G 46G 148G 24% /var/lib/docker/rootfs/overlayfs/e44ad8ada982413e134a0f808f5258611b96a2be7e5e78186d8098aef0ef5e42\noverlay 193G 46G 148G 24% /var/lib/docker/rootfs/overlayfs/d991d98f4a596c46d465054646dbf70ed26353b02a78c1c7c9752fe31650373c\noverlay 193G 46G 148G 24% /var/lib/docker/rootfs/overlayfs/f6063b3345a8dc4cb95c1142a63c2492122ed481aaf4120267445e9eabe926ac\noverlay 193G 46G 148G 24% /var/lib/docker/rootfs/overlayfs/0698fd968fa90c2803cc9168d05554a2af6f1f25f0280bae4ae0b5fbd84136aa\noverlay 193G 46G 148G 24% /var/lib/docker/rootfs/overlayfs/ac62d3eaf65e4733f6f83f85f409553724b99a0b87494ebfc3d607b0295cd84d\noverlay 193G 46G 148G 24% /var/lib/docker/rootfs/overlayfs/a8f1465efc695cbe55fc1b0a2a3352ad0532104847f062065bd3dc7e7075a5aa\noverlay 193G 46G 148G 24% /var/lib/docker/rootfs/overlayfs/15f495363998b7c196826202b6aa584976bf8b4a37ece873c3d3869caa973efe\noverlay 193G 46G 148G 24% /var/lib/docker/rootfs/overlayfs/e14d551d7fb67c76ff6533c116b0a70ba63f6523034278e508aa891c7fb4cc6e\noverlay 193G 46G 148G 24% /var/lib/docker/rootfs/overlayfs/d1bb2ab90222d9a4a1fc77c300dd48907993721c1b95ed4bead27653a20d3a07\noverlay 193G 46G 148G 24% /var/lib/docker/rootfs/overlayfs/e1312221d3f3e67b195ca1d561cce9984cd71cde22d7f04bf04b13558a8160b3\noverlay 193G 46G 148G 24% /var/lib/docker/rootfs/overlayfs/dcc956a69830a91dd3c16703e5653dfa277c007c2e8ceb6a516171ca0367cefa\noverlay 193G 46G 148G 24% /var/lib/docker/rootfs/overlayfs/83dcd9e8930be916501aef45855ffbf3b4eeba87ccc4ececf30198be162c5cd5\noverlay 193G 46G 148G 24% /var/lib/docker/rootfs/overlayfs/58d8d5bb29c0eae51f0fd8601bf8c1ef5163bae1ad41b2be27ce04e0ccdc052c\n--- inodes\nFilesystem Inodes IUsed IFree IUse% Mounted on\n/dev/root 26083328 763326 25320002 3% /\ntmpfs 989732 2 989730 1% /dev/shm\ntmpfs 819200 1143 818057 1% /run\ntmpfs 989732 3 989729 1% /run/lock\nefivarfs 0 0 0 - /sys/firmware/efi/efivars\n/dev/nvme0n1p16 58496 605 57891 2% /boot\n/dev/nvme0n1p15 0 0 0 - /boot/efi\noverlay 26083328 763326 25320002 3% /var/lib/docker/rootfs/overlayfs/e44ad8ada982413e134a0f808f5258611b96a2be7e5e78186d8098aef0ef5e42\noverlay 26083328 763326 25320002 3% /var/lib/docker/rootfs/overlayfs/d991d98f4a596c46d465054646dbf70ed26353b02a78c1c7c9752fe31650373c\noverlay 26083328 763326 25320002 3% /var/lib/docker/rootfs/overlayfs/f6063b3345a8dc4cb95c1142a63c2492122ed481aaf4120267445e9eabe926ac\noverlay 26083328 763326 25320002 3% /var/lib/docker/rootfs/overlayfs/0698fd968fa90c2803cc9168d05554a2af6f1f25f0280bae4ae0b5fbd84136aa\noverlay 26083328 763326 25320002 3% /var/lib/docker/rootfs/overlayfs/ac62d3eaf65e4733f6f83f85f409553724b99a0b87494ebfc3d607b0295cd84d\noverlay 26083328 763326 25320002 3% /var/lib/docker/rootfs/overlayfs/a8f1465efc695cbe55fc1b0a2a3352ad0532104847f062065bd3dc7e7075a5aa\noverlay 26083328 763326 25320002 3% /var/lib/docker/rootfs/overlayfs/15f495363998b7c196826202b6aa584976bf8b4a37ece873c3d3869caa973efe\noverlay 26083328 763326 25320002 3% /var/lib/docker/rootfs/overlayfs/e14d551d7fb67c76ff6533c116b0a70ba63f6523034278e508aa891c7fb4cc6e\noverlay 26083328 763326 25320002 3% /var/lib/docker/rootfs/overlayfs/d1bb2ab90222d9a4a1fc77c300dd48907993721c1b95ed4bead27653a20d3a07\noverlay 26083328 763326 25320002 3% /var/lib/docker/rootfs/overlayfs/e1312221d3f3e67b195ca1d561cce9984cd71cde22d7f04bf04b13558a8160b3\noverlay 26083328 763326 25320002 3% /var/lib/docker/rootfs/overlayfs/dcc956a69830a91dd3c16703e5653dfa277c007c2e8ceb6a516171ca0367cefa\noverlay 26083328 763326 25320002 3% /var/lib/docker/rootfs/overlayfs/83dcd9e8930be916501aef45855ffbf3b4eeba87ccc4ececf30198be162c5cd5\noverlay 26083328 763326 25320002 3% /var/lib/docker/rootfs/overlayfs/58d8d5bb29c0eae51f0fd8601bf8c1ef5163bae1ad41b2be27ce04e0ccdc052c",
"stderr": ""
},
"memory": {
"status": "Success",
"stdout": " total used free shared buff/cache available\nMem: 7.6Gi 2.3Gi 2.5Gi 4.4Mi 3.1Gi 5.3Gi\nSwap: 0B 0B 0B\n--- swap",
"stderr": ""
},
"code_dirs": {
"status": "Success",
"stdout": "/home:\ntotal 20\ndrwxr-xr-x 5 root root 4096 Jun 23 16:13 .\ndrwxr-xr-x 23 root root 4096 Aug 13 06:14 ..\ndrwxr-x--- 5 deploy deploy 4096 Jul 13 12:56 deploy\ndrwxr-x--- 2 gitlab-runner gitlab-runner 4096 Jun 23 16:13 gitlab-runner\ndrwxr-x--- 12 ubuntu ubuntu 4096 Jun 18 06:32 ubuntu\n\n/opt:\ntotal 40\ndrwxr-xr-x 6 root root 4096 Jul 15 13:42 .\ndrwxr-xr-x 23 root root 4096 Aug 13 06:14 ..\n-rw-rw-r-- 1 deploy deploy 797 Jul 9 18:26 .env\n-rw-r--r-- 1 deploy deploy 689 Jun 16 04:10 .env.bak.20260616-041003\ndrwxr-xr-x 5 root root 4096 Aug 26 00:53 aws\ndrwx--x--x 4 root root 4096 Mar 5 15:13 containerd\n-rw-r--r-- 1 root root 2412 Nov 30 2023 default\n-rw-r--r-- 1 root root 1659 Jun 23 11:01 ml-dev\ndrwxr-xr-x 11 root root 4096 Jun 18 10:06 patient-summary-service\ndrwxr-xr-x 14 root root 4096 Jun 16 10:13 post_processor\n\n/srv:\ntotal 56\ndrwxr-xr-x 10 ubuntu ubuntu 4096 Jun 24 09:22 .\ndrwxr-xr-x 23 root root 4096 Aug 13 06:14 ..\n-rw-rw-r-- 1 ubuntu ubuntu 15164 Mar 31 19:00 AGENTS.md\ndrwxr-xr-x 9 deploy deploy 4096 Jul 20 19:37 ml_monitoring\ndrwxr-xr-x 11 ubuntu ubuntu 4096 Jun 16 15:05 patient-summary-service\ndrwxr-xr-x 12 ubuntu ubuntu 4096 Jun 16 15:04 patient_document_parser\ndrwxr-xr-x 14 deploy deploy 4096 Jun 30 15:39 post_processor\ndrwxr-xr-x 2 root root 4096 Jun 24 09:22 redis-tls\ndrwxr-xr-x 4 root root 4096 Jun 24 08:55 redis_db\ndrwxr-xr-x 23 ubuntu ubuntu 4096 Jun 16 03:33 sai_suggestions\ndrwxr-xr-x 11 ubuntu ubuntu 4096 Jun 16 03:33 soniox_transcriber\n\n/var/www:\ntotal 12\ndrwxr-xr-x 3 root root 4096 May 1 12:04 .\ndrwxr-xr-x 14 root root 4096 May 1 12:04 ..\ndrwxr-xr-x 2 root root 4096 May 1 12:04 html",
"stderr": ""
},
"git_checkouts": {
"status": "Success",
"stdout": "/srv/sai_suggestions/.git\n/srv/patient-summary-service/.git\n/srv/patient_document_parser/.git\n/srv/ml_monitoring/.git\n/srv/post_processor/.git\n/srv/soniox_transcriber/.git\n/opt/patient-summary-service/.git\n/opt/post_processor/.git\n/home/ubuntu/.codex/.tmp/plugins/.git",
"stderr": ""
},
"git_remotes": {
"status": "Success",
"stdout": "== /srv/sai_suggestions\n== /srv/patient-summary-service\n== /srv/patient_document_parser\n== /srv/ml_monitoring\n== /srv/post_processor\n== /srv/soniox_transcriber\n== /opt/patient-summary-service\norigin\tgit@git.devteam.space:scrivas/patient-summary-service.git (fetch)\norigin\tgit@git.devteam.space:scrivas/patient-summary-service.git (push)\n7178a26575e261dbf889f40c974f607bb3c91ca7 Fri Jun 12 03:43:55 2026 +0500 Yegor Kovalev phi_logging: never crash the service when the audit log is unwritable (SOC 2 deploy fix)\n## dev...origin/dev\n== /opt/post_processor\norigin\tgit@git.devteam.space:scrivas/post_processor.git (fetch)\norigin\tgit@git.devteam.space:scrivas/post_processor.git (push)\n2f5cd0ada1c96f10616f378668c9b8cb99f73fc9 Tue Jun 16 08:29:18 2026 +0500 Yegor Kovalev SOC 2: Redis auth+TLS + loopback bind (host-net)\n## dev...origin/dev\n== /home/ubuntu/.codex/.tmp/plugins",
"stderr": ""
},
"manifests": {
"status": "Success",
"stdout": "/usr/share/doc/python3-botocore/requirements.txt\n/srv/sai_suggestions/requirements.txt\n/srv/sai_suggestions/tests/e2e/docker-compose.yml\n/srv/sai_suggestions/pyproject.toml\n/srv/sai_suggestions/Dockerfile\n/srv/sai_suggestions/docker-compose.yml\n/srv/patient-summary-service/requirements.txt\n/srv/patient-summary-service/pyproject.toml\n/srv/patient-summary-service/Dockerfile\n/srv/patient-summary-service/docker-compose.yml\n/srv/patient_document_parser/requirements.txt\n/srv/patient_document_parser/Dockerfile\n/srv/patient_document_parser/docker-compose.yml\n/srv/ml_monitoring/tests/mocks/Dockerfile\n/srv/ml_monitoring/pyproject.toml\n/srv/ml_monitoring/docker-compose.yml\n/srv/post_processor/requirements.txt\n/srv/post_processor/pyproject.toml\n/srv/post_processor/docker/Dockerfile\n/srv/soniox_transcriber/requirements.txt\n/srv/soniox_transcriber/tests/e2e/docker-compose.yml\n/srv/soniox_transcriber/pyproject.toml\n/srv/soniox_transcriber/docker/Dockerfile\n/srv/soniox_transcriber/docker/docker-compose.yml\n/opt/patient-summary-service/requirements.txt\n/opt/patient-summary-service/pyproject.toml\n/opt/patient-summary-service/Dockerfile\n/opt/patient-summary-service/docker-compose.yml\n/opt/post_processor/requirements.txt\n/opt/post_processor/pyproject.toml\n/opt/post_processor/docker/Dockerfile\n/opt/post_processor/docker/docker-compose.yml\n/home/ubuntu/.vscode-server/extensions/github.copilot-chat-0.36.2/package.json\n/home/ubuntu/.vscode-server/extensions/openai.chatgpt-26.609.30741-linux-x64/package.json\n/home/ubuntu/.vscode-server/extensions/openai.chatgpt-26.527.60818-linux-x64/package.json\n/home/ubuntu/.vscode-server/extensions/github.copilot-1.388.0/package.json\n/home/ubuntu/.vscode-server/extensions/github.vscode-pull-request-github-0.126.0/package.json",
"stderr": ""
},
"processes": {
"status": "Success",
"stdout": "USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND\nubuntu 3541290 0.2 3.8 547092 305344 ? Ssl Aug25 11:07 /usr/local/bin/python3.11 /usr/local/bin/uvicorn main:app --host 0.0.0.0 --port 8000\nroot 3536532 0.2 3.7 541604 299376 ? Ssl Aug25 12:31 /usr/local/bin/python3.11 /usr/local/bin/uvicorn sai_suggestions.api.main:app --host 0.0.0.0 --port 8000\nroot 3538327 0.2 3.2 978320 258268 ? Ssl Aug25 10:33 /usr/local/bin/python3.11 /usr/local/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000\nroot 2202636 0.2 3.2 643376 254172 ? Ssl Aug27 4:02 python -m app.main\nubuntu 3538482 0.2 3.0 502032 238000 ? Ssl Aug25 9:46 /usr/local/bin/python3.11 /usr/local/bin/uvicorn app:app --host 0.0.0.0 --port 8000\n472 1652 0.0 1.9 1530556 150580 ? Ssl Aug13 20:31 grafana server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --packaging=docker cfg:default.log.mode=console cfg:default.paths.data=/var/lib/grafana cfg:default.paths.logs=/var/log/grafana cfg:default.paths.plugins=/var/lib/grafana/plugins cfg:default.paths.provisioning=/etc/grafana/provisioning\nroot 1653 0.1 1.2 1402200 95976 ? Ssl Aug13 23:36 traefik traefik --providers.docker=true --providers.docker.exposedbydefault=false --providers.docker.network=traefik-net --entrypoints.web.address=:8090 --entrypoints.internal.address=:8091\nroot 815 0.5 1.0 2673500 80284 ? Ssl Aug13 114:41 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock\nnobody 1720 0.1 0.8 1752732 67052 ? Ssl Aug13 40:37 /bin/prometheus --web.listen-address=0.0.0.0:9090 --config.file=/tmp/prometheus.yml --storage.tsdb.path=/prometheus --storage.tsdb.retention.time=7d\nroot 651 0.3 0.8 2573492 63364 ? Ssl Aug13 80:21 /usr/bin/containerd\nroot 30117 0.1 0.7 1068508 55696 ? Ssl Aug13 38:38 /opt/aws/amazon-guardduty-agent/bin/amazon-guardduty-agent --worker-threads 8\nroot 2429504 0.3 0.6 1380784 52960 ? Sl Aug24 21:03 /snap/netbird/242/bin/netbird service run\nroot 3006517 0.0 0.6 83352 47916 ? S<s 06:53 0:01 /usr/lib/systemd/systemd-journald\nnobody 1664 0.0 0.4 1254824 35428 ? Ssl Aug13 15:01 /bin/alertmanager --config.file=/tmp/alertmanager.yml --web.listen-address=0.0.0.0:9093 --storage.path=/alertmanager\nroot 565 0.0 0.4 1366160 34096 ? Ssl Aug13 9:02 /usr/bin/gitlab-runner run --config /etc/gitlab-runner/config.toml --working-directory /home/gitlab-runner --service gitlab-runner --user gitlab-runner\nroot 2585 0.0 0.4 2212664 33724 ? Sl Aug13 5:26 /snap/amazon-ssm-agent/13349/ssm-agent-worker\nroot 581 0.0 0.3 1926012 29320 ? Ssl Aug13 0:48 /snap/snapd/current/usr/lib/snapd/snapd\nroot 3709299 1.7 0.3 1620160 28360 ? Sl 19:49 0:00 /snap/amazon-ssm-agent/13349/ssm-document-worker 30b02320-117d-466a-8755-44b8cd816992\nroot 3709350 50.0 0.3 1620416 28192 ? Sl 19:50 0:00 /snap/amazon-ssm-agent/13349/ssm-document-worker 5759e243-ffd3-4f6f-a765-41414513143e\nroot 183 0.0 0.3 288960 26532 ? SLsl Aug13 1:24 /sbin/multipathd -d -s\nroot 698 0.0 0.2 110060 21896 ? Ssl Aug13 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal\nroot 570 0.0 0.2 32564 20684 ? Ss Aug13 0:03 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers\nroot 577 0.0 0.2 1832820 19344 ? Ssl Aug13 1:08 /snap/amazon-ssm-agent/13349/amazon-ssm-agent\nroot 2681 0.0 0.1 1268532 15380 ? Sl Aug13 11:57 /usr/bin/containerd-shim-runc-v2 -namespace moby -id a8f1465efc695cbe55fc1b0a2a3352ad0532104847f062065bd3dc7e7075a5aa -address /run/containerd/containerd.sock\nroot 2700 0.0 0.1 1268532 15168 ? Sl Aug13 11:57 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 15f495363998b7c196826202b6aa584976bf8b4a37ece873c3d3869caa973efe -address /run/containerd/containerd.sock\n59000 1649 0.0 0.1 1233880 14316 ? Ssl Aug13 11:16 /redis_exporter --web.listen-address=0.0.0.0:9121 --tls-ca-cert-file=/tls/ca.crt\nroot 1 0.0 0.1 22824 14228 ? Ss Aug13 0:57 /usr/lib/systemd/systemd --system --deserialize=87\nroot 1623733 0.0 0.1 469160 13664 ? Ssl Aug27 0:03 /usr/libexec/udisks2/udisksd\nsystemd+ 3006514 0.0 0.1 21476 13300 ? Ss 06:53 0:03 /usr/lib/systemd/systemd-resolved",
"stderr": ""
},
"listening": {
"status": "Success",
"stdout": "udp UNCONN 0 0 0.0.0.0:51820 0.0.0.0:* \nudp UNCONN 0 0 127.0.0.1:3128 0.0.0.0:* users:((\"netbird\",pid=2429504,fd=16)) \nudp UNCONN 0 0 127.0.0.54:53 0.0.0.0:* users:((\"systemd-resolve\",pid=3006514,fd=16)) \nudp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:((\"systemd-resolve\",pid=3006514,fd=14)) \nudp UNCONN 0 0 100.112.95.128:53 0.0.0.0:* users:((\"netbird\",pid=2429504,fd=28)) \nudp UNCONN 0 0 172.31.26.26%ens5:68 0.0.0.0:* users:((\"systemd-network\",pid=3006513,fd=23)) \nudp UNCONN 0 0 127.0.0.1:323 0.0.0.0:* users:((\"chronyd\",pid=3006120,fd=5)) \nudp UNCONN 0 0 [::]:51820 [::]:* \nudp UNCONN 0 0 [::1]:323 [::]:* users:((\"chronyd\",pid=3006120,fd=6)) \ntcp LISTEN 0 4096 127.0.0.1:3000 0.0.0.0:* users:((\"docker-proxy\",pid=2176,fd=8)) \ntcp LISTEN 0 4096 127.0.0.1:6380 0.0.0.0:* users:((\"docker-proxy\",pid=2819,fd=8)) \ntcp LISTEN 0 4096 127.0.0.1:8090 0.0.0.0:* users:((\"docker-proxy\",pid=1818,fd=8)) \ntcp LISTEN 0 4096 127.0.0.1:8091 0.0.0.0:* users:((\"docker-proxy\",pid=1927,fd=8)) \ntcp LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:((\"sshd\",pid=3006515,fd=3),(\"systemd\",pid=1,fd=242)) \ntcp LISTEN 0 4096 127.0.0.1:9093 0.0.0.0:* users:((\"docker-proxy\",pid=2063,fd=8)) \ntcp LISTEN 0 4096 127.0.0.1:9090 0.0.0.0:* users:((\"docker-proxy\",pid=2134,fd=8)) \ntcp LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:((\"nginx\",pid=1623744,fd=7),(\"nginx\",pid=1623743,fd=7),(\"nginx\",pid=1623742,fd=7))\ntcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* users:((\"systemd-resolve\",pid=3006514,fd=15)) \ntcp LISTEN 0 4096 127.0.0.54:53 0.0.0.0:* users:((\"systemd-resolve\",pid=3006514,fd=17)) \ntcp LISTEN 0 4096 100.112.95.128:53 0.0.0.0:* users:((\"netbird\",pid=2429504,fd=27)) \ntcp LISTEN 0 4096 [::]:22 [::]:* users:((\"sshd\",pid=3006515,fd=4),(\"systemd\",pid=1,fd=247))",
"stderr": ""
},
"systemd_units": {
"status": "Success",
"stdout": " acpid.service loaded active running ACPI event daemon\n amazon-guardduty-agent.service loaded active running Amazon GuardDuty Agent\n chrony.service loaded active running chrony, an NTP client/server\n containerd.service loaded active running containerd container runtime\n cron.service loaded active running Regular background program processing daemon\n dbus.service loaded active running D-Bus System Message Bus\n docker.service loaded active running Docker Application Container Engine\n getty@tty1.service loaded active running Getty on tty1\n gitlab-runner.service loaded active running GitLab Runner\n irqbalance.service loaded active running irqbalance daemon\n ModemManager.service loaded active running Modem Manager\n multipathd.service loaded active running Device-Mapper Multipath Device Controller\n networkd-dispatcher.service loaded active running Dispatcher daemon for systemd-networkd\n nginx.service loaded active running A high performance web server and a reverse proxy server\n polkit.service loaded active running Authorization Manager\n rsyslog.service loaded active running System Logging Service\n serial-getty@ttyS0.service loaded active running Serial Getty on ttyS0\n snap.amazon-ssm-agent.amazon-ssm-agent.service loaded active running Service for snap application amazon-ssm-agent.amazon-ssm-agent\n snap.netbird.service-run.service loaded active running Service for snap application netbird.service-run\n snapd.service loaded active running Snap Daemon\n ssh.service loaded active running OpenBSD Secure Shell server\n systemd-journald.service loaded active running Journal Service\n systemd-logind.service loaded active running User Login Management\n systemd-networkd.service loaded active running Network Configuration\n systemd-resolved.service loaded active running Network Name Resolution\n systemd-udevd.service loaded active running Rule-based Manager for Device Events and Files\n udisks2.service loaded active running Disk Manager\n unattended-upgrades.service loaded active running Unattended Upgrades Shutdown",
"stderr": ""
},
"systemd_failed": {
"status": "Success",
"stdout": "",
"stderr": ""
},
"docker": {
"status": "Success",
"stdout": "dev-green-postprocess-1\t716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/postprocessor:33504e02\tUp 27 hours (healthy)\ndev-green-redis-1\tredis:7-alpine\tUp 27 hours (healthy)\ndev-green-soniox-1\t716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/sonioxtranscriber:7393c940\tUp 3 days (healthy)\ndev-green-patient-document-parser-1\t716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/patientdocumentparser:53586cc8\tUp 3 days (healthy)\ndev-blue-svc-1\t716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/patientsummaryservice:a41e2105\tUp 3 days (healthy)\ndev-green-saisuggestions-1\t716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/saisuggestions:02c3dd66\tUp 3 days (healthy)\nsai_suggestions_redis\tredis:7-alpine\tUp 2 weeks (healthy)\nsoniox_transcriber_redis\tredis:7-alpine\tUp 2 weeks (healthy)\nml_monitoring-grafana-1\tgrafana/grafana:11.2.0\tUp 2 weeks (healthy)\nml_monitoring-prometheus-1\tprom/prometheus:v2.54.1\tUp 2 weeks (healthy)\nml_monitoring-alertmanager-1\tprom/alertmanager:v0.28.1\tUp 2 weeks (healthy)\nml_monitoring-redis_exporter-1\toliver006/redis_exporter:v1.62.0\tUp 2 weeks\ntraefik-traefik-1\ttraefik:v3.7\tUp 2 weeks\npatient_document_parser-patient-document-parser-1\tpatient_document_parser-patient-document-parser\tExited (0) 2 months ago\nsoniox_transcriber-soniox-transcriber-service-1\tsoniox_transcriber-soniox-transcriber-service\tExited (137) 2 months ago\nsoniox_transcriber-redis-1\tredis:7-alpine\tExited (0) 2 months ago\nsai_suggestions_v2\tsai_suggestions-sai_suggestions\tExited (0) 2 months ago\npatient-summary-service-svc-1\tpatient-summary-service-svc\tExited (0) 2 months ago\ncompetent_lichterman\t4bfe3adfd150\tExited (0) 5 months ago",
"stderr": ""
},
"docker_images": {
"status": "Success",
"stdout": "716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/postprocessor:33504e02\t2026-08-27 16:45:03 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/saisuggestions:02c3dd66\t2026-08-25 12:19:58 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/postprocessor:239d587d\t2026-08-25 12:19:11 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/sonioxtranscriber:7393c940\t2026-08-25 12:17:54 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/patientdocumentparser:53586cc8\t2026-08-25 12:16:59 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/patientsummaryservice:a41e2105\t2026-08-25 12:15:25 +0000 UTC\npython:3.10-slim\t2026-08-25 01:21:04 +0000 UTC\npython:3.11-slim\t2026-08-25 01:20:06 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/saisuggestions:d8fffe5a\t2026-08-24 14:22:21 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/patientdocumentparser:737ff087\t2026-08-21 19:06:25 +0000 UTC\nregistry.gitlab.com/gitlab-org/gitlab-runner/gitlab-runner-helper:x86_64-v19.2.2\t2026-08-13 08:40:04 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/sonioxtranscriber:6f14e0cf\t2026-08-10 09:10:33 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/patientsummaryservice:69147b24\t2026-08-10 09:09:29 +0000 UTC\npatient_document_parser-patient-document-parser:latest\t2026-06-16 03:40:32 +0000 UTC\nsoniox_transcriber-soniox-transcriber-service:latest\t2026-06-16 03:39:43 +0000 UTC\nsai_suggestions-sai_suggestions:latest\t2026-06-16 03:35:54 +0000 UTC\npatient-summary-service-svc:latest\t2026-06-11 22:49:51 +0000 UTC\ntraefik:v3.7\t2026-06-10 17:56:26 +0000 UTC\nredis:7-alpine\t2026-02-23 17:35:24 +0000 UTC\nprom/alertmanager:v0.28.1\t2025-03-07 15:10:29 +0000 UTC",
"stderr": ""
},
"oom_kills": {
"status": "Success",
"stdout": "",
"stderr": ""
},
"svc_restarts": {
"status": "Success",
"stdout": "",
"stderr": ""
},
"reboots": {
"status": "Success",
"stdout": "reboot system boot 7.0.0-1010-aws Thu Aug 13 06:14 still running\nreboot system boot 6.17.0-1013-aws Mon May 11 12:01 - 06:14 (93+18:13)\nreboot system boot 6.17.0-1009-aws Mon Mar 16 14:20 - 11:59 (55+21:38)\nreboot system boot 6.14.0-1018-aws Thu Mar 5 15:07 - 11:59 (66+20:51)\n\nwtmp begins Thu Mar 5 15:07:06 2026",
"stderr": ""
},
"cron": {
"status": "Success",
"stdout": "total 32\ndrwxr-xr-x 2 root root 4096 May 4 09:16 .\ndrwxr-xr-x 117 root root 12288 Aug 28 06:53 ..\n-rw-r--r-- 1 root root 102 Mar 31 2024 .placeholder\n-rw-r--r-- 1 root root 802 Apr 16 2023 certbot\n-rw-r--r-- 1 root root 201 Apr 8 2024 e2scrub_all\n-rw-r--r-- 1 root root 396 Jan 9 2024 sysstat\n# Edit this file to introduce tasks to be run by cron.\n# \n# Each task to run has to be defined through a single line\n# indicating with different fields when the task will be run\n# and what command to run for the task\n# \n# To define the time you can provide concrete values for\n# minute (m), hour (h), day of month (dom), month (mon),\n# and day of week (dow) or use '*' in these fields (for 'any').\n# \n# Notice that tasks will be started based on the cron's system\n# daemon's notion of time and timezones.\n# \n# Output of the crontab jobs (including errors) is sent through\n# email to the user the crontab file belongs to (unless redirected).\n# \n# For example, you can run a backup of all your user accounts\n# at 5 a.m every week with:\n# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/\n# \n# For more information see the manual pages of crontab(5) and cron(8)\n# \n# m h dom mon dow command\n0 3 * * * /home/ubuntu/docker_clean.sh >> /var/log/docker_clean.log 2>&1",
"stderr": ""
}
},
"i-046e7fc4677eaa796": {
"os_release": {
"status": "Success",
"stdout": "PRETTY_NAME=\"Ubuntu 24.04.4 LTS\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"24.04\"\nVERSION=\"24.04.4 LTS (Noble Numbat)\"\nVERSION_CODENAME=noble\nID=ubuntu\nID_LIKE=debian\nHOME_URL=\"https://www.ubuntu.com/\"\nSUPPORT_URL=\"https://help.ubuntu.com/\"\nBUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu/\"\nPRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\nUBUNTU_CODENAME=noble\nLOGO=ubuntu-logo\nLinux ip-172-31-15-39 7.0.0-1010-aws #10~24.04.1-Ubuntu SMP PREEMPT Mon Jul 27 17:41:33 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux",
"stderr": ""
},
"uptime_load": {
"status": "Success",
"stdout": " 19:50:28 up 15 days, 13:15, 0 user, load average: 0.09, 0.14, 0.15\n0.09 0.14 0.15 1/567 3544357",
"stderr": ""
},
"disk": {
"status": "Success",
"stdout": "Filesystem Size Used Avail Use% Mounted on\n/dev/root 193G 16G 177G 9% /\ntmpfs 3.8G 0 3.8G 0% /dev/shm\ntmpfs 1.6G 2.1M 1.6G 1% /run\ntmpfs 5.0M 0 5.0M 0% /run/lock\nefivarfs 128K 3.8K 120K 4% /sys/firmware/efi/efivars\n/dev/nvme0n1p16 881M 202M 617M 25% /boot\n/dev/nvme0n1p15 105M 6.2M 99M 6% /boot/efi\noverlay 193G 16G 177G 9% /var/lib/docker/rootfs/overlayfs/dc4f0eea66d0ef7f68fdbce545dde313a70dc31cb7ebc974151456fc00e32c9b\noverlay 193G 16G 177G 9% /var/lib/docker/rootfs/overlayfs/593c1f008ef4b3435f5c87dba7aaf3e0e7626474afd85723bf20f39641b17ebd\noverlay 193G 16G 177G 9% /var/lib/docker/rootfs/overlayfs/09d2bcc0019a83128cefc04bd3fe7b285139300fb719785c3eaff8f25a455049\noverlay 193G 16G 177G 9% /var/lib/docker/rootfs/overlayfs/8bf98332778bea88cef93a3a7f2f3aae75adf266af13595c32097f84d1455cc3\noverlay 193G 16G 177G 9% /var/lib/docker/rootfs/overlayfs/d3082c17054f4df1d0f4153c227394c5c81a21cdddc77dcd780522d299d38a9b\noverlay 193G 16G 177G 9% /var/lib/docker/rootfs/overlayfs/70b3522388f403c2ca8efc798a3e70d6ede66cba286abb5f9dbb983eb7c4d029\noverlay 193G 16G 177G 9% /var/lib/docker/rootfs/overlayfs/585d70b786a8639b2ef434cfb94b3e671b7b43eeef79939c425e8141486479b0\noverlay 193G 16G 177G 9% /var/lib/docker/rootfs/overlayfs/f789b113f1043cffd988aaecaf20b779671d7b9147c2c74ea51ef20780f21919\noverlay 193G 16G 177G 9% /var/lib/docker/rootfs/overlayfs/02bfe27dc799c3db9b2ee96fa2b4dc580091cc1cf6339a2ef606d332da728d37\noverlay 193G 16G 177G 9% /var/lib/docker/rootfs/overlayfs/0a15f48f5e0ff2766db09d7424a7422d15f039604897123ab18bde5967306b7f\noverlay 193G 16G 177G 9% /var/lib/docker/rootfs/overlayfs/18171bc17d5e150474540790ed497f21043316b3787e247c5b3f47ea78679f17\noverlay 193G 16G 177G 9% /var/lib/docker/rootfs/overlayfs/d6e65594744f415245bd590bb829cba8cf2e472fb3760eaa48643245fc93bdea\noverlay 193G 16G 177G 9% /var/lib/docker/rootfs/overlayfs/212e6f24ca3a19a26aa952f2efd504b980ed4af6b1e33908ea7eb52a9e0118c9\n--- inodes\nFilesystem Inodes IUsed IFree IUse% Mounted on\n/dev/root 26083328 406304 25677024 2% /\ntmpfs 989732 2 989730 1% /dev/shm\ntmpfs 819200 1110 818090 1% /run\ntmpfs 989732 3 989729 1% /run/lock\nefivarfs 0 0 0 - /sys/firmware/efi/efivars\n/dev/nvme0n1p16 58496 605 57891 2% /boot\n/dev/nvme0n1p15 0 0 0 - /boot/efi\noverlay 26083328 406304 25677024 2% /var/lib/docker/rootfs/overlayfs/dc4f0eea66d0ef7f68fdbce545dde313a70dc31cb7ebc974151456fc00e32c9b\noverlay 26083328 406304 25677024 2% /var/lib/docker/rootfs/overlayfs/593c1f008ef4b3435f5c87dba7aaf3e0e7626474afd85723bf20f39641b17ebd\noverlay 26083328 406304 25677024 2% /var/lib/docker/rootfs/overlayfs/09d2bcc0019a83128cefc04bd3fe7b285139300fb719785c3eaff8f25a455049\noverlay 26083328 406304 25677024 2% /var/lib/docker/rootfs/overlayfs/8bf98332778bea88cef93a3a7f2f3aae75adf266af13595c32097f84d1455cc3\noverlay 26083328 406304 25677024 2% /var/lib/docker/rootfs/overlayfs/d3082c17054f4df1d0f4153c227394c5c81a21cdddc77dcd780522d299d38a9b\noverlay 26083328 406304 25677024 2% /var/lib/docker/rootfs/overlayfs/70b3522388f403c2ca8efc798a3e70d6ede66cba286abb5f9dbb983eb7c4d029\noverlay 26083328 406304 25677024 2% /var/lib/docker/rootfs/overlayfs/585d70b786a8639b2ef434cfb94b3e671b7b43eeef79939c425e8141486479b0\noverlay 26083328 406304 25677024 2% /var/lib/docker/rootfs/overlayfs/f789b113f1043cffd988aaecaf20b779671d7b9147c2c74ea51ef20780f21919\noverlay 26083328 406304 25677024 2% /var/lib/docker/rootfs/overlayfs/02bfe27dc799c3db9b2ee96fa2b4dc580091cc1cf6339a2ef606d332da728d37\noverlay 26083328 406304 25677024 2% /var/lib/docker/rootfs/overlayfs/0a15f48f5e0ff2766db09d7424a7422d15f039604897123ab18bde5967306b7f\noverlay 26083328 406304 25677024 2% /var/lib/docker/rootfs/overlayfs/18171bc17d5e150474540790ed497f21043316b3787e247c5b3f47ea78679f17\noverlay 26083328 406304 25677024 2% /var/lib/docker/rootfs/overlayfs/d6e65594744f415245bd590bb829cba8cf2e472fb3760eaa48643245fc93bdea\noverlay 26083328 406304 25677024 2% /var/lib/docker/rootfs/overlayfs/212e6f24ca3a19a26aa952f2efd504b980ed4af6b1e33908ea7eb52a9e0118c9",
"stderr": ""
},
"memory": {
"status": "Success",
"stdout": " total used free shared buff/cache available\nMem: 7.6Gi 2.3Gi 834Mi 3.9Mi 4.7Gi 5.2Gi\nSwap: 0B 0B 0B\n--- swap",
"stderr": ""
},
"code_dirs": {
"status": "Success",
"stdout": "/home:\ntotal 20\ndrwxr-xr-x 5 root root 4096 Jul 1 10:18 .\ndrwxr-xr-x 22 root root 4096 Aug 13 06:35 ..\ndrwxr-x--- 5 deploy deploy 4096 Jul 1 12:11 deploy\ndrwxr-x--- 2 gitlab-runner gitlab-runner 4096 Jul 1 10:18 gitlab-runner\ndrwxr-x--- 11 ubuntu ubuntu 4096 Jul 14 07:05 ubuntu\n\n/opt:\ntotal 32\ndrwxr-xr-x 5 root root 4096 Jul 15 15:14 .\ndrwxr-xr-x 22 root root 4096 Aug 13 06:35 ..\n-rw-rw-r-- 1 deploy deploy 663 Jun 24 11:34 .env\ndrwxr-xr-x 5 root root 4096 Aug 26 00:53 aws\ndrwx--x--x 4 root root 4096 Mar 5 14:10 containerd\n-rw-r--r-- 1 root root 4325 May 6 11:05 default\ndrwxr-xr-x 3 root root 4096 Jul 14 06:57 redis-tls\n\n/srv:\ntotal 56\ndrwxr-xr-x 10 ubuntu ubuntu 4096 Jul 14 07:01 .\ndrwxr-xr-x 22 root root 4096 Aug 13 06:35 ..\n-rw-rw-r-- 1 ubuntu ubuntu 13833 Mar 23 13:13 AGENTS.md\ndrwxr-xr-x 7 deploy deploy 4096 Jul 20 19:38 ml_monitoring\ndrwxr-xr-x 10 ubuntu ubuntu 4096 Jun 29 20:13 patient-summary-service\ndrwxr-xr-x 9 ubuntu ubuntu 4096 Jun 29 20:13 patient_document_parser\ndrwxr-xr-x 13 ubuntu ubuntu 4096 Jun 29 20:13 post_processor\ndrwxr-xr-x 2 root root 4096 Jul 15 12:47 redis-tls\ndrwxr-xr-x 4 root root 4096 Jul 1 18:06 redis_db\ndrwxr-xr-x 23 ubuntu ubuntu 4096 Jun 29 20:13 sai_suggestions\ndrwxr-xr-x 10 ubuntu ubuntu 4096 Jun 29 20:13 soniox_transcriber\n\n/var/www:\ntotal 12\ndrwxr-xr-x 3 root root 4096 May 5 07:11 .\ndrwxr-xr-x 14 root root 4096 May 5 07:11 ..\ndrwxr-xr-x 2 root root 4096 May 5 07:11 html",
"stderr": ""
},
"git_checkouts": {
"status": "Success",
"stdout": "/srv/sai_suggestions/.git\n/srv/patient-summary-service/.git\n/srv/patient_document_parser/.git\n/srv/ml_monitoring/.git\n/srv/post_processor/.git\n/srv/soniox_transcriber/.git\n/home/ubuntu/.codex/.tmp/plugins/.git",
"stderr": ""
},
"git_remotes": {
"status": "Success",
"stdout": "== /srv/sai_suggestions\n== /srv/patient-summary-service\n== /srv/patient_document_parser\n== /srv/ml_monitoring\n== /srv/post_processor\n== /srv/soniox_transcriber\n== /home/ubuntu/.codex/.tmp/plugins",
"stderr": ""
},
"manifests": {
"status": "Success",
"stdout": "/usr/share/doc/python3-botocore/requirements.txt\n/srv/sai_suggestions/requirements.txt\n/srv/sai_suggestions/tests/e2e/docker-compose.yml\n/srv/sai_suggestions/pyproject.toml\n/srv/sai_suggestions/Dockerfile\n/srv/sai_suggestions/docker-compose.yml\n/srv/patient-summary-service/requirements.txt\n/srv/patient-summary-service/pyproject.toml\n/srv/patient-summary-service/Dockerfile\n/srv/patient-summary-service/docker-compose.yml\n/srv/patient_document_parser/requirements.txt\n/srv/patient_document_parser/Dockerfile\n/srv/patient_document_parser/docker-compose.yml\n/srv/ml_monitoring/tests/mocks/Dockerfile\n/srv/ml_monitoring/pyproject.toml\n/srv/ml_monitoring/docker-compose.yml\n/srv/post_processor/requirements.txt\n/srv/post_processor/pyproject.toml\n/srv/post_processor/docker/Dockerfile\n/srv/post_processor/docker/docker-compose.yml\n/srv/soniox_transcriber/requirements.txt\n/srv/soniox_transcriber/tests/e2e/docker-compose.yml\n/srv/soniox_transcriber/pyproject.toml\n/srv/soniox_transcriber/docker/Dockerfile\n/srv/soniox_transcriber/docker/docker-compose.yml\n/home/ubuntu/.vscode-server/extensions/github.copilot-chat-0.36.2/package.json\n/home/ubuntu/.vscode-server/extensions/openai.chatgpt-26.506.31421-linux-x64/package.json\n/home/ubuntu/.vscode-server/extensions/openai.chatgpt-26.429.30905-linux-x64/package.json\n/home/ubuntu/.vscode-server/extensions/github.copilot-1.388.0/package.json\n/home/ubuntu/.vscode-server/extensions/github.vscode-pull-request-github-0.126.0/package.json",
"stderr": ""
},
"processes": {
"status": "Success",
"stdout": "USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND\nroot 1791 0.2 4.0 1110456 322956 ? Ssl Aug13 50:34 /usr/local/bin/python3.11 /usr/local/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000\nubuntu 1859 0.2 3.9 550928 312692 ? Ssl Aug13 53:11 /usr/local/bin/python3.11 /usr/local/bin/uvicorn main:app --host 0.0.0.0 --port 8000\nroot 1857 0.2 3.8 684340 301360 ? Ssl Aug13 58:17 /usr/local/bin/python3.11 /usr/local/bin/uvicorn sai_suggestions.api.main:app --host 0.0.0.0 --port 8000\nroot 2091197 0.2 3.2 644384 259620 ? Ssl Aug27 4:12 python -m app.main\nubuntu 2803851 0.2 3.0 501016 243864 ? Ssl Aug21 22:05 /usr/local/bin/python3.11 /usr/local/bin/uvicorn app:app --host 0.0.0.0 --port 8000\n472 1887 0.0 2.0 1538692 165088 ? Ssl Aug13 22:21 grafana server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --packaging=docker cfg:default.log.mode=console cfg:default.paths.data=/var/lib/grafana cfg:default.paths.logs=/var/log/grafana cfg:default.paths.plugins=/var/lib/grafana/plugins cfg:default.paths.provisioning=/etc/grafana/provisioning\nroot 850 0.5 1.4 2692076 114856 ? Ssl Aug13 115:49 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock\nnobody 1788 0.1 1.3 1757612 110120 ? Ssl Aug13 42:20 /bin/prometheus --web.listen-address=0.0.0.0:9090 --config.file=/tmp/prometheus.yml --storage.tsdb.path=/prometheus --storage.tsdb.retention.time=7d\nroot 1778 0.1 1.2 1402200 95220 ? Ssl Aug13 22:40 traefik traefik --providers.docker=true --providers.docker.exposedbydefault=false --providers.docker.network=traefik-net --entrypoints.web.address=:8090 --entrypoints.internal.address=:8091\nroot 548 0.0 0.9 1365648 77652 ? Ssl Aug13 9:36 /usr/bin/gitlab-runner run --config /etc/gitlab-runner/config.toml --working-directory /home/gitlab-runner --service gitlab-runner --user gitlab-runner\nroot 551 0.4 0.8 1282016 67988 ? Ssl Aug13 94:50 /usr/bin/netbird service run --log-level info --daemon-addr unix:///var/run/netbird.sock --log-file /var/log/netbird/client.log\nroot 618 0.3 0.8 2514128 66892 ? Ssl Aug13 75:44 /usr/bin/containerd\nroot 11880 0.1 0.7 998760 58708 ? Ssl Aug13 39:01 /opt/aws/amazon-guardduty-agent/bin/amazon-guardduty-agent --worker-threads 8\nroot 1485944 0.0 0.6 107768 51588 ? S<s Aug27 0:03 /usr/lib/systemd/systemd-journald\nroot 3458301 0.0 0.5 1925500 42632 ? Ssl Aug15 0:36 /snap/snapd/current/usr/lib/snapd/snapd\nnobody 1779 0.0 0.4 1255080 38724 ? Ssl Aug13 18:26 /bin/alertmanager --config.file=/tmp/alertmanager.yml --web.listen-address=0.0.0.0:9093 --storage.path=/alertmanager\nroot 2663 0.0 0.4 2212664 35296 ? Sl Aug13 5:57 /snap/amazon-ssm-agent/13349/ssm-agent-worker\nroot 3544776 75.0 0.3 1620160 28152 ? Sl 19:50 0:00 /snap/amazon-ssm-agent/13349/ssm-document-worker e4868bb4-b811-4733-9872-1aa517f39b08\nroot 3544764 1.8 0.3 1693892 28084 ? Sl 19:50 0:00 /snap/amazon-ssm-agent/13349/ssm-document-worker 27264072-49f5-4577-98ab-80b0dac9b69e\nroot 182 0.0 0.3 288960 26924 ? SLsl Aug13 1:35 /sbin/multipathd -d -s\nroot 684 0.0 0.2 110060 22756 ? Ssl Aug13 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal\nroot 556 0.0 0.2 1832820 21392 ? Ssl Aug13 1:13 /snap/amazon-ssm-agent/13349/amazon-ssm-agent\nroot 552 0.0 0.2 32564 20732 ? Ss Aug13 0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers\nroot 3204 0.0 0.1 1268276 15252 ? Sl Aug13 12:18 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 0a15f48f5e0ff2766db09d7424a7422d15f039604897123ab18bde5967306b7f -address /run/containerd/containerd.sock\nroot 3172 0.0 0.1 1268532 15116 ? Sl Aug13 12:02 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 02bfe27dc799c3db9b2ee96fa2b4dc580091cc1cf6339a2ef606d332da728d37 -address /run/containerd/containerd.sock\n59000 1807 0.0 0.1 1233880 14956 ? Ssl Aug13 10:26 /redis_exporter --web.listen-address=0.0.0.0:9121 --tls-ca-cert-file=/tls/ca.crt\nroot 1385 0.0 0.1 1268276 14316 ? Sl Aug13 15:47 /usr/bin/containerd-shim-runc-v2 -namespace moby -id dc4f0eea66d0ef7f68fdbce545dde313a70dc31cb7ebc974151456fc00e32c9b -address /run/containerd/containerd.sock\nroot 1 0.0 0.1 22688 14172 ? Ss Aug13 0:37 /usr/lib/systemd/systemd --system --deserialize=92\nroot 1485947 0.0 0.1 469148 13960 ? Ssl Aug27 0:03 /usr/libexec/udisks2/udisksd",
"stderr": ""
},
"listening": {
"status": "Success",
"stdout": "udp UNCONN 0 0 0.0.0.0:51820 0.0.0.0:* \nudp UNCONN 0 0 127.0.0.1:3128 0.0.0.0:* users:((\"netbird\",pid=551,fd=18)) \nudp UNCONN 0 0 127.0.0.54:53 0.0.0.0:* users:((\"systemd-resolve\",pid=1485946,fd=16)) \nudp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:((\"systemd-resolve\",pid=1485946,fd=14)) \nudp UNCONN 0 0 100.112.114.187:53 0.0.0.0:* users:((\"netbird\",pid=551,fd=26)) \nudp UNCONN 0 0 172.31.15.39%ens5:68 0.0.0.0:* users:((\"systemd-network\",pid=1485967,fd=23)) \nudp UNCONN 0 0 127.0.0.1:323 0.0.0.0:* users:((\"chronyd\",pid=637,fd=5)) \nudp UNCONN 0 0 [::]:51820 [::]:* \nudp UNCONN 0 0 [::1]:323 [::]:* users:((\"chronyd\",pid=637,fd=6)) \ntcp LISTEN 0 4096 127.0.0.1:6380 0.0.0.0:* users:((\"docker-proxy\",pid=3304,fd=8)) \ntcp LISTEN 0 4096 127.0.0.1:3000 0.0.0.0:* users:((\"docker-proxy\",pid=2397,fd=8)) \ntcp LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:((\"sshd\",pid=1485948,fd=3),(\"systemd\",pid=1,fd=113)) \ntcp LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:((\"nginx\",pid=1485963,fd=7),(\"nginx\",pid=1485962,fd=7),(\"nginx\",pid=1485961,fd=7))\ntcp LISTEN 0 4096 127.0.0.1:8090 0.0.0.0:* users:((\"docker-proxy\",pid=2300,fd=8)) \ntcp LISTEN 0 4096 127.0.0.1:8091 0.0.0.0:* users:((\"docker-proxy\",pid=2326,fd=8)) \ntcp LISTEN 0 4096 100.112.114.187:53 0.0.0.0:* users:((\"netbird\",pid=551,fd=27)) \ntcp LISTEN 0 4096 127.0.0.54:53 0.0.0.0:* users:((\"systemd-resolve\",pid=1485946,fd=17)) \ntcp LISTEN 0 4096 127.0.0.1:9093 0.0.0.0:* users:((\"docker-proxy\",pid=2034,fd=8)) \ntcp LISTEN 0 4096 127.0.0.1:9090 0.0.0.0:* users:((\"docker-proxy\",pid=2364,fd=8)) \ntcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* users:((\"systemd-resolve\",pid=1485946,fd=15)) \ntcp LISTEN 0 4096 [::]:22 [::]:* users:((\"sshd\",pid=1485948,fd=4),(\"systemd\",pid=1,fd=114))",
"stderr": ""
},
"systemd_units": {
"status": "Success",
"stdout": " acpid.service loaded active running ACPI event daemon\n amazon-guardduty-agent.service loaded active running Amazon GuardDuty Agent\n chrony.service loaded active running chrony, an NTP client/server\n containerd.service loaded active running containerd container runtime\n cron.service loaded active running Regular background program processing daemon\n dbus.service loaded active running D-Bus System Message Bus\n docker.service loaded active running Docker Application Container Engine\n getty@tty1.service loaded active running Getty on tty1\n gitlab-runner.service loaded active running GitLab Runner\n irqbalance.service loaded active running irqbalance daemon\n ModemManager.service loaded active running Modem Manager\n multipathd.service loaded active running Device-Mapper Multipath Device Controller\n netbird.service loaded active running NetBird mesh network client\n networkd-dispatcher.service loaded active running Dispatcher daemon for systemd-networkd\n nginx.service loaded active running A high performance web server and a reverse proxy server\n polkit.service loaded active running Authorization Manager\n rsyslog.service loaded active running System Logging Service\n serial-getty@ttyS0.service loaded active running Serial Getty on ttyS0\n snap.amazon-ssm-agent.amazon-ssm-agent.service loaded active running Service for snap application amazon-ssm-agent.amazon-ssm-agent\n snapd.service loaded active running Snap Daemon\n ssh.service loaded active running OpenBSD Secure Shell server\n systemd-journald.service loaded active running Journal Service\n systemd-logind.service loaded active running User Login Management\n systemd-networkd.service loaded active running Network Configuration\n systemd-resolved.service loaded active running Network Name Resolution\n systemd-udevd.service loaded active running Rule-based Manager for Device Events and Files\n udisks2.service loaded active running Disk Manager\n unattended-upgrades.service loaded active running Unattended Upgrades Shutdown",
"stderr": ""
},
"systemd_failed": {
"status": "Success",
"stdout": "\u25cf sai-suggestions-redis.service loaded failed failed SAI Suggestions Redis",
"stderr": ""
},
"docker": {
"status": "Success",
"stdout": "stage-blue-postprocess-1\t716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/postprocessor:33504e02\tUp 27 hours (healthy)\nstage-blue-redis-1\tredis:7-alpine\tUp 27 hours (healthy)\nstage-green-patient-document-parser-1\t716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/patientdocumentparser:737ff087\tUp 7 days (healthy)\nsai_suggestions_redis\tredis:7-alpine\tUp 2 weeks (healthy)\nsoniox_transcriber_redis\tredis:7-alpine\tUp 2 weeks (healthy)\nstage-blue-saisuggestions-1\t716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/saisuggestions:a188d92a\tUp 2 weeks (healthy)\nstage-green-soniox-1\t716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/sonioxtranscriber:6f14e0cf\tUp 2 weeks (healthy)\nstage-blue-svc-1\t716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/patientsummaryservice:69147b24\tUp 2 weeks (healthy)\nml_monitoring-grafana-1\tgrafana/grafana:11.2.0\tUp 2 weeks (healthy)\nml_monitoring-prometheus-1\tprom/prometheus:v2.54.1\tUp 2 weeks (healthy)\nml_monitoring-alertmanager-1\tprom/alertmanager:v0.28.1\tUp 2 weeks (healthy)\nml_monitoring-redis_exporter-1\toliver006/redis_exporter:v1.62.0\tUp 2 weeks\ntraefik-traefik-1\ttraefik:v3.7\tUp 2 weeks\npatient_document_parser-patient-document-parser-1\tpatient_document_parser-patient-document-parser\tExited (0) 7 weeks ago\npatient-summary-service-svc-1\tpatient-summary-service-svc\tExited (0) 7 weeks ago",
"stderr": ""
},
"docker_images": {
"status": "Success",
"stdout": "716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/postprocessor:33504e02\t2026-08-27 17:00:05 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/postprocessor:1fa89c2d\t2026-08-21 20:08:56 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/patientdocumentparser:737ff087\t2026-08-21 20:05:01 +0000 UTC\nregistry.gitlab.com/gitlab-org/gitlab-runner/gitlab-runner-helper:x86_64-v19.2.2\t2026-08-17 12:48:38 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/saisuggestions:a188d92a\t2026-08-10 13:10:12 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/patientdocumentparser:717a2d89\t2026-08-10 13:06:24 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/sonioxtranscriber:6f14e0cf\t2026-08-10 13:06:15 +0000 UTC\n716468089330.dkr.ecr.us-east-2.amazonaws.com/scrivas/patientsummaryservice:69147b24\t2026-08-10 13:03:56 +0000 UTC\npatient_document_parser-patient-document-parser:latest\t2026-06-29 15:54:43 +0000 UTC\npatient-summary-service-svc:latest\t2026-06-29 15:41:59 +0000 UTC\ntraefik:v3.7\t2026-06-10 17:56:26 +0000 UTC\nredis:7-alpine\t2026-02-23 17:35:24 +0000 UTC\nprom/alertmanager:v0.28.1\t2025-03-07 15:10:29 +0000 UTC\ngrafana/grafana:11.2.0\t2024-08-27 13:56:08 +0000 UTC\nprom/prometheus:v2.54.1\t2024-08-27 11:20:46 +0000 UTC\noliver006/redis_exporter:v1.62.0\t2024-07-17 20:53:05 +0000 UTC\ndocker:24\t2024-06-19 00:17:01 +0000 UTC",
"stderr": ""
},
"oom_kills": {
"status": "Success",
"stdout": "",
"stderr": ""
},
"svc_restarts": {
"status": "Success",
"stdout": "",
"stderr": ""
},
"reboots": {
"status": "Success",
"stdout": "reboot system boot 7.0.0-1010-aws Thu Aug 13 06:35 still running\nreboot system boot 6.17.0-1013-aws Thu May 14 10:34 - 06:35 (90+20:00)\nreboot system boot 6.14.0-1018-aws Thu Mar 5 14:04 - 10:33 (69+20:29)\n\nwtmp begins Thu Mar 5 14:04:12 2026",
"stderr": ""
},
"cron": {
"status": "Success",
"stdout": "total 32\ndrwxr-xr-x 2 root root 4096 May 5 07:41 .\ndrwxr-xr-x 117 root root 12288 Aug 27 06:00 ..\n-rw-r--r-- 1 root root 102 Mar 31 2024 .placeholder\n-rw-r--r-- 1 root root 802 Apr 16 2023 certbot\n-rw-r--r-- 1 root root 201 Apr 8 2024 e2scrub_all\n-rw-r--r-- 1 root root 396 Jan 9 2024 sysstat\n# Edit this file to introduce tasks to be run by cron.\n# \n# Each task to run has to be defined through a single line\n# indicating with different fields when the task will be run\n# and what command to run for the task\n# \n# To define the time you can provide concrete values for\n# minute (m), hour (h), day of month (dom), month (mon),\n# and day of week (dow) or use '*' in these fields (for 'any').\n# \n# Notice that tasks will be started based on the cron's system\n# daemon's notion of time and timezones.\n# \n# Output of the crontab jobs (including errors) is sent through\n# email to the user the crontab file belongs to (unless redirected).\n# \n# For example, you can run a backup of all your user accounts\n# at 5 a.m every week with:\n# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/\n# \n# For more information see the manual pages of crontab(5) and cron(8)\n# \n# m h dom mon dow command\n0 3 * * * /home/ubuntu/docker_clean.sh >> /var/log/docker_clean.log 2>&1",
"stderr": ""
}
},
"i-02754e7ae419cd5db": {
"os_release": {
"status": "Success",
"stdout": "PRETTY_NAME=\"Ubuntu 24.04.4 LTS\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"24.04\"\nVERSION=\"24.04.4 LTS (Noble Numbat)\"\nVERSION_CODENAME=noble\nID=ubuntu\nID_LIKE=debian\nHOME_URL=\"https://www.ubuntu.com/\"\nSUPPORT_URL=\"https://help.ubuntu.com/\"\nBUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu/\"\nPRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\nUBUNTU_CODENAME=noble\nLOGO=ubuntu-logo\nLinux ip-172-31-19-86 7.0.0-1010-aws #10~24.04.1-Ubuntu SMP PREEMPT Mon Jul 27 17:41:33 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux",
"stderr": ""
},
"uptime_load": {
"status": "Success",
"stdout": " 19:51:11 up 15 days, 13:25, 0 user, load average: 0.19, 0.12, 0.10\n0.19 0.12 0.10 2/328 105213",
"stderr": ""
},
"disk": {
"status": "Success",
"stdout": "Filesystem Size Used Avail Use% Mounted on\n/dev/root 24G 6.4G 17G 28% /\ntmpfs 2.0G 0 2.0G 0% /dev/shm\ntmpfs 782M 1.2M 781M 1% /run\ntmpfs 5.0M 0 5.0M 0% /run/lock\n/dev/xvda16 881M 202M 617M 25% /boot\n/dev/xvda15 105M 6.2M 99M 6% /boot/efi\noverlay 24G 6.4G 17G 28% /var/lib/docker/rootfs/overlayfs/ec16e04fb310adc22427b12093cf855bbcb4bb10f23444feb6791372e27fc66d\noverlay 24G 6.4G 17G 28% /var/lib/docker/rootfs/overlayfs/efac20386cb64dd82f0dcd510beef519f21f25a1e7ebb621277334c8f8dc415f\noverlay 24G 6.4G 17G 28% /var/lib/docker/rootfs/overlayfs/b83f92da28a542a416d2524d0e2d12bef5f19d71a0302b8fe6ece3706e84066f\n--- inodes\nFilesystem Inodes IUsed IFree IUse% Mounted on\n/dev/root 3145728 163314 2982414 6% /\ntmpfs 500170 2 500168 1% /dev/shm\ntmpfs 819200 758 818442 1% /run\ntmpfs 500170 3 500167 1% /run/lock\n/dev/xvda16 58496 605 57891 2% /boot\n/dev/xvda15 0 0 0 - /boot/efi\noverlay 3145728 163314 2982414 6% /var/lib/docker/rootfs/overlayfs/ec16e04fb310adc22427b12093cf855bbcb4bb10f23444feb6791372e27fc66d\noverlay 3145728 163314 2982414 6% /var/lib/docker/rootfs/overlayfs/efac20386cb64dd82f0dcd510beef519f21f25a1e7ebb621277334c8f8dc415f\noverlay 3145728 163314 2982414 6% /var/lib/docker/rootfs/overlayfs/b83f92da28a542a416d2524d0e2d12bef5f19d71a0302b8fe6ece3706e84066f",
"stderr": ""
},
"memory": {
"status": "Success",
"stdout": " total used free shared buff/cache available\nMem: 3.8Gi 859Mi 391Mi 2.1Mi 2.9Gi 3.0Gi\nSwap: 0B 0B 0B\n--- swap",
"stderr": ""
},
"code_dirs": {
"status": "Failed",
"stdout": "/home:\ntotal 12\ndrwxr-xr-x 3 root root 4096 Mar 12 14:41 .\ndrwxr-xr-x 22 root root 4096 Aug 13 06:25 ..\ndrwxr-x--- 4 ubuntu ubuntu 4096 Mar 12 18:00 ubuntu\n\n/opt:\ntotal 16\ndrwxr-xr-x 4 root root 4096 Mar 17 07:41 .\ndrwxr-xr-x 22 root root 4096 Aug 13 06:25 ..\ndrwxr-xr-x 5 root root 4096 Aug 26 00:53 aws\ndrwx--x--x 4 root root 4096 Mar 17 07:41 containerd\n\n/srv:\ntotal 28\ndrwxr-xr-x 3 root root 4096 Jun 11 20:58 .\ndrwxr-xr-x 22 root root 4096 Aug 13 06:25 ..\ndrwxr-xr-x 3 root root 4096 Jun 11 20:58 backup\n-rw-r--r-- 1 root root 4687 Mar 17 08:01 compose.yml\n-rw-r--r-- 1 root root 850 Mar 17 08:01 config.yaml\n-rw-r--r-- 1 root root 515 Mar 17 08:01 dashboard.env",
"stderr": "failed to run commands: exit status 2"
},
"git_checkouts": {
"status": "Success",
"stdout": "",
"stderr": ""
},
"git_remotes": {
"status": "Success",
"stdout": "",
"stderr": ""
},
"manifests": {
"status": "Success",
"stdout": "/usr/share/doc/python3-botocore/requirements.txt",
"stderr": ""
},
"processes": {
"status": "Success",
"stdout": "USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND\nroot 1253 0.2 2.6 1404280 107588 ? Ssl Aug13 58:26 traefik traefik --log.level=INFO --accesslog=true --providers.docker=true --providers.docker.exposedbydefault=false --providers.docker.network=netbird --entrypoints.web.address=:80 --entrypoints.websecure.address=:443 --entrypoints.websecure.allowACMEByPass=true --entrypoints.websecure.transport.respondingTimeouts.readTimeout=0 --entrypoints.websecure.transport.respondingTimeouts.writeTimeout=0 --entrypoints.websecure.transport.respondingTimeouts.idleTimeout=0 --entrypoints.web.http.redirections.entrypoint.to=websecure --entrypoints.web.http.redirections.entrypoint.scheme=https --certificatesresolvers.letsencrypt.acme.email=dilbag@devteamspace.com --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json --certificatesresolvers.letsencrypt.acme.tlschallenge=true --serverstransport.forwardingtimeouts.responseheadertimeout=0s --serverstransport.forwardingtimeouts.idleconntimeout=0s\nroot 783 0.0 2.2 2533408 90852 ? Ssl Aug13 17:17 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock\nroot 1252 0.1 1.9 2033336 77536 ? Ssl Aug13 36:44 /go/bin/netbird-server --config /etc/netbird/config.yaml\nroot 1932 0.2 1.5 998780 60872 ? Ssl Aug13 49:58 /opt/aws/amazon-guardduty-agent/bin/amazon-guardduty-agent --worker-threads 8\nroot 101706 0.0 1.2 87900 50444 ? S<s 06:19 0:01 /usr/lib/systemd/systemd-journald\nroot 607 0.0 1.1 1896676 46568 ? Ssl Aug13 20:42 /usr/bin/containerd\nroot 4621 0.0 1.0 1925756 42432 ? Ssl Aug13 0:49 /snap/snapd/current/usr/lib/snapd/snapd\nroot 1503 0.0 0.8 2212664 35504 ? Sl Aug13 6:37 /snap/amazon-ssm-agent/13349/ssm-agent-worker\nroot 105270 1.7 0.7 1620160 28376 ? Sl 19:51 0:00 /snap/amazon-ssm-agent/13349/ssm-document-worker ce03d6ec-1114-4ace-85dc-3cc96b817568\nroot 105281 60.0 0.7 1620160 28120 ? Sl 19:51 0:00 /snap/amazon-ssm-agent/13349/ssm-document-worker 5dbf20c5-44d1-4549-8097-c7f6e7d0eef8\nroot 191 0.0 0.6 288960 27292 ? SLsl Aug13 1:45 /sbin/multipathd -d -s\nroot 694 0.0 0.5 110008 22840 ? Ssl Aug13 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal\nroot 1249 0.0 0.5 24916 22540 ? Ss Aug13 4:03 /usr/bin/python3 /usr/bin/supervisord -c /etc/supervisord.conf\nroot 570 0.0 0.5 1832820 21308 ? Ssl Aug13 1:17 /snap/amazon-ssm-agent/13349/amazon-ssm-agent\nroot 566 0.0 0.5 32428 20784 ? Ss Aug13 0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers\nroot 89081 0.0 0.3 468960 13768 ? Ssl Aug26 0:04 /usr/libexec/udisks2/udisksd\nroot 1 0.0 0.3 22304 13740 ? Ss Aug13 0:38 /usr/lib/systemd/systemd --system --deserialize=75\nsystemd+ 101705 0.0 0.3 21476 13256 ? Ss 06:19 0:02 /usr/lib/systemd/systemd-resolved\nroot 698 0.0 0.3 318156 12812 ? Ssl Aug13 0:00 /usr/sbin/ModemManager\nroot 1180 0.0 0.2 1268276 11096 ? Sl Aug13 1:09 /usr/bin/containerd-shim-runc-v2 -namespace moby -id b83f92da28a542a416d2524d0e2d12bef5f19d71a0302b8fe6ece3706e84066f -address /run/containerd/containerd.sock\nroot 1183 0.0 0.2 1268020 10812 ? Sl Aug13 4:25 /usr/bin/containerd-shim-runc-v2 -namespace moby -id efac20386cb64dd82f0dcd510beef519f21f25a1e7ebb621277334c8f8dc415f -address /run/containerd/containerd.sock\nroot 1179 0.0 0.2 1268084 10704 ? Sl Aug13 1:13 /usr/bin/containerd-shim-runc-v2 -namespace moby -id ec16e04fb310adc22427b12093cf855bbcb4bb10f23444feb6791372e27fc66d -address /run/containerd/containerd.sock\npolkitd 567 0.0 0.2 383668 10012 ? Ssl Aug13 0:23 /usr/lib/polkit-1/polkitd --no-debug\nsystemd+ 101701 0.0 0.2 19004 9988 ? Ss 06:19 0:00 /usr/lib/systemd/systemd-networkd\nroot 574 0.0 0.2 18172 9052 ? Ss Aug13 0:03 /usr/lib/systemd/systemd-logind\nroot 89080 0.0 0.2 29364 8564 ? Ss Aug26 0:01 /usr/lib/systemd/systemd-udevd\nroot 101707 0.0 0.2 12028 8388 ? Ss 06:19 0:00 sshd: /usr/sbin/sshd -D -o AuthorizedKeysCommand /usr/share/ec2-instance-connect/eic_run_authorized_keys %u %f -o AuthorizedKeysCommandUser ec2-instance-connect [listener] 0 of 10-100 startups\nsyslog 738 0.0 0.1 222516 6688 ? Ssl Aug13 0:03 /usr/sbin/rsyslogd -n -iNONE\nmessage+ 559 0.0 0.1 9964 5868 ? Ss Aug13 0:25 @dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only",
"stderr": ""
},
"listening": {
"status": "Success",
"stdout": "udp UNCONN 0 0 127.0.0.54:53 0.0.0.0:* users:((\"systemd-resolve\",pid=101705,fd=16)) \nudp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:((\"systemd-resolve\",pid=101705,fd=14)) \nudp UNCONN 0 0 172.31.19.86%enX0:68 0.0.0.0:* users:((\"systemd-network\",pid=101701,fd=23)) \nudp UNCONN 0 0 127.0.0.1:323 0.0.0.0:* users:((\"chronyd\",pid=102077,fd=5)) \nudp UNCONN 0 0 0.0.0.0:3478 0.0.0.0:* users:((\"docker-proxy\",pid=1414,fd=8)) \nudp UNCONN 0 0 [::1]:323 [::]:* users:((\"chronyd\",pid=102077,fd=6)) \nudp UNCONN 0 0 [::]:3478 [::]:* users:((\"docker-proxy\",pid=1419,fd=8)) \ntcp LISTEN 0 4096 127.0.0.54:53 0.0.0.0:* users:((\"systemd-resolve\",pid=101705,fd=17)) \ntcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* users:((\"systemd-resolve\",pid=101705,fd=15)) \ntcp LISTEN 0 4096 0.0.0.0:443 0.0.0.0:* users:((\"docker-proxy\",pid=1378,fd=8)) \ntcp LISTEN 0 4096 0.0.0.0:80 0.0.0.0:* users:((\"docker-proxy\",pid=1333,fd=8)) \ntcp LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:((\"sshd\",pid=101707,fd=3),(\"systemd\",pid=1,fd=114))\ntcp LISTEN 0 4096 [::]:443 [::]:* users:((\"docker-proxy\",pid=1383,fd=8)) \ntcp LISTEN 0 4096 [::]:80 [::]:* users:((\"docker-proxy\",pid=1352,fd=8)) \ntcp LISTEN 0 4096 [::]:22 [::]:* users:((\"sshd\",pid=101707,fd=4),(\"systemd\",pid=1,fd=118))",
"stderr": ""
},
"systemd_units": {
"status": "Success",
"stdout": " acpid.service loaded active running ACPI event daemon\n amazon-guardduty-agent.service loaded active running Amazon GuardDuty Agent\n chrony.service loaded active running chrony, an NTP client/server\n containerd.service loaded active running containerd container runtime\n cron.service loaded active running Regular background program processing daemon\n dbus.service loaded active running D-Bus System Message Bus\n docker.service loaded active running Docker Application Container Engine\n getty@tty1.service loaded active running Getty on tty1\n irqbalance.service loaded active running irqbalance daemon\n ModemManager.service loaded active running Modem Manager\n multipathd.service loaded active running Device-Mapper Multipath Device Controller\n networkd-dispatcher.service loaded active running Dispatcher daemon for systemd-networkd\n polkit.service loaded active running Authorization Manager\n rsyslog.service loaded active running System Logging Service\n serial-getty@ttyS0.service loaded active running Serial Getty on ttyS0\n snap.amazon-ssm-agent.amazon-ssm-agent.service loaded active running Service for snap application amazon-ssm-agent.amazon-ssm-agent\n snapd.service loaded active running Snap Daemon\n ssh.service loaded active running OpenBSD Secure Shell server\n systemd-journald.service loaded active running Journal Service\n systemd-logind.service loaded active running User Login Management\n systemd-networkd.service loaded active running Network Configuration\n systemd-resolved.service loaded active running Network Name Resolution\n systemd-udevd.service loaded active running Rule-based Manager for Device Events and Files\n udisks2.service loaded active running Disk Manager\n unattended-upgrades.service loaded active running Unattended Upgrades Shutdown",
"stderr": ""
},
"systemd_failed": {
"status": "Success",
"stdout": "",
"stderr": ""
},
"docker": {
"status": "Success",
"stdout": "netbird-traefik\ttraefik:v3.6\tUp 2 weeks\nnetbird-server\tnetbirdio/netbird-server:latest\tUp 2 weeks\nnetbird-dashboard\tnetbirdio/dashboard:latest\tUp 2 weeks",
"stderr": ""
},
"docker_images": {
"status": "Success",
"stdout": "netbirdio/netbird-server:latest\t2026-06-10 20:25:13 +0000 UTC\ntraefik:v3.6\t2026-06-10 17:57:07 +0000 UTC\nnetbirdio/dashboard:latest\t2026-06-05 15:14:36 +0000 UTC",
"stderr": ""
},
"oom_kills": {
"status": "Success",
"stdout": "",
"stderr": ""
},
"svc_restarts": {
"status": "Success",
"stdout": "",
"stderr": ""
},
"reboots": {
"status": "Success",
"stdout": "reboot system boot 7.0.0-1010-aws Thu Aug 13 06:25 still running\nreboot system boot 6.14.0-1018-aws Thu Mar 12 14:41 - 06:24 (153+15:43)\n\nwtmp begins Thu Mar 12 14:41:10 2026",
"stderr": ""
},
"cron": {
"status": "Failed",
"stdout": "total 28\ndrwxr-xr-x 2 root root 4096 Dec 12 2025 .\ndrwxr-xr-x 116 root root 12288 Aug 28 06:19 ..\n-rw-r--r-- 1 root root 102 Mar 31 2024 .placeholder\n-rw-r--r-- 1 root root 201 Apr 8 2024 e2scrub_all\n-rw-r--r-- 1 root root 396 Jan 9 2024 sysstat",
"stderr": "failed to run commands: exit status 1"
}
}
}
}
File diff suppressed because one or more lines are too long
+11 -2
View File
@@ -55,10 +55,16 @@
<div class="eyebrow">Dasnuve · Cloud Discovery</div> <div class="eyebrow">Dasnuve · Cloud Discovery</div>
<h1>Scrivas — AWS Discovery Reports</h1> <h1>Scrivas — AWS Discovery Reports</h1>
<p class="lede">Read-only assessment of the Scrivas AWS Organization (<code>o-qfj0pvhhv7</code>) — footprint, <p class="lede">Read-only assessment of the Scrivas AWS Organization (<code>o-qfj0pvhhv7</code>) — footprint,
security posture, cost, and Organizations governance. Prepared to inform a proposal.</p> security posture, cost, and Organizations governance — extended with an EC2 source-code recovery and production reliability triage. Prepared to inform a proposal.</p>
<div class="meta">2 accounts · us-east-2 primary · generated 2026-08-19 · CONFIDENTIAL</div> <div class="meta">2 accounts · us-east-2 primary · generated 2026-08-19, EC2 code pass 2026-08-28 · CONFIDENTIAL</div>
<div class="cards"> <div class="cards">
<a class="card full" href="findings/code_dashboard.html">
<span class="k">CODE + RELIABILITY</span>
<h2>Source Code &amp; Reliability Triage <span class="badge">time-sensitive</span></h2>
<p>All 10 application repos found as full git checkouts on Scrivas-owned EC2 — recoverable despite the contractor holding the GitLab. Plus the reliability triage: 23 prod containers on one host, no memory limits, no swap.</p>
<span class="go">Open dashboard →</span>
</a>
<a class="card" href="findings/discovery_dashboard.html"> <a class="card" href="findings/discovery_dashboard.html">
<span class="k">FINDINGS</span> <span class="k">FINDINGS</span>
<h2>Discovery Findings</h2> <h2>Discovery Findings</h2>
@@ -83,6 +89,9 @@
<h3>Written report &amp; raw evidence</h3> <h3>Written report &amp; raw evidence</h3>
<ul> <ul>
<li><a href="findings/discovery_report.md">discovery_report.md</a> — narrative writeup <code>(renders on GitHub)</code></li> <li><a href="findings/discovery_report.md">discovery_report.md</a> — narrative writeup <code>(renders on GitHub)</code></li>
<li><a href="findings/ec2_code_discovery_report.md">ec2_code_discovery_report.md</a> — code recovery + reliability triage <code>(renders on GitHub)</code></li>
<li><code>findings/ec2_code_inspect.json</code> — SSM probe output, all 7 instances</li>
<li><code>findings/ec2_code_inspect_prod.json</code> — prod/stage probe snapshot</li>
<li><code>findings/org_assessment_report.json</code> — org / trust / delegated-admin raw data</li> <li><code>findings/org_assessment_report.json</code> — org / trust / delegated-admin raw data</li>
<li><code>findings/fast_discovery.json</code> — footprint, security, cost raw data</li> <li><code>findings/fast_discovery.json</code> — footprint, security, cost raw data</li>
<li><code>findings/member_lazka_547868853286.json</code> — member account raw data</li> <li><code>findings/member_lazka_547868853286.json</code> — member account raw data</li>
+159
View File
@@ -0,0 +1,159 @@
#!/usr/bin/env python3
"""
Scrivas — EC2 source-code discovery (stage 1: inventory)
========================================================
Read-only. Enumerates EC2 instances in active regions and collects the
signals that indicate where application source code lives:
- instance identity, state, type, AMI, launch time, tags
- IAM instance profile (what the box can reach)
- SSM managed status (can we run a read-only inspection on it?)
- EC2 user data (frequently contains the bootstrap/deploy script,
git remote URLs, artifact bucket names, image registries)
Context: the client does not hold the source code for their own platform;
it was built under contract by a third party. This inventories what is
running in the client's own account to locate their code.
Usage: python3 scripts/ec2_code_discovery.py [--profile PROFILE]
Output: findings/ec2_code_discovery.json
"""
import argparse
import base64
import json
import os
from datetime import datetime, date
import boto3
from botocore.exceptions import ClientError, BotoCoreError
DEFAULT_PROFILE = "dasnuve-scrivas-louis-impersonation"
REGIONS = ["us-east-2", "us-east-1"]
FINDINGS = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "findings")
def _default(o):
return o.isoformat() if isinstance(o, (datetime, date)) else str(o)
def safe(fn, *a, **k):
try:
return fn(*a, **k), None
except (ClientError, BotoCoreError) as e:
return None, str(e)
def tag_map(tags):
return {t["Key"]: t["Value"] for t in (tags or [])}
def user_data(ec2, iid):
resp, err = safe(ec2.describe_instance_attribute, InstanceId=iid, Attribute="userData")
if err:
return {"error": err}
raw = (resp.get("UserData") or {}).get("Value")
if not raw:
return None
try:
return {"text": base64.b64decode(raw).decode("utf-8", "replace")}
except Exception as e: # noqa: BLE001
return {"error": f"decode failed: {e}"}
def ssm_managed(session, region):
"""Instance IDs SSM can reach — these are inspectable without SSH keys."""
ssm = session.client("ssm", region_name=region)
out = {}
try:
for page in ssm.get_paginator("describe_instance_information").paginate():
for i in page.get("InstanceInformationList", []):
out[i.get("InstanceId")] = {
"ping_status": i.get("PingStatus"),
"platform": f'{i.get("PlatformName")} {i.get("PlatformVersion")}',
"agent": i.get("AgentVersion"),
"last_ping": i.get("LastPingDateTime"),
}
except (ClientError, BotoCoreError) as e:
return {"_error": str(e)}
return out
def scan_region(session, region):
ec2 = session.client("ec2", region_name=region)
managed = ssm_managed(session, region)
instances = []
pages, err = safe(lambda: list(ec2.get_paginator("describe_instances").paginate()))
if err:
return {"error": err}
for page in pages:
for res in page.get("Reservations", []):
for i in res.get("Instances", []):
iid = i["InstanceId"]
tags = tag_map(i.get("Tags"))
instances.append({
"instance_id": iid,
"name": tags.get("Name"),
"state": i["State"]["Name"],
"type": i.get("InstanceType"),
"image_id": i.get("ImageId"),
"launch_time": i.get("LaunchTime"),
"key_name": i.get("KeyName"),
"private_ip": i.get("PrivateIpAddress"),
"public_ip": i.get("PublicIpAddress"),
"iam_instance_profile": (i.get("IamInstanceProfile") or {}).get("Arn"),
"security_groups": [g["GroupId"] for g in i.get("SecurityGroups", [])],
"volumes": [
b["Ebs"]["VolumeId"]
for b in i.get("BlockDeviceMappings", []) if b.get("Ebs")
],
"tags": tags,
"ssm": managed.get(iid),
"user_data": user_data(ec2, iid),
})
return {
"region": region,
"ssm_managed_count": len([k for k in managed if not k.startswith("_")]),
"instance_count": len(instances),
"instances": instances,
}
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--profile", default=DEFAULT_PROFILE)
ap.add_argument("--regions", nargs="*", default=REGIONS)
args = ap.parse_args()
session = boto3.Session(profile_name=args.profile)
ident = session.client("sts").get_caller_identity()
report = {
"generated": datetime.now().astimezone().isoformat(),
"account": ident["Account"],
"principal": ident["Arn"],
"regions": [scan_region(session, r) for r in args.regions],
}
os.makedirs(FINDINGS, exist_ok=True)
path = os.path.join(FINDINGS, "ec2_code_discovery.json")
with open(path, "w") as fh:
json.dump(report, fh, indent=2, default=_default)
print(f"wrote {path}")
for r in report["regions"]:
if r.get("error"):
print(f'{r}')
continue
print(f'\n== {r["region"]}: {r["instance_count"]} instances, {r["ssm_managed_count"]} SSM-managed')
for i in r["instances"]:
ud = i["user_data"]
ud_flag = "userdata" if (ud and ud.get("text")) else "-"
ssm_flag = i["ssm"]["ping_status"] if i.get("ssm") else "-"
print(f' {i["instance_id"]:22} {i["state"]:10} {i["type"]:14} '
f'ssm={ssm_flag:8} {ud_flag:9} {i.get("name")}')
if __name__ == "__main__":
main()
+158
View File
@@ -0,0 +1,158 @@
#!/usr/bin/env python3
"""
Scrivas — EC2 code & reliability inspection (stage 2)
=====================================================
Runs a fixed, read-only command set on SSM-managed instances to locate the
deployed application code and collect reliability evidence.
Context: Scrivas does not hold the source for their own platform (built by a
third-party contractor) and is reporting production reliability issues. This
inspects the client's own instances, in the client's own account, to (a) find
where the code lives and (b) gather triage evidence.
SCOPE NOTE: ssm:SendCommand executes on the host. The command set below is
read-only by construction -- no writes, no restarts, no config changes, and
no dumping of file *contents* beyond manifests and VCS metadata. Review
PROBES before running. Requires explicit operator approval.
Usage:
python3 scripts/ec2_code_inspect.py --list
python3 scripts/ec2_code_inspect.py --instance i-073154fb4fa773bbd
python3 scripts/ec2_code_inspect.py --all
Output: findings/ec2_code_inspect.json
"""
import argparse
import json
import os
import time
from datetime import datetime, date
import boto3
from botocore.exceptions import ClientError, BotoCoreError
DEFAULT_PROFILE = "dasnuve-scrivas-louis-impersonation"
REGION = "us-east-2"
FINDINGS = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "findings")
# Read-only probes. Each is (label, shell). Keep every command non-mutating.
PROBES = [
("os_release", "cat /etc/os-release; uname -a"),
("uptime_load", "uptime; cat /proc/loadavg"),
("disk", "df -h; echo '--- inodes'; df -i"),
("memory", "free -h; echo '--- swap'; swapon --show"),
("code_dirs", "ls -la /opt /srv /var/www /home 2>/dev/null"),
("git_checkouts", "find / -maxdepth 6 -name .git -type d "
"-not -path '*/node_modules/*' 2>/dev/null | head -40"),
("git_remotes", "for g in $(find / -maxdepth 6 -name .git -type d "
"-not -path '*/node_modules/*' 2>/dev/null | head -20); do "
"r=$(dirname $g); echo \"== $r\"; "
"git -C $r remote -v 2>/dev/null; "
"git -C $r log -1 --format='%H %ad %an %s' 2>/dev/null; "
"git -C $r status -sb 2>/dev/null | head -5; done"),
("manifests", "find / -maxdepth 6 \\( -name package.json -o -name requirements.txt "
"-o -name pyproject.toml -o -name go.mod -o -name Dockerfile "
"-o -name docker-compose.y*ml \\) -not -path '*/node_modules/*' "
"2>/dev/null | head -40"),
("processes", "ps auxww --sort=-%mem | head -30"),
("listening", "ss -tulpnH 2>/dev/null | head -40"),
("systemd_units", "systemctl list-units --type=service --state=running --no-pager --no-legend | head -40"),
("systemd_failed", "systemctl list-units --state=failed --no-pager --no-legend"),
("docker", "docker ps -a --format '{{.Names}}\t{{.Image}}\t{{.Status}}' 2>/dev/null | head -30"),
("docker_images", "docker images --format '{{.Repository}}:{{.Tag}}\t{{.CreatedAt}}' 2>/dev/null | head -20"),
("oom_kills", "sudo dmesg -T 2>/dev/null | grep -iE 'oom|killed process' | tail -20"),
("svc_restarts", "sudo journalctl --since '7 days ago' --no-pager 2>/dev/null "
"| grep -iE 'segfault|out of memory|failed with result|start-limit' | tail -40"),
("reboots", "last -x reboot 2>/dev/null | head -10"),
("cron", "ls -la /etc/cron.d 2>/dev/null; crontab -l 2>/dev/null"),
]
def _default(o):
return o.isoformat() if isinstance(o, (datetime, date)) else str(o)
def managed(session):
ssm = session.client("ssm", region_name=REGION)
out = []
for page in ssm.get_paginator("describe_instance_information").paginate():
out += [i for i in page.get("InstanceInformationList", [])
if i.get("PingStatus") == "Online"]
return out
def run_probe(ssm, iid, label, shell, timeout=120):
try:
cmd = ssm.send_command(
InstanceIds=[iid],
DocumentName="AWS-RunShellScript",
Comment=f"dasnuve-discovery:{label}"[:100],
Parameters={"commands": [shell], "executionTimeout": [str(timeout)]},
)["Command"]["CommandId"]
except (ClientError, BotoCoreError) as e:
return {"error": str(e)}
for _ in range(int(timeout / 2)):
time.sleep(2)
try:
r = ssm.get_command_invocation(CommandId=cmd, InstanceId=iid)
except ClientError as e:
if "InvocationDoesNotExist" in str(e):
continue
return {"error": str(e)}
if r["Status"] in ("Pending", "InProgress", "Delayed"):
continue
return {
"status": r["Status"],
"stdout": r.get("StandardOutputContent", "").rstrip(),
"stderr": r.get("StandardErrorContent", "").rstrip(),
}
return {"error": "timed out waiting for invocation"}
def inspect(session, iid):
ssm = session.client("ssm", region_name=REGION)
print(f"\n=== {iid}")
res = {}
for label, shell in PROBES:
print(f" .. {label}", flush=True)
res[label] = run_probe(ssm, iid, label, shell)
return res
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--profile", default=DEFAULT_PROFILE)
ap.add_argument("--instance", action="append", dest="instances")
ap.add_argument("--all", action="store_true")
ap.add_argument("--list", action="store_true")
args = ap.parse_args()
session = boto3.Session(profile_name=args.profile)
online = managed(session)
if args.list:
for i in online:
print(f'{i["InstanceId"]:22} {i["PingStatus"]:8} '
f'{i.get("PlatformName")} {i.get("PlatformVersion")}')
return
targets = args.instances or ([i["InstanceId"] for i in online] if args.all else [])
if not targets:
ap.error("pass --instance ID (repeatable), --all, or --list")
report = {
"generated": datetime.now().astimezone().isoformat(),
"region": REGION,
"probes": [p[0] for p in PROBES],
"results": {iid: inspect(session, iid) for iid in targets},
}
os.makedirs(FINDINGS, exist_ok=True)
path = os.path.join(FINDINGS, "ec2_code_inspect.json")
with open(path, "w") as fh:
json.dump(report, fh, indent=2, default=_default)
print(f"\nwrote {path}")
if __name__ == "__main__":
main()