Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### [#5](https://github.com/Frost-Leo/Leviftas/issues/5) - Bootstrap configuration model

- test: Add comprehensive test suite for bootstrap settings models ([15734f3](https://github.com/Frost-Leo/Leviftas/commit/15734f3))
- refactor: Improve bootstrap settings inheritance and type safety ([683b2fa](https://github.com/Frost-Leo/Leviftas/commit/683b2fa))
- build: Add platformdirs dependency ([4b2bd18](https://github.com/Frost-Leo/Leviftas/commit/4b2bd18))
- feat: Add bootstrap configuration model with config center support ([a7ee9de](https://github.com/Frost-Leo/Leviftas/commit/a7ee9de))
- build: Add pydantic-settings dependency ([132c83c](https://github.com/Frost-Leo/Leviftas/commit/132c83c))

### [#3](https://github.com/Frost-Leo/Leviftas/issues/3) - Internal BaseModel foundation

- test: Add InternalBaseModel test suite ([1dd6798](https://github.com/Frost-Leo/Leviftas/commit/1dd6798))
Expand Down
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#
# - Author : FrostLeo <frostleo.dev@gmail.com>
# - Created : 2025/12/5
# - Modified : 2025/12/9
# - Modified : 2025/12/19

# Build system configuration - declares build backend and dependencies
[build-system]
Expand Down Expand Up @@ -75,7 +75,9 @@ classifiers = [
]
requires-python = ">=3.13"
dependencies = [
"platformdirs>=4.5.1",
"pydantic>=2.12.3",
"pydantic_settings>=2.12.0",
"typing_extensions>=4.15.0",
]

Expand Down
2 changes: 2 additions & 0 deletions src/leviftas/models/base/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
"""

from leviftas.models.base.internal_base_model import InternalBaseModel
from leviftas.models.base.internal_base_settings import InternalBaseSettings

__all__ = [
"InternalBaseModel",
"InternalBaseSettings",
]
78 changes: 78 additions & 0 deletions src/leviftas/models/base/internal_base_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright © 2025 Leviftas authors. All rights reserved.

Licensed under the GNU General Public License v3.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.gnu.org/licenses/gpl-3.0.html

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

internal_base_settings.py

Internal base settings model for Leviftas system components. This module provides
a strictly configured Pydantic BaseSettings designed for internal use only,
with security-hardened settings and consistent validation behavior.

- Author : FrostLeo <frostleo.dev@gmail.com>
- Created : 2025/12/19
- Modified : 2025/12/19
"""

from pydantic_settings import BaseSettings, SettingsConfigDict
from typing_extensions import ClassVar


class InternalBaseSettings(BaseSettings):
"""
Base settings model for all internal Leviftas system components.

This class provides a security-hardened, strictly-typed foundation for
internal settings models. It enforces consistent validation, serialization,
and security policies across all internal system components.

Subclasses should override model_config to set their own env_prefix while
keeping other settings consistent.

Attributes:
model_config (SettingsConfigDict): Pydantic settings configuration with
security-hardened settings for internal system use.

Note:
This model is intended for internal system use only. For public-facing
APIs or user-defined models, use the appropriate public model classes.
"""

model_config: ClassVar[SettingsConfigDict] = SettingsConfigDict(
# Environment variable prefix for all settings.
env_prefix="LEVIFTAS_",
# Case insensitive by default.
case_sensitive=False,
# Load configuration from .env file in the current working directory.
env_file=".env",
# Use UTF-8 encoding for .env file to avoid cross-platform issues.
env_file_encoding="utf-8",
# Ignore empty environment variables, use default values instead.
env_ignore_empty=True,
# Parse "null" string as None value.
env_parse_none_str="null",
# Use double underscore as nested delimiter for environment variables.
env_nested_delimiter="__",
# Disable CLI argument parsing by default, subclasses can enable if needed.
cli_parse_args=False,
# Parse "null" string as None value in CLI arguments.
cli_parse_none_str="null",
# Enable implicit flags: --debug equals --debug=true, --no-debug equals --debug=false.
cli_implicit_flags=True,
# Use kebab-case for CLI arguments: --node-id instead of --node_id.
cli_kebab_case=True,
# Disable secrets directory by default for cross-platform support.
secrets_dir=None,
)
25 changes: 25 additions & 0 deletions src/leviftas/models/bootstrap/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright © 2025 Leviftas authors. All rights reserved.

Licensed under the GNU General Public License v3.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.gnu.org/licenses/gpl-3.0.html

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

__init__.py



- Author : FrostLeo <frostleo.dev@gmail.com>
- Created : 2025/12/19
- Modified : 2025/12/19
"""
160 changes: 160 additions & 0 deletions src/leviftas/models/bootstrap/bootstrap_configuration_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright © 2025 Leviftas authors. All rights reserved.

Licensed under the GNU General Public License v3.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.gnu.org/licenses/gpl-3.0.html

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

bootstrap_configuration_model.py

Bootstrap configuration model for Leviftas system initialization. This module
provides the minimal configuration required to start the system and connect
to the configuration center. It supports loading from environment variables,
CLI arguments, and .env files.

- Author : FrostLeo <frostleo.dev@gmail.com>
- Created : 2025/12/19
- Modified : 2025/12/19
"""

import platform
import socket
import uuid

from platformdirs import user_config_dir
from pydantic import Field, model_validator
from pydantic_settings import SettingsConfigDict
from typing_extensions import ClassVar, Literal, Self

from leviftas.models.base.internal_base_settings import InternalBaseSettings
from leviftas.models.bootstrap.config_center import ConfigCenterBaseModel


class BootstrapConfigurationModel(InternalBaseSettings):
"""
Bootstrap configuration for Leviftas system startup.

This class provides the minimal configuration required to initialize the
system and establish connection to the configuration center. All other
runtime configurations (MQ, database, etc.) should be fetched from the
configuration center after bootstrap.

Attributes:
model_config (SettingsConfigDict): Pydantic settings configuration
for environment variables and CLI argument parsing.

Note:
Configuration priority (low to high):
1. Model default values
2. .env file
3. Environment variables
4. CLI arguments
"""

model_config: ClassVar[SettingsConfigDict] = SettingsConfigDict(
# Inherit all settings from parent class, override specific values.
**{
**InternalBaseSettings.model_config,
# Program name displayed in CLI help message.
"cli_prog_name": "leviftas",
# Enable CLI argument parsing as this is the entry point.
"cli_parse_args": True,
# Load secrets from Docker/Kubernetes secrets directory (Linux/container).
"secrets_dir": "/run/secrets",
},
)

hostname: str = Field(
default_factory=socket.gethostname,
description="Host name of the machine.",
)
"""Host name of the machine, auto-detected from system."""

os_type: str = Field(
default_factory=platform.system,
description="Operating system type (Windows, Linux, Darwin).",
)
"""Operating system type, auto-detected from system."""

os_version: str = Field(
default_factory=platform.version,
description="Operating system version.",
)
"""Operating system version, auto-detected from system."""

platform_arch: str = Field(
default_factory=platform.machine,
description="Platform architecture (x86_64, arm64, etc.).",
)
"""Platform architecture, auto-detected from system."""

node_id: str = Field(
default_factory=socket.gethostname,
description="Node identifier, shared by all instances on the same machine.",
)
"""Node identifier from environment variable, defaults to hostname."""

instance_id: str = Field(
default_factory=lambda: str(uuid.uuid4()),
description="Unique instance identifier, generated on each startup.",
)
"""Unique instance identifier, auto-generated UUID for each process."""

service_name: str = Field(
description="Service name for registration and discovery.",
)
"""Service name, required field from environment variable or CLI."""

env: str = Field(
default="dev",
description="Runtime environment (dev, staging, prod).",
)
"""Runtime environment, defaults to dev."""

config_source: Literal["remote", "local"] = Field(
default="remote",
description="Configuration source: 'remote' for config center, 'local' for file.",
)
"""Configuration source, defaults to remote (config center)."""

config_center_type: str | None = Field(
default=None,
description="Configuration center type (e.g., 'nacos', 'apollo').",
)
"""Configuration center type, required when config_source is 'remote'."""

config_center: ConfigCenterBaseModel | None = Field(
default=None,
description="Configuration center connection settings, auto-loaded by type.",
)
"""Configuration center settings, auto-instantiated from registry."""

config_dir: str = Field(
default_factory=lambda: user_config_dir("leviftas"),
description="Local configuration directory path.",
)
"""Local config directory, defaults to platform-specific user config dir."""

@model_validator(mode="after")
def validate_and_load_config(self) -> Self:
"""Validate config_source and auto-load config_center from registry."""
if self.config_source == "remote":
if self.config_center_type is None:
raise ValueError(
"config_center_type is required when config_source is 'remote'"
)
if self.config_center is None:
self.config_center = ConfigCenterBaseModel.get_by_type(
self.config_center_type
)
return self
35 changes: 35 additions & 0 deletions src/leviftas/models/bootstrap/config_center/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright © 2025 Leviftas authors. All rights reserved.

Licensed under the GNU General Public License v3.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.gnu.org/licenses/gpl-3.0.html

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

config_center/__init__.py

Configuration center connection models package for bootstrap phase.

- Author : FrostLeo <frostleo.dev@gmail.com>
- Created : 2025/12/19
- Modified : 2025/12/19
"""

from leviftas.models.bootstrap.config_center.base import ConfigCenterBaseModel
from leviftas.models.bootstrap.config_center.nacos_conn_config_model import (
NacosConnConfigModel,
)

__all__ = [
"ConfigCenterBaseModel",
"NacosConnConfigModel",
]
Loading
Loading