Compare commits

..

1 Commits

Author SHA1 Message Date
787c763b7a Added sops keys 2025-12-01 01:59:39 +01:00
48 changed files with 186 additions and 3251 deletions

2
.gitattributes vendored
View File

@@ -1,3 +1,3 @@
_secrets.yaml filter=git-crypt diff=git-crypt
secrets.yaml filter=git-crypt diff=git-crypt
*.agekey filter=git-crypt diff=git-crypt
_sops.asc filter=git-crypt diff=git-crypt

1
.gitignore vendored
View File

@@ -1,4 +1,3 @@
.ipxe/
rendered/
configs/
*.egg-info

View File

@@ -1,34 +0,0 @@
default_install_hook_types: [pre-commit, commit-msg]
exclude: gotk-.*.yaml
repos:
- repo: builtin
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
args:
- --allow-multiple-documents
- id: check-added-large-files
- id: check-merge-conflict
- id: check-executables-have-shebangs
- repo: https://github.com/jmlrt/check-yamlschema
rev: v0.0.7
hooks:
- id: check-yamlschema
files: ^patches/.*\.yaml$
- repo: https://github.com/crate-ci/typos
rev: v1.40.0
hooks:
- id: typos
- repo: https://github.com/sirwart/ripsecrets
rev: v0.1.11
hooks:
- id: ripsecrets-system
- repo: https://github.com/crate-ci/committed
rev: v1.1.8
hooks:
- id: committed

View File

@@ -1,3 +0,0 @@
_secrets.yaml
secrets.yaml
*.agekey

View File

@@ -1,2 +0,0 @@
style = "conventional"
ignore_author_re = "Flux"

View File

@@ -1,7 +1,7 @@
schematicId: !schematic default
arch: amd64
talosVersion: 1.11.3
kubernetesVersion: 1.34.1
talosVersion: v1.11.3
kubernesVersion: v1.34.1
kernelArgs:
- talos.platform=metal
- console=tty0
@@ -29,15 +29,6 @@ patches:
- !patch vip
- !patch tailscale
- !patch cilium
- !patch spegel
- !patch longhorn
- !patch longhorn-user-volume
- !patch local-path-provisioner-volume
- !patch limit-ephemeral
- !patch metrics
patchesControlPlane:
- !patch allow-control-plane-workloads
- !patch sops
- !patch cluster-variables
- !patch metrics-cluster
- !patch gateway-api

Binary file not shown.

View File

@@ -4,7 +4,6 @@ installDisk: /dev/vda
autoInstall: true
cluster:
name: testing
production: false
controlPlaneIp: 192.168.1.100
secretsFile: !realpath _secrets.yaml
sopsKeyFile: !realpath _age.agekey
sopsKeyFile: !realpath _sops.asc

BIN
nodes/testing/_sops.asc Normal file

Binary file not shown.

View File

@@ -0,0 +1,63 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=DrdW
-----END PGP PUBLIC KEY BLOCK-----

Binary file not shown.

View File

@@ -3,7 +3,6 @@ gateway: 10.0.0.1
installDisk: /dev/sda
cluster:
name: titan
production: true
controlPlaneIp: 10.0.2.1
secretsFile: !realpath _secrets.yaml
sopsKeyFile: !realpath _age.agekey
sopsKeyFile: !realpath _sops.asc

BIN
nodes/titan/_sops.asc Normal file

Binary file not shown.

63
nodes/titan/_sops.pub.asc Normal file
View File

@@ -0,0 +1,63 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=UtAO
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -1,3 +1,2 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
cluster:
allowSchedulingOnControlPlanes: true

View File

@@ -1,4 +1,3 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
features:
hostDNS:

View File

@@ -1,20 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
cluster:
inlineManifests:
- name: cluster-variables
contents: |
---
# yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/refs/heads/master/v1.34.1-standalone-strict/namespace.json
apiVersion: v1
kind: Namespace
metadata:
name: flux-system
---
# yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/refs/heads/master/v1.34.1-standalone-strict/configmap.json
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-variables
namespace: flux-system
data:
cluster_env: "{%- if node.cluster.production %} production {%- else %} staging {%- endif %}"

View File

@@ -1,4 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
cluster:
extraManifests:
- https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.1/standard-install.yaml

View File

@@ -1,4 +1,3 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
network:
hostname: "{{node.hostname}}"
hostname: {{node.hostname}}

View File

@@ -1,4 +1,3 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
install:
disk: "{{node.installDisk}}"
disk: {{node.installDisk}}

View File

@@ -1,6 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
apiVersion: v1alpha1
kind: VolumeConfig
name: EPHEMERAL
provisioning:
maxSize: 30GB

View File

@@ -1,9 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
apiVersion: v1alpha1
kind: UserVolumeConfig
name: local-path-provisioner
provisioning:
diskSelector:
match: system_disk
grow: true
maxSize: 10GB

View File

@@ -1,9 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
apiVersion: v1alpha1
kind: UserVolumeConfig
name: longhorn
provisioning:
diskSelector:
match: system_disk
grow: true
maxSize: 2000GB

View File

@@ -1,11 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
kubelet:
extraMounts:
- destination: /var/lib/longhorn
type: bind
source: /var/lib/longhorn
options:
- bind
- rshared
- rw

