dowrshak zoom in, turning point towards a dedicated credential management tool

Date: 2026 01-January 07


(
cd ~/dev/dworshak
cat README.md
ls
ls src/dworshak/
cat src/dworshak/cli.py
ls -a ~/.dworshak
)

This readme is mid edit

We took a version that said "dworshak should do credentials as part of a tools that does api data transfer orchestration" to now thinking that "clean separation is good, dworshak can be agnostic and puupose built for managing open ssl locally encrypted SQL credentials"


does a tool exist like this already?

It sounds like you are pivoting Project Dworshak toward being a lightweight, file-based "Secret Store" rather than an all-in-one data orchestrator.

The short answer is: Yes, tools like this exist, but they are often either "too big" (enterprise cloud) or "too small" (just a library).

Here is a breakdown of the existing landscape and how Dworshak compares to what’s currently out there.

1. The Direct Competition (CLI Secrets Management)

2. The "Library" Tier (Python-centric)

3. The Gap Dworshak Fills

You have identified a "Goldilocks Zone" for infrastructure automation:

Feature OS Keyring HashiCorp Vault Project Dworshak
Storage System Registry Memory/Server Local Encrypted SQLite
Portability Hard (OS specific) Hard (Server req) Easy (File-based)
Automation Medium High High (CLI/Cron-friendly)
Footprint Tiny Huge Small (Python/UV)

Why Dworshak is still worth building

Even if "Pass" or "Keyring" exist, your specific implementation has three "unfair advantages" for your use case:

  1. SQLite Backend: Unlike pass (which is just flat files), having a vault.db allows you to store metadata alongside credentials (e.g., When was this rotated? Which Emerson node does this belong to?).

  2. Environment Agnostic: By shipping your own "Root of Trust" (the .key file), you ensure that a script written on your Windows dev machine will run exactly the same way on a Termux-equipped tablet or a ruggedized field PLC.

  3. Scoped for Infrastructure: Most secret managers are for people passwords. Dworshak is designed for system credentials (SOAP/REST tokens) meant to be consumed by other scripts.

Refined Focus for your Readme

Since you are "mid-edit," you might want to lean into this "Separation of Concerns." Dworshak is the Security Guard, not the Delivery Truck. It provides the credentials to the orchestration scripts, but it doesn't necessarily have to move the data itself.

Would you like me to draft a "Changelog" entry for this pivot to a standalone credential manager, or should we refine the register command to handle metadata for those legacy SOAP services?

another question about separation of concerns

  

