Fleet database credential and role-topology tooling (Sprint 3.1). Verifies stored credentials against PostgreSQL SCRAM verifiers offline, so a pg_hba change can be proven safe before it is made.
| Tier | tools |
| Role | unclassified (baselined) |
| Path | crates/tools/fleet-db |
| Edition | 2021 |
| Targets | cutover, fleet-backup, verify-credentials, tools_fleet_db, scram, topology |
| Public items | 17 across 2 modules |
| Tests | 24 |
What it is for
This crate does not document itself. No //! block on its entry point. The facts below are complete; the reason this crate exists is not written down anywhere, and belongs in src/lib.rs rather than here.
Capabilities
scram (other)
Offline verification of a candidate password against PostgreSQL's stored
| Item |
|---|
fn parse_verifier(raw : & str) -> Result <ScramVerifier, VerifierError> |
fn is_ascii_password(candidate : & str) -> bool |
ScramVerifier
Offline verification of a candidate password against PostgreSQL's stored
| Item |
|---|
pub struct ScramVerifier |
VerifierError
Offline verification of a candidate password against PostgreSQL's stored
| Item |
|---|
pub enum VerifierError |
VerifierError :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result |
fn verify_password(raw_verifier : & str, candidate : & str) -> Result <bool, VerifierError> |
topology (other)
Role naming and ownership-transfer SQL (Sprint 3.1, US-3.1.2; ADR 0025 §1, §4).
| Item |
|---|
pub const MAX_IDENTIFIER_BYTES: usize |
fn ownership_transfer_sql(new_owner : & str, objects : & DbObject,) -> Result <Vec <String>, RoleError> |
DbObject
Role naming and ownership-transfer SQL (Sprint 3.1, US-3.1.2; ADR 0025 §1, §4).
| Item |
|---|
pub struct DbObject |
ObjectKind
Role naming and ownership-transfer SQL (Sprint 3.1, US-3.1.2; ADR 0025 §1, §4).
| Item |
|---|
pub enum ObjectKind |
ObjectKind :: fn alter_verb(self) -> & 'static str |
RoleError
Role naming and ownership-transfer SQL (Sprint 3.1, US-3.1.2; ADR 0025 §1, §4).
| Item |
|---|
pub enum RoleError |
RoleError :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result |
fn owner_role(db : & str) -> Result <String, RoleError> |
fn app_role(db : & str) -> Result <String, RoleError> |
Roles
Role naming and ownership-transfer SQL (Sprint 3.1, US-3.1.2; ADR 0025 §1, §4).
| Item |
|---|
pub struct Roles |
fn derive_roles(db : & str) -> Result <Roles, RoleError> |
How to use it
No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.
Module structure
tools_fleet_db
scramtopology
flowchart TD n_tools_fleet_db["tools_fleet_db"] n_tools_fleet_db --> n_scram["scram"] n_tools_fleet_db --> n_topology["topology"]
Public surface
`scram`
| Item | What it is |
|---|---|
pub enum VerifierError | Why a stored verifier could not be checked |
VerifierError :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result | — |
pub struct ScramVerifier | A decoded pg_authid.rolpassword. |
fn parse_verifier(raw : & str) -> Result <ScramVerifier, VerifierError> | Decode SCRAM-SHA-256$<iter>:<salt>$<StoredKey>:<ServerKey> |
fn verify_password(raw_verifier : & str, candidate : & str) -> Result <bool, VerifierError> | Does candidate reproduce this stored verifier? Ok(true) means the password is the one the cluster stores |
fn is_ascii_password(candidate : & str) -> bool | Is this password safe to check offline? SASLprep only matters for non-ASCII input; the caller should surface a warning rather than report a confident mismatch for such a password. |
`topology`
| Item | What it is |
|---|---|
pub const MAX_IDENTIFIER_BYTES: usize | PostgreSQL's identifier length limit |
pub enum RoleError | Why a name cannot be used. |
RoleError :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result | — |
pub struct Roles | The role pair for one database. |
fn derive_roles(db : & str) -> Result <Roles, RoleError> | Derive both roles for a database, validating the derived names |
fn owner_role(db : & str) -> Result <String, RoleError> | <db>_owner, validated |
fn app_role(db : & str) -> Result <String, RoleError> | <db>_app, validated |
pub enum ObjectKind | The object classes whose ownership must move, each with its own ALTER verb. |
ObjectKind :: fn alter_verb(self) -> & 'static str | The ALTER <kind> verb |
pub struct DbObject | One object enumerated from the target database. |
fn ownership_transfer_sql(new_owner : & str, objects : & DbObject,) -> Result <Vec <String>, RoleError> | Generate the per-object ownership transfer |
No pub use re-exports: every item above is declared in this crate.
Boundary
Reaches into infrastructure.
Shares tier tools with 84 other crates: tools-advisory-reach, tools-archive-guard, tools-artifact-scaffold, tools-ask-ai-core, tools-ask-ais, tools-ask-gemini, tools-book, tools-book-report, … (84 total).
_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._
Where it sits
| Tier (ontology) | tools |
| Architectural role (taxonomy) | unclassified (baselined) |
| Location | crates/tools/fleet-db |
| Vocabulary in force (lexicon) | current |
Tier flow. Which tiers this crate's own edges cross.
flowchart LR n_tools["tools"] --> n_infrastructure["infrastructure"]
Dependencies
Runtime, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `infrastructure-backup` | infrastructure | no | always |
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
anyhow | ^1 | — | no | always |
base64 | ^0.22 | — | no | always |
clap | ^4 | derive, env | no | always |
hmac | ^0.12 | — | no | always |
sha2 | ^0.10 | — | no | always |
sqlx | ^0.8 | runtime-tokio, postgres, chrono, uuid, json | no | always |
tokio | ^1 | full | no | always |
Development, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `tools-cli-conformance` | tools | no | always |
Build. None.
Depended on by. 1 workspace crate.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR n_tools_corpus["tools-corpus"] -->|uses| SELF SELF["tools-fleet-db"] SELF -->|development| n_tools_cli_conformance["tools-cli-conformance"] SELF -->|runtime| n_infrastructure_backup["infrastructure-backup"] classDef self fill:#1f883d,stroke:#1f883d,color:#fff; class SELF self;
Feature flags
No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.
Targets
| Kind | Name | Source |
|---|---|---|
| bin | cutover | `src/bin/cutover.rs` |
| bin | fleet-backup | `src/bin/fleet-backup.rs` |
| bin | verify-credentials | `src/bin/verify-credentials.rs` |
| lib | tools_fleet_db | `src/lib.rs` |
| test | scram | `tests/scram.rs` |
| test | topology | `tests/topology.rs` |
Error model
| Error type | Named by |
|---|---|
RoleError | app_role, derive_roles, owner_role, ownership_transfer_sql |
VerifierError | parse_verifier, verify_password |
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | none detected |
| async runtime | yes |
| database access | yes |
| network I/O | none detected |
| unsafe code | none detected |
| environment variables | yes |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
| Variable | Read in |
|---|---|
HOME | src/bin/verify-credentials.rs |
Related capabilities
1 workspace crate depends on this one: tools-corpus.
Verification
| Kind | Count |
|---|---|
| Unit tests | 3 |
| Integration tests | 21 |
| Examples | 0 |
| Doctests | 0 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
scram | 5 | 0 | 0 |
topology | 9 | 0 | 3 |
What the tests establish, by name:
a_malformed_verifier_is_an_error—tests/scram.rsa_wrong_password_does_not_verify—tests/scram.rsan_empty_verifier_is_an_error_not_a_mismatch—tests/scram.rsan_md5_verifier_is_unsupported_not_a_mismatch—tests/scram.rsthe_correct_password_verifies_against_the_rfc_vector—tests/scram.rsthe_verifier_fields_are_parsed—tests/scram.rszero_iterations_is_rejected—tests/scram.rsa_bad_target_owner_is_rejected—tests/topology.rsa_derived_name_over_63_bytes_is_rejected_not_truncated—tests/topology.rsa_quote_in_an_existing_name_is_doubled—tests/topology.rsan_empty_or_nul_object_name_is_still_rejected—tests/topology.rsan_injection_attempt_is_refused_by_policy—tests/topology.rseach_object_kind_uses_its_own_alter_verb—tests/topology.rsemitted_identifiers_are_quoted—tests/topology.rsexisting_objects_may_have_names_the_derivation_policy_forbids—tests/topology.rsnames_outside_the_policy_are_rejected—tests/topology.rsobjects_from_several_legacy_owners_are_all_transferred—tests/topology.rsroles_are_derived_from_the_database_name—tests/topology.rsthe_helpers_agree_with_derive_roles—tests/topology.rsthe_transfer_is_idempotent—tests/topology.rsthe_transfer_never_uses_reassign_owned—tests/topology.rscli_definition_conforms—src/bin/cutover.rscli_definition_conforms—src/bin/fleet-backup.rscli_definition_conforms—src/bin/verify-credentials.rs
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 15 | 17 |
Public modules with a //! block | 2 | 2 |
pie showData
title Public items with rustdoc
"Documented" : 15
"No rustdoc detected" : 2
Metrics
| Metric | Value |
|---|---|
| Rust source files | 6 |
| Source lines | 1174 |
| Code lines | 759 |
| Public API items | 17 |
| Public modules | 2 |
| Tests | 24 |
| Examples | 0 |
| Cargo features | 0 |
| Direct runtime dependencies | 8 |
| Workspace reverse dependencies | 1 |
pie showData
title Public API by kind
"constant" : 1
"enum" : 3
"function" : 7
"method" : 3
"struct" : 3
pie showData
title Rust source composition
"Code" : 759
"Blank or comment" : 415
Generation
Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.