Secure Exceptions¶
PathGuardrails and higher-level wrappers (mail guardrails, future storage helpers) raise
PathSecurityError whenever filesystem access breaches the configured policies. Keep this exception handy when
integrating guardrails so you can differentiate between OS-level errors and policy violations.
Exception Hierarchy¶
KstlibError
├── PathSecurityError # filesystem guardrails (also inherits RuntimeError)
└── PasswordError # password hashing (also inherits RuntimeError)
└── InvalidPasswordHashError # stored hash is corrupt or not a valid Argon2 hash
Note
Guardrails never bypass the operating system. They provide a consistent policy layer (auto-create roots, permission checks, traversal detection), but you still need to provision secure directories and ACLs yourself.
Quick overview¶
PathSecurityErrorinherits fromRuntimeErrorand signals traversal attempts, wrong file types, or permissions that exceed the allowed mask defined by the activeGuardPolicy.PasswordError(underKstlibError, also aRuntimeError) signals a password hashing failure: the optionalargon2-cffibackend is not installed, the password is notstr/bytes, it exceedsMAX_PASSWORD_LENGTH, or the backend itself failed.InvalidPasswordHashError(underPasswordError) is raised when a stored value is not a valid Argon2 hash. Note thatverify_passwordreturnsFalseon a wrong password and raisesInvalidPasswordHashErroronly when the stored hash itself is corrupt or malformed.
Usage patterns¶
Resolving safe files¶
from pathlib import Path
from kstlib.secure import PathGuardrails, PathSecurityError, STRICT_POLICY
guard = PathGuardrails(Path("~/.cache/kstlib"), policy=STRICT_POLICY)
try:
template = guard.resolve_file("templates/newsletter.html")
except PathSecurityError as error:
LOGGER.error("Blocked unsafe path", error=error)
Handling traversal attempts¶
from kstlib.secure import PathGuardrails, PathSecurityError, RELAXED_POLICY
guard = PathGuardrails("/srv/kstlib", policy=RELAXED_POLICY)
try:
guard.resolve_file("../etc/passwd")
except PathSecurityError:
print("Traversal prevented by guardrails")
Verifying a password safely¶
from kstlib.secure import InvalidPasswordHashError, verify_password
try:
ok = verify_password(submitted_password, stored_hash)
except InvalidPasswordHashError:
# The stored hash is corrupt or not an Argon2 hash: treat as an integrity
# error, never as a successful login.
ok = False
if not ok:
reject()
Exception reference¶
- exception kstlib.secure.fs.PathSecurityError[source]¶
Bases:
KstlibError,RuntimeErrorRaised when filesystem guardrails detect a security violation.
- exception kstlib.secure.passwords.PasswordError[source]¶
Bases:
KstlibError,RuntimeErrorRaised when a password hashing operation cannot be completed.
- exception kstlib.secure.passwords.InvalidPasswordHashError[source]¶
Bases:
PasswordErrorRaised when a stored value is not a valid Argon2 hash.
Module reference¶
Filesystem guardrails utilities for securing file access.
Example
Basic usage with a temporary directory:
>>> import tempfile
>>> from kstlib.secure import PathGuardrails, STRICT_POLICY
>>> with tempfile.TemporaryDirectory() as tmpdir:
... guard = PathGuardrails(tmpdir, policy=STRICT_POLICY)
... guard.root.is_dir()
True
- class kstlib.secure.fs.GuardPolicy(name, allow_external=False, auto_create_root=True, enforce_permissions=True, max_permission_octal=448)[source]
Bases:
objectConfiguration values defining how guardrails behave.
- name
Human-friendly label used for diagnostics.
- Type:
- allow_external
When True, paths outside the root are accepted.
- Type:
- auto_create_root
Automatically create the root directory when missing.
- Type:
- enforce_permissions
Whether POSIX permissions should be validated.
- Type:
- max_permission_octal
Maximum allowed permission mask (defaults to PRIVATE).
- Type:
Example
>>> from kstlib.secure import GuardPolicy >>> policy = GuardPolicy(name="custom", allow_external=False) >>> policy.name 'custom'
- name: str
- allow_external: bool
- auto_create_root: bool
- enforce_permissions: bool
- max_permission_octal: int
- __init__(self, name: 'str', allow_external: 'bool' = False, auto_create_root: 'bool' = True, enforce_permissions: 'bool' = True, max_permission_octal: 'int' = 448) None -> None
- class kstlib.secure.fs.PathGuardrails(root, *, policy=GuardPolicy(name='strict', allow_external=False, auto_create_root=True, enforce_permissions=True, max_permission_octal=448))[source]
Bases:
objectValidate and resolve paths relative to a trusted root.
Example
>>> import tempfile >>> from kstlib.secure import PathGuardrails, RELAXED_POLICY >>> with tempfile.TemporaryDirectory() as tmpdir: ... guard = PathGuardrails(tmpdir, policy=RELAXED_POLICY) ... guard.policy.name 'relaxed'
- __init__(self, root: 'str | Path', *, policy: 'GuardPolicy' = GuardPolicy(name='strict', allow_external=False, auto_create_root=True, enforce_permissions=True, max_permission_octal=448)) 'None' -> None[source]
Initialise guardrails rooted at root while enforcing policy.
- Raises:
PathSecurityError – If root does not exist or is not a directory.
- property root: Path
Return the resolved guardrail root directory.
- property policy: GuardPolicy
Return the policy associated with the guardrails.
- resolve_file(self, candidate: 'str | Path') 'Path' -> Path[source]
Resolve candidate and ensure it points to an existing file.
- Raises:
PathSecurityError – If path is not a file or is outside root.
- resolve_directory(self, candidate: 'str | Path') 'Path' -> Path[source]
Resolve candidate and ensure it points to an existing directory.
- Raises:
PathSecurityError – If path is not a directory or is outside root.
- resolve_path(self, candidate: 'str | Path') 'Path' -> Path[source]
Resolve candidate relative to the guardrail root without type checks.
- relax(self, *, allow_external: 'bool | None' = None) 'PathGuardrails' -> PathGuardrails[source]
Return a new guardrail instance with adjusted external allowances.
- exception kstlib.secure.fs.PathSecurityError[source]
Bases:
KstlibError,RuntimeErrorRaised when filesystem guardrails detect a security violation.