# Connecting MySQL Workbench to the B2G UAT database

How to reach the UAT RDS instance from a Windows workstation, using an SSM port-forwarding tunnel
through the bastion. No SSH key, no VPN, and no security-group change.

Every command and value below was executed and verified on 2026-08-02 against account
`022067219328` in `ap-south-1`, unless a line explicitly says otherwise. The
[Verification record](#appendix-b--verification-record) at the end lists exactly what was proved and
what was not.

---

## 1. The target

| Property | Value |
|---|---|
| DB instance | `uat-rds-db` |
| Endpoint | `uat-rds-db.c5myq6iqolml.ap-south-1.rds.amazonaws.com` |
| Port | `3306` |
| Engine | MySQL `8.4.9` |
| Class / AZ | `db.t4g.medium`, `ap-south-1a` |
| Publicly accessible | **`false`** |
| VPC security group | `sg-0d31a06531cad03bb` |
| Region | `ap-south-1` |

`PubliclyAccessible = false` is the whole reason this document exists. The endpoint resolves only
inside VPC `vpc-0ba5292c6e629d49b`; there is no route to it from your desk. Everything below is about
borrowing the bastion's position inside that VPC.

### Why the tunnel goes through the bastion

The RDS security group `sg-0d31a06531cad03bb` allows exactly one inbound rule on TCP 3306:

| Source | Meaning |
|---|---|
| `sg-0100d3a20fb80baef` | the bastion's own SG — **this is the path we use** |
| `sg-0148e52978f27d5a6` | B2G Fargate tasks |
| `223.181.117.177/32` | a fixed office IP; inert, since the instance is not public |

The bastion `i-04bed8d526c55e47d` (Ubuntu 24.04, private IP `10.0.1.128`, instance profile `SSM`) sits
in that group, is `running`, and reports SSM `PingStatus: Online` with agent `3.3.4793.0`.

### Why not an SSH tunnel

The bastion's SG `sg-0100d3a20fb80baef` allows port 22 from `223.181.117.177/32` only. A check of this
workstation's public IP returned **`103.16.202.164`**, which is not that address, so an SSH tunnel is
refused at the network layer before authentication is even attempted.

SSM port forwarding needs **no inbound rule at all** — the SSM agent on the bastion opens an
*outbound* connection to the SSM service and the session is carried back down it. That is why this
method works from any network, including hotel Wi-Fi and mobile tethering, and why it keeps working
if the office IP changes.

---

## 2. Prerequisites

### 2.1 AWS CLI credentials

You need an identity that can call `ssm:StartSession` on the bastion and
`secretsmanager:GetSecretValue` on `b2g/uat/db-app`. Confirm who you are:

```powershell
aws sts get-caller-identity --region ap-south-1
```

### 2.2 Session Manager plugin

The AWS CLI cannot port-forward on its own; it shells out to a separate binary. Install it with the
official Amazon installer (verified reachable, HTTP 200):

```powershell
$url = "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/windows/SessionManagerPluginSetup.exe"
Invoke-WebRequest -Uri $url -OutFile "$env:TEMP\SessionManagerPluginSetup.exe"
Start-Process -FilePath "$env:TEMP\SessionManagerPluginSetup.exe" -Wait
```

The installer places the binary at
`C:\Program Files\Amazon\SessionManagerPlugin\bin\session-manager-plugin.exe` and adds that directory
to the system `PATH`.

**Close and reopen your terminal after installing** — a running shell keeps the `PATH` it started
with, which is the most common reason a fresh install still reports "plugin not found".

Verify:

```powershell
session-manager-plugin --version
```

Any `1.2.x` build works. The tested build was `1.2.835.0`.

> Note on the install path: the plugin directory is added to the **system** `PATH`, not the user
> `PATH`. If your organisation blocks writes to `C:\Program Files`, the installer will fail silently
> in places; check `session-manager-plugin --version` rather than assuming success.

### 2.3 The region gotcha

**This workstation's AWS CLI has no default region configured.** Verified: running an SSM command
without a region fails with

```
You must specify a region. You can also configure your region by running "aws configure".
```

So every command must carry `--region ap-south-1`, or you set it once per shell:

```powershell
$env:AWS_REGION = "ap-south-1"
$env:AWS_DEFAULT_REGION = "ap-south-1"
```

Both variables are worth setting: different AWS SDK components read different ones. To fix it
permanently instead, run `aws configure set region ap-south-1`.

### 2.4 MySQL Workbench

Install MySQL Workbench 8.0 or later. **A MariaDB client will not work** — see
[section 6](#6-troubleshooting), "Access denied / auth plugin".

---

## 3. Open the tunnel

Run this in its own PowerShell window and **leave it open** — the tunnel lives only as long as the
command runs.

```powershell
aws ssm start-session `
  --region ap-south-1 `
  --target i-04bed8d526c55e47d `
  --document-name AWS-StartPortForwardingSessionToRemoteHost `
  --parameters '{\"host\":[\"uat-rds-db.c5myq6iqolml.ap-south-1.rds.amazonaws.com\"],\"portNumber\":[\"3306\"],\"localPortNumber\":[\"3307\"]}'
```

Expected output:

```
Starting session with SessionId: <you>-0123456789abcdef
Port 3307 opened for sessionId <you>-0123456789abcdef.
Waiting for connections...
```

`Waiting for connections...` means it is ready. Local port `3307` is now wired to
`uat-rds-db...:3306` via the bastion.

> **Quoting warning.** The `--parameters` value is JSON, and PowerShell mangles inline JSON quoting.
> The backslash-escaped inner quotes above are required in PowerShell. In **Git Bash** use plain
> single quotes instead, and also set `MSYS_NO_PATHCONV=1` so MSYS does not rewrite the JSON as a
> path:
>
> ```bash
> export MSYS_NO_PATHCONV=1
> aws ssm start-session --region ap-south-1 --target i-04bed8d526c55e47d \
>   --document-name AWS-StartPortForwardingSessionToRemoteHost \
>   --parameters '{"host":["uat-rds-db.c5myq6iqolml.ap-south-1.rds.amazonaws.com"],"portNumber":["3306"],"localPortNumber":["3307"]}'
> ```
>
> If quoting keeps fighting you, put the JSON in a file and pass
> `--parameters file://params.json` — but see the BOM warning in [section 6](#6-troubleshooting).

**To close the tunnel:** press `Ctrl+C` in that window. This ends the session cleanly on the AWS side
too. If you kill the process instead (`Stop-Process`), the local port closes but AWS still lists the
session as `Active` until it idle-times-out; clean it up with:

```powershell
aws ssm describe-sessions --state Active --region ap-south-1
aws ssm terminate-session --session-id <id> --region ap-south-1
```

---

## 4. Get the credentials

Two secrets exist. **Use `b2g/uat/db-app` for Workbench.**

| Secret | User | Use for |
|---|---|---|
| `b2g/uat/db-app` | `b2gapp` | normal work — read/write on all seven schemas |
| `b2g/uat/rds-master` | `admin` | DDL, migrations, user management only |

Retrieve the application credentials:

```powershell
aws secretsmanager get-secret-value `
  --region ap-south-1 `
  --secret-id b2g/uat/db-app `
  --query SecretString --output text
```

That returns a JSON document with the keys `username`, `password`, `host`, `port`, `engine` and
`dbInstanceIdentifier`. The username is `b2gapp`. To print just the password to the clipboard without
it landing in your scroll-back:

```powershell
$s = aws secretsmanager get-secret-value --region ap-south-1 --secret-id b2g/uat/db-app --query SecretString --output text | ConvertFrom-Json
$s.password | Set-Clipboard
```

> Passwords are deliberately not reproduced in this document. Always read them from Secrets Manager
> at the moment you need them, and never paste one into a ticket, commit, or chat message.

The effective grants on `b2gapp` were confirmed with `SHOW GRANTS`: `SELECT, INSERT, UPDATE, DELETE,
CREATE TEMPORARY TABLES, EXECUTE, SHOW VIEW` on each of the seven schemas, plus `USAGE` on `*.*`. It
has **no DDL rights** — no `CREATE`, `ALTER`, or `DROP`. Schema changes need the master secret.

---

## 5. Configure MySQL Workbench

In Workbench: **Database -> Manage Connections -> New**.

| Field | Value |
|---|---|
| Connection Name | `B2G UAT (SSM tunnel)` |
| **Connection Method** | **Standard (TCP/IP)** |
| Hostname | `127.0.0.1` |
| Port | **`3307`** |
| Username | `b2gapp` |
| Password | *Store in Vault…* — paste from Secrets Manager |
| Default Schema | leave blank |

Click **Test Connection**. With the tunnel window open this succeeds.

### Why *Standard (TCP/IP)* and not *Standard TCP/IP over SSH*

The SSH option tells Workbench to build its own tunnel: it would open an SSH connection to a bastion
and forward the port itself. That is the wrong tool here for two independent reasons:

1. **The tunnel already exists.** `aws ssm start-session` has already put a listener on
   `127.0.0.1:3307`. Asking Workbench to build a second tunnel on top would be redundant.
2. **SSH cannot work from this workstation anyway.** Port 22 on the bastion is restricted to
   `223.181.117.177/32`, and this workstation is `103.16.202.164`. Workbench's SSH connection would
   time out. There is also no SSH key distributed for this bastion — SSM is the access path by design.

So from Workbench's point of view the database is simply a MySQL server running on localhost. It does
not know or care that a tunnel is involved. **Standard (TCP/IP)** is exactly right.

### Why port 3307 and not 3306

`3306` is the port on the *remote* RDS instance — the far end of the tunnel. `3307` is the *local*
port on your machine, set by `localPortNumber` in the tunnel command. Workbench connects to the local
end, so it must use `3307`.

The local port is deliberately not `3306` because a local MySQL or MariaDB server (XAMPP, for
instance, which is installed on this workstation) usually already occupies `3306`. Using `3307` avoids
the clash and keeps it obvious whether you are looking at local data or UAT data. If you change
`localPortNumber`, change the Workbench port to match.

### A useful sanity check

Once connected, run:

```sql
SELECT VERSION(), CURRENT_USER(), @@hostname;
```

Verified output through the tunnel:

```
8.4.9    b2gapp@%    ip-172-30-2-44
```

`@@hostname` being an RDS-internal name is proof you are on the real instance and not a local server.
Note also that the server sees your connection as originating from `10.0.1.128` — the bastion's
private IP — which confirms the traffic genuinely traverses the bastion.

---

## 6. Troubleshooting

Error texts below marked *(verified)* were reproduced on this workstation and are quoted exactly.

### "SessionManagerPlugin is not found" *(verified)*

```
SessionManagerPlugin is not found. Please refer to SessionManager Documentation here:
http://docs.aws.amazon.com/console/systems-manager/session-manager-plugin-not-found
```

The CLI authenticated fine and started a session; it just cannot launch the helper binary.

- Reopen your terminal — a shell started before the install still has the old `PATH`.
- Check it resolves: `Get-Command session-manager-plugin`.
- If it is installed somewhere non-standard, prepend that directory for the session:
  `$env:PATH = "C:\Program Files\Amazon\SessionManagerPlugin\bin;$env:PATH"`.
- Note this failure still consumes a session server-side. Clear stragglers with
  `aws ssm describe-sessions --state Active --region ap-south-1`.

### "You must specify a region" *(verified)*

```
You must specify a region. You can also configure your region by running "aws configure".
```

The CLI here has no default region. Add `--region ap-south-1`, or set `$env:AWS_REGION` and
`$env:AWS_DEFAULT_REGION`, or run `aws configure set region ap-south-1`.

Watch for this appearing halfway through a script — a shell variable set in one PowerShell window does
not carry into another.

### `TargetNotConnected`

```
An error occurred (TargetNotConnected) when calling the StartSession operation:
<instance-id> is not connected.
```

AWS accepted your credentials but the SSM agent on the bastion is not currently reachable. Check:

```powershell
aws ssm describe-instance-information `
  --filters "Key=InstanceIds,Values=i-04bed8d526c55e47d" `
  --region ap-south-1
```

A healthy result shows `"PingStatus": "Online"` and a recent `LastPingDateTime`. If the list comes back
empty or `ConnectionLost`, the instance is stopped, the agent is down, or its IAM instance profile
(currently `SSM`) has been detached. Also confirm you typed the right instance ID — a typo produces
the same error.

### Port already in use

```
Port 3307 is already in use. Please specify a different port.
```

Something already holds `3307` — very often a tunnel you forgot to close. Find it:

```powershell
Get-NetTCPConnection -LocalPort 3307 -State Listen | Select-Object OwningProcess
Get-Process -Id <pid>
```

Close the old tunnel window, or start the new one on a different `localPortNumber` (`3308`, …) and
update the Workbench port to match.

### Access denied / auth plugin

`ERROR 1045 (28000): Access denied for user 'b2gapp'@'...'` means the tunnel is working — you reached
the database and it rejected the credentials. Re-fetch the password from Secrets Manager; do not retype
it by hand. If Workbench has a stale password cached, clear it under
**Edit -> Preferences -> MySQL -> "Clear Stored Passwords"** (or re-enter it in the connection's
password vault).

A different and more confusing failure *(verified)*:

```
ERROR 1045 (28000): Plugin caching_sha2_password could not be loaded:
The specified module could not be found. Library path is 'caching_sha2_password.dll'
```

This is **not** a wrong password. It is a MariaDB client trying to talk to MySQL 8.4. The server's
`authentication_policy` is `*:caching_sha2_password`, and MariaDB clients do not ship that plugin. The
XAMPP client on this workstation (`D:\xampp82\mysql\bin\mysql.exe`, MariaDB 10.4.28) fails this way
every time.

Use a genuine MySQL 8.x client. One ships with Workbench at
`C:\Program Files\MySQL\MySQL Workbench 8.0 CE\mysql.exe`. **Make sure that directory precedes
`D:\xampp82\mysql\bin` on your `PATH`**, or typing `mysql` will silently pick the MariaDB one.

### PowerShell `Set-Content -Encoding utf8` writes a BOM

Relevant if you script any of this and write JSON to a file — for example a `--parameters file://…`
payload or an IAM policy document.

**Verified on this workstation** (Windows PowerShell `5.1.26100.8875`): `Set-Content -Encoding utf8`
produces a file beginning with the bytes `EF BB BF`, the UTF-8 byte-order mark. The AWS CLI's JSON
parser does not skip it and fails with a parse error that points at character 0 and looks like invalid
JSON for no visible reason — the file opens fine in any editor.

Workarounds:

```powershell
# .NET, no BOM
[System.IO.File]::WriteAllText("params.json", $json, (New-Object System.Text.UTF8Encoding($false)))

# or ASCII, fine for plain-ASCII JSON
Set-Content -Path params.json -Value $json -Encoding ascii
```

PowerShell 7+ defaults to BOM-less UTF-8 and does not have this problem; `-Encoding utf8NoBOM` is
available there. Windows PowerShell 5.1 — the version installed here — does not support that value.

To check a suspect file:

```powershell
Format-Hex params.json | Select-Object -First 1
```

### Tunnel opens, then the connection hangs

If `Waiting for connections...` appears but Workbench times out, the local end is fine and the problem
is bastion-to-RDS. Confirm the RDS security group still admits the bastion's group on 3306:

```powershell
aws ec2 describe-security-groups --group-ids sg-0d31a06531cad03bb `
  --query 'SecurityGroups[0].IpPermissions' --region ap-south-1
```

You are looking for `sg-0100d3a20fb80baef` under `UserIdGroupPairs` for port 3306.

---

## 7. The seven schemas

All seven live on the single `uat-rds-db` instance. Table counts below were read from
`information_schema.TABLES` (`TABLE_TYPE='BASE TABLE'`) through the tunnel and match the deployment
runbook exactly. There are no views in any schema.

| Schema | Tables | Used by | Config source |
|---|---|---|---|
| `bgi_b2g_master_dev` | 73 | `b2g_micro` | `b2g_micro/config/db-local.php` |
| `bgi_b2g_reg_dev` | 70 | `b2g_usermgmt`, `b2g_profilemgmt`, `b2g_confmgmt`, `b2g_mail`, `b2g_filemst` | `db-local.php` in each; `b2g_filemst/backend/json/DB.json` |
| `bgi_b2g_gmarket_dev` | 97 | `b2g_gmarketapi` | `b2g_gmarketapi/config/db-local.php` |
| `bgi_b2g_digitall_dev` | 19 | `b2g_digitall` | `b2g_digitall/config/db-local.php` |
| `bgi_b2g_cengex_dev` | 17 | `b2g_cengex` | `b2g_cengex/config/db-local.php` |
| `bgi_jsrsv3_audit` | **0** | `b2g_filemst` audit trail (`dbAudit` component) | `b2g_filemst/backend/json/DBaudit.json` |
| `estore` | **0** | `b2g_filemst` `estore` module (`dbestore` component) | `b2g_filemst/common/config/base.php` |

Reproduce the counts yourself:

```sql
SELECT TABLE_SCHEMA, COUNT(*) AS tables_ct
FROM information_schema.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
  AND TABLE_SCHEMA NOT IN ('mysql','information_schema','performance_schema','sys')
GROUP BY TABLE_SCHEMA ORDER BY TABLE_SCHEMA;
```

Empty schemas do not appear in that result, which is expected — they contain no tables to count.
`SHOW DATABASES` does list all seven.

> **Read `db-local.php`, not `db-dev.php`.** In the AWS deployment every service resolves its
> environment to `local`, so `db-local.php` is the file that decides which schema a service actually
> uses. The `db-dev.php` files still carry the old on-premise DSNs
> (`192.168.1.200:3307`) and several of them name a *different* schema — `b2g_gmarketapi/config/db-dev.php`
> points at `bgi_b2g_master_dev`, and `b2g_confmgmt/config/db-dev.php` points at the non-existent
> `bgi_b2g_reg_uat`. Those files are misleading; the mapping in the table above comes from
> `db-local.php` and is the one in force.

### Why `bgi_jsrsv3_audit` and `estore` are empty

**This is intentional, not a failed import.** Both schemas were created empty so that `b2g_filemst`
can resolve its `dbAudit` and `dbestore` connection components at boot; without them the service
fails to start.

They are empty because **no dump for them exists in the S3 backup.** Verified by listing
`s3://amzn-s3-b2g-demo/db-backup/`, which contains exactly five files:

```
bgi_b2g_cengex_dev.sql     142.4 KiB
bgi_b2g_digitall_dev.sql    71.7 MiB
bgi_b2g_gmarket_dev.sql    829.2 KiB
bgi_b2g_master_dev.sql      42.1 MiB
bgi_b2g_reg_dev.sql         22.2 MiB
```

There is no `bgi_jsrsv3_audit.sql` and no `estore.sql`. Consequently the filemst audit trail is inert
in UAT and any `estore` module feature will fail on a missing table. Do not raise these as data-loss
bugs; if the data is needed, a fresh dump has to be taken from the source system.

---

## Appendix A — OPTIONAL read-only account for analysts

> **STATUS: NOT APPLIED.** This account does not exist on `uat-rds-db`. The SQL below is a proposal
> for a DBA to review and run deliberately. Nothing in this section has been executed, and the
> statements are therefore **unverified**.

`b2gapp` has write access to every schema, so it is the wrong credential to hand to someone who only
needs to read. To create a genuinely read-only account, an admin would connect with the
**`b2g/uat/rds-master`** secret (user `admin`) — `b2gapp` cannot do this, as it holds no DDL or
user-management rights.

```sql
-- Choose a strong password and store it in Secrets Manager (e.g. b2g/uat/db-readonly)
-- BEFORE running this. Do not inline a password into a script that gets committed.
CREATE USER 'b2gread'@'%' IDENTIFIED BY '<generated-strong-password>';

GRANT SELECT, SHOW VIEW ON `bgi_b2g_master_dev`.*   TO 'b2gread'@'%';
GRANT SELECT, SHOW VIEW ON `bgi_b2g_reg_dev`.*      TO 'b2gread'@'%';
GRANT SELECT, SHOW VIEW ON `bgi_b2g_gmarket_dev`.*  TO 'b2gread'@'%';
GRANT SELECT, SHOW VIEW ON `bgi_b2g_digitall_dev`.* TO 'b2gread'@'%';
GRANT SELECT, SHOW VIEW ON `bgi_b2g_cengex_dev`.*   TO 'b2gread'@'%';
GRANT SELECT, SHOW VIEW ON `bgi_jsrsv3_audit`.*     TO 'b2gread'@'%';
GRANT SELECT, SHOW VIEW ON `estore`.*               TO 'b2gread'@'%';

FLUSH PRIVILEGES;

-- Confirm the result
SHOW GRANTS FOR 'b2gread'@'%';
```

Points for the reviewer:

- `SELECT` plus `SHOW VIEW` is the read-only pair. `SHOW VIEW` lets Workbench render view definitions
  in the schema tree; without it views appear broken.
- No `EXECUTE`. Stored procedures in `bgi_b2g_reg_dev` can write, so granting `EXECUTE` would quietly
  defeat the read-only intent. Add it only for specific procedures if a real need appears.
- No `CREATE TEMPORARY TABLES`. Add it only if analysts hit a genuine need for temp tables in complex
  queries; it is a write privilege, though a contained one.
- `'%'` as host matches `b2gapp`'s existing definition and is required, since connections arrive from
  the bastion's private IP rather than a fixed address. Consider `'10.0.%'` to narrow it to the VPC.
- Consider `ALTER USER 'b2gread'@'%' WITH MAX_USER_CONNECTIONS 5;` so an analyst's runaway query
  cannot exhaust the connection pool on a `db.t4g.medium`.
- Analysts use the identical tunnel and Workbench setup above; only the username and password change.

---

## Appendix B — Verification record

Performed 2026-08-02 against account `022067219328`, region `ap-south-1`, as
`arn:aws:iam::022067219328:user/Balaji`.

### Proved

- **RDS facts.** `describe-db-instances` returned endpoint
  `uat-rds-db.c5myq6iqolml.ap-south-1.rds.amazonaws.com`, port `3306`, engine `mysql` `8.4.9`, status
  `available`, `PubliclyAccessible: false`, SG `sg-0d31a06531cad03bb`.
- **Bastion.** `i-04bed8d526c55e47d` is `running`, SSM `PingStatus: Online`, agent `3.3.4793.0`,
  Ubuntu 24.04, private IP `10.0.1.128`, instance profile `SSM`, SG `sg-0100d3a20fb80baef`.
- **SG chain.** RDS SG admits the bastion SG on TCP 3306.
- **SSH is unusable from here.** Bastion SG permits port 22 only from `223.181.117.177/32`; this
  workstation's public IP is `103.16.202.164`.
- **The tunnel works end to end.** Started
  `AWS-StartPortForwardingSessionToRemoteHost` forwarding `127.0.0.1:3307` to the RDS endpoint:3306.
  The port reached `LISTENING` within 1 second.
- **A real MySQL session ran over it.** Using the `b2gapp` credentials from `b2g/uat/db-app`,
  `SELECT VERSION(), CURRENT_USER(), @@hostname` returned `8.4.9`, `b2gapp@%`, `ip-172-30-2-44`. The
  session negotiated TLS (`Ssl_cipher = TLS_AES_256_GCM_SHA384`); `require_secure_transport` is `OFF`,
  so TLS is available but not enforced.
- **Traffic really transits the bastion.** A permissions error surfaced the server's view of the
  client as `'b2gapp'@'10.0.1.128'` — the bastion's private IP.
- **All seven schemas and their table counts**, read from `information_schema` over the tunnel:
  73 / 70 / 97 / 19 / 17 / 0 / 0, matching the runbook exactly.
- **`b2gapp` grants**, via `SHOW GRANTS FOR CURRENT_USER()` — read/write, no DDL, on all seven schemas.
- **No dumps exist** for `bgi_jsrsv3_audit` or `estore`; `s3://amzn-s3-b2g-demo/db-backup/` holds five
  `.sql` files only.
- **Error strings** for "plugin not found" and "You must specify a region" were reproduced verbatim.
- **The BOM behaviour** of `Set-Content -Encoding utf8` on PowerShell `5.1.26100.8875` — first three
  bytes `EF BB BF`.
- **The plugin installer URL** returns HTTP 200.
- **Teardown.** The tunnel process was killed, port 3307 confirmed closed, and the SSM session
  terminated; `describe-sessions --state Active` returned empty.

### Not proved

- **MySQL Workbench's own GUI connection was not exercised.** The database connection was proved with
  the command-line client `mysql.exe` shipped by Workbench 8.0.28, over the same tunnel and with the
  same host/port/user. The GUI uses the same client library, so the settings in section 5 are expected
  to work, but nobody clicked "Test Connection".
- **`TargetNotConnected` and "port already in use" error texts are reconstructed, not reproduced.**
  Triggering them would have meant disrupting the bastion or occupying a port. Treat those two quoted
  strings as indicative wording rather than verbatim.
- **The Session Manager plugin installer was not run** on this workstation. Only the download URL was
  checked. The tunnel test used a plugin binary (`1.2.835.0`) already present in a temporary directory,
  so the documented install path
  `C:\Program Files\Amazon\SessionManagerPlugin\bin\session-manager-plugin.exe` and the claim that the
  installer edits `PATH` come from Amazon's documented behaviour, not from local observation.
- **Appendix A was not executed.** No `b2gread` user exists.
- **The `b2g/uat/rds-master` secret was not opened.** Its existence and name were confirmed via
  `list-secrets`; the `admin` username is quoted from the deployment runbook, not read from the secret.
- **Microservice-to-schema mapping is from source configuration, not runtime.** It was derived by
  reading each service's `db-local.php` (plus filemst's JSON and `base.php`) and cross-checking against
  the deployment runbook, which agrees. No running task's environment was inspected.