an API management tool (let's call it pipeline. or heaphy, for two different credential management tools, of different scale) should have a way to store credentials.

  

maybe that documented way for both heaphy and pipeline should be to simply say "use the dworshak CLI for clear seaparation of concerns rather than an onboard subcommand. know your service and item names, and call them in scripts or from stored configs"

  

hypothetically dworshak could expose a library and be imported. This would make it an explicit requirement. Or, we could manaually set up creds using teh dworshak CLI (they have to be set up sometime, we can only automate so much). Then to program would only have to know the ~/.dworshak paths, not the dworshak functions. if it came down to it, in edge cases or other user stories, the CLI could be called using subprocess.run(['dworshak',`setup`]), etc.

  

compare and contrast one eay, the other, a hybrid, and a way i am not thinking of

This is the classic "Protocol vs. Product" debate in software design. By decoupling the credential store (Dworshak) from the consumer (Pipeline/Heaphy), you are moving toward a Unix-style ecosystem where tools communicate through agreed-upon conventions rather than heavy, built-in features.

Here is the breakdown of the three paths you've identified, plus a fourth "Conventions" approach that might be the cleanest of all.


1. The CLI Dependency (Subprocess Path)

In this model, Pipeline calls dworshak get --service x --item y to retrieve a secret.

2. The Library Dependency (Import Path)

You package Dworshak as a Python library (pip install dworshak) and Pipeline calls dworshak.get_secret(...).

3. The Hybrid (The "Tool-Provider" Model)

Dworshak provides a CLI for humans to manage keys, but provides a minimal, stable core library for programs to read them.

4. The "Agnostic Convention" Path (The way you might not be thinking of)

Instead of the tools knowing about "Dworshak" the software, they only know about The Dworshak Standard.


Comparison Matrix

Feature CLI/Subprocess Library Import Agnostic Convention
Separation Absolute Moderate (Shared Env) Highest
Speed Slow (Process overhead) Fastest Fast (Direct DB Read)
Language Any Python Only Any (with Fernet lib)
Maintenance Maintain CLI Output Maintain API/Types Maintain File Schema

Recommendation: The "Standardized Path"

Go with a version of Path 4.

  1. Dworshak is the only tool that writes to the vault. It owns the "Write" concern (registration, rotation, setup).

  2. Pipeline/Heaphy are "Read-Only" consumers. Instead of importing all of Dworshak (and its dependencies like typer and rich), they use a utility module (perhaps a single file dworshak_reader.py you copy-paste or a tiny 0-dependency package) that knows how to unlock the vault.db.

This keeps your "Anti-Daemon" and "Boring Tool" philosophy intact. You aren't building a platform; you're building a filesystem convention with a helper CLI.

Would you like me to show you how a "zero-dependency" reader script for Pipeline would look so it doesn't have to import the whole Dworshak CLI?

"The "Agnostic Convention" Path (The way you might not be thinking of)"

This is exactly what i was thinking of.
 
That's what i meant when i said "Then to program would only have to know the ~/.dworshak paths, not the dworshak functions"

That makes perfect sense. You’re essentially defining a local protocol. If you go this route, Dworshak isn't just a tool; it's a specification for where secrets live on your infrastructure.

By having Pipeline and Heaphy look directly at ~/.dworshak/, you achieve the ultimate separation of concerns: Dworshak can be updated, rewritten in Rust, or replaced entirely, and as long as the .key and vault.db stay in the same format, the rest of your ecosystem never breaks.

Here is how to solidify that "Agnostic Convention" so it remains robust:

1. The "Contract" (The Schema)

To make this work across different tools, you treat your file structure like an API. You commit to a fixed internal structure for vault.db.

2. The Implementation (Write vs. Read)

The Writer (Dworshak CLI)

This is what you've already started. It handles the "heavy" dependencies: typer for the UI, rich for the tables, and the logic for password prompts and confirmation dialogs.

The Reader (Pipeline/Heaphy)

Since these tools only need to Read, they don't need the CLI logic. You can create a "Minimalist Reader" pattern. In Python, this would be a single file (e.g., vault_util.py) that you can drop into any project:

Python

import sqlite3
from pathlib import Path
from cryptography.fernet import Fernet

def get_secret(service: str, item: str):
    root = Path.home() / ".dworshak"
    
    # 1. Get the Key
    key = (root / ".key").read_bytes()
    f = Fernet(key)
    
    # 2. Query the DB
    with sqlite3.connect(root / "vault.db") as conn:
        res = conn.execute(
            "SELECT secret FROM credentials WHERE service = ? AND item = ?", 
            (service, item)
        ).fetchone()
    
    # 3. Decrypt
    return f.decrypt(res[0]).decode() if res else None

3. Why this wins in your "Infrastructure" use case

4. The Risks of the "Convention"


The "Changelog" Perspective

Since you mentioned this readme is "mid-edit," this pivot is a major architectural milestone.

Would you like me to help you draft the "Architecture" section of the README to define this "Agnostic Convention" for other developers (or your future self) to follow?


since vault_util.py would need to be the same, and it shows the standard for how to access dworshak, it should probably be stabilized into a separate very light library, like dworshak-access, to be included as a dep


a person could just put a vault_util.py file in their code, to reduce dependencies or the need to call an online obfuscated library, but even still having it s a library is good docmetation for what that file should include.

is this the right thinking?

This is exactly the right thinking. You are effectively creating a "Standard Library" for your own infrastructure.

By splitting the project into dworshak (the management CLI) and dworshak-access (the lightweight reader), you are following the "Client-Server" pattern without the overhead of an actual server.


The Architecture of "Dworshak-Access"

To keep this "right," the dworshak-access library should follow a "Zero-Boilerplate" philosophy. It shouldn't have typer, rich, or click as dependencies—only the bare essentials for decryption (cryptography) and the standard library (sqlite3).

Why this is a superior approach:

  1. Formalized Schema: If you decide to change the SQLite table structure in the future, you only have to update dworshak-access. Every tool using that library gets the update automatically via their package manager.

  2. The "Single Source of Truth": Having a library prevents "Logic Drift." If you copy-paste vault_util.py into five different projects, and then find a bug in how paths are resolved on Termux, you have to find and fix all five files. With a library, you fix it once.

  3. Documentation by Code: The dworshak-access source code becomes the living documentation for the "Agnostic Convention." If someone wants to write a reader in Go or Rust, they look at that library to see exactly how the Fernet bytes are handled.

  4. Environment Isolation: Pipeline and Heaphy can remain "clean." They don't need to know how to create a vault; they only need to know how to request a secret.


How the Ecosystem looks now

Component Responsibility Dependencies
Dworshak (CLI) setup, register, rotate, list typer, rich, cryptography, sqlite3
Dworshak-Access get_secret(), check_vault() cryptography, sqlite3
Pipeline / Heaphy Data orchestration dworshak-access

The "Copy-Paste" Escape Hatch

Even with a library, you should still keep the logic simple enough that a user could copy-paste the core function if they were in a locked-down environment without pip access. You can even include a dworshak-access --snippet command in the main CLI that prints the standalone Python code for a vault_util.py file to the terminal.

Next Step for your README

Since we are standardizing the "Access" side, the README should clearly distinguish between "Management" (using the CLI) and "Consumption" (using the access library).

Would you like me to draft the "Consumption" section for your README, including the code example for how Pipeline would use the dworshak-access library?

(
cd ~/dev/dworshak-access
ls 
cat README.md
cat pyproject.toml
ls src
ls src/drowshak-access
cat src/dworshak-access/__init__.py
cat src/dworshak-access/vault_util.py
)

># src/dworshak-access/__init__.py
>from dworshak_accesss.vault_util import get_secret(), check_vault()
>
>__all__ = [
>    "get_secret",
>    "check_vault"
>]

we need the check_vault function

However you are an AI. I am not sure I trust your architecture for human touch points like central exposed functinos.

make a submission for functions which should be included, in roder of importance, and explain why their design is valid and useful

I appreciate the skepticism. To earn that trust, the "human touch point" design should focus on resilience and diagnostic clarity. If a script fails to get a secret, the developer needs to know why immediately: is the key missing, the database locked, or the service name misspelled?

Here is my submission for the core functions of dworshak-access, ordered by their utility in a real-world pipeline.


1. get_secret(service: str, item: str) -> str

The Primary Workhorse.

2. check_vault() -> VaultStatus

The Diagnostic Safety-Check.

3. list_items(service: Optional[str] = None) -> List[Tuple[str, str]]

The Discovery Tool.


Proposed Implementation for vault_util.py

Python

import sqlite3
import os
from pathlib import Path
from typing import NamedTuple, List, Tuple, Optional
from cryptography.fernet import Fernet

DEFAULT_ROOT = Path.home() / ".dworshak"

class VaultStatus(NamedTuple):
    is_valid: bool
    message: str
    root_path: Path

def check_vault(root: Path = DEFAULT_ROOT) -> VaultStatus:
    """Diagnose the health of the Dworshak environment."""
    if not root.exists():
        return VaultStatus(False, "Vault directory does not exist.", root)
    if not (root / ".key").exists():
        return VaultStatus(False, "Security key (.key) is missing.", root)
    if not (root / "vault.db").exists():
        return VaultStatus(False, "Credential database (vault.db) is missing.", root)
    
    try:
        with sqlite3.connect(root / "vault.db") as conn:
            conn.execute("SELECT 1 FROM credentials LIMIT 1")
    except sqlite3.Error as e:
        return VaultStatus(False, f"Database error: {e}", root)
        
    return VaultStatus(True, "Vault is healthy.", root)

def get_secret(service: str, item: str, root: Path = DEFAULT_ROOT) -> str:
    """Retrieve and decrypt a specific secret."""
    key_path = root / ".key"
    db_path = root / "vault.db"

    if not key_path.exists():
        raise FileNotFoundError(f"Dworshak key not found at {key_path}")

    fernet = Fernet(key_path.read_bytes())

    with sqlite3.connect(db_path) as conn:
        cursor = conn.execute(
            "SELECT secret FROM credentials WHERE service = ? AND item = ?",
            (service, item)
        )
        row = cursor.fetchone()

    if not row:
        raise KeyError(f"No credential found for {service}/{item}")

    return fernet.decrypt(row[0]).decode()

Why this design is "Human-Centric"

  1. Explains Failure: Using VaultStatus and descriptive KeyError/FileNotFoundError messages ensures that when a cron job fails at 2:00 AM, the logs tell you exactly which file was missing.

  2. Path Flexibility: By allowing a root argument (defaulting to ~/.dworshak), you make the library testable. You can point it at a temporary directory during CI/CD tests without touching your real production credentials.

  3. No Magic: It doesn't try to "auto-fix" anything. If the vault is broken, it tells you. This fits your "Data Dam" philosophy—predictability over cleverness.

Would you like me to generate a Changelog for dworshak-access reflecting these diagnostic additions?

service name and item id

please explain the typical expecations and common knowledge and even the history around the service name and item id pairing. I first was exposed to it using python keyring, and i have inspected windows credential manager, which is shaped a little differently. is the service name and item id pattern a common database artifact? which did it come into existance? how did it spread? what are the alternatives? is it stable and expected? how can it be best leveraged properly?

The (service, item) pairing is a foundational pattern in identity management. It is a implementation of Namespacing, a concept used to prevent collisions when multiple applications share a single storage backend.

1. The History: From Global to Scoped

In early computing, credentials were often stored in global files (like /etc/passwd) or application-specific flat files.

2. Is it a "Database Artifact"?

Technically, no. It is a Schema Pattern.

In database terms, this is a Composite Primary Key. In the dworshak vault, your primary key is defined as UNIQUE(service, item). This ensures that while you might have ten "primary" items, you only have one "primary" item per "service."

3. Comparison of Implementations

System Terminology Structure Philosophy
Python Keyring Service / Name API-driven abstraction Cross-platform middleware.
macOS Keychain Service / Account Attributes in a Keychain Item Deeply integrated into the OS; supports metadata.
Windows Cred. Mgr. Internet/Network Address "Target Name" Originally built for NTLM/Network auth; feels "flat" compared to Nix.
Project Dworshak Service / Item Namespace / Entry Portable, SQLite-backed, local-first.

4. How to Leverage it Properly

The "Service" name should describe the Target System, while the "Item" should describe the Role or Identity.

5. Alternatives

The primary alternative is a UUID-based system or Path-based system.

6. Stability and Expectations

The (service, item) pattern is extremely stable. By sticking to this, Dworshak follows the "Principle of Least Astonishment"—a developer familiar with Python's keyring or Linux's secret-service will immediately understand how to use your tool without reading a manual.


Implementation for Dworshak

In your vault_util.py, I recommend enforcing a lowercase, slug-friendly format for these names (e.g., service.lower().strip()) to prevent a situation where RJN_API and rjn_api are treated as different services.

(service, item) architecture: its longevity is largely due to how well it maps to real-world infrastructure. In automation, you are rarely just dealing with "a password"; you are dealing with a specific authority (the service) and a specific grant or identity (the item).

By adopting this, Dworshak isn't just a side project—it's speaking the same language as professional-grade security systems while maintaining the simplicity of a local SQLite file. It makes the system intuitive for anyone who has touched a Linux keyring or a modern API vault.