Repository navigation
v1.0.10
Focus: Security stabilization, continued: refresh-token replay held across a fleet, RBAC caches bound to generations, plaintext PostgreSQL auth refused after a downgrade, JWKS redirects pinned, project listings that never run project code, and repository URLs screened before git sees them
🛠️ PATCH version
Changes
- Unknown identifiers cost the same as a wrong password.
Usersverified a miss against a decoy hash minted on each instance's first miss, so with a store built per request every unknown email cost a hash plus a verify — a silent enumeration oracle. The decoy is now a well-formed argon2id string of the current policy: no hash is computed and no password verifies. - Refresh-token replay detection holds across hosts. On a fleet sharing one store, a concurrent double-submit lost theft detection and a revoked family could come back. The successor and the tombstone are stored before the atomic take that elects the consumer (the loser gets
Replay), families stay revoked until their newest token expires, and a refused store write leaves the presented token valid for a retry. - RBAC permission caches are bound to generations and a realm. A revoke plus
invalidate()racing a cache fill was undone for the whole lifetime, and two resolvers on one cache served each other's lists. Lists are now cached under a global and a per-identity generation read before the database, keyed by a realm of the connection and the tables (or an explicitrealm:). Database errors deny instead of throwing; cache faults answer from the database. - A password reset during a login stands. The login's rehash no longer overwrites it: the upgrade is compare-and-set over the hash just verified, and a login that loses the race fails.
- PostgreSQL refuses plaintext authentication after a TLS downgrade. Under the default
prefer, an on-path attacker could refuse TLS and receive the password in cleartext or as an MD5 response. After a downgrade on a non-loopback host, cleartext and MD5 are refused and SCRAM needs at least 4096 iterations; SCRAM attributes are parsed strictly and the iteration count is capped. - JWKS redirects cannot reach private addresses. Each hop is resolved once and its vetted addresses dialed in order within the hop timeout; a non-public hop after a public answer is refused.
projects list,project infoand the create picker never run a project's code. They read the signature as tokens: string literals only (a computed field shows(dynamic)),exportableonly as the literaltrue, and a missing, symlinked, oversized or unparseable signature becomes one(invalid signature: …)row. Rendered metadata is cleaned of control characters and Output markup.projects importrefuses a symlinked signature and a source carrying abootglylauncher, and its consent names every path that runs the imported code (start, restart, startup, migrate, seed, schedule, tests and queues).- Repository URLs are screened before git sees them (
projects import, its prompts and the Wizard, andkit): credentials in the URL, remote helpers (ext::,fd::), plaintexthttp:///git:///ftp://and malformed URLs are refused, and every displayed URL is redacted. Transfers run underGIT_ALLOW_PROTOCOL=file:https:ssh(narrowed, never widened, by one you export), option parsing ends before caller values, and the import clones without a shell into a private random staging directory that is always removed. kitnever adopts a spoofed or helper remote as its releases remote, and accepts a token your owninsteadOfadds.- Session cache keys are classified with one look (a concurrent worker could make another refuse a regular file), and the launcher tip finds the global
bootglywithout a shell (a fatal error on php-wasm or withshell_execdisabled).
Upgrading
Kit (installed with the installer, cloned, or created from the GitHub template) — at the kit root:
bootgly kit upgrade v1.0.10- Running projects keep the code they loaded: stop them first (
bootgly project <Name> stop) or reload
them after (bootgly project <Name> reload). - Coming from a release older than
v1.0.4, lay down the agent rules once afterwards:
bootgly kit boot --agents. - A kit older than
v1.0.0-rc.1has nokit upgradeyet — move it once by hand:
git fetch --tags && git checkout refs/tags/v1.0.10 && git submodule update.
Docker:
docker pull bootgly/bootgly.kit:1.0.10Start the new image with the same volumes (-v): what lives in a volume is kept, and a container run
without one keeps nothing. Inside the image kit upgrade refuses — the image tag is the release.
Release-specific notes:
- PostgreSQL: a server reached without TLS under the default
prefer(non-loopback) can no longer authenticate with cleartext or MD5 passwords. Enable TLS on the server, or setsecure.mode => 'disable'(DB_SSLMODE=disable) to declare plaintext deliberately. - Refresh tokens: a fleet double-submit now ends in
Replayand a re-login; a refused store write throwsRuntimeException('JWT refresh token could not be consumed.') and leaves the token valid. AVaultover an injected Redis or custom driver now needs a sharedsecret:(pass the contents of{path}{prefix}.secretto keep existing records). Upgrade every host: a mixed rolling deploy keeps the old race until all run 1.0.10. - RBAC: cache keys move to
rbac:v2:{realm}:…(old keys are deleted byinvalidate()); upgrade the processes that grant and revoke first, callinvalidate()after the commit, and make writers and readers derive one realm (or passrealm:). Permission reads always go to the primary, an RBAC over aTransactionis never cached, and a check costs 3 cache reads on a hit. Users::verify()returnsnullwhen a reset or a deletion wins the race during the login.- Projects: signature metadata (
name,description,version,author) must be string literals to be listed, andexportablemust be the literaltrue. projects import: put credentials in a git credential helper or use SSH — URLs carrying them are refused, and git asks no username or password during the import.http://,git://,ftp://and<helper>::URLs are refused (clone those yourself and import the local path). AGIT_ALLOW_PROTOCOLyou export narrows what Bootgly's transfers may use.
Commits
Fixes
fix — Bug fixes:
• fix(vcs): screen repository URLs and clone imports without a shell
• fix(projects): read signatures as tokens in list and info
• fix(security): refuse plaintext PostgreSQL auth after a downgrade and pin JWKS hops
• fix(api): bind the RBAC cache to generations and close the rehash race
• fix(api): keep refresh-token replay detection across hosts
• fix(wpi): classify the session cache key path with one look
• fix(cli): find the global launcher without a shell
• fix(api): verify unknown identifiers against a synthetic policy decoy
Implementations
test — Tests:
• test(wpi): time each immediate refork retry against the first backoff step
docs — Documentation:
• docs(kit): fit the agent rules back within their size budget
• docs(kit): ask every question through the agent's question tool
• docs(readme): clarify that only the core is built in
chore — Maintenance:
• chore(release): 1.0.10
• chore: open 1.1.0 development