v1.3.36.1 -- Capture automation: auth state + dimensions + banner fixes¶
A bugfix on top of v1.3.36 closing three regressions discovered in the operator's first capture session against prod.
argosVersion and frontend/package.json deliberately stay at 1.3.35.4 (tooling-only release; no panel binary change). scripts/capture/package.json bumps 1.3.36.0 → 1.3.36.1.
Bugs fixed¶
BUG 1 — auth state did not persist between Playwright tests¶
Symptom: tests #3+ (post-login captures) silently rendered the /login redirect instead of the authenticated panel content. They reported PASS but the PNGs were the wrong surface.
Root cause: v1.3.36's capture.spec.js had an empty test.beforeAll with a comment claiming the browser context is reused automatically. Default Playwright behaviour: each test() gets a fresh BrowserContext from the per-test page fixture, with no shared cookies. Test #2 (auth: log in for remaining captures) DID log in successfully, but the session cookie was scoped to test #2's context and discarded when the test ended. Tests #3+ got fresh contexts → no session → page.goto('/') redirected to /login.
Fix: canonical Playwright storageState pattern. Two new pieces:
scripts/capture/auth.setup.js(new): a separate "setup" Playwright project. Logs in vialib/auth.jsand persists cookies viacontext.storageState({ path: AUTH_STATE }).scripts/capture/playwright.config.jsdeclares two projects:setup(runsauth.setup.js) andcaptures(runscapture.spec.js, depends onsetup, readsuse.storageState = AUTH_STATE). Playwright loads the state into every test's context automatically.
The login.png capture is wrapped in test.describe('login (anon)') with test.use({ storageState: { cookies: [], origins: [] } }) so the /login page renders un-authenticated for that single capture.
run.sh and run-demo.sh gain a consolidated trap on EXIT INT TERM that deletes ${AUTH_STATE} so the operator's session cookie doesn't persist on disk past the run.
BUG 2 — banner output had un-expanded shell command-substitution¶
Symptom: end-of-run banner printed:
— the literal string, not the count.
Root cause: test.afterAll in capture.spec.js used a JS template literal:
JS template literals expand ${SKIP_LIST_PATH} (JS interpolation) but NOT $(...) (bash command substitution). The literal text reached stdout.
Fix: replace the bash command-sub with fs.readFileSync + JS line counting. The new code:
const skippedCount = fs.readFileSync(SKIP_LIST_PATH, 'utf8')
.split('\n')
.filter((line) => line.trim().length > 0)
.length;
console.log(`skipped=${skippedCount}`);
BUG 3 — viewport too short for scrollable surfaces¶
Symptom: surfaces with long content (Hosts list, Banned IPs, Activity audit log, Scenarios, Notification deliveries, Backups) were clipped at the 1440×900 viewport bottom. Most of the data wasn't in the screenshot.
Root cause: playwright.config.js set viewport to 1440×900 (matched the docs portal width but not deep enough for vertical lists), and shotFull() used fullPage: false which only captures the viewport.
Fix: two parts:
- Viewport bumped to
1440×1080so above-fold cards (dashboard, settings) have more room before scroll. - New
shotFullScroll(page, name)helper: samepage.screenshot()but withfullPage: truefor full scrollable content. The 15 long-list surfaces use it; the 21 above-fold / modal / card-shaped surfaces continue to useshotFull()(viewport-only):
| shotFullScroll (15) | shotFull (21) |
|---|---|
| hosts-list-auth-column | login |
| hosts-detect-badge | dashboard-overview |
| security-banned | dashboard-security |
| security-whitelist | host-form |
| security-activity | host-form-dns-provider-dropdown |
| security-scenarios | host-form-true-detect |
| security-overview | target-group-form |
| threats-decisions | target-group-first-target |
| notifications-deliveries | target-group-two-targets |
| logs-browser | appsec-status |
| backups-list | drift-indicators |
| settings-panel | selfblock-banner |
| appsec-metrics | |
| backup-settings | |
| geoip-status | |
| sso-allowlist | |
| totp-setup | |
| settings-dns-providers | |
| country-bans-progress |
Smoke updates¶
scripts/smoke/capture-automation.sh gains three new phases (6, 7, 8) on top of the existing 5:
6. storageState wiring:
- auth.setup.js present
- auth.setup.js calls context.storageState
- playwright.config.js declares use.storageState
- captures project depends on setup project
- run.sh + run-demo.sh trap-clean the auth state file
7. Banner output uses fs.readFileSync (no live console.log
with bash command-substitution syntax)
8. Viewport 1440×1080 + shotFullScroll() helper present;
reports the shotFullScroll/shotFull call counts
Plus two pre-existing fixes caught while re-running:
- Phase 5 (working-tree-clean) trap was being clobbered by a later
trap '...' EXITforSAFE_TEST_DIR. Consolidated into a single trap covering all cleanups. - Phase 1's
.envbackup was stored INSIDE the captures directory, so the bak file showed up ingit statusmid-smoke. Moved tomktemp -doutside the repo.
scripts/check-no-personal-data.sh gains --exclude-dir=test-results --exclude-dir=playwright-report so Playwright runtime artifacts (gitignored, but the script scans the live filesystem) don't trip the operator-LAN-IPs check on a stale post-run directory.
Live evidence (smoke output post-fix)¶
phase 1: run.sh refuses to run without .env... PASS
phase 2: .env is git check-ignore'd... PASS
phase 3: .env.example contains only RFC placeholders... PASS
phase 4: safeClick synthetic test (looksBlocked)... PASS (13/13)
phase 5: working tree unchanged by smoke... PASS
phase 6: storageState wiring (v1.3.36.1)... PASS (5 sub-checks)
phase 7: banner output uses fs.readFileSync... PASS
phase 8: viewport 1440x1080 + shotFullScroll... PASS
shotFullScroll calls: 15; shotFull calls: 21
Files changed¶
scripts/capture/auth.setup.js(new)scripts/capture/playwright.config.js(two-project config; viewport 1440×1080)scripts/capture/capture.spec.js(drop empty beforeAll + drop test #2 auth (handled by setup); login.png wrapped in anon describe; afterAll uses fs.readFileSync; new shotFullScroll helper; 15 surfaces use it)scripts/capture/run.sh(consolidated trap; AUTH_STATE cleanup; pass ARGOS_AUTH_STATE through)scripts/capture/run-demo.sh(same)scripts/capture/package.json(1.3.36.0→1.3.36.1)scripts/smoke/capture-automation.sh(phases 6-8 added; consolidated trap; backup outside repo)scripts/check-no-personal-data.sh(test-results+playwright-reportexcluded)docs/release-notes/v1.3.36.1.md(this file)CHANGELOG.md,mkdocs.yml
NOT changed: argosVersion stays at 1.3.35.4, frontend/package.json version stays at 1.3.35.4. No Go code; no frontend code; no panel binary change.
Operator workflow post-fix¶
cd ~/argos-edge && git pull
cd scripts/capture
# package-lock unchanged; just bump version applied:
# (no npm reinstall needed unless you blew away node_modules)
cd ~/argos-edge
scripts/capture/run.sh
# Verify:
# - /tmp/argos-captures-pending/dashboard-overview.png shows the
# real dashboard, not a /login redirect.
# - long-list surfaces (security-banned, security-activity,
# notifications-deliveries) are full-page, not viewport-clipped.
# - end-of-run banner reads "skipped=N" with a real number,
# not the literal "$(wc -l ...)" string.
When done:
The auth state file (/tmp/argos-auth-state.json) is auto-deleted by the trap on run.sh / run-demo.sh exit.
Versioning¶
scripts/capture/package.json 1.3.36.0 → 1.3.36.1 (independent of argosVersion; tracks tooling patches).
argosVersion + frontend/package.json deliberately stay at 1.3.35.4. Tag-without-rebuild precedent for tooling-only patches: v1.3.27.1, v1.3.34, v1.3.35.1, v1.3.35.5.