Skip to content

G9BrowserAgent 3.3.0

Choose a tag to compare

@ImanKari ImanKari released this 27 Sep 18:47

Download

System File Updates
Windows 10/11 (x64) G9BrowserAgent-Setup-3.3.0.exe — per user, no administrator rights Automatic: G9BrowserAgent checks these releases, downloads in the background and asks before installing
macOS 12+ (Apple silicon) G9BrowserAgent-3.3.0-mac-arm64.dmg G9BrowserAgent tells you when a release is out; download it and replace the app (the app is not signed with an Apple Developer ID yet, so macOS cannot install updates into it)
macOS 12+ (Intel) G9BrowserAgent-3.3.0-mac-x64.dmg As above
Linux (x64) G9BrowserAgent-x86_64.AppImage — keep this file name: updates replace the file in place Automatic, like Windows
Debian/Ubuntu (x64) G9BrowserAgent_3.3.0_amd64.deb G9BrowserAgent tells you; install the new .deb with your package manager

The installers are not code-signed: Windows SmartScreen and macOS Gatekeeper ask once before the first start. See the README for what to click, and for the browser extension (loaded once, updated by G9BrowserAgent itself).

latest.yml, latest-mac.yml and latest-linux.yml are the update metadata G9BrowserAgent reads; the .zip and .blockmap files are for the updater.

What changed in 3.3.0

Why. Ten approved runner/flow features in one batch: flows carrying credentials could not be
recorded safely, --env was only a label, the known world confused environments, a flow that could
not run either failed or silently "passed", and the device recorder's passive capture had no consumer.

Password masking at record time (extension/tools/record.js). The in-page recorder never emits
a password field's value (input type=password, or autocomplete current-/new-password — the same rule
the input sampler always used): the change event carries value: '', secret: true, so the
credential is not even in the raw session buffer. normalize() turns the marker into
{{secret:password}} (password2, … per distinct field, keyed by the strongest locator), and
stopRecording declares the matching parameters: { password: { type: "secretRef", required: true } }
(secretParametersOf). validateFlowSpec also refuses a secretRef carrying a literal under value,
next to the existing default rule; qa.substitute resolves {{secret:NAME}} exactly like
{{NAME}}.

Secrets at run time (runner/g9.mjs). resolveSecrets: the --data file first, then
G9_SECRET_<NAME> (uppercased, non-alphanumerics → _). A flow whose required secret has neither
is SKIPPED, the reason naming both ways to provide it. Secret VALUES are masked back to their
placeholder everywhere a result echoes them (maskSecretsDeep over the whole flow result — step
echoes, failure messages quoting field contents). Found and fixed on the way: parameterDefaults
(replay.js) handed the secretRef declaration object over as a value, so {{password}} typed
"[object Object]" into the field — a secretRef now contributes no default, and an unresolved one
fails substitution loudly.

Real --env (runner/g9.mjs, daemon/project.js). environments accepts the object form
{ "baseUrl", "features", "build" } beside the string form (a malformed entry is reported in
problems and kept out). With --env <name> (refused when it names no declared environment) every
flow URL — startUrl, navigate steps, url oracles — whose origin is ANY declared environment's origin
is re-pointed at the chosen one before import (rewriteFlowUrls); {{baseUrl}} resolves in URLs
and as a variable. Fixed on the way: the start URL was never substituted at all — {{placeholders}}
in it reached the browser literally (resolveUrlPlaceholders now runs before the goto).

Known worlds per environment (extension/lib/signature.js, approved.js, replay/flowsync/
router/flows). What "normal" looks like on test1 is not test2. knownWorldFor/withKnownWorld:
the flat recording.knownWorld IS the default environment's world (full compatibility — every
existing store, sidecar and panel keeps meaning what it meant), named environments live under
knownWorlds[env]. Replay compares, seeds and saves under the run's environment (the new
environment replay/calibrate argument; the runner passes --env through); approve folds the
reviewed run into the environment its signature names and refuses a contradicting --env. The
sidecar carries knownWorlds beside the flat knownWorld (validateApproved knows the shape;
applyApproved takes the later human approval PER ENVIRONMENT, so a repo approval on test2 never
overwrites a newer local one on test1); knownWorlds joined every local-truth list
(daemon/flows.js LOCAL_ONLY, daemon/router.js LOCAL_TRUTH, the import skip set). The desktop's
Approvals view still shows the default environment's approval only.

urlNormalizers are consumed (extension/lib/signature.js). The project's [{match, as}] rules
now reach the signature twice: buildSignature gets them from the new replay argument (the runner
reads g9.project.json), and renormalizeKnownWorld re-applies them to the STORED world's network
keys (and volatile masks) at comparison — so /api/orders/<guid> collapses to /api/orders/{id} on
both sides even for a world approved before the rule existed. Colliding keys keep the larger count,
never a sum past runs.

requires preflight and SKIPPED (extension/lib/flowspec.js, runner/g9.mjs,
runner/report.mjs). A flow may declare requires: { minBuild?, features?, environments? }
(validated; unknown keys refused; carried through toFlowSpec/fromFlowSpec — they used to drop
everything they did not know, so a Pull → Push would have silently erased it). Before a tab opens or
a device is driven: environments against --env; on maui, qa.ping/qa.capabilities once per
device per run (lenient numeric-dotted minBuild compare); on web, the environment object form —
data it does not declare is a SKIP saying "cannot evaluate requires.X … declare it in
g9.project.json", never a silent pass. SKIPPED is first-class: skipReason in run.json,
<skipped message> in junit.xml (with a testsuite skipped count), a distinct section in
report.html, "SKIPPED" in qa-automation-status.json. <reportDir>/skips.json maps
(flowId + environment) → { firstSkippedAt, lastReason }; an executed flow drops out, an entry
14+ days old warns loudly in the summary and the report («این فلو ۱۴+ روز است اجرا نشده — پوشش در
حال آب رفتن است»). Skips never make a run red.

