dworshak 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dworshak-0.1.2/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2026 George Clayton Bennett <https://github.com/City-of-Memphis-Wastewater/dworshak-access/>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,51 @@
1
+ Metadata-Version: 2.4
2
+ Name: dworshak
3
+ Version: 0.1.2
4
+ Summary: Manage local, encrypted credentials. The **dworshak* CLI leverages openssl, sqlite3, and cryptography.
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: cryptography>=46.0.3
9
+ Requires-Dist: typer>=0.21.0
10
+ Requires-Dist: rich>=13.0.0
11
+ Dynamic: license-file
12
+
13
+ # Project Dworshak 🌊
14
+
15
+ **Dworshak** is the security bones behind API orchestration of infrastructure data between legacy SOAP services (EDS) and modern REST APIs (RJN).
16
+
17
+ ## 🏗 The Ultimate Vision
18
+ To become a stable credential management tool for scripting the flow of Emerson Ovation data and related APIs, supporting multiple projects in and beyond at the Maxson Wastewater Treatment Plant.
19
+ * **The Wider Goal:** A system where data is fetched, validated, and mirrored locally so that decision-support tools (Dashboards, Alarms) never have to "wait" on a slow external API.
20
+ * **The Method:** "Do one boring thing well." Use OpenSSL to manage a local `~/.dowrshak/ directory which includes a `.key` file, a `vault.db` encrypted credential file, and a `config.json` file for controlling defaults.
21
+
22
+ ## ⚖️ User Stories
23
+ Dworshak supports two complementary roles within the infrastructure data ecosystem:
24
+ 1. Infrastructure Integrator (Primary User)
25
+ > I need a secure, predictable tool that orchestrates the movement of data between upstream and downstream systems — pulling from legacy SOAP endpoints, transforming or validating as needed, and pushing clean, trusted data to the services that depend on it.
26
+ > Dworshak should behave like a controlled “data dam,” ensuring one‑directional flow, consistent execution across platforms, and strict protection of credentials.
27
+ 2. Data Analyst (Secondary User)
28
+ > I need a reliable, set-and-forget tool that synchronizes remote API data into a local, high-performance SQLite mirror, so that dashboards, reports, and decision-support tools never have to wait on slow or unreliable external services. Equipped with the Dworshak CLI and its companion toolset, I can build visualizations and reports without worrying about credential leaks, API timeouts, or platform-specific (Windows vs. Termux) bugs.
29
+
30
+ ## 🚀 The MVP (Current State)
31
+ - **Secure Vault:** Fernet-encrypted SQLite storage for API credentials.
32
+ - **Root of Trust:** A local `.key` file architecture that works identically on Windows and Termux.
33
+ - **CLI Entry:** A `typer`-based interface for setup and credential management.
34
+
35
+ ## ⚠️ Risks & Guardrails
36
+ To prevent "going off the rails" or drowning in scope creep:
37
+ **The Anti-Daemon Bias:** Stay script-based. Using `task-scheduler` or `cron` is more robust than maintaining a long-running daemon process that can leak memory or crash silently.
38
+
39
+ ### Quick Start
40
+
41
+ ```bash
42
+ # Install the CLI
43
+ pipx install dworshak
44
+
45
+ # Bootstrap the security layer
46
+ dworshak setup
47
+
48
+ # Register your first API
49
+ dworshak register --service rjn_api --item username
50
+
51
+ ```
@@ -0,0 +1,39 @@
1
+ # Project Dworshak 🌊
2
+
3
+ **Dworshak** is the security bones behind API orchestration of infrastructure data between legacy SOAP services (EDS) and modern REST APIs (RJN).
4
+
5
+ ## 🏗 The Ultimate Vision
6
+ To become a stable credential management tool for scripting the flow of Emerson Ovation data and related APIs, supporting multiple projects in and beyond at the Maxson Wastewater Treatment Plant.
7
+ * **The Wider Goal:** A system where data is fetched, validated, and mirrored locally so that decision-support tools (Dashboards, Alarms) never have to "wait" on a slow external API.
8
+ * **The Method:** "Do one boring thing well." Use OpenSSL to manage a local `~/.dowrshak/ directory which includes a `.key` file, a `vault.db` encrypted credential file, and a `config.json` file for controlling defaults.
9
+
10
+ ## ⚖️ User Stories
11
+ Dworshak supports two complementary roles within the infrastructure data ecosystem:
12
+ 1. Infrastructure Integrator (Primary User)
13
+ > I need a secure, predictable tool that orchestrates the movement of data between upstream and downstream systems — pulling from legacy SOAP endpoints, transforming or validating as needed, and pushing clean, trusted data to the services that depend on it.
14
+ > Dworshak should behave like a controlled “data dam,” ensuring one‑directional flow, consistent execution across platforms, and strict protection of credentials.
15
+ 2. Data Analyst (Secondary User)
16
+ > I need a reliable, set-and-forget tool that synchronizes remote API data into a local, high-performance SQLite mirror, so that dashboards, reports, and decision-support tools never have to wait on slow or unreliable external services. Equipped with the Dworshak CLI and its companion toolset, I can build visualizations and reports without worrying about credential leaks, API timeouts, or platform-specific (Windows vs. Termux) bugs.
17
+
18
+ ## 🚀 The MVP (Current State)
19
+ - **Secure Vault:** Fernet-encrypted SQLite storage for API credentials.
20
+ - **Root of Trust:** A local `.key` file architecture that works identically on Windows and Termux.
21
+ - **CLI Entry:** A `typer`-based interface for setup and credential management.
22
+
23
+ ## ⚠️ Risks & Guardrails
24
+ To prevent "going off the rails" or drowning in scope creep:
25
+ **The Anti-Daemon Bias:** Stay script-based. Using `task-scheduler` or `cron` is more robust than maintaining a long-running daemon process that can leak memory or crash silently.
26
+
27
+ ### Quick Start
28
+
29
+ ```bash
30
+ # Install the CLI
31
+ pipx install dworshak
32
+
33
+ # Bootstrap the security layer
34
+ dworshak setup
35
+
36
+ # Register your first API
37
+ dworshak register --service rjn_api --item username
38
+
39
+ ```
@@ -0,0 +1,26 @@
1
+ [project]
2
+ name = "dworshak"
3
+ version = "0.1.2"
4
+ description = "Manage local, encrypted credentials. The **dworshak* CLI leverages openssl, sqlite3, and cryptography."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "cryptography>=46.0.3", # No marker needed if Rust is present
9
+ "typer>=0.21.0",
10
+ #"typer>=0.12.0",
11
+ "rich>=13.0.0",
12
+
13
+ ]
14
+
15
+ [project.scripts]
16
+ dworshak = "dworshak.cli:app"
17
+
18
+ [tool.uv]
19
+ # This tells uv that if it can't find a wheel for aarch64,
20
+ # it is allowed to build from source using your local Rust/Clang.
21
+ package = true
22
+ resolution = "highest"
23
+
24
+ [build-system]
25
+ requires = ["setuptools>=64", "wheel"]
26
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,110 @@
1
+ import os
2
+ import sqlite3
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Optional
6
+
7
+ import typer
8
+ from cryptography.fernet import Fernet
9
+ from rich.console import Console
10
+ from rich.panel import Panel
11
+ from rich.table import Table
12
+ import click
13
+
14
+ from dworshak.paths import APP_DIR,KEY_FILE,DB_FILE,CONFIG_FILE
15
+ from dworshak.services import KNOWN_SERVICES
16
+ from dworshak.core.bootstrap import initialize_environment
17
+ from dworshak.core.security import get_fernet
18
+ from dworshak.core.vault import (
19
+ credential_exists,
20
+ store_credential,
21
+ )
22
+
23
+ # Force Rich to always enable colors, even when running from a .pyz bundle
24
+ os.environ["FORCE_COLOR"] = "1"
25
+ # Optional but helpful for full terminal feature detection
26
+ os.environ["TERM"] = "xterm-256color"
27
+
28
+ app = typer.Typer(
29
+ name = "dworshak",
30
+ help="Secure API Orchestration for Infrastructure.",
31
+ add_completion=False,
32
+ invoke_without_command = True,
33
+ no_args_is_help = True,
34
+ context_settings={"ignore_unknown_options": True,
35
+ "allow_extra_args": True,
36
+ "help_option_names": ["-h", "--help"]},
37
+ )
38
+
39
+
40
+ console = Console()
41
+
42
+ # --- CLI COMMANDS ---
43
+
44
+ @app.command()
45
+ def setup():
46
+ """Bootstrap the Dworshak environment and generate security keys."""
47
+ #initialize_system()
48
+ initialize_environment()
49
+ console.print(Panel.fit(
50
+ "Dworshak System Initialized\n[bold green]Security Layer Active[/bold green]",
51
+ title="Success"
52
+ ))
53
+
54
+ # def register(service: str = typer.Option("rjn_api", prompt=True)):
55
+ @app.command()
56
+ def register(
57
+ service: str = typer.Option(
58
+ "rjn_api",
59
+ prompt="Service Name",
60
+ show_default=True,
61
+ click_type=click.Choice(KNOWN_SERVICES),),
62
+ item: str = typer.Option(..., prompt="Credential Item (e.g., primary)"),
63
+ username: str = typer.Option(..., prompt="Username"),
64
+ password: str = typer.Option(..., prompt="Password", hide_input=True)
65
+ ):
66
+
67
+ """Encrypt and store a new credential in the vault."""
68
+ # Check for existing credential
69
+ if credential_exists(service, item):
70
+ console.print(
71
+ f"[yellow]A credential for {service}/{item} already exists.[/yellow]"
72
+ )
73
+ overwrite = typer.confirm("Overwrite?", default=False)
74
+ if not overwrite:
75
+ console.print("[green]Operation cancelled.[/green]")
76
+ return
77
+
78
+ # Encrypt the payload
79
+ fernet = get_fernet()
80
+ payload = json.dumps({"u": username, "p": password}).encode()
81
+ encrypted_blob = fernet.encrypt(payload)
82
+
83
+ store_credential(service, item, encrypted_blob)
84
+ console.print(
85
+ f"[green]✔ Credential for [bold]{service}/{item}[/bold] stored securely.[/green]"
86
+ )
87
+
88
+ @app.command()
89
+ def list_services():
90
+ """List all services currently stored in the vault (names only)."""
91
+ if not DB_FILE.exists():
92
+ console.print("[red]Vault not initialized.[/red]")
93
+ return
94
+
95
+ conn = sqlite3.connect(DB_FILE)
96
+ cursor = conn.execute("SELECT service, item FROM credentials")
97
+ rows = cursor.fetchall()
98
+ conn.close()
99
+
100
+ table = Table(title="Secure Vault Services")
101
+ table.add_column("Service", style="cyan")
102
+ table.add_column("Item", style="magenta")
103
+
104
+ for row in rows:
105
+ table.add_row(row[0], row[1])
106
+
107
+ console.print(table)
108
+
109
+ if __name__ == "__main__":
110
+ app()
File without changes
@@ -0,0 +1,101 @@
1
+ """
2
+ Bootstrap routines for establishing the Dworshak runtime environment.
3
+
4
+ This module is responsible for:
5
+ - Creating the application directory structure
6
+ - Generating and securing the master encryption key
7
+ - Initializing the SQLite credential vault
8
+ - Writing the initial configuration file
9
+
10
+ These operations are intended to run once during setup, but remain
11
+ idempotent to support repeated execution without side effects.
12
+ """
13
+
14
+ import os
15
+ import json
16
+ import sqlite3
17
+ from cryptography.fernet import Fernet
18
+ from rich.console import Console
19
+
20
+ from dworshak.paths import APP_DIR, KEY_FILE, DB_FILE, CONFIG_FILE
21
+
22
+ console = Console()
23
+
24
+
25
+ def initialize_environment() -> None:
26
+ """
27
+ Establishes the Dworshak environment on the local system.
28
+
29
+ This includes:
30
+ - Ensuring the application directory exists
31
+ - Creating the master key if absent
32
+ - Initializing the credential vault
33
+ - Creating the configuration file with stable defaults
34
+
35
+ All operations are safe to repeat and will not overwrite existing data.
36
+ """
37
+ APP_DIR.mkdir(parents=True, exist_ok=True)
38
+
39
+ _ensure_master_key()
40
+ _ensure_vault()
41
+ _ensure_config()
42
+
43
+
44
+ def _ensure_master_key() -> None:
45
+ """
46
+ Generates the master Fernet key if it does not already exist.
47
+
48
+ The key is stored with restrictive permissions to limit access
49
+ to the current system account.
50
+ """
51
+ if KEY_FILE.exists():
52
+ return
53
+
54
+ console.print("[yellow]Initializing Root of Trust...[/yellow]")
55
+
56
+ key = Fernet.generate_key()
57
+ KEY_FILE.write_bytes(key)
58
+
59
+ # Restrict permissions: read/write for owner only
60
+ os.chmod(KEY_FILE, 0o600)
61
+
62
+ console.print(f"[green]✔ Master key generated at {KEY_FILE}[/green]")
63
+
64
+
65
+ def _ensure_vault() -> None:
66
+ """
67
+ Creates the SQLite credential vault if it does not exist.
68
+
69
+ The schema is intentionally minimal and stable to support long-term
70
+ compatibility across Dworshak versions.
71
+ """
72
+ conn = sqlite3.connect(DB_FILE)
73
+ conn.execute(
74
+ """
75
+ CREATE TABLE IF NOT EXISTS credentials (
76
+ service TEXT NOT NULL,
77
+ item TEXT NOT NULL,
78
+ encrypted_blob BLOB NOT NULL,
79
+ PRIMARY KEY (service, item)
80
+ )
81
+ """
82
+ )
83
+ conn.close()
84
+
85
+
86
+ def _ensure_config() -> None:
87
+ """
88
+ Writes the initial configuration file if absent.
89
+
90
+ The configuration file stores user preferences only.
91
+ Service definitions are maintained in code to ensure stability.
92
+ """
93
+ if CONFIG_FILE.exists():
94
+ return
95
+
96
+ default_config = {
97
+ "default_service": "rjn_api"
98
+ }
99
+
100
+ CONFIG_FILE.write_text(json.dumps(default_config, indent=2))
101
+ console.print(f"[green]✔ Config file created at {CONFIG_FILE}[/green]")
@@ -0,0 +1,40 @@
1
+ """
2
+ Security utilities for Dworshak.
3
+
4
+ This module provides:
5
+ - Loading of the master Fernet key
6
+ - Construction of Fernet instances for encryption and decryption
7
+
8
+ Environment overrides are supported to enable automated or headless
9
+ execution environments such as CI pipelines or scheduled tasks.
10
+ """
11
+
12
+ import os
13
+ from cryptography.fernet import Fernet
14
+
15
+ from dworshak.paths import KEY_FILE
16
+
17
+
18
+ def get_fernet() -> Fernet:
19
+ """
20
+ Returns a Fernet instance using the master key.
21
+
22
+ The key is loaded from:
23
+ 1. The DWORSHAK_MASTER_KEY environment variable, if present
24
+ 2. The .key file in the application directory
25
+
26
+ Raises:
27
+ FileNotFoundError: if no key is available from either source.
28
+ """
29
+ key_override = os.getenv("DWORSHAK_MASTER_KEY")
30
+
31
+ if key_override:
32
+ return Fernet(key_override.encode())
33
+
34
+ if not KEY_FILE.exists():
35
+ raise FileNotFoundError(
36
+ "Master key not found. Run 'dworshak setup' to initialize the environment."
37
+ )
38
+
39
+ key_bytes = KEY_FILE.read_bytes()
40
+ return Fernet(key_bytes)
@@ -0,0 +1,57 @@
1
+ """
2
+ Credential vault CRUD operations for Dworshak.
3
+
4
+ This module provides:
5
+ - Existence checks
6
+ - Insert and update operations
7
+ - Retrieval of encrypted blobs
8
+ - Listing of stored credentials
9
+
10
+ All encryption and decryption is handled by core.security.
11
+ """
12
+
13
+ import sqlite3
14
+ from typing import Optional, Tuple
15
+
16
+ from dworshak.paths import DB_FILE
17
+
18
+
19
+ def credential_exists(service: str, item: str) -> bool:
20
+ conn = sqlite3.connect(DB_FILE)
21
+ cursor = conn.execute(
22
+ "SELECT 1 FROM credentials WHERE service = ? AND item = ?",
23
+ (service, item)
24
+ )
25
+ exists = cursor.fetchone() is not None
26
+ conn.close()
27
+ return exists
28
+
29
+
30
+ def store_credential(service: str, item: str, encrypted_blob: bytes) -> None:
31
+ conn = sqlite3.connect(DB_FILE)
32
+ conn.execute(
33
+ "INSERT OR REPLACE INTO credentials (service, item, encrypted_blob)"
34
+ " VALUES (?, ?, ?)",
35
+ (service, item, encrypted_blob)
36
+ )
37
+ conn.commit()
38
+ conn.close()
39
+
40
+
41
+ def load_encrypted_credential(service: str, item: str) -> Optional[bytes]:
42
+ conn = sqlite3.connect(DB_FILE)
43
+ cursor = conn.execute(
44
+ "SELECT encrypted_blob FROM credentials WHERE service = ? AND item = ?",
45
+ (service, item)
46
+ )
47
+ row = cursor.fetchone()
48
+ conn.close()
49
+ return row[0] if row else None
50
+
51
+
52
+ def list_credentials() -> list[tuple[str, str]]:
53
+ conn = sqlite3.connect(DB_FILE)
54
+ cursor = conn.execute("SELECT service, item FROM credentials")
55
+ rows = cursor.fetchall()
56
+ conn.close()
57
+ return rows
@@ -0,0 +1,9 @@
1
+ from pathlib import Path
2
+
3
+ # --- CONFIGURATION & PATHS ---
4
+ # Standardizing on a hidden home directory for cross-platform utility (Termux/Windows)
5
+
6
+ APP_DIR = Path.home() / ".dworshak"
7
+ KEY_FILE = APP_DIR / ".key"
8
+ DB_FILE = APP_DIR / "vault.db"
9
+ CONFIG_FILE = APP_DIR / "config.json"
@@ -0,0 +1,7 @@
1
+ # src/dworshak/services.py
2
+
3
+ KNOWN_SERVICES = [
4
+ "rjn_api",
5
+ "eds_soap_api",
6
+ "mission_api",
7
+ ]
@@ -0,0 +1,51 @@
1
+ Metadata-Version: 2.4
2
+ Name: dworshak
3
+ Version: 0.1.2
4
+ Summary: Manage local, encrypted credentials. The **dworshak* CLI leverages openssl, sqlite3, and cryptography.
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: cryptography>=46.0.3
9
+ Requires-Dist: typer>=0.21.0
10
+ Requires-Dist: rich>=13.0.0
11
+ Dynamic: license-file
12
+
13
+ # Project Dworshak 🌊
14
+
15
+ **Dworshak** is the security bones behind API orchestration of infrastructure data between legacy SOAP services (EDS) and modern REST APIs (RJN).
16
+
17
+ ## 🏗 The Ultimate Vision
18
+ To become a stable credential management tool for scripting the flow of Emerson Ovation data and related APIs, supporting multiple projects in and beyond at the Maxson Wastewater Treatment Plant.
19
+ * **The Wider Goal:** A system where data is fetched, validated, and mirrored locally so that decision-support tools (Dashboards, Alarms) never have to "wait" on a slow external API.
20
+ * **The Method:** "Do one boring thing well." Use OpenSSL to manage a local `~/.dowrshak/ directory which includes a `.key` file, a `vault.db` encrypted credential file, and a `config.json` file for controlling defaults.
21
+
22
+ ## ⚖️ User Stories
23
+ Dworshak supports two complementary roles within the infrastructure data ecosystem:
24
+ 1. Infrastructure Integrator (Primary User)
25
+ > I need a secure, predictable tool that orchestrates the movement of data between upstream and downstream systems — pulling from legacy SOAP endpoints, transforming or validating as needed, and pushing clean, trusted data to the services that depend on it.
26
+ > Dworshak should behave like a controlled “data dam,” ensuring one‑directional flow, consistent execution across platforms, and strict protection of credentials.
27
+ 2. Data Analyst (Secondary User)
28
+ > I need a reliable, set-and-forget tool that synchronizes remote API data into a local, high-performance SQLite mirror, so that dashboards, reports, and decision-support tools never have to wait on slow or unreliable external services. Equipped with the Dworshak CLI and its companion toolset, I can build visualizations and reports without worrying about credential leaks, API timeouts, or platform-specific (Windows vs. Termux) bugs.
29
+
30
+ ## 🚀 The MVP (Current State)
31
+ - **Secure Vault:** Fernet-encrypted SQLite storage for API credentials.
32
+ - **Root of Trust:** A local `.key` file architecture that works identically on Windows and Termux.
33
+ - **CLI Entry:** A `typer`-based interface for setup and credential management.
34
+
35
+ ## ⚠️ Risks & Guardrails
36
+ To prevent "going off the rails" or drowning in scope creep:
37
+ **The Anti-Daemon Bias:** Stay script-based. Using `task-scheduler` or `cron` is more robust than maintaining a long-running daemon process that can leak memory or crash silently.
38
+
39
+ ### Quick Start
40
+
41
+ ```bash
42
+ # Install the CLI
43
+ pipx install dworshak
44
+
45
+ # Bootstrap the security layer
46
+ dworshak setup
47
+
48
+ # Register your first API
49
+ dworshak register --service rjn_api --item username
50
+
51
+ ```
@@ -0,0 +1,17 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/dworshak/__init__.py
5
+ src/dworshak/cli.py
6
+ src/dworshak/paths.py
7
+ src/dworshak/services.py
8
+ src/dworshak.egg-info/PKG-INFO
9
+ src/dworshak.egg-info/SOURCES.txt
10
+ src/dworshak.egg-info/dependency_links.txt
11
+ src/dworshak.egg-info/entry_points.txt
12
+ src/dworshak.egg-info/requires.txt
13
+ src/dworshak.egg-info/top_level.txt
14
+ src/dworshak/core/__init__.py
15
+ src/dworshak/core/bootstrap.py
16
+ src/dworshak/core/security.py
17
+ src/dworshak/core/vault.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ dworshak = dworshak.cli:app
@@ -0,0 +1,3 @@
1
+ cryptography>=46.0.3
2
+ typer>=0.21.0
3
+ rich>=13.0.0
@@ -0,0 +1 @@
1
+ dworshak