View File

@@ -1,5 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
cluster:
extraManifests:
- https://raw.githubusercontent.com/alex1989hu/kubelet-serving-cert-approver/main/deploy/standalone-install.yaml
- https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

View File

@@ -1,5 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
kubelet:
extraArgs:
rotate-server-certificates: "true"

View File

@@ -1,11 +1,10 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
network:
interfaces:
- interface: "{{node.interface}}"
- interface: {{node.interface}}
dhcp: false
addresses:
- "{{node.ip}}"
- {{node.ip}}
routes:
- network: 0.0.0.0/0
gateway: "{{node.gateway}}"
gateway: {{node.gateway}}

View File

@@ -1,17 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
# This is only needed on nodes that will have storage
sysctls:
vm.nr_hugepages: "1024"
nodeLabels:
openebs.io/engine: mayastor
# This is needed on ALL nodes
kubelet:
extraMounts:
- destination: /var/local
type: bind
source: /var/local
options:
- bind
- rshared
- rw

View File

@@ -1,4 +1,3 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
cluster:
inlineManifests:
- name: sops-key
@@ -14,5 +13,5 @@ cluster:
name: sops-gpg
namespace: flux-system
data:
age.agekey: |
sops.acs: |
{{ helper.load_secret(node.cluster.sopsKeyFile) }}

View File

@@ -1,8 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
files:
- path: /etc/cri/conf.d/20-customization.part
op: create
content: |
[plugins."io.containerd.cri.v1.images"]
discard_unpacked_layers = false

View File

@@ -1,8 +1,9 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
apiVersion: v1alpha1
kind: ExtensionServiceConfig
name: tailscale
environment:
- TS_AUTHKEY={{ config.tailscale.authKey }}
- TS_EXTRA_ARGS=--login-server {{ config.tailscale.loginServer }} --advertise-tags=tag:cluster-{{ node.cluster.name }}
- TS_ROUTES={% if node.advertiseRoutes -%} {{ helper.tailscale_subnet(node.gateway, node.netmask) }} {%- endif %}
{% if node.advertiseRoutes %}
- TS_ROUTES={{ helper.tailscale_subnet(node.gateway, node.netmask) }}
{% endif %}

View File

@@ -1,7 +1,6 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
network:
interfaces:
- interface: "{{node.interface}}"
- interface: {{node.interface}}
vip:
ip: "{{node.cluster.controlPlaneIp}}"
ip: {{node.cluster.controlPlaneIp}}

View File

@@ -9,9 +9,6 @@ dependencies = [
"jinja2==3.1.6",
"mergedeep==1.3.4",
"netaddr==1.3.0",
"pydantic>=2.12.5",
"pydantic-extra-types>=2.11.0",
"pyyaml==6.0.3",
"requests==2.32.5",
"semver>=3.0.4",
]

View File

@@ -1,62 +0,0 @@
# generated by datamodel-codegen:
# filename: schema.tRo.json
# timestamp: 2026-02-20T04:31:38+00:00
from __future__ import annotations
from pydantic import RootModel
from . import (
block,
extensions,
hardware,
network,
runtime,
security,
siderolink,
v1alpha1,
)
class Model(
RootModel[
block.ExistingVolumeConfigV1Alpha1
| block.RawVolumeConfigV1Alpha1
| block.SwapVolumeConfigV1Alpha1
| block.UserVolumeConfigV1Alpha1
| block.VolumeConfigV1Alpha1
| block.ZswapConfigV1Alpha1
| extensions.ServiceConfigV1Alpha1
| hardware.PCIDriverRebindConfigV1Alpha1
| network.DefaultActionConfigV1Alpha1
| network.EthernetConfigV1Alpha1
| network.KubespanEndpointsConfigV1Alpha1
| network.RuleConfigV1Alpha1
| runtime.EventSinkV1Alpha1
| runtime.KmsgLogV1Alpha1
| runtime.WatchdogTimerV1Alpha1
| security.TrustedRootsConfigV1Alpha1
| siderolink.ConfigV1Alpha1
| v1alpha1.Config
]
):
root: (
block.ExistingVolumeConfigV1Alpha1
| block.RawVolumeConfigV1Alpha1
| block.SwapVolumeConfigV1Alpha1
| block.UserVolumeConfigV1Alpha1
| block.VolumeConfigV1Alpha1
| block.ZswapConfigV1Alpha1
| extensions.ServiceConfigV1Alpha1
| hardware.PCIDriverRebindConfigV1Alpha1
| network.DefaultActionConfigV1Alpha1
| network.EthernetConfigV1Alpha1
| network.KubespanEndpointsConfigV1Alpha1
| network.RuleConfigV1Alpha1
| runtime.EventSinkV1Alpha1
| runtime.KmsgLogV1Alpha1
| runtime.WatchdogTimerV1Alpha1
| security.TrustedRootsConfigV1Alpha1
| siderolink.ConfigV1Alpha1
| v1alpha1.Config
)

View File

