Skip to main content

A Python linter for Umbrel app stores and applications

Project description

ulint

A linter for Umbrel apps written in Python.

PyPI version

Features

  • YAML Validation: validation of umbrel-app.yml and umbrel-app-store.yml files
  • Docker Compose Validation: validation of Docker Compose files with security checks
  • Directory Structure Validation: validation of proper app directory structure
  • Security Checks: validation of potential security vulnerabilities

Installation

Installation via uv

# using uv tool
uv tool install ulint

# using uvx
uvx ulint --help

# using pipx
pipx install ulint

# using pip
pip install ulint

Build from Source

This project uses uv as the package manager. Make sure you have uv installed, then:

# Clone the repository
git clone http://github.com/Mr-Sunglasses/ulint
cd ulint                

# Install dependencies
uv sync

# Install the package in development mode
uv pip install -e .

Usage

Command Line Interface

# Lint all apps in a directory
ulint lint /path/to/app-store

# Lint a specific app
umbrel-linter lint /path/to/app-store --app my-app

# Lint with specific options
umbrel-linter lint /path/to/app-store \
    --log-level error \
    --strict \
    --skip-architectures \
    --format json

Available Commands

  • lint: Main linting command
  • version: Show version information
  • config: Show configuration information

Command Options

  • --app, -a: Specific app ID to lint
  • --log-level, -l: Log level (error, warning, info)
  • --strict, -s: Treat warnings as errors
  • --skip-architectures: Skip checking Docker image architectures
  • --new-submission: This is a new app submission
  • --pr-url: Pull request URL for new submissions
  • --store-type: App store type (official, community)
  • --format, -f: Output format (rich, json, plain)
  • --verbose, -v: Verbose output

Programmatic Usage

from umbrel_linter import UmbrelLinter
from umbrel_linter.core.models import LinterConfig, LintingContext
from pathlib import Path

# Create linter with configuration
config = LinterConfig(
    check_image_architectures=True,
    log_level="warning",
    strict_mode=False
)

linter = UmbrelLinter(config)

# Lint a specific app
result = linter.lint_app(Path("/path/to/app-store"), "my-app")

# Check results
if result.has_errors():
    print(f"Found {result.total_errors} errors")
    for error in result.errors:
        print(f"{error.severity}: {error.title} - {error.message}")

Configuration

The linter can be configured through the LinterConfig class:

from umbrel_linter.core.models import LinterConfig, Severity

config = LinterConfig(
    check_image_architectures=True,  # Check Docker image architectures
    log_level=Severity.WARNING,      # Minimum log level
    strict_mode=False,               # Treat warnings as errors
    ignore_patterns=["*.tmp"]        # File patterns to ignore
)

Error Types

The linter identifies various types of issues:

YAML Validation Errors

  • Invalid YAML syntax
  • Missing required fields
  • Invalid field types
  • Schema validation failures

Docker Compose Validation Errors

  • Invalid image names and tags
  • Security vulnerabilities (Docker socket mounting, root user)
  • Invalid volume mounts
  • Missing required files/directories
  • Invalid port mappings
  • Incorrect app proxy configuration

Directory Structure Errors

  • Empty directories without .gitkeep files
  • Missing required files

Security Warnings

  • Docker socket mounting
  • Root user usage
  • Host network mode
  • Insecure volume mounts

Development

Setting up Development Environment

# Install development dependencies
uv sync --dev

# Run tests
uv run pytest

# Run linting
uv run ruff check .
uv run black .

# Run type checking
uv run mypy .

Running Tests

# Run all tests
uv run pytest

# Run with coverage
uv run pytest --cov=umbrel_linter

# Run specific test file
uv run pytest tests/test_models.py

Code Quality

The project uses several tools for code quality:

  • Black: Code formatting
  • Ruff: Fast Python linter
  • MyPy: Static type checking
  • Pytest: Testing framework

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass
  6. Submit a pull request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

umbrel_linter-0.1.0.tar.gz (93.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

umbrel_linter-0.1.0-py3-none-any.whl (34.5 kB view details)

Uploaded Python 3

File details

Details for the file umbrel_linter-0.1.0.tar.gz.

File metadata

  • Download URL: umbrel_linter-0.1.0.tar.gz
  • Upload date:
  • Size: 93.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for umbrel_linter-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1fbd5a5a80c4ad27871e27a5fffc68181f18f7ad1596f32d39f0fdb5ecce0d90
MD5 9bca505aa577a8eff31a9d8205ea9a28
BLAKE2b-256 d96145f4e84f5c8a7340fe76e8d1ce540ecc8e7c5f55d2c65296e4af0d9d4e7d

See more details on using hashes here.

File details

Details for the file umbrel_linter-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: umbrel_linter-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 34.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for umbrel_linter-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 aba94d98e6c4da0dda6e64c0ea953c5174f1e27bfb2761ba5c2d291c3a414b5a
MD5 77a99446f5736bc2e2b5bd7b1d783347
BLAKE2b-256 0b57efea80e97e1cf3aced3cfeaaf387e77d54de7b63181bc5d117a764f98c7f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page