Reference
Create a Google app password for Skrzynka, without opening the account.
weles app-password signs one Skarbiec Google login in on the managed executor, creates an app password named Skrzynka and hands it to skrzynka account app-password --provider gmail, which proves it over IMAP, stores it in Skarbiec and declares the mailbox.
Why it exists#
When two-step verification is on, Google refuses an account's ordinary password over IMAP with "Application-specific password required". Google offers no API that issues an app password; the only way is the account's own App passwords page in a signed-in browser. This action is that browser step, so a mailbox is connected by a command rather than by a person copying sixteen letters from a web page.
Commands and execution#
Start with weles app-password --provider google --login-role <skarbiec-role> --organization <skrzynka-organization> --account <mailbox-email>, or select the exact existing login with --login-item <skarbiec-item> instead of --login-role. The independently supplied --account is required for creation. The runtime API calls it expectedAccount and POST /run params call it expected_account. Whitespace is trimmed; no account is inferred from the selected vault item. The managed executor starts a detached google_app_password run and returns its identifier. Configure WELES_WORKER_API_BASE and WELES_WORKER_TOKEN as for account-security. Neither command starts a browser on the caller's machine.
Admission resolves the selector once and retains login_item, organization and expected_account in both execution parameters and the saved request. The trajectory resolves login material once and compares that snapshot's username with expected_account, ignoring case and surrounding whitespace, before creating a profile or browser. A changed vault binding is refused rather than connecting another mailbox. The CLI requires exactly one of --login-role, --login-item or --run; creation also requires --provider google, --organization and --account. Readback with weles app-password --run <run-id> accepts none of those creation options. Blank, conflicting or unknown inputs are refused before contacting the executor; invalid API input returns HTTP 400.
The login item holds username, password and, when enrolled, totp_secret. The run reuses the per-account browser profile under ~/.weles/browser_profiles/google-account/<account>, answers Google's address, password and authenticator-code screens from the item, opens https://myaccount.google.com/apppasswords, creates a password named Skrzynka and reads it from the one dialog that shows it. It then runs skrzynka --organization <skrzynka-organization> account app-password --provider gmail --email <username> on the executor's host with the password on stdin; WELES_SKRZYNKA_BIN names another Skrzynka executable.
The shared Google-account sign-in helper observes page readiness and the visible password challenge rather than inserting deliberate or long idle gaps. After the email step, the password helper follows the actual visible field, offered password method or provider refusal; it takes no idle-pause dependency. The same helper serves authenticator enrolment, and its browser and provider errors remain the caller's result.
The password is never written to a file, a log, the run result or the HTTP answer: anything shaped like an app password is redacted from every report, and the only copy leaves the browser on Skrzynka's stdin.
weles app-password --provider google --login-role <skarbiec-role> --organization <skrzynka-organization> --account <mailbox-email>
weles app-password --provider google --login-item <skarbiec-item> --organization <skrzynka-organization> --account <mailbox-email>
weles app-password --run <returned-run-id>Result contract#
The saved request retains login_item, organization and expected_account. A trajectory result records ok, login_item, expected_account and the resolved email; on success it also records app_name Skrzynka and Skrzynka's own answer. Success requires Skrzynka's real IMAP verification and persistence, not merely admission of a run.
Refusals and diagnosis#
expected_account_required means the trajectory received no nonempty WELES_EXPECTED_ACCOUNT. expected_account_mismatch means the resolved login username differs from the independently requested account. Both stop before profile creation or browser/provider mutation and name the missing or conflicting identity.
google_push_approval_required means Google requested a phone approval. The refusal's next_action serializes the exact login_item and original expected_account into google_authenticator_enrol, then supplies a POSIX-quoted resume command preserving --login-item, --organization and --account. Standalone enrollment without expected_account remains supported; when supplied, it is checked before enrollment starts. Printing this continuation is not enrollment or IMAP success.
Enrollment persists the seed with Skarbiec set-json --if-unchanged against the exact login payload read before the browser started. It refuses a changed payload instead of attaching the seed to a rebound item or overwriting another edit. The vault compares and writes within one opened vault and refuses a concurrent save. seed_persist_unconfirmed with provider_enrollment_confirmed: true means Google accepted enrollment but the vault write/readback did not confirm the same account and seed; seed_written is null, not success. Its detail names the failed operation. Do not blindly repeat enrollment to hide that partial outcome.
google_sign_in_page_unrecognised: the sign-in page showed neither the address, the password nor the account; url and heading name what it did show.
google_app_passwords_unavailable: Google shows "The setting you are looking for is not available for your account". Two-step verification is off, a Workspace administrator has turned app passwords off, or the account is under Advanced Protection. textPreview carries the page.
app_passwords_page_not_reached, app_name_field_not_found, create_action_not_found and app_password_not_shown each name the step whose control or dialog Google did not show, with the address and a redacted page preview.
skrzynka_unavailable: the Skrzynka executable could not be started on the executor's host. skrzynka_refused_app_password: Skrzynka exited nonzero; detail carries its JSON refusal, for example GMAIL_IMAP_PASSWORD_REJECTED, and app_password_created: true records that Google's list now holds an unused Skrzynka entry the owner may revoke.
Real account-binding qualification#
Use an existing isolated Skrzynka organization and test mailbox, a dedicated authorized Gmail account, and its real Skarbiec login. The managed executor must be on its dedicated host at the committed Weles revision being qualified. The success journey creates a real Google app password and changes that test mailbox's stored receiving credential; never point it at an operator mailbox or unrelated login. The test does not provision or delete the fixture.
For --outcome account-mismatch, keep --account equal to the test mailbox's email but choose a real login belonging to a different dedicated test account. The run must report expected_account_mismatch with the original expected_account and resolved email. Saved run parameters must retain login_item, organization and expected_account without requiring equality of unrelated run metadata. Separately, persisted mailbox state must remain entirely unchanged: the test excludes only the derived credential_source and recovery_command observations from that comparison. No browser/provider mutation is accepted as part of this refusal.
For --outcome connected, the login must belong to the named account. Qualification checks the retained worker source revision, CLI admission and readback binding, persisted mailbox identity, and a real Skrzynka Gmail connection report whose app_password path is usable. A running run is retained as awaiting_observation, never passed. Resume it using --admission-report <retained-report.json> and exactly the same fixture arguments; this observes the existing run instead of creating another app password. Evidence is retained under build/real-tests/app-password-account/<run-uuid>/report.json, with downloaded run diagnostics and supported recordings beside it. A recording download failure marks qualification failed rather than silently claiming complete evidence. The command below is a qualification definition, not a claim that it has been run.
node tests/security/app-password-account.mjs --binary <weles> --skrzynka <skrzynka> --organization <isolated-org> --mailbox <test-mailbox> --account <expected-email> --login-item <real-login> --bind <loopback-address:port> --outcome connected
# For the independent wrong-login fixture, use --outcome account-mismatch.
# To observe an active run again, repeat the same arguments and add:
# --admission-report <retained-report.json>