@@ -1,403 +0,0 @@
# generated by datamodel-codegen:
# filename: schema.tRo.json
# timestamp: 2026-02-20T04:31:38+00:00
from __future__ import annotations
from enum import Enum
from pydantic import BaseModel, ConfigDict, Field
class DiskSelector(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
match: str | None = Field(
None,
description='The Common Expression Language (CEL) expression to match the disk.\n',
title='match',
)
class EncryptionKeyKMS(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
endpoint: str | None = Field(
None, description='KMS endpoint to Seal/Unseal the key.\n', title='endpoint'
)
class EncryptionKeyNodeID(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
class EncryptionKeyStatic(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
passphrase: str | None = Field(
None, description='Defines the static passphrase value.\n', title='passphrase'
)
class EncryptionKeyTPM(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
checkSecurebootStatusOnEnroll: bool | None = Field(
None,
description='Check that Secureboot is enabled in the EFI firmware.\nIf Secureboot is not enabled, the enrollment of the key will fail. As the TPM key is anyways bound to the value of PCR 7, changing Secureboot status or configuration after the initial enrollment will make the key unusable.\n',
title='checkSecurebootStatusOnEnroll',
)
class Provider(Enum):
luks2 = 'luks2'
class Cipher(Enum):
aes_xts_plain64 = 'aes-xts-plain64'
xchacha12_aes_adiantum_plain64 = 'xchacha12,aes-adiantum-plain64'
xchacha20_aes_adiantum_plain64 = 'xchacha20,aes-adiantum-plain64'
class Options(Enum):
no_read_workqueue = 'no_read_workqueue'
no_write_workqueue = 'no_write_workqueue'
same_cpu_crypt = 'same_cpu_crypt'
class ApiVersion(Enum):
v1alpha1 = 'v1alpha1'
class Kind(Enum):
ExistingVolumeConfig = 'ExistingVolumeConfig'
class Type(Enum):
ext4 = 'ext4'
xfs = 'xfs'
class FilesystemSpec(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
type: Type | None = Field(
None, description='Filesystem type. Default is xfs.\n', title='type'
)
projectQuotaSupport: bool | None = Field(
None,
description='Enables project quota support, valid only for xfs filesystem.\n\nNote: changing this value might require a full remount of the filesystem.\n',
title='projectQuotaSupport',
)
class MountSpec(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
readOnly: bool | None = Field(
None, description='Mount the volume read-only.\n', title='readOnly'
)
class ProvisioningSpec(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
diskSelector: DiskSelector | None = Field(
None, description='The disk selector expression.\n', title='diskSelector'
)
grow: bool | None = Field(
None,
description='Should the volume grow to the size of the disk (if possible).\n',
title='grow',
)
minSize: str | None = Field(
None,
description='The minimum size of the volume.\n\nSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\n',
title='minSize',
)
maxSize: str | None = Field(
None,
description='The maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\n\nSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\n',
title='maxSize',
)
class KindModel(Enum):
RawVolumeConfig = 'RawVolumeConfig'
class KindModel1(Enum):
SwapVolumeConfig = 'SwapVolumeConfig'
class KindModel2(Enum):
UserVolumeConfig = 'UserVolumeConfig'
class KindModel3(Enum):
VolumeConfig = 'VolumeConfig'
class VolumeSelector(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
match: str | None = Field(
None,
description='The Common Expression Language (CEL) expression to match the volume.\n',
title='match',
)
class KindModel4(Enum):
ZswapConfig = 'ZswapConfig'
class ZswapConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: KindModel4 = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
maxPoolPercent: int | None = Field(
None,
description='The maximum percent of memory that zswap can use.\nThis is a percentage of the total system memory.\nThe value must be between 0 and 100.\n',
title='maxPoolPercent',
)
shrinkerEnabled: bool | None = Field(
None,
description='Enable the shrinker feature: kernel might move\ncold pages from zswap to swap device to free up memory\nfor other use cases.\n',
title='shrinkerEnabled',
)
class EncryptionKey(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
slot: int | None = Field(
None, description='Key slot number for LUKS2 encryption.\n', title='slot'
)
static: EncryptionKeyStatic | None = Field(
None,
description='Key which value is stored in the configuration file.\n',
title='static',
)
nodeID: EncryptionKeyNodeID | None = Field(
None,
description='Deterministically generated key from the node UUID and PartitionLabel.\n',
title='nodeID',
)
kms: EncryptionKeyKMS | None = Field(
None, description='KMS managed encryption key.\n', title='kms'
)
tpm: EncryptionKeyTPM | None = Field(
None, description='Enable TPM based disk encryption.\n', title='tpm'
)
lockToState: bool | None = Field(
None,
description='Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.\n',
title='lockToState',
)
class EncryptionSpec(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
provider: Provider | None = Field(
None,
description='Encryption provider to use for the encryption.\n',
title='provider',
)
keys: list[EncryptionKey] | None = Field(
None,
description='Defines the encryption keys generation and storage method.\n',
title='keys',
)
cipher: Cipher | None = Field(
None,
description='Cipher to use for the encryption. Depends on the encryption provider.\n',
title='cipher',
)
keySize: int | None = Field(
None, description='Defines the encryption key length.\n', title='keySize'
)
blockSize: int | None = Field(
None, description='Defines the encryption sector size.\n', title='blockSize'
)
options: Options | None = Field(
None,
description='Additional perf parameters for the LUKS2 encryption.\n',
title='options',
)
class RawVolumeConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: KindModel = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
name: str | None = Field(
None,
description='Name of the volume.\n\nName might be between 1 and 34 characters long and can only contain:\nlowercase and uppercase ASCII letters, digits, and hyphens.\n',
title='name',
)
provisioning: ProvisioningSpec | None = Field(
None,
description='The provisioning describes how the volume is provisioned.\n',
title='provisioning',
)
encryption: EncryptionSpec | None = Field(
None,
description='The encryption describes how the volume is encrypted.\n',
title='encryption',
)
class SwapVolumeConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: KindModel1 = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
name: str | None = Field(
None,
description='Name of the volume.\n\nName might be between 1 and 34 characters long and can only contain:\nlowercase and uppercase ASCII letters, digits, and hyphens.\n',
title='name',
)
provisioning: ProvisioningSpec | None = Field(
None,
description='The provisioning describes how the volume is provisioned.\n',
title='provisioning',
)
encryption: EncryptionSpec | None = Field(
None,
description='The encryption describes how the volume is encrypted.\n',
title='encryption',
)
class UserVolumeConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: KindModel2 = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
name: str | None = Field(
None,
description='Name of the volume.\n\nName might be between 1 and 34 characters long and can only contain:\nlowercase and uppercase ASCII letters, digits, and hyphens.\n',
title='name',
)
provisioning: ProvisioningSpec | None = Field(
None,
description='The provisioning describes how the volume is provisioned.\n',
title='provisioning',
)
filesystem: FilesystemSpec | None = Field(
None,
description='The filesystem describes how the volume is formatted.\n',
title='filesystem',
)
encryption: EncryptionSpec | None = Field(
None,
description='The encryption describes how the volume is encrypted.\n',
title='encryption',
)
class VolumeConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: KindModel3 = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
name: str | None = Field(None, description='Name of the volume.\n', title='name')
provisioning: ProvisioningSpec | None = Field(
None,
description='The provisioning describes how the volume is provisioned.\n',
title='provisioning',
)
encryption: EncryptionSpec | None = Field(
None,
description='The encryption describes how the volume is encrypted.\n',
title='encryption',
)
class VolumeDiscoverySpec(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
volumeSelector: VolumeSelector | None = Field(
None, description='The volume selector expression.\n', title='volumeSelector'
)
class ExistingVolumeConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: Kind = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
name: str | None = Field(
None,
description='Name of the volume.\n\nName can only contain:\nlowercase and uppercase ASCII letters, digits, and hyphens.\n',
title='name',
)
discovery: VolumeDiscoverySpec | None = Field(
None,
description='The discovery describes how to find a volume.\n',
title='discovery',
)
mount: MountSpec | None = Field(
None,
description='The mount describes additional mount options.\n',
title='mount',
)

View File

@@ -1,58 +0,0 @@
# generated by datamodel-codegen:
# filename: schema.tRo.json
# timestamp: 2026-02-20T04:31:38+00:00
from __future__ import annotations
from enum import Enum
from pydantic import BaseModel, ConfigDict, Field
class ConfigFile(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
content: str | None = Field(
None,
description='The content of the extension service config file.\n',
title='content',
)
mountPath: str | None = Field(
None,
description='The mount path of the extension service config file.\n',
title='mountPath',
)
class ApiVersion(Enum):
v1alpha1 = 'v1alpha1'
class Kind(Enum):
ExtensionServiceConfig = 'ExtensionServiceConfig'
class ServiceConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: Kind = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
name: str = Field(..., description='Name of the extension service.\n', title='name')
configFiles: list[ConfigFile] | None = Field(
None,
description='The config files for the extension service.\n',
title='configFiles',
)
environment: list[str] | None = Field(
None,
description='The environment for the extension service.\n',
title='environment',
)

View File

@@ -1,37 +0,0 @@
# generated by datamodel-codegen:
# filename: schema.tRo.json
# timestamp: 2026-02-20T04:31:38+00:00
from __future__ import annotations
from enum import Enum
from pydantic import BaseModel, ConfigDict, Field
class ApiVersion(Enum):
v1alpha1 = 'v1alpha1'
class Kind(Enum):
PCIDriverRebindConfig = 'PCIDriverRebindConfig'
class PCIDriverRebindConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: Kind = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
name: str = Field(..., description='PCI device id\n', title='name')
targetDriver: str = Field(
...,
description='Target driver to rebind the PCI device to.\n',
title='targetDriver',
)

View File

@@ -1,220 +0,0 @@
# generated by datamodel-codegen:
# filename: schema.tRo.json
# timestamp: 2026-02-20T04:31:38+00:00
from __future__ import annotations
from enum import Enum
from pydantic import BaseModel, ConfigDict, Field, constr
class ApiVersion(Enum):
v1alpha1 = 'v1alpha1'
class Kind(Enum):
NetworkDefaultActionConfig = 'NetworkDefaultActionConfig'
class Ingress(Enum):
accept = 'accept'
block = 'block'
class DefaultActionConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: Kind = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
ingress: Ingress | None = Field(
None,
description='Default action for all not explicitly configured ingress traffic: accept or block.\n',
title='ingress',
)
class EthernetChannelsConfig(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
rx: int | None = Field(None, description='Number of RX channels.\n', title='rx')
tx: int | None = Field(None, description='Number of TX channels.\n', title='tx')
other: int | None = Field(
None, description='Number of other channels.\n', title='other'
)
combined: int | None = Field(
None, description='Number of combined channels.\n', title='combined'
)
class KindModel(Enum):
EthernetConfig = 'EthernetConfig'
class EthernetRingsConfig(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
rx: int | None = Field(None, description='Number of RX rings.\n', title='rx')
tx: int | None = Field(None, description='Number of TX rings.\n', title='tx')
rx_mini: int | None = Field(
None, alias='rx-mini', description='Number of RX mini rings.\n', title='rx-mini'
)
rx_jumbo: int | None = Field(
None,
alias='rx-jumbo',
description='Number of RX jumbo rings.\n',
title='rx-jumbo',
)
rx_buf_len: int | None = Field(
None, alias='rx-buf-len', description='RX buffer length.\n', title='rx-buf-len'
)
cqe_size: int | None = Field(
None, alias='cqe-size', description='CQE size.\n', title='cqe-size'
)
tx_push: bool | None = Field(
None, alias='tx-push', description='TX push enabled.\n', title='tx-push'
)
rx_push: bool | None = Field(
None, alias='rx-push', description='RX push enabled.\n', title='rx-push'
)
tx_push_buf_len: int | None = Field(
None,
alias='tx-push-buf-len',
description='TX push buffer length.\n',
title='tx-push-buf-len',
)
tcp_data_split: bool | None = Field(
None,
alias='tcp-data-split',
description='TCP data split enabled.\n',
title='tcp-data-split',
)
class IngressRule(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
subnet: constr(pattern=r'^[0-9a-f.:]+/\d{1,3}$') | None = Field(
None, description='Subnet defines a source subnet.\n', title='subnet'
)
except_: constr(pattern=r'^[0-9a-f.:]+/\d{1,3}$') | None = Field(
None,
alias='except',
description='Except defines a source subnet to exclude from the rule, it gets excluded from the subnet.\n',
title='except',
)
class KindModel1(Enum):
KubeSpanEndpoints = 'KubeSpanEndpoints'
class KubespanEndpointsConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: KindModel1 = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
extraAnnouncedEndpoints: list[str] | None = Field(
None,
description='A list of extra Wireguard endpoints to announce from this machine.\n\nTalos automatically adds endpoints based on machine addresses, public IP, etc.\nThis field allows to add extra endpoints which are managed outside of Talos, e.g. NAT mapping.\n',
title='extraAnnouncedEndpoints',
)
class KindModel2(Enum):
NetworkRuleConfig = 'NetworkRuleConfig'
class Protocol(Enum):
tcp = 'tcp'
udp = 'udp'
icmp = 'icmp'
icmpv6 = 'icmpv6'
class RulePortSelector(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
ports: list[int | str] | None = Field(
None,
description='Ports defines a list of port ranges or single ports.\nThe port ranges are inclusive, and should not overlap.\n',
title='ports',
)
protocol: Protocol | None = Field(
None,
description='Protocol defines traffic protocol (e.g. TCP or UDP).\n',
title='protocol',
)
class EthernetConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: KindModel = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
name: str = Field(..., description='Name of the link (interface).\n', title='name')
features: dict[constr(pattern=r'.*'), bool] | None = Field(
None,
description='Configuration for Ethernet features.\n\nSet of features available and whether they can be enabled or disabled is driver specific.\nUse talosctl get ethernetstatus <link> -o yaml to get the list of available features and\ntheir current status.\n',
title='features',
)
rings: EthernetRingsConfig | None = Field(
None,
description='Configuration for Ethernet link rings.\n\nThis is similar to ethtool -G command.\n',
title='rings',
)
channels: EthernetChannelsConfig | None = Field(
None,
description='Configuration for Ethernet link channels.\n\nThis is similar to ethtool -L command.\n',
title='channels',
)
class RuleConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: KindModel2 = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
name: str = Field(..., description='Name of the config document.\n', title='name')
portSelector: RulePortSelector | None = Field(
None,
description='Port selector defines which ports and protocols on the host are affected by the rule.\n',
title='portSelector',
)
ingress: list[IngressRule] | None = Field(
None,
description='Ingress defines which source subnets are allowed to access the host ports/protocols defined by the portSelector.\n',
title='ingress',
)

View File

@@ -1,90 +0,0 @@
# generated by datamodel-codegen:
# filename: schema.tRo.json
# timestamp: 2026-02-20T04:31:38+00:00
from __future__ import annotations
from enum import Enum
from pydantic import BaseModel, ConfigDict, Field, constr
class ApiVersion(Enum):
v1alpha1 = 'v1alpha1'
class Kind(Enum):
EventSinkConfig = 'EventSinkConfig'
class EventSinkV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: Kind = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
endpoint: str | None = Field(
None,
description='The endpoint for the event sink as host:port.\n',
title='endpoint',
)
class KindModel(Enum):
KmsgLogConfig = 'KmsgLogConfig'
class KmsgLogV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: KindModel = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
name: str | None = Field(
None, description='Name of the config document.\n', title='name'
)
url: constr(pattern=r'^(tcp|udp)://') | None = Field(
None,
description='The URL encodes the log destination.\nThe scheme must be tcp:// or udp://.\nThe path must be empty.\nThe port is required.\n',
title='url',
)
class KindModel1(Enum):
WatchdogTimerConfig = 'WatchdogTimerConfig'
class WatchdogTimerV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: KindModel1 = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
device: str | None = Field(
None, description='Path to the watchdog device.\n', title='device'
)
timeout: (
constr(pattern=r'^[-+]?(((\d+(\.\d*)?|\d*(\.\d+)+)([nuµm]?s|m|h))|0)+$') | None
) = Field(
None,
description='Timeout for the watchdog.\n\nIf Talos is unresponsive for this duration, the watchdog will reset the system.\n\nDefault value is 1 minute, minimum value is 10 seconds.\n',
title='timeout',
)

View File

@@ -1,37 +0,0 @@
# generated by datamodel-codegen:
# filename: schema.tRo.json
# timestamp: 2026-02-20T04:31:38+00:00
from __future__ import annotations
from enum import Enum
from pydantic import BaseModel, ConfigDict, Field
class ApiVersion(Enum):
v1alpha1 = 'v1alpha1'
class Kind(Enum):
TrustedRootsConfig = 'TrustedRootsConfig'
class TrustedRootsConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: Kind = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
name: str = Field(..., description='Name of the config document.\n', title='name')
certificates: str | None = Field(
None,
description='List of additional trusted certificate authorities (as PEM-encoded certificates).\n\nMultiple certificates can be provided in a single config document, separated by newline characters.\n',
title='certificates',
)

View File

@@ -1,39 +0,0 @@
# generated by datamodel-codegen:
# filename: schema.tRo.json
# timestamp: 2026-02-20T04:31:38+00:00
from __future__ import annotations
from enum import Enum
from pydantic import BaseModel, ConfigDict, Field, constr
class ApiVersion(Enum):
v1alpha1 = 'v1alpha1'
class Kind(Enum):
SideroLinkConfig = 'SideroLinkConfig'
class ConfigV1Alpha1(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
apiVersion: ApiVersion = Field(
...,
description='apiVersion is the API version of the resource.\n',
title='apiVersion',
)
kind: Kind = Field(
..., description='kind is the kind of the resource.\n', title='kind'
)
apiUrl: constr(pattern=r'^(https|grpc)://') | None = Field(
None, description='SideroLink API URL to connect to.\n', title='apiUrl'
)
uniqueToken: str | None = Field(
None,
description='SideroLink unique token to use for the connection (optional).\n\nThis value is overridden with META key UniqueMachineToken.\n',
title='uniqueToken',
)

File diff suppressed because it is too large Load Diff

View File

@@ -17,8 +17,8 @@ goto node_${serial} || exit
{% do kernelArgs.append("talos.config=" ~ config.server.httpUrl ~ "/configs/" ~ node.filename ~ ".yaml") %}
{% endif %}
imgfree
kernel https://pxe.factory.talos.dev/image/{{ node.schematicId }}/v{{ node.talosVersion }}/kernel-{{ node.arch }} {{ kernelArgs|join(" ") }}
initrd https://pxe.factory.talos.dev/image/{{ node.schematicId }}/v{{ node.talosVersion }}/initramfs-{{ node.arch }}.xz
kernel https://pxe.factory.talos.dev/image/{{ node.schematicId }}/{{ node.talosVersion }}/kernel-{{ node.arch }} {{ kernelArgs|join(" ") }}
initrd https://pxe.factory.talos.dev/image/{{ node.schematicId }}/{{ node.talosVersion }}/initramfs-{{ node.arch }}.xz
boot
{% endif %}
{% endfor %}

View File

@@ -6,16 +6,16 @@ CONFIGS={{ root }}/configs
{% for node in nodes -%}
talosctl gen config {{ node.cluster.name }} https://{{ node.cluster.controlPlaneIp }}:6443 -f \
--with-secrets {{ node.cluster.secretsFile }} \
--talos-version v{{ node.talosVersion }} \
--kubernetes-version v{{ node.kubernetesVersion }} \
--talos-version {{ node.talosVersion }} \
--kubernetes-version {{ node.kubernesVersion }} \
--output-types {{ node.type }} \
--install-image factory.talos.dev/metal-installer/{{ node.schematicId }}:v{{ node.talosVersion }} \
--install-image factory.talos.dev/metal-installer/{{ node.schematicId }}:{{ node.talosVersion }} \
{% for patch in node.patches -%}
{# The double call to tojson is needed to properly escape the patch (object -> json -> string) -#}
--config-patch {{ helper.model_dump_json(patch)|tojson }} \
--config-patch {{ patch|tojson|tojson }} \
{% endfor -%}
{% for patch in node.patchesControlPlane -%}
--config-patch-control-plane {{ helper.model_dump_json(patch)|tojson }} \
--config-patch-control-plane {{ patch|tojson|tojson }} \
{% endfor -%}
--with-docs=false \
--with-examples=false \

View File

@@ -5,9 +5,9 @@
import base64
import functools
import json
import pathlib
import sys
from typing import Annotated, Any, List, Literal
import git
import requests
@@ -15,17 +15,6 @@ import yaml
from jinja2 import Environment, FileSystemLoader, StrictUndefined, Template
from mergedeep import Strategy, merge
from netaddr import IPAddress
from pydantic import (
BaseModel,
BeforeValidator,
ConfigDict,
HttpUrl,
IPvAnyAddress,
ValidationInfo,
)
from pydantic_extra_types.semantic_version import SemanticVersion
from models import Model as TalosModel
REPO = git.Repo(sys.path[0], search_parent_directories=True)
assert REPO.working_dir is not None
@@ -50,38 +39,6 @@ TEMPLATES = Environment(
)
class ServerConfig(BaseModel):
model_config = ConfigDict(strict=True, extra="forbid")
tftpIp: IPvAnyAddress
httpUrl: HttpUrl
class TailscaleConfig(BaseModel):
model_config = ConfigDict(strict=True, extra="forbid")
loginServer: HttpUrl
authKey: str
class Config(BaseModel):
model_config = ConfigDict(strict=True, extra="forbid")
server: ServerConfig
tailscale: TailscaleConfig
class Cluster(BaseModel):
model_config = ConfigDict(strict=True, extra="forbid")
name: str
production: bool
controlPlaneIp: IPvAnyAddress
# TODO: Path
secretsFile: str
sopsKeyFile: str
# When we try to make a deep copy of the nodes dict it fails as the Template
# does not implement __deepcopy__, so this wrapper type facilitates that
class TemplateWrapper:
@@ -94,68 +51,31 @@ class TemplateWrapper:
return self
def render_patch(wrapper: Any, info: ValidationInfo):
if not isinstance(wrapper, TemplateWrapper):
raise RuntimeError("Expected TemplateWrapper")
args = (info.context or {}) | {"node": info.data}
def render_templates(node: dict, args: dict):
class Inner(json.JSONEncoder):
def default(self, o):
if isinstance(o, TemplateWrapper):
try:
rendered = wrapper.template.render(args)
rendered = o.template.render(args | {"node": node})
except Exception as e:
e.add_note(f"While rendering for: {args['node']['hostname']}")
e.add_note(f"While rendering for: {node['hostname']}")
raise e
# Parse the rendered yaml
return yaml.safe_load(rendered)
return super().default(o)
class Node(BaseModel):
model_config = ConfigDict(strict=True, extra="forbid")
schematicId: str
arch: Literal["amd64"]
talosVersion: SemanticVersion
kubernetesVersion: SemanticVersion
kernelArgs: List[str]
extraKernelArgs: List[str]
dns: List[IPvAnyAddress]
# TODO: Validation
ntp: str
install: bool
advertiseRoutes: bool
serial: str
interface: str
ip: IPvAnyAddress
netmask: IPvAnyAddress
gateway: IPvAnyAddress
# TODO: Extra validation
installDisk: str
autoInstall: bool
cluster: Cluster
hostname: str
filename: str
type: Literal["controlplane", "worker"]
patches: List[Annotated[TalosModel, BeforeValidator(render_patch)]]
patchesControlPlane: List[Annotated[TalosModel, BeforeValidator(render_patch)]]
return Inner
def tailscale_subnet(gateway: IPvAnyAddress, netmask: IPvAnyAddress):
netmask_bits = IPAddress(netmask.exploded).netmask_bits()
return f"{IPAddress(gateway.exploded) & IPAddress(netmask.exploded)}/{netmask_bits}"
def tailscale_subnet(gateway: str, netmask: str):
netmask_bits = IPAddress(netmask).netmask_bits()
return f"{IPAddress(gateway) & IPAddress(netmask)}/{netmask_bits}"
def load_secret(path: str):
with open(path) as f:
return base64.b64encode(f.read().encode()).decode()
def model_dump_json(model: BaseModel):
return model.model_dump_json(exclude_none=True)
@functools.cache
def get_schematic_id(schematic: str):
"""Lookup the schematic id associated with a given schematic"""
@@ -246,19 +166,13 @@ def main():
with open(ROOT.joinpath("secrets.yaml")) as fyaml:
merge(config, yaml.safe_load(fyaml), strategy=Strategy.TYPESAFE_REPLACE)
config = Config(**config)
template_args = {
"config": config,
"root": ROOT,
"helper": {
"tailscale_subnet": tailscale_subnet,
"load_secret": load_secret,
"model_dump_json": model_dump_json,
},
"helper": {"tailscale_subnet": tailscale_subnet, "load_secret": load_secret},
}
nodes: List[Node] = []
nodes = []
for fullname in walk_files(NODES):
filename = str(fullname.relative_to(NODES).parent) + "/" + fullname.stem
@@ -272,15 +186,24 @@ def main():
)
yml_data["hostname"] = fullname.stem
yml_data["filename"] = filename
node = Node.model_validate(yml_data, context=template_args)
nodes.append(node)
nodes.append(yml_data)
# Quick and dirty way to resolve all the templates using a custom encoder
nodes = list(
map(
lambda node: json.loads(
json.dumps(node, cls=render_templates(node, template_args))
),
nodes,
)
)
# HACK: We can't hash a dict, so we first convert it to json, the use set
# to get all the unique entries, and then convert it back
# NOTE: This assumes that all nodes in the cluster use the same definition for the cluster
clusters = list(
Cluster.model_validate_json(cluster)
for cluster in set(node.cluster.model_dump_json() for node in nodes)
json.loads(cluster)
for cluster in set(json.dumps(node["cluster"]) for node in nodes)
)
template_args |= {"nodes": nodes, "clusters": clusters}

View File

@@ -1,15 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT=$(git rev-parse --show-toplevel)
MODELS_DIR=${ROOT}/src/models
rm -rf ${MODELS_DIR}
SCHEMA_FILE=$(mktemp schema.XXX.json)
function cleanup() {
rm -rf ${SCHEMA_FILE}
}
trap cleanup EXIT
curl https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json > ${SCHEMA_FILE}
uvx --from datamodel-code-generator datamodel-codegen --input ${SCHEMA_FILE} --input-file-type jsonschema --output ${MODELS_DIR} --output-model pydantic_v2.BaseModel

View File

@@ -3,9 +3,9 @@ set -euo pipefail
ROOT=$(git rev-parse --show-toplevel)
VM_NAME="talos-vm"
VCPUS="6"
RAM_MB="16384"
DISK_GB="100"
VCPUS="2"
RAM_MB="2048"
DISK_GB="10"
NETWORK=talos
CONNECTION="qemu:///system"

126
uv.lock generated
View File

@@ -2,15 +2,6 @@ version = 1
revision = 3
requires-python = ">=3.13"
[[package]]
name = "annotated-types"
version = "0.7.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
]
[[package]]
name = "bootstrap"
version = "0.1.0"
@@ -20,11 +11,8 @@ dependencies = [
{ name = "jinja2" },
{ name = "mergedeep" },
{ name = "netaddr" },
{ name = "pydantic" },
{ name = "pydantic-extra-types" },
{ name = "pyyaml" },
{ name = "requests" },
{ name = "semver" },
]
[package.metadata]
@@ -33,11 +21,8 @@ requires-dist = [
{ name = "jinja2", specifier = "==3.1.6" },
{ name = "mergedeep", specifier = "==1.3.4" },
{ name = "netaddr", specifier = "==1.3.0" },
{ name = "pydantic", specifier = ">=2.12.5" },
{ name = "pydantic-extra-types", specifier = ">=2.11.0" },
{ name = "pyyaml", specifier = "==6.0.3" },
{ name = "requests", specifier = "==2.32.5" },
{ name = "semver", specifier = ">=3.0.4" },
]
[[package]]
@@ -205,87 +190,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/12/cc/f4fe2c7ce68b92cbf5b2d379ca366e1edae38cccaad00f69f529b460c3ef/netaddr-1.3.0-py3-none-any.whl", hash = "sha256:c2c6a8ebe5554ce33b7d5b3a306b71bbb373e000bbbf2350dd5213cc56e3dbbe", size = 2262023, upload-time = "2024-05-28T21:30:34.191Z" },
]
[[package]]
name = "pydantic"
version = "2.12.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "annotated-types" },
{ name = "pydantic-core" },
{ name = "typing-extensions" },
{ name = "typing-inspection" },
]
sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" },
]
[[package]]
name = "pydantic-core"
version = "2.41.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" },
{ url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" },
{ url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" },
{ url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" },
{ url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" },
{ url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" },
{ url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" },
{ url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" },
{ url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" },
{ url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" },
{ url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" },
{ url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" },
{ url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" },
{ url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" },
{ url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" },
{ url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" },
{ url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" },
{ url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" },
{ url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" },
{ url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" },
{ url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" },
{ url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" },
{ url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" },
{ url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" },
{ url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" },
{ url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" },
{ url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" },
{ url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" },
{ url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" },
{ url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" },
{ url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" },
{ url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" },
{ url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" },
{ url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" },
{ url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" },
{ url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" },
{ url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" },
{ url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" },
{ url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" },
{ url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" },
{ url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" },
{ url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" },
]
[[package]]
name = "pydantic-extra-types"
version = "2.11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pydantic" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fd/35/2fee58b1316a73e025728583d3b1447218a97e621933fc776fb8c0f2ebdd/pydantic_extra_types-2.11.0.tar.gz", hash = "sha256:4e9991959d045b75feb775683437a97991d02c138e00b59176571db9ce634f0e", size = 157226, upload-time = "2025-12-31T16:18:27.944Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fe/17/fabd56da47096d240dd45ba627bead0333b0cf0ee8ada9bec579287dadf3/pydantic_extra_types-2.11.0-py3-none-any.whl", hash = "sha256:84b864d250a0fc62535b7ec591e36f2c5b4d1325fa0017eb8cda9aeb63b374a6", size = 74296, upload-time = "2025-12-31T16:18:26.38Z" },
]
[[package]]
name = "pyyaml"
version = "6.0.3"
@@ -337,15 +241,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
]
[[package]]
name = "semver"
version = "3.0.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/d1/d3159231aec234a59dd7d601e9dd9fe96f3afff15efd33c1070019b26132/semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602", size = 269730, upload-time = "2025-01-24T13:19:27.617Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746", size = 17912, upload-time = "2025-01-24T13:19:24.949Z" },
]
[[package]]
name = "smmap"
version = "5.0.2"
@@ -355,27 +250,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" },
]
[[package]]
name = "typing-extensions"
version = "4.15.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
]
[[package]]
name = "typing-inspection"
version = "0.4.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
]
[[package]]
name = "urllib3"
version = "2.5.0"