Suite order and stopOn (runner/g9.mjs). order: "risk-desc" (critical > high > medium >
low; missing = medium, "normal" accepted; stable) and stopOn: "failure" — the suite stops after
FAIL_PRODUCT / FAIL_AUTOMATION / ERROR (not SURPRISE, not SKIPPED), and the rest are reported
NOT_RUN, naming the stopping flow. Any other stopOn value is refused by name.

Exit code 5 (runner/g9.mjs, scheduler, desktop, README). A runner-internal ERROR exits 5,
distinct from product 1; precedence 1 > 2 > 5 > 3 > 0. The scheduler's exit-code fallback and the
desktop's verdict maps learned SKIPPED/NOT_RUN and 5.

Provenance (runner/g9.mjs, report.mjs). run.json/report.html/junit properties carry
provenance: { gitCommit, gitBranch, appBuild } — git asked in the directory holding
g9.project.json (nulls without git), appBuild from the device's qa.ping or the web environment's
declared build.

g9 harvest --platform agripad (runner/g9.mjs). Reaches the device exactly like
run --platform agripad (adb forward, port 8799, lease), calls flow.record.harvest (drains the
app's passive ring buffer) and writes each candidate to
<flowsDir>/agripad/candidates/<yyyyMMdd-HHmm>-<n>.candidate.json (format: "g9/flow-candidate",
schemaVersion 1, tags ["@candidate"], capture time, device, provenance, the device's steps passed
through untouched). An app build without the command gets a friendly message naming its build.
Candidates are NOT flows: the runner's loaders read only *.flow.json, and the daemon's library
walk now skips *.candidate.json by name (it used to list any .json as a flow).

Also found and fixed on the way.

  • Device type steps typed NOTHING: the driver sent text, the bridge reads args.value — every
    type step "passed" while the field stayed empty (runner/drivers/agripad.mjs).
  • The device's consent refusal ("Live access has not been granted") was classified FAIL_PRODUCT:
    the runner's pattern said "has not granted live access". Both wordings classify as
    FAIL_AUTOMATION now.
  • Device flows were never validated: loadDeviceFlows now runs validateFlowSpec with the action
    set widened by the driver's own dismiss (the validator takes { actions }), so a malformed
    file stops the run with its name instead of failing step-by-step on the device.
  • Device steps never saw --data variables at all; they are substituted now (including
    {{secret:…}}), and step outcomes are masked like the web path's.

Docs/tests. g9.project.example.json shows the environment object form and marks
operationAliases/reportSink/volatile RESERVED — not implemented; runner/README.md covers all
of the above; the extension suite grew from 88 to 100 tests (masking, secrets, requires, --env
rewriting, urlNormalizers both sides, per-env worlds and sidecars, junit <skipped>, exit
precedence, the skip ledger, candidate exclusion); the version stays 3.2.1 until this ships.

SHA-256

daa9b71ef8b67c1a7337b120a653d8570fdc1c0026715644a72df918c05455cf  G9BrowserAgent-3.3.0-mac-arm64.dmg
e7c644f3eee5a923f7240f111abcaa5a4b7be0bd239a90dfbebf99ba241c2d95  G9BrowserAgent-3.3.0-mac-arm64.dmg.blockmap
a81d77f0deced0137bf9daed1b42fdb0d4e3fd73726b4f6c552db570446605f5  G9BrowserAgent-3.3.0-mac-arm64.zip
9a139791b6a646f9b5de8531b612258ab71db4652ce3f3f13adc920adf54971a  G9BrowserAgent-3.3.0-mac-arm64.zip.blockmap
aaef3a4d2218154c5a7e7f00a2b0837f8874c0093cddfb4b494c6332830cf9e7  G9BrowserAgent-3.3.0-mac-x64.dmg
7e7c41bd7fe2cd7b8b82523b49f0410c3d24cdfaefdc2a5a4ab13d1c293861a9  G9BrowserAgent-3.3.0-mac-x64.dmg.blockmap
a947dee1d4ed6a43e9e1fb8bcecc9c6fd54008187759c9fc097cb2c255c5fa47  G9BrowserAgent-3.3.0-mac-x64.zip
91dd0b48d65367d3e9acf41ca58f478dc787709f30990b45523772f41209cb20  G9BrowserAgent-3.3.0-mac-x64.zip.blockmap
f8ddf6e7c8407f8be3ffbeaa5a5c52b87143d7d66428c99987851ad8cc9e1786  G9BrowserAgent-Setup-3.3.0.exe
2add8f0c10a5eb3e812c719a9b0be71f0ea9f559f133731c8f207fa25f3132b6  G9BrowserAgent-Setup-3.3.0.exe.blockmap
3e8d612dc5abfaeed16f698e4916a4c7e853ef923b6ec22a7098eb4d8c738181  G9BrowserAgent-x86_64.AppImage
d5448478a923ba2e2a74eaf5c3b820559e1d7f6fdc626fb9c2ecac8cff1e4385  G9BrowserAgent_3.3.0_amd64.deb