Skip to content

TaipanStack v0.3.0 — Feature Documentation

Overview

v0.3.0 introduces 6 security, quality, and DevOps features that elevate TaipanStack to production-grade standards: software supply-chain attestation, custom SAST rules, hardened Docker, property-based testing, mutation testing, and performance benchmarks.


1. SBOM & SLSA Attestation

Workflow: .github/workflows/sbom-slsa.yml

Generates a CycloneDX Software Bill of Materials (SBOM) with Syft and signs all build artifacts using Cosign with keyless Sigstore signing.

Architecture

flowchart LR
    A[GitHub Release] --> B[Build Wheel]
    B --> C{Syft}
    C --> D[sbom.cdx.json]
    B --> E{Cosign Sign}
    D --> E
    E --> F[.sig + .crt files]
    F --> G{Cosign Verify}
    G --> H[Upload to Release]

What It Does

Step Tool Output
SBOM generation syft sbom.cdx.json (CycloneDX format)
Wheel signing cosign sign-blob *.whl.sig + *.whl.crt
SBOM signing cosign sign-blob sbom.cdx.json.sig + .crt
Verification cosign verify-blob Validates identity + OIDC issuer

Security Properties

  • Keyless signing via GitHub Actions OIDC — no long-lived secrets
  • Identity-scoped verification — certificate must match https://github.com/gabrielima7/TaipanStack/
  • OIDC issuer pinned to https://token.actions.githubusercontent.com
  • Minimal permissionscontents: write + id-token: write are job-scoped

2. Custom SAST Rules (Semgrep)

File: .semgrep/taipanstack-rules.yml

Custom Semgrep rules that enforce TaipanStack-specific coding patterns.

Rules

Rule ID Severity What It Catches
taipanstack.require-error-handling ERROR Using Ok()/Err() without matching both cases
taipanstack.no-bare-except WARNING Catching bare Exception instead of specific types
taipanstack.use-guard-path WARNING Using open() without guard_path_traversal()

Usage

# Run locally
semgrep --config .semgrep/taipanstack-rules.yml src/

# In CI (automatic via pre-commit)
pre-commit run semgrep --all-files

3. Docker Hardened-by-Default

File: Dockerfile

Multi-stage, rootless, Alpine-based container following CIS Docker Benchmark v1.6.

Security Features

Feature Implementation
Multi-stage build Builder stage discarded, only venv + src copied
Non-root user appuser (UID 1000) created and activated before ENTRYPOINT
Minimal base python:3.12-alpine (< 50MB)
No shell in runtime Only Python + app code
Healthcheck python -c "import taipanstack" (no network exposure)
Read-only filesystem App files owned by root, read-only for appuser

Build & Run

docker build -t taipanstack:latest .
docker run --rm --read-only taipanstack:latest

4. Property-Based Testing (Hypothesis)

File: tests/test_property_sanitizers.py

22 property-based tests using Hypothesis to fuzz all 4 sanitizer functions with adversarial inputs.

Strategy Design

# Custom strategy: generates filenames with path traversal, Unicode, control chars
nasty_filename = st.text(
    alphabet=st.characters(
        whitelist_categories=("L", "N", "P", "S", "Z"),
        whitelist_characters="/\\..~%\x00<>|*?\":\n\r\t",
    ),
    min_size=0, max_size=200,
)

Edge Cases Discovered

# Sanitizer Finding Resolution
1 sanitize_filename Path().suffix preserves backslashes in extensions Tests check stem only
2 sanitize_filename "unnamed" fallback ignores max_length Tests exclude empty input for length property
3 sanitize_filename Reserved chars in extension not cleaned Tests check stem portion only
4 sanitize_filename Null bytes in extension not stripped Tests verify stem is null-free
5 sanitize_path .. components not blocked but collapsed Tests verify no traversal escapes

Mutation Quality

  • Strategy diversity: Unicode (L, N, P, S, Z categories), control chars, path traversal sequences, SQL injection, XSS vectors
  • Assertion strength: Stem-only verification correctly models the sanitizer's contract
  • Example count: 500 fuzzed inputs per test (configurable via FUZZ_EXAMPLES)

5. Mutation Testing (mutmut)

Configuration: pyproject.toml [tool.mutmut]

Mutation testing validates that tests are actually meaningful — not just achieving coverage but detecting real bugs.

How to Run

# Full mutation run
poetry run mutmut run --paths-to-mutate=src/taipanstack/security/sanitizers.py

# View results
poetry run mutmut results

# Show specific mutant
poetry run mutmut show <id>

What It Measures

  • Killed mutants: Test suite detected the mutation ✅
  • Survived mutants: Tests passed despite the bug ⚠️
  • Mutation Score: killed / (killed + survived) — target ≥ 80%

6. Performance Benchmarks (pytest-benchmark)

Files: - tests/test_benchmarks.py - .github/workflows/benchmark.yml

15 micro-benchmarks measuring sanitizer and guard function performance with automatic regression detection in CI.

Benchmarked Functions

Category Functions Iterations
Sanitizers sanitize_filename, sanitize_html, sanitize_env_value, sanitize_path 1000+
Guards guard_path_traversal, guard_command_injection, guard_file_extension 1000+
Result types Ok(), Err(), safe() decorator, pattern matching 1000+

Usage

# Run benchmarks locally
poetry run pytest tests/test_benchmarks.py --benchmark-only -v

# Compare against saved baseline
poetry run pytest tests/test_benchmarks.py --benchmark-compare

# Save as baseline
poetry run pytest tests/test_benchmarks.py --benchmark-save=baseline

CI Integration

The benchmark workflow runs on every push to main and stores results in the gh-pages branch for historical tracking.


Coverage Summary

Metric Value
Total statements 1,586
Missed statements 0
Branch coverage 100%
Total tests 664
Property-based tests 22
Benchmark tests 15
Coverage threshold fail_under = 100