skills/infrastructure/aws/investigation-toolkit/skills/aws-console-navigator/SKILL.md
Navigate the AWS Console via browser or Playwright MCP — SSO authentication, account selection, region switching, CloudWatch Logs Insights, alarms, metrics. Covers iframe DOM patterns for screenshot capture: scroll, row click, element interaction inside the microConsole iframe. Keywords: Playwright SSO iframe CloudWatch browser-automation screenshot microConsole logs-table__wrapper page.mouse.click frame.evaluate IAM-Identity-Center region cookie-banner sidebar-collapse locator-timeout.
npx skillsauth add pantheon-org/tekhne aws-console-navigatorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The CloudWatch console is a micro-frontend SPA embedded inside an iframe
(iframe[name="microConsole-Logs"]). This has three non-obvious consequences:
window.document is the outer shell, not CloudWatch. All DOM queries must target
the iframe's contentDocument. In Playwright, use page.frame({ name: 'microConsole-Logs' }).
locator.click() on iframe elements times out. Playwright's locator API hits a 5 s
timeout when clicking elements inside cross-origin iframes. Use page.mouse.click(x, y)
with coordinates calculated from the iframe bounding box + element's getBoundingClientRect.
The results table is its own scroll container. window.scrollBy() scrolls the outer
shell. The CloudWatch results table lives in DIV.logs-table__wrapper. Scroll it directly:
frame.evaluate(() => document.querySelector('.logs-table__wrapper').scrollTop = N).
locator.click() works normally thereaws-cloudwatch-url-builder insteadDirect URL: See aws-cloudwatch-url-builder for the encoded URL template.
Direct URL:
https://{region}.console.aws.amazon.com/cloudwatch/home?region={region}#alarmsV2:alarm/{alarm_name}
For full SSO auth steps and region codes, see references/console-reference.md.
Full Playwright code snippets are in references/playwright-patterns.md.
Get the frame reference first — optionally cache it for reuse across multiple operations:
const frame = page.frame({ name: 'microConsole-Logs' });
await page.waitForSelector('iframe[name="microConsole-Logs"]', { timeout: 15000 });
Scroll the results table (use frame.evaluate, not window.scrollBy):
await frame.evaluate(() => {
document.querySelector('.logs-table__wrapper').scrollTop = 600;
});
Expand a log row using page-level coordinates (consider pre-calculating for multiple rows):
const iframeBox = await page.locator('iframe[name="microConsole-Logs"]').boundingBox();
const rowBox = await frame.locator('tr.logs-table__row').first().boundingBox();
await page.mouse.click(iframeBox.x + rowBox.x + 20, iframeBox.y + rowBox.y + rowBox.height / 2);
Each entry shows the BAD practice and the GOOD replacement.
❌ NEVER use locator.click() directly on CloudWatch iframe elements
WHY: Playwright's locator.click() uses accessibility tree traversal and times out after 5 s
when targeting elements inside a cross-origin or sandboxed iframe.
✅ BAD: await frame.locator('tr').first().click() → GOOD: calculate page-level coordinates
from iframeBox + rowBox, then call page.mouse.click(absoluteX, absoluteY).
❌ NEVER use window.scrollBy() or window.scrollTo() inside the CloudWatch iframe
WHY: window in the iframe context scrolls MAIN.logs__main__visual-refresh (the outer
page-level scroller), not the results table. The results table is in a separate overflow
container (DIV.logs-table__wrapper) and will not move.
✅ Use: frame.evaluate(() => document.querySelector('.logs-table__wrapper').scrollTop = N)
❌ NEVER query window.document from page.evaluate() to interact with CloudWatch content
WHY: page.evaluate() runs in the outer shell document. CloudWatch content is inside the iframe.
document.querySelector('.logs-table__wrapper') returns null from page.evaluate().
✅ Use frame.evaluate() where frame = page.frame({ name: 'microConsole-Logs' }).
❌ NEVER assume AWS/Lambda Errors = 0 means no alarm triggered
WHY: The native AWS/Lambda Errors metric counts invocation-level failures (exit code ≠ 0).
An alarm driven by a Logs metric filter fires even when the invocation exits cleanly, as
long as ERROR-level log lines were emitted.
✅ Always screenshot the alarm detail page, not the raw AWS/Lambda Errors metric graph.
tools
A skill that produces warnings but no errors.
testing
A well-formed example skill for testing the validator.
development
A skill with code blocks and imperative instructions for testing content and contamination analysis.
tools