Skip to content

Limits

provide.foundation.archive.limits

TODO: Add module docstring.

Classes

ArchiveLimits

Configurable limits for archive extraction to prevent decompression bombs.

Attributes:

Name Type Description
max_total_size int

Maximum total extracted size in bytes (default: 1GB)

max_file_count int

Maximum number of files in archive (default: 10,000)

max_compression_ratio float

Maximum compression ratio (default: 100:1)

max_single_file_size int

Maximum size of any single file (default: 100MB)

enabled bool

Whether to enforce limits (default: True)

ExtractionTracker

ExtractionTracker(limits: ArchiveLimits)

Track extraction progress to enforce limits.

Initialize tracker with limits.

Parameters:

Name Type Description Default
limits ArchiveLimits

Archive extraction limits

required
Source code in provide/foundation/archive/limits.py
def __init__(self, limits: ArchiveLimits) -> None:
    """Initialize tracker with limits.

    Args:
        limits: Archive extraction limits

    """
    self.limits = limits
    self.total_extracted_size = 0
    self.file_count = 0
    self.compressed_size = 0
Functions
add_extracted_size
add_extracted_size(size: int) -> None

Track extracted size and check total limit.

Parameters:

Name Type Description Default
size int

Size of extracted content in bytes

required

Raises:

Type Description
ArchiveError

If total extracted size exceeds limit

Source code in provide/foundation/archive/limits.py
def add_extracted_size(self, size: int) -> None:
    """Track extracted size and check total limit.

    Args:
        size: Size of extracted content in bytes

    Raises:
        ArchiveError: If total extracted size exceeds limit

    """
    if not self.limits.enabled:
        return

    self.total_extracted_size += size
    if self.total_extracted_size > self.limits.max_total_size:
        raise ArchiveError(
            f"Total extracted size exceeds maximum: {self.total_extracted_size} > {self.limits.max_total_size}",
            code="MAX_TOTAL_SIZE_EXCEEDED",
        )
check_compression_ratio
check_compression_ratio() -> None

Check if compression ratio exceeds limit.

Raises:

Type Description
ArchiveError

If compression ratio exceeds limit

Source code in provide/foundation/archive/limits.py
def check_compression_ratio(self) -> None:
    """Check if compression ratio exceeds limit.

    Raises:
        ArchiveError: If compression ratio exceeds limit

    """
    if not self.limits.enabled or self.compressed_size == 0:
        return

    ratio = self.total_extracted_size / self.compressed_size
    if ratio > self.limits.max_compression_ratio:
        raise ArchiveError(
            f"Compression ratio exceeds maximum: {ratio:.1f} > {self.limits.max_compression_ratio}",
            code="MAX_COMPRESSION_RATIO_EXCEEDED",
        )
check_file_count
check_file_count(count: int = 1) -> None

Check if adding files would exceed limit.

Parameters:

Name Type Description Default
count int

Number of files to add

1

Raises:

Type Description
ArchiveError

If file count would exceed limit

Source code in provide/foundation/archive/limits.py
def check_file_count(self, count: int = 1) -> None:
    """Check if adding files would exceed limit.

    Args:
        count: Number of files to add

    Raises:
        ArchiveError: If file count would exceed limit

    """
    if not self.limits.enabled:
        return

    self.file_count += count
    if self.file_count > self.limits.max_file_count:
        raise ArchiveError(
            f"Archive exceeds maximum file count: {self.file_count} > {self.limits.max_file_count}",
            code="MAX_FILE_COUNT_EXCEEDED",
        )
check_file_size
check_file_size(size: int) -> None

Check if file size exceeds single file limit.

Parameters:

Name Type Description Default
size int

File size in bytes

required

Raises:

Type Description
ArchiveError

If file size exceeds limit

Source code in provide/foundation/archive/limits.py
def check_file_size(self, size: int) -> None:
    """Check if file size exceeds single file limit.

    Args:
        size: File size in bytes

    Raises:
        ArchiveError: If file size exceeds limit

    """
    if not self.limits.enabled:
        return

    if size > self.limits.max_single_file_size:
        raise ArchiveError(
            f"File size exceeds maximum: {size} > {self.limits.max_single_file_size}",
            code="MAX_FILE_SIZE_EXCEEDED",
        )
set_compressed_size
set_compressed_size(size: int) -> None

Set the compressed archive size for ratio calculation.

Parameters:

Name Type Description Default
size int

Compressed archive size in bytes

required
Source code in provide/foundation/archive/limits.py
def set_compressed_size(self, size: int) -> None:
    """Set the compressed archive size for ratio calculation.

    Args:
        size: Compressed archive size in bytes

    """
    self.compressed_size = size
validate_member_size
validate_member_size(
    member_size: int,
    compressed_member_size: int | None = None,
) -> None

Validate a single archive member before extraction.

Parameters:

Name Type Description Default
member_size int

Uncompressed size of the member

required
compressed_member_size int | None

Optional compressed size for ratio check

None

Raises:

Type Description
ArchiveError

If member violates any limits

Source code in provide/foundation/archive/limits.py
def validate_member_size(self, member_size: int, compressed_member_size: int | None = None) -> None:
    """Validate a single archive member before extraction.

    Args:
        member_size: Uncompressed size of the member
        compressed_member_size: Optional compressed size for ratio check

    Raises:
        ArchiveError: If member violates any limits

    """
    # Check single file size limit
    self.check_file_size(member_size)

    # Check that adding this file won't exceed total size
    if self.limits.enabled and (self.total_extracted_size + member_size) > self.limits.max_total_size:
        raise ArchiveError(
            f"Extracting this file would exceed total size limit: "
            f"{self.total_extracted_size + member_size} > {self.limits.max_total_size}",
            code="MAX_TOTAL_SIZE_EXCEEDED",
        )

    # Check individual file compression ratio if available
    if compressed_member_size and compressed_member_size > 0:
        member_ratio = member_size / compressed_member_size
        if self.limits.enabled and member_ratio > self.limits.max_compression_ratio:
            raise ArchiveError(
                f"File compression ratio exceeds maximum: {member_ratio:.1f} > {self.limits.max_compression_ratio}",
                code="MAX_COMPRESSION_RATIO_EXCEEDED",
            )

Functions

get_archive_size

get_archive_size(archive_path: Path) -> int

Get the size of an archive file.

Parameters:

Name Type Description Default
archive_path Path

Path to archive file

required

Returns:

Type Description
int

Size in bytes

Source code in provide/foundation/archive/limits.py
def get_archive_size(archive_path: Path) -> int:
    """Get the size of an archive file.

    Args:
        archive_path: Path to archive file

    Returns:
        Size in bytes

    """
    return archive_path.stat().st_size