Secure Engineering
StonkSmith
I need financial security, not another app.
- Python 3.14
- SQLite
- Playwright
- OS keyring
- Google Sheets API
- pytest
- secrets in the database
- 0
- credential store
- OS keyring
- test functions
- 918
- broker integrations
- 5
The tool aggregates my own investment accounts, which means it handles about the most sensitive data a personal project can hold: live broker credentials, authenticated sessions, account identifiers, and balances. That is why it is on this page. Almost every design decision in it is a decision about what the tool is allowed to keep.
Secrets go to the operating system keyring, whether that is Keychain, Secret Service, or Credential Locker, and never into SQLite. The database stores a reference of the form broker:account, which is enough to find the secret and useless on its own. Displaying credentials masks them. Exporting them writes the reference, not the value. Databases created before the keyring existed are migrated when they are opened: the plaintext password moves to the keyring and the column is cleared in place, because a migration that leaves the old copy behind has not migrated anything. The README states that passing a password on the command line leaks it to shell history and the process list, and tells you to use stored credentials instead.
One broker fronts its login with commercial bot detection and device fingerprinting. StonkSmith does not defeat that sensor and does not try to. It requires a manual login: a human signs in, including the second factor, and only then does the tool take over the session and persist it. It deliberately never drives an attached browser before you are signed in. That is a stated scope limit, the same way opseclint is explicitly not an evasion tool, and not an unfinished feature.
The verification record is part of the repository. A document tracks, claim by claim, which broker behaviour has been observed against a live account and which is only unit-tested, and most rows still say no. Five brokers are implemented; five brokers are not proven. One claim failed there, when a broker turned out not to persist sessions at all and so needs a manual login every run, and the README was corrected rather than left standing. A failed step is information, not a defect.
The same care shows up in the data handling. The fixture the parser is tested against is a real signed-in page, redacted before it was committed, because a synthetic fixture only proves the parser can read a page nobody has. Snapshots are append-only, so a wrong mark is deleted explicitly and never overwritten. Money is stored numerically with the source's raw text kept beside it, so a parsing disagreement is visible instead of silent. And because it runs unattended, it has an exit-code contract: 0 did the work, 1 did not complete, and 130 is an interrupt kept distinct so a scheduler pages on a real failure and shrugs at a human pressing Ctrl-C.
Details
- Secrets stored in the OS keyring (Keychain, Secret Service, Credential Locker); SQLite holds only a reference
- Legacy databases migrate on open: plaintext passwords move to the keyring and the column is cleared in place
- Credential display masks; credential export writes the reference rather than the value
- README documents that passing a password on the command line leaks to shell history and the process list
- Manual login required where a broker fronts sign-in with bot detection: the tool never drives an attached browser before a human has authenticated
- A live-verification document records which broker claims are observed against a real account and which are only unit-tested; most are still unverified
- A claim that failed live verification was corrected in the README rather than left standing
- Parser fixture is a real signed-in page, redacted before commit
- Append-only snapshots; money stored numerically with the source's raw text retained beside it
- Broker plugins discovered from the source tree and the user's config directory; one that fails to load is reported and skipped rather than taking down the run
- CI runs ruff lint, ruff format check, ty type checking, and 918 tests across 56 files